Browse Source

Merge branch 'master' of https://github.com/libigl/libigl

Conflicts:
	include/igl/find_cross_field_singularities.cpp
	include/igl/triangle_triangle_adjacency.cpp

Former-commit-id: 68f46289dbebda4bbcc5523dec6b61a401ffea2e
Olga Diamanti 10 years ago
parent
commit
580c57ed4f
44 changed files with 715 additions and 261 deletions
  1. 1 0
      RELEASE_HISTORY.txt
  2. 1 1
      VERSION.txt
  3. 1 1
      build/Makefile.conf
  4. 0 23
      examples/principal_curvature/Makefile
  5. 0 164
      examples/principal_curvature/curvature.cpp
  6. 24 1
      examples/quicklook-mesh/Info.plist
  7. 9 3
      examples/quicklook-mesh/src/render_to_buffer.cpp
  8. 6 1
      file-formats/index.html
  9. 26 0
      include/igl/ReAntTweakBar.cpp
  10. 1 0
      include/igl/ReAntTweakBar.h
  11. 1 0
      include/igl/boolean/mesh_boolean.h
  12. 4 4
      include/igl/boundary_facets.h
  13. 2 2
      include/igl/boundary_loop.h
  14. 7 5
      include/igl/cgal/SelfIntersectMesh.h
  15. 1 1
      include/igl/comiso/miq.cpp
  16. 1 1
      include/igl/cotmatrix.h
  17. 1 1
      include/igl/draw_mesh.cpp
  18. 1 2
      include/igl/embree/reorient_facets_raycast.h
  19. 2 1
      include/igl/find_cross_field_singularities.h
  20. 2 2
      include/igl/internal_angles.cpp
  21. 62 0
      include/igl/outline_ordered.cpp
  22. 35 0
      include/igl/outline_ordered.h
  23. 2 1
      include/igl/peal_outer_hull_layers.cpp
  24. 1 0
      include/igl/ply.h.REMOVED.git-id
  25. 6 0
      include/igl/principal_curvature.cpp
  26. 190 0
      include/igl/readPLY.cpp
  27. 54 0
      include/igl/readPLY.h
  28. 7 0
      include/igl/read_triangle_mesh.cpp
  29. 4 2
      include/igl/read_triangle_mesh.h
  30. 8 7
      include/igl/triangle_triangle_adjacency.cpp
  31. 1 1
      include/igl/viewer/Viewer.cpp
  32. 3 0
      include/igl/viewer/Viewer.h
  33. 8 5
      include/igl/viewer/ViewerPlugin.h
  34. 142 0
      include/igl/writePLY.cpp
  35. 41 0
      include/igl/writePLY.h
  36. 3 2
      tutorial/401_BiharmonicDeformation/main.cpp
  37. 6 1
      tutorial/403_BoundedBiharmonicWeights/CMakeLists.txt
  38. 3 1
      tutorial/609_Boolean/CMakeLists.txt
  39. 12 2
      tutorial/CMakeLists.shared
  40. 5 0
      tutorial/CMakeLists.txt
  41. 8 4
      tutorial/cmake/FindANTTWEAKBAR.cmake
  42. 8 1
      tutorial/cmake/FindGLFW.cmake
  43. 14 19
      tutorial/cmake/FindLIBIGL.cmake
  44. 1 2
      tutorial/cmake/FindMOSEK.cmake

+ 1 - 0
RELEASE_HISTORY.txt

@@ -1,3 +1,4 @@
+1.1.1  PLY file format support
 1.1.0  Mesh boolean operations using CGAL and cork, implementing [Attene 14]
 1.0.3  Bone heat method
 1.0.2  Bug fix in winding number code

+ 1 - 1
VERSION.txt

@@ -3,4 +3,4 @@
 # Anyone may increment Minor to indicate a small change.
 # Major indicates a large change or large number of changes (upload to website)
 # World indicates a substantial change or release
-1.1.0
+1.1.1

+ 1 - 1
build/Makefile.conf

@@ -107,7 +107,7 @@ endif
 ifeq ($(IGL_USERNAME),daniele)
 	IGL_WITH_MATLAB=0
 	AFLAGS=-m64
-	GG=g++-4.7
+	GG=g++
 	EIGEN3_INC=-I/usr/local/include/eigen3
 endif
 

+ 0 - 23
examples/principal_curvature/Makefile

@@ -1,23 +0,0 @@
-
-.PHONY: all
-
-# Shared flags etc.
-include ../../build/Makefile.conf
-
-all: curvature
-
-.PHONY: curvature
-
-igl_lib=../../
-eigen=-I$(DEFAULT_PREFIX)/include/eigen3
-
-inc=-I$(igl_lib)/include $(eigen)
-
-curvature: curvature.o
-	g++ $(CFLAGS) $(OPENMP) -o curvature curvature.o $(lib)
-
-curvature.o: curvature.cpp
-	g++ $(CFLAGS) $(OPENMP) -c curvature.cpp -o curvature.o $(inc)
-clean:
-	rm -f curvature.o
-	rm -f curvature

+ 0 - 164
examples/principal_curvature/curvature.cpp

