Selaa lähdekoodia

- reorganized PVF tutorials

Former-commit-id: b14137eaaf1ce64968db42b67d084e378b94a394
Daniele Panozzo 11 vuotta sitten
vanhempi
commit
629420a275

+ 14 - 15
tutorial/507_PolyVectorField/main.cpp

@@ -21,15 +21,12 @@ double global_scale;
 Eigen::VectorXi isConstrained;
 Eigen::VectorXi isConstrained;
 std::vector<Eigen::MatrixXd> constraints;
 std::vector<Eigen::MatrixXd> constraints;
 
 
-
-
-
 bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 {
 {
   using namespace std;
   using namespace std;
   using namespace Eigen;
   using namespace Eigen;
 
 
-  if (key <'0' || key >'4')
+  if (key <'1' || key >'4')
     return false;
     return false;
 
 
   viewer.clear();
   viewer.clear();
@@ -39,32 +36,35 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 
 
   int num = key  - '0';
   int num = key  - '0';
 
 
-  if (num == 0)
-    return false;
   // Interpolate
   // Interpolate
-  cerr<<"Interpolating for n = "<<num<<"... ";
-  // Interpolated polyVector field
+  cerr<<"Interpolating N-PolyVector field for N = "<<num<<"... ";
+
+  // Interpolated PolyVector field
   Eigen::MatrixXd pvf;
   Eigen::MatrixXd pvf;
   igl::n_polyvector(V, F, isConstrained, constraints[num-1], pvf);
   igl::n_polyvector(V, F, isConstrained, constraints[num-1], pvf);
-  cerr<<"done." <<endl;
 
 
   // Highlight in red the constrained faces
   // Highlight in red the constrained faces
   MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
   MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
   for (unsigned i=0; i<F.rows();++i)
   for (unsigned i=0; i<F.rows();++i)
     if (isConstrained[i])
     if (isConstrained[i])
-      C.row(i) << 1, 0, 0;
+    C.row(i) << 1, 0, 0;
   viewer.set_colors(C);
   viewer.set_colors(C);
 
 
-  for (int n =0; n<num; ++n)
+  for (int n=0; n<num; ++n)
   {
   {
     // Frame field constraints
     // Frame field constraints
     MatrixXd F_t = MatrixXd::Zero(F.rows(),3);
     MatrixXd F_t = MatrixXd::Zero(F.rows(),3);
     for (unsigned i=0; i<F.rows();++i)
     for (unsigned i=0; i<F.rows();++i)
       if (isConstrained[i])
       if (isConstrained[i])
         F_t.row(i) = constraints[num-1].block(i,n*3,1,3);
         F_t.row(i) = constraints[num-1].block(i,n*3,1,3);
+    viewer.add_edges (B, B + global_scale*F_t , Eigen::RowVector3d(0,0,1));
+
     const Eigen::MatrixXd &pvf_t = pvf.block(0,n*3,F.rows(),3);
     const Eigen::MatrixXd &pvf_t = pvf.block(0,n*3,F.rows(),3);
-    viewer.add_edges (B - global_scale*F_t, B + global_scale*F_t , Eigen::RowVector3d(0,0,1));
-    viewer.add_edges (B - global_scale*pvf_t, B + global_scale*pvf_t , Eigen::RowVector3d(0,1,0));
+    for (unsigned i=0; i<F.rows();++i)
+      if (isConstrained[i])
+        F_t.row(i) *= 0;
+
+    viewer.add_edges (B, B + global_scale*pvf_t , Eigen::RowVector3d(0,0,1));
   }
   }
 
 
 
 
@@ -103,8 +103,7 @@ int main(int argc, char *argv[])
 
 
   igl::Viewer viewer;
   igl::Viewer viewer;
 
 
-  // Plot the original mesh with a texture parametrization
-  key_down(viewer,'0',0);
+  key_down(viewer,'5',0);
 
 
   // Launch the viewer
   // Launch the viewer
   viewer.callback_key_down = &key_down;
   viewer.callback_key_down = &key_down;

+ 1 - 1
tutorial/509_AngleBoundPVF/CMakeLists.txt → tutorial/508_ConjugateField/CMakeLists.txt

@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 2.6)
 cmake_minimum_required(VERSION 2.6)
-project(509_AngleBoundPVF)
+project(508_ConjugateField)
 
 
 include("../CMakeLists.shared")
 include("../CMakeLists.shared")
 
 

+ 157 - 0
tutorial/508_ConjugateField/main.cpp

@@ -0,0 +1,157 @@
+#undef IGL_STATIC_LIBRARY
+#include <igl/readOBJ.h>
+#include <igl/readDMAT.h>
+#include <igl/viewer/Viewer.h>
+#include <igl/barycenter.h>
+#include <igl/avg_edge_length.h>
+#include <vector>
+#include <igl/n_polyvector.h>
+#include <igl/conjugate_frame_fields.h>
+#include <stdlib.h>
+#include <igl/readOFF.h>
+#include <igl/jet.h>
+#include <igl/quad_planarity.h>
+#include <igl/planarize_quad_mesh.h>
+
+// Input mesh
+Eigen::MatrixXd V;
+Eigen::MatrixXi F;
+
+// Face barycenters
+Eigen::MatrixXd B;
+
+
+// Quad mesh generated from smooth field
+Eigen::MatrixXd VQS;
+Eigen::MatrixXi FQS;
+Eigen::MatrixXi FQStri;
+Eigen::MatrixXd PQS0, PQS1, PQS2, PQS3;
+
+// Quad mesh generated from conjugate field
+Eigen::MatrixXd VQC;
+Eigen::MatrixXi FQC;
+Eigen::MatrixXi FQCtri;
+Eigen::MatrixXd VQCplan;
+Eigen::MatrixXd PQC0, PQC1, PQC2, PQC3;
+Eigen::MatrixXd PQCp0, PQCp1, PQCp2, PQCp3;
+
+// Scale for visualizing the fields
+double global_scale;
+
+// Input constraints
+Eigen::VectorXi isConstrained;
+Eigen::MatrixXd constraints;
+
+Eigen::MatrixXd smooth_pvf;
+Eigen::MatrixXd conjugate_pvf;
+
+igl::ConjugateFFSolverData<Eigen::MatrixXd, Eigen::MatrixXi> *csdata;
+
+bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
+{
+  using namespace std;
+  using namespace Eigen;
+
+  if (key <'1' || key >'3')
+    return false;
+
+  viewer.clear();
+  viewer.core.show_lines = false;
+  viewer.core.show_texture = false;
+
+  viewer.set_mesh(V, F);
+
+  // Highlight in red the constrained faces
+  MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
+  for (unsigned i=0; i<F.rows();++i)
+    if (isConstrained[i])
+      C.row(i) << 1, 0, 0;
+  viewer.set_colors(C);
+
+  if (key == '1')
+  {
+    // Frame field constraints
+    MatrixXd F1_t = MatrixXd::Zero(F.rows(),3);
+    MatrixXd F2_t = MatrixXd::Zero(F.rows(),3);
+
+    for (unsigned i=0; i<F.rows();++i)
+      if (isConstrained[i])
+      {
+        F1_t.row(i) = constraints.block(i,0,1,3);
+        F2_t.row(i) = constraints.block(i,3,1,3);
+      }
+
+    viewer.add_edges (B - global_scale*F1_t, B + global_scale*F1_t , Eigen::RowVector3d(0,0,1));
+    viewer.add_edges (B - global_scale*F2_t, B + global_scale*F2_t , Eigen::RowVector3d(0,0,1));
+  }
+
+  if (key == '2')
+  {
+    // Interpolated result
+    viewer.add_edges (B - global_scale*smooth_pvf.block(0,0,F.rows(),3),
+                      B + global_scale*smooth_pvf.block(0,0,F.rows(),3),
+                      Eigen::RowVector3d(0,0,1));
+    viewer.add_edges (B - global_scale*smooth_pvf.block(0,3,F.rows(),3),
+                      B + global_scale*smooth_pvf.block(0,3,F.rows(),3),
+                      Eigen::RowVector3d(0,0,1));
+  }
+
+  if (key == '3')
+  {
+    // Conjugate field
+    viewer.add_edges (B - global_scale*conjugate_pvf.block(0,0,F.rows(),3),
+                      B + global_scale*conjugate_pvf.block(0,0,F.rows(),3),
+                      Eigen::RowVector3d(0,0,1));
+    viewer.add_edges (B - global_scale*conjugate_pvf.block(0,3,F.rows(),3),
+                      B + global_scale*conjugate_pvf.block(0,3,F.rows(),3),
+                      Eigen::RowVector3d(0,0,1));
+  }
+
+  return false;
+}
+
+int main(int argc, char *argv[])
+{
+  using namespace Eigen;
+  using namespace std;
+
+  // Load a mesh in OBJ format
+  igl::readOBJ("../shared/inspired_mesh.obj", V, F);
+
+  // Compute face barycenters
+  igl::barycenter(V, F, B);
+
+  // Compute scale for visualizing fields
+  global_scale =  .4*igl::avg_edge_length(V, F);
+
+  // Load constraints
+  MatrixXd temp;
+  igl::readDMAT("../shared/inspired_mesh.dmat",temp);
+  isConstrained = temp.block(0,0,temp.rows(),1).cast<int>();
+  constraints = temp.block(0,1,temp.rows(),temp.cols()-1);
+
+  // Interpolate to get a smooth field
+  igl::n_polyvector(V, F, isConstrained, constraints, smooth_pvf);
+
+  // Initialize conjugate field with smooth field
+  csdata = new igl::ConjugateFFSolverData<Eigen::MatrixXd,Eigen::MatrixXi>(V,F);
+  conjugate_pvf = smooth_pvf;
+
+  // Optimize the field
+  int conjIter = 20;
+  int totalConjIter = 0;
+  double lambdaOrtho = .1;
+  double lambdaInit = 100;
+  double lambdaMultFactor = 1.01;
+  bool doHardConstraints = true;
+  double lambdaOut;
+  igl::conjugate_frame_fields(*csdata, isConstrained, conjugate_pvf, conjugate_pvf, conjIter, lambdaOrtho, lambdaInit, lambdaMultFactor, doHardConstraints,
+                              &lambdaOut);
+
+  // Launch the viewer
+  igl::Viewer viewer;
+  key_down(viewer,'3',0);
+  viewer.core.invert_normals = true;
+  viewer.callback_key_down = &key_down;
+  viewer.launch();
+}

+ 0 - 245
tutorial/508_ConjugatePVF/main.cpp

@@ -1,245 +0,0 @@
-#undef IGL_STATIC_LIBRARY
-#include <igl/readOBJ.h>
-#include <igl/readDMAT.h>
-#include <igl/viewer/Viewer.h>
-#include <igl/barycenter.h>
-#include <igl/avg_edge_length.h>
-#include <vector>
-#include <igl/n_polyvector.h>
-#include <igl/conjugate_frame_fields.h>
-#include <stdlib.h>
-#include <igl/readOFF.h>
-#include <igl/jet.h>
-#include <igl/quad_planarity.h>
-#include <igl/planarize_quad_mesh.h>
-
-// Input mesh
-Eigen::MatrixXd V;
-Eigen::MatrixXi F;
-
-// Face barycenters
-Eigen::MatrixXd B;
-
-
-// Quad mesh generated from smooth field
-Eigen::MatrixXd VQS;
-Eigen::MatrixXi FQS;
-Eigen::MatrixXi FQStri;
-Eigen::MatrixXd PQS0, PQS1, PQS2, PQS3;
-
-// Quad mesh generated from conjugate field
-Eigen::MatrixXd VQC;
-Eigen::MatrixXi FQC;
-Eigen::MatrixXi FQCtri;
-Eigen::MatrixXd VQCplan;
-Eigen::MatrixXd PQC0, PQC1, PQC2, PQC3;
-Eigen::MatrixXd PQCp0, PQCp1, PQCp2, PQCp3;
-
-// Scale for visualizing the fields
-double global_scale;
-
-// Input constraints
-Eigen::VectorXi isConstrained;
-Eigen::MatrixXd constraints;
-
-Eigen::MatrixXd smooth_pvf;
-Eigen::MatrixXd conjugate_pvf;
-
-igl::ConjugateFFSolverData<Eigen::MatrixXd, Eigen::MatrixXi> *csdata;
-
-int conjIter = 2;
-int totalConjIter = 0;
-double lambdaOrtho = .1;
-double lambdaInit = 100;
-double lambdaMultFactor = 1.01;
-bool doHardConstraints = true;
-
-bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
-{
-  using namespace std;
-  using namespace Eigen;
-
-  if (key <'1' || key >'6')
-    return false;
-
-  viewer.clear();
-  viewer.core.show_lines = false;
-  viewer.core.show_texture = false;
-  if (key <= '3')
-  {
-    viewer.set_mesh(V, F);
-    // Highlight in red the constrained faces
-    MatrixXd C = MatrixXd::Constant(F.rows(),3,1);
-    for (unsigned i=0; i<F.rows();++i)
-      if (isConstrained[i])
-        C.row(i) << 1, 0, 0;
-    viewer.set_colors(C);
-  }
-
-  if (key == '1')
-  {
-    // Frame field constraints
-    MatrixXd F1_t = MatrixXd::Zero(F.rows(),3);
-    MatrixXd F2_t = MatrixXd::Zero(F.rows(),3);
-    for (unsigned i=0; i<F.rows();++i)
-      if (isConstrained[i])
-      {
-        F1_t.row(i) = constraints.block(i,0,1,3);
-        F2_t.row(i) = constraints.block(i,3,1,3);
-      }
-    viewer.add_edges (B - global_scale*F1_t, B + global_scale*F1_t , Eigen::RowVector3d(0,0,1));
-    viewer.add_edges (B - global_scale*F2_t, B + global_scale*F2_t , Eigen::RowVector3d(0,0,1));
-
-  }
-  if (key == '2')
-  {
-    viewer.add_edges (B - global_scale*smooth_pvf.block(0,0,F.rows(),3),
-                      B + global_scale*smooth_pvf.block(0,0,F.rows(),3),
-                      Eigen::RowVector3d(0,1,0));
-    viewer.add_edges (B - global_scale*smooth_pvf.block(0,3,F.rows(),3),
-                      B + global_scale*smooth_pvf.block(0,3,F.rows(),3),
-                      Eigen::RowVector3d(0,1,0));
-  }
-
-  if (key == '3')
-  {
-    if (totalConjIter <50)
-    {
-      double lambdaOut;
-      igl::conjugate_frame_fields(*csdata, isConstrained, conjugate_pvf, conjugate_pvf, conjIter, lambdaOrtho, lambdaInit, lambdaMultFactor, doHardConstraints,
-                                  &lambdaOut);
-      totalConjIter += 2;
-      lambdaInit = lambdaOut;
-    }
-    viewer.add_edges (B - global_scale*conjugate_pvf.block(0,0,F.rows(),3),
-                      B + global_scale*conjugate_pvf.block(0,0,F.rows(),3),
-                      Eigen::RowVector3d(0,1,0));
-    viewer.add_edges (B - global_scale*conjugate_pvf.block(0,3,F.rows(),3),
-                      B + global_scale*conjugate_pvf.block(0,3,F.rows(),3),
-                      Eigen::RowVector3d(0,1,0));
-  }
-
-  if (key == '4')
-  {
-    viewer.set_mesh(VQS, FQStri);
-
-    // show planarity
-    VectorXd planarity;
-    igl::quad_planarity( VQS, FQS, planarity);
-    MatrixXd Ct;
-    igl::jet(planarity, 0, 0.02, Ct);
-    MatrixXd C(FQStri.rows(),3);
-    C << Ct, Ct;
-    viewer.set_colors(C);
-
-    viewer.add_edges (PQS0, PQS1, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQS1, PQS2, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQS2, PQS3, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQS3, PQS0, Eigen::RowVector3d(0,0,0));
-
-  }
-
-  if (key == '5')
-  {
-    viewer.set_mesh(VQC, FQCtri);
-
-    // show planarity
-    VectorXd planarity;
-    igl::quad_planarity( VQC, FQC, planarity);
-    MatrixXd Ct;
-    igl::jet(planarity, 0, 0.02, Ct);
-    MatrixXd C(FQCtri.rows(),3);
-    C << Ct, Ct;
-    viewer.set_colors(C);
-
-    viewer.add_edges (PQC0, PQC1, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQC1, PQC2, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQC2, PQC3, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQC3, PQC0, Eigen::RowVector3d(0,0,0));
-  }
-
-  if (key == '6')
-  {
-    igl ::planarize_quad_mesh(VQC, FQC, 50, 0.01, VQCplan);
-    viewer.set_mesh(VQCplan, FQCtri);
-    igl::slice( VQCplan, FQC.col(0), 1, PQCp0);
-    igl::slice( VQCplan, FQC.col(1), 1, PQCp1);
-    igl::slice( VQCplan, FQC.col(2), 1, PQCp2);
-    igl::slice( VQCplan, FQC.col(3), 1, PQCp3);
-
-    // show planarity
-    VectorXd planarity;
-    igl::quad_planarity( VQCplan, FQC, planarity);
-    MatrixXd Ct;
-    igl::jet(planarity, 0, 0.02, Ct);
-    MatrixXd C(FQCtri.rows(),3);
-    C << Ct, Ct;
-    viewer.set_colors(C);
-
-    viewer.add_edges (PQCp0, PQCp1, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQCp1, PQCp2, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQCp2, PQCp3, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQCp3, PQCp0, Eigen::RowVector3d(0,0,0));
-  }
-
-  return false;
-}
-
-int main(int argc, char *argv[])
-{
-  using namespace Eigen;
-  using namespace std;
-  // Load a mesh in OBJ format
-  igl::readOBJ("../shared/inspired_mesh.obj", V, F);
-
-  // Compute face barycenters
-  igl::barycenter(V, F, B);
-
-  // Compute scale for visualizing fields
-  global_scale =  .2*igl::avg_edge_length(V, F);
-
-  // Load constraints
-  MatrixXd temp;
-  igl::readDMAT("../shared/inspired_mesh.dmat",temp);
-  isConstrained = temp.block(0,0,temp.rows(),1).cast<int>();
-  constraints = temp.block(0,1,temp.rows(),temp.cols()-1);
-
-  // Interpolate to get a smooth field
-  igl::n_polyvector(V, F, isConstrained, constraints, smooth_pvf);
-
-  // Initialize conjugate field with smooth field
-  csdata = new igl::ConjugateFFSolverData<Eigen::MatrixXd,Eigen::MatrixXi>(V,F);
-  conjugate_pvf = smooth_pvf;
-
-  // Load quad mesh generated by smooth field
-  igl::readOFF("../shared/inspired_mesh_quads_Smooth.off", VQS, FQS);
-  FQStri.resize(2*FQS.rows(), 3);
-  FQStri <<  FQS.col(0),FQS.col(1),FQS.col(2),
-             FQS.col(2),FQS.col(3),FQS.col(0);
-  igl::slice( VQS, FQS.col(0), 1, PQS0);
-  igl::slice( VQS, FQS.col(1), 1, PQS1);
-  igl::slice( VQS, FQS.col(2), 1, PQS2);
-  igl::slice( VQS, FQS.col(3), 1, PQS3);
-
-
-  // Load quad mesh generated by conjugate field
-  igl::readOFF("../shared/inspired_mesh_quads_Conjugate.off", VQC, FQC);
-  FQCtri.resize(2*FQC.rows(), 3);
-  FQCtri <<  FQC.col(0),FQC.col(1),FQC.col(2),
-             FQC.col(2),FQC.col(3),FQC.col(0);
-  igl::slice( VQC, FQC.col(0), 1, PQC0);
-  igl::slice( VQC, FQC.col(1), 1, PQC1);
-  igl::slice( VQC, FQC.col(2), 1, PQC2);
-  igl::slice( VQC, FQC.col(3), 1, PQC3);
-
-
-
-  igl::Viewer viewer;
-
-  // Plot the original mesh with a texture parametrization
-  key_down(viewer,'1',0);
-
-  // Launch the viewer
-  viewer.callback_key_down = &key_down;
-  viewer.launch();
-}

+ 0 - 264
tutorial/509_AngleBoundPVF/main.cpp

@@ -1,264 +0,0 @@
-#undef IGL_STATIC_LIBRARY
-#include <igl/readOBJ.h>
-#include <igl/readDMAT.h>
-#include <igl/viewer/Viewer.h>
-#include <igl/barycenter.h>
-#include <igl/avg_edge_length.h>
-#include <vector>
-#include <igl/n_polyvector.h>
-#include <igl/angle_bound_frame_fields.h>
-#include <stdlib.h>
-#include <igl/jet.h>
-
-// Input mesh
-Eigen::MatrixXd V;
-Eigen::MatrixXi F;
-
-// Face barycenters
-Eigen::MatrixXd B;
-
-
-// Quad mesh generated from smooth field
-Eigen::MatrixXd VQS;
-Eigen::MatrixXi FQS;
-Eigen::MatrixXi FQStri;
-Eigen::MatrixXd PQS0, PQS1, PQS2, PQS3;
-
-// Quad mesh generated from conjugate field
-Eigen::MatrixXd VQC;
-Eigen::MatrixXi FQC;
-Eigen::MatrixXi FQCtri;
-Eigen::MatrixXd PQC0, PQC1, PQC2, PQC3;
-
-// Scale for visualizing the fields
-double global_scale;
-
-// Input constraints
-Eigen::VectorXi isConstrained;
-Eigen::MatrixXd constraints;
-
-Eigen::MatrixXd smooth_pvf;
-Eigen::MatrixXd angle_bound_pvf;
-
-igl::AngleBoundFFSolverData<Eigen::MatrixXd, Eigen::MatrixXi> *csdata;
-
-int conjIter = 2;
-int totalConjIter = 0;
-double lambdaOrtho = .1;
-double lambdaInit = 100;
-double lambdaMultFactor = 1.5;
-bool doHardConstraints = false;
-
-bool showAngles = true;
-int curr_key = 0;
-
-void computeAngles(const Eigen::MatrixXd &ff, Eigen::VectorXd &angles)
-{
- angles.resize(ff.rows(),1);
-  int num =0;
- for (int i =0; i<ff.rows(); ++i)
- {
-  Eigen::RowVector3d u = (ff.block(i,0,1,3)); u.normalize();
-  Eigen::RowVector3d v = (ff.block(i,3,1,3)); v.normalize();
-  double s = (u.cross(v)).norm();
-  double c = fabs(u.dot(v));
-  angles[i] = atan2(s,c);
-   num += (angles[i]<70*M_PI/180);
-  }
-  std::cerr<<"out of bound:"<<num<<std::endl;
-}
-
-void getAngleColor(const Eigen::MatrixXd &ff, Eigen::MatrixXd &C)
-{
-  Eigen::VectorXd angles;
-  computeAngles(ff, angles);
-  Eigen::VectorXd val = 0.5*M_PI*Eigen::VectorXd::Ones(angles.rows(),1)-angles;
-  igl::jet(val, 0, 20*M_PI/180., C);
-}
-
-bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
-{
-  using namespace std;
-  using namespace Eigen;
-
-  // Highlight in red the constrained faces
-  MatrixXd CC = MatrixXd::Constant(F.rows(),3,1);
-  for (unsigned i=0; i<F.rows();++i)
-    if (isConstrained[i])
-      CC.row(i) << 1, 0, 0;
-
-  if (key == 'c' || key == 'C')
-  {
-    showAngles = !showAngles;
-    if (curr_key == 2)
-    {
-      MatrixXd C = CC;
-      if (showAngles)
-        getAngleColor(smooth_pvf, C);
-      viewer.set_colors(C);
-    }
-    else if (curr_key == 3)
-    {
-      MatrixXd C = CC;
-      if (showAngles)
-        getAngleColor(angle_bound_pvf, C);
-      viewer.set_colors(C);
-    }
-    return false;
-  }
-
-  if (key <'1' || key >'5')
-  {
-    return false;
-  }
-
-  viewer.clear();
-  viewer.core.show_lines = false;
-  viewer.core.show_texture = false;
-
-  if (key == '1')
-  {
-    viewer.set_mesh(V, F);
-    viewer.set_colors(CC);
-    // Frame field constraints
-    MatrixXd F1_t = MatrixXd::Zero(F.rows(),3);
-    MatrixXd F2_t = MatrixXd::Zero(F.rows(),3);
-    for (unsigned i=0; i<F.rows();++i)
-      if (isConstrained[i])
-      {
-        F1_t.row(i) = constraints.block(i,0,1,3);
-        F2_t.row(i) = constraints.block(i,3,1,3);
-      }
-    viewer.add_edges (B - global_scale*F1_t, B + global_scale*F1_t , Eigen::RowVector3d(0,0,1));
-    viewer.add_edges (B - global_scale*F2_t, B + global_scale*F2_t , Eigen::RowVector3d(0,0,1));
-    curr_key = 1;
-  }
-  if (key == '2')
-  {
-    viewer.set_mesh(V, F);
-    viewer.add_edges (B - global_scale*smooth_pvf.block(0,0,F.rows(),3),
-                      B + global_scale*smooth_pvf.block(0,0,F.rows(),3),
-                      Eigen::RowVector3d(0,1,0));
-    viewer.add_edges (B - global_scale*smooth_pvf.block(0,3,F.rows(),3),
-                      B + global_scale*smooth_pvf.block(0,3,F.rows(),3),
-                      Eigen::RowVector3d(0,1,0));
-    MatrixXd C = CC;
-    if (showAngles)
-      getAngleColor(smooth_pvf, C);
-    viewer.set_colors(C);
-    curr_key = 2;
-  }
-
-  if (key == '3')
-  {
-    viewer.set_mesh(V, F);
-    if (totalConjIter <50)
-    {
-      double lambdaOut;
-      igl::angle_bound_frame_fields(*csdata,
-                                     70,
-                                     isConstrained,
-                                     angle_bound_pvf,
-                                     angle_bound_pvf,
-                                     conjIter,
-                                     lambdaInit,
-                                     lambdaMultFactor,
-                                     doHardConstraints,
-                                     &lambdaOut);
-      totalConjIter += conjIter;
-      lambdaInit = lambdaOut;
-    }
-    viewer.add_edges (B - global_scale*angle_bound_pvf.block(0,0,F.rows(),3),
-                      B + global_scale*angle_bound_pvf.block(0,0,F.rows(),3),
-                      Eigen::RowVector3d(0,1,0));
-    viewer.add_edges (B - global_scale*angle_bound_pvf.block(0,3,F.rows(),3),
-                      B + global_scale*angle_bound_pvf.block(0,3,F.rows(),3),
-                      Eigen::RowVector3d(0,1,0));
-    MatrixXd C = CC;
-    if (showAngles)
-      getAngleColor(angle_bound_pvf, C);
-    viewer.set_colors(C);
-    curr_key = 3;
-  }
-
-  if (key == '4')
-  {
-    viewer.set_mesh(VQS, FQStri);
-    viewer.add_edges (PQS0, PQS1, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQS1, PQS2, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQS2, PQS3, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQS3, PQS0, Eigen::RowVector3d(0,0,0));
-    curr_key = 4;
-  }
-
-  if (key == '5')
-  {
-    viewer.set_mesh(VQC, FQCtri);
-    viewer.add_edges (PQC0, PQC1, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQC1, PQC2, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQC2, PQC3, Eigen::RowVector3d(0,0,0));
-    viewer.add_edges (PQC3, PQC0, Eigen::RowVector3d(0,0,0));
-    curr_key = 5;
-  }
-
-
-  return false;
-}
-
-int main(int argc, char *argv[])
-{
-  using namespace Eigen;
-  using namespace std;
-  // Load a mesh in OBJ format
-  igl::readOBJ("../shared/teddy.obj", V, F);
-
-  // Compute face barycenters
-  igl::barycenter(V, F, B);
-
-  // Compute scale for visualizing fields
-  global_scale =  .2*igl::avg_edge_length(V, F);
-
-  // Load constraints
-  MatrixXd temp;
-  igl::readDMAT("../shared/teddy.dmat",temp);
-  isConstrained = temp.block(0,0,temp.rows(),1).cast<int>();
-  constraints = temp.block(0,1,temp.rows(),temp.cols()-1);
-
-  // Interpolate to get a smooth field
-  igl::n_polyvector(V, F, isConstrained, constraints, smooth_pvf);
-
-  // Initialize conjugate field with smooth field
-  csdata = new igl::AngleBoundFFSolverData<Eigen::MatrixXd,Eigen::MatrixXi>(V,F);
-  angle_bound_pvf = smooth_pvf;
-
-  // Load quad mesh generated by smooth field
-  igl::readOBJ("../shared/teddy_smooth_remeshed.obj", VQS, FQS);
-  FQStri.resize(2*FQS.rows(), 3);
-  FQStri <<  FQS.col(0),FQS.col(1),FQS.col(2),
-             FQS.col(2),FQS.col(3),FQS.col(0);
-
-  // Load quad mesh generated by conjugate field
-  igl::readOBJ("../shared/teddy_angle_bound_remeshed.obj", VQC, FQC);
-  FQCtri.resize(2*FQC.rows(), 3);
-  FQCtri <<  FQC.col(0),FQC.col(1),FQC.col(2),
-             FQC.col(2),FQC.col(3),FQC.col(0);
-
-  igl::slice( VQS, FQS.col(0), 1, PQS0);
-  igl::slice( VQS, FQS.col(1), 1, PQS1);
-  igl::slice( VQS, FQS.col(2), 1, PQS2);
-  igl::slice( VQS, FQS.col(3), 1, PQS3);
-
-  igl::slice( VQC, FQC.col(0), 1, PQC0);
-  igl::slice( VQC, FQC.col(1), 1, PQC1);
-  igl::slice( VQC, FQC.col(2), 1, PQC2);
-  igl::slice( VQC, FQC.col(3), 1, PQC3);
-
-  igl::Viewer viewer;
-
-  // Plot the original mesh with a texture parametrization
-  key_down(viewer,'1',0);
-
-  // Launch the viewer
-  viewer.callback_key_down = &key_down;
-  viewer.launch();
-}

+ 1 - 1
tutorial/508_ConjugatePVF/CMakeLists.txt → tutorial/509_Planarization/CMakeLists.txt

@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 2.6)
 cmake_minimum_required(VERSION 2.6)
