Browse Source

* completed tutorial example for frame fields

Former-commit-id: 44b1f7471db723438d0e1d2f4cd1fe58ddf7dc07
Daniele Panozzo 11 năm trước cách đây
mục cha
commit
72e5248274

+ 5 - 5
include/igl/comiso/frame_field.cpp

@@ -209,7 +209,7 @@ void FrameInterpolator::interpolateCross()
 
   MatrixXd R = nrosy.getFieldPerFace();
   assert(R.rows() == F.rows());
-  
+
   for (unsigned i=0; i<F.rows(); ++i)
     thetas(i) = vector2theta(TPs[i],R.row(i));
 }
@@ -633,8 +633,8 @@ IGL_INLINE void igl::frame_field(
                                  const Eigen::VectorXi& b,
                                  const Eigen::MatrixXd& bc1,
                                  const Eigen::MatrixXd& bc2,
-                                 Eigen::MatrixXd& F1,
-                                 Eigen::MatrixXd& F2
+                                 Eigen::MatrixXd& FF1,
+                                 Eigen::MatrixXd& FF2
                                  )
 
 {
@@ -657,6 +657,6 @@ IGL_INLINE void igl::frame_field(
 
   // Copy back
   MatrixXd R = field.getFieldPerFace();
-  F1 = R.block(0, 0, R.rows(), 3);
-  F2 = R.block(0, 3, R.rows(), 3);
+  FF1 = R.block(0, 0, R.rows(), 3);
+  FF2 = R.block(0, 3, R.rows(), 3);
 }

+ 4 - 4
include/igl/comiso/frame_field.h

@@ -27,8 +27,8 @@ namespace igl
 //   bc2     #B by 3 list of the constrained second representative vector of the frame field (up to permutation and sign)
 //
 // Outputs:
-//   F1      #F by 3 the first representative vector of the frame field (up to permutation and sign)
-//   F2      #F by 3 the second representative vector of the frame field (up to permutation and sign)
+//   FF1      #F by 3 the first representative vector of the frame field (up to permutation and sign)
+//   FF2      #F by 3 the second representative vector of the frame field (up to permutation and sign)
 //
 // TODO: it now supports only soft constraints, should be extended to support both hard and soft constraints
 IGL_INLINE void frame_field(
@@ -37,8 +37,8 @@ IGL_INLINE void frame_field(
   const Eigen::VectorXi& b,
   const Eigen::MatrixXd& bc1,
   const Eigen::MatrixXd& bc2,
-  Eigen::MatrixXd& F1,
-  Eigen::MatrixXd& F2
+  Eigen::MatrixXd& FF1,
+  Eigen::MatrixXd& FF2
   );
 }
 

+ 32 - 0
include/igl/dot_row.cpp

@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "igl/dot_row.h"
+
+using namespace Eigen;
+
+namespace igl
+{
+
+  template <typename DerivedV>
+  IGL_INLINE Eigen::PlainObjectBase<DerivedV> dot_row(
+    const Eigen::PlainObjectBase<DerivedV>& A,
+    const Eigen::PlainObjectBase<DerivedV>& B
+    )
+  {
+    assert(A.rows() == B.rows());
+    assert(A.cols() == B.cols());
+
+    return (A.array() * B.array()).rowwise().sum();
+  }
+
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+// generated by autoexplicit.sh
+#endif

+ 39 - 0
include/igl/dot_row.h

@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DOT_ROW_H
+#define IGL_DOT_ROW_H
+
+#include "igl/igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+  // Compute the dot product between each row of A and B
+  // Templates:
+  //   DerivedV derived from vertex positions matrix type: i.e. MatrixXd
+  //   DerivedF derived from face indices matrix type: i.e. MatrixXi
+  // Inputs:
+  //   A  eigen matrix r by c
+  //   B  eigen matrix r by c
+  // Outputs:
+  //   d a column vector with r entries that contains the dot product of each corresponding row of A and B
+  //
+  // See also: adjacency_matrix
+  template <typename DerivedV>
+  IGL_INLINE Eigen::PlainObjectBase<DerivedV> dot_row(
+    const Eigen::PlainObjectBase<DerivedV>& A,
+    const Eigen::PlainObjectBase<DerivedV>& B
+    );
+
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "dot_row.cpp"
+#endif
+
+#endif

+ 58 - 0
include/igl/frame_to_cross_field.cpp

@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "frame_to_cross_field.h"
+#include <igl/local_basis.h>
+#include <igl/dot_row.h>
+
+IGL_INLINE void igl::frame_to_cross_field(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  const Eigen::MatrixXd& FF1,
+  const Eigen::MatrixXd& FF2,
+  Eigen::MatrixXd& X)
+{
+  using namespace Eigen;
+
+  // Generate local basis
+  MatrixXd B1, B2, B3;
+
+  igl::local_basis(V,F,B1,B2,B3);
+
+  // Project the frame fields in the local basis
+  MatrixXd d1, d2;
+  d1.resize(F.rows(),2);
+  d2.resize(F.rows(),2);
+
+  d1 << igl::dot_row(B1,FF1), igl::dot_row(B2,FF1);
+  d2 << igl::dot_row(B1,FF2), igl::dot_row(B2,FF2);
+
+  X.resize(F.rows(), 3);
+
+	for (int i=0;i<F.rows();i++)
+	{
+		Vector2d v1 = d1.row(i);
+		Vector2d v2 = d2.row(i);
+
+    // define inverse map that maps the canonical axis to the given frame directions
+		Matrix2d A;
+		A <<    v1[0], v2[0],
+            v1[1], v2[1];
+
+		// find the closest rotation
+		Eigen::JacobiSVD<Matrix<double,2,2> > svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV );
+    Matrix2d C = svd.matrixU() * svd.matrixV().transpose();
+
+    Vector2d v = C.col(0);
+    X.row(i) = v(0) * B1.row(i) + v(1) * B2.row(i);
+  }
+}
+
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+#endif

+ 39 - 0
include/igl/frame_to_cross_field.h

@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FRAME_TO_CROSS_FIELD_H
+#define IGL_FRAME_TO_CROSS_FIELD_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+  // Convert a frame field into its closest cross field
+  // Inputs:
+  //   V       #V by 3 coordinates of the vertices
+  //   F       #F by 3 list of mesh faces (must be triangles)
+  //   FF1     #F by 3 the first representative vector of the frame field (up to permutation and sign)
+  //   FF2     #F by 3 the second representative vector of the frame field (up to permutation and sign)
+  //
+  // Outputs:
+  //   X       #F by 3 representative vector of the closest cross field
+  //
+  IGL_INLINE void frame_to_cross_field(
+    const Eigen::MatrixXd& V,
+    const Eigen::MatrixXi& F,
+    const Eigen::MatrixXd& FF1,
+    const Eigen::MatrixXd& FF2,
+    Eigen::MatrixXd& X);
+
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "frame_to_cross_field.cpp"
+#endif
+
+#endif

+ 83 - 32
tutorial/506_FrameField/main.cpp

@@ -8,6 +8,7 @@
 #include <igl/comiso/frame_field.h>
 #include <igl/frame_field_deformer.h>
 #include <igl/jet.h>
+#include <igl/frame_to_cross_field.h>
 
 // Input mesh
 Eigen::MatrixXd V;
@@ -39,13 +40,29 @@ Eigen::MatrixXd FF2_deformed;
 Eigen::MatrixXd X1_deformed;
 Eigen::MatrixXd X2_deformed;
 
-// Quad mesh on deformed
-Eigen::MatrixXd V_quad_deformed;
-Eigen::MatrixXi F_quad_deformed;
+// Global parametrization
+Eigen::MatrixXd V_uv;
+Eigen::MatrixXi F_uv;
 
-// Quad mesh
-Eigen::MatrixXd V_quad;
-Eigen::MatrixXi F_quad;
+// Create a texture that hides the integer translation in the parametrization
+void line_texture(Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> &texture_R,
+                  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> &texture_G,
+                  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> &texture_B)
+{
+  unsigned size = 128;
+  unsigned size2 = size/2;
+  unsigned lineWidth = 3;
+  texture_R.setConstant(size, size, 255);
+  for (unsigned i=0; i<size; ++i)
+    for (unsigned j=size2-lineWidth; j<=size2+lineWidth; ++j)
+      texture_R(i,j) = 0;
+  for (unsigned i=size2-lineWidth; i<=size2+lineWidth; ++i)
+    for (unsigned j=0; j<size; ++j)
+      texture_R(i,j) = 0;
+  
+  texture_G = texture_R;
+  texture_B = texture_R;
+}
 
 bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
 {
@@ -112,8 +129,8 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
   {
     // Deformed with frame field
     viewer.set_mesh(V_deformed, F);
-    viewer.add_edges (B_deformed, B_deformed + global_scale*FF1_deformed ,Eigen::RowVector3d(1,0,0));
-    viewer.add_edges (B_deformed, B_deformed + global_scale*FF2_deformed ,Eigen::RowVector3d(0,0,1));
+    viewer.add_edges (B_deformed - global_scale*FF1_deformed, B_deformed + global_scale*FF1_deformed ,Eigen::RowVector3d(1,0,0));
+    viewer.add_edges (B_deformed - global_scale*FF2_deformed, B_deformed + global_scale*FF2_deformed ,Eigen::RowVector3d(0,0,1));
     viewer.set_colors(RowVector3d(1,1,1));
   }
 
@@ -121,22 +138,34 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
   {
     // Deformed with cross field
     viewer.set_mesh(V_deformed, F);
-    viewer.add_edges (B, B + global_scale*X1_deformed ,Eigen::RowVector3d(1,0,0));
-    viewer.add_edges (B, B + global_scale*X2_deformed ,Eigen::RowVector3d(0,0,1));
+    viewer.add_edges (B_deformed - global_scale*X1_deformed, B_deformed + global_scale*X1_deformed ,Eigen::RowVector3d(0,0,1));
+    viewer.add_edges (B_deformed - global_scale*X2_deformed, B_deformed + global_scale*X2_deformed ,Eigen::RowVector3d(0,0,1));
+    viewer.set_colors(RowVector3d(1,1,1));
   }
 
   if (key == '5')
   {
-    // Deformed with quad mesh
-    viewer.set_mesh(V_quad_deformed, F_quad_deformed);
+    // Deformed with quad texture
+    viewer.set_mesh(V_deformed, F);
+    viewer.set_uv(V_uv,F_uv);
+    viewer.set_colors(RowVector3d(1,1,1));
+    viewer.options.show_texture = true;
   }
 
   if (key == '6')
   {
-    // Deformed with quad mesh
-    viewer.set_mesh(V_quad, F_quad);
+    // Deformed with quad texture
+    viewer.set_mesh(V, F);
+    viewer.set_uv(V_uv,F_uv);
+    viewer.set_colors(RowVector3d(1,1,1));
+    viewer.options.show_texture = true;
   }
 
+  // Replace the standard texture with an integer shift invariant texture
+  Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic> texture_R, texture_G, texture_B;
+  line_texture(texture_R, texture_G, texture_B);
+  viewer.set_texture(texture_R, texture_B, texture_G);
+
   return false;
 }
 
@@ -160,23 +189,6 @@ int main(int argc, char *argv[])
   b   = temp.block(0,0,temp.rows(),1).cast<int>();
   bc1 = temp.block(0,1,temp.rows(),3);
   bc2 = temp.block(0,4,temp.rows(),3);
-
-//  // Load a mesh in OBJ format
-//  igl::readOFF("../shared/planexy.off", V, F);
-//  
-//  // Compute face barycenters
-//  igl::barycenter(V, F, B);
-//  
-//  // Compute scale for visualizing fields
-//  global_scale =  .2*igl::avg_edge_length(V, F);
-//  
-//  b.resize(1);
-//  b << 0;
-//  bc1.resize(1,3);
-//  bc1 << (V.row(F(0,0)) - V.row(F(0,1))).normalized();
-//  MatrixXd B1,B2,B3;
-//  igl::local_basis(V,F,B1,B2,B3);
-//  bc2 = igl::rotate_vectors(bc1, VectorXd::Constant(1,M_PI/2), B1, B2);
   
   // Interpolate the frame field
   igl::frame_field(V, F, b, bc1, bc2, FF1, FF2);
@@ -187,9 +199,48 @@ int main(int argc, char *argv[])
   // Compute face barycenters deformed mesh
   igl::barycenter(V_deformed, F, B_deformed);
 
+  // Find the closest crossfield to the deformed frame field
+  igl::frame_to_cross_field(V,F,FF1_deformed,FF2_deformed,X1_deformed);
+  
+  // Find a smooth crossfield that interpolates the deformed constraints
+  MatrixXd bc_x(b.size(),3);
+  for (unsigned i=0; i<b.size();++i)
+    bc_x.row(i) = X1_deformed.row(b(i));
+  
+  VectorXd S;
+  igl::nrosy(
+             V,
+             F,
+             b,
+             bc_x,
+             VectorXi(),
+             VectorXd(),
+             MatrixXd(),
+             4,
+             0.5,
+             X1_deformed,
+             S);
+
+  // The other representative of the cross field is simply rotated by 90 degrees
+  MatrixXd B1,B2,B3;
+  igl::local_basis(V_deformed,F,B1,B2,B3);
+  X2_deformed = igl::rotate_vectors(X1_deformed, VectorXd::Constant(1,M_PI/2), B1, B2);
+
+  // Global seamless parametrization
+  igl::miq(V_deformed,
+           F,
+           X1_deformed,
+           X2_deformed,
+           V_uv,
+           F_uv,
+           60.0,
+           5.0,
+           false,
+           0);
+
   igl::Viewer viewer;
   // Plot the original mesh with a texture parametrization
-  key_down(viewer,'1',0);
+  key_down(viewer,'6',0);
 
   // Launch the viewer
   viewer.callback_key_down = &key_down;

+ 1 - 0
tutorial/shared/cube.dmat.REMOVED.git-id

@@ -0,0 +1 @@
+0cf31a9c14c209589d958925048d56edf39a9b19

+ 1 - 0
tutorial/shared/cube.obj.REMOVED.git-id

@@ -0,0 +1 @@
+7035c05d19a50c3d9e1197f385914604708f4038