@@ -1,164 +0,0 @@
-// This example is broken. It secretly uses classes from inside
-// principal_curvature.cpp not the api provided in the header
-// principal_curvature.h
-#undef IGL_STATIC_LIBRARY
-#include <igl/principal_curvature.h>
-#include <igl/read_triangle_mesh.h>
-#include <iostream>
-#include <Eigen/Dense>
-#include <Eigen/Sparse>
-
-
-using namespace std;
-bool cont=true;
-bool benchmark=false;
-
-void print_help()
-{
-    cout << "Usage: Curvature -i meshfile [-o curvfile] [-S scalefile] "
-            "[-k N | -e F] [-a] [-l] [-p] [-m N] [-s] [-z] [-b] [-n N] [-M N] [-h] \n"
-            "    -k N: compute using the N-ring of vertexes.\n"
-            "    -e S: compute using a sphere of radius R = S * mesh_average_edge.\n"
-            "    -a: no projection plane, use normals average.\n"
-            "    -l: local mode, use vcg normal (when using -a) or incident faces normal (default)\n"
-            "    -p: check projection plane calculation\n"
-            "    -m N: use montecarlo, extract N vertices maximum.\n"
-            "    -b: benchmark mode\n"
-            "    -n N: step for benchmarking\n"
-            "    -M N: max size for benchmarking\n"
-            "    -s: use svd calculation, not pseudoinverse.\n"
-            "    -z: check if determinant is almost zero.\n"
-            "    -h: print this help and exit.\n";
-}
-
-bool isDir(char* file)
-{
-    std::string s(file);
-    return (s.find_last_of('/')==s.size()-1);
-}
-
-void app_init(int argc, char* argv[], CurvatureCalculator& c, Eigen::MatrixXd& V, Eigen::MatrixXi& F)
-{
-    if (argc<2)
-    {
-        print_help();
-        exit(0);
-    }
-    char* tmp;
-    const char* meshName;
-    //char * scaleFile;
-    for (argc--, argv++; argc--; argv++)
-    {
-        if( (*argv)[0] == '-')
-        {
-            switch( (*argv)[1] )
-            {
-            case 'b':
-                benchmark=true;
-                break;
-            case 'n':
-                tmp=*++argv;
-                if (!strcmp(tmp,"exp"))
-                    c.expStep=true;
-                else
-                    c.step=atoi(tmp);
-                --argc;
-                break;
-            case 'M':
-                c.maxSize=atoi(*++argv);
-                argc--;
-                break;
-            case 'i':
-                meshName=*++argv;
-                igl::read_triangle_mesh(meshName,V,F);
-                argc--;
-                break;
-            case 'k':
-                c.st=K_RING_SEARCH;
-                c.kRing = atoi (*++argv);
-                argc--;
-                break;
-
-            case 'e':
-                c.st=SPHERE_SEARCH;
-                c.sphereRadius = atof (*++argv);
-                argc--;
-                break;
-
-            case 'a':
-                c.nt=AVERAGE;
-                break;
-
-            case 'l':
-                c.localMode = true;
-                break;
-
-            case 'p':
-                c.projectionPlaneCheck = true;
-                break;
-
-            case 'm':
-                c.montecarlo=true;
-                c.montecarloN = atoi (*++argv);
-                argc--;
-                break;
-
-            case 's':
-                c.svd = true;
-                break;
-
-            case 'z':
-                c.zeroDetCheck = true;
-                break;
-
-            case 'f':
-                /* dc.fitCreaseMode = atoi (*++argv);
-                    argc--;*/
-                break;
-
-            case 'o':
-                tmp=*++argv;
-                cerr << "Tmp: " << tmp << endl;
-                if (isDir(tmp))
-                {
-                    std::string tmpS(tmp);
-                    std::string tmpM(meshName);
-                    size_t pos=tmpM.find_last_of('/');
-                    tmpM.assign(tmpM.begin()+pos+1,tmpM.end());
-                    c.lastMeshName=tmpS+tmpM;
-                }
-                else
-                    c.lastMeshName=tmp;
-                argc--;
-                break;
-
-            case 'h':
-                print_help();
-                exit(0);
-
-            default:
-                print_help();
-                exit(0);
-            }
-        }
-    }
-
-    return;
-}
-
-int main(int argc, char *argv[])
-{
-    CurvatureCalculator c;
-    Eigen::MatrixXd V;
-    Eigen::MatrixXi F;
-    string filename;
-
-    app_init(argc,argv,c,V,F);
-
-    c.init(V,F);
-
-    c.computeCurvature();
-
-    c.printCurvature(c.lastMeshName);
-
-}

+ 24 - 1
examples/quicklook-mesh/Info.plist

@@ -13,8 +13,9 @@
 			<array>
 				<string>org.mesh</string>
 				<string>org.obj</string>
-				<string>org.stl</string>
 				<string>org.off</string>
+				<string>org.ply</string>
+				<string>org.stl</string>
 				<string>org.wrl</string>
 			</array>
 		</dict>
@@ -84,6 +85,7 @@
 				</array>
 			</dict>
 		</dict>
+
 		<dict>
 			<key>UTTypeConformsTo</key>
 			<array>
@@ -103,6 +105,27 @@
 				</array>
 			</dict>
 		</dict>
+
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.image</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>PLY 3D file</string>
+			<key>UTTypeIdentifier</key>
+			<string>org.ply</string>
+			<key>UTTypeReferenceURL</key>
+			<string>http://en.wikipedia.org/wiki/PLY_%28file_format%29</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>ply</string>
+				</array>
+			</dict>
+		</dict>
+
 		<dict>
 			<key>UTTypeConformsTo</key>
 			<array>

+ 9 - 3
examples/quicklook-mesh/src/render_to_buffer.cpp

@@ -2,9 +2,6 @@
 extern "C" {
 #include "render_to_buffer.h"
 };
-// We're probably didn't build libigl.a with LLVM so just use the headers only
-// version.
-#define IGL_HEADER_ONLY
 #include <igl/per_face_normals.h>
 #include <igl/normalize_row_lengths.h>
 #include <igl/get_seconds.h>
