Browse Source

- new tutorial example for harmonic parametrization
- fixed compilation bug in min_quad_with_fixed


Former-commit-id: f2c092f207a25f5fe7099fefa1a92f86590baf2c

Daniele Panozzo 11 years ago
parent
commit
abd3989efb

+ 101 - 0
include/igl/boundary_vertices_sorted.cpp

@@ -0,0 +1,101 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@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 "boundary_vertices_sorted.h"
+
+#include "igl/tt.h"
+#include "igl/vf.h"
+
+IGL_INLINE void igl::boundary_vertices_sorted(
+    const Eigen::MatrixXd& V,
+    const Eigen::MatrixXi& F,
+    Eigen::VectorXi& b)
+{
+  std::vector<int> bnd;
+  bnd.clear();
+  std::vector<bool> isVisited(V.rows(),false);
+
+  Eigen::MatrixXi TT,TTi;
+  std::vector<std::vector<int> > VF, VFi;
+  igl::tt(V,F,TT,TTi);
+  igl::vf(V,F,VF,VFi);
+
+  // Extract one boundary edge
+  bool done = false;
+  for (int i = 0; i < TT.rows() && !done; i++)
+  {
+    for (int j = 0; j < TT.cols(); j++)
+    {
+      if (TT(i,j) < 0)
+      {
+        int idx1, idx2;
+        idx1 = F(i,j);
+        idx2 = F(i,(j+1) % F.cols());
+        bnd.push_back(idx1);
+        bnd.push_back(idx2);
+        isVisited[idx1] = true;
+        isVisited[idx2] = true;
+        done = true;
+        break;
+      }
+    }
+  }
+
+  // Traverse boundary
+  while(1)
+  {
+    bool changed = false;
+    int lastV;
+    lastV = bnd[bnd.size()-1];
+
+    for (int i = 0; i < VF[lastV].size(); i++)
+    {
+      int curr_neighbor = VF[lastV][i];
+
+      if (TT.row(curr_neighbor).minCoeff() < 0.) // Face contains boundary edge
+      {
+        int idx_lastV_in_face;
+        if (F(curr_neighbor,0) == lastV) idx_lastV_in_face = 0;
+        if (F(curr_neighbor,1) == lastV) idx_lastV_in_face = 1;
+        if (F(curr_neighbor,2) == lastV) idx_lastV_in_face = 2;
+
+        int idx_prev = (idx_lastV_in_face + F.cols()-1) % F.cols();
+        int idx_next = (idx_lastV_in_face + 1) % F.cols();
+        bool isPrevVisited = isVisited[F(curr_neighbor,idx_prev)];
+        bool isNextVisited = isVisited[F(curr_neighbor,idx_next)];
+
+        bool gotBndEdge = false;
+        int next_bnd_vertex;
+        if (!isNextVisited && TT(curr_neighbor,idx_lastV_in_face) < 0)
+        {
+          next_bnd_vertex = idx_next;
+          gotBndEdge = true;
+        }
+        else if (!isPrevVisited && TT(curr_neighbor,(idx_lastV_in_face+2) % F.cols()) < 0)
+        {
+          next_bnd_vertex = idx_prev;
+          gotBndEdge = true;
+        }
+
+        if (gotBndEdge)
+        {
+          changed = true;
+          bnd.push_back(F(curr_neighbor,next_bnd_vertex));
+          isVisited[F(curr_neighbor,next_bnd_vertex)] = true;
+          break;
+        }
+      }
+    }
+
+    if (!changed)
+      break;
+  }
+
+  b.resize(bnd.size());
+  for(unsigned i=0;i<bnd.size();++i)
+    b(i) = bnd[i];
+}

+ 35 - 0
include/igl/boundary_vertices_sorted.h

