Kaynağa Gözat

merge

Former-commit-id: d864a9899823a602db036829029f49c3a7d88866
Wenzel Jakob 11 yıl önce
ebeveyn
işleme
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.1  Migrated much of the FAST code including extra for Sifakis' 3x3 svd
 0.4.0  Release under MPL2 license

+ 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
-0.4.3
+0.4.4

+ 50 - 21
examples/arap/example.cpp

@@ -28,6 +28,7 @@
 #include <igl/material_colors.h>
 #include <igl/barycenter.h>
 #include <igl/matlab_format.h>
+#include <igl/material_colors.h>
 #include <igl/ReAntTweakBar.h>
 #include <igl/pathinfo.h>
 #include <igl/Camera.h>
@@ -129,7 +130,7 @@ int width,height;
 // Position of light
 float light_pos[4] = {0.1,0.1,-0.9,0};
 // Vertex positions, normals, colors and centroid
-Eigen::MatrixXd V,U,N,mid;
+Eigen::MatrixXd V,U,N,C,mid;
 Eigen::VectorXi S;
 igl::ARAPData arap_data;
 Eigen::MatrixXi F;
@@ -163,6 +164,7 @@ bool init_arap()
   using namespace std;
   VectorXi b(num_in_selection(S));
   assert(S.rows() == V.rows());
+  C.resize(S.rows(),3);
   MatrixXd bc = MatrixXd::Zero(b.size(),S.maxCoeff()+1);
   // get b from S
   {
@@ -174,6 +176,19 @@ bool init_arap()
         b(bi) = v;
         bc(bi,S(v)) = 1;
         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:
           {
-            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;
           }
           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;
           }
           default:
@@ -304,7 +330,7 @@ void lights()
   using namespace std;
   glEnable(GL_LIGHTING);
   glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
-  glEnable(GL_LIGHT0);
+  //glEnable(GL_LIGHT0);
   glEnable(GL_LIGHT1);
   float amb[4];
   amb[0] = amb[1] = amb[2] = 0;
@@ -328,7 +354,8 @@ void lights()
   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()
 {
   using namespace Eigen;
@@ -363,17 +390,18 @@ void display()
 
   // Draw the model
   // 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);
 
   pop_object();
@@ -387,7 +415,8 @@ void display()
   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};
 
-  draw_floor(GREY,DARK_GREY);
+  //draw_floor(GREY,DARK_GREY);
+  draw_floor();
   glPopMatrix();
 
   pop_scene();

+ 4 - 2
examples/patches/example.vcxproj

@@ -58,7 +58,7 @@
       </PrecompiledHeader>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <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>
       <AdditionalIncludeDirectories>..\..\external\embree;..\..\external\embree\embree;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OpenMPSupport>true</OpenMPSupport>
@@ -66,6 +66,7 @@
     <Link>
       <SubSystem>Console</SubSystem>
       <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>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -76,7 +77,7 @@
       <Optimization>Disabled</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <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>
       <AdditionalIncludeDirectories>..\..\external\embree;..\..\external\embree\embree;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OpenMPSupport>true</OpenMPSupport>
@@ -87,6 +88,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <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>
   </ItemDefinitionGroup>
   <ItemGroup>

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

@@ -13,6 +13,7 @@
 			<array>
 				<string>org.mesh</string>
 				<string>org.obj</string>
+				<string>org.stl</string>
 				<string>org.off</string>
 				<string>org.wrl</string>
 			</array>
@@ -102,6 +103,25 @@
 				</array>
 			</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>
 			<key>UTTypeConformsTo</key>
 			<array>

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

@@ -13,6 +13,7 @@ extern "C" {
 #include <igl/material_colors.h>
 #include <igl/pathinfo.h>
 #include <igl/readOBJ.h>
+#include <igl/readSTL.h>
 #include <igl/readWRL.h>
 #include <igl/triangulate.h>
 #include <igl/readOFF.h>
@@ -375,6 +376,14 @@ bool render_to_buffer(
       red(width,height,buffer);
       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
   {
     // 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: 
       <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=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="./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>

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

+ 19 - 19
include/igl/readOBJ.cpp

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