浏览代码

merge orient outward heuristic, bfs orient patches, patch example

Former-commit-id: c81ba7a2429e4a8e4abe029879cc6803cf9ed184
Alec Jacobson (jalec 11 年之前
父节点
当前提交
5f982bef4b

+ 11 - 1
examples/embree/example.cpp

@@ -438,7 +438,17 @@ int main(int argc, char * argv[])
   using namespace std;
 
   // init mesh
-  if(!read("../shared/decimated-knight.obj",V,F))
+  string filename = "../shared/decimated-knight.obj";
+  if(argc < 2)
+  {
+    cerr<<"Usage:"<<endl<<"    ./example input.obj"<<endl;
+    cout<<endl<<"Opening default mesh..."<<endl;
+  }else
+  {
+    // Read and prepare mesh
+    filename = argv[1];
+  }
+  if(!read(filename,V,F))
   {
     return 1;
   }

+ 7 - 4
examples/flare-eyes/example.cpp

@@ -72,7 +72,7 @@ std::stack<State> redo_stack;
 bool is_rotating = false;
 int down_x,down_y;
 igl::Camera down_camera;
-bool render_to_png_on_next = false;
+bool render_to_tga_on_next = false;
 int render_count = 0;
 
 int width,height;
@@ -236,7 +236,7 @@ void draw_eyes()
     LED_METHOD_COLORED_CIRCLE = 0,
     LED_METHOD_OUTLINED_CIRCLE = 1,
     LED_METHOD_TEXTURE_FLARE = 2
-  } method = LED_METHOD_TEXTURE_FLARE;
+  } method = LED_METHOD_COLORED_CIRCLE;
 
   
   for(int l = 0;l<NUM_LEDS;l++)
@@ -345,14 +345,14 @@ void display()
 
   report_gl_error();
 
-  if(render_to_png_on_next)
+  if(render_to_tga_on_next)
   {
     GLint viewport[4];
     glGetIntegerv(GL_VIEWPORT,viewport);
     render_to_tga(
       STR("./"<< "flare-eyes-" << setw(4) << setfill('0') << render_count++ << ".tga"),
       viewport[2],viewport[3],true);
-    //render_to_png_on_next = false;
+    //render_to_tga_on_next = false;
   }
 
   TwDraw();
@@ -595,6 +595,9 @@ void key(unsigned char key, int mouse_x, int mouse_y)
           s.camera.rotation);
         break;
       }