@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@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_BOUNDARYVERTICESSORTED_H
+#define IGL_BOUNDARYVERTICESSORTED_H
+#include <igl/igl_inline.h>
+
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl
+{
+
+  // Compute sorted list of boundary vertices for mesh with single boundary.
+  //
+  // Inputs:
+  //   V  #V by dim list of mesh vertex positions
+  //   F  #V by dim list of mesh faces
+  // Outputs:
+  //   bnd   sorted list of boundary vertex indices
+  IGL_INLINE void boundary_vertices_sorted(
+  	const Eigen::MatrixXd& V, 
+  	const Eigen::MatrixXi& F, 
+    Eigen::VectorXi& bnd);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "boundary_vertices_sorted.cpp"
+#endif
+
+#endif

+ 59 - 0
include/igl/map_vertices_to_circle.cpp

@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@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 "map_vertices_to_circle.h"
+
+#include <Eigen/Sparse>
+
+#include "igl/cotmatrix.h"
+#include "igl/boundary_vertices_sorted.h"
+
+IGL_INLINE void igl::map_vertices_to_circle(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  const Eigen::VectorXi& bnd,
+  Eigen::MatrixXd& UV)
+{
+  // Get sorted list of boundary vertices
+  std::vector<int> interior,map_ij;
+  map_ij.resize(V.rows());
+
+  std::vector<bool> isOnBnd(V.rows(),false);
+  for (int i = 0; i < bnd.size(); i++)
+  {
+    isOnBnd[bnd[i]] = true;
+    map_ij[bnd[i]] = i;
+  }
+
+  for (int i = 0; i < isOnBnd.size(); i++)
+  {
+    if (!isOnBnd[i])
+    {
+      map_ij[i] = interior.size();
+      interior.push_back(i);
+    }
+  }
+
+  // Map boundary to unit circle
+  std::vector<double> len(bnd.size());
+  len[0] = 0.;
+
+  for (int i = 1; i < bnd.size(); i++)
+  {
+    len[i] = len[i-1] + (V.row(bnd[i-1]) - V.row(bnd[i])).norm();
+  }
+  double total_len = len[len.size()-1] + (V.row(bnd[0]) - V.row(bnd[bnd.size()-1])).norm();
+
+  UV.resize(bnd.size(),2);
+  for (int i = 0; i < bnd.size(); i++)
+  {
+    double frac = len[i] * 2. * M_PI / total_len;
+    UV.row(map_ij[bnd[i]]) << cos(frac), sin(frac);
+  }
+
+}

+ 37 - 0
include/igl/map_vertices_to_circle.h

@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@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_MAPVERTICESTOCIRCLE_H
+#define IGL_MAPVERTICESTOCIRCLE_H
+#include <igl/igl_inline.h>
+
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl
+{
+
+  // Map the vertices whose indices are in b on the unit circle.
+  //
+  // Inputs:
+  //   V  #V by dim list of mesh vertex positions
+  //   F  #V by dim list of mesh faces
+  //   b  #W list of vertex ids
+  // Outputs:
+  //   UV   #W by 2 list of 2D position on the unit circle for the vertices in b
+  IGL_INLINE void map_vertices_to_circle(
+  	const Eigen::MatrixXd& V,
+  	const Eigen::MatrixXi& F,
+    const Eigen::VectorXi& b,
+  	Eigen::MatrixXd& UV);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "map_vertices_to_circle.cpp"
+#endif
+
+#endif

+ 10 - 11
include/igl/min_quad_with_fixed.h

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@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 
+//
+// 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_MIN_QUAD_WITH_FIXED_H
 #define IGL_MIN_QUAD_WITH_FIXED_H
@@ -13,7 +13,6 @@
 #include <Eigen/Core>
 #include <Eigen/Dense>
 #include <Eigen/Sparse>
-#include <Eigen/SparseExtra>
 // Bug in unsupported/Eigen/SparseExtra needs iostream first
 #include <iostream>
 #include <unsupported/Eigen/SparseExtra>
@@ -56,9 +55,9 @@ namespace igl
     );
 
   // Solves a system previously factored using min_quad_with_fixed_precompute
-  // 
+  //
   // Template:
-  //   T  type of sparse matrix (e.g. double) 
+  //   T  type of sparse matrix (e.g. double)
   //   DerivedY  type of Y (e.g. derived from VectorXd or MatrixXd)
   //   DerivedZ  type of Z (e.g. derived from VectorXd or MatrixXd)
   // Inputs:
@@ -72,9 +71,9 @@ namespace igl
   // Returns true on success, false on error
   template <
     typename T,
-    typename DerivedB, 
+    typename DerivedB,
     typename DerivedY,
-    typename DerivedBeq, 
+    typename DerivedBeq,
     typename DerivedZ,
     typename Derivedsol>
   IGL_INLINE bool min_quad_with_fixed_solve(
@@ -87,9 +86,9 @@ namespace igl
   // Wrapper without sol
   template <
     typename T,
-    typename DerivedB, 
+    typename DerivedB,
     typename DerivedY,
-    typename DerivedBeq, 
+    typename DerivedBeq,
     typename DerivedZ>
   IGL_INLINE bool min_quad_with_fixed_solve(
     const min_quad_with_fixed_data<T> & data,

+ 16 - 4
include/igl/viewer/Viewer.cpp

@@ -2151,10 +2151,22 @@ namespace igl
   void Viewer::set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
   {
     using namespace std;
+
+    Eigen::MatrixXd V_temp;
+    
+    // If V only has two columns, pad with a column of zeros
+    if (V.cols() == 2)
+    {
+      V_temp = Eigen::MatrixXd::Zero(V.rows(),3);
+      V_temp.block(0,0,V.rows(),2) = V;
+    }
+    else
+      V_temp = V;
+
     if (data.V.rows() == 0 && data.F.rows() == 0)
     {
       clear_mesh();
-      data.V = V;
+      data.V = V_temp;
       data.F = F;
 
       compute_normals();
@@ -2169,7 +2181,7 @@ namespace igl
     {
       if (data.V.rows() == V.rows() && data.F.rows() == F.rows())
       {
-        data.V = V;
+        data.V = V_temp;
         data.F = F;
         alignCameraCenter();
       }
@@ -2249,7 +2261,7 @@ namespace igl
 
   }
 
-  void Viewer::set_UV(const Eigen::MatrixXd& UV)
+  void Viewer::set_uv(const Eigen::MatrixXd& UV)
   {
     using namespace std;
     if (UV.rows() == data.V.rows())
@@ -2262,7 +2274,7 @@ namespace igl
     data.dirty |= DIRTY_UV;
   }
 
-  void Viewer::set_UV(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
+  void Viewer::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
   {
     set_face_based(true);
     data.V_uv = UV_V;

+ 2 - 2
include/igl/viewer/Viewer.h

@@ -357,8 +357,8 @@ namespace igl
     // Inputs:
     //   C  #V|#F|1 by 3 list of colors
     void set_colors(const Eigen::MatrixXd &C);
-    void set_UV(const Eigen::MatrixXd& UV);
-    void set_UV(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F);
+    void set_uv(const Eigen::MatrixXd& UV);
+    void set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F);
     void set_texture(
                       const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& R,
                       const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,

+ 3 - 3
tutorial/104_Events/main.cpp

@@ -15,12 +15,12 @@ bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
     // Draw_mesh creates or updates the vertices and faces of the displayed mesh.
     // If a mesh is already displayed, draw_mesh returns an error if the given V and
     // F have size different than the current ones
-    viewer.draw_mesh(V1, F1);
+    viewer.set_mesh(V1, F1);
   }
   else if (key == '2')
   {
     viewer.clear_mesh();
-    viewer.draw_mesh(V2, F2);
+    viewer.set_mesh(V2, F2);
   }
 
   return false;
@@ -37,6 +37,6 @@ int main(int argc, char *argv[])
   // Register a keyboard callback that allows to switch between
   // the two loaded meshes
   viewer.callback_key_down = &key_down;
-  viewer.draw_mesh(V1, F1);
+  viewer.set_mesh(V1, F1);
   viewer.launch();
 }

+ 11 - 0
tutorial/501_HarmonicParam/CMakeLists.txt

@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.6)
+project(501_HarmonicParam)
+
+include("../CMakeLists.shared")
+
+set(SOURCES
+${PROJECT_SOURCE_DIR}/main.cpp
+)
+
+add_executable(${CMAKE_PROJECT_NAME} ${SOURCES} ${SHARED_SOURCES})
+target_link_libraries(${CMAKE_PROJECT_NAME} ${SHARED_LIBRARIES})

+ 58 - 0
tutorial/501_HarmonicParam/main.cpp

@@ -0,0 +1,58 @@
+#include <igl/readOFF.h>
+#include <igl/viewer/Viewer.h>
+#include <igl/boundary_vertices_sorted.h>
+#include <igl/map_vertices_to_circle.h>
+#include <igl/harmonic.h>
+
+Eigen::MatrixXd V;
+Eigen::MatrixXi F;
+Eigen::MatrixXd V_uv;
+
+bool key_down(igl::Viewer& viewer, unsigned char key, int modifier)
+{
+  if (key == '1')
+    // Plot the 3D mesh
+    viewer.set_mesh(V,F);
+  else if (key == '2')
+    // Plot the mesh in 2D using the UV coordinates as vertex coordinates
+    viewer.set_mesh(V_uv,F);
+
+  viewer.compute_normals();
+
+  return false;
+}
+
+int main(int argc, char *argv[])
+{
+  // Load a mesh in OFF format
+  igl::readOFF("../shared/camelhead.off", V, F);
+
+  // Find the open boundary
+  Eigen::VectorXi bnd;
+  igl::boundary_vertices_sorted(V,F,bnd);
+
+  // Map the boundary to a circle, preserving edge proportions
+  Eigen::MatrixXd bnd_uv;
+  igl::map_vertices_to_circle(V,F,bnd,bnd_uv);
+
+  // Harmonic parametrization for the internal vertices
+  igl::harmonic(V,F,bnd,bnd_uv,1,V_uv);
+
+  // Scale UV to make the texture more clear
+  V_uv *= 5;
+
+  // Plot the mesh
+  igl::Viewer viewer;
+  viewer.set_mesh(V, F);
+  viewer.set_uv(V_uv);
+  viewer.callback_key_down = &key_down;
+
+  // Disable wireframe
+  viewer.options.show_lines = false;
+
+  // Draw checkerboard texture
+  viewer.options.show_texture = true;
+
+  // Launch the viewer
+  viewer.launch();
+}

+ 1 - 0
tutorial/shared/camelhead.off.REMOVED.git-id

@@ -0,0 +1 @@
+9bfd194b1bc4dd4b10e394f41b05e91643a64779

+ 1 - 0
tutorial/shared/lion.off.REMOVED.git-id

@@ -0,0 +1 @@
+6aa7cd79a038749b98f9f2602e4829037295bcc7