-project(508_ConjugatePVF)
+project(509_Planarization)
 
 
 include("../CMakeLists.shared")
 include("../CMakeLists.shared")
 
 

+ 113 - 0
tutorial/509_Planarization/main.cpp

@@ -0,0 +1,113 @@
+#include <igl/readOBJ.h>
+#include <igl/readDMAT.h>
+#include <igl/viewer/Viewer.h>
+#include <igl/barycenter.h>
+#include <igl/avg_edge_length.h>
+#include <vector>
+#include <stdlib.h>
+#include <igl/jet.h>
+#include <igl/quad_planarity.h>
+#include <igl/planarize_quad_mesh.h>
+#include <igl/slice.h>
+
+// Quad mesh generated from conjugate field
+Eigen::MatrixXd VQC;
+Eigen::MatrixXi FQC;
+Eigen::MatrixXi FQCtri;
+Eigen::MatrixXd PQC0, PQC1, PQC2, PQC3;
+
+// Planarized quad mesh
+Eigen::MatrixXd VQCplan;
+Eigen::MatrixXi FQCtriplan;
+Eigen::MatrixXd PQC0plan, PQC1plan, PQC2plan, PQC3plan;
+
+
+// Scale for visualizing the fields
+double global_scale;
+
+
+bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
+{
+  using namespace std;
+  using namespace Eigen;
+
+  // Plot the original quad mesh
+  if (key == '1')
+  {
+    // Draw the triangulated quad mesh
+    viewer.set_mesh(VQC, FQCtri);
+
+    // Assign a color to each quad that corresponds to its planarity
+    VectorXd planarity;
+    igl::quad_planarity( VQC, FQC, planarity);
+    MatrixXd Ct;
+    igl::jet(planarity, 0, 0.02, Ct);
+    MatrixXd C(FQCtri.rows(),3);
+    C << Ct, Ct;
+    viewer.set_colors(C);
+
+    // Plot a line for each edge of the quad mesh
+    viewer.add_edges (PQC0, PQC1, Eigen::RowVector3d(0,0,0));
+    viewer.add_edges (PQC1, PQC2, Eigen::RowVector3d(0,0,0));
+    viewer.add_edges (PQC2, PQC3, Eigen::RowVector3d(0,0,0));
+    viewer.add_edges (PQC3, PQC0, Eigen::RowVector3d(0,0,0));
+  }
+
+  // Plot the planarized quad mesh
+  if (key == '2')
+  {
+    // Draw the triangulated quad mesh
+    viewer.set_mesh(VQCplan, FQCtri);
+
+    // Assign a color to each quad that corresponds to its planarity
+    VectorXd planarity;
+    igl::quad_planarity( VQCplan, FQC, planarity);
+    MatrixXd Ct;
+    igl::jet(planarity, 0, 0.02, Ct);
+    MatrixXd C(FQCtri.rows(),3);
+    C << Ct, Ct;
+    viewer.set_colors(C);
+
+    // Plot a line for each edge of the quad mesh
+    viewer.add_edges (PQC0plan, PQC1plan, Eigen::RowVector3d(0,0,0));
+    viewer.add_edges (PQC1plan, PQC2plan, Eigen::RowVector3d(0,0,0));
+    viewer.add_edges (PQC2plan, PQC3plan, Eigen::RowVector3d(0,0,0));
+    viewer.add_edges (PQC3plan, PQC0plan, Eigen::RowVector3d(0,0,0));
+  }
+
+  return false;
+}
+
+int main(int argc, char *argv[])
+{
+  using namespace Eigen;
+  using namespace std;
+
+  // Load a quad mesh generated by a conjugate field
+  igl::readOFF("../shared/inspired_mesh_quads_Conjugate.off", VQC, FQC);
+
+  // Convert it in a triangle mesh
+  FQCtri.resize(2*FQC.rows(), 3);
+  FQCtri <<  FQC.col(0),FQC.col(1),FQC.col(2),
+             FQC.col(2),FQC.col(3),FQC.col(0);
+  igl::slice( VQC, FQC.col(0), 1, PQC0);
+  igl::slice( VQC, FQC.col(1), 1, PQC1);
+  igl::slice( VQC, FQC.col(2), 1, PQC2);
+  igl::slice( VQC, FQC.col(3), 1, PQC3);
+
+  // Planarize it
+  igl::planarize_quad_mesh(VQC, FQC, 100, 0.005, VQCplan);
+
+  // Convert the planarized mesh to triangles
+  igl::slice( VQCplan, FQC.col(0), 1, PQC0plan);
+  igl::slice( VQCplan, FQC.col(1), 1, PQC1plan);
+  igl::slice( VQCplan, FQC.col(2), 1, PQC2plan);
+  igl::slice( VQCplan, FQC.col(3), 1, PQC3plan);
+
+  // Launch the viewer
+  igl::Viewer viewer;
+  key_down(viewer,'2',0);
+  viewer.core.invert_normals = true;
+  viewer.callback_key_down = &key_down;
+  viewer.launch();
+}

+ 3 - 2
tutorial/CMakeLists.txt

@@ -52,9 +52,10 @@ add_subdirectory("504_NRosyDesign")
 add_subdirectory("505_MIQ")
 add_subdirectory("505_MIQ")
 add_subdirectory("506_FrameField")
 add_subdirectory("506_FrameField")
 add_subdirectory("507_PolyVectorField")
 add_subdirectory("507_PolyVectorField")
-add_subdirectory("508_ConjugatePVF")
-add_subdirectory("509_AngleBoundPVF")
+add_subdirectory("508_ConjugateField")
 endif(LIBCOMISO_FOUND)
 endif(LIBCOMISO_FOUND)
+add_subdirectory("509_Planarization")
+
 
 
 # Chapter 6
 # Chapter 6
 add_subdirectory("601_Serialization")
 add_subdirectory("601_Serialization")