瀏覽代碼

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

Former-commit-id: 45e3b4d2c623dea9389b0511e05d1ad288f485ff
schuellc 11 年之前
父節點
當前提交
fde20c73d9
共有 49 個文件被更改,包括 3057 次插入594 次删除
  1. 24 20
      Makefile
  2. 1 0
      Makefile.conf
  3. 5 1
      README.md
  4. 1 0
      RELEASE_HISTORY.txt
  5. 1 1
      VERSION.txt
  6. 1 1
      documentation/active-set.tex
  7. 47 0
      documentation/implemented-papers.tex
  8. 1 0
      documentation/references.bib.REMOVED.git-id
  9. 1 1
      examples/bbw/main.cpp
  10. 43 0
      examples/intersections/Makefile
  11. 8 0
      examples/intersections/README.md
  12. 700 0
      examples/intersections/example.cpp
  13. 3 3
      examples/patches/example.vcxproj
  14. 4 1
      examples/skeleton/example.cpp
  15. 4 2
      include/igl/active_set.h
  16. 37 0
      include/igl/cgal/CGAL_includes.hpp
  17. 44 0
      include/igl/cgal/Makefile
  18. 923 0
      include/igl/cgal/SelfIntersectMesh.h
  19. 123 0
      include/igl/cgal/intersect_other.cpp
  20. 46 0
      include/igl/cgal/intersect_other.h
  21. 33 0
      include/igl/cgal/mesh_to_cgal_triangle_list.cpp
  22. 25 0
      include/igl/cgal/mesh_to_cgal_triangle_list.h
  23. 41 0
      include/igl/cgal/selfintersect.cpp
  24. 55 0
      include/igl/cgal/selfintersect.h
  25. 58 106
      include/igl/cotangent.cpp
  26. 9 3
      include/igl/cotangent.h
  27. 3 3
      include/igl/cotmatrix.cpp
  28. 2 2
      include/igl/cotmatrix.h
  29. 94 0
      include/igl/dihedral_angles.cpp
  30. 55 0
      include/igl/dihedral_angles.h
  31. 2 0
      include/igl/doublearea.cpp
  32. 49 7
      include/igl/edge_lengths.cpp
  33. 8 3
      include/igl/edge_lengths.h
  34. 0 222
      include/igl/embree/orient_outward_ao.cpp
  35. 0 61
      include/igl/embree/orient_outward_ao.h
  36. 22 24
      include/igl/embree/reorient_facets_raycast.cpp
  37. 7 4
      include/igl/embree/reorient_facets_raycast.h
  38. 48 0
      include/igl/face_areas.cpp
  39. 46 0
      include/igl/face_areas.h
  40. 143 0
      include/igl/file_dialog.cpp
  41. 44 0
      include/igl/file_dialog.h
  42. 99 98
      include/igl/gradMat.cpp
  43. 50 22
      include/igl/pos.h
  44. 2 2
      include/igl/readOFF.cpp
  45. 7 0
      include/igl/sort.cpp
  46. 9 2
      include/igl/vf.h
  47. 72 0
      include/igl/volume.cpp
  48. 51 0
      include/igl/volume.h
  49. 6 5
      todos.txt

+ 24 - 20
Makefile

@@ -17,19 +17,26 @@ CFLAGS += $(OPTFLAGS)
 # We use well-supported features of c++11
 
 EXTRA_DIRS=
-ifeq ($(IGL_WITH_TETGEN),1)
-	# append tetgen extra dir
-	EXTRA_DIRS+=include/igl/tetgen
-	EXTRAS += tetgen
+ifeq ($(IGL_WITH_BBW),1)
+	EXTRA_DIRS+=include/igl/bbw
+	EXTRAS += bbw
+endif
+ifeq ($(IGL_WITH_BOOST),1)
+	EXTRA_DIRS+=include/igl/boost
+	EXTRAS += boost
+endif
+ifeq ($(IGL_WITH_CGAL),1)
+	EXTRA_DIRS+=include/igl/cgal
+	EXTRAS += cgal
+endif
+ifeq ($(IGL_WITH_EMBREE),1)
+	EXTRA_DIRS+=include/igl/embree
+	EXTRAS += embree
 endif
 ifeq ($(IGL_WITH_MATLAB),1)
 	EXTRA_DIRS+=include/igl/matlab
 	EXTRAS += matlab
 endif
-ifeq ($(IGL_WITH_BBW),1)
-	EXTRA_DIRS+=include/igl/bbw
-	EXTRAS += bbw
-endif
 ifeq ($(IGL_WITH_MOSEK),1)
 	EXTRA_DIRS+=include/igl/mosek
 	EXTRAS += mosek
@@ -38,22 +45,19 @@ ifeq ($(IGL_WITH_PNG),1)
 	EXTRA_DIRS+=include/igl/png
 	EXTRAS += png
 endif
-ifeq ($(IGL_WITH_XML),1)
-	EXTRA_DIRS+=include/igl/xml
-	EXTRAS += xml
-endif
-ifeq ($(IGL_WITH_EMBREE),1)
-	EXTRA_DIRS+=include/igl/embree
-	EXTRAS += embree
-endif
-ifeq ($(IGL_WITH_BOOST),1)
-	EXTRA_DIRS+=include/igl/boost
-	EXTRAS += boost
-endif
 ifeq ($(IGL_WITH_SVD3X3),1)
 	EXTRA_DIRS+=include/igl/svd3x3
 	EXTRAS += svd3x3
 endif
+ifeq ($(IGL_WITH_TETGEN),1)
+	# append tetgen extra dir
+	EXTRA_DIRS+=include/igl/tetgen
+	EXTRAS += tetgen
+endif
+ifeq ($(IGL_WITH_XML),1)
+	EXTRA_DIRS+=include/igl/xml
+	EXTRAS += xml
+endif
 
 .PHONY: examples
 .PHONY: extras

+ 1 - 0
Makefile.conf

@@ -51,6 +51,7 @@ ifeq ($(IGL_USERNAME),ajx)
 	IGL_WITH_EMBREE=1
 	IGL_WITH_MATLAB=1
 	IGL_WITH_MOSEK=1
+	IGL_WITH_CGAL=1
 	IGL_WITH_BBW=1
 	IGL_WITH_SVD3X3=1
 	IGL_WITH_PNG=1

+ 5 - 1
README.md

@@ -24,7 +24,11 @@ listed below.
 - libpng  libiglpng extra only
 - Mosek  libiglmosek extra only
 - Matlab  libiglmatlab extra only
-- boost  libboost extra only
+- boost  libiglboost, libiglcgal extra only
+- CGAL  libiglcgal extra only
+    * boost 
+    * gmp
+    * mpfr
 
 ### Optional (included in external/) ###
 - TetGen  libigltetgen extra only

+ 1 - 0
RELEASE_HISTORY.txt

@@ -1,3 +1,4 @@
+0.4.5  CGAL extra: mesh selfintersection
 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

+ 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.4
+0.4.5

+ 1 - 1
documentation/active-set.tex

@@ -25,7 +25,7 @@
 \url{http://www.math.uh.edu/~rohop/fall_06/Chapter2.pdf}, and
 \url{http://www.cs.cornell.edu/courses/cs322/2007sp/notes/qr.pdf}. Mostly this
 is to put everything in the same place and use notation compatible with the
-libigl implementation. The ideas and descriptions, however, are not novel.}
+\textsc{libigl} implementation. The ideas and descriptions, however, are not novel.}
 \end{pullout}
 
 Quadratic programming problems (QPs) can be written in general as:

+ 47 - 0
documentation/implemented-papers.tex