+    case ' ':
+      render_to_tga_on_next = !render_to_tga_on_next;
+      break;
     default:
       if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
       {

+ 3 - 1
examples/patches/Makefile

@@ -8,6 +8,8 @@ all: obj example
 
 .PHONY: example
 
+CFLAGS=-g
+
 LIBIGL=../../
 LIBIGL_INC=-I$(LIBIGL)/include
 LIBIGL_LIB=-L$(LIBIGL)/lib -ligl -liglmatlab -liglembree -liglboost
@@ -43,5 +45,5 @@ obj/%.o: %.cpp %.h
 	g++ $(OPENMP) $(AFLAGS) $(CFLAGS) -c $< -o $@ $(INC)
 
 clean:
-	rm -f example.o
+	rm -f $(OBJ_FILES)
 	rm -f example

+ 38 - 18
examples/patches/example.cpp

@@ -23,8 +23,12 @@
 #include <igl/ReAntTweakBar.h>
 #include <igl/get_seconds.h>
 #include <igl/jet.h>
+#include <igl/randperm.h>
+#include <igl/normalize_row_lengths.h>
 #include <igl/boost/manifold_patches.h>
 #include <igl/boost/components.h>
+#include <igl/boost/bfs_orient.h>
+#include <igl/orient_outward.h>
 
 #include <Eigen/Core>
 #include <Eigen/Geometry>
@@ -37,13 +41,14 @@
 #include <iostream>
 
 
-Eigen::MatrixXd V,N,C;
+Eigen::MatrixXd V,C;
 Eigen::VectorXd Vmid,Vmin,Vmax;
 double bbd = 1.0;
 Eigen::MatrixXi F;
 struct State
 {
   igl::Camera camera;
+  Eigen::MatrixXd N;
 } s;
 
 // See README for descriptions
@@ -213,23 +218,23 @@ void lights()
   glEnable(GL_LIGHTING);
   //glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
   glEnable(GL_LIGHT0);
-  float WHITE[4] =  {0.7,0.7,0.7,1.};
-  float GREY[4] =  {0.4,0.4,0.4,1.};
-  float BLACK[4] =  {0.,0.,0.,1.};
+  float WHITE[4] = {1,1,1,1.};
+  float GREY[4] = {0.4,0.4,0.4,1.};
+  float BLACK[4] = {0.,0.,0.,1.};
   float NEAR_BLACK[4] =  {0.1,0.1,0.1,1.};
   Vector4f pos = light_pos;
-  glLightfv(GL_LIGHT0,GL_AMBIENT,GREY);
+  glLightfv(GL_LIGHT0,GL_AMBIENT,BLACK);
   glLightfv(GL_LIGHT0,GL_DIFFUSE,WHITE);
   glLightfv(GL_LIGHT0,GL_SPECULAR,BLACK);
   glLightfv(GL_LIGHT0,GL_POSITION,pos.data());
-  glEnable(GL_LIGHT1);
-  pos(0) *= -1;
-  pos(1) *= -1;
-  pos(2) *= -1;
-  glLightfv(GL_LIGHT1,GL_AMBIENT,BLACK);
-  glLightfv(GL_LIGHT1,GL_DIFFUSE,NEAR_BLACK);
-  glLightfv(GL_LIGHT1,GL_SPECULAR,BLACK);
-  glLightfv(GL_LIGHT1,GL_POSITION,pos.data());
+  //glEnable(GL_LIGHT1);
+  //pos(0) *= -1;
+  //pos(1) *= -1;
+  //pos(2) *= -1;
+  //glLightfv(GL_LIGHT1,GL_AMBIENT,BLACK);
+  //glLightfv(GL_LIGHT1,GL_DIFFUSE,NEAR_BLACK);
+  //glLightfv(GL_LIGHT1,GL_SPECULAR,BLACK);
+  //glLightfv(GL_LIGHT1,GL_POSITION,pos.data());
 }
 
 void display()
@@ -264,7 +269,8 @@ void display()
   // Set material properties
   glEnable(GL_COLOR_MATERIAL);
   glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
-  draw_mesh(V,F,N,C);
+  draw_mesh(V,F,s.N,C);
+
   pop_object();
 
   // Draw a nice floor
