diff --git a/external/AntTweakBar/src/Makefile.osx.igl b/external/AntTweakBar/src/Makefile.osx.igl index 809cc77a6..2747a600d 100755 --- a/external/AntTweakBar/src/Makefile.osx.igl +++ b/external/AntTweakBar/src/Makefile.osx.igl @@ -13,12 +13,16 @@ OUT_DIR = ../lib #OUT_DIR = ../lib/debug #BASE = /Developer/SDKs/MacOSX10.5.sdk/System/Library/Frameworks +ifndef CXX CXX = gcc +endif #CXXFLAGS = $(CXXCFG) -Wall -fPIC -fno-strict-aliasing -D_MACOSX -ObjC++ -D__PLACEMENT_NEW_INLINE CXXFLAGS = $(CXXCFG) -Wall -fPIC -fno-strict-aliasing -D_MACOSX -x objective-c++ -D__PLACEMENT_NEW_INLINE INCPATH = -I../include -I/usr/local/include -I/usr/X11R6/include -I/usr/include #-I$(BASE)/OpenGL.framework/Headers/ -I$(BASE)/GLUT.framework/Headers/ -I$(BASE)/AppKit.framework/Headers/ +ifndef LINK LINK = gcc +endif #LIBS = -L/usr/X11R6/lib -L. -lglfw -lGL -lGLU -lX11 -lXxf86vm -lXext -lpthread -lm #LIBS = -L/usr/X11R6/lib -lGL -lX11 -lXxf86vm -lXext -lpthread -lm LIBS = -framework OpenGL -framework GLUT -framework AppKit @@ -40,7 +44,9 @@ NO_STDERR = 2> /dev/null # name of the application: +ifndef TARGET TARGET = AntTweakBar +endif # source files without extension: SRC_FILES = TwColors.cpp TwFonts.cpp TwOpenGL.cpp TwOpenGLCore.cpp TwBar.cpp TwMgr.cpp LoadOGL.cpp LoadOGLCore.cpp TwEventGLFW.c TwEventGLUT.c TwEventSDL.c TwEventSDL12.c TwEventSDL13.c TwEventSFML.cpp diff --git a/include/igl/boolean/MeshBooleanType.h b/include/igl/boolean/MeshBooleanType.h index e12ce6542..035bbfa47 100644 --- a/include/igl/boolean/MeshBooleanType.h +++ b/include/igl/boolean/MeshBooleanType.h @@ -1,14 +1,17 @@ #ifndef MESH_BOOLEAN_TYPE_H #define MESH_BOOLEAN_TYPE_H -enum MeshBooleanType +namespace igl { - MESH_BOOLEAN_TYPE_UNION = 0, - MESH_BOOLEAN_TYPE_INTERSECT = 1, - MESH_BOOLEAN_TYPE_MINUS = 2, - MESH_BOOLEAN_TYPE_XOR = 3, - MESH_BOOLEAN_TYPE_RESOLVE = 4, - NUM_MESH_BOOLEAN_TYPES = 5 + enum MeshBooleanType + { + MESH_BOOLEAN_TYPE_UNION = 0, + MESH_BOOLEAN_TYPE_INTERSECT = 1, + MESH_BOOLEAN_TYPE_MINUS = 2, + MESH_BOOLEAN_TYPE_XOR = 3, + MESH_BOOLEAN_TYPE_RESOLVE = 4, + NUM_MESH_BOOLEAN_TYPES = 5 + }; }; #endif diff --git a/include/igl/boolean/from_cork_mesh.cpp b/include/igl/boolean/from_cork_mesh.cpp index 674173e70..7c15262cf 100644 --- a/include/igl/boolean/from_cork_mesh.cpp +++ b/include/igl/boolean/from_cork_mesh.cpp @@ -31,6 +31,7 @@ IGL_INLINE void igl::from_cork_mesh( #ifdef IGL_STATIC_LIBRARY // Explicit template specialization template void igl::from_cork_mesh, Eigen::Matrix >(CorkTriMesh const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::from_cork_mesh, Eigen::Matrix >(CorkTriMesh const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif #endif diff --git a/include/igl/boolean/mesh_boolean.cpp b/include/igl/boolean/mesh_boolean.cpp index 9cb69ad5f..6ba4308b4 100644 --- a/include/igl/boolean/mesh_boolean.cpp +++ b/include/igl/boolean/mesh_boolean.cpp @@ -11,7 +11,8 @@ template < typename DerivedVB, typename DerivedFB, typename DerivedVC, - typename DerivedFC> + typename DerivedFC, + typename DerivedJ> IGL_INLINE void igl::mesh_boolean( const Eigen::PlainObjectBase & VA, const Eigen::PlainObjectBase & FA, @@ -19,15 +20,17 @@ IGL_INLINE void igl::mesh_boolean( const Eigen::PlainObjectBase & FB, const MeshBooleanType & type, Eigen::PlainObjectBase & VC, - Eigen::PlainObjectBase & FC) + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) { const std::function &, const Eigen::Matrix&, Eigen::Matrix &, - Eigen::Matrix&)> + Eigen::Matrix&, + Eigen::Matrix&)> empty_fun; - return mesh_boolean(VA,FA,VB,FB,type,empty_fun,VC,FC); + return mesh_boolean(VA,FA,VB,FB,type,empty_fun,VC,FC,J); } template < @@ -37,6 +40,34 @@ template < typename DerivedFB, typename DerivedVC, typename DerivedFC> +IGL_INLINE void igl::mesh_boolean( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC) +{ + Eigen::Matrix J; + const std::function &, + const Eigen::Matrix&, + Eigen::Matrix &, + Eigen::Matrix&, + Eigen::Matrix&)> + empty_fun; + return mesh_boolean(VA,FA,VB,FB,type,empty_fun,VC,FC,J); +} + +template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> IGL_INLINE void igl::mesh_boolean( const Eigen::PlainObjectBase & VA, const Eigen::PlainObjectBase & FA, @@ -47,10 +78,12 @@ IGL_INLINE void igl::mesh_boolean( const Eigen::Matrix&, const Eigen::Matrix&, Eigen::Matrix&, - Eigen::Matrix&)> + Eigen::Matrix&, + Eigen::Matrix&)> & resolve_fun, Eigen::PlainObjectBase & VC, - Eigen::PlainObjectBase & FC) + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J) { using namespace Eigen; using namespace std; @@ -63,6 +96,7 @@ IGL_INLINE void igl::mesh_boolean( typedef Matrix MatrixX3I; typedef Matrix MatrixX2I; typedef Matrix VectorXI; + typedef Matrix VectorXJ; MatrixX3S V(VA.rows()+VB.rows(),3); MatrixX3I F(FA.rows()+FB.rows(),3); V.block(0,0,VA.rows(),VA.cols()) = VA; @@ -89,14 +123,15 @@ IGL_INLINE void igl::mesh_boolean( const MatrixX3S & V, const MatrixX3I & F, MatrixX3S & CV, - MatrixX3I & CF) + MatrixX3I & CF, + VectorXJ & J) { MatrixX3S SV; MatrixX3I SF; MatrixX2I SIF; - VectorXI SJ,SIM,UIM; + VectorXI SIM,UIM; RemeshSelfIntersectionsParam params; - remesh_self_intersections(V,F,params,SV,SF,SIF,SJ,SIM); + remesh_self_intersections(V,F,params,SV,SF,SIF,J,SIM); for_each(SF.data(),SF.data()+SF.size(),[&SIM](int & a){a=SIM(a);}); { remove_unreferenced(SV,SF,CV,CF,UIM); @@ -105,18 +140,20 @@ IGL_INLINE void igl::mesh_boolean( MatrixX3S CV; MatrixX3I CF; + VectorXJ CJ; if(resolve_fun) { - resolve_fun(V,F,CV,CF); + resolve_fun(V,F,CV,CF,CJ); }else { - libigl_resolve(V,F,CV,CF); + libigl_resolve(V,F,CV,CF,CJ); } if(type == MESH_BOOLEAN_TYPE_RESOLVE) { FC = CF; VC = CV; + J = CJ; return; } @@ -152,7 +189,7 @@ IGL_INLINE void igl::mesh_boolean( if((!odd(f) && !flip(f)) || (odd(f) && flip(f))) { vG.push_back(f); - Gflip.push_back(false); + Gflip.push_back(type == MESH_BOOLEAN_TYPE_MINUS); } break; default: @@ -162,14 +199,23 @@ IGL_INLINE void igl::mesh_boolean( } const Index gm = vG.size(); MatrixX3I G(gm,3); + VectorXi GJ(gm,1); for(Index g = 0;g, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::mesh_boolean, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif diff --git a/include/igl/boolean/mesh_boolean.h b/include/igl/boolean/mesh_boolean.h index 096507bb3..464ab12b7 100644 --- a/include/igl/boolean/mesh_boolean.h +++ b/include/igl/boolean/mesh_boolean.h @@ -19,9 +19,27 @@ namespace igl // Outputs: // W #W by 3 list of vertex positions of boolean result mesh // H #H by 3 list of triangle indices into W + // J #H list of indices into [FA;FB] revealing "birth" facet // // See also: self_intersect // + template < + typename DerivedVA, + typename DerivedFA, + typename DerivedVB, + typename DerivedFB, + typename DerivedVC, + typename DerivedFC, + typename DerivedJ> + IGL_INLINE void mesh_boolean( + const Eigen::PlainObjectBase & VA, + const Eigen::PlainObjectBase & FA, + const Eigen::PlainObjectBase & VB, + const Eigen::PlainObjectBase & FB, + const MeshBooleanType & type, + Eigen::PlainObjectBase & VC, + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); template < typename DerivedVA, typename DerivedFA, @@ -46,7 +64,8 @@ namespace igl typename DerivedVB, typename DerivedFB, typename DerivedVC, - typename DerivedFC> + typename DerivedFC, + typename DerivedJ> IGL_INLINE void mesh_boolean( const Eigen::PlainObjectBase & VA, const Eigen::PlainObjectBase & FA, @@ -55,12 +74,14 @@ namespace igl const MeshBooleanType & type, const std::function &, - const Eigen::Matrix &, + const Eigen::Matrix &, Eigen::Matrix &, - Eigen::Matrix &)> + Eigen::Matrix &, + Eigen::Matrix&)> & resolve_fun, Eigen::PlainObjectBase & VC, - Eigen::PlainObjectBase & FC); + Eigen::PlainObjectBase & FC, + Eigen::PlainObjectBase & J); } #ifndef IGL_STATIC_LIBRARY diff --git a/include/igl/boolean/mesh_boolean_cork.cpp b/include/igl/boolean/mesh_boolean_cork.cpp index b82a1d7a9..65f2f7844 100644 --- a/include/igl/boolean/mesh_boolean_cork.cpp +++ b/include/igl/boolean/mesh_boolean_cork.cpp @@ -88,6 +88,7 @@ IGL_INLINE void igl::mesh_boolean_cork( #ifdef IGL_STATIC_LIBRARY // Explicit template specialization template void igl::mesh_boolean_cork, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::mesh_boolean_cork, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif #endif diff --git a/include/igl/boolean/to_cork_mesh.cpp b/include/igl/boolean/to_cork_mesh.cpp index 7aba7f44c..c30997eb4 100644 --- a/include/igl/boolean/to_cork_mesh.cpp +++ b/include/igl/boolean/to_cork_mesh.cpp @@ -33,5 +33,6 @@ IGL_INLINE void igl::to_cork_mesh( #ifdef IGL_STATIC_LIBRARY // Explicit template specialization template void igl::to_cork_mesh, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CorkTriMesh&); +template void igl::to_cork_mesh, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, CorkTriMesh&); #endif #endif diff --git a/include/igl/cgal/remesh_self_intersections.cpp b/include/igl/cgal/remesh_self_intersections.cpp index 80f6c5c37..57d9278f9 100644 --- a/include/igl/cgal/remesh_self_intersections.cpp +++ b/include/igl/cgal/remesh_self_intersections.cpp @@ -84,4 +84,5 @@ IGL_INLINE void igl::remesh_self_intersections( // Explicit template specialization template void igl::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); template void igl::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); +template void igl::remesh_self_intersections, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif diff --git a/include/igl/matlab/mexStream.h b/include/igl/matlab/mexStream.h index 242184f36..079fb5f61 100644 --- a/include/igl/matlab/mexStream.h +++ b/include/igl/matlab/mexStream.h @@ -32,6 +32,7 @@ namespace igl } // Implementation +#include inline std::streamsize igl::MexStream::xsputn( const char *s, std::streamsize n) diff --git a/include/igl/matlab/prepare_lhs.cpp b/include/igl/matlab/prepare_lhs.cpp index 2d46e423a..cfa455909 100644 --- a/include/igl/matlab/prepare_lhs.cpp +++ b/include/igl/matlab/prepare_lhs.cpp @@ -37,4 +37,5 @@ IGL_INLINE void igl::prepare_lhs_index( template void igl::prepare_lhs_index >(Eigen::PlainObjectBase > const&, mxArray_tag**); template void igl::prepare_lhs_index >(Eigen::PlainObjectBase > const&, mxArray_tag**); template void igl::prepare_lhs_double >(Eigen::PlainObjectBase > const&, mxArray_tag**); +template void igl::prepare_lhs_index >(Eigen::PlainObjectBase > const&, mxArray_tag**); #endif diff --git a/include/igl/triangle_triangle_adjacency.cpp b/include/igl/triangle_triangle_adjacency.cpp index d4d6f4733..a0555ef35 100644 --- a/include/igl/triangle_triangle_adjacency.cpp +++ b/include/igl/triangle_triangle_adjacency.cpp @@ -137,7 +137,6 @@ template < using namespace std; assert(F.cols() == 3 && "Faces must be triangles"); // number of faces - const int m = F.rows(); typedef typename DerivedF::Index Index; typedef Matrix MatrixX2I; typedef Matrix VectorXI; @@ -166,7 +165,7 @@ template < using namespace Eigen; typedef typename DerivedE::Index Index; const size_t m = E.rows()/3; - assert(E.rows() == m*3 && "E should come from list of triangles."); + assert((size_t)E.rows() == m*3 && "E should come from list of triangles."); // E2E[i] --> {j,k,...} means face edge i corresponds to other faces edges j // and k TT.resize (m,vector >(3)); @@ -177,20 +176,17 @@ template < // No race conditions because TT*[f][c]'s are in bijection with e's // Minimum number of iterms per openmp thread - const size_t ne = E.rows(); + //const size_t num_e = E.rows(); # ifndef IGL_OMP_MIN_VALUE # define IGL_OMP_MIN_VALUE 1000 # endif -# pragma omp parallel for if (ne>IGL_OMP_MIN_VALUE) +# pragma omp parallel for if (m>IGL_OMP_MIN_VALUE) // Slightly better memory access than loop over E for(Index f = 0;f<(Index)m;f++) { for(Index c = 0;c<3;c++) { const Index e = f + m*c; - const Index i = E(e,0); - const Index j = E(e,1); - //const Index f = e%m; //const Index c = e/m; const vector & N = uE2E[EMAP(e)]; for(const auto & ne : N) diff --git a/include/igl/unique_edge_map.cpp b/include/igl/unique_edge_map.cpp index 8ddbd5766..bf1a70901 100644 --- a/include/igl/unique_edge_map.cpp +++ b/include/igl/unique_edge_map.cpp @@ -29,7 +29,7 @@ IGL_INLINE void igl::unique_edge_map( uE2E.resize(uE.rows()); // This does help a little for_each(uE2E.begin(),uE2E.end(),[](vector & v){v.reserve(2);}); - assert(EMAP.size() == ne); + assert((size_t)EMAP.size() == ne); for(uE2EType e = 0;e<(uE2EType)ne;e++) { uE2E[EMAP(e)].push_back(e); diff --git a/include/igl/viewer/Viewer.cpp b/include/igl/viewer/Viewer.cpp index 73810544b..4af70fdcd 100644 --- a/include/igl/viewer/Viewer.cpp +++ b/include/igl/viewer/Viewer.cpp @@ -911,7 +911,7 @@ namespace igl glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif - window = glfwCreateWindow(1280, 800, "IGL Viewer", NULL, NULL); + window = glfwCreateWindow(1280, 800, "libigl viewer", NULL, NULL); if (!window) { glfwTerminate(); diff --git a/tutorial/609_Boolean/CMakeLists.txt b/tutorial/609_Boolean/CMakeLists.txt new file mode 100644 index 000000000..a200c45a4 --- /dev/null +++ b/tutorial/609_Boolean/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 2.6) +project(609_Boolean) + +find_package(CGAL REQUIRED) +include(${CGAL_USE_FILE}) + +# for some reason must come after cgal include +include("../CMakeLists.shared") + +set(SOURCES +${PROJECT_SOURCE_DIR}/main.cpp +) + +add_executable(${PROJECT_NAME}_bin ${SOURCES} ${SHARED_SOURCES}) +target_link_libraries(${PROJECT_NAME}_bin ${SHARED_LIBRARIES} ${CGAL_LIBRARIES}) diff --git a/tutorial/609_Boolean/main.cpp b/tutorial/609_Boolean/main.cpp new file mode 100755 index 000000000..170ba2eb6 --- /dev/null +++ b/tutorial/609_Boolean/main.cpp @@ -0,0 +1,94 @@ +#include +#define IGL_NO_CORK +#include +#include + +#include +#include + +Eigen::MatrixXd VA,VB,VC; +Eigen::VectorXi J; +Eigen::MatrixXi FA,FB,FC; +igl::MeshBooleanType boolean_type(igl::MESH_BOOLEAN_TYPE_UNION); + +const char * MESH_BOOLEAN_TYPE_NAMES[] = +{ + "Union", + "Intersect", + "Minus", + "XOR", + "Resolve", +}; + +void update(igl::Viewer &viewer) +{ + igl::mesh_boolean(VA,FA,VB,FB,boolean_type,VC,FC,J); + Eigen::MatrixXd C(FC.rows(),3); + for(size_t f = 0;f( + (boolean_type+1)% igl::NUM_MESH_BOOLEAN_TYPES); + break; + case ',': + boolean_type = + static_cast( + (boolean_type+igl::NUM_MESH_BOOLEAN_TYPES-1)% + igl::NUM_MESH_BOOLEAN_TYPES); + break; + case '[': + viewer.core.camera_dnear -= 0.1; + return true; + case ']': + viewer.core.camera_dnear += 0.1; + return true; + } + std::cout<<"A "<
  • 606 Baking ambient occlusion
  • 607 Picking vertices and faces
  • 608 Locally Injective Maps
  • +
  • 609 Boolean Operations on Meshes
  • Chapter 7: Outlook for continuing development
  • @@ -2422,6 +2423,78 @@ editing plus the anti-flipping constraints (right)." />
    A mesh (left) deformed using Laplacian editing (middle) and with Laplacian editing plus the anti-flipping constraints (right).
    +

    Boolean operations on meshes

    + +

    Constructive solid geometry (CSG) is a technique to define a complex surface as +the result of a number of set operations on solid regions of space: union, +intersection, set difference, symmetric difference, complement. Typically, CSG +libraries represent the inputs and outputs to these operations implicitly: +the solid \(A\) is defined as the open set of points \(\mathbf{x}\) for which some +function \(a(\mathbf{x})\) ``returns true’’. The surface of this shape is the +closure of all points \(x\) in \(A\).

    + +

    With this sort of representation, boolean +operations are straightforward. For example, the union of solids \(A\) and \(B\) +is simply

    + +

    \(A \cup B = \{\mathbf{x} \left.\right| + a(\mathbf{x}) \text{ or } b(\mathbf{x})\},\)

    + +

    the intersection is

    + +

    \(A \cap B = \{\mathbf{x} \left.\right| + a(\mathbf{x}) \text{ and } b(\mathbf{x})\},\)

    + +

    the difference \(A\) minus \(B\) is

    + +

    \(A \setminus B = \{\mathbf{x} \left.\right| + a(\mathbf{x}) \text{ and _not_ } b(\mathbf{x})\},\)

    + +

    and the symmetric difference (XOR) is

    + +

    \(A \setminus B = \{\mathbf{x} \left.\right| + \text{either } a(\mathbf{x}) \text{ or } b(\mathbf{x}) \text{ but not both }\}.\)

    + +

    Stringing together many of these operations, one can design quite complex +shapes. A typical CSG library might only keep explicit base-case +representations of canonical shapes: half-spaces, quadrics, etc.

    + +

    In libigl, we do currently not have an implicit surface representation. +Instead we expect our users to be working with explicit triangle mesh +boundary representations of solid shapes. CSG operations are much hard to +compute robustly with boundary representations, but are nonetheless useful.

    + +

    To compute a boolean operation on a triangle mesh with vertices VA and +triangles FA and another mesh VB and FB, libigl first computes a unified +mesh with vertices V and triangles F where all triangle-triangle +intersections have been “resolved”. That is, edges and vertices are added +exactly at the intersection lines, so the resulting non-manifold mesh (V,F) +has no self-intersections.

    + +

    Then libigl peals the outer hull [#attene_14] off this mesh recursively, +keeping track of the iteration parity and orientation flips for each layer. +For any boolean operation, these two pieces of information determine for each +triangle (1) if it should be included in the output, and (2) if its orientation +should be reversed before added to the output.

    + +

    Calling libigl’s boolean operations is simple. To compute the union of +(VA,FA) and (VB,FB) into a new mesh (VC,FC), use:

    + +
    igl::mesh_boolean(VA,FA,VB,FB,MESH_BOOLEAN_TYPE_UNION,VC,FC);
    +
    + +
    +The example Boolean conducts
+boolean operations on the Cheburashka (red) and Knight (green). From left
+to right: union, intersection, set minus, symmetric difference (XOR),
+``resolve. Bottom row reveals inner surfaces, darker color indicates
+back-facing triangles. +
    The example Boolean conducts +boolean operations on the Cheburashka (red) and Knight (green). From left +to right: union, intersection, set minus, symmetric difference (XOR), +``resolve’’. Bottom row reveals inner surfaces, darker color indicates +back-facing triangles.
    +

    Outlook for continuing development

    Libigl is in active development, and we plan to focus on the following features @@ -2557,7 +2630,8 @@ Nicolas Ray, Bruno Vallet, Wan Chiu Li, Bruno Lévy TOG 2008

  • Mixed-integer -quadrangulation, David Bommes, Henrik Zimmer, Leif Kobbelt SIGGRAPH 2009

    +quadrangulation, +David Bommes, Henrik Zimmer, Leif Kobbelt SIGGRAPH 2009

  • Globally Optimal Direction diff --git a/tutorial/tutorial.md b/tutorial/tutorial.md index d0833fffe..b2cc83ba2 100644 --- a/tutorial/tutorial.md +++ b/tutorial/tutorial.md @@ -85,6 +85,7 @@ lecture notes links to a cross-platform example application. * [606 Baking ambient occlusion](#606) * [607 Picking vertices and faces](#607) * [608 Locally Injective Maps](#608) + * [609 Boolean Operations on Meshes](#609) * [Chapter 7: Outlook for continuing development](#future) # Chapter 1 [100] @@ -2198,6 +2199,75 @@ deformation energies. A simple deformation of a 2D grid is computed in [Example ![A mesh (left) deformed using Laplacian editing (middle) and with Laplacian editing plus the anti-flipping constraints (right).](images/608_LIM.png) +## Boolean operations on meshes [609] + +Constructive solid geometry (CSG) is a technique to define a complex surface as +the result of a number of set operations on solid regions of space: union, +intersection, set difference, symmetric difference, complement. Typically, CSG +libraries represent the inputs and outputs to these operations _implicitly_: +the solid $A$ is defined as the open set of points $\mathbf{x}$ for which some +function $a(\mathbf{x})$ ``returns true''. The surface of this shape is the +_closure_ of all points $x$ in $A$. + +With this sort of representation, boolean +operations are straightforward. For example, the union of solids $A$ and $B$ +is simply + +$A \cup B = \{\mathbf{x} \left.\right| + a(\mathbf{x}) \text{ or } b(\mathbf{x})\},$ + +the intersection is + +$A \cap B = \{\mathbf{x} \left.\right| + a(\mathbf{x}) \text{ and } b(\mathbf{x})\},$ + +the difference $A$ _minus_ $B$ is + +$A \setminus B = \{\mathbf{x} \left.\right| + a(\mathbf{x}) \text{ and _not_ } b(\mathbf{x})\},$ + +and the symmetric difference (XOR) is + +$A \setminus B = \{\mathbf{x} \left.\right| + \text{either } a(\mathbf{x}) \text{ or } b(\mathbf{x}) \text{ but not both }\}.$ + +Stringing together many of these operations, one can design quite complex +shapes. A typical CSG library might only keep explicit _base-case_ +representations of canonical shapes: half-spaces, quadrics, etc. + +In libigl, we do currently _not_ have an implicit surface representation. +Instead we expect our users to be working with _explicit_ triangle mesh +_boundary representations_ of solid shapes. CSG operations are much hard to +compute robustly with boundary representations, but are nonetheless useful. + +To compute a boolean operation on a triangle mesh with vertices `VA` and +triangles `FA` and another mesh `VB` and `FB`, libigl first computes a unified +mesh with vertices `V` and triangles `F` where all triangle-triangle +intersections have been "resolved". That is, edges and vertices are added +exactly at the intersection lines, so the resulting _non-manifold_ mesh `(V,F)` +has no self-intersections. + +Then libigl _peals_ the outer hull [#attene_14][] off this mesh recursively, +keeping track of the iteration parity and orientation flips for each layer. +For any boolean operation, these two pieces of information determine for each +triangle (1) if it should be included in the output, and (2) if its orientation +should be reversed before added to the output. + +Calling libigl's boolean operations is simple. To compute the union of +`(VA,FA)` and `(VB,FB)` into a new mesh `(VC,FC)`, use: + +```cpp +igl::mesh_boolean(VA,FA,VB,FB,MESH_BOOLEAN_TYPE_UNION,VC,FC); +``` + +![The example [Boolean](609_Boolean/main.cpp) conducts +boolean operations on the _Cheburashka_ (red) and _Knight_ (green). From left +to right: union, intersection, set minus, symmetric difference (XOR), +``resolve''. Bottom row reveals inner surfaces, darker color indicates +back-facing triangles.](images/cheburashka-knight-boolean.jpg) + + + # Outlook for continuing development [future] Libigl is in active development, and we plan to focus on the following features @@ -2229,8 +2299,13 @@ repository](https://github.com/libigl/libigl). +[#attene_2014]:["Direct repair of + self-intersecting + meshes"](https://www.google.com/search?q=Direct+repair+of+self-intersecting+meshes), + Marco Attene, 2014. [#bommes_2009]:[Mixed-integer -quadrangulation](http://www-sop.inria.fr/members/David.Bommes/publications/miq.pdf), David Bommes, Henrik Zimmer, Leif Kobbelt SIGGRAPH 2009 +quadrangulation](http://www-sop.inria.fr/members/David.Bommes/publications/miq.pdf), +David Bommes, Henrik Zimmer, Leif Kobbelt SIGGRAPH 2009 [#botsch_2004]: Matrio Botsch and Leif Kobbelt. ["An Intuitive Framework for Real-Time Freeform Modeling,"](https://www.google.com/search?q=An+Intuitive+Framework+for+Real-Time+Freeform+Modeling)