@@ -0,0 +1,47 @@
+\documentclass[12pt]{diary}
+\immediate\write18{bibtex \jobname}
+
+\title{Papers implemented in \textsc{libigl}}
+\author{Alec Jacobson}
+\date{last revised 22 April 2014}
+
+\begin{document}
+This document serves as a companion reference to better list the references to
+scientific articles implemented within \textsc{libigl}. It will no doubt be
+incomplete.
+
+\paragraph{\texttt{cotmatrix}, \texttt{massmatrix}}
+build discrete operators on triangle and tetrahedral meshes. 
+\cite{Pinkall:1993:CDM,meyer03ddo,Jacobson:THESIS:2013}. For tet meshes, we no
+longer use the ``by the book'' FEM construction \`a la \cite{Sharf:2007vv},
+rather a purely geometric approach \cite{Barth:1994,Xu:1999}.
+
+\paragraph{\texttt{harmonic}} solves a Laplace problem (equivalently
+minimizes the Dirichlet energy) with some simple boundary conditions
+\cite{HarmonicCoodinates07}. There's also an option to solve
+``higher order Laplace problems'' (bi-Laplace, tri-Laplace, etc.)
+\cite{Botsch:2004:AIF,sorkine04lsm,Jacobson:MixedFEM:2010}.
+
+\paragraph{\texttt{bbw/}} implements ``bounded biharmonic
+weights'' \cite{Jacobson:BBW:2011}.
+
+\paragraph{\texttt{svd3x3/arap}} is a generalized implementation
+for solving ``as-rigid-as-possible'' (ARAP) mesh deformation or parameterization
+problems \cite{ARAP_modeling:2007,Liu:2008:ALA,Chao:2010:ASG}.
+
+\paragraph{\texttt{svd3x3/arap\_dof}} implements ``FAST'',
+which is simultaneously a reduced form of ARAP and a method for automatically
+choosing skinning transformations \cite{Jacobson:FAST:2012}.
+
+\paragraph{\texttt{dqs}} implements ``Dual quaternion skinning''
+\cite{Kavan:2008:GSW}.
+
+\paragraph{\texttt{lbs}} implements ``linear blend skinning'', also known as
+``skeletal subspace deformation'', or ``enveloping''. This technique is often
+attributed to \cite{Magnenat-Thalmann:1988:JLD}.
+
+\bibliographystyle{acmsiggraph}
+\bibliography{references} 
+
+\end{document}
+__END__

+ 1 - 0
documentation/references.bib.REMOVED.git-id

@@ -0,0 +1 @@
+92b6b20756fd71dd62d7b52066a7bcf07e4acd28

+ 1 - 1
examples/bbw/main.cpp

@@ -257,7 +257,7 @@ int main(int argc, char * argv[])
   // Default bbw data and flags
   BBWData bbw_data;
   bbw_data.qp_solver = QP_SOLVER_IGL_ACTIVE_SET;
-  bbw_data.qp_solver = QP_SOLVER_MOSEK;
+  //bbw_data.qp_solver = QP_SOLVER_MOSEK;
   // Weights matrix
   MatrixXd W;
   if(!bbw(VV,TT,b,bc,bbw_data,W))

+ 43 - 0
examples/intersections/Makefile

@@ -0,0 +1,43 @@
+
+.PHONY: all
+
+# Shared flags etc.
+include ../../Makefile.conf
+
+all: example
+
+.PHONY: example
+
+LIBIGL=../../
+LIBIGL_INC=-I$(LIBIGL)/include
+LIBIGL_LIB=-L$(LIBIGL)/lib -ligl -liglembree -liglcgal
+
+CGAL=/opt/local/
+CGAL_LIB=-L$(CGAL)/lib -lCGAL -lCGAL_Core -lgmp -lmpfr -lboost_thread-mt -lboost_system-mt
+CGAL_INC=-I$(CGAL)/include -I/usr/include/
+# This is absolutely necessary for Exact Construction
+CGAL_FLAGS=-frounding-math -fsignaling-nans 
+
+EIGEN3_INC=-I/opt/local/include/eigen3 -I/opt/local/include/eigen3/unsupported
+
+#EMBREE=$(LIBIGL)/external/embree
+#EMBREE_INC=-I$(EMBREE)/rtcore -I$(EMBREE)/common
+#EMBREE_LIB=-L$(EMBREE)/build -lrtcore -lsys
+EMBREE=$(LIBIGL)/external/embree
+EMBREE_INC=-I$(EMBREE)/ -I$(EMBREE)/embree
+EMBREE_LIB=-L$(EMBREE)/build -lembree -lsys
+
+ANTTWEAKBAR_INC=-I$(LIBIGL)/external/AntTweakBar/include
+ANTTWEAKBAR_LIB=-L$(LIBIGL)/external/AntTweakBar/lib -lAntTweakBar -framework AppKit
+INC=$(LIBIGL_INC) $(ANTTWEAKBAR_INC) $(EIGEN3_INC) $(EMBREE_INC) $(CGAL_INC)
+LIB=$(OPENGL_LIB) $(GLUT_LIB) $(ANTTWEAKBAR_LIB) $(LIBIGL_LIB) $(EMBREE_LIB) $(CGAL_LIB)
+CFLAGS+=$(CGAL_FLAGS)
+
+example: example.o
+	g++ $(OPENMP) $(AFLAGS) $(CFLAGS) $(LIB) -o example example.o 
+
+example.o: example.cpp
+	g++ $(OPENMP) $(AFLAGS) $(CFLAGS) -c example.cpp -o example.o $(INC)
+clean:
+	rm -f example.o
+	rm -f example

+ 8 - 0
examples/intersections/README.md

@@ -0,0 +1,8 @@
+To compute and visualize all facets participating in self-intersections issue:
+
+    ./example input.obj
+
+To compute and visualize all facets participating in intersections between mesh
+A and mesh B (ignoring self-intersections in each) issue:
+
+    ./example A.obj B.obj

+ 700 - 0
examples/intersections/example.cpp

@@ -0,0 +1,700 @@
+#include <igl/OpenGL_convenience.h>
+#include <igl/per_face_normals.h>
+#include <igl/two_axis_valuator_fixed_up.h>
+#include <igl/normalize_row_lengths.h>
+#include <igl/draw_mesh.h>
+#include <igl/draw_floor.h>
+#include <igl/quat_to_mat.h>
+#include <igl/report_gl_error.h>
+#include <igl/readOBJ.h>
+#include <igl/readDMAT.h>
+#include <igl/readOFF.h>
+#include <igl/readMESH.h>
+#include <igl/jet.h>
+#include <igl/readWRL.h>
+#include <igl/trackball.h>
+#include <igl/list_to_matrix.h>
+#include <igl/snap_to_canonical_view_quat.h>
+#include <igl/snap_to_fixed_up.h>
+#include <igl/triangulate.h>
+#include <igl/material_colors.h>
+#include <igl/barycenter.h>
+#include <igl/matlab_format.h>
+#include <igl/ReAntTweakBar.h>
+#include <igl/pathinfo.h>
+#include <igl/Camera.h>
+#include <igl/get_seconds.h>
+#include <igl/cgal/selfintersect.h>
+#include <igl/cgal/intersect_other.h>
+
+#ifdef __APPLE__
+#  include <GLUT/glut.h>
+#else
+#  include <GL/glut.h>
+#endif
+
+#include <Eigen/Core>
+
+#include <vector>
+#include <iostream>
+#include <algorithm>
+
+struct State
+{
+  igl::Camera camera;
+} s;
+enum RotationType
+{
+  ROTATION_TYPE_IGL_TRACKBALL = 0,
+  ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
+  NUM_ROTATION_TYPES = 2,
+} rotation_type;
+bool is_rotating = false;
+int down_x,down_y;
+igl::Camera down_camera;
+bool is_animating = false;
+double animation_start_time = 0;
+double ANIMATION_DURATION = 0.5;
+Eigen::Quaterniond animation_from_quat;
+Eigen::Quaterniond animation_to_quat;
+// Use vector for range-based `for`
+std::vector<State> undo_stack;
+std::vector<State> redo_stack;
+
+void push_undo()
+{
+  undo_stack.push_back(s);
+  // Clear
+  redo_stack = std::vector<State>();
+}
+
+void undo()
+{
+  using namespace std;
+  if(!undo_stack.empty())
+  {
+    redo_stack.push_back(s);
+    s = undo_stack.front();
+    undo_stack.pop_back();
+  }
+}
+
+void redo()
+{
+  using namespace std;
+  if(!redo_stack.empty())
+  {
+    undo_stack.push_back(s);
+    s = redo_stack.front();
+    redo_stack.pop_back();
+  }
+}
+
+void TW_CALL set_rotation_type(const void * value, void * clientData)
+{
+  using namespace Eigen;
+  using namespace std;
+  using namespace igl;
+  const RotationType old_rotation_type = rotation_type;
+  rotation_type = *(const RotationType *)(value);
+  if(rotation_type == ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP && 
+    old_rotation_type != ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
+  {
+    push_undo();
+    animation_from_quat = s.camera.m_rotation_conj;
+    snap_to_fixed_up(animation_from_quat,animation_to_quat);
+    // start animation
+    animation_start_time = get_seconds();
+    is_animating = true;
+  }
+}
+
+void TW_CALL get_rotation_type(void * value, void *clientData)
+{
+  RotationType * rt = (RotationType *)(value);
+  *rt = rotation_type;
+}
+
+// Width and height of window
+int width,height;
+// Position of light
+float light_pos[4] = {0.1,0.1,-0.9,0};
+// V,U  Vertex positions
+// C,D  Colors
+// N,W  Normals
+// mid  combined "centroid"
+Eigen::MatrixXd V,N,C,Z,mid,U,W,D;
+// F,G  faces
+Eigen::MatrixXi F,G;
+bool has_other = false;
+bool show_A = true;
+bool show_B = true;
+int selected_col = 0;
+// Bounding box diagonal length
+double bbd;
+// Running ambient occlusion
+Eigen::VectorXd S;
+int tot_num_samples = 0;
+#define REBAR_NAME "temp.rbr"
+igl::ReTwBar rebar; // Pointer to the tweak bar
+
+void reshape(int width,int height)
+{
+  using namespace std;
+  // Save width and height
+  ::width = width;
+  ::height = height;
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glViewport(0,0,width,height);
+  // Send the new window size to AntTweakBar
+  TwWindowSize(width, height);
+  // Set aspect for all cameras
+  s.camera.m_aspect = (double)width/(double)height;
+  for(auto & s : undo_stack)
+  {
+    s.camera.m_aspect = (double)width/(double)height;
+  }
+  for(auto & s : redo_stack)
+  {
+    s.camera.m_aspect = (double)width/(double)height;
+  }
+}
+
+void push_scene()
+{
+  using namespace igl;
+  using namespace std;
+  glMatrixMode(GL_PROJECTION);
+  glPushMatrix();
+  glLoadIdentity();
+  auto & camera = s.camera;
+  gluPerspective(camera.m_angle,camera.m_aspect,camera.m_near,camera.m_far);
+  glMatrixMode(GL_MODELVIEW);
+  glPushMatrix();
+  glLoadIdentity();
+  gluLookAt(
+    camera.eye()(0), camera.eye()(1), camera.eye()(2),
+    camera.at()(0), camera.at()(1), camera.at()(2),
+    camera.up()(0), camera.up()(1), camera.up()(2));
+}
+
+void pop_scene()
+{
+  glMatrixMode(GL_PROJECTION);
+  glPopMatrix();
+  glMatrixMode(GL_MODELVIEW);
+  glPopMatrix();
+}
+
+void pop_object()
+{
+  glPopMatrix();
+}
+
+// Scale and shift for object
+void push_object()
+{
+  glPushMatrix();
+  glScaled(2./bbd,2./bbd,2./bbd);
+  glTranslated(-mid(0,0),-mid(0,1),-mid(0,2));
+}
+
+// Set up double-sided lights
+void lights()
+{
+  using namespace std;
+  glEnable(GL_LIGHTING);
+  glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
+  glEnable(GL_LIGHT0);
+  glEnable(GL_LIGHT1);
+  float amb[4];
+  amb[0] = amb[1] = amb[2] = 0;
+  amb[3] = 1.0;
+  float diff[4] = {0.0,0.0,0.0,0.0};
+  diff[0] = diff[1] = diff[2] = (1.0 - 0/0.4);;
+  diff[3] = 1.0;
+  float zeros[4] = {0.0,0.0,0.0,0.0};
+  float pos[4];
+  copy(light_pos,light_pos+4,pos);
+  glLightfv(GL_LIGHT0,GL_AMBIENT,amb);
+  glLightfv(GL_LIGHT0,GL_DIFFUSE,diff);
+  glLightfv(GL_LIGHT0,GL_SPECULAR,zeros);
+  glLightfv(GL_LIGHT0,GL_POSITION,pos);
+  pos[0] *= -1;
+  pos[1] *= -1;
+  pos[2] *= -1;
+  glLightfv(GL_LIGHT1,GL_AMBIENT,amb);
+  glLightfv(GL_LIGHT1,GL_DIFFUSE,diff);
+  glLightfv(GL_LIGHT1,GL_SPECULAR,zeros);
+  glLightfv(GL_LIGHT1,GL_POSITION,pos);
+}
+
+const float back[4] = {30.0/255.0,30.0/255.0,50.0/255.0,0};
+void display()
+{
+  using namespace Eigen;
+  using namespace igl;
+  using namespace std;
+
+  glClearColor(back[0],back[1],back[2],0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  if(is_animating)
+  {
+    double t = (get_seconds() - animation_start_time)/ANIMATION_DURATION;
+    if(t > 1)
+    {
+      t = 1;
+      is_animating = false;
+    }
+    const Quaterniond q = animation_from_quat.slerp(t,animation_to_quat).normalized();
+    s.camera.orbit(q.conjugate());
+  }
+
+  glDisable(GL_LIGHTING);
+  lights();
+  push_scene();
+  glEnable(GL_DEPTH_TEST);
+  glDepthFunc(GL_LEQUAL);
+  glEnable(GL_NORMALIZE);
+  glEnable(GL_COLOR_MATERIAL);
+  glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
+  push_object();
+
+  // Draw the model
+  // Set material properties
+  glEnable(GL_COLOR_MATERIAL);
+
+  const auto draw = [](
+    const MatrixXd & V,
+    const MatrixXi & F,
+    const MatrixXd & N,
+    const MatrixXd & C)
+  {
+    glEnable(GL_POLYGON_OFFSET_FILL); // Avoid Stitching!
+    glPolygonOffset(1.0,1);
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+    draw_mesh(V,F,N,C);
+    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
+    glDisable(GL_COLOR_MATERIAL);
+    const float black[4] = {0,0,0,1};
+    glColor4fv(black);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  black);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  black);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);
+    glLightfv(GL_LIGHT0, GL_AMBIENT, black);
+    glLightfv(GL_LIGHT0, GL_DIFFUSE, black);
+    glLineWidth(1.0);
+    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+    draw_mesh(V,F,N,C);
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+    glEnable(GL_COLOR_MATERIAL);
+  };
+  if(show_A)
+  {
+    draw(V,F,N,C);
+  }
+  if(show_B)
+  {
+    draw(U,G,W,D);
+  }
+
+  pop_object();
+
+  // Draw a nice floor
+  glPushMatrix();
+  const double floor_offset =
+    -2./bbd*(V.col(1).maxCoeff()-mid(1));
+  glTranslated(0,floor_offset,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};
+  draw_floor(GREY,DARK_GREY);
+  glPopMatrix();
+
+  pop_scene();
+
+  report_gl_error();
+
+  TwDraw();
+  glutSwapBuffers();
+  if(is_animating)
+  {
+    glutPostRedisplay();
+  }
+}
+
+void mouse_wheel(int wheel, int direction, int mouse_x, int mouse_y)
+{
+  using namespace std;
+  using namespace igl;
+  using namespace Eigen;
+  GLint viewport[4];
+  glGetIntegerv(GL_VIEWPORT,viewport);
+  if(wheel == 0 && TwMouseMotion(mouse_x, viewport[3] - mouse_y))
+  {
+    static double mouse_scroll_y = 0;
+    const double delta_y = 0.125*direction;
+    mouse_scroll_y += delta_y;
+    TwMouseWheel(mouse_scroll_y);
+    return;
+  }
+  push_undo();
+  auto & camera = s.camera;
+  if(wheel==0)
+  {
+    // factor of zoom change
+    double s = (1.-0.01*direction);
+    //// FOV zoom: just widen angle. This is hardly ever appropriate.
+    //camera.m_angle *= s;
+    //camera.m_angle = min(max(camera.m_angle,1),89);
+    camera.push_away(s);
+  }else
+  {
+    // Dolly zoom:
+    camera.dolly_zoom((double)direction*1.0);
+  }
+}
+
+void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
+{
+  using namespace std;
+  using namespace Eigen;
+  using namespace igl;
+  bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y);
+  switch(glutButton)
+  {
+    case GLUT_RIGHT_BUTTON:
+    case GLUT_LEFT_BUTTON:
+    {
+      switch(glutState)
+      {
+        case 1:
+          // up
+          glutSetCursor(GLUT_CURSOR_LEFT_ARROW);
+          is_rotating = false;
+          break;
+        case 0:
+          // down
+          if(!tw_using)
+          {
+            glutSetCursor(GLUT_CURSOR_CYCLE);
+            // collect information for trackball
+            is_rotating = true;
+            down_camera = s.camera;
+            down_x = mouse_x;
+            down_y = mouse_y;
+          }
+        break;
+      }
+      break;
+    }
+    // Scroll down
+    case 3:
+    {
+      mouse_wheel(0,-1,mouse_x,mouse_y);
+      break;
+    }
+    // Scroll up
+    case 4:
+    {
+      mouse_wheel(0,1,mouse_x,mouse_y);
+      break;
+    }
+    // Scroll left
+    case 5:
+    {
+      mouse_wheel(1,-1,mouse_x,mouse_y);
+      break;
+    }
+    // Scroll right
+    case 6:
+    {
+      mouse_wheel(1,1,mouse_x,mouse_y);
+      break;
+    }
+  }
+  glutPostRedisplay();
+}
+
+void mouse_drag(int mouse_x, int mouse_y)
+{
+  using namespace igl;
+  using namespace Eigen;
+
+  if(is_rotating)
+  {
+    glutSetCursor(GLUT_CURSOR_CYCLE);
+    Quaterniond q;
+    auto & camera = s.camera;
+    switch(rotation_type)
+    {
+      case ROTATION_TYPE_IGL_TRACKBALL:
+      {
+        // Rotate according to trackball
+        igl::trackball<double>(
+          width,
+          height,
+          2.0,
+          down_camera.m_rotation_conj.coeffs().data(),
+          down_x,
+          down_y,
+          mouse_x,
+          mouse_y,
+          q.coeffs().data());
+          break;
+      }
+      case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
+      {
+        // Rotate according to two axis valuator with fixed up vector 
+        two_axis_valuator_fixed_up(
+          width, height,
+          2.0,
+          down_camera.m_rotation_conj,
+          down_x, down_y, mouse_x, mouse_y,
+          q);
+        break;
+      }
+      default:
+        break;
+    }
+    camera.orbit(q.conjugate());
+  }else
+  {
+    TwEventMouseMotionGLUT(mouse_x, mouse_y);
+  }
+  glutPostRedisplay();
+}
+
+
+
+void color_selfintersections(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  Eigen::MatrixXd & C)
+{
+  using namespace igl;
+  using namespace Eigen;
+  MatrixXd SV;
+  MatrixXi SF,IF;
+  SelfintersectParam params;
+  params.detect_only = true;
+  selfintersect(V,F,params,SV,SF,IF);
+  C.resize(F.rows(),3);
+  C.col(0).setConstant(0.4);
+  C.col(1).setConstant(0.8);
+  C.col(2).setConstant(0.3);
+  for(int f = 0;f<IF.rows();f++)
+  {
+    C.row(IF(f,0)) = RowVector3d(1,0.4,0.4);
+    C.row(IF(f,1)) = RowVector3d(1,0.4,0.4);
+  }
+}
+
+void color_intersections(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  const Eigen::MatrixXd & U,
+  const Eigen::MatrixXi & G,
+  Eigen::MatrixXd & C,
+  Eigen::MatrixXd & D)
+{
+  using namespace igl;
+  using namespace Eigen;
+  MatrixXi IF;
+  const bool first_only = false;
+  intersect_other(V,F,U,G,first_only,IF);
+  C.resize(F.rows(),3);
+  C.col(0).setConstant(0.4);
+  C.col(1).setConstant(0.8);
+  C.col(2).setConstant(0.3);
+  D.resize(G.rows(),3);
+  D.col(0).setConstant(0.4);
+  D.col(1).setConstant(0.3);
+  D.col(2).setConstant(0.8);
+  for(int f = 0;f<IF.rows();f++)
+  {
+    C.row(IF(f,0)) = RowVector3d(1,0.4,0.4);
+    D.row(IF(f,1)) = RowVector3d(0.8,0.7,0.3);
+  }
+}
+
+void key(unsigned char key, int mouse_x, int mouse_y)
+{
+  using namespace std;
+  switch(key)
+  {
+    // ESC
+    case char(27):
+      rebar.save(REBAR_NAME);
+    // ^C
+    case char(3):
+      exit(0);
+    default:
+      if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
+      {
+        cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
+      }
+  }
+  
+  glutPostRedisplay();
+}
+
+int main(int argc, char * argv[])
+{
+  using namespace Eigen;
+  using namespace igl;
+  using namespace std;
+
+  // init mesh
+  string filename = "../shared/truck.obj";
+  string filename_other = "";
+  switch(argc)
+  {
+    case 3:
+      // Read and prepare mesh
+      filename_other = argv[2];
+      has_other=true;
+      // fall through
+    case 2:
+      // Read and prepare mesh
+      filename = argv[1];
+      break;
+    default:
+    cerr<<"Usage:"<<endl<<"    ./example input.obj [other.obj]"<<endl;
+    cout<<endl<<"Opening default mesh..."<<endl;
+  }
+
+  const auto read = []
+    (const string & filename, MatrixXd & V, MatrixXi & F, MatrixXd & N) -> bool
+  {
+    // dirname, basename, extension and filename
+    string d,b,ext,f;
+    pathinfo(filename,d,b,ext,f);
+    // Convert extension to lower case
+    transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+    vector<vector<double > > vV,vN,vTC;
+    vector<vector<int > > vF,vFTC,vFN;
+    if(ext == "obj")
+    {
+      // Convert extension to lower case
+      if(!igl::readOBJ(filename,vV,vTC,vN,vF,vFTC,vFN))
+      {
+        return false;
+      }
+    }else if(ext == "off")
+    {
+      // Convert extension to lower case
+      if(!igl::readOFF(filename,vV,vF,vN))
+      {
+        return false;
+      }
+    }else if(ext == "wrl")
+    {
+      // Convert extension to lower case
+      if(!igl::readWRL(filename,vV,vF))
+      {
+        return false;
+      }
+    //}else
+    //{
+    //  // Convert extension to lower case
+    //  MatrixXi T;
+    //  if(!igl::readMESH(filename,V,T,F))
+    //  {
+    //    return false;
+    //  }
+    //  //if(F.size() > T.size() || F.size() == 0)
+    //  {
+    //    boundary_faces(T,F);
+    //  }
+    }
+    if(vV.size() > 0)
+    {
+      if(!list_to_matrix(vV,V))
+      {
+        return false;
+      }
+      triangulate(vF,F);
+    }
+    // Compute normals, centroid, colors, bounding box diagonal
+    per_face_normals(V,F,N);
+    return true;
+  };
+
+  if(!read(filename,V,F,N))
+  {
+    return 1;
+  }
+  if(has_other)
+  {
+    if(!read(argv[2],U,G,W))
+    {
+      return 1;
+    }
+    mid = 0.25*(V.colwise().maxCoeff() + V.colwise().minCoeff()) +
+      0.25*(U.colwise().maxCoeff() + U.colwise().minCoeff());
+    bbd = max(
+      (V.colwise().maxCoeff() - V.colwise().minCoeff()).maxCoeff(),
+      (U.colwise().maxCoeff() - U.colwise().minCoeff()).maxCoeff());
+    color_intersections(V,F,U,G,C,D);
+  }else
+  {
+    mid = 0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff());
+    bbd = (V.colwise().maxCoeff() - V.colwise().minCoeff()).maxCoeff();
+    color_selfintersections(V,F,C);
+  }
+
+  // Init glut
+  glutInit(&argc,argv);
+
+  if( !TwInit(TW_OPENGL, NULL) )
+  {
+    // A fatal error occured
+    fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
+    return 1;
+  }
+  // Create a tweak bar
+  rebar.TwNewBar("TweakBar");
+  rebar.TwAddVarRW("camera_rotation", TW_TYPE_QUAT4D, 
+    s.camera.m_rotation_conj.coeffs().data(), "open readonly=true");
+  s.camera.push_away(3);
+  s.camera.dolly_zoom(25-s.camera.m_angle);
+  TwType RotationTypeTW = ReTwDefineEnumFromString("RotationType",
+    "igl_trackball,two-a...-fixed-up");
+  rebar.TwAddVarCB( "rotation_type", RotationTypeTW,
+    set_rotation_type,get_rotation_type,NULL,"keyIncr=] keyDecr=[");
+  if(has_other)
+  {
+    rebar.TwAddVarRW("show_A",TW_TYPE_BOOLCPP,&show_A, "key=a",false);
+    rebar.TwAddVarRW("show_B",TW_TYPE_BOOLCPP,&show_B, "key=b",false);
+  }
+  rebar.load(REBAR_NAME);
+
+  glutInitDisplayString("rgba depth double samples>=8 ");
+  glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT));
+  glutCreateWindow("mesh-intersections");
+  glutDisplayFunc(display);
+  glutReshapeFunc(reshape);
+  glutKeyboardFunc(key);
+  glutMouseFunc(mouse);
+  glutMotionFunc(mouse_drag);
+  glutPassiveMotionFunc(
+    [](int x, int y)
+    {
+      TwEventMouseMotionGLUT(x,y);
+      glutPostRedisplay();
+    });
+  static std::function<void(int)> timer_bounce;
+  auto timer = [] (int ms) {
+    timer_bounce(ms);
+  };
+  timer_bounce = [&] (int ms) {
+    glutTimerFunc(ms, timer, ms);
+    glutPostRedisplay();
+  };
+  glutTimerFunc(500, timer, 500);
+
+  glutMainLoop();
+  return 0;
+}

+ 3 - 3
examples/patches/example.vcxproj

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
     <ProjectConfiguration Include="Debug|Win32">
       <Configuration>Debug</Configuration>
@@ -19,14 +19,14 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v120</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v110</PlatformToolset>
+    <PlatformToolset>v120</PlatformToolset>
     <WholeProgramOptimization>false</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>

+ 4 - 1
examples/skeleton/example.cpp

@@ -252,7 +252,10 @@ void display()
   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, SILVER_SPECULAR);
   glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 128);
 
-  vector<Quaterniond> dQ(BE.rows(),Quaterniond::Identity()),vQ;
+  typedef std::vector<
+    Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> >
+    RotationList;
+  RotationList dQ(BE.rows(),Quaterniond::Identity()),vQ;
   vector<Vector3d> vT;
   Matrix3d A = Matrix3d::Identity();
   for(int e = 0;e<BE.rows();e++)

+ 4 - 2
include/igl/active_set.h

@@ -38,6 +38,8 @@ namespace igl
   //   lx  n by 1 list of lower bounds [] implies -Inf
   //   ux  n by 1 list of upper bounds [] implies Inf
   //   params  struct of additional parameters (see below)
+  //   Z  if not empty, is taken to be an n by 1 list of initial guess values
+  //     (see output)
   // Outputs:
   //   Z  n by 1 list of solution values
   // Returns true on success, false on error
@@ -80,7 +82,7 @@ struct igl::active_set_params
 {
   // Input parameters for active_set:
   //   Auu_pd  whether Auu is positive definite {false}
-  //   max_iter  Maximum number of iterations ({0} = Infinity)
+  //   max_iter  Maximum number of iterations (0 = Infinity, {100})
   //   inactive_threshold  Threshold on Lagrange multiplier values to determine
   //     whether to keep constraints active {EPS}
   //   constraint_threshold  Threshold on whether constraints are violated (0
@@ -94,7 +96,7 @@ struct igl::active_set_params
   double solution_diff_threshold;
   active_set_params():
     Auu_pd(false),
-    max_iter(-1),
+    max_iter(100),
     inactive_threshold(igl::DOUBLE_EPS),
     constraint_threshold(igl::DOUBLE_EPS),
     solution_diff_threshold(igl::DOUBLE_EPS)

+ 37 - 0
include/igl/cgal/CGAL_includes.hpp

@@ -0,0 +1,37 @@
+#ifndef IGL_CGAL_INCLUDES_H
+#define IGL_CGAL_INCLUDES_H
+
+// Triangle triangle intersection
+#include <CGAL/intersections.h>
+// THIS CANNOT BE INCLUDED IN THE SAME FILE AS <CGAL/intersections.h>
+// #include <CGAL/Boolean_set_operations_2.h>
+
+// Constrained Delaunay Triangulation types
+#include <CGAL/Constrained_Delaunay_triangulation_2.h>
+#include <CGAL/Constrained_triangulation_plus_2.h>
+
+// Axis-align boxes for all-pairs self-intersection detection
+#include <CGAL/point_generators_3.h>
+#include <CGAL/Bbox_3.h>
+#include <CGAL/box_intersection_d.h>
+#include <CGAL/function_objects.h>
+#include <CGAL/Join_input_iterator.h>
+#include <CGAL/algorithm.h>
+#include <vector>
+
+// Axis-aligned bounding box tree for tet tri intersection
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+
+// Boolean operations
+#include <CGAL/Polyhedron_3.h>
+#include <CGAL/Nef_polyhedron_3.h>
+
+// Delaunay Triangulation in 3D
+#include <CGAL/Delaunay_triangulation_3.h>
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+#endif

+ 44 - 0
include/igl/cgal/Makefile

@@ -0,0 +1,44 @@
+
+.PHONY: all
+all: libiglcgal
+debug: libiglcgal
+
+include ../../../Makefile.conf
+all: CFLAGS += -O3 -DNDEBUG 
+debug: CFLAGS += -g -Wall -Werror
+
+.PHONY: libcgal
+libiglcgal: obj ../../../lib/libiglcgal.a
+
+CPP_FILES=$(wildcard *.cpp)
+OBJ_FILES=$(addprefix obj/,$(notdir $(CPP_FILES:.cpp=.o)))
+
+# include igl headers
+INC+=-I../../../include/
+
+# EXPECTS THAT CFLAGS IS ALREADY SET APPROPRIATELY 
+
+# Eigen dependency
+EIGEN3_INC=-I$(DEFAULT_PREFIX)/include/eigen3 -I$(DEFAULT_PREFIX)/include/eigen3/unsupported
+INC+=$(EIGEN3_INC)
+
+# CGAL dependency
+CGAL=$(DEFAULT_PREFIX)
+CGAL_INC=-I$(CGAL)/include
+CGAL_FLAGS=-frounding-math -fsignaling-nans 
+CFLAGS+=$(CGAL_FLAGS)
+INC+=$(CGAL_INC)
+
+obj: 
+	mkdir -p obj
+
+../../../lib/libiglcgal.a: $(OBJ_FILES)
+	rm -f $@
+	ar cqs $@ $(OBJ_FILES)
+
+obj/%.o: %.cpp %.h
+	g++ $(AFLAGS) $(CFLAGS) -c -o $@ $< $(INC)
+
+clean:
+	rm -f obj/*.o
+	rm -f ../../../lib/libiglcgal.a

+ 923 - 0
include/igl/cgal/SelfIntersectMesh.h

@@ -0,0 +1,923 @@
+#ifndef IGL_SELFINTERSECTMESH_H
+#define IGL_SELFINTERSECTMESH_H
+
+#include "CGAL_includes.hpp"
+#include "selfintersect.h"
+
+#include <Eigen/Dense>
+#include <list>
+#include <map>
+#include <vector>
+
+#ifndef IGL_FIRST_HIT_EXCEPTION
+#define IGL_FIRST_HIT_EXCEPTION 10
+#endif
+
+// The easiest way to keep track of everything is to use a class
+
+namespace igl
+{
+  // Kernel is a CGAL kernel like:
+  //     CGAL::Exact_predicates_inexact_constructions_kernel
+  // or 
+  //     CGAL::Exact_predicates_exact_constructions_kernel
+
+  template <typename Kernel>
+  class SelfIntersectMesh
+  {
+    public:
+      // 3D Primitives
+      typedef CGAL::Point_3<Kernel>    Point_3;
+      typedef CGAL::Segment_3<Kernel>  Segment_3; 
+      typedef CGAL::Triangle_3<Kernel> Triangle_3; 
+      typedef CGAL::Plane_3<Kernel>    Plane_3;
+      typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3; 
+      typedef CGAL::Polyhedron_3<Kernel> Polyhedron_3; 
+      typedef CGAL::Nef_polyhedron_3<Kernel> Nef_polyhedron_3; 
+      // 2D Primitives
+      typedef CGAL::Point_2<Kernel>    Point_2;
+      typedef CGAL::Segment_2<Kernel>  Segment_2; 
+      typedef CGAL::Triangle_2<Kernel> Triangle_2; 
+      // 2D Constrained Delaunay Triangulation types
+      typedef CGAL::Triangulation_vertex_base_2<Kernel>  TVB_2;
+      typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
+      typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
+      typedef CGAL::Exact_intersections_tag Itag;
+      typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> 
+        CDT_2;
+      typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
+      // Axis-align boxes for all-pairs self-intersection detection
+      typedef std::vector<Triangle_3> Triangles;
+      typedef typename Triangles::iterator TrianglesIterator;
+      typedef typename Triangles::const_iterator TrianglesConstIterator;
+      typedef 
+        CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator> 
+        Box;
+
+      // Input mesh
+      const Eigen::MatrixXd & V;
+      const Eigen::MatrixXi & F;
+      // Number of self-intersecting triangle pairs
+      int count;
+      std::vector<std::list<CGAL::Object> > F_objects;
+      Triangles T;
+      std::list<int> lIF;
+      std::vector<bool> offensive;
+      std::vector<int> offending_index;
+      std::vector<int> offending;
+      // Make a short name for the edge map's key
+      typedef std::pair<int,int> EMK;
+      // Make a short name for the type stored at each edge, the edge map's
+      // value
+      typedef std::list<int> EMV;
+      // Make a short name for the edge map
+      typedef std::map<EMK,EMV> EdgeMap;
+      EdgeMap edge2faces;
+    public:
+      SelfintersectParam params;
+    public:
+      // Constructs (VV,FF) a new mesh with self-intersections of (V,F)
+      // subdivided
+      inline SelfIntersectMesh(
+        const Eigen::MatrixXd & V,
+        const Eigen::MatrixXi & F,
+        const SelfintersectParam & params,
+        Eigen::MatrixXd & VV,
+        Eigen::MatrixXi & FF,
+        Eigen::MatrixXi & IF);
+    private:
+      // Helper function to mark a face as offensive
+      //
+      // Inputs:
+      //   f  index of face in F
+      inline void mark_offensive(const int f);
+      // Helper function to count intersections between faces
+      //
+      // Input:
+      //   fa  index of face A in F
+      //   fb  index of face B in F
+      inline void count_intersection(const int fa,const int fb);
+      // Helper function for box_intersect. Intersect two triangles A and B,
+      // append the intersection object (point,segment,triangle) to a running
+      // list for A and B
+      //
+      // Inputs:
+      //   A  triangle in 3D
+      //   B  triangle in 3D
+      //   fa  index of A in F (and F_objects)
+      //   fb  index of A in F (and F_objects)
+      // Returns true only if A intersects B
+      //
+      inline bool intersect(
+          const Triangle_3 & A, 
+          const Triangle_3 & B, 
+          const int fa,
+          const int fb);
+      // Helper function for box_intersect. In the case where A and B have
+      // already been identified to share a vertex, then we only want to add
+      // possible segment intersections. Assumes truly duplicate triangles are
+      // not given as input
+      //
+      // Inputs:
+      //   A  triangle in 3D
+      //   B  triangle in 3D
+      //   fa  index of A in F (and F_objects)
+      //   fb  index of B in F (and F_objects)
+      //   va  index of shared vertex in A (and F_objects)
+      //   vb  index of shared vertex in B (and F_objects)
+      //// Returns object of intersection (should be Segment or point)
+      //   Returns true if intersection (besides shared point)
+      //
+      inline bool single_shared_vertex(
+          const Triangle_3 & A,
+          const Triangle_3 & B,
+          const int fa,
+          const int fb,
+          const int va,
+          const int vb);
+      // Helper handling one direction
+      inline bool single_shared_vertex(
+          const Triangle_3 & A,
+          const Triangle_3 & B,
+          const int fa,
+          const int fb,
+          const int va);
+      // Helper function for box_intersect. In the case where A and B have
+      // already been identified to share two vertices, then we only want to add
+      // a possible coplanar (Triangle) intersection. Assumes truly degenerate
+      // facets are not givine as input.
+      inline bool double_shared_vertex(
+          const Triangle_3 & A,
+          const Triangle_3 & B,
+          const int fa,
+          const int fb);
+
+    public:
+      // Callback function called during box self intersections test. Means
+      // boxes a and b intersect. This method then checks if the triangles in
+      // each box intersect and if so, then processes the intersections
+      //
+      // Inputs:
+      //   a  box containing a triangle
+      //   b  box containing a triangle
+      inline void box_intersect(const Box& a, const Box& b);
+    private:
+      // Compute 2D delaunay triangulation of a given 3d triangle and a list of
+      // intersection objects (points,segments,triangles). CGAL uses an affine
+      // projection rather than an isometric projection, so we're not
+      // guaranteed that the 2D delaunay triangulation here will be a delaunay
+      // triangulation in 3D.
+      //
+      // Inputs:
+      //   A  triangle in 3D
+      //   A_objects_3  updated list of intersection objects for A
+      // Outputs:
+      //   cdt  Contrained delaunay triangulation in projected 2D plane
+      inline void projected_delaunay(
+          const Triangle_3 & A,
+          const std::list<CGAL::Object> & A_objects_3,
+          CDT_plus_2 & cdt);
+      // Getters:
+    public:
+      //const std::list<int>& get_lIF() const{ return lIF;}
+      static inline void box_intersect(
+        SelfIntersectMesh * SIM, 
+        const SelfIntersectMesh::Box &a, 
+        const SelfIntersectMesh::Box &b);
+  };
+}
+
+// Implementation
+
+#include "mesh_to_cgal_triangle_list.h"
+
+#include <igl/REDRUM.h>
+#include <igl/C_STR.h>
+
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <exception>
+#include <cassert>
+#include <iostream>
+
+// References:
+// http://minregret.googlecode.com/svn/trunk/skyline/src/extern/CGAL-3.3.1/examples/Polyhedron/polyhedron_self_intersection.cpp
+// http://www.cgal.org/Manual/3.9/examples/Boolean_set_operations_2/do_intersect.cpp
+
+// Q: Should we be using CGAL::Polyhedron_3?
+// A: No! Input is just a list of unoriented triangles. Polyhedron_3 requires
+// a 2-manifold.
+// A: But! It seems we could use CGAL::Triangulation_3. Though it won't be easy
+// to take advantage of functions like insert_in_facet because we want to
+// constrain segments. Hmmm. Actualy Triangulation_3 doesn't look right...
+
+//static void box_intersect(SelfIntersectMesh * SIM,const Box & A, const Box & B)
+//{
+//  return SIM->box_intersect(A,B);
+//}
+
+
+// CGAL's box_self_intersection_d uses C-style function callbacks without
+// userdata. This is a leapfrog method for calling a member function. It should
+// be bound as if the prototype was:
+//   static void box_intersect(const Box &a, const Box &b)
+// using boost:
+//  boost::function<void(const Box &a,const Box &b)> cb
+//    = boost::bind(&::box_intersect, this, _1,_2);
+//   
+template <typename Kernel>
+inline void igl::SelfIntersectMesh<Kernel>::box_intersect(
+  igl::SelfIntersectMesh<Kernel> * SIM, 
+  const typename igl::SelfIntersectMesh<Kernel>::Box &a, 
+  const typename igl::SelfIntersectMesh<Kernel>::Box &b)
+{
+  SIM->box_intersect(a,b);
+}
+
+template <typename Kernel>
+inline igl::SelfIntersectMesh<Kernel>::SelfIntersectMesh(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  const SelfintersectParam & params,
+  Eigen::MatrixXd & VV,
+  Eigen::MatrixXi & FF,
+  Eigen::MatrixXi & IF):
+  V(V),
+  F(F),
+  count(0),
+  F_objects(F.rows()),
+  T(),
+  lIF(),
+  offensive(F.rows(),false),
+  offending_index(F.rows(),-1),
+  offending(),
+  edge2faces(),
+  params(params)
+{
+  using namespace std;
+  using namespace Eigen;
+  // Compute and process self intersections
+  mesh_to_cgal_triangle_list(V,F,T);
+  // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5 
+  // Create the corresponding vector of bounding boxes
+  std::vector<Box> boxes;
+  boxes.reserve(T.size());
+  for ( 
+    TrianglesIterator tit = T.begin(); 
+    tit != T.end(); 
+    ++tit)
+  {
+    boxes.push_back(Box(tit->bbox(), tit));
+  }
+  // Leapfrog callback
+  boost::function<void(const Box &a,const Box &b)> cb
+    = boost::bind(&box_intersect, this, _1,_2);
+  // Run the self intersection algorithm with all defaults
+  try{
+    CGAL::box_self_intersection_d(boxes.begin(), boxes.end(),cb);
+  }catch(int e)
+  {
+    // Rethrow if not IGL_FIRST_HIT_EXCEPTION
+    if(e != IGL_FIRST_HIT_EXCEPTION)
+    {
+      throw e;
+    }
+    // Otherwise just fall through
+  }
+
+  // Convert lIF to Eigen matrix
+  assert(lIF.size()%2 == 0);
+  IF.resize(lIF.size()/2,2);
+  {
+    int i=0;
+    for(
+      typename list<int>::const_iterator ifit = lIF.begin();
+      ifit!=lIF.end();
+      )
+    {
+      IF(i,0) = (*ifit);
+      ifit++; 
+      IF(i,1) = (*ifit);
+      ifit++;
+      i++;
+    }
+  }
+
+  if(params.detect_only)
+  {
+    return;
+  }
+
+  int NF_count = 0;
+  // list of new faces, we'll fix F later
+  vector<MatrixXi> NF(offending.size());
+  // list of new vertices
+  list<Point_3> NV;
+  int NV_count = 0;
+  vector<CDT_plus_2> cdt(offending.size());
+  vector<Plane_3> P(offending.size());
+  // Use map for *all* faces
+  map<typename CDT_plus_2::Vertex_handle,int> v2i;
+  // Loop over offending triangles
+  for(int o = 0;o<(int)offending.size();o++)
+  {
+    // index in F
+    const int f = offending[o];
+    projected_delaunay(T[f],F_objects[f],cdt[o]);
+    // Q: Is this also delaunay in 3D?
+    // A: No, because the projection is affine and delaunay is not affine
+    // invariant.
+    // Q: Then, can't we first get the 2D delaunay triangulation, then lift it
+    // to 3D and flip any offending edges?
+    // Plane of projection (also used by projected_delaunay)
+    P[o] = Plane_3(T[f].vertex(0),T[f].vertex(1),T[f].vertex(2));
+    // Build index map
+    {
+      int i=0;
+      for(
+        typename CDT_plus_2::Finite_vertices_iterator vit = cdt[o].finite_vertices_begin();
+        vit != cdt[o].finite_vertices_end();
+        ++vit)
+      {
+        if(i<3)
+        {
+          //cout<<T[f].vertex(i)<<
+          //  (T[f].vertex(i) == P[o].to_3d(vit->point())?" == ":" != ")<<
+          //  P[o].to_3d(vit->point())<<endl;
+#ifndef NDEBUG
+          // I want to be sure that the original corners really show up as the
+          // original corners of the CDT. I.e. I don't trust CGAL to maintain the
+          // order
+          assert(T[f].vertex(i) == P[o].to_3d(vit->point()));
+#endif
+          // For first three, use original index in F
+          v2i[vit] = F(f,i);
+        }else
+        {
+          const Point_3 vit_point_3 = P[o].to_3d(vit->point());
+          // First look up each edge's neighbors to see if exact point has
+          // already been added (This makes everything a bit quadratic)
+          bool found = false;
+          for(int e = 0; e<3 && !found;e++)
+          {
+            // Index of F's eth edge in V
+            int i = F(f,(e+1)%3);
+            int j = F(f,(e+2)%3);
+            // Be sure that i<j
+            if(i>j)
+            {
+              swap(i,j);
+            }
+            assert(edge2faces.count(EMK(i,j))==1);
+            // loop over neighbors
+            for(
+              list<int>::const_iterator nit = edge2faces[EMK(i,j)].begin();
+              nit != edge2faces[EMK(i,j)].end() && !found;
+              nit++)
+            {
+              // don't consider self
+              if(*nit == f)
+              {
+                continue;
+              }
+              // index of neighbor in offending (to find its cdt)
+              int no = offending_index[*nit];
+              // Loop over vertices of that neighbor's cdt (might not have been
+              // processed yet, but then it's OK because it'll just be empty)
+              for(
+                  typename CDT_plus_2::Finite_vertices_iterator uit = cdt[no].finite_vertices_begin();
+                  uit != cdt[no].finite_vertices_end() && !found;
+                  ++uit)
+              {
+                if(vit_point_3 == P[no].to_3d(uit->point()))
+                {
+                  assert(v2i.count(uit) == 1);
+                  v2i[vit] = v2i[uit];
+                  found = true;
+                }
+              }
+            }
+          }
+          if(!found)
+          {
+            v2i[vit] = V.rows()+NV_count;
+            NV.push_back(vit_point_3);
+            NV_count++;
+          }
+        }
+        i++;
+      }
+    }
+    {
+      int i = 0;
+      // Resize to fit new number of triangles
+      NF[o].resize(cdt[o].number_of_faces(),3);
+      NF_count+=NF[o].rows();
+      // Append new faces to NF
+      for(
+        typename CDT_plus_2::Finite_faces_iterator fit = cdt[o].finite_faces_begin();
+        fit != cdt[o].finite_faces_end();
+        ++fit)
+      {
+        NF[o](i,0) = v2i[fit->vertex(0)];
+        NF[o](i,1) = v2i[fit->vertex(1)];
+        NF[o](i,2) = v2i[fit->vertex(2)];
+        i++;
+      }
+    }
+  }
+  assert(NV_count == (int)NV.size());
+  // Build output
+#ifndef NDEBUG
+  {
+    int off_count = 0;
+    for(int f = 0;f<F.rows();f++)
+    {
+      off_count+= (offensive[f]?1:0);
+    }
+    assert(off_count==(int)offending.size());
+  }
+#endif
+  // Append faces
+  FF.resize(F.rows()-offending.size()+NF_count,3);
+  // First append non-offending original faces
+  // There's an Eigen way to do this in one line but I forget
+  int off = 0;
+  for(int f = 0;f<F.rows();f++)
+  {
+    if(!offensive[f])
+    {
+      FF.row(off++) = F.row(f);
+    }
+  }
+  assert(off == (int)(F.rows()-offending.size()));
+  // Now append replacement faces for offending faces
+  for(int o = 0;o<(int)offending.size();o++)
+  {
+    FF.block(off,0,NF[o].rows(),3) = NF[o];
+    off += NF[o].rows();
+  }
+  // Append vertices
+  VV.resize(V.rows()+NV_count,3);
+  VV.block(0,0,V.rows(),3) = V;
+  {
+    int i = 0;
+    for(
+      typename list<Point_3>::const_iterator nvit = NV.begin();
+      nvit != NV.end();
+      nvit++)
+    {
+      for(int d = 0;d<3;d++)
+      {
+        const Point_3 & p = *nvit;
+        VV(V.rows()+i,d) = CGAL::to_double(p[d]);
+        // This distinction does not seem necessary:
+//#ifdef INEXACT_CONSTRUCTION
+//        VV(V.rows()+i,d) = CGAL::to_double(p[d]);
+//#else
+//        VV(V.rows()+i,d) = CGAL::to_double(p[d].exact());
+//#endif
+      }
+      i++;
+    }
+  }
+
+  // Q: Does this give the same result as TETGEN?
+  // A: For the cow and beast, yes.
+
+  // Q: Is tetgen faster than this CGAL implementation?
+  // A: Well, yes. But Tetgen is only solving the detection (predicates)
+  // problem. This is also appending the intersection objects (construction).
+  // But maybe tetgen is still faster for the detection part. For example, this
+  // CGAL implementation on the beast takes 98 seconds but tetgen detection
+  // takes 14 seconds
+
+}
+
+
+template <typename Kernel>
+inline void igl::SelfIntersectMesh<Kernel>::mark_offensive(const int f)
+{
+  using namespace std;
+  lIF.push_back(f);
+  if(!offensive[f])
+  {
+    offensive[f]=true;
+    offending_index[f]=offending.size();
+    offending.push_back(f);
+    // Add to edge map
+    for(int e = 0; e<3;e++)
+    {
+      // Index of F's eth edge in V
+      int i = F(f,(e+1)%3);
+      int j = F(f,(e+2)%3);
+      // Be sure that i<j
+      if(i>j)
+      {
+        swap(i,j);
+      }
+      // Create new list if there is no entry
+      if(edge2faces.count(EMK(i,j))==0)
+      {
+        edge2faces[EMK(i,j)] = list<int>();
+      }
+      // append to list
+      edge2faces[EMK(i,j)].push_back(f);
+    }
+  }
+}
+
+template <typename Kernel>
+inline void igl::SelfIntersectMesh<Kernel>::count_intersection(
+  const int fa,
+  const int fb)
+{
+  mark_offensive(fa);
+  mark_offensive(fb);
+  this->count++;
+  // We found the first intersection
+  if(params.first_only && this->count >= 1)
+  {
+    throw IGL_FIRST_HIT_EXCEPTION;
+  }
+}
+
+template <typename Kernel>
+inline bool igl::SelfIntersectMesh<Kernel>::intersect(
+  const Triangle_3 & A, 
+  const Triangle_3 & B, 
+  const int fa,
+  const int fb)
+{
+  // Determine whether there is an intersection
+  if(!CGAL::do_intersect(A,B))
+  {
+    return false;
+  }
+  if(!params.detect_only)
+  {
+    // Construct intersection
+    CGAL::Object result = CGAL::intersection(A,B);
+    F_objects[fa].push_back(result);
+    F_objects[fb].push_back(result);
+  }
+  count_intersection(fa,fb);
+  return true;
+}
+
+template <typename Kernel>
+inline bool igl::SelfIntersectMesh<Kernel>::single_shared_vertex(
+  const Triangle_3 & A,
+  const Triangle_3 & B,
+  const int fa,
+  const int fb,
+  const int va,
+  const int vb)
+{
+  ////using namespace std;
+  //CGAL::Object result = CGAL::intersection(A,B);
+  //if(CGAL::object_cast<Segment_3 >(&result))
+  //{
+  //  // Append to each triangle's running list
+  //  F_objects[fa].push_back(result);
+  //  F_objects[fb].push_back(result);
+  //  count_intersection(fa,fb);
+  //}else
+  //{
+  //  // Then intersection must be at point
+  //  // And point must be at shared vertex
+  //  assert(CGAL::object_cast<Point_3>(&result));
+  //}
+  if(single_shared_vertex(A,B,fa,fb,va))
+  {
+    return true;
+  }
+  return single_shared_vertex(B,A,fb,fa,vb);
+}
+
+template <typename Kernel>
+inline bool igl::SelfIntersectMesh<Kernel>::single_shared_vertex(
+  const Triangle_3 & A,
+  const Triangle_3 & B,
+  const int fa,
+  const int fb,
+  const int va)
+{
+  // This was not a good idea. It will not handle coplanar triangles well.
+  using namespace std;
+  Segment_3 sa(
+    A.vertex((va+1)%3),
+    A.vertex((va+2)%3));
+
+  if(CGAL::do_intersect(sa,B))
+  {
+    CGAL::Object result = CGAL::intersection(sa,B);
+    if(const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
+    {
+      if(!params.detect_only)
+      {
+        // Single intersection --> segment from shared point to intersection
+        CGAL::Object seg = CGAL::make_object(Segment_3(
+          A.vertex(va),
+          *p));
+        F_objects[fa].push_back(seg);
+        F_objects[fb].push_back(seg);
+      }
+      count_intersection(fa,fb);
+      return true;
+    }else if(CGAL::object_cast<Segment_3 >(&result))
+    {
+      //cerr<<REDRUM("Coplanar at: "<<fa<<" & "<<fb<<" (single shared).")<<endl;
+      // Must be coplanar
+      if(params.detect_only)
+      {
+        count_intersection(fa,fb);
+      }else
+      {
+        // WRONG:
+        //// Segment intersection --> triangle from shared point to intersection
+        //CGAL::Object tri = CGAL::make_object(Triangle_3(
+        //  A.vertex(va),
+        //  s->vertex(0),
+        //  s->vertex(1)));
+        //F_objects[fa].push_back(tri);
+        //F_objects[fb].push_back(tri);
+        //count_intersection(fa,fb);
+        // Need to do full test. Intersection could be a general poly.
+        bool test = intersect(A,B,fa,fb);
+        ((void)test);
+        assert(test);
+      }
+      return true;
+    }else
+    {
+      cerr<<REDRUM("Segment ∩ triangle neither point nor segment?")<<endl;
+      assert(false);
+    }
+  }
+
+  return false;
+}
+
+
+template <typename Kernel>
+inline bool igl::SelfIntersectMesh<Kernel>::double_shared_vertex(
+  const Triangle_3 & A,
+  const Triangle_3 & B,
+  const int fa,
+  const int fb)
+{
+  using namespace std;
+  // Cheaper way to do this than calling do_intersect?
+  if(
+    // Can only have an intersection if co-planar
+    (A.supporting_plane() == B.supporting_plane() ||
+    A.supporting_plane() == B.supporting_plane().opposite()) &&
+    CGAL::do_intersect(A,B))
+  {
+    // Construct intersection
+    try
+    {
+      CGAL::Object result = CGAL::intersection(A,B);
+      if(result)
+      {
+        if(CGAL::object_cast<Segment_3 >(&result))
+        {
+          // not coplanar
+          return false;
+        } else if(CGAL::object_cast<Point_3 >(&result))
+        {
+          // this "shouldn't" happen but does for inexact
+          return false;
+        } else
+        {
+          if(!params.detect_only)
+          {
+            // Triangle object
+            F_objects[fa].push_back(result);
+            F_objects[fb].push_back(result);
+          }
+          count_intersection(fa,fb);
+          //cerr<<REDRUM("Coplanar at: "<<fa<<" & "<<fb<<" (double shared).")<<endl;
+          return true;
+        }
+      }else
+      {
+        // CGAL::intersection is disagreeing with do_intersect
+        return false;
+      }
+    }catch(...)
+    {
+      // This catches some cgal assertion:
+      //     CGAL error: assertion violation!
+      //     Expression : is_finite(d)
+      //     File       : /opt/local/include/CGAL/GMP/Gmpq_type.h
+      //     Line       : 132
+      //     Explanation: 
+      // But only if NDEBUG is not defined, otherwise there's an uncaught
+      // "Floating point exception: 8" SIGFPE
+      return false;
+    }
+  }
+  // Shouldn't get here either
+  assert(false);
+  return false;
+}
+
+template <typename Kernel>
+inline void igl::SelfIntersectMesh<Kernel>::box_intersect(
+  const Box& a, 
+  const Box& b)
+{
+  using namespace std;
+  // index in F and T
+  int fa = a.handle()-T.begin();
+  int fb = b.handle()-T.begin();
+  const Triangle_3 & A = *a.handle();
+  const Triangle_3 & B = *b.handle();
+  // I'm not going to deal with degenerate triangles, though at some point we
+  // should
+  assert(!a.handle()->is_degenerate());
+  assert(!b.handle()->is_degenerate());
+  // Number of combinatorially shared vertices
+  int comb_shared_vertices = 0;
+  // Number of geometrically shared vertices (*not* including combinatorially
+  // shared)
+  int geo_shared_vertices = 0;
+  // Keep track of shared vertex indices (we only handles single shared
+  // vertices as a special case, so just need last/first/only ones)
+  int va=-1,vb=-1;
+  int ea,eb;
+  for(ea=0;ea<3;ea++)
+  {
+    for(eb=0;eb<3;eb++)
+    {
+      if(F(fa,ea) == F(fb,eb))
+      {
+        comb_shared_vertices++;
+        va = ea;
+        vb = eb;
+      }else if(A.vertex(ea) == B.vertex(eb))
+      {
+        geo_shared_vertices++;
+        va = ea;
+        vb = eb;
+      }
+    }
+  }
+  const int total_shared_vertices = comb_shared_vertices + geo_shared_vertices;
+  if(comb_shared_vertices== 3)
+  {
+    // Combinatorially duplicate face, these should be removed by preprocessing
+    cerr<<REDRUM("Facets "<<fa<<" and "<<fb<<" are combinatorial duplicates")<<endl;
+    goto done;
+  }
+  if(total_shared_vertices== 3)
+  {
+    // Geometrically duplicate face, these should be removed by preprocessing
+    cerr<<REDRUM("Facets "<<fa<<" and "<<fb<<" are geometrical duplicates")<<endl;
+    goto done;
+  }
+  //// SPECIAL CASES ARE BROKEN FOR COPLANAR TRIANGLES
+  //if(total_shared_vertices > 0)
+  //{
+  //  bool coplanar = 
+  //    CGAL::coplanar(A.vertex(0),A.vertex(1),A.vertex(2),B.vertex(0)) &&
+  //    CGAL::coplanar(A.vertex(0),A.vertex(1),A.vertex(2),B.vertex(1)) &&
+  //    CGAL::coplanar(A.vertex(0),A.vertex(1),A.vertex(2),B.vertex(2));
+  //  if(coplanar)
+  //  {
+  //    cerr<<MAGENTAGIN("Facets "<<fa<<" and "<<fb<<
+  //      " are coplanar and share vertices")<<endl;
+  //    goto full;
+  //  }
+  //}
+
+  if(total_shared_vertices == 2)
+  {
+    // Q: What about coplanar?
+    //
+    // o    o
+    // |\  /|
+    // | \/ |
+    // | /\ |
+    // |/  \|
+    // o----o
+    double_shared_vertex(A,B,fa,fb);
+
+    goto done;
+  }
+  assert(total_shared_vertices<=1);
+  if(total_shared_vertices==1)
+  {
+    assert(va>=0 && va<3);
+    assert(vb>=0 && vb<3);
+//#ifndef NDEBUG
+//    CGAL::Object result =
+//#endif
+    single_shared_vertex(A,B,fa,fb,va,vb);
+//#ifndef NDEBUG
+//    if(!CGAL::object_cast<Segment_3 >(&result))
+//    {
+//      const Point_3 * p = CGAL::object_cast<Point_3 >(&result);
+//      assert(p);
+//      for(int ea=0;ea<3;ea++)
+//      {
+//        for(int eb=0;eb<3;eb++)
+//        {
+//          if(F(fa,ea) == F(fb,eb))
+//          {
+//            assert(*p==A.vertex(ea));
+//            assert(*p==B.vertex(eb));
+//          }
+//        }
+//      }
+//    }
+//#endif
+  }else
+  {
+//full:
+    // No geometrically shared vertices, do general intersect
+    intersect(*a.handle(),*b.handle(),fa,fb);
+  }
+done:
+  return;
+}
+
+// Compute 2D delaunay triangulation of a given 3d triangle and a list of
+// intersection objects (points,segments,triangles). CGAL uses an affine
+// projection rather than an isometric projection, so we're not guaranteed
+// that the 2D delaunay triangulation here will be a delaunay triangulation
+// in 3D.
+//
+// Inputs:
+//   A  triangle in 3D
+//   A_objects_3  updated list of intersection objects for A
+// Outputs:
+//   cdt  Contrained delaunay triangulation in projected 2D plane
+template <typename Kernel>
+inline void igl::SelfIntersectMesh<Kernel>::projected_delaunay(
+  const Triangle_3 & A,
+  const std::list<CGAL::Object> & A_objects_3,
+  CDT_plus_2 & cdt)
+{
+  using namespace std;
+  // http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus
+  // Plane of triangle A
+  Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2));
+  // Insert triangle into vertices
+  typename CDT_plus_2::Vertex_handle corners[3];
+  for(int i = 0;i<3;i++)
+  {
+    corners[i] = cdt.insert(P.to_2d(A.vertex(i)));
+  }
+  // Insert triangle edges as constraints
+  for(int i = 0;i<3;i++)
+  {
+    cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]);
+  }
+  // Insert constraints for intersection objects
+  for(
+    typename list<CGAL::Object>::const_iterator lit = A_objects_3.begin();
+    lit != A_objects_3.end();
+    lit++)
+  {
+    CGAL::Object obj = *lit;
+    if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
+    {
+      // Add point
+      cdt.insert(P.to_2d(*ipoint));
+    } else if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
+    {
+      // Add segment constraint
+      cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
+    } else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
+    {
+      // Add 3 segment constraints
+      cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
+      cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
+      cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
+    } else if(const std::vector<Point_3 > *polyp = 
+        CGAL::object_cast< std::vector<Point_3 > >(&obj))
+    {
+      //cerr<<REDRUM("Poly...")<<endl;
+      const std::vector<Point_3 > & poly = *polyp;
+      const int m = poly.size();
+      assert(m>=2);
+      for(int p = 0;p<m;p++)
+      {
+        const int np = (p+1)%m;
+        cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
+      }
+    }else
+    {
+      cerr<<REDRUM("What is this object?!")<<endl;
+      assert(false);
+    }
+  }
+}
+
+#endif
+

+ 123 - 0
include/igl/cgal/intersect_other.cpp

@@ -0,0 +1,123 @@
+#include "intersect_other.h"
+#include "CGAL_includes.hpp"
+#include "mesh_to_cgal_triangle_list.h"
+
+#ifndef IGL_FIRST_HIT_EXCEPTION
+#define IGL_FIRST_HIT_EXCEPTION 10
+#endif
+
+IGL_INLINE void igl::intersect_other(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  const Eigen::MatrixXd & U,
+  const Eigen::MatrixXi & G,
+  const bool first_only,
+  Eigen::MatrixXi & IF)
+{
+  using namespace std;
+  using namespace Eigen;
+
+
+  typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+  // 3D Primitives
+  typedef CGAL::Point_3<Kernel>    Point_3;
+  typedef CGAL::Segment_3<Kernel>  Segment_3; 
+  typedef CGAL::Triangle_3<Kernel> Triangle_3; 
+  typedef CGAL::Plane_3<Kernel>    Plane_3;
+  typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3; 
+  typedef CGAL::Polyhedron_3<Kernel> Polyhedron_3; 
+  typedef CGAL::Nef_polyhedron_3<Kernel> Nef_polyhedron_3; 
+  // 2D Primitives
+  typedef CGAL::Point_2<Kernel>    Point_2;
+  typedef CGAL::Segment_2<Kernel>  Segment_2; 
+  typedef CGAL::Triangle_2<Kernel> Triangle_2; 
+  // 2D Constrained Delaunay Triangulation types
+  typedef CGAL::Triangulation_vertex_base_2<Kernel>  TVB_2;
+  typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
+  typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
+  typedef CGAL::Exact_intersections_tag Itag;
+  typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> 
+    CDT_2;
+  typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
+  // Axis-align boxes for all-pairs self-intersection detection
+  typedef std::vector<Triangle_3> Triangles;
+  typedef typename Triangles::iterator TrianglesIterator;
+  typedef typename Triangles::const_iterator TrianglesConstIterator;
+  typedef 
+    CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator> 
+    Box;
+
+  Triangles TF,TG;
+  // Compute and process self intersections
+  mesh_to_cgal_triangle_list(V,F,TF);
+  mesh_to_cgal_triangle_list(U,G,TG);
+  // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5 
+  // Create the corresponding vector of bounding boxes
+  std::vector<Box> F_boxes,G_boxes;
+  const auto box_up = [](Triangles & T, std::vector<Box> & boxes)
+  {
+    boxes.reserve(T.size());
+    for ( 
+      TrianglesIterator tit = T.begin(); 
+      tit != T.end(); 
+      ++tit)
+    {
+      boxes.push_back(Box(tit->bbox(), tit));
+    }
+  };
+  box_up(TF,F_boxes);
+  box_up(TG,G_boxes);
+  std::list<int> lIF;
+  const auto cb = [&](const Box &a, const Box &b)
+  {
+    using namespace std;
+    // index in F and T
+    int fa = a.handle()-TF.begin();
+    int fb = b.handle()-TG.begin();
+    const Triangle_3 & A = *a.handle();
+    const Triangle_3 & B = *b.handle();
+    if(CGAL::do_intersect(A,B))
+    {
+      // There was an intersection
+      lIF.push_back(fa);
+      lIF.push_back(fb);
+      if(first_only)
+      {
+        throw IGL_FIRST_HIT_EXCEPTION;
+      }
+    }
+  };
+  try{
+    CGAL::box_intersection_d(
+      F_boxes.begin(), F_boxes.end(),
+      G_boxes.begin(), G_boxes.end(),
+      cb);
+  }catch(int e)
+  {
+    // Rethrow if not FIRST_HIT_EXCEPTION
+    if(e != IGL_FIRST_HIT_EXCEPTION)
+    {
+      throw e;
+    }
+    // Otherwise just fall through
+  }
+
+  // Convert lIF to Eigen matrix
+  assert(lIF.size()%2 == 0);
+  IF.resize(lIF.size()/2,2);
+  {
+    int i=0;
+    for(
+      list<int>::const_iterator ifit = lIF.begin();
+      ifit!=lIF.end();
+      )
+    {
+      IF(i,0) = (*ifit);
+      ifit++; 
+      IF(i,1) = (*ifit);
+      ifit++;
+      i++;
+    }
+  }
+
+}

+ 46 - 0
include/igl/cgal/intersect_other.h

@@ -0,0 +1,46 @@
+#ifndef IGL_INTERSECT_OTHER_H
+#define IGL_INTERSECT_OTHER_H
+#include <igl/igl_inline.h>
+
+#include <Eigen/Dense>
+
+#ifdef MEX
+#  include <mex.h>
+#  include <cassert>
+#  undef assert
+#  define assert( isOK ) ( (isOK) ? (void)0 : (void) mexErrMsgTxt(C_STR(__FILE__<<":"<<__LINE__<<": failed assertion `"<<#isOK<<"'"<<std::endl) ) )
+#endif
+
+namespace igl
+{
+  // INTERSECT Given a triangle mesh (V,F) and another mesh (U,G) find all pairs
+  // of intersecting faces. Note that self-intersections are ignored.
+  // 
+  // [VV,FF,IF] = selfintersect(V,F,'ParameterName',ParameterValue, ...)
+  //
+  // Inputs:
+  //   V  #V by 3 list of vertex positions
+  //   F  #F by 3 list of triangle indices into V
+  //   U  #U by 3 list of vertex positions
+  //   G  #G by 3 list of triangle indices into U
+  //   first_only  whether to only detect the first intersection.
+  // Outputs:
+  //   IF  #intersecting face pairs by 2 list of intersecting face pairs,
+  //     indexing F and G
+  //
+  // See also: selfintersect
+  IGL_INLINE void intersect_other(
+    const Eigen::MatrixXd & V,
+    const Eigen::MatrixXi & F,
+    const Eigen::MatrixXd & U,
+    const Eigen::MatrixXi & G,
+    const bool first_only,
+    Eigen::MatrixXi & IF);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "intersect_other.cpp"
+#endif
+  
+#endif
+

+ 33 - 0
include/igl/cgal/mesh_to_cgal_triangle_list.cpp

@@ -0,0 +1,33 @@
+#include "mesh_to_cgal_triangle_list.h"
+
+#include <cassert>
+
+template <typename Kernel>
+IGL_INLINE void igl::mesh_to_cgal_triangle_list(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  std::vector<CGAL::Triangle_3<Kernel> > & T)
+{
+  typedef CGAL::Point_3<Kernel>    Point_3;
+  typedef CGAL::Triangle_3<Kernel> Triangle_3; 
+  // Must be 3D
+  assert(V.cols() == 3);
+  // Must be triangles
+  assert(F.cols() == 3);
+  T.reserve(F.rows());
+  // Loop over faces
+  for(int f = 0;f<(int)F.rows();f++)
+  {
+    T.push_back(
+      Triangle_3(
+        Point_3( V(F(f,0),0), V(F(f,0),1), V(F(f,0),2)),
+        Point_3( V(F(f,1),0), V(F(f,1),1), V(F(f,1),2)),
+        Point_3( V(F(f,2),0), V(F(f,2),1), V(F(f,2),2))));
+  }
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+template void igl::mesh_to_cgal_triangle_list<CGAL::Epeck>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+template void igl::mesh_to_cgal_triangle_list<CGAL::Epick>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+#endif

+ 25 - 0
include/igl/cgal/mesh_to_cgal_triangle_list.h

@@ -0,0 +1,25 @@
+#ifndef IGL_MESH_TO_CGAL_TRIANGLE_LIST_H
+#define IGL_MESH_TO_CGAL_TRIANGLE_LIST_H
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+#include "CGAL_includes.hpp"
+namespace igl
+{
+  // Convert a mesh (V,F) to a list of CGAL triangles
+  //
+  // Inputs:
+  //   V  #V by 3 list of vertex positions
+  //   F  #F by 3 list of triangle indices
+  // Outputs:
+  //   T  #F list of CGAL triangles
+  template <typename Kernel>
+  IGL_INLINE void mesh_to_cgal_triangle_list(
+    const Eigen::MatrixXd & V,
+    const Eigen::MatrixXi & F,
+    std::vector<CGAL::Triangle_3<Kernel> > & T);
+}
+#ifdef IGL_HEADER_ONLY
+#  include "mesh_to_cgal_triangle_list.cpp"
+#endif
+
+#endif

+ 41 - 0
include/igl/cgal/selfintersect.cpp

@@ -0,0 +1,41 @@
+#include "selfintersect.h"
+#include "SelfIntersectMesh.h"
+#include <igl/C_STR.h>
+#include <list>
+
+IGL_INLINE void igl::selfintersect(
+  const Eigen::MatrixXd & V,
+  const Eigen::MatrixXi & F,
+  const SelfintersectParam & params,
+  Eigen::MatrixXd & VV,
+  Eigen::MatrixXi & FF,
+  Eigen::MatrixXi & IF)
+{
+  using namespace std;
+  if(params.detect_only)
+  {
+    //// This is probably a terrible idea, but CGAL is throwing floating point
+    //// exceptions.
+
+//#ifdef __APPLE__
+//#define IGL_THROW_FPE 11
+//    const auto & throw_fpe = [](int e)
+//    {
+//      throw "IGL_THROW_FPE";
+//    };
+//    signal(SIGFPE,throw_fpe);
+//#endif
+
+    typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+    SelfIntersectMesh<Kernel> SIM = SelfIntersectMesh<Kernel>(V,F,params,VV,FF,IF);
+
+//#ifdef __APPLE__
+//    signal(SIGFPE,SIG_DFL);
+//#endif
+
+  }else
+  {
+    typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
+    SelfIntersectMesh<Kernel> SIM = SelfIntersectMesh<Kernel>(V,F,params,VV,FF,IF);
+  }
+}

+ 55 - 0
include/igl/cgal/selfintersect.h

@@ -0,0 +1,55 @@
+#ifndef IGL_SELFINTERSECT_H
+#define IGL_SELFINTERSECT_H
+#include <igl/igl_inline.h>
+
+#include <Eigen/Dense>
+
+#ifdef MEX
+#  include <mex.h>
+#  include <cassert>
+#  undef assert
+#  define assert( isOK ) ( (isOK) ? (void)0 : (void) mexErrMsgTxt(C_STR(__FILE__<<":"<<__LINE__<<": failed assertion `"<<#isOK<<"'"<<std::endl) ) )
+#endif
+
+namespace igl
+{
+  // Optional Parameters
+  //   DetectOnly  Only compute IF, leave VV and FF alone
+  struct SelfintersectParam
+  {
+    bool detect_only;
+    bool first_only;
+    SelfintersectParam():detect_only(false),first_only(false){};
+  };
+  
+  // Given a triangle mesh (V,F) compute a new mesh (VV,FF) which is the same as
+  // (V,F) except that any self-intersecting triangles in (V,F) have been
+  // subdivided (new vertices and face created) so that the self-intersection
+  // contour lies exactly on edges in (VV,FF). New vertices will appear in
+  // original faces or on original edges. New vertices on edges are "merged" only
+  // across original faces sharing that edge. This means that if the input
+  // triangle mesh is a closed manifold the output will be too.
+  //
+  // Inputs:
+  //   V  #V by 3 list of vertex positions
+  //   F  #F by 3 list of triangle indices into V
+  //   params  struct of optional parameters
+  // Outputs:
+  //   VV  #VV by 3 list of vertex positions
+  //   FF  #FF by 3 list of triangle indices into V
+  //   IF  #intersecting face pairs by 2  list of intersecting face pairs,
+  //     indexing F
+  IGL_INLINE void selfintersect(
+    const Eigen::MatrixXd & V,
+    const Eigen::MatrixXi & F,
+    const SelfintersectParam & params,
+    Eigen::MatrixXd & VV,
+    Eigen::MatrixXi & FF,
+    Eigen::MatrixXi & IF);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "selfintersect.cpp"
+#endif
+  
+#endif

+ 58 - 106
include/igl/cotangent.cpp

@@ -6,13 +6,20 @@
 // 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 "cotangent.h"
+#include "doublearea.h"
 #include "edge_lengths.h"
+#include "face_areas.h"
+#include "volume.h"
+#include "dihedral_angles.h"
 
 #include "verbose.h"
 
 
-template <class MatV, class MatF, class MatC>
-IGL_INLINE void igl::cotangent(const MatV & V, const MatF & F, MatC & C)
+template <typename DerivedV, typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::cotangent(
+  const Eigen::PlainObjectBase<DerivedV>& V,
+  const Eigen::PlainObjectBase<DerivedF>& F,
+  Eigen::PlainObjectBase<DerivedC>& C)
 {
   using namespace igl;
   using namespace std;
@@ -23,127 +30,72 @@ IGL_INLINE void igl::cotangent(const MatV & V, const MatF & F, MatC & C)
   int m = F.rows();
 
   // Law of cosines + law of sines
-  if(simplex_size == 3)
+  switch(simplex_size)
   {
-    // Triangles
-    //Matrix<typename MatC::Scalar,Dynamic,3> l;
-    //edge_lengths(V,F,l);
-    // edge lengths numbered same as opposite vertices
-    Matrix<typename MatC::Scalar,Dynamic,3> l(m,3);
-    // loop over faces
-    for(int i = 0;i<m;i++)
+    case 3:
     {
-      l(i,0) = sqrt((V.row(F(i,1))-V.row(F(i,2))).array().pow(2).sum());
-      l(i,1) = sqrt((V.row(F(i,2))-V.row(F(i,0))).array().pow(2).sum());
-      l(i,2) = sqrt((V.row(F(i,0))-V.row(F(i,1))).array().pow(2).sum());
+      // Triangles
+      //Matrix<typename DerivedC::Scalar,Dynamic,3> l;
+      //edge_lengths(V,F,l);
+      // edge lengths numbered same as opposite vertices
+      Matrix<typename DerivedC::Scalar,Dynamic,3> l;
+      igl::edge_lengths(V,F,l);
+      // double area
+      Matrix<typename DerivedC::Scalar,Dynamic,1> dblA;
+      doublearea(l,dblA);
+      // cotangents and diagonal entries for element matrices
+      // correctly divided by 4 (alec 2010)
+      C.resize(m,3);
+      for(int i = 0;i<m;i++)
+      {
+        C(i,0) = (l(i,1)*l(i,1) + l(i,2)*l(i,2) - l(i,0)*l(i,0))/dblA(i)/4.0;
+        C(i,1) = (l(i,2)*l(i,2) + l(i,0)*l(i,0) - l(i,1)*l(i,1))/dblA(i)/4.0;
+        C(i,2) = (l(i,0)*l(i,0) + l(i,1)*l(i,1) - l(i,2)*l(i,2))/dblA(i)/4.0;
+      }
+      break;
     }
-    // semiperimeters
-    Matrix<typename MatC::Scalar,Dynamic,1> s = l.rowwise().sum()*0.5;
-    assert(s.rows() == m);
-    // Heron's formula for area
-    Matrix<typename MatC::Scalar,Dynamic,1> dblA(m);
-    for(int i = 0;i<m;i++)
+    case 4:
     {
-      dblA(i) = 2.0*sqrt(s(i)*(s(i)-l(i,0))*(s(i)-l(i,1))*(s(i)-l(i,2)));
-    }
-    // cotangents and diagonal entries for element matrices
-    // correctly divided by 4 (alec 2010)
-    C.resize(m,3);
-    for(int i = 0;i<m;i++)
-    {
-      C(i,0) = (l(i,1)*l(i,1) + l(i,2)*l(i,2) - l(i,0)*l(i,0))/dblA(i)/4.0;
-      C(i,1) = (l(i,2)*l(i,2) + l(i,0)*l(i,0) - l(i,1)*l(i,1))/dblA(i)/4.0;
-      C(i,2) = (l(i,0)*l(i,0) + l(i,1)*l(i,1) - l(i,2)*l(i,2))/dblA(i)/4.0;
-    }
-  }else if(simplex_size == 4)
-  {
-    // Tetrahedra
-    typedef Matrix<typename MatV::Scalar,3,1> Vec3;
-    typedef Matrix<typename MatV::Scalar,3,3> Mat3;
-    typedef Matrix<typename MatV::Scalar,3,4> Mat3x4;
-    typedef Matrix<typename MatV::Scalar,4,4> Mat4x4;
 
-    // preassemble right hand side
-    // COLUMN-MAJOR ORDER FOR LAPACK
-    Mat3x4 rhs;
-    rhs <<
-      1,0,0,-1,
-      0,1,0,-1,
-      0,0,1,-1;
+      // edge lengths numbered same as opposite vertices
+      Matrix<typename DerivedC::Scalar,Dynamic,6> l;
+      edge_lengths(V,F,l);
+      Matrix<typename DerivedC::Scalar,Dynamic,4> s;
+      face_areas(l,s);
+      Matrix<typename DerivedC::Scalar,Dynamic,6> cos_theta,theta;
+      dihedral_angles_intrinsic(l,s,theta,cos_theta);
 
-    bool diag_all_pos = true;
-    C.resize(m,6);
+      // volume
+      Matrix<typename DerivedC::Scalar,Dynamic,1> vol;
+      volume(l,vol);
 
-    // loop over tetrahedra
-    for(int j = 0;j<F.rows();j++)
-    {
-      // points a,b,c,d make up the tetrahedra
-      size_t a = F(j,0);
-      size_t b = F(j,1);
-      size_t c = F(j,2);
-      size_t d = F(j,3);
-      //const std::vector<double> & pa = vertices[a];
-      //const std::vector<double> & pb = vertices[b];
-      //const std::vector<double> & pc = vertices[c];
-      //const std::vector<double> & pd = vertices[d];
-      Vec3 pa = V.row(a);
-      Vec3 pb = V.row(b);
-      Vec3 pc = V.row(c);
-      Vec3 pd = V.row(d);
-
-      // Following definition that appears in the appendix of: ``Interactive
-      // Topology-aware Surface Reconstruction,'' by Sharf, A. et al
-      // http://www.cs.bgu.ac.il/~asharf/Projects/InSuRe/Insure_siggraph_final.pdf
 
-      // compute transpose of jacobian Jj
-      Mat3 JTj;
-      JTj.row(0) = pa-pd;
-      JTj.row(1) = pb-pd;
-      JTj.row(2) = pc-pd;
+      // Law of sines
+      // http://mathworld.wolfram.com/Tetrahedron.html
+      Matrix<typename DerivedC::Scalar,Dynamic,6> sin_theta(m,6);
+      sin_theta.col(0) = vol.array() / ((2./(3.*l.col(0).array())).array() * s.col(1).array() * s.col(2).array());
+      sin_theta.col(1) = vol.array() / ((2./(3.*l.col(1).array())).array() * s.col(2).array() * s.col(0).array());
+      sin_theta.col(2) = vol.array() / ((2./(3.*l.col(2).array())).array() * s.col(0).array() * s.col(1).array());
+      sin_theta.col(3) = vol.array() / ((2./(3.*l.col(3).array())).array() * s.col(3).array() * s.col(0).array());
+      sin_theta.col(4) = vol.array() / ((2./(3.*l.col(4).array())).array() * s.col(3).array() * s.col(1).array());
+      sin_theta.col(5) = vol.array() / ((2./(3.*l.col(5).array())).array() * s.col(3).array() * s.col(2).array());
 
-      // compute abs(determinant of JTj)/6 (volume of tet)
-      // determinant of transpose of A equals determinant of A
-      double volume = fabs(JTj.determinant())/6.0;
-      //printf("volume[%d] = %g\n",j+1,volume);
 
-      // solve Jj' * Ej = [-I -1], for Ej
-      // in other words solve JTj * Ej = [-I -1], for Ej
-      Mat3x4 Ej = JTj.inverse() * rhs;
-      // compute Ej'*Ej
-      Mat4x4 EjTEj = Ej.transpose() * Ej;
+      // http://arxiv.org/pdf/1208.0354.pdf Page 18
+      C = (1./6.) * l.array() * cos_theta.array() / sin_theta.array();
 
-      // Kj =  det(JTj)/6 * Ej'Ej 
-      Mat4x4 Kj = EjTEj*volume;
-      diag_all_pos &= ((Kj(0,0)>0) & (Kj(1,1)>0)) & ((Kj(2,2)>0) & (Kj(3,3)>0));
-      C(j,0) = Kj(1,2);
-      C(j,1) = Kj(2,0);
-      C(j,2) = Kj(0,1);
-      C(j,3) = Kj(3,0);
-      C(j,4) = Kj(3,1);
-      C(j,5) = Kj(3,2);
+      break;
     }
-    if(diag_all_pos)
+    default:
     {
-#ifdef VERBOSE 
-      verbose("cotangent.h: Flipping sign of cotangent, so that cots are positive\n");
-#endif
-      C *= -1.0;
+      fprintf(stderr,
+          "cotangent.h: Error: Simplex size (%d) not supported\n", simplex_size);
+      assert(false);
     }
-  }else
-  {
-    fprintf(stderr,
-      "cotangent.h: Error: Simplex size (%d) not supported\n", simplex_size);
-    assert(false);
   }
 }
 
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
-// generated by autoexplicit.sh
-template void igl::cotangent<Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
-// generated by autoexplicit.sh
-template void igl::cotangent<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
-// generated by autoexplicit.sh
-template void igl::cotangent<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
-template void igl::cotangent<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+template void igl::cotangent<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 9 - 3
include/igl/cotangent.h

@@ -8,6 +8,7 @@
 #ifndef IGL_COTANGENT_H
 #define IGL_COTANGENT_H
 #include "igl_inline.h"
+#include <Eigen/Core>
 namespace igl
 {
   // COTANGENT compute the cotangents of each angle in mesh (V,F)
@@ -22,12 +23,17 @@ namespace igl
   // Outputs:
   //   C  #F by {3|6} list of cotangents corresponding angles
   //     for triangles, columns correspond to edges [1,2],[2,0],[0,1]
-  //     for tets, columns correspond to edges [1,2],[2,0],[0,1],[3,0],[3,1],[3,2]
+  //     for tets, columns correspond to edges
+  //     [1,2],[2,0],[0,1],[3,0],[3,1],[3,2] **times corresponding edge
+  //     lengths**
   //
   // Known bug:
   //   This computes 0.5*cotangent
-  template <class MatV, class MatF, class MatC>
-  IGL_INLINE void cotangent(const MatV & V, const MatF & F, MatC & C);
+  template <typename DerivedV, typename DerivedF, typename DerivedC>
+  IGL_INLINE void cotangent(
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedF>& F,
+    Eigen::PlainObjectBase<DerivedC>& C);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 3 - 3
include/igl/cotmatrix.cpp

@@ -17,8 +17,8 @@
 
 template <typename DerivedV, typename DerivedF, typename Scalar>
 IGL_INLINE void igl::cotmatrix(
-  const Eigen::MatrixBase<DerivedV> & V, 
-  const Eigen::MatrixBase<DerivedF> & F, 
+  const Eigen::PlainObjectBase<DerivedV> & V, 
+  const Eigen::PlainObjectBase<DerivedF> & F, 
   Eigen::SparseMatrix<Scalar>& L)
 {
   using namespace igl;
@@ -81,5 +81,5 @@ IGL_INLINE void igl::cotmatrix(
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
 // generated by autoexplicit.sh
-template void igl::cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
 #endif

+ 2 - 2
include/igl/cotmatrix.h

@@ -43,8 +43,8 @@ namespace igl
   // arithmetic order in cotangent.h: C(i,e) = (arithmetic)/dblA/4
   template <typename DerivedV, typename DerivedF, typename Scalar>
   IGL_INLINE void cotmatrix(
-    const Eigen::MatrixBase<DerivedV> & V, 
-    const Eigen::MatrixBase<DerivedF> & F, 
+    const Eigen::PlainObjectBase<DerivedV> & V, 
+    const Eigen::PlainObjectBase<DerivedF> & F, 
     Eigen::SparseMatrix<Scalar>& L);
 }
 

+ 94 - 0
include/igl/dihedral_angles.cpp

@@ -0,0 +1,94 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "dihedral_angles.h"
+#include <cassert>
+
+template <
+  typename DerivedV, 
+  typename DerivedT, 
+  typename Derivedtheta,
+  typename Derivedcos_theta>
+IGL_INLINE void igl::dihedral_angles(
+  Eigen::PlainObjectBase<DerivedV>& V,
+  Eigen::PlainObjectBase<DerivedT>& T,
+  Eigen::PlainObjectBase<Derivedtheta>& theta,
+  Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta)
+{
+  using namespace Eigen;
+  assert(T.cols() == 4);
+  Matrix<typename Derivedtheta::Scalar,Dynamic,6> l;
+  edge_lengths(V,T,l);
+  Matrix<typename Derivedtheta::Scalar,Dynamic,4> s;
+  face_areas(l,s);
+  return dihedral_angles_intrinsic(l,s,theta,cos_theta);
+}
+
+template <
+  typename DerivedL, 
+  typename DerivedA, 
+  typename Derivedtheta,
+  typename Derivedcos_theta>
+IGL_INLINE void igl::dihedral_angles_intrinsic(
+  Eigen::PlainObjectBase<DerivedL>& L,
+  Eigen::PlainObjectBase<DerivedA>& A,
+  Eigen::PlainObjectBase<Derivedtheta>& theta,
+  Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta)
+{
+  using namespace Eigen;
+  const int m = L.rows();
+  assert(m == A.rows());
+  // Law of cosines
+  // http://math.stackexchange.com/a/49340/35376
+  Matrix<typename Derivedtheta::Scalar,Dynamic,6> H_sqr(m,6);
+  H_sqr.col(0) = (1./16.) * (4. * L.col(3).array().square() * L.col(0).array().square() - 
+                                ((L.col(1).array().square() + L.col(4).array().square()) -
+                                 (L.col(2).array().square() + L.col(5).array().square())).square());
+  H_sqr.col(1) = (1./16.) * (4. * L.col(4).array().square() * L.col(1).array().square() - 
+                                ((L.col(2).array().square() + L.col(5).array().square()) -
+                                 (L.col(3).array().square() + L.col(0).array().square())).square());
+  H_sqr.col(2) = (1./16.) * (4. * L.col(5).array().square() * L.col(2).array().square() - 
+                                ((L.col(3).array().square() + L.col(0).array().square()) -
+                                 (L.col(4).array().square() + L.col(1).array().square())).square());
+  H_sqr.col(3) = (1./16.) * (4. * L.col(0).array().square() * L.col(3).array().square() - 
+                                ((L.col(4).array().square() + L.col(1).array().square()) -
+                                 (L.col(5).array().square() + L.col(2).array().square())).square());
+  H_sqr.col(4) = (1./16.) * (4. * L.col(1).array().square() * L.col(4).array().square() - 
+                                ((L.col(5).array().square() + L.col(2).array().square()) -
+                                 (L.col(0).array().square() + L.col(3).array().square())).square());
+  H_sqr.col(5) = (1./16.) * (4. * L.col(2).array().square() * L.col(5).array().square() - 
+                                ((L.col(0).array().square() + L.col(3).array().square()) -
+                                 (L.col(1).array().square() + L.col(4).array().square())).square());
+  cos_theta.resize(m,6);
+  cos_theta.col(0) = (H_sqr.col(0).array() - 
+      A.col(1).array().square() - A.col(2).array().square()).array() / 
+      (-2.*A.col(1).array() * A.col(2).array());
+  cos_theta.col(1) = (H_sqr.col(1).array() - 
+      A.col(2).array().square() - A.col(0).array().square()).array() / 
+      (-2.*A.col(2).array() * A.col(0).array());
+  cos_theta.col(2) = (H_sqr.col(2).array() - 
+      A.col(0).array().square() - A.col(1).array().square()).array() / 
+      (-2.*A.col(0).array() * A.col(1).array());
+  cos_theta.col(3) = (H_sqr.col(3).array() - 
+      A.col(3).array().square() - A.col(0).array().square()).array() / 
+      (-2.*A.col(3).array() * A.col(0).array());
+  cos_theta.col(4) = (H_sqr.col(4).array() - 
+      A.col(3).array().square() - A.col(1).array().square()).array() / 
+      (-2.*A.col(3).array() * A.col(1).array());
+  cos_theta.col(5) = (H_sqr.col(5).array() - 
+      A.col(3).array().square() - A.col(2).array().square()).array() / 
+      (-2.*A.col(3).array() * A.col(2).array());
+
+  theta = cos_theta.array().acos();
+
+  cos_theta.resize(m,6);
+
+}
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+template void igl::dihedral_angles_intrinsic<Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+#endif

+ 55 - 0
include/igl/dihedral_angles.h

@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DIHEDRAL_ANGLES_H
+#define IGL_DIHEDRAL_ANGLES_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // DIHEDRAL_ANGLES Compute dihedral angles for all tets of a given tet mesh
+  // (V,T)
+  //
+  // theta = dihedral_angles(V,T)
+  // theta = dihedral_angles(V,T,'ParameterName',parameter_value,...)
+  //
+  // Inputs:
+  //   V  #V by dim list of vertex positions
+  //   T  #V by 4 list of tet indices
+  // Outputs:
+  //   theta  #T by 6 list of dihedral angles (in radians)
+  //   cos_theta  #T by 6 list of cosine of dihedral angles (in radians)
+  //
+  template <
+    typename DerivedV, 
+    typename DerivedT, 
+    typename Derivedtheta,
+    typename Derivedcos_theta>
+  IGL_INLINE void dihedral_angles(
+    Eigen::PlainObjectBase<DerivedV>& V,
+    Eigen::PlainObjectBase<DerivedT>& T,
+    Eigen::PlainObjectBase<Derivedtheta>& theta,
+    Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
+  template <
+    typename DerivedL, 
+    typename DerivedA, 
+    typename Derivedtheta,
+    typename Derivedcos_theta>
+  IGL_INLINE void dihedral_angles_intrinsic(
+    Eigen::PlainObjectBase<DerivedL>& L,
+    Eigen::PlainObjectBase<DerivedA>& A,
+    Eigen::PlainObjectBase<Derivedtheta>& theta,
+    Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
+
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "dihedral_angles.cpp"
+#endif
+
+#endif
+

+ 2 - 0
include/igl/doublearea.cpp

@@ -101,6 +101,8 @@ IGL_INLINE void igl::doublearea(
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
 // generated by autoexplicit.sh
+template void igl::doublearea<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
 template void igl::doublearea<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);

+ 49 - 7
include/igl/edge_lengths.cpp

@@ -6,6 +6,7 @@
 // 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 "edge_lengths.h"
+#include <iostream>
 
 template <typename DerivedV, typename DerivedF, typename DerivedL>
 IGL_INLINE void igl::edge_lengths(
@@ -13,20 +14,61 @@ IGL_INLINE void igl::edge_lengths(
   const Eigen::PlainObjectBase<DerivedF>& F,
   Eigen::PlainObjectBase<DerivedL>& L)
 {
-  assert(F.cols() == 3);
-  L.resize(F.rows(),3);
-  // loop over faces
-  for(int i = 0;i<F.rows();i++)
+  using namespace std;
+  switch(F.cols())
   {
-    L(i,0) = sqrt((V.row(F(i,1))-V.row(F(i,2))).array().pow(2).sum());
-    L(i,1) = sqrt((V.row(F(i,2))-V.row(F(i,0))).array().pow(2).sum());
-    L(i,2) = sqrt((V.row(F(i,0))-V.row(F(i,1))).array().pow(2).sum());
+    case 3:
+    {
+      L.resize(F.rows(),3);
+      // loop over faces
+      for(int i = 0;i<F.rows();i++)
+      {
+        L(i,0) = sqrt((V.row(F(i,1))-V.row(F(i,2))).array().pow(2).sum());
+        L(i,1) = sqrt((V.row(F(i,2))-V.row(F(i,0))).array().pow(2).sum());
+        L(i,2) = sqrt((V.row(F(i,0))-V.row(F(i,1))).array().pow(2).sum());
+      }
+      break;
+    }
+    case 4:
+    {
+      const int m = F.rows();
+      L.resize(m,6);
+      // loop over faces
+      for(int i = 0;i<m;i++)
+      {
+        L(i,0) = sqrt((V.row(F(i,3))-V.row(F(i,0))).array().pow(2).sum());
+        L(i,1) = sqrt((V.row(F(i,3))-V.row(F(i,1))).array().pow(2).sum());
+        L(i,2) = sqrt((V.row(F(i,3))-V.row(F(i,2))).array().pow(2).sum());
+        L(i,3) = sqrt((V.row(F(i,1))-V.row(F(i,2))).array().pow(2).sum());
+        L(i,4) = sqrt((V.row(F(i,2))-V.row(F(i,0))).array().pow(2).sum());
+        L(i,5) = sqrt((V.row(F(i,0))-V.row(F(i,1))).array().pow(2).sum());
+      }
+      break;
+    }
+    default:
+    {
+      cerr<< "edge_lengths.h: Error: Simplex size ("<<F.cols()<<
+        ") not supported"<<endl;
+      assert(false);
+    }
   }
 }
 
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
 // generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 2, 0, -1, 2>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 2, 0, -1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 2, 0, -1, 2> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
 template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
 template void igl::edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 8 - 3
include/igl/edge_lengths.h

@@ -14,7 +14,8 @@
 namespace igl
 {
   // Constructs a list of lengths of edges opposite each index in a face
-  // (triangle) list
+  // (triangle/tet) list
+  //
   // Templates:
   //   DerivedV derived from vertex positions matrix type: i.e. MatrixXd
   //   DerivedF derived from face indices matrix type: i.e. MatrixXi
@@ -22,10 +23,14 @@ namespace igl
   // Inputs:
   //   V  eigen matrix #V by 3
   //   F  #F by 3 list of mesh faces (must be triangles)
+  //    or
+  //   T  #T by 4 list of mesh elements (must be tets)
   // Outputs:
-  //   E #E by 2 list of edges in no particular order
+  //   L  #F by {3|6} list of edge lengths 
+  //     for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+  //     for tets, columns correspond to edges
+  //     [1,2],[2,0],[0,1],[3,0],[3,1],[3,2]
   //
-  // See also: adjacency_matrix
   template <typename DerivedV, typename DerivedF, typename DerivedL>
   IGL_INLINE void edge_lengths(
     const Eigen::PlainObjectBase<DerivedV>& V,

+ 0 - 222
include/igl/embree/orient_outward_ao.cpp

@@ -1,222 +0,0 @@
-// 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 "orient_outward_ao.h"
-#include "../per_face_normals.h"
-#include "../doublearea.h"
-#include "../random_dir.h"
-#include "EmbreeIntersector.h"
-#include <iostream>
-#include <random>
-#include <ctime>
-#include <limits>
-
-template <
-  typename DerivedV, 
-  typename DerivedF, 
-  typename DerivedC, 
-  typename DerivedFF, 
-  typename DerivedI>
-IGL_INLINE void igl::orient_outward_ao(
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedF> & F,
-  const Eigen::PlainObjectBase<DerivedC> & C,
-  const int min_num_rays_per_component,
-  const int total_num_rays,
-  Eigen::PlainObjectBase<DerivedFF> & FF,
-  Eigen::PlainObjectBase<DerivedI> & I)
-{
-  using namespace Eigen;
-  using namespace std;
-  assert(C.rows() == F.rows());
-  assert(F.cols() == 3);
-  assert(V.cols() == 3);
-  
-  EmbreeIntersector ei;
-  ei.init(V.template cast<float>(),F);
-  
-  // number of faces
-  const int m = F.rows();
-  // number of patches
-  const int num_cc = C.maxCoeff()+1;
-  I.resize(num_cc);
-  if(&FF != &F)
-  {
-    FF = F;
-  }
-  
-  // face normal
-  MatrixXd N;
-  per_face_normals(V,F,N);
-  
-  // face area
-  Matrix<typename DerivedV::Scalar,Dynamic,1> A;
-  doublearea(V,F,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_rays_per_component.setZero(num_cc);
-  for (int c = 0; c < num_cc; ++c)
-  {
-    num_rays_per_component(c) = max<int>(min_num_rays_per_component, static_cast<int>(total_num_rays * area_per_component(c) / area_total));
-  }
-  
-  // generate all the rays
-  //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(total_num_rays);
-  ray_ori .reserve(total_num_rays);
-  ray_dir .reserve(total_num_rays);
-  for (int c = 0; c < num_cc; ++c)
-  {
-    if (area_per_component[c] == 0)
-    {
-      continue;
-    }
-    vector<int> CF;     // set of faces per component
-    vector<int> CF_area;
-    for (int f = 0; f < m; ++f)
-    {
-      if (C(f)==c)
-      {
-        CF.push_back(f);
-        CF_area.push_back(static_cast<int>(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(F(f,0)).template cast<float>().eval()       // be careful with the index!!!
-                 + b * V.row(F(f,1)).template cast<float>().eval()
-                 + c * V.row(F(f,2)).template cast<float>().eval();
-      Vector3f n = N.row(f).cast<float>();
-      // 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);
-    }
-  }
-  
-  // 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
-  
-  //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 (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;
-    }
-  }
-  
-  for(int c = 0;c<num_cc;c++)
-  {
-    I(c) = (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;
-  }
-  // flip according to I
-  for(int f = 0;f<m;f++)
-  {
-    if(I(C(f)))
-    {
-      FF.row(f) = FF.row(f).reverse().eval();
-    }
-  }
-  //cout << "done!\n";
-}
-
-// Call with default parameters
-template <
-  typename DerivedV, 
-  typename DerivedF, 
-  typename DerivedC, 
-  typename DerivedFF, 
-  typename DerivedI>
-IGL_INLINE void igl::orient_outward_ao(
-  const Eigen::PlainObjectBase<DerivedV> & V,
-  const Eigen::PlainObjectBase<DerivedF> & F,
-  const Eigen::PlainObjectBase<DerivedC> & C,
-  Eigen::PlainObjectBase<DerivedFF> & FF,
-  Eigen::PlainObjectBase<DerivedI> & I)
-{
-  return orient_outward_ao(V, F, C, 100, F.rows() * 100, FF, I);
-}
-
-#ifndef IGL_HEADER_ONLY
-// Explicit template specialization
-template void igl::orient_outward_ao<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
-#endif

+ 0 - 61
include/igl/embree/orient_outward_ao.h

@@ -1,61 +0,0 @@
-// 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
-  //   C                            #F list of components
-  //   min_num_rays_per_component   Each component receives at least this number of rays
-  //   total_num_rays               Total number of rays that will be shot
-  // Outputs:
-  //   FF  #F by 3 list of new triangle indices such that FF(~I,:) = F(~I,:) and
-  //     FF(I,:) = fliplr(F(I,:)) (OK if &FF = &F)
-  //   I  max(C)+1 list of whether face has been flipped
-  template <
-    typename DerivedV, 
-    typename DerivedF, 
-    typename DerivedC, 
-    typename DerivedFF, 
-    typename DerivedI>
-  IGL_INLINE void orient_outward_ao(
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedF> & F,
-    const Eigen::PlainObjectBase<DerivedC> & C,
-    const int min_num_rays_per_component,
-    const int total_num_rays,
-    Eigen::PlainObjectBase<DerivedFF> & FF,
-    Eigen::PlainObjectBase<DerivedI> & I);
-  
-  // Call with default number of rays
-  template <
-    typename DerivedV, 
-    typename DerivedF, 
-    typename DerivedC, 
-    typename DerivedFF, 
-    typename DerivedI>
-  IGL_INLINE void orient_outward_ao(
-    const Eigen::PlainObjectBase<DerivedV> & V,
-    const Eigen::PlainObjectBase<DerivedF> & F,
-    const Eigen::PlainObjectBase<DerivedC> & C,
-    Eigen::PlainObjectBase<DerivedFF> & FF,
-    Eigen::PlainObjectBase<DerivedI> & I);
-};
-
-#ifdef IGL_HEADER_ONLY
-#  include "orient_outward_ao.cpp"
-#endif
-
-#endif

+ 22 - 24
include/igl/embree/reorient_facets_raycast.cpp

@@ -17,19 +17,21 @@
 #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)
+template <
+  typename DerivedV, 
+  typename DerivedF, 
+  typename DerivedI,
+  typename DerivedC>
+IGL_INLINE void igl::reorient_facets_raycast(
+  const Eigen::PlainObjectBase<DerivedV> & V,
+  const Eigen::PlainObjectBase<DerivedF> & F,
+  int rays_total,
+  int rays_minimum,
+  bool facet_wise,
+  bool use_parity,
+  bool is_verbose,
+  Eigen::PlainObjectBase<DerivedI> & I,
+  Eigen::PlainObjectBase<DerivedC> & C)
 {
   using namespace Eigen;
   using namespace std;
@@ -39,9 +41,8 @@
   // number of faces
   const int m = F.rows();
   
-  VectorXi C;
   MatrixXi FF = F;
-  if (face_wise) {
+  if (facet_wise) {
     C.resize(m);
     for (int i = 0; i < m; ++i) C(i) = i;
   
@@ -65,11 +66,6 @@
   // 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
@@ -104,18 +100,17 @@
       continue;
     }
     vector<int> CF;     // set of faces per component
-    vector<unsigned long long> CF_area;
+    vector<double> 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));
+        CF_area.push_back(A(f));
       }
     }
     // 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...
+    discrete_distribution<int> ddist(CF.size(), 0, CF.size(), [&](double i){ return CF_area[static_cast<int>(i)]; });       // simple ctor of (Iter, Iter) not provided by the stupid VC11/12
     for (int i = 0; i < num_rays_per_component[c]; ++i)
     {
       int f = CF[ddist(prng)];          // select face with probability proportional to face area
@@ -217,6 +212,9 @@
               C_vote_infinity[c].first <  C_vote_infinity[c].second
               ? 1 : 0;
     }
+    // To account for the effect of bfs_orient
+    if (F.row(f) != FF.row(f))
+      I(f) = 1 - I(f);
   }
   if (is_verbose) cout << "done!" << endl;
 }

+ 7 - 4
include/igl/embree/reorient_facets_raycast.h

@@ -19,24 +19,27 @@ namespace igl
   //   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)
+  //   faceg_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
+  //   C                            #F list of patch ID
   template <
     typename DerivedV, 
     typename DerivedF, 
-    typename DerivedI>
+    typename DerivedI,
+    typename DerivedC>
   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 facet_wise,
     bool use_parity,
     bool is_verbose,
-    Eigen::PlainObjectBase<DerivedI> & I);
+    Eigen::PlainObjectBase<DerivedI> & I,
+    Eigen::PlainObjectBase<DerivedC> & C);
 };
 
 #ifdef IGL_HEADER_ONLY

+ 48 - 0
include/igl/face_areas.cpp

@@ -0,0 +1,48 @@
+#include "face_areas.h"
+#include "edge_lengths.h"
+#include "doublearea.h"
+
+template <typename DerivedV, typename DerivedT, typename DerivedA>
+IGL_INLINE void igl::face_areas(
+  const Eigen::PlainObjectBase<DerivedV>& V,
+  const Eigen::PlainObjectBase<DerivedT>& T,
+  Eigen::PlainObjectBase<DerivedA>& A)
+{
+  assert(T.cols() == 4);
+  typename Eigen::PlainObjectBase<DerivedA> L;
+  edge_lengths(V,T,L);
+  return face_areas(L,A);
+}
+
+template <typename DerivedL, typename DerivedA>
+IGL_INLINE void igl::face_areas(
+  const Eigen::PlainObjectBase<DerivedL>& L,
+  Eigen::PlainObjectBase<DerivedA>& A)
+{
+  using namespace Eigen;
+  assert(L.cols() == 6);
+  const int m = L.rows();
+  // (unsigned) face Areas (opposite vertices: 1 2 3 4)
+  Matrix<typename DerivedA::Scalar,Dynamic,1> 
+    A0(m,1), A1(m,1), A2(m,1), A3(m,1);
+  Matrix<typename DerivedA::Scalar,Dynamic,3> 
+    L0(m,3), L1(m,3), L2(m,3), L3(m,3);
+  L0<<L.col(1),L.col(2),L.col(3);
+  L1<<L.col(0),L.col(2),L.col(4);
+  L2<<L.col(0),L.col(1),L.col(5);
+  L3<<L.col(3),L.col(4),L.col(5);
+  doublearea(L0,A0);
+  doublearea(L1,A1);
+  doublearea(L2,A2);
+  doublearea(L3,A3);
+  A.resize(m,4);
+  A.col(0) = 0.5*A0;
+  A.col(1) = 0.5*A1;
+  A.col(2) = 0.5*A2;
+  A.col(3) = 0.5*A3;
+}
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+// generated by autoexplicit.sh
+template void igl::face_areas<Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
+#endif

+ 46 - 0
include/igl/face_areas.h

@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FACE_AREAS_H
+#define IGL_FACE_AREAS_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+  // Constructs a list of face areas of faces opposite each index in a tet list
+  //
+  // Templates:
+  //   DerivedV derived from vertex positions matrix type: i.e. MatrixXd
+  //   DerivedT derived from face indices matrix type: i.e. MatrixXi
+  //   DerivedL derived from edge lengths matrix type: i.e. MatrixXd
+  // Inputs:
+  //   V  eigen matrix #V by 3
+  //   T  #T by 3 list of mesh faces (must be triangles)
+  // Outputs:
+  //   E #E by 2 list of edges in no particular order
+  //
+  // See also: adjacency_matrix
+  template <typename DerivedV, typename DerivedT, typename DerivedA>
+  IGL_INLINE void face_areas(
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedT>& T,
+    Eigen::PlainObjectBase<DerivedA>& A);
+  template <typename DerivedL, typename DerivedA>
+  IGL_INLINE void face_areas(
+    const Eigen::PlainObjectBase<DerivedL>& L,
+    Eigen::PlainObjectBase<DerivedA>& A);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "face_areas.cpp"
+#endif
+
+#endif
+
+

+ 143 - 0
include/igl/file_dialog.cpp

@@ -0,0 +1,143 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#define FILE_DIALOG_MAX_BUFFER 1024
+
+std::string IGL_INLINE igl::file_dialog_open()
+{
+  char buffer[FILE_DIALOG_MAX_BUFFER];
+  
+#ifdef __APPLE__
+  // For apple use applescript hack
+  FILE * output = popen(
+                        "osascript -e \""
+                        "   tell application \\\"System Events\\\"\n"
+                        "           activate\n"
+                        "           set existing_file to choose file\n"
+                        "   end tell\n"
+                        "   set existing_file_path to (POSIX path of (existing_file))\n"
+                        "\" 2>/dev/null | tr -d '\n' ","r");
+  while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL ){
+  }
+#elif _WIN32
+  
+  // Use native windows file dialog box
+  // (code contributed by Tino Weinkauf)
+
+  OPENFILENAME ofn;       // common dialog box structure
+  char szFile[260];       // buffer for file name
+  HWND hwnd;              // owner window
+  HANDLE hf;              // file handle
+
+  // Initialize OPENFILENAME
+  ZeroMemory(&ofn, sizeof(ofn));
+  ofn.lStructSize = sizeof(ofn);
+  ofn.hwndOwner = NULL;//hwnd;
+  ofn.lpstrFile = new wchar_t[100];
+  // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
+  // use the contents of szFile to initialize itself.
+  ofn.lpstrFile[0] = '\0';
+  ofn.nMaxFile = sizeof(szFile);
+  ofn.lpstrFilter = L"*.*\0";//off\0*.off\0obj\0*.obj\0mp\0*.mp\0";
+  ofn.nFilterIndex = 1;
+  ofn.lpstrFileTitle = NULL;
+  ofn.nMaxFileTitle = 0;
+  ofn.lpstrInitialDir = NULL;
+  ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+
+  // Display the Open dialog box. 
+  int pos = 0;
+  if (GetOpenFileName(&ofn)==TRUE)
+  {
+    while(ofn.lpstrFile[pos] != '\0')
+    {
+      buffer[pos] = (char)ofn.lpstrFile[pos];
+      pos++;
+    }
+    buffer[pos] = 0;
+  } 
+  
+#else
+  
+  // For linux use zenity
+  FILE * output = popen("/usr/bin/zenity --file-selection","r");
+  while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL ){
+  }
+  
+  if (strlen(buffer) > 0)
+    buffer[strlen(buffer)-1] = 0;
+#endif
+  return std::string(buffer);
+}
+
+std::string IGL_INLINE igl::file_dialog_save()
+{
+  char buffer[FILE_DIALOG_MAX_BUFFER];
+#ifdef __APPLE__
+  // For apple use applescript hack
+  // There is currently a bug in Applescript that strips extensions off
+  // of chosen existing files in the "choose file name" dialog
+  // I'm assuming that will be fixed soon
+  FILE * output = popen(
+                        "osascript -e \""
+                        "   tell application \\\"System Events\\\"\n"
+                        "           activate\n"
+                        "           set existing_file to choose file name\n"
+                        "   end tell\n"
+                        "   set existing_file_path to (POSIX path of (existing_file))\n"
+                        "\" 2>/dev/null | tr -d '\n' ","r");
+  while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL ){
+  }
+#elif _WIN32
+
+  // Use native windows file dialog box
+  // (code contributed by Tino Weinkauf)
+
+  OPENFILENAME ofn;       // common dialog box structure
+  char szFile[260];       // buffer for file name
+  HWND hwnd;              // owner window
+  HANDLE hf;              // file handle
+
+  // Initialize OPENFILENAME
+  ZeroMemory(&ofn, sizeof(ofn));
+  ofn.lStructSize = sizeof(ofn);
+  ofn.hwndOwner = NULL;//hwnd;
+  ofn.lpstrFile = new wchar_t[100];
+  // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
+  // use the contents of szFile to initialize itself.
+  ofn.lpstrFile[0] = '\0';
+  ofn.nMaxFile = sizeof(szFile);
+  ofn.lpstrFilter = L"";
+  ofn.nFilterIndex = 1;
+  ofn.lpstrFileTitle = NULL;
+  ofn.nMaxFileTitle = 0;
+  ofn.lpstrInitialDir = NULL;
+  ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+
+  // Display the Open dialog box. 
+  int pos = 0;
+  if (GetSaveFileName(&ofn)==TRUE)
+  {
+    while(ofn.lpstrFile[pos] != '\0')
+    {
+      buffer[pos] = (char)ofn.lpstrFile[pos];
+      pos++;
+    }
+    buffer[pos] = 0;
+  }
+
+#else
+  // For every other machine type use zenity
+  FILE * output = popen("/usr/bin/zenity --file-selection --save","r");
+  while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL ){
+  }
+  
+  if (strlen(buffer) > 0)
+    buffer[strlen(buffer)-1] = 0;
+#endif
+}

+ 44 - 0
include/igl/file_dialog.h

@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FILE_DIALOG_H
+#define IGL_FILE_DIALOG_H
+
+#include <stdio.h>
+#include <string>
+
+#ifdef _WIN32
+ #include <Commdlg.h>
+#endif
+
+namespace igl
+{
+
+// Returns a string with a path to an existing file
+// The string is returned empty if no file is selected
+// (on Linux machines, it assumes that Zenity is installed)
+//
+// Usage:
+//   std::string str = get_open_file_path();
+std::string IGL_INLINE file_dialog_open();
+
+// Returns a string with a path to a new/existing file
+// The string is returned empty if no file is selected
+// (on Linux machines, it assumes that Zenity is installed)
+//
+// Usage:
+//   char buffer[FILE_DIALOG_MAX_BUFFER];
+//   get_save_file_path(buffer);
+std::string IGL_INLINE file_dialog_save();
+
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "file_dialog.cpp"
+#endif
+
+#endif

+ 99 - 98
include/igl/gradMat.cpp

@@ -5,101 +5,102 @@
 // 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 "gradMat.h"
-#include <vector>
-
-template <typename T, typename S>
-IGL_INLINE void igl::gradMat(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
-  const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> &F,
-  Eigen::SparseMatrix<T> &G )
-{
-  Eigen::PlainObjectBase<Eigen::Matrix<T,Eigen::Dynamic,3> > eperp21, eperp13;
-  eperp21.resize(F.rows(),3);
-  eperp13.resize(F.rows(),3);
-
-  for (int i=0;i<F.rows();++i)
-  {
-    // renaming indices of vertices of triangles for convenience
-    int i1 = F(i,0);
-    int i2 = F(i,1);
-    int i3 = F(i,2);
-    
-    // #F x 3 matrices of triangle edge vectors, named after opposite vertices
-    Eigen::Matrix<T, 1, 3> v32 = V.row(i3) - V.row(i2);
-    Eigen::Matrix<T, 1, 3> v13 = V.row(i1) - V.row(i3);
-    Eigen::Matrix<T, 1, 3> v21 = V.row(i2) - V.row(i1);
-    
-    // area of parallelogram is twice area of triangle
-    // area of parallelogram is || v1 x v2 || 
-    Eigen::Matrix<T, 1, 3> n  = v32.cross(v13); 
-    
-    // This does correct l2 norm of rows, so that it contains #F list of twice
-    // triangle areas
-    double dblA = std::sqrt(n.dot(n));
-    
-    // now normalize normals to get unit normals
-    Eigen::Matrix<T, 1, 3> u = n / dblA;
-    
-    // rotate each vector 90 degrees around normal
-    double norm21 = std::sqrt(v21.dot(v21));
-    double norm13 = std::sqrt(v13.dot(v13));
-    eperp21.row(i) = u.cross(v21);
-    eperp21.row(i) = eperp21.row(i) / std::sqrt(eperp21.row(i).dot(eperp21.row(i)));
-    eperp21.row(i) *= norm21 / dblA;
-    eperp13.row(i) = u.cross(v13);
-    eperp13.row(i) = eperp13.row(i) / std::sqrt(eperp13.row(i).dot(eperp13.row(i)));
-    eperp13.row(i) *= norm13 / dblA;
-  }
-
-  std::vector<int> rs;
-  rs.reserve(F.rows()*4*3);
-  std::vector<int> cs;
-  cs.reserve(F.rows()*4*3);
-  std::vector<double> vs;
-  vs.reserve(F.rows()*4*3);
-
-  // row indices
-  for(int r=0;r<3;r++)
-  {
-    for(int j=0;j<4;j++)
-    {
-      for(int i=r*F.rows();i<(r+1)*F.rows();i++) rs.push_back(i);
-    }
-  }
-
-  // column indices
-  for(int r=0;r<3;r++)
-  {
-    for(int i=0;i<F.rows();i++) cs.push_back(F(i,1));
-    for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
-    for(int i=0;i<F.rows();i++) cs.push_back(F(i,2));
-    for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
-  }
-  
-  // values
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,0));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,0));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,0));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,0));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,1));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,1));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,1));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,1));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,2));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,2));
-  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,2));
-  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,2));
-
-  // create sparse gradient operator matrix
-  G.resize(3*F.rows(),V.rows()); 
-  std::vector<Eigen::Triplet<T> > triplets;
-  for (int i=0;i<vs.size();++i)
-  {
-    triplets.push_back(Eigen::Triplet<T>(rs[i],cs[i],vs[i]));
-  }
-  G.setFromTriplets(triplets.begin(), triplets.end());
-}
-
-#ifndef IGL_HEADER_ONLY
-// Explicit template specialization
-#endif
+#include "gradMat.h"
+#include <vector>
+
+template <typename T, typename S>
+IGL_INLINE void igl::gradMat(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
+  const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> &F,
+  Eigen::SparseMatrix<T> &G )
+{
+  Eigen::PlainObjectBase<Eigen::Matrix<T,Eigen::Dynamic,3> > eperp21, eperp13;
+  eperp21.resize(F.rows(),3);
+  eperp13.resize(F.rows(),3);
+
+  for (int i=0;i<F.rows();++i)
+  {
+    // renaming indices of vertices of triangles for convenience
+    int i1 = F(i,0);
+    int i2 = F(i,1);
+    int i3 = F(i,2);
+    
+    // #F x 3 matrices of triangle edge vectors, named after opposite vertices
+    Eigen::Matrix<T, 1, 3> v32 = V.row(i3) - V.row(i2);
+    Eigen::Matrix<T, 1, 3> v13 = V.row(i1) - V.row(i3);
+    Eigen::Matrix<T, 1, 3> v21 = V.row(i2) - V.row(i1);
+    
+    // area of parallelogram is twice area of triangle
+    // area of parallelogram is || v1 x v2 || 
+    Eigen::Matrix<T, 1, 3> n  = v32.cross(v13); 
+    
+    // This does correct l2 norm of rows, so that it contains #F list of twice
+    // triangle areas
+    double dblA = std::sqrt(n.dot(n));
+    
+    // now normalize normals to get unit normals
+    Eigen::Matrix<T, 1, 3> u = n / dblA;
+    
+    // rotate each vector 90 degrees around normal
+    double norm21 = std::sqrt(v21.dot(v21));
+    double norm13 = std::sqrt(v13.dot(v13));
+    eperp21.row(i) = u.cross(v21);
+    eperp21.row(i) = eperp21.row(i) / std::sqrt(eperp21.row(i).dot(eperp21.row(i)));
+    eperp21.row(i) *= norm21 / dblA;
+    eperp13.row(i) = u.cross(v13);
+    eperp13.row(i) = eperp13.row(i) / std::sqrt(eperp13.row(i).dot(eperp13.row(i)));
+    eperp13.row(i) *= norm13 / dblA;
+  }
+
+  std::vector<int> rs;
+  rs.reserve(F.rows()*4*3);
+  std::vector<int> cs;
+  cs.reserve(F.rows()*4*3);
+  std::vector<double> vs;
+  vs.reserve(F.rows()*4*3);
+
+  // row indices
+  for(int r=0;r<3;r++)
+  {
+    for(int j=0;j<4;j++)
+    {
+      for(int i=r*F.rows();i<(r+1)*F.rows();i++) rs.push_back(i);
+    }
+  }
+
+  // column indices
+  for(int r=0;r<3;r++)
+  {
+    for(int i=0;i<F.rows();i++) cs.push_back(F(i,1));
+    for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
+    for(int i=0;i<F.rows();i++) cs.push_back(F(i,2));
+    for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
+  }
+  
+  // values
+  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,0));
+  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,0));
+  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,0));
+  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,0));
+  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,1));
+  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,1));
+  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,1));
+  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,1));
+  for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,2));
+  for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,2));
+  for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,2));
+  for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,2));
+
+  // create sparse gradient operator matrix
+  G.resize(3*F.rows(),V.rows()); 
+  std::vector<Eigen::Triplet<T> > triplets;
+  for (int i=0;i<vs.size();++i)
+  {
+    triplets.push_back(Eigen::Triplet<T>(rs[i],cs[i],vs[i]));
+  }
+  G.setFromTriplets(triplets.begin(), triplets.end());
+}
+
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+#endif
+

+ 50 - 22
include/igl/pos.h

@@ -5,6 +5,7 @@
 // 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_POS_H
 #define IGL_POS_H
 
@@ -29,30 +30,13 @@ template <typename S>
         )
     : F(F), FF(FF), FFi(FFi), fi(fi), ei(ei), reverse(reverse)
     {}
-
-//    // Init the pos by specifying Face,Vertex Index and Orientation
-//    Pos(Eigen::MatrixXi& F, 
-//        Eigen::MatrixXi& FF, 
-//        Eigen::MatrixXi& FFi, 
-//        int fi,
-//        int vi,
-//        bool reverse = false
-//        )
-//    : F(F), FF(FF), FFi(FFi), fi(fi), reverse(reverse)
-//    {
-//      ei = -1;
-//      for (int i=0;i<3;++i)
-//        if (F(fi,i) == vi)
-//          ei = i;
-//      assert(ei != -1);
-//      
-//      if (reverse)
-//        ei = (ei-1)%3;
-//    }
     
     // Change Face
     void flipF()
     {
+      if (isBorder())
+        return;
+      
       int fin = (*FF)(fi,ei);
       int ein = (*FFi)(fi,ei);
       int reversen = !reverse;
@@ -79,6 +63,42 @@ template <typename S>
       reverse = !reverse;
     }
     
+    bool isBorder()
+    {
+      return (*FF)(fi,ei) == -1;
+    }
+    
+    /*!
+     * Returns the next edge skipping the border
+     *      _________
+     *     /\ c | b /\
+     *    /  \  |  /  \
+     *   / d  \ | / a  \
+     *  /______\|/______\
+     *          v
+     * In this example, if a and d are of-border and the pos is iterating counterclockwise, this method iterate through the faces incident on vertex v,
+     * producing the sequence a, b, c, d, a, b, c, ...
+     */
+    bool NextFE()
+    {
+      if ( isBorder() ) // we are on a border
+      {
+        do
+        {
+					flipF();
+					flipE();
+        } while (!isBorder());
+        flipE();
+        return false;
+      }
+      else
+      {
+        flipF();
+        flipE();
+        return true;
+      }
+    }
+    
     // Get vertex index
     int Vi()
     {
@@ -98,6 +118,13 @@ template <typename S>
     {
       return fi;
     }
+
+    // Get edge index
+    int Ei()
+    {
+      return ei;
+    }
+
     
     bool operator==(Pos& p2)
     {
@@ -112,13 +139,14 @@ template <typename S>
        );
     }
     
+  private:
     int fi;
     int ei;
     bool reverse;
     
     const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic>*     F;
-    Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic>*     FF;
-    Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic>*     FFi;
+    const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic>*     FF;
+    const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic>*     FFi;
   };
   
 }

+ 2 - 2
include/igl/readOFF.cpp

@@ -58,9 +58,9 @@ IGL_INLINE bool igl::readOFF(
   // Read vertices
   for(int i = 0;i<number_of_vertices;)
   {
+    fgets(line, 1000, off_file);
     double x,y,z,nx,ny,nz;
-    if((has_normals && fscanf(off_file, "%lg %lg %lg %lg %lg %lg\n",&x,&y,&z,&nx,&ny,&nz)==6) || 
-       (!has_normals && fscanf(off_file, "%lg %lg %lg\n",&x,&y,&z)==3))
+    if(sscanf(line, "%lg %lg %lg %lg %lg %lg",&x,&y,&z,&nx,&ny,&nz)>= 3)
     {
       std::vector<Scalar > vertex;
       vertex.resize(3);

+ 7 - 0
include/igl/sort.cpp

@@ -213,6 +213,12 @@ IGL_INLINE void igl::sort(
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
 // generated by autoexplicit.sh
+template void igl::sort<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::sort<Eigen::Matrix<float, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::sort<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
 template void igl::sort<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::sort<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::sort<SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> > >(std::vector<SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> >, std::allocator<SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> > > > const&, bool, std::vector<SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> >, std::allocator<SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> > > >&, std::vector<unsigned long, std::allocator<unsigned long> >&);
@@ -225,4 +231,5 @@ template void igl::sort<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<in
 template void igl::sort<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::sort<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::sort<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::sort<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 9 - 2
include/igl/vf.h

@@ -14,14 +14,21 @@
 
 namespace igl 
 {
-  // Constructs the vertex-face topology of a given mesh (V,F)
+  // TODO: This function is badly named.
+  //
+  // VF Constructs the vertex-face topology of a given mesh (V,F)
+  //
   // Inputs:
   //   V  #V by 3 list of vertex coordinates
   //   F  #F by dim list of mesh faces (must be triangles)
   // Outputs: 
-  // 
+  //   VF  #V list of lists of incident faces (adjacency list)
+  //   VI  #V list of lists of index of incidence within incident faces listed
+  //     in VF
   //
   // See also: edges, cotmatrix, diag, vv
+  //
+  // Known bugs: this should not take V as an input parameter.
     
   template <typename DerivedV, typename DerivedF, typename IndexType>
   IGL_INLINE void vf(

+ 72 - 0
include/igl/volume.cpp

@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "volume.h"
+template <
+  typename DerivedV, 
+  typename DerivedT, 
+  typename Derivedvol>
+IGL_INLINE void igl::volume(
+  Eigen::PlainObjectBase<DerivedV>& V,
+  Eigen::PlainObjectBase<DerivedT>& T,
+  Eigen::PlainObjectBase<Derivedvol>& vol)
+{
+  using namespace Eigen;
+  const int m = T.rows();
+  vol.resize(m,1);
+  for(int t = 0;t<m;t++)
+  {
+    const auto & a = V.row(T(t,0));
+    const auto & b = V.row(T(t,1));
+    const auto & c = V.row(T(t,2));
+    const auto & d = V.row(T(t,3));
+    vol(t) = -(a-d).dot((b-d).cross(c-d))/6.;
+  }
+}
+
+template <
+  typename DerivedL, 
+  typename Derivedvol>
+IGL_INLINE void igl::volume(
+  Eigen::PlainObjectBase<DerivedL>& L,
+  Eigen::PlainObjectBase<Derivedvol>& vol)
+{
+  using namespace Eigen;
+  const int m = L.rows();
+  typedef typename Derivedvol::Scalar ScalarS;
+  vol.resize(m,1);
+  for(int t = 0;t<m;t++)
+  {
+    const ScalarS u = L(t,0);
+    const ScalarS v = L(t,1);
+    const ScalarS w = L(t,2);
+    const ScalarS U = L(t,3);
+    const ScalarS V = L(t,4);
+    const ScalarS W = L(t,5);
+    const ScalarS X = (w - U + v)*(U + v + w);
+    const ScalarS x = (U - v + w)*(v - w + U);
+    const ScalarS Y = (u - V + w)*(V + w + u);
+    const ScalarS y = (V - w + u)*(w - u + V);
+    const ScalarS Z = (v - W + u)*(W + u + v);
+    const ScalarS z = (W - u + v)*(u - v + W);
+    const ScalarS a = sqrt(x*Y*Z); 
+    const ScalarS b = sqrt(y*Z*X); 
+    const ScalarS c = sqrt(z*X*Y); 
+    const ScalarS d = sqrt(x*y*z); 
+    vol(t) = sqrt(
+       (-a + b + c + d)*
+       ( a - b + c + d)*
+       ( a + b - c + d)*
+       ( a + b + c - d))/
+       (192.*u*v*w);
+  }
+}
+#ifndef IGL_HEADER_ONLY
+// Explicit template specialization
+// generated by autoexplicit.sh
+template void igl::volume<Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif

+ 51 - 0
include/igl/volume.h

@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+// 
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public License 
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VOLUME_H
+#define IGL_VOLUME_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+  // VOLUME Compute volume for all tets of a given tet mesh
+  // (V,T)
+  //
+  // vol = volume(V,T)
+  //
+  // Inputs:
+  //   V  #V by dim list of vertex positions
+  //   T  #V by 4 list of tet indices
+  // Outputs:
+  //   vol  #T list of dihedral angles (in radians)
+  //
+  template <
+    typename DerivedV, 
+    typename DerivedT, 
+    typename Derivedvol>
+  IGL_INLINE void volume(
+    Eigen::PlainObjectBase<DerivedV>& V,
+    Eigen::PlainObjectBase<DerivedT>& T,
+    Eigen::PlainObjectBase<Derivedvol>& vol);
+  // Intrinsic version:
+  //
+  // Inputs:
+  //   L  #V by 6 list of edge lengths (see edge_lengths)
+  template <
+    typename DerivedL, 
+    typename Derivedvol>
+  IGL_INLINE void volume(
+    Eigen::PlainObjectBase<DerivedL>& L,
+    Eigen::PlainObjectBase<Derivedvol>& vol);
+}
+
+#ifdef IGL_HEADER_ONLY
+#  include "volume.cpp"
+#endif
+
+#endif
+
+

+ 6 - 5
todos.txt

@@ -1,10 +1,9 @@
+- sort out `grad.*` vs `gradMat.*`
 - clean up externals
   - What's there for convenience?
   - What's there because it's patched/
 - compile on Linux, Mac OS X, Windows
 - unit tests for all functions
-- standardize name of library "libigl", purge IGL LIB, igl_lib, igl lib, IGL
-    Library, etc.
 - clean up examples
 - standardize use of string/char *, add to style conventions
 - standardize Eigen Templates, add to style conventions
@@ -19,13 +18,13 @@
 - fix bugs in examples/Core/example2.cpp
 - replace generic names read.h/write.h with something like read_poly_mesh.h
 - replace DynamicSparseMatrix: coeffRef += ---> setFromTriplets()
-- create libigltga extra
+- create libigltga extra...why? license?
 - rename moveFV.h
 - is_border_vertex.h should not require V
 - consistent checks/asserts for: manifoldness, closedness, triangles-only
-    e.g. check_mesh(V,F,MANIFOLD | CLOSED | TRIANGLES_ONLY)
+    e.g. check_mesh(V,F,IS_MANIFOLD | IS_CLOSED | IS_TRIANGLES_ONLY)
 - clean up Timer.h
-- svd.* depends on lapack, should use eigen...
+x svd.* depends on lapack, should use eigen...
 - use preprocessor macros to automatically include .cpp files at end of .h
 - unify include opengl with convenience includes
 - MatrixBase --> PlainObjectBase
@@ -33,3 +32,5 @@
 - everywhere appropriate change:
   `#pragma omp parallel for` to `#pragma omp parallel for if (n>10000)` where
   `n` and `1000` are replaced accordingly
++ standardize name of library "libigl", purge IGL LIB, igl_lib, igl lib, IGL
+    Library, etc.