@@ -448,7 +454,8 @@ void init_relative()
 {
   using namespace Eigen;
   using namespace igl;
-  per_face_normals(V,F,N);
+  per_face_normals(V,F,s.N);
+  normalize_row_lengths(s.N,s.N);
   Vmax = V.colwise().maxCoeff();
   Vmin = V.colwise().minCoeff();
   Vmid = 0.5*(Vmax + Vmin);
@@ -462,14 +469,20 @@ void init_patches()
   using namespace std;
   VectorXi CC;
   SparseMatrix<int> A;
-  //manifold_patches(F,CC,A);
   components(F,CC);
+  cout<<"There are "<<CC.maxCoeff()+1<<" connected components."<<endl;
+  //manifold_patches(F,CC,A);
+  bfs_orient(F,F,CC);
+  VectorXi I;
+  orient_outward(V,F,CC,F,I);
   C.resize(CC.rows(),3);
   double num_cc = (double)CC.maxCoeff()+1.0;
+  cout<<"There are "<<num_cc<<" 'manifold/orientable' patches."<<endl;
+  randperm(num_cc,I);
   for(int f = 0;f<CC.rows();f++)
   {
     jet(
-      (double)CC(f)/num_cc,
+      (double)I(CC(f))/num_cc,
       C(f,0),
       C(f,1),
       C(f,2));
@@ -510,6 +523,13 @@ void key(unsigned char key, int mouse_x, int mouse_y)
     // ^C
     case char(3):
       exit(0);
+    case 'I':
+    case 'i':
+      {
+        push_undo();
+        s.N *= -1.0;
+        break;
+      }
     case 'z':
     case 'Z':
       if(mod & GLUT_ACTIVE_COMMAND)
@@ -545,7 +565,7 @@ int main(int argc, char * argv[])
   using namespace std;
   using namespace Eigen;
   using namespace igl;
-  string filename = "../shared/cheburashka.obj";
+  string filename = "../shared/truck.obj";
   if(argc < 2)
   {
     cerr<<"Usage:"<<endl<<"    ./example input.obj"<<endl;

+ 1 - 1
examples/patches/temp.rbr

@@ -1,3 +1,3 @@
-camera_rotation: TW_TYPE_QUAT4D -0.118843 -0.81634 -0.535375 -0.181213
+camera_rotation: TW_TYPE_QUAT4D -0.0878474 0.235658 0.0213947 -0.967621
 rotation_type: RotationType two axis fixed up
 

+ 93 - 0
include/igl/boost/bfs_orient.cpp

@@ -0,0 +1,93 @@
+#include "bfs_orient.h"
+#include "manifold_patches.h"
+#include <Eigen/Sparse>
+#include <queue>
+
+template <typename DerivedF, typename DerivedFF, typename DerivedC>
+void igl::bfs_orient(
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedFF> & FF,
+  Eigen::PlainObjectBase<DerivedC> & C)
+{
+  using namespace Eigen;
+  using namespace igl;
+  using namespace std;
+  SparseMatrix<int> A;
+  manifold_patches(F,C,A);
+
+  // number of faces
+  const int m = F.rows();
+  // number of patches
+  const int num_cc = C.maxCoeff()+1;
+  VectorXi seen = VectorXi::Zero(m);
+
+  // Edge sets
+  const int ES[3][2] = {{1,2},{2,0},{0,1}};
+
+  if(&FF != &F)
+  {
+    FF = F;
+  }
+  // loop over patches
+  for(int c = 0;c<num_cc;c++)
+  {
+    queue<int> Q;
+    // find first member of patch c
+    for(int f = 0;f<FF.rows();f++)
+    {
+      if(C(f) == c)
+      {
+        Q.push(f);
+        break;
+      }
+    }
+    assert(!Q.empty());
+    while(!Q.empty())
+    {
+      const int f = Q.front();
+      Q.pop();
+      if(seen(f) > 0)
+      {
+        continue;
+      }
+      seen(f)++;
+      // loop over neighbors of f
+      for(typename SparseMatrix<int>::InnerIterator it (A,f); it; ++it)
+      {
+        // might be some lingering zeros, and skip self-adjacency
+        if(it.value() != 0 && it.row() != f)
+        {
+          const int n = it.row();
+          assert(n != f);
+          // loop over edges of f
+          for(int efi = 0;efi<3;efi++)
+          {
+            // efi'th edge of face f
+            Vector2i ef(FF(f,ES[efi][0]),FF(f,ES[efi][1]));
+            // loop over edges of n
+            for(int eni = 0;eni<3;eni++)
+            {
+              // eni'th edge of face n
+              Vector2i en(FF(n,ES[eni][0]),FF(n,ES[eni][1]));
+              // Match (half-edges go same direction)
+              if(ef(0) == en(0) && ef(1) == en(1))
+              {
+                // flip face n
+                FF.row(n) = FF.row(n).reverse().eval();
+              }
+            }
+          }
+          // add neighbor to queue
+          Q.push(n);
+        }
+      }
+    }
+  }
+
+  // make sure flip is OK if &FF = &F
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+template void igl::bfs_orient<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif

+ 29 - 0
include/igl/boost/bfs_orient.h

@@ -0,0 +1,29 @@
+#ifndef IGL_BFS_ORIENT_H
+#define IGL_BFS_ORIENT_H
+#include <Eigen/Core>
+#include <igl/igl_inline.h>
+
+namespace igl
+{
+  // Consistently orient faces in orientable patches using BFS
+  //
+  // F = bfs_orient(F,V);
+  //
+  // Inputs:
+  //  F  #F by 3 list of faces
+  // Outputs:
+  //  FF  #F by 3 list of faces (OK if same as F)
+  //  C  #F list of component ids
+  //
+  //
+  template <typename DerivedF, typename DerivedFF, typename DerivedC>
+  void bfs_orient(
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    Eigen::PlainObjectBase<DerivedFF> & FF,
+    Eigen::PlainObjectBase<DerivedC> & C);
+};
+#ifdef IGL_HEADER_ONLY
+#  include "bfs_orient.cpp"
+#endif
+
+#endif

+ 29 - 20
include/igl/boost/manifold_patches.cpp

@@ -2,7 +2,9 @@
 #include "components.h"
 #include <igl/sort.h>
 #include <igl/unique.h>
+#include <igl/matlab_format.h>
 #include <vector>
+#include <iostream>
 
 template <typename DerivedF, typename DerivedC, typename AScalar>
 void igl::manifold_patches(
@@ -18,41 +20,48 @@ void igl::manifold_patches(
 
   // List of all "half"-edges: 3*#F by 2
   Matrix<typename DerivedF::Scalar, Dynamic, 2> allE,sortallE,uE;
-  VectorXi IC,_;
-  allE.block(0*F.rows(),0,F.rows(),0) = F.col(1);
-  allE.block(0*F.rows(),0,F.rows(),1) = F.col(2);
-  allE.block(1*F.rows(),0,F.rows(),0) = F.col(2);
-  allE.block(1*F.rows(),0,F.rows(),1) = F.col(0);
-  allE.block(2*F.rows(),0,F.rows(),0) = F.col(0);
-  allE.block(2*F.rows(),0,F.rows(),1) = F.col(1);
+  allE.resize(F.rows()*3,2);
+  Matrix<int,Dynamic,2> IX;
+  VectorXi IA,IC;
+  allE.block(0*F.rows(),0,F.rows(),1) = F.col(1);
+  allE.block(0*F.rows(),1,F.rows(),1) = F.col(2);
+  allE.block(1*F.rows(),0,F.rows(),1) = F.col(2);
+  allE.block(1*F.rows(),1,F.rows(),1) = F.col(0);
+  allE.block(2*F.rows(),0,F.rows(),1) = F.col(0);
+  allE.block(2*F.rows(),1,F.rows(),1) = F.col(1);
   // Sort each row
-  sort(allE,2,true,sortallE,_);
+  sort(allE,2,true,sortallE,IX);
   //IC(i) tells us where to find sortallE(i,:) in uE: 
   // so that sortallE(i,:) = uE(IC(i),:)
-  unique_rows(sortallE,uE,_,IC);
-  // uE2F(e,f) = 1 means face f is adjacent to unique edge e
-  vector<Triplet<AScalar> > uE2Fijv(IC.rows());
+  unique_rows(sortallE,uE,IA,IC);
+  // uE2FT(e,f) = 1 means face f is adjacent to unique edge e
+  vector<Triplet<AScalar> > uE2FTijv(IC.rows());
   for(int e = 0;e<IC.rows();e++)
   {
-    uE2Fijv[e] = Triplet<AScalar>(IC(e),e%F.rows(),1);
+    uE2FTijv[e] = Triplet<AScalar>(e%F.rows(),IC(e),1);
   }
-  SparseMatrix<AScalar> uE2F(uE.rows(),F.rows());
-  uE2F.setFromTriplets(uE2Fijv.begin(),uE2Fijv.end());
+  SparseMatrix<AScalar> uE2FT(F.rows(),uE.rows());
+  uE2FT.setFromTriplets(uE2FTijv.begin(),uE2FTijv.end());
   // kill non-manifold edges
-  for(int j=0; j<uE2F.outerSize();j++)
+  for(int j=0; j<(int)uE2FT.outerSize();j++)
   {
+    int degree = 0;
+    for(typename SparseMatrix<AScalar>::InnerIterator it (uE2FT,j); it; ++it)
+    {
+      degree++;
+    }
     // Iterate over inside
-    for(typename SparseMatrix<AScalar>::InnerIterator it (uE2F,j); it; ++it)
+    if(degree > 2)
     {
-      if(it.value() > 2)
+      for(typename SparseMatrix<AScalar>::InnerIterator it (uE2FT,j); it; ++it)
       {
-        uE2F.coeffRef(it.row(),it.col()) = 0;
+        uE2FT.coeffRef(it.row(),it.col()) = 0;
       }
     }
   }
   // Face-face Adjacency matrix
-  SparseMatrix<AScalar> uE2FT;
-  uE2FT = uE2F.transpose().eval();
+  SparseMatrix<AScalar> uE2F;
+  uE2F = uE2FT.transpose().eval();
   A = uE2FT*uE2F;
   // All ones
   for(int j=0; j<A.outerSize();j++)

+ 85 - 0
include/igl/orient_outward.cpp

@@ -0,0 +1,85 @@
+#include "orient_outward.h"
+#include "per_face_normals.h"
+#include "barycenter.h"
+#include "doublearea.h"
+#include <iostream>
+
+template <
+  typename DerivedV, 
+  typename DerivedF, 
+  typename DerivedC, 
+  typename DerivedFF, 
+  typename DerivedI>
+IGL_INLINE void igl::orient_outward(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::PlainObjectBase<DerivedC> & C,
+  Eigen::PlainObjectBase<DerivedFF> & FF,
+  Eigen::PlainObjectBase<DerivedI> & I)
+{
+  using namespace Eigen;
+  using namespace std;
+  assert(C.rows() == F.rows());
+  assert(F.cols() == 3);
+  assert(V.cols() == 3);
+
+  // number of faces
+  const int m = F.rows();
+  // number of patches
+  const int num_cc = C.maxCoeff()+1;
+  I.resize(num_cc);
+  if(&FF != &F)
+  {
+    FF = F;
+  }
+  PlainObjectBase<DerivedV> N,BC,BCmean;
+  Matrix<typename DerivedV::Scalar,Dynamic,1> A;
+  VectorXd totA(num_cc), dot(num_cc);
+  per_face_normals(V,F,N);
+  barycenter(V,F,BC);
+  doublearea(V,F,A);
+  BCmean.setConstant(num_cc,3,0);
+  // loop over faces
+  for(int f = 0;f<m;f++)
+  {
+    BCmean.row(C(f)) += A(f)*BC.row(f);
+    totA(C(f))++;
+  }
+  // take area weighted average
+  for(int c = 0;c<num_cc;c++)
+  {
+    BCmean.row(c) /= (typename DerivedV::Scalar) totA(c);
+  }
+  // subtract bcmean
+  for(int f = 0;f<m;f++)
+  {
+    BC.row(f) -= BCmean.row(C(f));
+    dot(C(f)) += A(f)*N.row(f).dot(BC.row(f));
+  }
+  // take area weighted average
+  for(int c = 0;c<num_cc;c++)
+  {
+    dot(c) /= (typename DerivedV::Scalar) totA(c);
+    if(dot(c) < 0)
+    {
+      I(c) = true;
+    }else
+    {
+      I(c) = false;
+    }
+  }
+  // flip according to I
+  for(int f = 0;f<m;f++)
+  {
+    if(I(C(f)))
+    {
+      FF.row(f) = FF.row(f).reverse().eval();
+    }
+  }
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+template void igl::orient_outward<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
+

+ 36 - 0
include/igl/orient_outward.h

@@ -0,0 +1,36 @@
+#ifndef IGL_ORIENT_OUTWARD_H
+#define IGL_ORIENT_OUTWARD_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // Orient each component (identified by C) of a mesh (V,F) so the normals on
+  // average point away from the patch's centroid.
+  //
+  // Inputs:
+  //   V  #V by 3 list of vertex positions
+  //   F  #F by 3 list of triangle indices
+  //   C  #F list of components
+  // Outputs:
+  //   FF  #F by 3 list of new triangle indices such that FF(~I,:) = F(~I,:) and
+  //     FF(I,:) = fliplr(F(I,:)) (OK if &FF = &F)
+  //   I  max(C)+1 list of whether face has been flipped
+  template <
+    typename DerivedV, 
+    typename DerivedF, 
+    typename DerivedC, 
+    typename DerivedFF, 
+    typename DerivedI>
+  IGL_INLINE void orient_outward(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::PlainObjectBase<DerivedC> & C,
+    Eigen::PlainObjectBase<DerivedFF> & FF,
+    Eigen::PlainObjectBase<DerivedI> & I);
+};
+
+#ifdef IGL_HEADER_ONLY
+#  include "orient_outward.cpp"
+#endif
+
+#endif

+ 27 - 0
include/igl/randperm.cpp

@@ -0,0 +1,27 @@
+#include "randperm.h"
+#include "colon.h"
+#include <algorithm> 
+
+template <typename DerivedI>
+IGL_INLINE void igl::randperm(
+  const int n,
+  Eigen::PlainObjectBase<DerivedI> & I)
+{
+  Eigen::VectorXi II;
+  igl::colon(0,1,n-1,II);
+  I = II;
+  std::random_shuffle(I.data(),I.data()+n);
+}
+
+template <typename DerivedI>
+IGL_INLINE Eigen::PlainObjectBase<DerivedI> igl::randperm( const int n)
+{
+  Eigen::PlainObjectBase<DerivedI> I;
+  randperm(n,I);
+  return I;
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif

+ 23 - 0
include/igl/randperm.h

@@ -0,0 +1,23 @@
+#ifndef IGL_RANDPERM_H
+#define IGL_RANDPERM_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // Like matlab's randperm(n) but minus 1
+  //
+  // Inputs:
+  //   n  number of elements
+  // Outputs:
+  //   I  n list of rand permutation of 0:n-1
+  template <typename DerivedI>
+  IGL_INLINE void randperm(
+    const int n,
+    Eigen::PlainObjectBase<DerivedI> & I);
+  template <typename DerivedI>
+  IGL_INLINE Eigen::PlainObjectBase<DerivedI> randperm( const int n);
+}
+#ifdef IGL_HEADER_ONLY
+#  include "randperm.cpp"
+#endif
+#endif

+ 6 - 4
include/igl/sort.cpp

@@ -151,12 +151,12 @@ IGL_INLINE void igl::sort2(
   IX.resize(X.rows(),X.cols());
   if(dim==1)
   {
-    IX.row(0) = Eigen::PlainObjectBase<DerivedIX>::Zero(1,IX.cols());
-    IX.row(1) = Eigen::PlainObjectBase<DerivedIX>::Ones (1,IX.cols());
+    IX.row(0).setConstant(0);// = Eigen::PlainObjectBase<DerivedIX>::Zero(1,IX.cols());
+    IX.row(1).setConstant(1);// = Eigen::PlainObjectBase<DerivedIX>::Ones (1,IX.cols());
   }else
   {
-    IX.col(0) = Eigen::PlainObjectBase<DerivedIX>::Zero(IX.rows(),1);
-    IX.col(1) = Eigen::PlainObjectBase<DerivedIX>::Ones (IX.rows(),1);
+    IX.col(0).setConstant(0);// = Eigen::PlainObjectBase<DerivedIX>::Zero(IX.rows(),1);
+    IX.col(1).setConstant(1);// = Eigen::PlainObjectBase<DerivedIX>::Ones (IX.rows(),1);
   }
   // loop over columns (or rows)
   for(int i = 0;i<num_outer;i++)
@@ -216,4 +216,6 @@ template void igl::sort2<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix
 template void igl::sort_new<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::sort<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::sort<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
 #endif

+ 1 - 0
include/igl/sortrows.cpp

@@ -79,4 +79,5 @@ template void igl::sortrows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Mat
 template void igl::sortrows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::sortrows<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::sortrows<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif

+ 1 - 0
include/igl/unique.cpp

@@ -194,4 +194,5 @@ template void igl::unique_rows<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Mat
 template void igl::unique_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::unique_rows<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::unique_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_rows<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif