Selaa lähdekoodia

merge

Former-commit-id: d864a9899823a602db036829029f49c3a7d88866
Wenzel Jakob 11 vuotta sitten
vanhempi
commit
dbc62bc2dd

+ 0 - 0
LICENSE.TXT → LICENSE


+ 147 - 0
README.md

@@ -0,0 +1,147 @@
+libigl - A simple c++ geometry processing library
+=================================================
+
+<http://igl.ethz.ch/projects/libigl/>
+
+Copyright 2013 - Alec Jacobson, Daniele Panozzo, Olga Diamanti, Kenshi
+Takayama, Leo Sacht
+
+This is first and foremost a *header* library. Each header file should contain
+a single function.  The function may have multiple prototypes. All functions
+should use the igl namespace and should adhere to the conventions and styles
+listed below. 
+
+## Dependencies ##
+- Eigen3  Last tested with Eigen Version 3.2
+
+### Optional ###
+- OpenGL (IGL_NO_OPENGL)
+- AntTweakBar  (IGL_NO_ANTTWEAKBAR) Last tested 1.16 (see
+-   libigl/external/AntTweakBar)
+- GLEW  Windows only
+- OpenMP  
+- libpng  libiglpng extra only
+- Mosek  libiglmosek extra only
+- Matlab  libiglmatlab extra only
+- boost  libboost extra only
+
+### Optional (included in external/) ###
+- TetGen  libigltetgen extra only
+- Embree  libiglembree extra only
+- tinyxml2  libiglxml extra only
+ 
+## Header only ##
+libigl is designed to work "out-of-the-box" as a headers only library. To
+include libigl in your project. You need only include the libigl/include/
+directory in your include path and define the IGL_HEADER_ONLY macro. To 
+compile a hello-word example.cpp:
+
+    #include <Eigen/Dense>
+    #include <igl/readOBJ.h>
+    #include <iostream>
+    int main(int argc, char * argv[])
+    {
+      if(argc>1)
+      {
+        Eigen::MatrixXd V;
+        Eigen::MatrixXi F;
+        igl::readOBJ(argv[1],V,F);
+        std::cout<<"Hello, mesh with "<<V.rows()<<" vertices!"<<std::endl;
+      }else{
+        std::cout<<"Hello, world!"<<std::endl;
+      }
+      return 0;
+    }
+
+using gcc (replacing appropriate paths):
+
+    g++ -DIGL_HEADER_ONLY -I/usr/local/igl/libigl/include \
+      -I/opt/local/include/eigen3 example.cpp -o example
+
+Then run this example with:
+
+    ./example examples/shared/TinyTorus.obj
+
+## Compile ##
+libigl is developed most often on Mac OS X, though has current users in Linux and Windows.
+
+### Linux/Mac OS X/Cygwin ###
+  
+libigl may also be compiled to a static library. This is advantageous when
+building a project with libigl, since the header only directive can slow down
+compile times.
+
+To build the entire libigl library producing lib/libigl.a, issue:
+  
+    make lib
+  
+You may need to edit Makefile.conf accordingly. Best to give yourself an
+IGL_USERNAME and add a custom install suite for yourself. Then you can enable
+appropriate extras.
+  
+#### Extras ####
+Once you've set up an IGL_USERNAME and enabled extras within Makefile.conf.
+You can build the extra libraries (into lib/ligiglpng.a, lib/libiglmatlab.a,
+lib/libigltetgen.a, lib/libiglmosek.a, etc.) by issuing:
+  
+    make extras
+  
+#### Examples ####
+You can make a slew of examples by issuing:
+  
+    make examples
+  
+#### External ####
+Finally there are a number of external libraries that we include in
+./external/ because they are either difficult to obtain or they have been
+patched for easier use with libigl. Please see the respective readmes in
+those directories.
+
+## Windows (Experimental) ##
+To build a static library (.lib) on windows, open Visual Studio 2010.
+
+- New > Project ...
+- Visual C++ > Win32
+- Win32 Console Application
+- Name: libiglVisualStudio
+- Uncheck "Create directory for solution"
+- Then hit OK, and then Next
+- Check "Static Library"
+- Uncheck "Precompiled headers"
+- Add all include/igl/*.cpp to the sources directory
+- Add all include/igl/*.h to the headers directory
+- Open Project > libigl Properties...
+- Add the path to eigen3 to the include paths
+- Change the target name to libigl
+- Build and pray (this should create libigl.lib
+
+[Source](http://msdn.microsoft.com/en-us/library/ms235627(v=vs.80).aspx)
+
+## Examples ##
+To get started, we advise that you take a look at a few examples:
+
+    ./examples/hello-world/
+
+    ./examples/meshio/
+
+    ./examples/basic-topology/
+
+    ./examples/ReAntTweakBar/
+
+## Development ##
+Further documentation for developers is listed in tutorial.html,
+style_guidelines.html
+
+## License ##
+See `LICENSE.txt`
+
+## Zipping ##
+Zip this directory without .hg litter using:
+
+    make clean
+    zip -9 -r --exclude=@exclude.lst  libigl.zip ../libigl
+
+## Contact ##
+libigl is a group endeavor led by Alec Jacobson and Daniele Panozzo. Please
+contact [alecjacobson@gmail.com](mailto:alecjacobson@gmail.com) if you have questions or comments. We are happy
+to get feedback! Enjoy!

+ 1 - 0
RELEASE_HISTORY.txt

@@ -1,3 +1,4 @@
+0.4.4  STL file format support
 0.4.3  ARAP implementation
 0.4.3  ARAP implementation
 0.4.1  Migrated much of the FAST code including extra for Sifakis' 3x3 svd
 0.4.1  Migrated much of the FAST code including extra for Sifakis' 3x3 svd
 0.4.0  Release under MPL2 license
 0.4.0  Release under MPL2 license

+ 1 - 1
VERSION.txt

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

+ 50 - 21
examples/arap/example.cpp

@@ -28,6 +28,7 @@
 #include <igl/material_colors.h>
 #include <igl/material_colors.h>
 #include <igl/barycenter.h>
 #include <igl/barycenter.h>
 #include <igl/matlab_format.h>
 #include <igl/matlab_format.h>
+#include <igl/material_colors.h>
 #include <igl/ReAntTweakBar.h>
 #include <igl/ReAntTweakBar.h>
 #include <igl/pathinfo.h>
 #include <igl/pathinfo.h>
 #include <igl/Camera.h>
 #include <igl/Camera.h>
@@ -129,7 +130,7 @@ int width,height;
 // Position of light
 // Position of light
 float light_pos[4] = {0.1,0.1,-0.9,0};
 float light_pos[4] = {0.1,0.1,-0.9,0};
 // Vertex positions, normals, colors and centroid
 // Vertex positions, normals, colors and centroid
-Eigen::MatrixXd V,U,N,mid;
+Eigen::MatrixXd V,U,N,C,mid;
 Eigen::VectorXi S;
 Eigen::VectorXi S;
 igl::ARAPData arap_data;
 igl::ARAPData arap_data;
 Eigen::MatrixXi F;
 Eigen::MatrixXi F;
@@ -163,6 +164,7 @@ bool init_arap()
   using namespace std;
   using namespace std;
   VectorXi b(num_in_selection(S));
   VectorXi b(num_in_selection(S));
   assert(S.rows() == V.rows());
   assert(S.rows() == V.rows());
+  C.resize(S.rows(),3);
   MatrixXd bc = MatrixXd::Zero(b.size(),S.maxCoeff()+1);
   MatrixXd bc = MatrixXd::Zero(b.size(),S.maxCoeff()+1);
   // get b from S
   // get b from S
   {
   {
@@ -174,6 +176,19 @@ bool init_arap()
         b(bi) = v;
         b(bi) = v;
         bc(bi,S(v)) = 1;
         bc(bi,S(v)) = 1;
         bi++;
         bi++;
+        if(S(v) == 0)
+        {
+          C.row(v) = RowVector3d(0.039,0.31,1);
+        }else
+        {
+          C.row(v) = RowVector3d(1,0.41,0.70);
+        }
+      }else
+      {
+        C.row(v) = RowVector3d(
+          GOLD_DIFFUSE[0],
+          GOLD_DIFFUSE[1],
+          GOLD_DIFFUSE[2]);
       }
       }
     }
     }
   }
   }
@@ -208,16 +223,27 @@ bool update_arap()
         {
         {
           case 0:
           case 0:
           {
           {
-            const double r = mid(0)*0.25;
-            bc(bi,0) += r*cos(0.5*get_seconds()*2.*PI);
-            bc(bi,1) -= r+r*sin(0.5*get_seconds()*2.*PI);
+            //const double r = mid(0)*0.25;
+            //bc(bi,0) += r*cos(0.5*get_seconds()*2.*PI);
+            //bc(bi,1) -= r+r*sin(0.5*get_seconds()*2.*PI);
             break;
             break;
           }
           }
           case 1:
           case 1:
           {
           {
-            const double r = mid(1)*0.15;
-            bc(bi,1) += r+r*cos(0.15*get_seconds()*2.*PI);
-            bc(bi,2) -= r*sin(0.15*get_seconds()*2.*PI);
+            //const double r = mid(1)*0.15;
+            //bc(bi,1) += r+r*cos(0.15*get_seconds()*2.*PI);
+            //bc(bi,2) -= r*sin(0.15*get_seconds()*2.*PI);
+
+            //// Pull-up
+            //bc(bi,0) += 0.42;//mid(0)*0.5;
+            //bc(bi,1) += 0.55;//mid(0)*0.5;
+            // Bend
+            Vector3d t(-1,0,0);
+            Quaterniond q(AngleAxisd(PI/1.5,Vector3d(0,1.0,0.1).normalized()));
+            const Vector3d a = bc.row(bi);
+            bc.row(bi) = (q*(a-t) + t) + Vector3d(1.5,0.1,0.9);
+                
+
             break;
             break;
           }
           }
           default:
           default:
@@ -304,7 +330,7 @@ void lights()
   using namespace std;
   using namespace std;
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHTING);
   glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
   glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
-  glEnable(GL_LIGHT0);
+  //glEnable(GL_LIGHT0);
   glEnable(GL_LIGHT1);
   glEnable(GL_LIGHT1);
   float amb[4];
   float amb[4];
   amb[0] = amb[1] = amb[2] = 0;
   amb[0] = amb[1] = amb[2] = 0;
@@ -328,7 +354,8 @@ void lights()
   glLightfv(GL_LIGHT1,GL_POSITION,pos);
   glLightfv(GL_LIGHT1,GL_POSITION,pos);
 }
 }
 
 
-const float back[4] = {30.0/255.0,30.0/255.0,50.0/255.0,0};
+//const float back[4] = {30.0/255.0,30.0/255.0,50.0/255.0,0};
+const float back[4] = {255.0/255.0,255.0/255.0,255.0/255.0,0};
 void display()
 void display()
 {
 {
   using namespace Eigen;
   using namespace Eigen;
@@ -363,17 +390,18 @@ void display()
 
 
   // Draw the model
   // Draw the model
   // Set material properties
   // Set material properties
-  glDisable(GL_COLOR_MATERIAL);
-  glMaterialfv(GL_FRONT, GL_AMBIENT,  GOLD_AMBIENT);
-  glMaterialfv(GL_FRONT, GL_DIFFUSE,  GOLD_DIFFUSE  );
-  glMaterialfv(GL_FRONT, GL_SPECULAR, GOLD_SPECULAR);
-  glMaterialf (GL_FRONT, GL_SHININESS, 128);
-  glMaterialfv(GL_BACK, GL_AMBIENT,  SILVER_AMBIENT);
-  glMaterialfv(GL_BACK, GL_DIFFUSE,  FAST_GREEN_DIFFUSE  );
-  glMaterialfv(GL_BACK, GL_SPECULAR, SILVER_SPECULAR);
-  glMaterialf (GL_BACK, GL_SHININESS, 128);
-
-  draw_mesh(U,F,N);
+  //glDisable(GL_COLOR_MATERIAL);
+  //glMaterialfv(GL_FRONT, GL_AMBIENT,  GOLD_AMBIENT);
+  //glMaterialfv(GL_FRONT, GL_DIFFUSE,  GOLD_DIFFUSE  );
+  //glMaterialfv(GL_FRONT, GL_SPECULAR, GOLD_SPECULAR);
+  //glMaterialf (GL_FRONT, GL_SHININESS, 128);
+  //glMaterialfv(GL_BACK, GL_AMBIENT,  SILVER_AMBIENT);
+  //glMaterialfv(GL_BACK, GL_DIFFUSE,  FAST_GREEN_DIFFUSE  );
+  //glMaterialfv(GL_BACK, GL_SPECULAR, SILVER_SPECULAR);
+  //glMaterialf (GL_BACK, GL_SHININESS, 128);
+  glEnable(GL_COLOR_MATERIAL);
+
+  draw_mesh(U,F,N,C);
   glDisable(GL_COLOR_MATERIAL);
   glDisable(GL_COLOR_MATERIAL);
 
 
   pop_object();
   pop_object();
@@ -387,7 +415,8 @@ void display()
   const float GREY[4] = {0.5,0.5,0.6,1.0};
   const float GREY[4] = {0.5,0.5,0.6,1.0};
   const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
   const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
 
 
-  draw_floor(GREY,DARK_GREY);
+  //draw_floor(GREY,DARK_GREY);
+  draw_floor();
   glPopMatrix();
   glPopMatrix();
 
 
   pop_scene();
   pop_scene();

+ 4 - 2
examples/patches/example.vcxproj

@@ -58,7 +58,7 @@
       </PrecompiledHeader>
       </PrecompiledHeader>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>IGL_HEADER_ONLY;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>EIGEN_DONT_ALIGN_STATICALLY;IGL_HEADER_ONLY;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <AdditionalIncludeDirectories>..\..\external\embree;..\..\external\embree\embree;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>..\..\external\embree;..\..\external\embree\embree;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OpenMPSupport>true</OpenMPSupport>
       <OpenMPSupport>true</OpenMPSupport>
@@ -66,6 +66,7 @@
     <Link>
     <Link>
       <SubSystem>Console</SubSystem>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>glew32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -76,7 +77,7 @@
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <PreprocessorDefinitions>IGL_HEADER_ONLY;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>EIGEN_DONT_ALIGN_STATICALLY;IGL_HEADER_ONLY;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <AdditionalIncludeDirectories>..\..\external\embree;..\..\external\embree\embree;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <AdditionalIncludeDirectories>..\..\external\embree;..\..\external\embree\embree;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OpenMPSupport>true</OpenMPSupport>
       <OpenMPSupport>true</OpenMPSupport>
@@ -87,6 +88,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>false</OptimizeReferences>
       <OptimizeReferences>false</OptimizeReferences>
+      <AdditionalDependencies>glew32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     </Link>
   </ItemDefinitionGroup>
   </ItemDefinitionGroup>
   <ItemGroup>
   <ItemGroup>

+ 20 - 0
examples/quicklook-mesh/Info.plist

@@ -13,6 +13,7 @@
 			<array>
 			<array>
 				<string>org.mesh</string>
 				<string>org.mesh</string>
 				<string>org.obj</string>
 				<string>org.obj</string>
+				<string>org.stl</string>
 				<string>org.off</string>
 				<string>org.off</string>
 				<string>org.wrl</string>
 				<string>org.wrl</string>
 			</array>
 			</array>
@@ -102,6 +103,25 @@
 				</array>
 				</array>
 			</dict>
 			</dict>
 		</dict>
 		</dict>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.image</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>Stereolithography CAD model</string>
+			<key>UTTypeIdentifier</key>
+			<string>org.stl</string>
+			<key>UTTypeReferenceURL</key>
+			<string>http://en.wikipedia.org/wiki/STL_(file_format)</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>stl</string>
+				</array>
+			</dict>
+		</dict>
 		<dict>
 		<dict>
 			<key>UTTypeConformsTo</key>
 			<key>UTTypeConformsTo</key>
 			<array>
 			<array>

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

@@ -13,6 +13,7 @@ extern "C" {
 #include <igl/material_colors.h>
 #include <igl/material_colors.h>
 #include <igl/pathinfo.h>
 #include <igl/pathinfo.h>
 #include <igl/readOBJ.h>
 #include <igl/readOBJ.h>
+#include <igl/readSTL.h>
 #include <igl/readWRL.h>
 #include <igl/readWRL.h>
 #include <igl/triangulate.h>
 #include <igl/triangulate.h>
 #include <igl/readOFF.h>
 #include <igl/readOFF.h>
@@ -375,6 +376,14 @@ bool render_to_buffer(
       red(width,height,buffer);
       red(width,height,buffer);
       return false;
       return false;
     }
     }
+  }else if(ext == "stl")
+  {
+    // Convert extension to lower case
+    if(!igl::readSTL(filename,vV,vF,vN))
+    {
+      red(width,height,buffer);
+      return false;
+    }
   }else
   }else
   {
   {
     // Convert extension to lower case
     // Convert extension to lower case

+ 1 - 0
file-formats/index.html

@@ -36,6 +36,7 @@
     <li><i>.poly</i> Piecewise-linear complex. This format comes in many similar but importantly different flavors: 
     <li><i>.poly</i> Piecewise-linear complex. This format comes in many similar but importantly different flavors: 
       <a href="https://www.cs.cmu.edu/~quake/triangle.poly.html">triangle's</a>, <a href="http://tetgen.berlios.de/fformats.poly.html">tetgen's</a>, <a href="http://sparse-meshing.com/svr/0.2.1/format-poly.html">pyramid/SVR's</a></li>
       <a href="https://www.cs.cmu.edu/~quake/triangle.poly.html">triangle's</a>, <a href="http://tetgen.berlios.de/fformats.poly.html">tetgen's</a>, <a href="http://sparse-meshing.com/svr/0.2.1/format-poly.html">pyramid/SVR's</a></li>
     <li><a href=./rbr.html>.rbr</a> ASCII files for saving state of ReAntTweakBar</li>
     <li><a href=./rbr.html>.rbr</a> ASCII files for saving state of ReAntTweakBar</li>
+    <li><a href=http://en.wikipedia.org/wiki/STL_(file_format)>.stl</a> 3D Systems' CAD and 3D printing mesh file format. ASCII and binary versions.</li>
     <li><a href=http://en.wikipedia.org/wiki/Truevision_TGA>.tga</a> Truevision TGA or TARGA image file format. IGLLIB supports only very basic reading and writing RGB/RGBA files without colormaps and (unverified) run-length compression.</li>
     <li><a href=http://en.wikipedia.org/wiki/Truevision_TGA>.tga</a> Truevision TGA or TARGA image file format. IGLLIB supports only very basic reading and writing RGB/RGBA files without colormaps and (unverified) run-length compression.</li>
     <li><a href="./tgf.html">.tgf</a> ASCII files for representing control handle graphs</li>
     <li><a href="./tgf.html">.tgf</a> ASCII files for representing control handle graphs</li>
     <li><a href="http://en.wikipedia.org/wiki/VRML#WRL_File_Format">.wrl</a>
     <li><a href="http://en.wikipedia.org/wiki/VRML#WRL_File_Format">.wrl</a>

+ 2 - 1
include/igl/cotangent.cpp

@@ -22,6 +22,7 @@ IGL_INLINE void igl::cotangent(const MatV & V, const MatF & F, MatC & C)
   // Number of elements
   // Number of elements
   int m = F.rows();
   int m = F.rows();
 
 
+  // Law of cosines + law of sines
   if(simplex_size == 3)
   if(simplex_size == 3)
   {
   {
     // Triangles
     // Triangles
@@ -39,7 +40,7 @@ IGL_INLINE void igl::cotangent(const MatV & V, const MatF & F, MatC & C)
     // semiperimeters
     // semiperimeters
     Matrix<typename MatC::Scalar,Dynamic,1> s = l.rowwise().sum()*0.5;
     Matrix<typename MatC::Scalar,Dynamic,1> s = l.rowwise().sum()*0.5;
     assert(s.rows() == m);
     assert(s.rows() == m);
-    // Heron's forumal for area
+    // Heron's formula for area
     Matrix<typename MatC::Scalar,Dynamic,1> dblA(m);
     Matrix<typename MatC::Scalar,Dynamic,1> dblA(m);
     for(int i = 0;i<m;i++)
     for(int i = 0;i<m;i++)
     {
     {

+ 2 - 2
include/igl/draw_mesh.cpp

@@ -89,9 +89,9 @@ IGL_INLINE void igl::draw_mesh(
   {
   {
     assert(F.maxCoeff() < V.rows());
     assert(F.maxCoeff() < V.rows());
     assert(V.cols() == 3);
     assert(V.cols() == 3);
-    assert(C.rows() == V.rows() || C.rows() == F.rows()*3 || C.size() == 0);
+    assert(rC == rV || rC == rF || rC == rF*3 || C.size() == 0);
     assert(C.cols() == 3 || C.size() == 0);
     assert(C.cols() == 3 || C.size() == 0);
-    assert(N.cols() == 3);
+    assert(N.cols() == 3 || N.size() == 0);
     assert(TC.cols() == 2 || TC.size() == 0);
     assert(TC.cols() == 2 || TC.size() == 0);
   }
   }
   if(W.size()>0)
   if(W.size()>0)

+ 226 - 0
include/igl/embree/reorient_facets_raycast.cpp

@@ -0,0 +1,226 @@
+// 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "reorient_facets_raycast.h"
+#include "../per_face_normals.h"
+#include "../doublearea.h"
+#include "../random_dir.h"
+#include "../boost/bfs_orient.h"
+#include "orient_outward_ao.h"
+#include "EmbreeIntersector.h"
+#include <iostream>
+#include <random>
+#include <ctime>
+#include <limits>
+
+  template <
+    typename DerivedV, 
+    typename DerivedF, 
+    typename DerivedI>
+  IGL_INLINE void igl::reorient_facets_raycast(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    int rays_total,
+    int rays_minimum,
+    bool face_wise,
+    bool use_parity,
+    bool is_verbose,
+    Eigen::PlainObjectBase<DerivedI> & I)
+{
+  using namespace Eigen;
+  using namespace std;
+  assert(F.cols() == 3);
+  assert(V.cols() == 3);
+  
+  // number of faces
+  const int m = F.rows();
+  
+  VectorXi C;
+  MatrixXi FF = F;
+  if (face_wise) {
+    C.resize(m);
+    for (int i = 0; i < m; ++i) C(i) = i;
+  
+  } else {
+    if (is_verbose) cout << "extracting patches... ";
+    bfs_orient(F,FF,C);
+  }
+  if (is_verbose) cout << (C.maxCoeff() + 1)  << " components. ";
+  
+  // number of patches
+  const int num_cc = C.maxCoeff()+1;
+  
+  // Init Embree
+  EmbreeIntersector ei;
+  ei.init(V.template cast<float>(),FF);
+  
+  // face normal
+  MatrixXd N;
+  per_face_normals(V,FF,N);
+  
+  // face area
+  Matrix<typename DerivedV::Scalar,Dynamic,1> A;
+  doublearea(V,FF,A);
+  double area_min = numeric_limits<double>::max();
+  for (int f = 0; f < m; ++f)
+  {
+    area_min = A(f) != 0 && A(f) < area_min ? A(f) : area_min;
+  }
+  double area_total = A.sum();
+  
+  // determine number of rays per component according to its area
+  VectorXd area_per_component;
+  area_per_component.setZero(num_cc);
+  for (int f = 0; f < m; ++f)
+  {
+    area_per_component(C(f)) += A(f);
+  }
+  VectorXi num_rays_per_component(num_cc);
+  for (int c = 0; c < num_cc; ++c)
+  {
+    num_rays_per_component(c) = max<int>(static_cast<int>(rays_total * area_per_component(c) / area_total), rays_minimum);
+  }
+  rays_total = num_rays_per_component.sum();
+  
+  // generate all the rays
+  if (is_verbose) cout << "generating rays... ";
+  uniform_real_distribution<float> rdist;
+  mt19937 prng;
+  prng.seed(time(nullptr));
+  vector<int     > ray_face;
+  vector<Vector3f> ray_ori;
+  vector<Vector3f> ray_dir;
+  ray_face.reserve(rays_total);
+  ray_ori .reserve(rays_total);
+  ray_dir .reserve(rays_total);
+  for (int c = 0; c < num_cc; ++c)
+  {
+    if (area_per_component[c] == 0)
+    {
+      continue;
+    }
+    vector<int> CF;     // set of faces per component
+    vector<unsigned long long> CF_area;
+    for (int f = 0; f < m; ++f)
+    {
+      if (C(f)==c)
+      {
+        CF.push_back(f);
+        CF_area.push_back(static_cast<unsigned long long>(100 * A(f) / area_min));
+      }
+    }
+    // discrete distribution for random selection of faces with probability proportional to their areas
+    auto ddist_func = [&] (double i) { return CF_area[static_cast<int>(i)]; };
+    discrete_distribution<int> ddist(CF.size(), 0, CF.size(), ddist_func);      // simple ctor of (Iter, Iter) not provided by the stupid VC11 impl...
+    for (int i = 0; i < num_rays_per_component[c]; ++i)
+    {
+      int f = CF[ddist(prng)];          // select face with probability proportional to face area
+      float s = rdist(prng);            // random barycentric coordinate (reference: Generating Random Points in Triangles [Turk, Graphics Gems I 1990])
+      float t = rdist(prng);
+      float sqrt_t = sqrtf(t);
+      float a = 1 - sqrt_t;
+      float b = (1 - s) * sqrt_t;
+      float c = s * sqrt_t;
+      Vector3f p = a * V.row(FF(f,0)).template cast<float>().eval()       // be careful with the index!!!
+                 + b * V.row(FF(f,1)).template cast<float>().eval()
+                 + c * V.row(FF(f,2)).template cast<float>().eval();
+      Vector3f n = N.row(f).cast<float>();
+      if (n.isZero()) continue;
+      // random direction in hemisphere around n (avoid too grazing angle)
+      Vector3f d;
+      while (true) {
+        d = random_dir().cast<float>();
+        float ndotd = n.dot(d);
+        if (fabsf(ndotd) < 0.1f)
+        {
+          continue;
+        }
+        if (ndotd < 0)
+        {
+          d *= -1.0f;
+        }
+        break;
+      }
+      ray_face.push_back(f);
+      ray_ori .push_back(p);
+      ray_dir .push_back(d);
+
+      if (is_verbose && ray_face.size() % (rays_total / 10) == 0) cout << ".";
+    }
+  }
+  if (is_verbose) cout << ray_face.size()  << " rays. ";
+  
+  // per component voting: first=front, second=back
+  vector<pair<float, float>> C_vote_distance(num_cc, make_pair(0, 0));      // sum of distance between ray origin and intersection
+  vector<pair<int  , int  >> C_vote_infinity(num_cc, make_pair(0, 0));      // number of rays reaching infinity
+  vector<pair<int  , int  >> C_vote_parity(num_cc, make_pair(0, 0));        // sum of parity count for each ray
+  
+  if (is_verbose) cout << "shooting rays... ";
+#pragma omp parallel for
+  for (int i = 0; i < (int)ray_face.size(); ++i)
+  {
+    int      f = ray_face[i];
+    Vector3f o = ray_ori [i];
+    Vector3f d = ray_dir [i];
+    int c = C(f);
+    
+    // shoot ray toward front & back
+    vector<Hit> hits_front;
+    vector<Hit> hits_back;
+    int num_rays_front;
+    int num_rays_back;
+    ei.intersectRay(o,  d, hits_front, num_rays_front);
+    ei.intersectRay(o, -d, hits_back , num_rays_back );
+    if (!hits_front.empty() && hits_front[0].id == f) hits_front.erase(hits_front.begin());
+    if (!hits_back .empty() && hits_back [0].id == f) hits_back .erase(hits_back .begin());
+    
+    if (use_parity) {
+#pragma omp atomic
+      C_vote_parity[c].first  += hits_front.size() % 2;
+#pragma omp atomic
+      C_vote_parity[c].second += hits_back .size() % 2;
+    
+    } else {
+      if (hits_front.empty())
+      {
+#pragma omp atomic
+        C_vote_infinity[c].first++;
+      } else {
+#pragma omp atomic
+        C_vote_distance[c].first += hits_front[0].t;
+      }
+    
+      if (hits_back.empty())
+      {
+#pragma omp atomic
+        C_vote_infinity[c].second++;
+      } else {
+#pragma omp atomic
+        C_vote_distance[c].second += hits_back[0].t;
+      }
+    }
+  }
+  
+  I.resize(m);
+  for(int f = 0; f < m; ++f)
+  {
+    int c = C(f);
+    if (use_parity) {
+      I(f) = C_vote_parity[c].first > C_vote_parity[c].second ? 1 : 0;      // Ideally, parity for the front/back side should be 1/0 (i.e., parity sum for all rays should be smaller on the front side)
+    
+    } else {
+      I(f) = (C_vote_infinity[c].first == C_vote_infinity[c].second && C_vote_distance[c].first <  C_vote_distance[c].second) ||
+              C_vote_infinity[c].first <  C_vote_infinity[c].second
+              ? 1 : 0;
+    }
+  }
+  if (is_verbose) cout << "done!" << endl;
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+#endif

+ 46 - 0
include/igl/embree/reorient_facets_raycast.h

@@ -0,0 +1,46 @@
+// 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ORIENT_OUTWARD_AO_H
+#define IGL_ORIENT_OUTWARD_AO_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // Orient each component (identified by C) of a mesh (V,F) using ambient occlusion 
+  // such that the front side is less occluded than back side
+  //
+  // Inputs:
+  //   V                            #V by 3 list of vertex positions
+  //   F                            #F by 3 list of triangle indices
+  //   rays_total                   Total number of rays that will be shot
+  //   rays_minimum                 Minimum number of rays that each patch should receive
+  //   face_wise                    Decision made for each face independently, no use of patches (i.e., each face is treated as a patch)
+  //   use_parity                   Use parity mode
+  //   is_verbose                   Verbose output to cout
+  // Outputs:
+  //   I                            #F list of whether face has been flipped
+  template <
+    typename DerivedV, 
+    typename DerivedF, 
+    typename DerivedI>
+  IGL_INLINE void reorient_facets_raycast(
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    int rays_total,
+    int rays_minimum,
+    bool face_wise,
+    bool use_parity,
+    bool is_verbose,
+    Eigen::PlainObjectBase<DerivedI> & I);
+};
+
+#ifdef IGL_HEADER_ONLY
+#  include "reorient_facets_raycast.cpp"
+#endif
+
+#endif

+ 1 - 0
include/igl/project.cpp

@@ -117,6 +117,7 @@ template Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > igl::proj
 template int igl::project<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
 template int igl::project<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
 template Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > igl::project<Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&);
 template Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > igl::project<Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&);
 template Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > igl::project<Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&);
 template Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > igl::project<Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&);
+template int igl::project<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
 #endif
 #endif
 
 
 #endif
 #endif

+ 19 - 19
include/igl/readOBJ.cpp

@@ -38,7 +38,7 @@ IGL_INLINE bool igl::readOBJ(
   F.clear();
   F.clear();
   FTC.clear();
   FTC.clear();
   FN.clear();
   FN.clear();
-  
+
   // variables an constants to assist parsing the .obj file
   // variables an constants to assist parsing the .obj file
   // Constant strings to compare against
   // Constant strings to compare against
   std::string v("v");
   std::string v("v");
@@ -46,15 +46,15 @@ IGL_INLINE bool igl::readOBJ(
   std::string vt("vt");
   std::string vt("vt");
   std::string f("f");
   std::string f("f");
   std::string tic_tac_toe("#");
   std::string tic_tac_toe("#");
-#ifndef LINE_MAX
-#  define LINE_MAX 2048
+#ifndef IGL_LINE_MAX
+#  define IGL_LINE_MAX 2048
 #endif
 #endif
-  
-  char line[LINE_MAX];
+
+  char line[IGL_LINE_MAX];
   int line_no = 1;
   int line_no = 1;
-  while (fgets(line, LINE_MAX, obj_file) != NULL) 
+  while (fgets(line, IGL_LINE_MAX, obj_file) != NULL) 
   {
   {
-    char type[LINE_MAX];
+    char type[IGL_LINE_MAX];
     // Read first word containing type
     // Read first word containing type
     if(sscanf(line, "%s",type) == 1)
     if(sscanf(line, "%s",type) == 1)
     {
     {
@@ -123,7 +123,7 @@ IGL_INLINE bool igl::readOBJ(
         std::vector<Index > ftc;
         std::vector<Index > ftc;
         std::vector<Index > fn;
         std::vector<Index > fn;
         // Read each "word" after type
         // Read each "word" after type
-        char word[LINE_MAX];
+        char word[IGL_LINE_MAX];
         int offset;
         int offset;
         while(sscanf(l,"%s%n",word,&offset) == 1)
         while(sscanf(l,"%s%n",word,&offset) == 1)
         {
         {
@@ -196,10 +196,10 @@ IGL_INLINE bool igl::readOBJ(
     line_no++;
     line_no++;
   }
   }
   fclose(obj_file);
   fclose(obj_file);
-  
+
   assert(F.size() == FN.size());
   assert(F.size() == FN.size());
   assert(F.size() == FTC.size());
   assert(F.size() == FTC.size());
-  
+
   return true;
   return true;
 }
 }
 
 
@@ -243,7 +243,7 @@ IGL_INLINE bool igl::readOBJ(
       return false;
       return false;
     }
     }
   }
   }
-  
+
   if(!vFN.empty())
   if(!vFN.empty())
   {
   {
     bool FN_rect = igl::list_to_matrix(vFN,FN);
     bool FN_rect = igl::list_to_matrix(vFN,FN);
@@ -253,10 +253,10 @@ IGL_INLINE bool igl::readOBJ(
       return false;
       return false;
     }
     }
   }
   }
-  
+
   if(!vTC.empty())
   if(!vTC.empty())
   {
   {
-    
+
     bool T_rect = igl::list_to_matrix(vTC,TC);
     bool T_rect = igl::list_to_matrix(vTC,TC);
     if(!T_rect)
     if(!T_rect)
     {
     {
@@ -266,7 +266,7 @@ IGL_INLINE bool igl::readOBJ(
   }
   }
   if(!vFTC.empty())
   if(!vFTC.empty())
   {
   {
-    
+
     bool FTC_rect = igl::list_to_matrix(vFTC,FTC);
     bool FTC_rect = igl::list_to_matrix(vFTC,FTC);
     if(!FTC_rect)
     if(!FTC_rect)
     {
     {
@@ -308,31 +308,31 @@ IGL_INLINE bool igl::readOBJPoly(
     return false;
     return false;
 
 
   F = vF;
   F = vF;
-  
+
   if(!vN.empty())
   if(!vN.empty())
   {
   {
     bool VN_rect = igl::list_to_matrix(vN,CN);
     bool VN_rect = igl::list_to_matrix(vN,CN);
     if(!VN_rect)
     if(!VN_rect)
       return false;
       return false;
   }
   }
-  
+
   if(!vFN.empty())
   if(!vFN.empty())
   {
   {
     bool FN_rect = igl::list_to_matrix(vFN,FN);
     bool FN_rect = igl::list_to_matrix(vFN,FN);
     if(!FN_rect)
     if(!FN_rect)
       return false;
       return false;
   }
   }
-  
+
   if(!vTC.empty())
   if(!vTC.empty())
   {
   {
-    
+
     bool T_rect = igl::list_to_matrix(vTC,TC);
     bool T_rect = igl::list_to_matrix(vTC,TC);
     if(!T_rect)
     if(!T_rect)
       return false;
       return false;
   }
   }
   if(!vFTC.empty())
   if(!vFTC.empty())
   {
   {
-    
+
     bool FTC_rect = igl::list_to_matrix(vFTC,FTC);
     bool FTC_rect = igl::list_to_matrix(vFTC,FTC);
     if(!FTC_rect)
     if(!FTC_rect)
       return false;
       return false;

+ 212 - 0
include/igl/readSTL.cpp

@@ -0,0 +1,212 @@
+#include "readSTL.h"
+#include "list_to_matrix.h"
+
+#include <iostream>
+template <typename DerivedV, typename DerivedF, typename DerivedN>
+IGL_INLINE bool igl::readSTL(
+  const std::string & filename,
+  Eigen::PlainObjectBase<DerivedV> & V,
+  Eigen::PlainObjectBase<DerivedF> & F,
+  Eigen::PlainObjectBase<DerivedN> & N)
+{
+  using namespace std;
+  vector<vector<typename DerivedV::Scalar> > vV;
+  vector<vector<typename DerivedN::Scalar> > vN;
+  vector<vector<typename DerivedF::Scalar> > vF;
+  if(!readSTL(filename,vV,vF,vN))
+  {
+    return false;
+  }
+
+  if(!list_to_matrix(vV,V))
+  {
+    return false;
+  }
+
+  if(!list_to_matrix(vF,F))
+  {
+    return false;
+  }
+
+  if(!list_to_matrix(vN,N))
+  {
+    return false;
+  }
+  return true;
+}
+
+template <typename TypeV, typename TypeF, typename TypeN>
+IGL_INLINE bool igl::readSTL(
+  const std::string & filename,
+  std::vector<std::vector<TypeV> > & V,
+  std::vector<std::vector<TypeF> > & F,
+  std::vector<std::vector<TypeN> > & N)
+{
+  using namespace std;
+  // Should test for ascii
+
+  // Open file, and check for error
+  FILE * stl_file = fopen(filename.c_str(),"r");
+  if(NULL==stl_file)
+  {
+    fprintf(stderr,"IOError: %s could not be opened...\n",
+            filename.c_str());
+    return false;
+  }
+  V.clear();
+  F.clear();
+  N.clear();
+#ifndef IGL_LINE_MAX
+#  define IGL_LINE_MAX 2048
+#endif
+  char solid[IGL_LINE_MAX];
+  if(fscanf(stl_file,"%s",solid)!=1)
+  {
+    // file too short
+    cerr<<"IOError: "<<filename<<" too short."<<endl;
+    goto close_false;
+  }
+  if(string("solid") == solid)
+  {
+    // Eat file name
+    char name[IGL_LINE_MAX];
+    if(NULL==fgets(name,IGL_LINE_MAX,stl_file))
+    {
+      cerr<<"IOError: "<<filename<<" too short."<<endl;
+      goto close_false;
+    }
+    // ascii
+    while(true)
+    {
+      int ret;
+      char facet[IGL_LINE_MAX],normal[IGL_LINE_MAX];
+      vector<TypeN > n(3);
+      ret = fscanf(stl_file,"%s %s %lg %lg %lg",facet,normal,&n[0],&n[1],&n[2]);
+      if(string("endsolid") == facet)
+      {
+        break;
+      }
+      if(ret != 5 || string("facet") != facet || string("normal") != normal)
+      {
+        cerr<<"IOError: "<<filename<<" bad format (1)."<<endl;
+        goto close_false;
+      }
+      N.push_back(n);
+      char outer[IGL_LINE_MAX], loop[IGL_LINE_MAX];
+      ret = fscanf(stl_file,"%s %s",outer,loop);
+      if(ret != 2 || string("outer") != outer || string("loop") != loop)
+      {
+        cerr<<"IOError: "<<filename<<" bad format (2)."<<endl;
+        goto close_false;
+      }
+      vector<TypeF> f;
+      while(true)
+      {
+        char word[IGL_LINE_MAX];
+        int ret = fscanf(stl_file,"%s",word);
+        if(ret == 1 && string("endloop") == word)
+        {
+          break;
+        }else if(ret == 1 && string("vertex") == word)
+        {
+          vector<TypeV> v(3);
+          int ret = fscanf(stl_file,"%lg %lg %lg",&v[0],&v[1],&v[2]);
+          if(ret != 3)
+          {
+            cerr<<"IOError: "<<filename<<" bad format (3)."<<endl;
+            goto close_false;
+          }
+          f.push_back(V.size());
+          V.push_back(v);
+        }else
+        {
+          cerr<<"IOError: "<<filename<<" bad format (4)."<<endl;
+          goto close_false;
+        }
+      }
+      F.push_back(f);
+      char endfacet[IGL_LINE_MAX];
+      ret = fscanf(stl_file,"%s",endfacet);
+      if(ret != 1 || string("endfacet") != endfacet)
+      {
+        cerr<<"IOError: "<<filename<<" bad format (5)."<<endl;
+        goto close_false;
+      }
+    }
+    // read endfacet
+    fclose(stl_file);
+    goto close_true;
+  }else
+  {
+    // Binary
+    fclose(stl_file);
+    stl_file = fopen(filename.c_str(),"rb");
+    if(NULL==stl_file)
+    {
+      fprintf(stderr,"IOError: %s could not be opened...\n",
+              filename.c_str());
+      return false;
+    }
+    // Read 80 header
+    char header[80];
+    if(fread(header,sizeof(char),80,stl_file)!=80)
+    {
+      cerr<<"IOError: "<<filename<<" bad format (1)."<<endl;
+      goto close_false;
+    }
+    // Read number of triangles
+    unsigned int num_tri;
+    if(fread(&num_tri,sizeof(unsigned int),1,stl_file)!=1)
+    {
+      cerr<<"IOError: "<<filename<<" bad format (2)."<<endl;
+      goto close_false;
+    }
+    V.resize(num_tri*3,vector<TypeV >(3,0));
+    N.resize(num_tri,vector<TypeN >(3,0));
+    F.resize(num_tri,vector<TypeF >(3,0));
+    for(int t = 0;t<num_tri;t++)
+    {
+      // Read normal
+      float n[3];
+      if(fread(n,sizeof(float),3,stl_file)!=3)
+      {
+        cerr<<"IOError: "<<filename<<" bad format (3)."<<endl;
+        goto close_false;
+      }
+      // Read each vertex
+      for(int c = 0;c<3;c++)
+      {
+        F[t][c] = 3*t+c;
+        N[t][c] = n[c];
+        float v[3];
+        if(fread(v,sizeof(float),3,stl_file)!=3)
+        {
+          cerr<<"IOError: "<<filename<<" bad format (4)."<<endl;
+          goto close_false;
+        }
+        V[3*t+c][0] = v[0];
+        V[3*t+c][1] = v[1];
+        V[3*t+c][2] = v[2];
+      }
+      // Read attribute size
+      unsigned short att_count;
+      if(fread(&att_count,sizeof(unsigned short),1,stl_file)!=1)
+      {
+        cerr<<"IOError: "<<filename<<" bad format (5)."<<endl;
+        goto close_false;
+      }
+    }
+    goto close_true;
+  }
+close_false:
+  fclose(stl_file);
+  return false;
+close_true:
+  fclose(stl_file);
+  return true;
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template instanciation
+template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif

+ 57 - 0
include/igl/readSTL.h

@@ -0,0 +1,57 @@
+// 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READSTL_H
+#define IGL_READSTL_H
+#include "igl_inline.h"
+
+#ifndef IGL_NO_EIGEN
+#  include <Eigen/Core>
+#endif
+#include <string>
+#include <vector>
+
+namespace igl 
+{
+  // Read a mesh from an ascii/binary stl file.
+  //
+  // Templates:
+  //   Scalar  type for positions and vectors (will be read as double and cast
+  //     to Scalar)
+  // Inputs:
+  //   filename path to .obj file
+  // Outputs:
+  //   V  double matrix of vertex positions  #F*3 by 3
+  //   F  index matrix of triangle indices #F by 3
+  //   N  double matrix of vertex positions  #F by 3
+  // Returns true on success, false on errors
+  //
+  // Example:
+  //   bool success = readSTL(filename,temp_V,F,N);
+  //   remove_duplicate_vertices(temp_V,0,V,SVI,SVJ);
+  //   for_each(F.data(),F.data()+F.size(),[&SVJ](int & f){f=SVJ(f);});
+  //   writeOBJ("Downloads/cat.obj",V,F);
+  template <typename DerivedV, typename DerivedF, typename DerivedN>
+  IGL_INLINE bool readSTL(
+    const std::string & filename,
+    Eigen::PlainObjectBase<DerivedV> & V,
+    Eigen::PlainObjectBase<DerivedF> & F,
+    Eigen::PlainObjectBase<DerivedN> & N);
+  template <typename TypeV, typename TypeF, typename TypeN>
+  IGL_INLINE bool readSTL(
+    const std::string & filename,
+    std::vector<std::vector<TypeV> > & V,
+    std::vector<std::vector<TypeF> > & F,
+    std::vector<std::vector<TypeN> > & N);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "readSTL.cpp"
+#endif
+
+#endif
+

+ 101 - 0
include/igl/writeSTL.cpp

@@ -0,0 +1,101 @@
+#include "writeSTL.h"
+
+template <typename DerivedV, typename DerivedF, typename DerivedN>
+IGL_INLINE bool igl::writeSTL(
+  const std::string & filename,
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  const Eigen::PlainObjectBase<DerivedN> & N,
+  const bool ascii)
+{
+  using namespace std;
+  assert(N.rows() == 0 || F.rows() == N.rows());
+  if(ascii)
+  {
+    FILE * stl_file = fopen(filename.c_str(),"w");
+    if(stl_file == NULL)
+    {
+      cerr<<"IOError: "<<filename<<" could not be opened for writing."<<endl;
+      return false;
+    }
+    fprintf(stl_file,"solid %s\n",filename.c_str());
+    for(int f = 0;f<F.rows();f++)
+    {
+      fprintf(stl_file,"facet normal ");
+      if(N.rows()>0)
+      {
+        fprintf(stl_file,"%e %e %e\n",
+          (float)N(f,0),
+          (float)N(f,1),
+          (float)N(f,2));
+      }else
+      {
+        fprintf(stl_file,"0 0 0\n");
+      }
+      fprintf(stl_file,"outer loop\n");
+      for(int c = 0;c<F.cols();c++)
+      {
+        fprintf(stl_file,"vertex %e %e %e\n",
+          (float)V(F(f,c),0),
+          (float)V(F(f,c),1),
+          (float)V(F(f,c),2));
+      }
+      fprintf(stl_file,"endloop\n");
+      fprintf(stl_file,"endfacet\n");
+    }
+    fprintf(stl_file,"endsolid %s\n",filename.c_str());
+    fclose(stl_file);
+    return true;
+  }else
+  {
+    FILE * stl_file = fopen(filename.c_str(),"wb");
+    if(stl_file == NULL)
+    {
+      cerr<<"IOError: "<<filename<<" could not be opened for writing."<<endl;
+      return false;
+    }
+    // Write unused 80-char header
+    for(char h = 0;h<80;h++)
+    {
+      fwrite(&h,sizeof(char),1,stl_file);
+    }
+    // Write number of triangles
+    unsigned int num_tri = F.rows();
+    fwrite(&num_tri,sizeof(unsigned int),1,stl_file);
+    assert(F.cols() == 3);
+    // Write each triangle
+    for(int f = 0;f<F.rows();f++)
+    {
+      vector<float> n(3,0);
+      if(N.rows() > 0)
+      {
+        n[0] = N(f,0);
+        n[1] = N(f,1);
+        n[2] = N(f,2);
+      }
+      fwrite(&n[0],sizeof(float),3,stl_file);
+      for(int c = 0;c<3;c++)
+      {
+        vector<float> v(3);
+        v[0] = V(F(f,c),0);
+        v[1] = V(F(f,c),1);
+        v[2] = V(F(f,c),2);
+        fwrite(&v[0],sizeof(float),3,stl_file);
+      }
+      unsigned short att_count = 0;
+      fwrite(&att_count,sizeof(unsigned short),1,stl_file);
+    }
+    fclose(stl_file);
+    return true;
+  }
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::writeSTL(
+  const std::string & filename,
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  const bool ascii)
+{
+  return writeSTL(filename,V,F, Eigen::PlainObjectBase<DerivedV>(), ascii);
+}

+ 52 - 0
include/igl/writeSTL.h

@@ -0,0 +1,52 @@
+// 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 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITESTL_H
+#define IGL_WRITESTL_H
+#include "igl_inline.h"
+
+#ifndef IGL_NO_EIGEN
+#  include <Eigen/Core>
+#endif
+#include <string>
+#include <vector>
+
+namespace igl 
+{
+  // Write a mesh to an stl file.
+  //
+  // Templates:
+  //   Scalar  type for positions and vectors (will be read as double and cast
+  //     to Scalar)
+  // Inputs:
+  //   filename path to .obj file
+  //   V  double matrix of vertex positions  #F*3 by 3
+  //   F  index matrix of triangle indices #F by 3
+  //   N  double matrix of vertex positions  #F by 3
+  //   asci  write ascii file {true}
+  // Returns true on success, false on errors
+  //
+  template <typename DerivedV, typename DerivedF, typename DerivedN>
+  IGL_INLINE bool writeSTL(
+    const std::string & filename,
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    const Eigen::PlainObjectBase<DerivedN> & N,
+    const bool ascii=true);
+  template <typename DerivedV, typename DerivedF>
+  IGL_INLINE bool writeSTL(
+    const std::string & filename,
+    const Eigen::PlainObjectBase<DerivedV> & V,
+    const Eigen::PlainObjectBase<DerivedF> & F,
+    const bool ascii=true);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "writeSTL.cpp"
+#endif
+
+#endif

+ 9 - 3
matlab-to-eigen.html

@@ -6,7 +6,7 @@
     <table>
     <table>
       <tr class="header">
       <tr class="header">
         <th>MATLAB</th>
         <th>MATLAB</th>
-        <th>Eigen</th>
+        <th>Eigen with libigl</th>
         <th>Notes</th>
         <th>Notes</th>
       </tr>
       </tr>
 
 
@@ -202,13 +202,19 @@
       </tr>
       </tr>
 
 
       <tr class=d0>
       <tr class=d0>
-        <td><pre><code>B = IM(A)</code></pre></td>
+        <td><pre><code>B = IM(A)
+
+A = IM(A);
+  </code></pre></td>
         <td><pre><code>B = A.unaryExpr(bind1st(mem_fun( 
         <td><pre><code>B = A.unaryExpr(bind1st(mem_fun( 
   static_cast&lt;VectorXi::Scalar&amp;(VectorXi::*)(VectorXi::Index)&gt;
   static_cast&lt;VectorXi::Scalar&amp;(VectorXi::*)(VectorXi::Index)&gt;
   (&amp;VectorXi::operator())), &amp;IM)).eval();
   (&amp;VectorXi::operator())), &amp;IM)).eval();
+
+for_each(A.data(),A.data()+A.size(),[&amp;IM](int &amp; a){a=IM(a);});
   </code></pre></td>
   </code></pre></td>
         <td>Where IM is an "index map" column vector and A is an arbitrary
         <td>Where IM is an "index map" column vector and A is an arbitrary
-        matrix. The <code>.eval()</code> is not necessary if A != B</td>
+        matrix. The <code>.eval()</code> is not necessary if A != B, but then
+        the second option should be used.</td>
       </tr>
       </tr>
 
 
       <tr class=d1>
       <tr class=d1>

+ 0 - 153
readme.txt

@@ -1,153 +0,0 @@
-libigl - A simple c++ geometry processing library
-
-http://igl.ethz.ch/projects/libigl/
-
-Copyright 2013 - Alec Jacobson, Daniele Panozzo, Olga Diamanti, Kenshi
-Takayama, Leo Sacht, Interactive Geometry Lab - ETH Zurich
-
-This is first and foremost a *header* library. Each header file should contain
-a single function.  The function may have multiple prototypes. All functions
-should use the igl namespace and should adhere to the conventions and styles
-listed below. 
-
-= Dependencies =
-Eigen3  Last tested with Eigen Version 3.2
-
-  = Optional =
-  OpenGL (IGL_NO_OPENGL)
-  AntTweakBar  (IGL_NO_ANTTWEAKBAR) Last tested 1.16 (see
-    libigl/external/AntTweakBar)
-  GLEW  Windows only
-  OpenMP  
-  libpng  libiglpng extra only
-  Mosek  libiglmosek extra only
-  Matlab  libiglmatlab extra only
-  boost  libboost extra only
-
-  = Optional (included in external/ =
-  TetGen  libigltetgen extra only
-  Embree  libiglembree extra only
-  tinyxml2  libiglxml extra only
-
-= Header only =
-libigl is designed to work "out-of-the-box" as a headers only library. To
-include libigl in your project. You need only include the libigl/include/
-directory in your include path and define the IGL_HEADER_ONLY macro. To 
-compile a hello-word example.cpp:
-
-#include <Eigen/Dense>
-#include <igl/readOBJ.h>
-#include <iostream>
-int main(int argc, char * argv[])
-{
-  if(argc>1)
-  {
-    Eigen::MatrixXd V;
-    Eigen::MatrixXi F;
-    igl::readOBJ(argv[1],V,F);
-    std::cout<<"Hello, mesh with "<<V.rows()<<" vertices!"<<std::endl;
-  }else{
-    std::cout<<"Hello, world!"<<std::endl;
-  }
-  return 0;
-}
-
-using gcc (replacing appropriate paths):
-
-g++ -DIGL_HEADER_ONLY -I/usr/local/igl/libigl/include \
-  -I/opt/local/include/eigen3 example.cpp -o example
-
-Then run this example with:
-
-./example examples/shared/TinyTorus.obj
-
-= Compile =
-
-  = Linux/Mac OS X/Cygwin =
-  
-  libigl may also be compiled to a static library. This is advantageous when
-  building a project with libigl, since the header only directive can slow down
-  compile times.
-  
-  To build the entire libigl library producing lib/libigl.a, issue:
-  
-  make lib
-  
-  You may need to edit Makefile.conf accordingly. Best to give yourself an
-  IGL_USERNAME and add a custom install suite for yourself. Then you can enable
-  appropriate extras.
-  
-    = Extras =
-    Once you've set up an IGL_USERNAME and enabled extras within Makefile.conf.
-    You can build the extra libraries (into lib/ligiglpng.a, lib/libiglmatlab.a,
-    lib/libigltetgen.a, lib/libiglmosek.a, etc.) by issuing:
-  
-    make extras
-  
-    = Examples =
-    You can make a slew of examples by issuing:
-  
-    make examples
-  
-    = External =
-    Finally there are a number of external libraries that we include in
-    ./external/ because they are either difficult to obtain or they have been
-    patched for easier use with libigl. Please see the respective readmes in
-    those directories.
-
-  = Windows (Experimental) =
-  To build a static library (.lib) on windows, open Visual Studio 2010.
-
-  New > Project ...
-  Visual C++ > Win32
-  Win32 Console Application
-  Name: libiglVisualStudio
-  Uncheck "Create directory for solution"
-  
-  Then hit OK, and then Next
-
-  Check "Static Library"
-  Uncheck "Precompiled headers"
-
-  Add all include/igl/*.cpp to the sources directory
-  Add all include/igl/*.h to the headers directory
-
-  Open Project > libigl Properties...
-  Add the path to eigen3 to the include paths
-  Change the target name to libigl
-
-  Build and pray (this should create libigl.lib
-
-    = Source =
-    http://msdn.microsoft.com/en-us/library/ms235627(v=vs.80).aspx
-
-= Examples =
-To get started, we advise that you take a look at a few examples:
-
-  ./examples/hello-world/
-
-  ./examples/meshio/
-
-  ./examples/basic-topology/
-
-  ./examples/ReAntTweakBar/
-
-= Development =
-Further documentation for developers is listed in tutorial.html,
-style_guidelines.html
-
-= License =
-For now, all files are Copyright 2013 - Alec Jacobson, Daniele Panozzo, Olga
-Diamanti, Kenshi Takayama, Leo Sacht, Interactive Geometry Lab - ETH Zurich
-unless otherwise noted. Soon we hope to upgrade to a more liberal license.
-
-= Zipping =
-Zip this directory without .hg litter using:
-
-make clean
-zip -9 -r --exclude=@exclude.lst  libigl.zip ../libigl
-
-= Contact =
-libigl is a group endeavor led by Alec Jacobson and Daniele Panozzo. Please
-contact alecjacobson@gmail.com if you have questions or comments. We are happy
-to get feedback! Enjoy!