@@ -13,6 +10,7 @@ extern "C" {
 #include <igl/material_colors.h>
 #include <igl/pathinfo.h>
 #include <igl/readOBJ.h>
+#include <igl/readPLY.h>
 #include <igl/readSTL.h>
 #include <igl/readWRL.h>
 #include <igl/polygon_mesh_to_triangle_mesh.h>
@@ -376,6 +374,14 @@ bool render_to_buffer(
       red(width,height,buffer);
       return false;
     }
+  }else if(ext == "ply")
+  {
+    // Convert extension to lower case
+    if(!igl::readPLY(filename,vV,vF,vN,vTC))
+    {
+      red(width,height,buffer);
+      return false;
+    }
   }else if(ext == "stl")
   {
     // Convert extension to lower case

+ 6 - 1
file-formats/index.html

@@ -27,7 +27,12 @@
     href=http://www.cs.berkeley.edu/~jrs/stellar/#fileformats>Stellar</a>.
     </li>
     <li><a href="http://tetgen.berlios.de/fformats.off.html">.off</a> Geomview's polyhedral file format</li>
-    <li><a href="http://en.wikipedia.org/wiki/Wavefront_.obj_file#File_format">.obj</a> Wavefront object file format. Usually unsafe to assume anything more than vertex positions and triangle indices are supported</li>
+    <li><a
+    href="http://en.wikipedia.org/wiki/Wavefront_.obj_file#File_format">.obj</a>
+    Wavefront object file format. Usually unsafe to assume anything more than
+    vertex positions and triangle indices are supported</li>
+    <li><a href=http://en.wikipedia.org/wiki/PLY_%28file_format%29>.ply</a>
+    Polygon File Format, supporting ASCII and binary encoding</li>
     <li><a
     href=https://en.wikipedia.org/wiki/Portable_Network_Graphics>.png</a>
     Portable Network Graphics image file. IGLLIB (in the libiglpng extra)

+ 26 - 0
include/igl/ReAntTweakBar.cpp

@@ -416,6 +416,12 @@ IGL_INLINE std::string igl::ReTwBar::get_value_as_string(
         sstr << *(static_cast<int*>(var));
         break;
       }
+    case TW_TYPE_UINT32:
+      {
+        sstr << "TW_TYPE_UINT32" << " ";
+        sstr << *(static_cast<unsigned int*>(var));
+        break;
+      }
     case TW_TYPE_FLOAT:
       {
         sstr << "TW_TYPE_FLOAT" << " ";
@@ -571,6 +577,7 @@ bool igl::ReTwBar::set_value_from_string(
   float f[4];
   double d[4];
   bool b;
+  unsigned int u;
   unsigned char uc;
   std::string s;
 
@@ -670,6 +677,18 @@ bool igl::ReTwBar::set_value_from_string(
         }
         break;
       }
+    case TW_TYPE_UINT32:
+      {
+        if(sscanf(value_str," %u",&u) == 1)
+        {
+          value = &u;
+        }else
+        {
+          printf("ERROR: Bad value format...\n");
+          return false;
+        }
+        break;
+      }
     case TW_TYPE_FLOAT:
       {
         if(sscanf(value_str," %f",&v) == 1)
@@ -808,6 +827,13 @@ bool igl::ReTwBar::set_value_from_string(
             *ivar = *ivalue;
             break;
           }
+        case TW_TYPE_UINT32:
+          {
+            unsigned int * uvar =   static_cast<unsigned int*>(var);
+            unsigned int * uvalue = static_cast<unsigned int*>(value);
+            *uvar = *uvalue;
+            break;
+          }
         case TW_TYPE_FLOAT:
           {
             float * fvar = static_cast<float*>(var);

+ 1 - 0
include/igl/ReAntTweakBar.h

@@ -25,6 +25,7 @@
 //   TW_TYPE_DIR3D
 //   TW_TYPE_BOOL32
 //   TW_TYPE_INT32
+//   TW_TYPE_UINT32
 //   TW_TYPE_FLOAT
 //   TW_TYPE_DOUBLE
 //   TW_TYPE_UINT8

+ 1 - 0
include/igl/boolean/mesh_boolean.h

@@ -4,6 +4,7 @@
 #include <igl/igl_inline.h>
 #include "MeshBooleanType.h"
 #include <Eigen/Core>
+#include <functional>
 
 namespace igl
 {

+ 4 - 4
include/igl/boundary_facets.h

@@ -5,8 +5,8 @@
 // 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_BOUNDARY_FACES_H
-#define IGL_BOUNDARY_FACES_H
+#ifndef IGL_BOUNDARY_FACETS_H
+#define IGL_BOUNDARY_FACETS_H
 #include "igl_inline.h"
 
 #ifndef IGL_NO_EIGEN
@@ -17,8 +17,8 @@
 
 namespace igl
 {
-  // BOUNDARY_FACES Determine boundary faces (edges) of tetrahedra (triangles)
-  // stored in T
+  // BOUNDARY_FACETS Determine boundary faces (edges) of tetrahedra (triangles)
+  // stored in T (analogous to qptoolbox's `outline` and `boundary_faces`).
   //
   // Templates:
   //   IntegerT  integer-value: e.g. int

+ 2 - 2
include/igl/boundary_loop.h

@@ -5,8 +5,8 @@
 // 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_BOUNDARY_VERTICES_SORTED_H
-#define IGL_BOUNDARY_VERTICES_SORTED_H
+#ifndef IGL_BOUNDARY_LOOP_H
+#define IGL_BOUNDARY_LOOP_H
 #include <igl/igl_inline.h>
 
 #include <Eigen/Dense>

+ 7 - 5
include/igl/cgal/SelfIntersectMesh.h

@@ -406,7 +406,9 @@ inline igl::SelfIntersectMesh<
   map<typename CDT_plus_2::Vertex_handle,Index> v2i;
   // Loop over offending triangles
   const size_t noff = offending.size();
-# pragma omp parallel for if (noff>1000)
+  // Unfortunately it looks like CGAL has trouble allocating memory when
+  // multiple openmp threads are running. Crashes durring CDT...
+//# pragma omp parallel for if (noff>1000)
   for(Index o = 0;o<(Index)noff;o++)
   {
     // index in F
@@ -441,7 +443,7 @@ inline igl::SelfIntersectMesh<
           assert(T[f].vertex(i) == P[o].to_3d(vit->point()));
 #endif
           // For first three, use original index in F
-#   pragma omp critical
+//#   pragma omp critical
           v2i[vit] = F(f,i);
         }else
         {
@@ -483,7 +485,7 @@ inline igl::SelfIntersectMesh<
                 if(vit_point_3 == P[no].to_3d(uit->point()))
                 {
                   assert(v2i.count(uit) == 1);
-#   pragma omp critical
+//#   pragma omp critical
                   v2i[vit] = v2i[uit];
                   found = true;
                 }
@@ -492,7 +494,7 @@ inline igl::SelfIntersectMesh<
           }
           if(!found)
           {
-#   pragma omp critical
+//#   pragma omp critical
             {
               v2i[vit] = V.rows()+NV_count;
               NV.push_back(vit_point_3);
@@ -507,7 +509,7 @@ inline igl::SelfIntersectMesh<
       Index i = 0;
       // Resize to fit new number of triangles
       NF[o].resize(cdt[o].number_of_faces(),3);
-#   pragma omp atomic
+//#   pragma omp atomic
       NF_count+=NF[o].rows();
       // Append new faces to NF
       for(

+ 1 - 1
include/igl/comiso/miq.cpp

@@ -1007,7 +1007,7 @@ IGL_INLINE void igl::PoissonSolver<DerivedV, DerivedF>::SolvePoisson(Eigen::Vect
   if (DEBUGPRINT)
     printf("\n BUILT THE MATRIX \n");
 
-  if (integer_rounding)    
+  if (integer_rounding)
     AddToRoundVertices(roundVertices);
 
   if (_singularity_rounding)

+ 1 - 1
include/igl/cotmatrix.h

@@ -1,6 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // 
-// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2014 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 

+ 1 - 1
include/igl/draw_mesh.cpp

@@ -91,7 +91,7 @@ IGL_INLINE void igl::draw_mesh(
     assert(F.maxCoeff() < V.rows());
     assert(V.cols() == 3);
     assert(rC == rV || rC == rF || rC == rF*3 || rC==1 || C.size() == 0);
-    assert(C.cols() == 3 || C.size() == 0);
+    assert(C.cols() >= 3 || C.size() == 0);
     assert(N.cols() == 3 || N.size() == 0);
     assert(TC.cols() == 2 || TC.size() == 0);
     assert(cF == 3 || cF == 4);

+ 1 - 2
include/igl/embree/reorient_facets_raycast.h

@@ -25,8 +25,7 @@ namespace igl
   //   is_verbose  Verbose output to cout
   // Outputs:
   //   I  #F list of whether face has been flipped
-  //   C  #F list of patch ID (outpute of bfs_orient
-  //     > manifold patches
+  //   C  #F list of patch ID (output of bfs_orient > manifold patches)
   template <
     typename DerivedV, 
     typename DerivedF, 

+ 2 - 1
include/igl/find_cross_field_singularities.h

@@ -31,7 +31,8 @@ namespace igl
                                                  Eigen::PlainObjectBase<DerivedO> &isSingularity,
                                                  Eigen::PlainObjectBase<DerivedO> &singularityIndex);
 
-  // Wrapper that calculates the missmatch if it is not provided
+  // Wrapper that calculates the missmatch if it is not provided.
+  // Note that the field in PD1 and PD2 MUST BE combed (see igl::comb_cross_field).
   // Inputs:
   //   V                #V by 3 eigen Matrix of mesh vertex 3D positions
   //   F                #F by 3 eigen Matrix of face (quad) indices

+ 2 - 2
include/igl/internal_angles.cpp

@@ -48,9 +48,9 @@ IGL_INLINE void igl::internal_angles(
   #  define IGL_OMP_MIN_VALUE 1000
   #endif
   #pragma omp parallel for if (m>IGL_OMP_MIN_VALUE)
-  for(int f = 0;f<m;f++)
+  for(size_t f = 0;f<m;f++)
   {
-    for(int d = 0;d<3;d++)
+    for(size_t d = 0;d<3;d++)
     {
       const auto & s1 = L(f,d);
       const auto & s2 = L(f,(d+1)%3);

+ 62 - 0
include/igl/outline_ordered.cpp

@@ -0,0 +1,62 @@
+// 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 "outline_ordered.h"
+#include "exterior_edges.h"
+#include <set>
+
+template <typename DerivedF, typename Index>
+IGL_INLINE void igl::outline_ordered(
+    const Eigen::PlainObjectBase<DerivedF> & F, 
+    std::vector<std::vector<Index> >& L)
+{
+  using namespace std;
+  using namespace Eigen;
+  // Exterior edges include some non-manifold edges (poor function name). I
+  // suppose `outline_ordered` is not well defined for non-manifold meshes, but
+  // perhaps this should just call `boundary_facets`
+  MatrixXi E = exterior_edges(F);
+
+  set<int> unseen;
+  for (int i = 0; i < E.rows(); ++i)
+  {
+    unseen.insert(unseen.end(),i);
+  }
+
+  while (!unseen.empty())
+  {
+      vector<Index> l;
+
+      // Get first vertex of loop
+      int startEdge = *unseen.begin();
+      unseen.erase(unseen.begin());
+
+      int start = E(startEdge,0);
+      int next = E(startEdge,1);
+      l.push_back(start);
+
+      while (start != next)
+      {
+          l.push_back(next);
+
+          // Find next edge
+          int nextEdge;
+          set<int>::iterator it;
+          for (it=unseen.begin(); it != unseen.end() ; ++it)
+          {
+              if (E(*it,0) == next || E(*it,1) == next)
+              {
+                  nextEdge = *it;
+                  break;
+              }                  
+          }
+          unseen.erase(nextEdge);
+          next = (E(nextEdge,0) == next) ? E(nextEdge,1) : E(nextEdge,0);
+      }
+      L.push_back(l);
+  }
+}

+ 35 - 0
include/igl/outline_ordered.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_OUTLINE_ORDERED_H
+#define IGL_OUTLINE_ORDERED_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl
+{
+  // Compute list of ordered boundary loops for a manifold mesh.
+  //
+  // Templates:
+  //  Index  index type
+  // Inputs:
+  //   F  #V by dim list of mesh faces
+  // Outputs:
+  //   L  list of loops where L[i] = ordered list of boundary vertices in loop i
+  //
+  template <typename DerivedF, typename Index>
+  IGL_INLINE void outline_ordered(
+    const Eigen::PlainObjectBase<DerivedF> & F, 
+    std::vector<std::vector<Index> >& L);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "outline_ordered.cpp"
+#endif
+#endif

+ 2 - 1
include/igl/peal_outer_hull_layers.cpp

@@ -1,6 +1,7 @@
 #include <vector>
 #include "peal_outer_hull_layers.h"
 #include "outer_hull.h"
+#include <vector>
 
 using namespace std;
 template <
@@ -42,7 +43,7 @@ IGL_INLINE void igl::peal_outer_hull_layers(
     outer_hull(V,Fr,Fo,Jo,flipr);
     assert(Fo.rows() == Jo.rows());
     // all faces in Fo of Fr
-    vector<bool> in_outer(Fr.rows(),false); 
+    vector<bool> in_outer(Fr.rows(),false);
     for(Index g = 0;g<Jo.rows();g++)
     {
       odd(IM(Jo(g))) = odd_iter;

+ 1 - 0
include/igl/ply.h.REMOVED.git-id

@@ -0,0 +1 @@
+05e282fe767ea0bd8987f68ae4b79d0ab4c26a09

+ 6 - 0
include/igl/principal_curvature.cpp

@@ -794,6 +794,12 @@ IGL_INLINE void igl::principal_curvature(
 {
   using namespace std;
 
+  if (radius < 2)
+  {
+    radius = 2;
+    cout << "WARNING: igl::principal_curvature needs a radius >= 2, fixing it to 2." << endl;
+  }
+
   // Preallocate memory
   PD1.resize(V.rows(),3);
   PD2.resize(V.rows(),3);

+ 190 - 0
include/igl/readPLY.cpp

@@ -0,0 +1,190 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 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
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readPLY.h"
+#include "list_to_matrix.h"
+#include "ply.h"
+#include <iostream>
+
+template <
+  typename Vtype,
+  typename Ftype,
+  typename Ntype,
+  typename UVtype>
+IGL_INLINE bool igl::readPLY(
+  const std::string & filename,
+  std::vector<std::vector<Vtype> > & V,
+  std::vector<std::vector<Ftype> > & F,
+  std::vector<std::vector<Ntype> > & N,
+  std::vector<std::vector<UVtype> >  & UV)
+{
+  using namespace std;
+  // Largely follows ply2iv.c
+
+   typedef struct Vertex {
+     double x,y,z;          /* position */
+     double nx,ny,nz;         /* surface normal */
+     double s,t;              /* texture coordinates */
+     void *other_props;       /* other properties */
+   } Vertex;
+
+   typedef struct Face {
+     unsigned char nverts;    /* number of vertex indices in list */
+     int *verts;              /* vertex index list */
+     void *other_props;       /* other properties */
+   } Face;
+
+  PlyProperty vert_props[] = { /* list of property information for a vertex */
+    {"x", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,x), 0, 0, 0, 0},
+    {"y", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,y), 0, 0, 0, 0},
+    {"z", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,z), 0, 0, 0, 0},
+    {"nx", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,nx), 0, 0, 0, 0},
+    {"ny", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,ny), 0, 0, 0, 0},
+    {"nz", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,nz), 0, 0, 0, 0},
+    {"s", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,s), 0, 0, 0, 0},
+    {"t", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,t), 0, 0, 0, 0},
+  };
+
+  PlyProperty face_props[] = { /* list of property information for a face */
+    {"vertex_indices", PLY_INT, PLY_INT, offsetof(Face,verts),
+      1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
+  };
+  FILE * fp = fopen(filename.c_str(),"r");
+  if(fp == NULL)
+  {
+    return false;
+  }
+  int nelems;
+  char ** elem_names;
+  PlyFile * in_ply = ply_read(fp,&nelems,&elem_names);
+  if(in_ply==NULL)
+  {
+    return false;
+  }
+
+  bool has_normals = false;
+  bool has_texture_coords = false;
+  PlyProperty **plist;
+  int nprops;
+  int elem_count;
+  plist = ply_get_element_description (in_ply,"vertex", &elem_count, &nprops);
+  if (plist != NULL)
+  {
+    /* set up for getting vertex elements */
+    ply_get_property (in_ply,"vertex",&vert_props[0]);
+    ply_get_property (in_ply,"vertex",&vert_props[1]);
+    ply_get_property (in_ply,"vertex",&vert_props[2]);
+    for (int j = 0; j < nprops; j++)
+    {
+      PlyProperty * prop = plist[j];
+      if (equal_strings ("nx", prop->name) 
+        || equal_strings ("ny", prop->name)
+        || equal_strings ("nz", prop->name))
+      {
+        ply_get_property (in_ply,"vertex",&vert_props[3]);
+        ply_get_property (in_ply,"vertex",&vert_props[4]);
+        ply_get_property (in_ply,"vertex",&vert_props[5]);
+        has_normals = true;
+      }
+      if (equal_strings ("s", prop->name) ||
+        equal_strings ("t", prop->name))
+      {
+        ply_get_property(in_ply,"vertex",&vert_props[6]);
+        ply_get_property(in_ply,"vertex",&vert_props[7]);
+        has_texture_coords = true;
+      }
+    }
+    // Is this call necessary?
+    ply_get_other_properties(in_ply,"vertex",
+				     offsetof(Vertex,other_props));
+    V.resize(elem_count,std::vector<Vtype>(3));
+    if(has_normals)
+    {
+      N.resize(elem_count,std::vector<Ntype>(3));
+    }else
+    {
+      N.resize(0);
+    }
+    if(has_texture_coords)
+    {
+      UV.resize(elem_count,std::vector<UVtype>(2));
+    }else
+    {
+      UV.resize(0);
+    }
+    for(int j = 0;j<elem_count;j++)
+    {
+      Vertex v;
+      ply_get_element_setup(in_ply,"vertex",3,vert_props);
+      ply_get_element(in_ply,(void*)&v);
+      V[j][0] = v.x;
+      V[j][1] = v.y;
+      V[j][2] = v.z;
+      if(has_normals)
+      {
+        N[j][0] = v.nx;
+        N[j][1] = v.ny;
+        N[j][2] = v.nz;
+      }
+      if(has_texture_coords)
+      {
+        UV[j][0] = v.s;
+        UV[j][1] = v.t;
+      }
+    }
+  }
+  plist = ply_get_element_description (in_ply,"face", &elem_count, &nprops);
+  if (plist != NULL)
+  {
+    F.resize(elem_count);
+    ply_get_property(in_ply,"face",&face_props[0]);
+    for (int j = 0; j < elem_count; j++) 
+    {
+      Face f;
+      ply_get_element(in_ply, (void *) &f);
+      for(size_t c = 0;c<f.nverts;c++)
+      {
+        F[j].push_back(f.verts[c]);
+      }
+    }
+  }
+  ply_close(in_ply);
+  fclose(fp);
+  return true;
+}
+
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedN,
+  typename DerivedUV>
+IGL_INLINE bool igl::readPLY(
+  const std::string & filename,
+  Eigen::PlainObjectBase<DerivedV> & V,
+  Eigen::PlainObjectBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedN> & N,
+  Eigen::PlainObjectBase<DerivedUV> & UV)
+{
+  std::vector<std::vector<typename DerivedV::Scalar> > vV;
+  std::vector<std::vector<typename DerivedF::Scalar> > vF;
+  std::vector<std::vector<typename DerivedN::Scalar> > vN;
+  std::vector<std::vector<typename DerivedUV::Scalar> > vUV;
+  if(!readPLY(filename,vV,vF,vN,vUV))
+  {
+    return false;
+  }
+  return 
+    list_to_matrix(vV,V) &&
+    list_to_matrix(vF,F) &&
+    list_to_matrix(vN,N) &&
+    list_to_matrix(vUV,UV);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+template bool igl::readPLY<double, int, double, double>(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&);
+#endif

+ 54 - 0
include/igl/readPLY.h

@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READPLY_H
+#define IGL_READPLY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+#include <vector>
+
+namespace igl
+{
+  // Read a mesh from a .ply file. 
+  //
+  // Inputs:
+  //   filename  path to .ply file
+  // Outputs:
+  //   V  #V by 3 list of vertex positions
+  //   F  #F list of lists of triangle indices
+  //   N  #V by 3 list of vertex normals
+  //   UV  #V by 2 list of vertex texture coordinates
+  // Returns true iff success
+  template <
+    typename Vtype,
+    typename Ftype,
+    typename Ntype,
+    typename UVtype>
+  IGL_INLINE bool readPLY(
+    const std::string & filename,
+    std::vector<std::vector<Vtype> > & V,
+    std::vector<std::vector<Ftype> > & F,
+    std::vector<std::vector<Ntype> > & N,
+    std::vector<std::vector<UVtype> >  & UV);
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedN,
+    typename DerivedUV>
+  IGL_INLINE bool readPLY(
+    const std::string & filename,
+    Eigen::PlainObjectBase<DerivedV> & V,
+    Eigen::PlainObjectBase<DerivedF> & F,
+    Eigen::PlainObjectBase<DerivedN> & N,
+    Eigen::PlainObjectBase<DerivedUV> & UV);
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "readPLY.cpp"
+#endif
+#endif
+

+ 7 - 0
include/igl/read_triangle_mesh.cpp

@@ -12,6 +12,7 @@
 #include <igl/readOBJ.h>
 #include <igl/readOFF.h>
 #include <igl/readSTL.h>
+#include <igl/readPLY.h>
 #include <igl/readWRL.h>
 #include <igl/pathinfo.h>
 #include <igl/boundary_facets.h>
@@ -104,6 +105,12 @@ IGL_INLINE bool igl::read_triangle_mesh(
     {
       return false;
     }
+  }else if(ext == "ply")
+  {
+    if(!readPLY(filename,vV,vF,vN,vTC))
+    {
+      return false;
+    }
   }else if(ext == "stl")
   {
     MatrixXd _;

+ 4 - 2
include/igl/read_triangle_mesh.h

@@ -20,13 +20,15 @@
 
 namespace igl
 {
-  // read mesh from an ascii file with automatic detection of file format. supported: obj, off)
+  // read mesh from an ascii file with automatic detection of file format.
+  // supported: obj, off, stl, wrl, ply, mesh)
+  // 
   // Templates:
   //   Scalar  type for positions and vectors (will be read as double and cast
   //     to Scalar)
   //   Index  type for indices (will be read as int and cast to Index)
   // Inputs:
-  //   str  path to .obj/.off file
+  //   str  path to file
   // Outputs:
   //   V  eigen double matrix #V by 3
   //   F  eigen int matrix #F by 3

+ 8 - 7
include/igl/triangle_triangle_adjacency.cpp

@@ -101,8 +101,8 @@ IGL_INLINE void igl::triangle_triangle_adjacency(const Eigen::PlainObjectBase<Sc
 }
 
 template <
-  typename DerivedF, 
-  typename TTIndex, 
+  typename DerivedF,
+  typename TTIndex,
   typename TTiIndex>
   IGL_INLINE void igl::triangle_triangle_adjacency(
     const Eigen::PlainObjectBase<DerivedF> & F,
@@ -113,7 +113,7 @@ template <
 }
 
 template <
-  typename DerivedF, 
+  typename DerivedF,
   typename TTIndex>
   IGL_INLINE void igl::triangle_triangle_adjacency(
     const Eigen::PlainObjectBase<DerivedF> & F,
@@ -124,8 +124,8 @@ template <
 }
 
 template <
-  typename DerivedF, 
-  typename TTIndex, 
+  typename DerivedF,
+  typename TTIndex,
   typename TTiIndex>
   IGL_INLINE void igl::triangle_triangle_adjacency(
     const Eigen::PlainObjectBase<DerivedF> & F,
@@ -148,10 +148,10 @@ template <
 }
 
 template <
-  typename DerivedE, 
+  typename DerivedE,
   typename DerivedEMAP,
   typename uE2EType,
-  typename TTIndex, 
+  typename TTIndex,
   typename TTiIndex>
   IGL_INLINE void igl::triangle_triangle_adjacency(
     const Eigen::PlainObjectBase<DerivedE> & E,
@@ -206,6 +206,7 @@ template <
 #ifdef IGL_STATIC_LIBRARY
 // Explicit template specialization
 template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, long, long>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, bool, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&);
+template void igl::triangle_triangle_adjacency<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&, 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> >&);
 template void igl::triangle_triangle_adjacency<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
 template void igl::triangle_triangle_adjacency<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
 #endif

+ 1 - 1
include/igl/viewer/Viewer.cpp

@@ -585,7 +585,7 @@ namespace igl
     if (key == 'A')
       mouse_scroll(-1);
 
-    // Why aren't these handled view AntTweakBar?
+    // Why aren't these handled via AntTweakBar?
     if (key == 'z') // Don't use 'Z' because that clobbers snap_to_canonical_view_quat
       core.trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f;
 

+ 3 - 0
include/igl/viewer/Viewer.h

@@ -8,6 +8,9 @@
 
 #ifndef IGL_VIEWER_H
 #define IGL_VIEWER_H
+#ifndef IGL_OPENGL_4
+#define IGL_OPENGL_4
+#endif
 
 #include <AntTweakBar.h>
 

+ 8 - 5
include/igl/viewer/ViewerPlugin.h

@@ -20,11 +20,14 @@ namespace igl
 {
 
 // Abstract class for plugins
-// All plugins MUST have this class as their parent and implement all the callbacks
-// For an example of a basic plugins see plugins/skeleton.h
+// All plugins MUST have this class as their parent and may implement any/all
+// the callbacks marked `virtual` here.
 //
-// Return value of callbacks: returning true to any of the callbacks tells Preview3D that the event has been
-// handled and that it should not be passed to other plugins or to other internal functions of Preview3D
+// /////For an example of a basic plugins see plugins/skeleton.h
+//
+// Return value of callbacks: returning true to any of the callbacks tells
+// Viewer that the event has been handled and that it should not be passed to
+// other plugins or to other internal functions of Viewer
 
 // Forward declaration of the viewer
 class Viewer;
@@ -130,7 +133,7 @@ public:
 
   std::string plugin_name;
 protected:
-  // Pointer to the main Preview3D class
+  // Pointer to the main Viewer class
   Viewer *viewer;
 };
 

+ 142 - 0
include/igl/writePLY.cpp

@@ -0,0 +1,142 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 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
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writePLY.h"
+#include <igl/ply.h>
+
+template <
+  typename DerivedV,
+  typename DerivedF,
+  typename DerivedN,
+  typename DerivedUV>
+IGL_INLINE bool igl::writePLY(
+  const std::string & filename,
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::PlainObjectBase<DerivedN> & N,
+  const Eigen::PlainObjectBase<DerivedUV> & UV,
+  const bool ascii)
+{
+  // Largely based on obj2ply.c
+
+  typedef struct Vertex
+  {
+    double x,y,z,w;          /* position */
+    double nx,ny,nz;         /* surface normal */
+    double s,t;              /* texture coordinates */
+  } Vertex;
+
+  typedef struct Face
+  {
+    unsigned char nverts;    /* number of vertex indices in list */
+    int *verts;              /* vertex index list */
+  } Face;
+
+  PlyProperty vert_props[] = 
+  { /* list of property information for a vertex */
+    {"x", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,x), 0, 0, 0, 0},
+    {"y", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,y), 0, 0, 0, 0},
+    {"z", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,z), 0, 0, 0, 0},
+    {"nx", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,nx), 0, 0, 0, 0},
+    {"ny", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,ny), 0, 0, 0, 0},
+    {"nz", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,nz), 0, 0, 0, 0},
+    {"s", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,s), 0, 0, 0, 0},
+    {"t", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,t), 0, 0, 0, 0},
+  };
+
+  PlyProperty face_props[] = 
+  { /* list of property information for a face */
+    {"vertex_indices", PLY_INT, PLY_INT, offsetof(Face,verts),
+      1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
+  };
+  const bool has_normals = N.rows() > 0;
+  const bool has_texture_coords = UV.rows() > 0;
+  std::vector<Vertex> vlist(V.rows());
+  std::vector<Face> flist(F.rows());
+  for(size_t i = 0;i<V.rows();i++)
+  {
+    vlist[i].x = V(i,0);
+    vlist[i].y = V(i,1);
+    vlist[i].z = V(i,2);
+    if(has_normals)
+    {
+      vlist[i].nx = N(i,0);
+      vlist[i].ny = N(i,1);
+      vlist[i].nz = N(i,2);
+    }
+    if(has_texture_coords)
+    {
+      vlist[i].s = UV(i,0);
+      vlist[i].t = UV(i,1);
+    }
+  }
+  for(size_t i = 0;i<F.rows();i++)
+  {
+    flist[i].nverts = F.cols();
+    flist[i].verts = new int[F.cols()];
+    for(size_t c = 0;c<F.cols();c++)
+    {
+      flist[i].verts[c] = F(i,c);
+    }
+  }
+
+  const char * elem_names[] = {"vertex","face"};
+  FILE * fp = fopen(filename.c_str(),"w");
+  if(fp==NULL)
+  {
+    return false;
+  }
+  PlyFile * ply = ply_write(fp, 2,elem_names, 
+      (ascii ? PLY_ASCII : PLY_BINARY_LE));
+  if(ply==NULL)
+  {
+    return false;
+  }
+
+  std::vector<PlyProperty> plist;
+  plist.push_back(vert_props[0]);
+  plist.push_back(vert_props[1]);
+  plist.push_back(vert_props[2]);
+  if (has_normals) 
+  {
+    plist.push_back(vert_props[3]);
+    plist.push_back(vert_props[4]);
+    plist.push_back(vert_props[5]);
+  }
+  if (has_texture_coords)
+  {
+    plist.push_back(vert_props[6]);
+    plist.push_back(vert_props[7]);
+  }
+  ply_describe_element(ply, "vertex", V.rows(),plist.size(),
+    &plist[0]);
+
+  ply_describe_element(ply, "face", F.rows(),1,&face_props[0]);
+  ply_header_complete(ply);
+  ply_put_element_setup(ply, "vertex");
+  for(const auto v : vlist)
+  {
+    ply_put_element(ply, (void *) &v);
+  }
+  ply_put_element_setup(ply, "face");
+  for(const auto f : flist)
+  {
+    ply_put_element(ply, (void *) &f);
+  }
+
+  ply_close(ply);
+  fclose(fp);
+  for(size_t i = 0;i<F.rows();i++)
+  {
+    delete[] flist[i].verts;
+  }
+  return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template specialization
+#endif

+ 41 - 0
include/igl/writePLY.h

@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITEPLY_H
+#define IGL_WRITEPLY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+
+namespace igl
+{
+  // Write a mesh to a .ply file. 
+  //
+  // Inputs:
+  //   filename  path to .ply file
+  //   V  #V by 3 list of vertex positions
+  //   F  #F by 3 list of triangle indices
+  //   N  #V by 3 list of vertex normals
+  //   UV  #V by 2 list of vertex texture coordinates
+  // Returns true iff success
+  template <
+    typename DerivedV,
+    typename DerivedF,
+    typename DerivedN,
+    typename DerivedUV>
+  IGL_INLINE bool writePLY(
+    const std::string & filename,
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::PlainObjectBase<DerivedN> & N,
+    const Eigen::PlainObjectBase<DerivedUV> & UV,
+    const bool ascii = true);
+}
+#ifndef IGL_STATIC_LIBRARY
+#  include "writePLY.cpp"
+#endif
+#endif

+ 3 - 2
tutorial/401_BiharmonicDeformation/main.cpp

@@ -46,12 +46,13 @@ bool key_down(igl::Viewer &viewer, unsigned char key, int mods)
   {
     case ' ':
       viewer.core.is_animating = !viewer.core.is_animating;
-      break;
+      return true;
     case 'D':
     case 'd':
       deformation_field = !deformation_field;
-      break;
+      return true;
   }
+  return false;
 }
 
 int main(int argc, char *argv[])

+ 6 - 1
tutorial/403_BoundedBiharmonicWeights/CMakeLists.txt

@@ -3,7 +3,12 @@ project(403_BoundedBiharmonicWeights)
 
 include("../CMakeLists.shared")
 
-find_package(MOSEK REQUIRED)
+if(NOT MOSEK_FOUND)
+  add_definitions(-DIGL_NO_MOSEK)
+  if(LIBIGL_USE_STATIC_LIBRARY)
+    set(LIBIGLMOSEK_LIBRARY "")
+  endif(LIBIGL_USE_STATIC_LIBRARY)
+endif(NOT MOSEK_FOUND)
 
 include_directories( ${MOSEK_INCLUDE_DIR} )
 

+ 3 - 1
tutorial/609_Boolean/CMakeLists.txt

@@ -4,7 +4,9 @@ project(609_Boolean)
 find_package(CGAL REQUIRED)
 include(${CGAL_USE_FILE})
 
-# for some reason must come after cgal include
+# for some reason must come after cgal include. I think that it's overwriting
+# come flags like CXX_FLAGS
+set(CMAKELISTS_SHARED_INCLUDED FALSE)
 include("../CMakeLists.shared")
 
 set(SOURCES

+ 12 - 2
tutorial/CMakeLists.shared

@@ -1,16 +1,25 @@
+if(NOT CMAKELISTS_SHARED_INCLUDED)
+set(CMAKELISTS_SHARED_INCLUDED TRUE)
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+find_package(OpenMP)
+if (OPENMP_FOUND)
+  set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+  set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+endif()
+
 SET(CMAKE_VERBOSE_MAKEFILE ON)
 
-set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake)
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake ${PROJECT_SOURCE_DIR}/cmake)
 set(CMAKE_COLOR_MAKEFILE ON)
 
 ############################
 ## SEPARATE BUILD OPTIONS ##
 ############################
 
-find_package(ANTTWEAKBAR REQUIRED)
 find_package(OpenGL REQUIRED)
 find_package(EIGEN REQUIRED)
 find_package(LIBIGL REQUIRED)
+find_package(ANTTWEAKBAR REQUIRED)
 find_package(GLFW REQUIRED)
 
 if(NOT APPLE)
@@ -84,3 +93,4 @@ set(SHARED_LIBRARIES
 )
 
 #message(FATAL_ERROR ${SHARED_LIBRARIES})
+endif(NOT CMAKELISTS_SHARED_INCLUDED)

+ 5 - 0
tutorial/CMakeLists.txt

@@ -14,6 +14,11 @@ find_package(MATLAB QUIET)
 find_package(EMBREE QUIET)
 find_package(CGAL QUIET)
 
+## Check for mosek
+find_package(MOSEK QUIET)
+
+include("CMakeLists.shared")
+
 # Chapter 1
 add_subdirectory("101_FileIO")
 add_subdirectory("102_DrawMesh")

+ 8 - 4
tutorial/cmake/FindANTTWEAKBAR.cmake

@@ -17,20 +17,23 @@ IF (WIN32)
 	FIND_PATH( ANT_TWEAK_BAR_INCLUDE_DIR AntTweakBar.h
       PATHS
 		${PROJECT_SOURCE_DIR}/../../external/AntTweakBar/include
+		${PROJECT_SOURCE_DIR}/../external/AntTweakBar/include
 		$ENV{ANT_TWEAK_BAR_ROOT}/include
 		DOC "The directory where AntTweakBar.h resides")
 
     FIND_LIBRARY( ANT_TWEAK_BAR_LIBRARY AntTweakBar${BITS}
         PATHS
 		${PROJECT_SOURCE_DIR}/../../external/AntTweakBar/lib
-        $ENV{ANT_TWEAK_BAR_ROOT}/lib
-        DOC "The AntTweakBar library")
+		${PROJECT_SOURCE_DIR}/../external/AntTweakBar/lib
+                $ENV{ANT_TWEAK_BAR_ROOT}/lib
+                DOC "The AntTweakBar library")
 ELSE (WIN32)
 
 FIND_PATH(ANT_TWEAK_BAR_INCLUDE_DIR AntTweakBar.h
       PATHS
-	    ${PROJECT_SOURCE_DIR}/../libigl/external/AntTweakBar/include/
+	    ${LIBIGL_INCLUDE_DIR}/../external/AntTweakBar/include/
       ${PROJECT_SOURCE_DIR}/../../external/AntTweakBar/include/
+      ${PROJECT_SOURCE_DIR}/../external/AntTweakBar/include/
       /usr/local/include
       /usr/X11/include
       /usr/include
@@ -38,8 +41,9 @@ FIND_PATH(ANT_TWEAK_BAR_INCLUDE_DIR AntTweakBar.h
 
 FIND_LIBRARY( ANT_TWEAK_BAR_LIBRARY AntTweakBar
   PATHS
-		${PROJECT_SOURCE_DIR}/../libigl/external/AntTweakBar/lib
+		${LIBIGL_INCLUDE_DIR}/../external/AntTweakBar/lib
     ${PROJECT_SOURCE_DIR}/../../external/AntTweakBar/lib
+    ${PROJECT_SOURCE_DIR}/../external/AntTweakBar/lib
     /usr/local
     /usr/X11
     /usr

+ 8 - 1
tutorial/cmake/FindGLFW.cmake

@@ -7,9 +7,12 @@
 # GLFW_LIBRARIES
 #
 
+if(NOT GLFW_FOUND)
+
 FIND_PATH(GLFW_INCLUDE_DIR GLFW/glfw3.h
   PATHS
     ${PROJECT_SOURCE_DIR}/../../external/glfw/include
+    ${PROJECT_SOURCE_DIR}/../external/glfw/include
     /usr/local/include
     /usr/X11/include
     /usr/include
@@ -20,7 +23,9 @@ FIND_PATH(GLFW_INCLUDE_DIR GLFW/glfw3.h
 FIND_LIBRARY( GLFW_LIBRARIES NAMES glfw glfw3
   PATHS
     ${PROJECT_SOURCE_DIR}/../../external/glfw/src
-	${PROJECT_SOURCE_DIR}/../../external/glfw/lib/x64
+    ${PROJECT_SOURCE_DIR}/../external/glfw/src
+    ${PROJECT_SOURCE_DIR}/../../external/glfw/lib/x64
+    ${PROJECT_SOURCE_DIR}/../external/glfw/lib/x64
     /usr/local
     /usr/X11
     /usr
@@ -41,3 +46,5 @@ if(GLFW_FOUND)
 else(GLFW_FOUND)
   message(FATAL_ERROR "could NOT find GLFW")
 endif(GLFW_FOUND)
+
+endif(NOT GLFW_FOUND)

+ 14 - 19
tutorial/cmake/FindLIBIGL.cmake

@@ -4,10 +4,7 @@
 #  LIBIGL_FOUND - system has LIBIGL
 #  LIBIGL_INCLUDE_DIR - the LIBIGL include directory
 #  LIBIGL_SOURCES - the LIBIGL source files
-
-# Mosek is not required but must be found before libigl to ensure correct flags
-# are set
-find_package(Mosek QUIET)
+if(NOT LIBIGL_FOUND)
 
 FIND_PATH(LIBIGL_INCLUDE_DIR igl/readOBJ.h
    /usr/include
@@ -31,10 +28,6 @@ if(LIBIGL_INCLUDE_DIR)
    #)
 endif(LIBIGL_INCLUDE_DIR)
 
-if (NOT MOSEK_FOUND)
-  add_definitions(-DIGL_NO_MOSEK)
-endif (NOT MOSEK_FOUND)
-
 if(LIBIGL_USE_STATIC_LIBRARY)
   add_definitions(-DIGL_STATIC_LIBRARY)
   set(LIBIGL_LIB_DIRS
@@ -60,18 +53,18 @@ if(LIBIGL_USE_STATIC_LIBRARY)
   endif(NOT LIBIGLBBW_LIBRARY)
   set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES}  ${LIBIGLBBW_LIBRARY})
   FIND_LIBRARY( LIBIGLMOSEK_LIBRARY NAMES iglmosek PATHS ${LIBIGL_LIB_DIRS})
-  if(NOT LIBIGLMOSEK_LIBRARY)
-    set(LIBIGL_FOUND FALSE)
-    message(FATAL_ERROR "could NOT find libiglmosek")
-  endif(NOT LIBIGLMOSEK_LIBRARY)
+#  if(NOT LIBIGLMOSEK_LIBRARY)
+#    set(LIBIGL_FOUND FALSE)
+#    message(FATAL_ERROR "could NOT find libiglmosek")
+#  endif(NOT LIBIGLMOSEK_LIBRARY)
   set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES}  ${LIBIGLMOSEK_LIBRARY})
-  if(MOSEK_FOUND)
-    set(LIBIGL_INCLUDE_DIR ${LIBIGL_INCLUDE_DIR}  ${MOSEK_INCLUDE_DIR})
-    set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES}  ${MOSEK_LIBRARIES})
-  else(MOSEK_FOUND)
-    set(LIBIGL_FOUND FALSE)
-    message(FATAL_ERROR "could NOT find mosek")
-  endif(MOSEK_FOUND)
+#if(MOSEK_FOUND)
+#    set(LIBIGL_INCLUDE_DIR ${LIBIGL_INCLUDE_DIR}  ${MOSEK_INCLUDE_DIR})
+#    set(LIBIGL_LIBRARIES ${LIBIGL_LIBRARIES}  ${MOSEK_LIBRARIES})
+#  else(MOSEK_FOUND)
+#    set(LIBIGL_FOUND FALSE)
+#    message(FATAL_ERROR "could NOT find mosek")
+#  endif(MOSEK_FOUND)
 
   FIND_LIBRARY( LIBIGLCGAL_LIBRARY NAMES iglcgal PATHS ${LIBIGL_LIB_DIRS})
   if(NOT LIBIGLCGAL_LIBRARY)
@@ -167,3 +160,5 @@ else(LIBIGL_FOUND)
 endif(LIBIGL_FOUND)
 
 MARK_AS_ADVANCED(LIBIGL_INCLUDE_DIR LIBIGL_LIBRARIES IGL_VIEWER_SOURCES)
+
+endif(NOT LIBIGL_FOUND)

+ 1 - 2
tutorial/cmake/FindMOSEK.cmake

@@ -26,6 +26,5 @@ IF (MOSEK_FOUND)
    SET(MOSEK_INCLUDE_DIRS ${MOSEK_INCLUDE_DIR} )
 ELSE (MOSEK_FOUND)
     #add_definitions(-DIGL_NO_MOSEK)
-    message(WARNING "could NOT find MOSEK")
+    #message(WARNING "could NOT find MOSEK")
 ENDIF (MOSEK_FOUND)
-