New files from new booleans
authorAlexander Ewering <blender@instinctive.de>
Fri, 28 Oct 2005 20:17:27 +0000 (20:17 +0000)
committerAlexander Ewering <blender@instinctive.de>
Fri, 28 Oct 2005 20:17:27 +0000 (20:17 +0000)
38 files changed:
intern/boolop/Makefile [new file with mode: 0644]
intern/boolop/extern/BOP_Interface.h [new file with mode: 0644]
intern/boolop/intern/BOP_BBox.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_BBox.h [new file with mode: 0644]
intern/boolop/intern/BOP_BSPNode.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_BSPNode.h [new file with mode: 0644]
intern/boolop/intern/BOP_BSPTree.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_BSPTree.h [new file with mode: 0644]
intern/boolop/intern/BOP_Chrono.h [new file with mode: 0644]
intern/boolop/intern/BOP_Edge.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Edge.h [new file with mode: 0644]
intern/boolop/intern/BOP_Face.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Face.h [new file with mode: 0644]
intern/boolop/intern/BOP_Face2Face.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Face2Face.h [new file with mode: 0644]
intern/boolop/intern/BOP_Indexs.h [new file with mode: 0644]
intern/boolop/intern/BOP_Interface.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Material.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Material.h [new file with mode: 0644]
intern/boolop/intern/BOP_MaterialContainer.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_MaterialContainer.h [new file with mode: 0644]
intern/boolop/intern/BOP_MathUtils.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_MathUtils.h [new file with mode: 0644]
intern/boolop/intern/BOP_Merge.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Merge.h [new file with mode: 0644]
intern/boolop/intern/BOP_Mesh.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Mesh.h [new file with mode: 0644]
intern/boolop/intern/BOP_Segment.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Segment.h [new file with mode: 0644]
intern/boolop/intern/BOP_Splitter.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Splitter.h [new file with mode: 0644]
intern/boolop/intern/BOP_Tag.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Tag.h [new file with mode: 0644]
intern/boolop/intern/BOP_Triangulator.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Triangulator.h [new file with mode: 0644]
intern/boolop/intern/BOP_Vertex.cpp [new file with mode: 0644]
intern/boolop/intern/BOP_Vertex.h [new file with mode: 0644]
intern/boolop/intern/Makefile [new file with mode: 0644]

diff --git a/intern/boolop/Makefile b/intern/boolop/Makefile
new file mode 100644 (file)
index 0000000..85e6754
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License.  See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Hans Lambermont
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+# bsp main makefile.
+#
+
+include nan_definitions.mk
+
+LIBNAME = boolop
+SOURCEDIR = intern/$(LIBNAME)
+DIR = $(OCGDIR)/$(SOURCEDIR)
+DIRS = intern
+# not yet TESTDIRS = test
+
+include nan_subdirs.mk
+
+install: all debug
+       @[ -d $(NAN_BOOLOP) ] || mkdir $(NAN_BOOLOP)
+       @[ -d $(NAN_BOOLOP)/include ] || mkdir $(NAN_BOOLOP)/include
+       @[ -d $(NAN_BOOLOP)/lib ] || mkdir $(NAN_BOOLOP)/lib
+       @[ -d $(NAN_BOOLOP)/lib/debug ] || mkdir $(NAN_BOOLOP)/lib/debug
+       @../tools/cpifdiff.sh $(DIR)/libboolop.a $(NAN_BOOLOP)/lib/
+       @../tools/cpifdiff.sh $(DIR)/debug/libboolop.a $(NAN_BOOLOP)/lib/debug/
+ifeq ($(OS),darwin)
+       ranlib $(NAN_BOOLOP)/lib/libboolop.a
+       ranlib $(NAN_BOOLOP)/lib/debug/libboolop.a
+endif
+       @../tools/cpifdiff.sh extern/*.h $(NAN_BOOLOP)/include/
+
+
+
+
diff --git a/intern/boolop/extern/BOP_Interface.h b/intern/boolop/extern/BOP_Interface.h
new file mode 100644 (file)
index 0000000..446dd1b
--- /dev/null
@@ -0,0 +1,53 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_INTERFACE_H
+#define BOP_INTERFACE_H
+
+#include "../../bsp/intern/BSP_CSGMesh.h"
+
+typedef enum EnumBoolOpState {BOP_OK, BOP_NO_SOLID, BOP_ERROR} BoolOpState;
+typedef enum EnumBoolOpType {BOP_INTERSECTION=e_csg_intersection, BOP_UNION=e_csg_union, BOP_DIFFERENCE=e_csg_difference} BoolOpType;
+
+// extern interpolator.
+typedef int (*CSG_InterpolateUserFaceVertexDataFunc)(void *d1, void * d2, void *dnew, float epsilon);
+
+BoolOpState BOP_performBooleanOperation(BoolOpType                   opType,
+                                       CSG_MeshPropertyDescriptor   outputProps,
+                                       BSP_CSGMesh**                outputMesh,
+                                       CSG_MeshPropertyDescriptor   obAProps,
+                                       CSG_FaceIteratorDescriptor   obAFaces,
+                                       CSG_VertexIteratorDescriptor obAVertices,
+                                       CSG_MeshPropertyDescriptor   obBProps,
+                                       CSG_FaceIteratorDescriptor   obBFaces,
+                                       CSG_VertexIteratorDescriptor obBVertices,
+                                       CSG_InterpolateUserFaceVertexDataFunc interpFunc);
+
+#endif
diff --git a/intern/boolop/intern/BOP_BBox.cpp b/intern/boolop/intern/BOP_BBox.cpp
new file mode 100644 (file)
index 0000000..767847e
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "BOP_BBox.h"
+
+#include "MT_Scalar.h"
+
+/**
+ * Constructs a nwe bounding box.
+ */
+BOP_BBox::BOP_BBox()
+{
+       m_minX = MT_INFINITY;
+       m_minY = MT_INFINITY;
+       m_minZ = MT_INFINITY;
+       m_maxX = -MT_INFINITY;
+       m_maxY = -MT_INFINITY;
+       m_maxZ = -MT_INFINITY;
+}
+
+/**
+ * Constructs a new bounding box using three points.
+ * @param p1 first point
+ * @param p2 second point
+ * @param p3 third point
+ */
+BOP_BBox::BOP_BBox(const MT_Point3& p1,const MT_Point3& p2,const MT_Point3& p3)
+{
+  m_minX = BOP_MIN(BOP_MIN(p1[0],p2[0]),p3[0]);
+  m_minY = BOP_MIN(BOP_MIN(p1[1],p2[1]),p3[1]);
+  m_minZ = BOP_MIN(BOP_MIN(p1[2],p2[2]),p3[2]);
+  m_maxX = BOP_MAX(BOP_MAX(p1[0],p2[0]),p3[0]);
+  m_maxY = BOP_MAX(BOP_MAX(p1[1],p2[1]),p3[1]);
+  m_maxZ = BOP_MAX(BOP_MAX(p1[2],p2[2]),p3[2]);
+}
diff --git a/intern/boolop/intern/BOP_BBox.h b/intern/boolop/intern/BOP_BBox.h
new file mode 100644 (file)
index 0000000..473a982
--- /dev/null
@@ -0,0 +1,96 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BOP_BBOX_H
+#define BOP_BBOX_H
+
+#include "MT_Point3.h"
+#include "BOP_MathUtils.h"
+
+#define BOP_MAX(a, b) ((a > b) ? a : b)
+#define BOP_MIN(a, b) ((a < b) ? a : b)
+#define BOP_ABS(a) ((a < 0) ? -(a) : a)
+
+class BOP_BBox
+{
+public:
+       MT_Scalar m_minX;
+       MT_Scalar m_minY;
+       MT_Scalar m_minZ;
+       MT_Scalar m_maxX;
+       MT_Scalar m_maxY;
+       MT_Scalar m_maxZ;
+       MT_Scalar m_centerX;
+       MT_Scalar m_centerY;
+       MT_Scalar m_centerZ;
+       MT_Scalar m_extentX;
+       MT_Scalar m_extentY;
+       MT_Scalar m_extentZ;
+       
+public:
+       BOP_BBox();
+       BOP_BBox(const MT_Point3& p1,const MT_Point3& p2,const MT_Point3& p3);
+       inline void add(const MT_Point3& p)
+       {
+               m_minX = BOP_MIN(m_minX,p[0]);
+               m_minY = BOP_MIN(m_minY,p[1]);
+               m_minZ = BOP_MIN(m_minZ,p[2]);
+               m_maxX = BOP_MAX(m_maxX,p[0]);
+               m_maxY = BOP_MAX(m_maxY,p[1]);
+               m_maxZ = BOP_MAX(m_maxZ,p[2]);
+       };
+
+       inline const MT_Scalar getCenterX() const {return m_centerX;};
+       inline const MT_Scalar getCenterY() const {return m_centerY;};
+       inline const MT_Scalar getCenterZ() const {return m_centerZ;};
+
+       inline const MT_Scalar getExtentX() const {return m_extentX;};
+       inline const MT_Scalar getExtentY() const {return m_extentY;};
+       inline const MT_Scalar getExtentZ() const {return m_extentZ;};
+       
+       inline void compute() {
+               m_extentX = (m_maxX-m_minX)/2.0f;
+               m_extentY = (m_maxY-m_minY)/2.0f;
+               m_extentZ = (m_maxZ-m_minZ)/2.0f;
+               m_centerX = m_minX+m_extentX;
+               m_centerY = m_minY+m_extentY;
+               m_centerZ = m_minZ+m_extentZ;
+       };
+
+       inline const bool intersect(const BOP_BBox& b) const {
+         return (!((BOP_comp(m_maxX,b.m_minX)<0) || (BOP_comp(b.m_maxX,m_minX)<0) ||
+                   (BOP_comp(m_maxY,b.m_minY)<0) || (BOP_comp(b.m_maxY,m_minY)<0) ||
+                   (BOP_comp(m_maxZ,b.m_minZ)<0) || (BOP_comp(b.m_maxZ,m_minZ)<0)));
+       };
+       
+       
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_BSPNode.cpp b/intern/boolop/intern/BOP_BSPNode.cpp
new file mode 100644 (file)
index 0000000..afe4858
--- /dev/null
@@ -0,0 +1,671 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_MathUtils.h"
+#include "BOP_BSPNode.h"
+#include "MT_assert.h"
+#include "MT_MinMax.h"
+#include <iostream>
+using namespace std;
+
+/**
+ * Constructs a new BSP node.
+ * @param plane split plane.
+ */
+BOP_BSPNode::BOP_BSPNode(const MT_Plane3& plane)
+{
+       m_plane      = plane;
+       m_inChild    = NULL;
+       m_outChild   = NULL;
+       m_deep       = 1;
+}
+
+/**
+ * Destroys a BSP tree.
+ */
+BOP_BSPNode::~BOP_BSPNode()
+{
+       if (m_inChild!=NULL) delete m_inChild;
+       if (m_outChild!=NULL) delete m_outChild;
+}
+
+/**
+ * Adds a new face to this BSP tree.
+ * @param p1 first face point.
+ * @param p2 second face point.
+ * @param p3 third face point.
+ * @param plane face plane.
+ */
+unsigned int BOP_BSPNode::addFace(const MT_Point3& p1, 
+                                                                 const MT_Point3& p2, 
+                                                                 const MT_Point3& p3, 
+                                                                 const MT_Plane3& plane)
+{
+       unsigned int newDeep = 0;
+       BOP_TAG tag = BOP_createTAG(testPoint(p1), testPoint(p2), testPoint(p3));
+       if ((tag & IN_IN_IN) != 0) {
+               if (m_inChild != NULL)
+                       newDeep = m_inChild->addFace(p1, p2, p3, plane) + 1;
+               else {
+                       m_inChild = new BOP_BSPNode(plane);
+                       newDeep = 2;
+               }    
+       }
+       
+       if ((tag & OUT_OUT_OUT) != 0){
+               if (m_outChild != NULL)
+                       newDeep = max(newDeep, m_outChild->addFace(p1, p2, p3, plane) + 1);
+               else {
+                       m_outChild = new BOP_BSPNode(plane);
+                       newDeep = max(newDeep,(unsigned int)2);
+               }      
+       }
+       
+       // update the deep attribute
+       m_deep = MT_max(m_deep,newDeep);
+       
+       return m_deep;
+}
+
+/**
+ * Tests the point situation respect the node plane.
+ * @param p point to test.
+ * @return TAG result: IN, OUT or ON.
+ */
+BOP_TAG BOP_BSPNode::testPoint(const MT_Point3& p) const
+{
+  return BOP_createTAG(BOP_classify(p,m_plane));
+
+}
+
+/**
+ * Classifies a face using its coordinates and plane.
+ * @param p1 first point.
+ * @param p2 second point.
+ * @param p3 third point.
+ * @param plane face plane.
+ * @return TAG result: IN, OUT or IN&OUT.
+ */
+BOP_TAG BOP_BSPNode::classifyFace(const MT_Point3& p1, 
+                                                                 const MT_Point3& p2, 
+                                                                 const MT_Point3& p3, 
+                                                                 const MT_Plane3& plane) const
+{
+       // local variables
+       MT_Point3 auxp1, auxp2;
+       BOP_TAG auxtag1, auxtag2, auxtag3;
+
+       switch(BOP_createTAG(testPoint(p1),testPoint(p2),testPoint(p3))) {
+               // Classify the face on the IN side
+               case IN_IN_IN : 
+                       return classifyFaceIN(p1, p2, p3, plane);
+               case IN_IN_ON :
+               case IN_ON_IN :
+               case ON_IN_IN :
+               case IN_ON_ON :
+               case ON_IN_ON :
+               case ON_ON_IN :
+                       return BOP_addON(classifyFaceIN(p1, p2, p3, plane));
+       
+               // Classify the face on the OUT side
+               case OUT_OUT_OUT :
+                       return classifyFaceOUT(p1, p2, p3, plane);
+               case OUT_OUT_ON :
+               case OUT_ON_OUT :
+               case ON_OUT_OUT :
+               case ON_ON_OUT :
+               case ON_OUT_ON :
+               case OUT_ON_ON :
+                       return BOP_addON(classifyFaceOUT(p1, p2, p3, plane));
+       
+               // Classify the ON face depending on it plane normal
+               case ON_ON_ON :
+                       if (hasSameOrientation(plane))
+                               return BOP_addON(classifyFaceIN(p1, p2, p3, plane));
+                       else
+                               return BOP_addON(classifyFaceOUT(p1, p2, p3, plane));
+
+               // Classify the face IN/OUT and one vertex ON
+               // becouse only one ON, only one way to subdivide the face
+               case IN_OUT_ON :
+                       auxp1 = BOP_intersectPlane(m_plane, p1, p2);
+                       auxtag1 = classifyFaceIN( p1,    auxp1 , p3, plane);
+                       auxtag2 = classifyFaceOUT(auxp1, p2,     p3, plane);
+                       return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT);
+
+               case OUT_IN_ON :
+                       auxp1 = BOP_intersectPlane(m_plane, p1, p2);
+                       auxtag1 = classifyFaceOUT(p1,    auxp1, p3, plane);
+                       auxtag2 = classifyFaceIN( auxp1, p2,    p3, plane);
+                       return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT);
+
+               case IN_ON_OUT :
+                       auxp1 = BOP_intersectPlane(m_plane, p1, p3);
+                       auxtag1 = classifyFaceIN( p1, p2, auxp1, plane);
+                       auxtag2 = classifyFaceOUT(p2, p3, auxp1, plane);
+                       return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT);
+
+               case OUT_ON_IN :
+                       auxp1 = BOP_intersectPlane(m_plane, p1, p3);
+                       auxtag1 = classifyFaceOUT(p1, p2, auxp1, plane);
+                       auxtag2 = classifyFaceIN( p2, p3, auxp1, plane);
+                       return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT);
+
+               case ON_IN_OUT :
+                       auxp1 = BOP_intersectPlane(m_plane, p2, p3);
+                       auxtag1 = classifyFaceIN( p1,    p2, auxp1, plane);
+                       auxtag2 = classifyFaceOUT(auxp1, p3, p1,    plane);
+                       return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT);
+
+               case ON_OUT_IN :
+                       auxp1 = BOP_intersectPlane(m_plane, p2, p3);
+                       auxtag1 = classifyFaceOUT(p1,    p2, auxp1, plane);
+                       auxtag2 = classifyFaceIN( auxp1, p3, p1,    plane);
+                       return (BOP_compTAG(auxtag1,auxtag2)?BOP_addON(auxtag1):INOUT);
+
+               // Classify IN/OUT face without ON vertices.
+               // Two ways to divide the triangle, 
+               // will chose the least degenerated sub-triangles.
+               case IN_OUT_OUT :
+                       auxp1 = BOP_intersectPlane(m_plane, p1, p2);
+                       auxp2 = BOP_intersectPlane(m_plane, p1, p3);
+       
+                       // f1: p1 auxp1 , auxp1 auxp2
+                       auxtag1 = classifyFaceIN(p1, auxp1, auxp2, plane);
+       
+                       // f2: auxp1 p2 , p2 auxp2;  f3: p2 p3 , p3 auxp2  ||  
+                       // f2: auxp1 p3, p3 auxp2;   f3: p2 p3 , p3 auxp1
+                       if (BOP_isInsideCircle(p2, p3, auxp1, auxp2)) {
+                               auxtag2 = classifyFaceOUT(auxp1, p2, auxp2, plane);
+                               auxtag3 = classifyFaceOUT(p2,    p3, auxp2, plane);
+                       }
+                       else {
+                               auxtag2 = classifyFaceOUT(auxp1, p3, auxp2, plane);
+                               auxtag3 = classifyFaceOUT(p2,    p3, auxp1, plane);
+                       }
+                       return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT);
+
+               case OUT_IN_IN :
+                       auxp1 = BOP_intersectPlane(m_plane, p1, p2);
+                       auxp2 = BOP_intersectPlane(m_plane, p1, p3);
+       
+                       // f1: p1 auxp1 , auxp1 auxp2
+                       auxtag1 = classifyFaceOUT(p1, auxp1, auxp2, plane);
+       
+                       // f2: auxp1 p2 , p2 auxp2;  f3: p2 p3 , p3 auxp2  ||
+                       // f2: auxp1 p3, p3 auxp2;  f3: p2 p3 , p3 auxp1
+                       if (BOP_isInsideCircle(p2, p3, auxp1, auxp2)) {
+                               auxtag2 = classifyFaceIN(auxp1, p2, auxp2, plane);
+                               auxtag3 = classifyFaceIN(p2, p3, auxp2, plane);
+                       }
+                       else {
+                               auxtag2 = classifyFaceIN(auxp1, p3, auxp2, plane);
+                               auxtag3 = classifyFaceIN(p2,    p3, auxp1, plane);
+                       }
+                       return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT);
+
+               case OUT_IN_OUT :
+                       auxp1 = BOP_intersectPlane(m_plane, p2, p1);
+                       auxp2 = BOP_intersectPlane(m_plane, p2, p3);
+       
+                       // f1: auxp1 p2 , p2 auxp2
+                       auxtag1 = classifyFaceIN(auxp1, p2, auxp2, plane);
+       
+                       // f2: p1 auxp1 , auxp1 auxp2;  f3: p1 auxp2 , auxp2 p3  ||  
+                       // f2: p3 auxp1, auxp1 auxp2  f3:p1 auxp1, auxp1 p3
+                       if (BOP_isInsideCircle(p1, p3, auxp1, auxp2)) {
+                               auxtag2 = classifyFaceOUT(p1, auxp1, auxp2, plane);
+                               auxtag3 = classifyFaceOUT(p1, auxp2, p3,    plane);
+                       }
+                       else {
+                               auxtag2 = classifyFaceOUT(p3, auxp1, auxp2, plane);
+                               auxtag3 = classifyFaceOUT(p1, auxp1, p3,    plane);
+                       }
+                       return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT);
+    
+               case IN_OUT_IN :
+                       auxp1 = BOP_intersectPlane(m_plane, p2, p1);
+                       auxp2 = BOP_intersectPlane(m_plane, p2, p3);
+       
+                       // f1: auxp1 p2 , p2 auxp2
+                       auxtag1 = classifyFaceOUT(auxp1, p2, auxp2, plane);
+       
+                       // f2: p1 auxp1 , auxp1 auxp2;  f3: p1 auxp2 , auxp2 p3  ||  
+                       // f2: p3 auxp1, auxp1 auxp2  f3:p1 auxp1, auxp1 p3
+                       if (BOP_isInsideCircle(p1, p3, auxp1, auxp2)) {
+                               auxtag2 = classifyFaceIN(p1, auxp1, auxp2, plane);
+                               auxtag3 = classifyFaceIN(p1, auxp2, p3,    plane);
+                       }
+                       else {
+                               auxtag2 = classifyFaceIN(p3, auxp1, auxp2, plane);
+                               auxtag3 = classifyFaceIN(p1, auxp1, p3,    plane);
+                       }
+                       return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT);
+       
+               case OUT_OUT_IN :
+                       auxp1 = BOP_intersectPlane(m_plane, p3, p1);
+                       auxp2 = BOP_intersectPlane(m_plane, p3, p2);
+       
+                       // f1: auxp1 auxp2 , auxp2 p3
+                       auxtag1 = classifyFaceIN(auxp1, auxp2, p3, plane);
+       
+                       // f2: p1 p2 , p2 auxp2;   f3:p1 auxp2 , auxp2 auxp1  ||
+                       // f2: p1 p2, p2 auxp1;  f3:p2 auxp2, auxp2 auxp1
+                       if (BOP_isInsideCircle(p1, p2, auxp1, auxp2)) {
+                               auxtag2 = classifyFaceOUT(p1, p2,    auxp2, plane);
+                               auxtag3 = classifyFaceOUT(p1, auxp2, auxp1, plane);
+                       }
+                       else {
+                               auxtag2 = classifyFaceOUT(p1, p2,    auxp1, plane);
+                               auxtag3 = classifyFaceOUT(p2, auxp2, auxp1, plane);
+                       }
+                       return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT);
+
+               case IN_IN_OUT :
+                       auxp1 = BOP_intersectPlane(m_plane, p3, p1);
+                       auxp2 = BOP_intersectPlane(m_plane, p3, p2);
+       
+                       // f1: auxp1 auxp2 , auxp2 p3
+                       auxtag1 = classifyFaceOUT(auxp1, auxp2, p3, plane);
+       
+                       // f2: p1 p2 , p2 auxp2;   f3:p1 auxp2 , auxp2 auxp1  ||
+                       // f2: p1 p2, p2 auxp1;  f3:p2 auxp2, auxp2 auxp1
+                       if (BOP_isInsideCircle(p1, p2, auxp1, auxp2)) {
+                               auxtag2 = classifyFaceIN(p1, p2,    auxp2, plane);
+                               auxtag3 = classifyFaceIN(p1, auxp2, auxp1, plane);
+                       }
+                       else {
+                               auxtag2 = classifyFaceIN(p1, p2,    auxp1, plane);
+                               auxtag3 = classifyFaceIN(p2, auxp2, auxp1, plane);
+                       }
+                       return (BOP_compTAG(auxtag1,auxtag2)&&BOP_compTAG(auxtag2,auxtag3)?auxtag1:INOUT);
+
+               default:
+                       return UNCLASSIFIED;
+       }
+}
+
+/**
+ * Classifies a face through IN subtree.
+ * @param p1 firts face vertex.
+ * @param p2 second face vertex.
+ * @param p3 third face vertex.
+ * @param plane face plane.
+ */
+BOP_TAG BOP_BSPNode::classifyFaceIN(const MT_Point3& p1, 
+                                                                       const MT_Point3& p2, 
+                                                                       const MT_Point3& p3, 
+                                                                       const MT_Plane3& plane) const
+{
+       if (m_inChild != NULL)
+               return m_inChild->classifyFace(p1, p2, p3, plane);
+       else
+               return IN;
+}
+
+/**
+ * Classifies a face through OUT subtree.
+ * @param p1 firts face vertex.
+ * @param p2 second face vertex.
+ * @param p3 third face vertex.
+ * @param plane face plane.
+ */
+BOP_TAG BOP_BSPNode::classifyFaceOUT(const MT_Point3& p1, 
+                                                                        const MT_Point3& p2, 
+                                                                        const MT_Point3& p3, 
+                                                                        const MT_Plane3& plane) const
+{
+       if (m_outChild != NULL)
+               return m_outChild->classifyFace(p1, p2, p3, plane);
+       else
+               return OUT;
+}
+
+/**
+ * Simplified classification (optimized but requires that the face is not 
+ * INOUT; only works correctly with faces completely IN or OUT).
+ * @param p1 firts face vertex.
+ * @param p2 second face vertex.
+ * @param p3 third face vertex.
+ * @param plane face plane.
+ * @return TAG result: IN or OUT.
+ */
+BOP_TAG BOP_BSPNode::simplifiedClassifyFace(const MT_Point3& p1, 
+                                                                                       const MT_Point3& p2, 
+                                                                                       const MT_Point3& p3, 
+                                                                                       const MT_Plane3& plane) const
+{
+       MT_Point3 ret[3];
+
+       BOP_TAG tag = BOP_createTAG(testPoint(p1),testPoint(p2),testPoint(p3));
+
+       if ((tag & IN_IN_IN) != 0) {
+               if ((tag & OUT_OUT_OUT) != 0) {     
+                 if (splitTriangle(ret,m_plane,p1,p2,p3,tag)<0)
+                   return simplifiedClassifyFaceIN(ret[0],ret[1],ret[2],plane);
+                 else
+                   return simplifiedClassifyFaceOUT(ret[0],ret[1],ret[2],plane);
+               }
+               else {
+                       return simplifiedClassifyFaceIN(p1,p2,p3,plane);
+               }
+       }
+       else {
+               if ((tag & OUT_OUT_OUT) != 0) {
+                       return simplifiedClassifyFaceOUT(p1,p2,p3,plane);
+               }
+               else {
+                       if (hasSameOrientation(plane)) {
+                               return simplifiedClassifyFaceIN(p1,p2,p3,plane);
+                       }
+                       else {
+                               return simplifiedClassifyFaceOUT(p1,p2,p3,plane);
+                       }
+               }
+       }
+       
+       return IN;
+}
+
+/**
+ * Simplified classify through IN subtree.
+ * @param p1 firts face vertex.
+ * @param p2 second face vertex.
+ * @param p3 third face vertex.
+ * @param plane face plane.
+ */
+BOP_TAG BOP_BSPNode::simplifiedClassifyFaceIN(const MT_Point3& p1, 
+                                                                                         const MT_Point3& p2, 
+                                                                                         const MT_Point3& p3, 
+                                                                                         const MT_Plane3& plane) const
+{
+       if (m_inChild != NULL)
+               return m_inChild->simplifiedClassifyFace(p1, p2, p3, plane);
+       else
+               return IN;
+}
+
+/**
+ * Simplified classify through OUT subtree.
+ * @param p1 firts face vertex.
+ * @param p2 second face vertex.
+ * @param p3 third face vertex.
+ * @param plane face plane.
+ */
+BOP_TAG BOP_BSPNode::simplifiedClassifyFaceOUT(const MT_Point3& p1, 
+                                                                                          const MT_Point3& p2, 
+                                                                                          const MT_Point3& p3, 
+                                                                                          const MT_Plane3& plane) const
+{
+       if (m_outChild != NULL)
+               return m_outChild->simplifiedClassifyFace(p1, p2, p3, plane);
+       else
+               return OUT;
+}
+
+/**
+ * Determine if the input plane have the same orientation of the node plane.
+ * @param plane plane to test.
+ * @return TRUE if have the same orientation, FALSE otherwise.
+ */
+bool BOP_BSPNode::hasSameOrientation(const MT_Plane3& plane) const
+{
+       return (BOP_orientation(m_plane,plane)>0);
+}
+
+/**
+ * Comparation between both childrens.
+ * @return 0 equal deep, 1 inChild more deep than outChild and -1 otherwise.
+ */
+int BOP_BSPNode::compChildren() const
+{
+       unsigned int deep1 = (m_inChild == NULL?0:m_inChild->getDeep());
+       unsigned int deep2 = (m_outChild == NULL?0:m_outChild->getDeep());
+       
+       if (deep1 == deep2)
+               return 0;
+       else if (deep1 < deep2)
+               return -1;
+       else
+               return 1;
+}
+
+/**
+ * Extract a subtriangle from input triangle, is used for simplified classification.
+ * The subtriangle is obtained spliting the input triangle by input plane.
+ * @param res output subtriangle result.
+ * @param plane spliter plane.
+ * @param p1 first triangle point.
+ * @param p2 second triangle point.
+ * @param p3 third triangle point.
+ * @param tag triangle orientation respect the plane.
+ */
+int BOP_BSPNode::splitTriangle(MT_Point3* res, 
+                                                          const MT_Plane3& plane, 
+                                                          const MT_Point3& p1, 
+                                                          const MT_Point3& p2, 
+                                                          const MT_Point3& p3, 
+                                                          const BOP_TAG tag) const
+{
+       switch (tag) {
+               case IN_OUT_ON :
+                 if (compChildren()<0) {
+                   // f1: p1 new p3 || new = splitedge(p1,p2)
+                   res[0] = p1;
+                   res[1] = BOP_intersectPlane( plane, p1, p2 );
+                   res[2] = p3;
+                   return -1;
+                 }else{
+                   // f1: p2 new p3 || new = splitedge(p1,p2)
+                   res[0] = p2;
+                   res[1] = p3;
+                   res[2] = BOP_intersectPlane( plane, p1, p2 );
+                   return 1;
+                 }
+               case OUT_IN_ON :
+                 if (compChildren()<0) {
+                   // f1: p2 new p3 || new = splitedge(p1,p2)
+                   res[0] = p2;
+                   res[1] = p3;
+                   res[2] = BOP_intersectPlane( plane, p1, p2 );
+                   return -1;
+                 }else{
+                   // f1: p1 new p3 || new = splitedge(p1,p2)
+                   res[0] = p1;
+                   res[1] = BOP_intersectPlane( plane, p1, p2 );
+                   res[2] = p3;
+                   return 1;
+                 }
+               case IN_ON_OUT :
+                 if (compChildren()<0) {
+                   // f1: p1 p2 new || new = splitedge(p1,p3)
+                   res[0] = p1;
+                   res[1] = p2;
+                   res[2] = BOP_intersectPlane( plane, p1, p3 );
+                   return -1;
+                 }else{
+                   // f1: p2 p3 new || new = splitedge(p1,p3)
+                   res[0] = p2;
+                   res[1] = p3;
+                   res[2] = BOP_intersectPlane( plane, p1, p3 );
+                   return 1;
+                 }
+               case OUT_ON_IN :
+                 if (compChildren()<0) {
+                   // f1: p2 p3 new || new = splitedge(p1,p3)
+                   res[0] = p2;
+                   res[1] = p3;
+                   res[2] = BOP_intersectPlane( plane, p1, p3 );
+                   return -1;
+                 }else{
+                   // f1: p1 p2 new || new = splitedge(p1,p3)
+                   res[0] = p1;
+                   res[1] = p2;
+                   res[2] = BOP_intersectPlane( plane, p1, p3 );
+                   return 1;
+                 }
+               case ON_IN_OUT :
+                 if (compChildren()<0) {
+                   // f1: p1 p2 new || new = splitedge(p2,p3)
+                   res[0] = p1;
+                   res[1] = p2;
+                   res[2] = BOP_intersectPlane( plane, p2, p3 );
+                   return -1;
+                 }else{
+                   // f1: p1 p3 new || new = splitedge(p2,p3)
+                   res[0] = p1;
+                   res[1] = BOP_intersectPlane( plane, p2, p3 );
+                   res[2] = p3;
+                   return 1;
+                 }
+               case ON_OUT_IN :
+                 if (compChildren()<0) {
+                   // f1: p1 p2 new || new = splitedge(p2,p3)
+                   res[0] = p1;
+                   res[1] = BOP_intersectPlane( plane, p2, p3 );
+                   res[2] = p3;
+                   return -1;
+                 }else{
+                   // f1: p1 p2 new || new = splitedge(p2,p3)
+                   res[0] = p1;
+                   res[1] = p2;
+                   res[2] = BOP_intersectPlane( plane, p2, p3 );
+                   return 1;
+                 }
+               case IN_OUT_OUT :
+                 if (compChildren()<=0) {
+                   // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3)
+                   res[0] = p1;
+                   res[1] = BOP_intersectPlane( plane, p1, p2 );
+                   res[2] = BOP_intersectPlane( plane, p1, p3 );
+                   return -1;
+                 }else{
+                   // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3)
+                   res[0] = BOP_intersectPlane( plane, p1, p2 );
+                   res[1] = p2;
+                   res[2] = p3;
+                   return 1;
+                 }
+               case OUT_IN_IN :
+                 if (compChildren()<0) {
+                   // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3)
+                   res[0] = BOP_intersectPlane( plane, p1, p2 );
+                   res[1] = p2;
+                   res[2] = p3;
+                   return -1;
+                 }else {
+                   // f1: p1 new1 new2 || new1 = splitedge(p1,p2) new2 = splitedge(p1,p3)
+                   res[0] = p1;
+                   res[1] = BOP_intersectPlane( plane, p1, p2 );
+                   res[2] = BOP_intersectPlane( plane, p1, p3 );
+                   return 1;
+                 }
+               case OUT_IN_OUT :
+                 if (compChildren()<=0) {
+                   // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3)
+                   res[0] = BOP_intersectPlane( plane, p2, p1 );
+                   res[1] = p2;
+                   res[2] = BOP_intersectPlane( plane, p2, p3 );
+                   return -1;
+                 }else {
+                   // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3)
+                   res[0] = p1;
+                   res[1] = BOP_intersectPlane( plane, p2, p1 );
+                   res[2] = BOP_intersectPlane( plane, p2, p3 );
+                   return 1;
+                 }
+               case IN_OUT_IN :
+                 if (compChildren()<0) {
+                   // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3)
+                   res[0] = p1;
+                   res[1] = BOP_intersectPlane( plane, p2, p1 );
+                   res[2] = BOP_intersectPlane( plane, p2, p3 );
+                   return -1;
+                 }else{
+                   // f1: new1 p2 new2 || new1 = splitedge(p2,p1) new2 = splitedge(p2,p3)
+                   res[0] = BOP_intersectPlane( plane, p2, p1 );
+                   res[1] = p2;
+                   res[2] = BOP_intersectPlane( plane, p2, p3 );
+                   return 1;
+                 }
+               case OUT_OUT_IN :
+                 if (compChildren()<=0) {
+                   // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2)
+                   res[0] = BOP_intersectPlane( plane, p3, p1 );
+                   res[1] = BOP_intersectPlane( plane, p3, p2 );
+                   res[2] = p3;
+                   return -1;
+                 }else{
+                   // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2)
+                   res[0] = BOP_intersectPlane( plane, p3, p1 );
+                   res[1] = p1;
+                   res[2] = p2;
+                   return 1;
+                 }
+               case IN_IN_OUT :
+                 if (compChildren()<0) {
+                   // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2)
+                   res[0] = BOP_intersectPlane( plane, p3, p1 );
+                   res[1] = p1;
+                   res[2] = p2;
+                   return -1;
+                 }else{
+                   // f1: new1 new2 p2 || new1 = splitedge(p3,p1) new2 = splitedge(p3,p2)
+                   res[0] = BOP_intersectPlane( plane, p3, p1 );
+                   res[1] = BOP_intersectPlane( plane, p3, p2 );
+                   res[2] = p3;
+                   return 1;
+                 }
+       default:
+         return 0;
+       }
+}
+
+/**
+ * Debug info.
+ */
+void BOP_BSPNode::print(unsigned int deep)
+{
+       for (unsigned int i = 0; i < deep; ++i)
+               cout << "  ";
+       
+       cout << m_plane.x() << ", ";
+       cout << m_plane.y() << ", ";
+       cout << m_plane.z() << ", ";
+       cout << m_plane.w() << endl;
+       if (m_inChild != NULL) {
+               cout << "IN:";
+               m_inChild->print(deep + 1);
+       }
+       if (m_outChild != NULL) {
+               cout << "OUT:";
+               m_outChild->print(deep + 1);
+       }
+}
diff --git a/intern/boolop/intern/BOP_BSPNode.h b/intern/boolop/intern/BOP_BSPNode.h
new file mode 100644 (file)
index 0000000..d4f7f1c
--- /dev/null
@@ -0,0 +1,104 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_BSPNODE_H
+#define BOP_BSPNODE_H
+
+#include "MT_Plane3.h"
+#include "BOP_Tag.h"
+#include "BOP_Face.h"
+
+class BOP_BSPNode
+{
+protected:
+       BOP_BSPNode* m_inChild;
+       BOP_BSPNode* m_outChild;
+       MT_Plane3    m_plane;
+       unsigned int m_deep;
+
+public:
+       // Construction methods
+       BOP_BSPNode(const MT_Plane3& plane);
+       ~BOP_BSPNode();
+       unsigned int addFace(const MT_Point3& p1, 
+                                                const MT_Point3& p2, 
+                                                const MT_Point3& p3, 
+                                                const MT_Plane3& plane);
+       BOP_TAG classifyFace(const MT_Point3& p1, 
+                                                const MT_Point3& p2, 
+                                                const MT_Point3& p3, 
+                                                const MT_Plane3& plane) const;
+       BOP_TAG simplifiedClassifyFace(const MT_Point3& p1, 
+                                                                  const MT_Point3& p2, 
+                                                                  const MT_Point3& p3, 
+                                                                  const MT_Plane3& plane) const;
+       
+protected:
+       BOP_TAG testPoint(const MT_Point3& p) const;
+       BOP_TAG classifyFaceIN(const MT_Point3& p1, 
+                                                  const MT_Point3& p2, 
+                                                  const MT_Point3& p3, 
+                                                  const MT_Plane3& plane) const;
+       BOP_TAG classifyFaceOUT(const MT_Point3& p1, 
+                                                       const MT_Point3& p2, 
+                                                       const MT_Point3& p3, 
+                                                       const MT_Plane3& plane) const;
+       BOP_TAG simplifiedClassifyFaceIN(const MT_Point3& p1, 
+                                                                        const MT_Point3& p2, 
+                                                                        const MT_Point3& p3, 
+                                                                        const MT_Plane3& plane) const;
+       BOP_TAG simplifiedClassifyFaceOUT(const MT_Point3& p1, 
+                                                                         const MT_Point3& p2, 
+                                                                         const MT_Point3& p3, 
+                                                                         const MT_Plane3& plane) const;
+       bool hasSameOrientation(const MT_Plane3& plane) const;
+       int compChildren() const;
+       int splitTriangle(MT_Point3* res, 
+                                         const MT_Plane3& plane, 
+                                         const MT_Point3& p1, 
+                                         const MT_Point3& p2, 
+                                         const MT_Point3& p3, 
+                                         const BOP_TAG tag) const;
+
+public:
+       // Inline acces methods
+       inline void setInChild(BOP_BSPNode* inChild) { m_inChild=inChild; };
+       inline void setOutChild(BOP_BSPNode* outChild) { m_outChild=outChild; };
+       inline BOP_BSPNode* getInChild() { return m_inChild; };
+       inline BOP_BSPNode* getOutChild() { return m_outChild; };
+       inline bool isLeaf() const { return !m_inChild && !m_outChild; };
+       inline void setPlane(const MT_Plane3& plane) {m_plane=plane;};
+       inline MT_Plane3& getPlane() { return m_plane; };
+
+       inline unsigned int getDeep() const {return m_deep;};
+       void print(unsigned int deep);
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_BSPTree.cpp b/intern/boolop/intern/BOP_BSPTree.cpp
new file mode 100644 (file)
index 0000000..4e5c171
--- /dev/null
@@ -0,0 +1,212 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_BSPTree.h"
+#include <vector>
+#include <iostream>
+using namespace std;
+
+/**
+ * Constructs a new BSP tree.
+ */
+BOP_BSPTree::BOP_BSPTree()
+{
+       m_root = NULL;
+       m_bspBB = NULL;
+}
+
+/**
+ * Destroys a BSP tree.
+ */
+BOP_BSPTree::~BOP_BSPTree()
+{
+       if (m_root!=NULL) delete m_root;
+       if (m_bspBB!=NULL) delete m_bspBB;
+}
+
+/**
+ * Adds all mesh faces to BSP tree.
+ * @param mesh mesh to add.
+ * @param facesList face list to add.
+ */
+void BOP_BSPTree::addMesh(BOP_Mesh* mesh, BOP_Faces& facesList)
+{
+       for (BOP_IT_Faces it = facesList.begin(); it != facesList.end(); ++it) {
+               addFace( mesh, *it );
+       }
+       
+}
+
+/**
+ * Adds a new face into bsp tree.
+ * @param mesh Input data for BSP tree.
+ * @param face index to mesh face.
+ */
+void BOP_BSPTree::addFace(BOP_Mesh* mesh, BOP_Face* face)
+{
+       addFace(mesh->getVertex(face->getVertex(0))->getPoint(),
+                       mesh->getVertex(face->getVertex(1))->getPoint(),
+                       mesh->getVertex(face->getVertex(2))->getPoint(),
+                       face->getPlane());
+}
+
+/**
+ * Adds new facee to the bsp-tree.
+ * @param p1 first face point.
+ * @param p2 second face point.
+ * @param p3 third face point.
+ * @param plane face plane.
+ */
+void BOP_BSPTree::addFace(const MT_Point3& p1, 
+                                                 const MT_Point3& p2, 
+                                                 const MT_Point3& p3, 
+                                                 const MT_Plane3& plane)
+{
+       if (m_root == NULL)
+               m_root = new BOP_BSPNode(plane);
+       else
+               m_root->addFace(p1,p2,p3,plane);
+
+       // update bounding box
+       m_bbox.add(p1);
+       m_bbox.add(p2);
+       m_bbox.add(p3);
+}
+
+/**
+ * Tests face vs bsp-tree (returns where is the face respect bsp planes).
+ * @param p1 first face triangle point.
+ * @param p2 secons face triangle point.
+ * @param p3 third face triangle point.
+ * @param plane face plane.
+ * @return BSP_IN, BSP_OUT or BSP_IN_OUT
+ */
+BOP_TAG BOP_BSPTree::classifyFace(const MT_Point3& p1, 
+                                                                 const MT_Point3& p2, 
+                                                                 const MT_Point3& p3, 
+                                                                 const MT_Plane3& plane) const
+{
+       if ( m_root != NULL )
+         return m_root->classifyFace(p1, p2, p3, plane);
+       else
+         return OUT;
+}
+
+/**
+ * Filters a face using the BSP bounding infomation.
+ * @param p1 first face triangle point.
+ * @param p2 secons face triangle point.
+ * @param p3 third face triangle point.
+ * @param face face to test.
+ * @return UNCLASSIFIED, BSP_IN, BSP_OUT or BSP_IN_OUT
+ */
+BOP_TAG BOP_BSPTree::filterFace(const MT_Point3& p1, 
+                                                               const MT_Point3& p2, 
+                                                               const MT_Point3& p3, 
+                                                               BOP_Face* face)
+{
+       if ( m_bspBB != NULL ) {
+               return m_bspBB->classifyFace(p1,p2,p3,face->getPlane());
+       }
+       else
+               return UNCLASSIFIED;
+}
+
+/**
+ * Tests face vs bsp-tree (returns where is the face respect bsp planes).
+ * @param p1 first face triangle point.
+ * @param p2 secons face triangle point.
+ * @param p3 third face triangle point.
+ * @param plane face plane.
+ * @return BSP_IN, BSP_OUT or BSP_IN_OUT
+ */
+BOP_TAG BOP_BSPTree::simplifiedClassifyFace(const MT_Point3& p1, 
+                                                                                       const MT_Point3& p2, 
+                                                                                       const MT_Point3& p3, 
+                                                                                       const MT_Plane3& plane) const
+{
+       if ( m_root != NULL )
+         return m_root->simplifiedClassifyFace(p1, p2, p3, plane);
+       else
+         return OUT;
+}
+
+/**
+ * Returns the deep of this BSP tree.
+ * @return tree deep
+ */
+unsigned int BOP_BSPTree::getDeep() const
+{
+       if ( m_root != NULL )
+         return m_root->getDeep();
+       else
+         return 0;
+}
+
+/**
+ * Computes the bounding BSP data.
+ */
+void BOP_BSPTree::computeBox()
+{
+       if ( m_root != NULL ) {
+               MT_Point3 p1(m_bbox.m_minX,m_bbox.m_minY,m_bbox.m_minZ);
+               MT_Point3 p2(m_bbox.m_maxX,m_bbox.m_minY,m_bbox.m_minZ);
+               MT_Point3 p3(m_bbox.m_maxX,m_bbox.m_maxY,m_bbox.m_minZ);
+               MT_Point3 p4(m_bbox.m_minX,m_bbox.m_maxY,m_bbox.m_minZ);
+               MT_Point3 p5(m_bbox.m_minX,m_bbox.m_minY,m_bbox.m_maxZ);
+               MT_Point3 p6(m_bbox.m_maxX,m_bbox.m_minY,m_bbox.m_maxZ);
+               MT_Point3 p7(m_bbox.m_maxX,m_bbox.m_maxY,m_bbox.m_maxZ);
+               MT_Point3 p8(m_bbox.m_minX,m_bbox.m_maxY,m_bbox.m_maxZ);        
+               
+               MT_Plane3 plane1(p3,p2,p1);
+               MT_Plane3 plane2(p5,p6,p7);
+               MT_Plane3 plane3(p1,p2,p6);
+               MT_Plane3 plane4(p8,p7,p3);
+               MT_Plane3 plane5(p2,p3,p7);
+               MT_Plane3 plane6(p1,p5,p8);
+               
+               BOP_BSPNode bsp(plane1);
+               bsp.addFace(p5,p6,p7,plane2);
+               bsp.addFace(p1,p2,p6,plane3);
+               bsp.addFace(p8,p7,p3,plane4);
+               bsp.addFace(p2,p3,p7,plane5);
+               bsp.addFace(p1,p5,p8,plane6);
+       }
+}
+
+/**
+ * Prints debug information.
+ */
+void BOP_BSPTree::print()
+{
+       if ( m_root != NULL )
+               m_root->print( 0 );
+}
+
diff --git a/intern/boolop/intern/BOP_BSPTree.h b/intern/boolop/intern/BOP_BSPTree.h
new file mode 100644 (file)
index 0000000..7e5b5a4
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_BSPTREE_H
+#define BOP_BSPTREE_H
+
+#include "BOP_BSPNode.h"
+#include "BOP_Mesh.h"
+#include "BOP_Tag.h"
+#include "BOP_BBox.h"
+
+class BOP_BSPTree
+{
+protected:
+       BOP_BSPNode* m_root;
+       BOP_BSPNode* m_bspBB;
+       BOP_BBox     m_bbox;
+public:
+       // Construction methods
+       BOP_BSPTree();
+       virtual ~BOP_BSPTree();
+       void addMesh(BOP_Mesh* mesh, BOP_Faces& facesList);
+       void addFace(BOP_Mesh* mesh, BOP_Face* face);
+       virtual void addFace(const MT_Point3& p1, 
+                                                const MT_Point3& p2, 
+                                                const MT_Point3& p3, 
+                                                const MT_Plane3& plane);
+       BOP_TAG classifyFace(const MT_Point3& p1, 
+                                                const MT_Point3& p2, 
+                                                const MT_Point3& p3, 
+                                                const MT_Plane3& plane) const;
+       BOP_TAG filterFace(const MT_Point3& p1, 
+                                          const MT_Point3& p2, 
+                                          const MT_Point3& p3, 
+                                          BOP_Face* face);
+       BOP_TAG simplifiedClassifyFace(const MT_Point3& p1, 
+                                                                  const MT_Point3& p2, 
+                                                                  const MT_Point3& p3, 
+                                                                  const MT_Plane3& plane) const;
+       unsigned int getDeep() const;
+       void computeBox();
+       void print();
+       inline void setRoot(BOP_BSPNode* root) {m_root=root;};
+       inline BOP_BSPNode* getRoot() const {return m_root;};
+};
+
+#endif
+
diff --git a/intern/boolop/intern/BOP_Chrono.h b/intern/boolop/intern/BOP_Chrono.h
new file mode 100644 (file)
index 0000000..5ce64f7
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BOP_CHRONO_H
+#define BOP_CHRONO_H
+
+#include <time.h>
+
+class BOP_Chrono
+{
+private:
+       clock_t m_begin;
+public:
+       BOP_Chrono(){};
+       void start() {m_begin = clock();};
+       float stamp() {
+               clock_t c = clock();
+               clock_t stmp = c - m_begin;
+               m_begin = c;
+               float t = ((float) stmp / (float) CLOCKS_PER_SEC)*1000.0f;
+               return t;
+       };
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_Edge.cpp b/intern/boolop/intern/BOP_Edge.cpp
new file mode 100644 (file)
index 0000000..3141113
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_Edge.h"
+
+/**
+ * Constructs a new edge.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ */
+BOP_Edge::BOP_Edge(BOP_Index v1, BOP_Index v2) 
+{
+       m_vertexs[0] = v1;
+       m_vertexs[1] = v2;
+}
+
+/**
+ * Adds a new face index to this edge.
+ * @param i face index
+ */
+void BOP_Edge::addFace(BOP_Index i) 
+{
+       if (!containsFace(i))
+               m_faces.push_back(i);
+}
+
+/**
+ * Returns if this edge contains the specified face index.
+ * @param i face index
+ * @return true if this edge contains the specified face index, false otherwise
+ */
+bool BOP_Edge::containsFace(BOP_Index i)
+{
+       int pos=0;
+       for(BOP_IT_Indexs it = m_faces.begin();it!=m_faces.end();pos++,it++) {
+               if ((*it) == i)
+               return true;
+       }
+       
+       return false;
+}
+
+/**
+ * Replaces an edge vertex index.
+ * @param oldIndex old vertex index
+ * @param newIndex new vertex index
+ */
+void BOP_Edge::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) 
+{
+       if (m_vertexs[0] == oldIndex) m_vertexs[0] = newIndex;
+       else if (m_vertexs[1] == oldIndex) m_vertexs[1] = newIndex;
+}
+
+
diff --git a/intern/boolop/intern/BOP_Edge.h b/intern/boolop/intern/BOP_Edge.h
new file mode 100644 (file)
index 0000000..abf5dd0
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_EDGE_H
+#define BOP_EDGE_H
+
+#include "BOP_Indexs.h"
+
+class BOP_Edge
+{
+private:
+       BOP_Index  m_vertexs[2];
+       BOP_Indexs m_faces;
+
+       bool containsFace(BOP_Index i);
+
+public:
+       BOP_Edge(BOP_Index v1, BOP_Index v2);
+       inline BOP_Index getVertex1() { return m_vertexs[0];};
+       inline BOP_Index getVertex2() { return m_vertexs[1];};
+       void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex);
+       inline BOP_Index getFace(unsigned int i){return m_faces[i];};
+       inline unsigned int getNumFaces(){return m_faces.size();};
+       inline BOP_Indexs &getFaces(){return m_faces;};
+       void addFace(BOP_Index face);
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_Face.cpp b/intern/boolop/intern/BOP_Face.cpp
new file mode 100644 (file)
index 0000000..80c917f
--- /dev/null
@@ -0,0 +1,416 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_Face.h"
+
+/******************************************************************************/
+/*** BOP_Face                                                               ***/
+/******************************************************************************/
+
+/**
+ * Constructs a new face.
+ * @param plane face plane
+ * @param originalFace index of the original face
+ */
+BOP_Face::BOP_Face(MT_Plane3 plane, BOP_Index originalFace)
+{
+       m_plane        = plane;
+       m_tag          = UNCLASSIFIED;
+       m_originalFace = originalFace;
+}
+
+/**
+ * Inverts this face.
+ */
+void BOP_Face::invert()
+{
+       getPlane().Invert();
+       BOP_Index aux = m_indexs[0];
+       m_indexs[0] = m_indexs[2];
+       m_indexs[2] = aux;
+}
+
+/******************************************************************************/
+/*** BOP_Face                                                              ***/
+/******************************************************************************/
+
+/**
+ * Constructs a new triangle face.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ * @param v3 vertex index
+ * @param plane face plane
+ * @param originalFace index of the original face
+ */
+BOP_Face3::BOP_Face3(BOP_Index v1, BOP_Index v2, BOP_Index v3, MT_Plane3 plane, BOP_Index originalFace): BOP_Face(plane,originalFace) 
+{
+       m_indexs[0] = v1;
+       m_indexs[1] = v2;
+       m_indexs[2] = v3;       
+       m_size = 3;
+}
+
+/**
+ * Returns the relative edge index (1,2,3) for the specified vertex indexs.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ * @param e relative edge index (1,2,3)
+ * @return true if (v1,v2) is an edge of this face, false otherwise
+ */
+bool BOP_Face3::getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e)
+{
+       if (m_indexs[0] == v1) {
+               if (m_indexs[1] == v2) {
+                       e = 1;
+               }
+               else if (m_indexs[2] == v2) {
+                       e = 3;
+               }
+               else
+                 return false;
+       }
+       else if (m_indexs[1] == v1) {
+               if (m_indexs[0] == v2) {
+                       e = 1;
+               }
+               else if (m_indexs[2] == v2) {
+                       e = 2;
+               }
+               else
+                 return false;
+       }
+       else if (m_indexs[2] == v1) {
+               if (m_indexs[0] == v2) {
+                       e = 3;
+               }
+               else if (m_indexs[1] == v2) {
+                       e = 2;
+               }
+               else
+                 return false;
+       }else {
+         return false;
+       }
+       
+       return  true;
+} 
+
+/**
+ * Returns if this face contains the specified vertex index.
+ * @param v vertex index
+ * @return true if this face contains the specified vertex index, false otherwise
+ */
+bool BOP_Face3::containsVertex(BOP_Index v) 
+{
+       return (m_indexs[0] == v || m_indexs[1] == v || m_indexs[2] == v);
+}
+
+/**
+ * Returns the neighbours of the specified vertex index.
+ * @param v vertex index
+ * @param prev previous vertex index
+ * @param next next vertex index
+ * @return true if this face contains the vertex index v, false otherwise
+ */
+bool BOP_Face3::getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next) 
+{
+       if (m_indexs[0] == v) {
+         prev = m_indexs[2];
+         next = m_indexs[1];
+       }
+       else if (m_indexs[1] == v) {
+         prev = m_indexs[0];
+         next = m_indexs[2];
+       }
+        else if (m_indexs[2] == v) {
+         prev = m_indexs[1];
+         next = m_indexs[0];
+       }
+       else return false;
+       
+       return true;
+}
+
+/**
+ * Returns the previous neighbour of the specified vertex index.
+ * @param v vertex index
+ * @param w previous vertex index
+ * @return true if this face contains the specified vertex index, false otherwise
+ */
+bool BOP_Face3::getPreviousVertex(BOP_Index v, BOP_Index &w) 
+{
+       if (m_indexs[0] == v) w = m_indexs[2];
+       else if (m_indexs[1] == v) w = m_indexs[0];
+       else if (m_indexs[2] == v) w = m_indexs[1];
+       else return false;
+       
+       return true;
+}
+
+/**
+ * Returns the next neighbour of the specified vertex index.
+ * @param v vertex index
+ * @param w vertex index
+ * @return true if this face contains the specified vertex index, false otherwise
+ */
+bool BOP_Face3::getNextVertex(BOP_Index v, BOP_Index &w) 
+{
+       if (m_indexs[0] == v) w = m_indexs[1];
+       else if (m_indexs[1] == v) w = m_indexs[2];
+       else if (m_indexs[2] == v) w = m_indexs[0];
+       else return false;
+       
+       return true;
+} 
+
+/**
+ * Replaces a face vertex index.
+ * @param oldIndex old vertex index
+ * @param newIndex new vertex index
+ */
+void BOP_Face3::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex)
+{
+       if (m_indexs[0] == oldIndex) m_indexs[0] = newIndex;
+       else if (m_indexs[1] == oldIndex) m_indexs[1] = newIndex;
+       else if (m_indexs[2] == oldIndex) m_indexs[2] = newIndex;
+}
+
+/******************************************************************************/
+/*** BOP_Face4                                                              ***/
+/******************************************************************************/
+
+/**
+ * Constructs a new quad face.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ * @param v3 vertex index
+ * @param v4 vertex index
+ * @param plane face plane
+ * @param originalFace index of the original face
+ */
+BOP_Face4::BOP_Face4(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, MT_Plane3 plane, 
+                                        BOP_Index originalFace): 
+                                        BOP_Face(plane,originalFace) 
+{
+       m_indexs[0] = v1;
+       m_indexs[1] = v2;
+       m_indexs[2] = v3;
+       m_indexs[3] = v4;
+       
+       m_size = 4;
+}
+
+/**
+ * Returns if this face contains the specified vertex index.
+ * @param v vertex index
+ * @return true if this face contains the specified vertex index, false otherwise
+ */
+bool BOP_Face4::containsVertex(BOP_Index v) 
+{
+       return (m_indexs[0] == v || m_indexs[1] == v || m_indexs[2] == v || m_indexs[3]==v);
+}
+
+/**
+ * Returns the neighbours of the specified vertex index.
+ * @param v vertex index
+ * @param prev previous vertex index
+ * @param next next vertex index
+ * @param opp opposite vertex index
+ * @return true if this face contains the vertex index v, false otherwise
+ */
+bool BOP_Face4::getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next, BOP_Index &opp) 
+{
+       if (m_indexs[0] == v) {
+         prev = m_indexs[3];
+         next = m_indexs[1];
+         opp = m_indexs[2];
+       }
+       else if (m_indexs[1] == v) {
+         prev = m_indexs[0];
+         next = m_indexs[2];
+         opp = m_indexs[3];
+       }
+       else if (m_indexs[2] == v) {
+         prev = m_indexs[1];
+         next = m_indexs[3];
+         opp = m_indexs[0];
+       }
+       else if (m_indexs[3] == v) {
+         prev = m_indexs[2];
+         next = m_indexs[0];
+         opp = m_indexs[1];
+       }
+       else return false;
+
+       return true;
+}
+
+/**
+ * Returns the previous neighbour of the specified vertex index.
+ * @param v vertex index
+ * @param w previous vertex index
+ * @return true if this face contains the specified vertex index, false otherwise
+ */
+bool BOP_Face4::getPreviousVertex(BOP_Index v, BOP_Index &w) 
+{
+       if (m_indexs[0] == v) w = m_indexs[3];
+       else if (m_indexs[1] == v) w = m_indexs[0];
+       else if (m_indexs[2] == v) w = m_indexs[1];
+       else if (m_indexs[3] == v) w = m_indexs[2];
+       else return false;
+
+       return true;
+}
+
+/**
+ * Returns the next neighbour of the specified vertex index.
+ * @param v vertex index
+ * @param w next vertex index
+ * @return true if this face contains the specified vertex index, false otherwise
+ */
+bool BOP_Face4::getNextVertex(BOP_Index v, BOP_Index &w) 
+{
+       if (m_indexs[0] == v) w = m_indexs[1];
+       else if (m_indexs[1] == v) w = m_indexs[2];
+       else if (m_indexs[2] == v) w = m_indexs[3];
+       else if (m_indexs[3] == v) w = m_indexs[0];
+       else return false;
+
+       return true;
+} 
+
+/**
+ * Returns the opposite  neighbour of the specified vertex index.
+ * @param v vertex index
+ * @param w opposite vertex index
+ * @return true if this face contains the specified vertex index, false otherwise
+ */
+bool BOP_Face4::getOppositeVertex(BOP_Index v, BOP_Index &w)
+{
+       if (m_indexs[0] == v) 
+               w = m_indexs[2];
+       else if (m_indexs[1] == v) 
+               w = m_indexs[3];
+       else if (m_indexs[2] == v) 
+               w = m_indexs[0];
+       else if (m_indexs[3] == v) 
+               w = m_indexs[1];
+       else
+         return false;
+
+       return true;
+}
+
+/**
+ * Replaces a face vertex index.
+ * @param oldIndex old vertex index
+ * @param newIndex new vertex index
+ */
+void BOP_Face4::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex)
+{
+       if (m_indexs[0] == oldIndex) m_indexs[0] = newIndex;
+       else if (m_indexs[1] == oldIndex) m_indexs[1] = newIndex;
+       else if (m_indexs[2] == oldIndex) m_indexs[2] = newIndex;
+       else if (m_indexs[3] == oldIndex) m_indexs[3] = newIndex;
+}
+
+/**
+ * Returns the relative edge index (1,2,3,4) for the specified vertex indexs.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ * @param e relative edge index (1,2,3,4)
+ * @return true if (v1,v2) is an edge of this face, false otherwise
+ */
+bool BOP_Face4::getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e)
+{
+       if (m_indexs[0] == v1) {
+               if (m_indexs[1] == v2) {
+                       e = 1;
+               }
+               else if (m_indexs[3] == v2) {
+                       e = 4;
+               }
+               else
+                 return false;
+       }
+       else if (m_indexs[1] == v1) {
+               if (m_indexs[0] == v2) {
+                       e = 1;
+               }
+               else if (m_indexs[2] == v2) {
+                       e = 2;
+               }
+               else
+                 return false;
+       }
+       else if (m_indexs[2] == v1) {
+               if (m_indexs[1] == v2) {
+                       e = 2;
+               }
+               else if (m_indexs[3] == v2) {
+                       e = 3;
+               }
+               else
+                 return false;
+       }
+       else if (m_indexs[3] == v1) {
+               if (m_indexs[2] == v2) {
+                       e = 3;
+               }
+               else if (m_indexs[0] == v2) {
+                       e = 4;
+               }
+               else
+                 return false;
+       }
+       else return false;
+       
+       return  true;
+}  
+
+/**
+ * Implements operator <<.
+ */
+ostream &operator<<(ostream &stream, BOP_Face *f)
+{
+       char aux[20];
+       BOP_stringTAG(f->m_tag,aux);
+       if (f->size()==3) {
+               stream << "Face[" << f->getVertex(0) << "," << f->getVertex(1) << ",";
+               stream << f->getVertex(2) << "] ("  <<  aux  <<  ") <-- " << f->m_originalFace;
+       }
+       else {
+               stream << "Face[" << f->getVertex(0) << "," << f->getVertex(1) << ",";
+               stream << f->getVertex(2) << "," << f->getVertex(3) << "] ("  <<  aux;
+               stream <<  ") <-- " << f->m_originalFace;
+       }
+
+       return stream;
+}
diff --git a/intern/boolop/intern/BOP_Face.h b/intern/boolop/intern/BOP_Face.h
new file mode 100644 (file)
index 0000000..7db5ab1
--- /dev/null
@@ -0,0 +1,105 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_FACE_H
+#define BOP_FACE_H
+
+#include "BOP_Tag.h"
+#include "MT_Plane3.h"
+#include "BOP_Indexs.h"
+#include <iostream>
+#include <vector>
+using namespace std;
+
+class BOP_Face;
+
+typedef vector<BOP_Face *> BOP_Faces;
+typedef vector<BOP_Face *>::iterator BOP_IT_Faces;
+
+class BOP_Face
+{
+private:
+       BOP_TAG      m_tag;
+       MT_Plane3    m_plane;
+       BOP_Index    m_originalFace;
+
+protected:
+       BOP_Index    m_indexs[4];
+       unsigned int m_size;
+
+public:
+       BOP_Face(MT_Plane3 plane, BOP_Index originalFace);
+       virtual ~BOP_Face(){};
+       inline MT_Plane3 getPlane() const {return m_plane;};
+       inline void setPlane(const MT_Plane3 plane) {m_plane = plane;};
+       inline BOP_TAG getTAG() const {return m_tag;};
+       inline void setTAG(const BOP_TAG t) {m_tag = t;};
+       inline BOP_Index getOriginalFace() const {return m_originalFace;};
+       inline void setOriginalFace(const BOP_Index originalFace) {m_originalFace=originalFace;};
+       inline BOP_Index getVertex(unsigned int i) const {return m_indexs[i];};
+       inline void setVertex(const BOP_Index idx, const BOP_Index i) {m_indexs[idx]=i;};
+       void invert();
+       inline unsigned int size() const {return m_size;};
+       
+       virtual bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e) = 0;
+       virtual void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) = 0;
+       virtual bool containsVertex(BOP_Index v) = 0;
+               
+       friend ostream &operator<<(ostream &stream, BOP_Face *f);
+};
+
+class BOP_Face3: public BOP_Face 
+{
+public:
+       BOP_Face3(BOP_Index i, BOP_Index j, BOP_Index k, MT_Plane3 p, BOP_Index originalFace);
+       bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e);
+       void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex);
+       bool containsVertex(BOP_Index v);
+
+       bool getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next);
+       bool getPreviousVertex(BOP_Index v, BOP_Index &w);
+       bool getNextVertex(BOP_Index v, BOP_Index &w);
+};
+
+class BOP_Face4: public BOP_Face 
+{
+public:
+       BOP_Face4(BOP_Index i, BOP_Index j, BOP_Index k, BOP_Index l, MT_Plane3 p, BOP_Index originalFace);
+       bool getEdgeIndex(BOP_Index v1, BOP_Index v2, unsigned int &e);
+       void replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex);
+       bool containsVertex(BOP_Index v);
+
+       bool getNeighbours(BOP_Index v, BOP_Index &prev, BOP_Index &next, BOP_Index &opp);
+       bool getPreviousVertex(BOP_Index v, BOP_Index &w);
+       bool getNextVertex(BOP_Index v, BOP_Index &w);
+       bool getOppositeVertex(BOP_Index v, BOP_Index &w);
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_Face2Face.cpp b/intern/boolop/intern/BOP_Face2Face.cpp
new file mode 100644 (file)
index 0000000..6d7c671
--- /dev/null
@@ -0,0 +1,1270 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_Face2Face.h"
+#include "BOP_BBox.h"
+
+// TAGS for segment classification in x-segment creation
+// sA -> point of sA
+// sB -> point of sB
+// sX -> point of sA and SB
+#define sA_sB 12
+#define sB_sA 21
+#define sX_sA 31
+#define sA_sX 13
+#define sX_sB 32
+#define sB_sX 23
+#define sX_sX 33
+    
+#define sA_sA_sB 112
+#define sB_sB_sA 221
+#define sB_sA_sA 211
+#define sA_sB_sB 122
+#define sA_sB_sA 121
+#define sB_sA_sB 212
+#define sA_sX_sB 132
+#define sB_sX_sA 231
+#define sX_sA_sB 312
+#define sX_sB_sA 321
+#define sA_sB_sX 123
+#define sB_sA_sX 213
+
+#define sA_sA_sB_sB 1122
+#define sB_sB_sA_sA 2211
+#define sA_sB_sA_sB 1212
+#define sB_sA_sB_sA 2121
+#define sA_sB_sB_sA 1221
+#define sB_sA_sA_sB 2112
+
+void BOP_intersectCoplanarFaces(BOP_Mesh*  mesh, 
+                                                               BOP_Faces* facesB, 
+                                                               BOP_Face*  faceA, 
+                                                               BOP_Face*  faceB, 
+                                                               bool       invert);
+
+void BOP_intersectCoplanarFaces(BOP_Mesh*   mesh, 
+                                                               BOP_Faces*  facesB, 
+                                                               BOP_Face*   faceB, 
+                                                               BOP_Segment sA, 
+                                                               MT_Plane3   planeA, 
+                                                               bool        invert);
+
+void BOP_intersectNonCoplanarFaces(BOP_Mesh*  mesh, 
+                                                                  BOP_Faces* facesA,  
+                                                                  BOP_Faces* facesB, 
+                                                                  BOP_Face*  faceA, 
+                                                                  BOP_Face*  faceB);
+
+void BOP_getPoints(BOP_Mesh*    mesh, 
+                                  BOP_Face*    faceA, 
+                                  BOP_Segment& sA, 
+                                  MT_Plane3    planeB, 
+                                  MT_Point3*   points, 
+                                  unsigned int*         faces, 
+                                  unsigned int&         size, 
+                                  unsigned int         faceValue);
+
+void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bool &invertA, bool &invertB);
+
+void BOP_createXS(BOP_Mesh*    mesh, 
+                                 BOP_Face*    faceA, 
+                                 BOP_Face*    faceB, 
+                                 BOP_Segment  sA, 
+                                 BOP_Segment  sB, 
+                                 bool         invert, 
+                                 BOP_Segment* segments);    
+
+void BOP_createXS(BOP_Mesh*    mesh, 
+                                 BOP_Face*    faceA, 
+                                 BOP_Face*    faceB, 
+                                 MT_Plane3    planeA, 
+                                 MT_Plane3    planeB, 
+                                 BOP_Segment  sA, 
+                                 BOP_Segment  sB, 
+                                 bool         invert, 
+                                 BOP_Segment* segments);    
+
+BOP_Index BOP_getVertexIndex(BOP_Mesh* mesh, 
+                                          MT_Point3 point, 
+                                          unsigned int       cfgA, 
+                                          unsigned int       cfgB, 
+                                          BOP_Index       vA, 
+                                          BOP_Index       vB, 
+                                          bool      invert);
+
+BOP_Index BOP_getVertexIndex(BOP_Mesh *mesh, MT_Point3 point, unsigned int cfg, BOP_Index v);
+
+void triangulate(BOP_Mesh *mesh,  BOP_Faces *faces, BOP_Face *face, BOP_Segment s);
+
+BOP_Face *BOP_getOppositeFace(BOP_Mesh*  mesh, 
+                                                         BOP_Faces* faces, 
+                                                         BOP_Face*  face, 
+                                                         BOP_Edge*  edge);
+
+bool BOP_overlap(MT_Vector3 normal, 
+                                MT_Point3  p1, 
+                                MT_Point3  p2, 
+                                MT_Point3  p3, 
+                                MT_Point3  q1, 
+                                MT_Point3  q2, 
+                                MT_Point3  q3);
+
+void BOP_mergeVertexs(BOP_Mesh *mesh, unsigned int firstFace);
+
+
+/**
+ * Computes intersections between faces of both lists.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param facesA set of faces from object A
+ * @param facesB set of faces from object B
+ */
+void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB)
+{              
+       for(unsigned int idxFaceA=0;idxFaceA<facesA->size();idxFaceA++) {
+               BOP_Face *faceA = (*facesA)[idxFaceA];
+               MT_Plane3 planeA = faceA->getPlane();
+               MT_Point3 p1 = mesh->getVertex(faceA->getVertex(0))->getPoint();
+               MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint();
+               MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint();
+
+               BOP_BBox boxA(p1,p2,p3);
+       
+               for(unsigned int idxFaceB=0;
+                       idxFaceB<facesB->size() && (faceA->getTAG() != BROKEN) && (faceA->getTAG() != PHANTOM);) {
+                       BOP_Face *faceB = (*facesB)[idxFaceB];
+                       if ((faceB->getTAG() != BROKEN) && (faceB->getTAG() != PHANTOM)) {
+                         BOP_BBox boxB(mesh->getVertex(faceB->getVertex(0))->getPoint(),
+                                       mesh->getVertex(faceB->getVertex(1))->getPoint(),
+                                       mesh->getVertex(faceB->getVertex(2))->getPoint());
+                         if (boxA.intersect(boxB)) {
+
+                           MT_Plane3 planeB = faceB->getPlane();
+                           if (BOP_containsPoint(planeB,p1) && 
+                               BOP_containsPoint(planeB,p2) && 
+                               BOP_containsPoint(planeB,p3)) {
+                             if (BOP_orientation(planeB,planeA)>0) {
+                               BOP_intersectCoplanarFaces(mesh,facesB,faceA,faceB,false);
+                             }
+                           }
+                           else {
+                             BOP_intersectNonCoplanarFaces(mesh,facesA,facesB,faceA,faceB);
+                           }
+                         }                       
+                       }
+                       if (faceB->getTAG()==BROKEN){
+                         facesB->erase(facesB->begin()+idxFaceB);
+                       }else
+                         idxFaceB++;
+               }
+       }
+       
+       
+       // Clean broken faces from facesA
+       BOP_IT_Faces it;
+       it = facesA->begin();
+       while (it != facesA->end()) {
+               BOP_Face *face = *it;
+               if (face->getTAG() == BROKEN) it = facesA->erase(it);
+               else it++;
+       }
+       /*
+       it = facesB->begin();
+       while (it != facesB->end()) {
+               BOP_Face *face = *it;
+               if (face->getTAG() == BROKEN) it = facesB->erase(it);
+               else it++;
+       }
+       */
+}
+
+/**
+ * Computes intesections of coplanars faces from object A with faces from object B.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param facesA set of faces from object A
+ * @param facesB set of faces from object B
+ */
+void BOP_sew(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB)
+{
+       for(unsigned int idxFaceB = 0; idxFaceB < facesB->size(); idxFaceB++) {
+               BOP_Face *faceB = (*facesB)[idxFaceB];
+               MT_Plane3 planeB = faceB->getPlane();
+               MT_Point3 p1 = mesh->getVertex(faceB->getVertex(0))->getPoint();
+               MT_Point3 p2 = mesh->getVertex(faceB->getVertex(1))->getPoint();
+               MT_Point3 p3 = mesh->getVertex(faceB->getVertex(2))->getPoint();
+               
+               for(unsigned int idxFaceA = 0;
+                       idxFaceA < facesA->size() &&
+                       faceB->getTAG() != BROKEN &&
+                       faceB->getTAG() != PHANTOM;
+                       idxFaceA++) {
+                       BOP_Face *faceA = (*facesA)[idxFaceA];
+                       if ((faceA->getTAG() != BROKEN)&&(faceA->getTAG() != PHANTOM)) {
+                               MT_Plane3 planeA = faceA->getPlane();
+                               if (BOP_containsPoint(planeA,p1) && 
+                                       BOP_containsPoint(planeA,p2) && 
+                                       BOP_containsPoint(planeA,p3)) {
+                                       if (BOP_orientation(planeA,planeB) > 0) {
+                                               BOP_intersectCoplanarFaces(mesh,facesA,faceB,faceA,true);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+/**
+ * Triangulates faceB using edges of faceA that both are complanars.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param facesB set of faces from object B
+ * @param faceA face from object A
+ * @param faceB face from object B
+ * @param invert indicates if faceA has priority over faceB
+ */
+void BOP_intersectCoplanarFaces(BOP_Mesh*  mesh,
+                                                               BOP_Faces* facesB, 
+                                                               BOP_Face*  faceA, 
+                                                               BOP_Face*  faceB, 
+                                                               bool       invert)
+{
+       unsigned int oldSize = facesB->size();
+       unsigned int originalFaceB = faceB->getOriginalFace();    
+       
+       MT_Point3 p1 = mesh->getVertex(faceA->getVertex(0))->getPoint();
+       MT_Point3 p2 = mesh->getVertex(faceA->getVertex(1))->getPoint();
+       MT_Point3 p3 = mesh->getVertex(faceA->getVertex(2))->getPoint();
+       
+       MT_Vector3 normal(faceA->getPlane().x(),faceA->getPlane().y(),faceA->getPlane().z());
+       
+       MT_Vector3 p1p2 = p2-p1;
+       
+       MT_Plane3 plane1((p1p2.cross(normal).normalized()),p1);
+       
+       BOP_Segment sA;
+       sA.m_cfg1 = BOP_Segment::createVertexCfg(1);
+       sA.m_v1 = faceA->getVertex(0);
+       sA.m_cfg2 = BOP_Segment::createVertexCfg(2);
+       sA.m_v2 = faceA->getVertex(1);
+       
+       BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane1,invert);
+       
+       MT_Vector3 p2p3 = p3-p2;
+       MT_Plane3 plane2((p2p3.cross(normal).normalized()),p2);
+       
+       sA.m_cfg1 = BOP_Segment::createVertexCfg(2);
+       sA.m_v1 = faceA->getVertex(1);
+       sA.m_cfg2 = BOP_Segment::createVertexCfg(3);
+       sA.m_v2 = faceA->getVertex(2);
+  
+       if (faceB->getTAG() == BROKEN) {
+               for(unsigned int idxFace = oldSize; idxFace < facesB->size(); idxFace++) {
+                       BOP_Face *face = (*facesB)[idxFace];
+                       if (face->getTAG() != BROKEN && originalFaceB == face->getOriginalFace())
+                               BOP_intersectCoplanarFaces(mesh,facesB,face,sA,plane2,invert);
+               }
+       }
+       else {
+               BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane2,invert);
+       }
+  
+       MT_Vector3 p3p1 = p1-p3;
+       MT_Plane3 plane3((p3p1.cross(normal).normalized()),p3);
+       
+       sA.m_cfg1 = BOP_Segment::createVertexCfg(3);
+       sA.m_v1 = faceA->getVertex(2);
+       sA.m_cfg2 = BOP_Segment::createVertexCfg(1);
+       sA.m_v2 = faceA->getVertex(0);
+  
+       if (faceB->getTAG() == BROKEN) {
+               for(unsigned int idxFace = oldSize; idxFace < facesB->size(); idxFace++) {
+                       BOP_Face *face = (*facesB)[idxFace];
+                       if (face->getTAG() != BROKEN && originalFaceB == face->getOriginalFace())
+                               BOP_intersectCoplanarFaces(mesh,facesB,face,sA,plane3,invert);
+               }
+       }
+       else {
+               BOP_intersectCoplanarFaces(mesh,facesB,faceB,sA,plane3,invert);
+       } 
+}
+
+/**
+ * Triangulates faceB using segment sA and planeA.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param facesB set of faces from object B
+ * @param faceB face from object B
+ * @param sA segment to intersect with faceB
+ * @param planeA plane to intersect with faceB
+ * @param invert indicates if sA has priority over faceB
+ */
+void BOP_intersectCoplanarFaces(BOP_Mesh*   mesh, 
+                                                               BOP_Faces*  facesB, 
+                                                               BOP_Face*   faceB, 
+                                                               BOP_Segment sA, 
+                                                               MT_Plane3   planeA, 
+                                                               bool        invert)
+{
+       BOP_Segment sB = BOP_splitFace(planeA,mesh,faceB);
+
+       if (BOP_Segment::isDefined(sB.m_cfg1)) {
+               BOP_Segment xSegment[2];
+               BOP_createXS(mesh,NULL,faceB,planeA,MT_Plane3(),sA,sB,invert,xSegment);
+               if (BOP_Segment::isDefined(xSegment[1].m_cfg1)) {
+                       unsigned int sizefaces = mesh->getNumFaces();
+                       triangulate(mesh,facesB,faceB,xSegment[1]);
+                       BOP_mergeVertexs(mesh,sizefaces);
+               }
+       }
+}
+
+/**
+ * Triangulates faceB using edges of faceA that both are not complanars.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param facesB set of faces from object B
+ * @param faceA face from object A
+ * @param faceB face from object B
+ */
+void BOP_intersectNonCoplanarFaces(BOP_Mesh *mesh, 
+                                                                  BOP_Faces *facesA, 
+                                                                  BOP_Faces *facesB, 
+                                                                  BOP_Face *faceA, 
+                                                                  BOP_Face *faceB)
+{
+       // Obtain segments of faces A and B from the intersection with their planes
+       BOP_Segment sA = BOP_splitFace(faceB->getPlane(),mesh,faceA);
+       BOP_Segment sB = BOP_splitFace(faceA->getPlane(),mesh,faceB);
+       
+       if (BOP_Segment::isDefined(sA.m_cfg1) && BOP_Segment::isDefined(sB.m_cfg1)) {    
+               // There is an intesection, build the X-segment
+               BOP_Segment xSegment[2];
+               BOP_createXS(mesh,faceA,faceB,sA,sB,false,xSegment);
+               
+               unsigned int sizefaces = mesh->getNumFaces();
+               triangulate(mesh,facesA,faceA,xSegment[0]);
+               BOP_mergeVertexs(mesh,sizefaces);
+       
+               sizefaces = mesh->getNumFaces();
+               triangulate(mesh,facesB,faceB,xSegment[1]);
+               BOP_mergeVertexs(mesh,sizefaces);
+       }
+}
+
+/**
+ * Tests if faces since firstFace have all vertexs non-coincident of colinear, otherwise repairs the mesh.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param firstFace first face index to be tested
+ */
+void BOP_mergeVertexs(BOP_Mesh *mesh, unsigned int firstFace)
+{
+       unsigned int numFaces = mesh->getNumFaces();
+       for(unsigned int idxFace = firstFace; idxFace < numFaces; idxFace++) {
+               BOP_Face *face = mesh->getFace(idxFace);
+               if ((face->getTAG() != BROKEN) && (face->getTAG() != PHANTOM)) {
+                       BOP_Index v1 = face->getVertex(0);
+                       BOP_Index v2 = face->getVertex(1);
+                       BOP_Index v3 = face->getVertex(2);
+                       MT_Point3 vertex1 = mesh->getVertex(v1)->getPoint();
+                       MT_Point3 vertex2 = mesh->getVertex(v2)->getPoint();
+                       MT_Point3 vertex3 = mesh->getVertex(v3)->getPoint();
+                       int dist12 = BOP_comp(vertex1,vertex2);
+                       int dist13 = BOP_comp(vertex1,vertex3);
+                       int dist23 = BOP_comp(vertex2,vertex3);
+
+                       if (dist12 == 0) {
+                               if (dist13 == 0) {
+                                       // v1 ~= v2 , v1 ~= v3 , v2 ~= v3
+                                       mesh->replaceVertexIndex(v2,v1);
+                                       mesh->replaceVertexIndex(v3,v1);                
+                               }
+                               else {
+                                       if (dist23 == 0) {
+                                               mesh->replaceVertexIndex(v1,v2);
+                                               mesh->replaceVertexIndex(v3,v2);
+                                       }
+                                       else {
+                                               mesh->replaceVertexIndex(v1,v2);
+                                       }
+                               }
+                       }
+                       else {
+                               if (dist13 == 0) {
+                                       // v1 ~= v3
+                                       if (dist23 == 0) {
+                                               mesh->replaceVertexIndex(v1,v3);
+                                               mesh->replaceVertexIndex(v2,v3);
+                                       }
+                                       else {
+                                               mesh->replaceVertexIndex(v1,v3);
+                                       }
+                               }
+                               else {
+                                       if (dist23 == 0) {
+                                               // v2 ~= v3
+                                               mesh->replaceVertexIndex(v2,v3);
+                                       } else {
+                                               // all differents
+                                               if (BOP_collinear(vertex1,vertex2,vertex3)) {
+                                                       // collinear triangle 
+                                                       face->setTAG(PHANTOM);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+/**
+ * Obtains the points of the segment created from the intersection between faceA and planeB.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faceA intersected face
+ * @param sA segment of the intersection between  faceA and planeB
+ * @param planeB intersected plane
+ * @param points array of points where the new points are saved
+ * @param faces array of relative face index to the points
+ * @param size size of arrays points and faces
+ * @param faceValue relative face index of new points
+ */
+void BOP_getPoints(BOP_Mesh*    mesh, 
+                                  BOP_Face*    faceA, 
+                                  BOP_Segment& sA, 
+                                  MT_Plane3    planeB, 
+                                  MT_Point3*   points, 
+                                  unsigned int*         faces, 
+                                  unsigned int&         size, 
+                                  unsigned int          faceValue) 
+{
+       MT_Point3 p1,p2;  
+  
+       if (BOP_Segment::isDefined(sA.m_cfg1)) {
+               if (BOP_Segment::isEdge(sA.m_cfg1)) {
+                       // the new point becomes of split faceA edge 
+                       p1 = BOP_splitEdge(planeB,mesh,faceA,BOP_Segment::getEdge(sA.m_cfg1));
+               }
+               else if (BOP_Segment::isVertex(sA.m_cfg1)) {
+                       // the new point becomes of vertex faceA
+                       p1 =  mesh->getVertex(BOP_Segment::getVertex(sA.m_v1))->getPoint();
+               }
+
+               if (BOP_Segment::isDefined(sA.m_cfg2)) {
+                       if (BOP_Segment::isEdge(sA.m_cfg2)) {
+                               p2 = BOP_splitEdge(planeB,mesh,faceA,BOP_Segment::getEdge(sA.m_cfg2));
+                       }
+                       else if (BOP_Segment::isVertex(sA.m_cfg2)) { 
+                               p2 =  mesh->getVertex(BOP_Segment::getVertex(sA.m_v2))->getPoint();
+                       }
+                       points[size] = p1;
+                       points[size+1] = p2;
+                       faces[size] = faceValue;
+                       faces[size+1] = faceValue;
+                       size += 2;
+               }
+       
+               else {
+                       points[size] = p1;
+                       faces[size] = faceValue;
+                       size++;
+               }
+       }
+}
+
+/**
+ * Sorts the colinear points and relative face indices.
+ * @param points array of points where the new points are saved
+ * @param faces array of relative face index to the points
+ * @param size size of arrays points and faces
+ * @param invertA indicates if points of same relative face had been exchanged
+ */
+void BOP_mergeSort(MT_Point3 *points, unsigned int *face, unsigned int &size, bool &invertA, bool &invertB) {
+  MT_Point3 sortedPoints[4];
+  unsigned int sortedFaces[4];
+  unsigned int position[4];
+  if (size == 2) {
+
+    // Trivial case, only test the merge ...
+    if (BOP_comp(0,points[0].distance(points[1]))==0) {
+      face[0] = 3;
+      size--;
+    }
+  }
+  else {
+    // size is 3 or 4
+    // Get segment extreme points
+    MT_Scalar maxDistance = -1;
+    for(unsigned int i=0;i<size-1;i++){
+      for(unsigned int j=i+1;j<size;j++){
+        MT_Scalar distance = points[i].distance(points[j]);
+        if (distance > maxDistance){
+          maxDistance = distance;
+          position[0] = i;
+          position[size-1] = j;
+        }
+      }
+    }
+
+    // Get segment inner points
+    position[1] = position[2] = size;
+    for(unsigned int i=0;i<size;i++){
+      if ((i != position[0]) && (i != position[size-1])){
+        if (position[1] == size) position[1] = i;
+        else position[2] = i;
+      }
+    }
+
+    // Get inner points
+    if (position[2] < size) {
+      MT_Scalar d1 = points[position[1]].distance(points[position[0]]);
+      MT_Scalar d2 = points[position[2]].distance(points[position[0]]);
+      if (d1 > d2) {
+        unsigned int aux = position[1];
+        position[1] = position[2];
+        position[2] = aux;
+      }
+    }
+
+    // Sort data
+    for(unsigned int i=0;i<size;i++) {
+      sortedPoints[i] = points[position[i]];
+      sortedFaces[i] = face[position[i]];
+    }
+
+    // invertA, invertB ¿?
+    invertA = false;
+    invertB = false;
+    if (face[1] == 1) {
+      // invertA¿?
+      for(unsigned int i=0;i<size;i++) {
+        if (position[i] == 1) {
+          invertA = true;
+          break;
+        }
+        else if (position[i] == 0) break;
+      }
+      // invertB¿?
+      if (size == 4) {
+        for(unsigned int i=0;i<size;i++) {
+          if (position[i] == 3) {
+            invertB = true;
+            break;
+          }
+          else if (position[i] == 2) break;
+        }
+      }
+    }
+    else if (face[1] == 2) {
+      // invertB¿?
+      for(unsigned int i=0;i<size;i++) {
+        if (position[i] == 2) {
+          invertB = true;
+          break;
+        }
+        else if (position[i] == 1) break;
+      }
+    }
+
+
+    // Merge data
+    MT_Scalar d1 = sortedPoints[1].distance(sortedPoints[0]);
+    MT_Scalar d2 = sortedPoints[1].distance(sortedPoints[2]);
+    if (BOP_comp(0,d1)==0 && sortedFaces[1] != sortedFaces[0]) {
+      if (BOP_comp(0,d2)==0 && sortedFaces[1] != sortedFaces[2])  {
+        if (d1 < d2) {
+          // merge 0 and 1
+          sortedFaces[0] = 3;
+          for(unsigned int i = 1; i<size-1;i++) {
+            sortedPoints[i] = sortedPoints[i+1];
+            sortedFaces[i] = sortedFaces[i+1];
+          }
+          size--;
+          if (size == 3) {
+            // merge 1 and 2 ???
+            d1 = sortedPoints[1].distance(sortedPoints[2]);
+            if (BOP_comp(0,d1)==0 && sortedFaces[1] != sortedFaces[2])  {
+              // merge!
+              sortedFaces[1] = 3;
+              size--;
+            }
+          }
+        }
+        else {
+          // merge 1 and 2
+          sortedFaces[1] = 3;
+          for(unsigned int i = 2; i<size-1;i++) {
+            sortedPoints[i] = sortedPoints[i+1];
+            sortedFaces[i] = sortedFaces[i+1];
+          }
+          size--;
+        }        
+      }
+      else {
+        // merge 0 and 1
+        sortedFaces[0] = 3;
+        for(unsigned int i = 1; i<size-1;i++) {
+          sortedPoints[i] = sortedPoints[i+1];
+          sortedFaces[i] = sortedFaces[i+1];
+        }
+        size--;
+        if (size == 3) {
+          // merge 1 i 2 ???
+          d1 = sortedPoints[1].distance(sortedPoints[2]);
+          if (BOP_comp(0,d1)==0 && sortedFaces[1] != sortedFaces[2])  {
+            // merge!
+            sortedFaces[1] = 3;
+            size--;
+          }
+        }
+      }     
+    }
+    else {
+      if (BOP_comp(0,d2)==0 && sortedFaces[1] != sortedFaces[2])  {
+        // merge 1 and 2
+        sortedFaces[1] = 3;
+        for(unsigned int i = 2; i<size-1;i++) {
+          sortedPoints[i] = sortedPoints[i+1];
+          sortedFaces[i] = sortedFaces[i+1];
+        }
+        size--;
+      }
+      else if (size == 4) {
+        d1 = sortedPoints[2].distance(sortedPoints[3]);
+        if (BOP_comp(0,d1)==0 && sortedFaces[2] != sortedFaces[3])  {
+          // merge 2 and 3
+          sortedFaces[2] = 3;
+          size--;
+        }
+      }
+    }
+    
+    // Merge initial points ...
+    for(unsigned int i=0;i<size;i++) {
+      points[i] = sortedPoints[i];
+      face[i] = sortedFaces[i];
+    }
+
+  }
+}  
+
+
+/**
+ * Computes the x-segment of two segments (the shared interval). The segments needs to have sA.m_cfg1 > 0 && sB.m_cfg1 > 0 .
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faceA face of object A
+ * @param faceB face of object B
+ * @param sA segment of intersection between faceA and planeB
+ * @param sB segment of intersection between faceB and planeA
+ * @param invert indicates if faceA has priority over faceB
+ * @param segmemts array of the output x-segments
+ */
+void BOP_createXS(BOP_Mesh*    mesh, 
+                                 BOP_Face*    faceA, 
+                                 BOP_Face*    faceB, 
+                                 BOP_Segment  sA, 
+                                 BOP_Segment  sB, 
+                                 bool         invert, 
+                                 BOP_Segment* segments) {    
+       return BOP_createXS(mesh, faceA, faceB, faceA->getPlane(), faceB->getPlane(),
+                                               sA, sB, invert, segments);
+}
+
+/**
+ * Computes the x-segment of two segments (the shared interval). The segments needs to have sA.m_cfg1 > 0 && sB.m_cfg1 > 0 .
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faceA face of object A
+ * @param faceB face of object B
+ * @param planeA plane of faceA
+ * @param planeB plane of faceB
+ * @param sA segment of intersection between faceA and planeB
+ * @param sB segment of intersection between faceB and planeA
+ * @param invert indicates if faceA has priority over faceB
+ * @param segmemts array of the output x-segments
+ */
+void BOP_createXS(BOP_Mesh*    mesh, 
+                                 BOP_Face*    faceA, 
+                                 BOP_Face*    faceB, 
+                                 MT_Plane3    planeA, 
+                                 MT_Plane3    planeB, 
+                                 BOP_Segment  sA, 
+                                 BOP_Segment  sB, 
+                                 bool         invert, 
+                                 BOP_Segment* segments)
+{    
+       MT_Point3 points[4];  // points of the segments
+       unsigned int face[4]; // relative face indexs (1 => faceA, 2 => faceB)
+       unsigned int size = 0;  // size of points and relative face indexs
+  
+       BOP_getPoints(mesh, faceA, sA, planeB, points, face, size, 1);
+       BOP_getPoints(mesh, faceB, sB, planeA, points, face, size, 2);
+
+       bool invertA = false;
+       bool invertB = false;
+       BOP_mergeSort(points,face,size,invertA,invertB);
+
+       if (invertA) sA.invert();
+       if (invertB) sB.invert();
+       
+       // Compute the configuration label
+       unsigned int label = 0;
+       for(unsigned int i =0; i < size; i++) {
+               label = face[i]+label*10;    
+       }
+
+       if (size == 1) {
+               // Two coincident points
+               segments[0].m_cfg1 = sA.m_cfg1;
+               segments[1].m_cfg1 = sB.m_cfg1;
+               
+               segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1,
+                                                                                         sA.m_v1, sB.m_v1, invert);
+               segments[1].m_v1 = segments[0].m_v1;
+               segments[0].m_cfg2 = segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+       }
+       else if (size == 2) {
+               switch(label) {
+               // Two non-coincident points
+               case sA_sB:
+               case sB_sA:
+                       segments[0].m_cfg1 = 
+                       segments[1].m_cfg1 = 
+                       segments[0].m_cfg2 = 
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+      
+               // Two coincident points and one non-coincident of sA
+               case sA_sX:
+                       segments[0].m_cfg1 = sA.m_cfg2;
+                       segments[1].m_cfg1 = sB.m_cfg1;
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg1,
+                                                                                                 sA.m_v2, sB.m_v1, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+               case sX_sA:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.m_cfg1;
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1,
+                                                                                                 sA.m_v1, sB.m_v1, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+      
+               // Two coincident points and one non-coincident of sB
+               case sB_sX:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.m_cfg2;
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg1, sB.m_cfg2, 
+                                                                                                 sA.m_v1, sB.m_v2, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+               case sX_sB:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.m_cfg1;
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, 
+                                                                                                 sA.m_v1, sB.m_v1, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+               
+                       segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+      
+               // coincident points 2-2
+               case sX_sX:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.m_cfg1;          
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1, 
+                                                                                                 sA.m_v1, sB.m_v1, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = sA.m_cfg2;
+                       segments[1].m_cfg2 = sB.m_cfg2;          
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg2, 
+                                                                                                 sA.m_v2, sB.m_v2, invert);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;
+               
+               default:
+                       break; 
+               }
+       }
+       else if (size == 3) {
+               switch(label) {
+               case sA_sA_sB:
+               case sB_sA_sA:
+               case sA_sB_sB:
+               case sB_sB_sA:
+                       segments[0].m_cfg1 = 
+                       segments[1].m_cfg1 = 
+                       segments[0].m_cfg2 = 
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+      
+               case sA_sB_sA:
+                       segments[1].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1);
+                       segments[1].m_cfg1 = sB.m_cfg1;
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[0].m_cfg1 = sA.getConfig();
+                       segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[0].m_v1 = segments[1].m_v1;
+                       break;
+      
+               case sB_sA_sB:
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1);
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[1].m_cfg1 = sB.getConfig();
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[1].m_v1 = segments[0].m_v1;
+                       break;
+      
+               case sA_sX_sB:
+                       segments[0].m_cfg1 = sA.m_cfg2;
+                       segments[1].m_cfg1 = sB.m_cfg1;          
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sB.m_cfg1, 
+                                                                                                 sA.m_v2, sB.m_v1, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+    
+               case sB_sX_sA:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.m_cfg2;          
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg1, sB.m_cfg2, 
+                                                                                                 sA.m_v1, sB.m_v2, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       segments[0].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+      
+               case sX_sA_sB:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.m_cfg1;          
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1,
+                                                                                                 sA.m_v1, sB.m_v1, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = sA.m_cfg2;
+                       segments[1].m_cfg2 = sB.getConfig();
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh, points[1], sA.m_cfg2, sA.m_v2);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;
+      
+               case sX_sB_sA:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.m_cfg1;          
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh, points[0], sA.m_cfg1, sB.m_cfg1,
+                                                                                                 sA.m_v1, sB.m_v1, invert);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = sA.getConfig();
+                       segments[1].m_cfg2 = sB.m_cfg2;
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg2,sB.m_v2);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;
+      
+               case sA_sB_sX:
+                       segments[0].m_cfg1 = sA.getConfig();
+                       segments[1].m_cfg1 = sB.m_cfg1;
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = sA.m_cfg2;
+                       segments[1].m_cfg2 = sB.m_cfg2;          
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh, points[2], sA.m_cfg2, sB.m_cfg2, 
+                                                                                                 sA.m_v2, sB.m_v2, invert);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;
+
+               case sB_sA_sX:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.getConfig();
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = sA.m_cfg2;
+                       segments[1].m_cfg2 = sB.m_cfg2;          
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh, points[2], sA.m_cfg2, sB.m_cfg2,
+                                                                                                 sA.m_v2, sB.m_v2, invert);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;
+      
+               default:
+                       break; 
+               }
+       }
+       else {
+               // 4!
+               switch(label) {
+               case sA_sA_sB_sB:
+               case sB_sB_sA_sA:
+                       segments[0].m_cfg1 = 
+                       segments[1].m_cfg1 = 
+                       segments[0].m_cfg2 = 
+                       segments[1].m_cfg2 = BOP_Segment::createUndefinedCfg();
+                       break;
+      
+               case sA_sB_sA_sB:
+                       segments[0].m_cfg1 = sA.getConfig();
+                       segments[1].m_cfg1 = sB.m_cfg1;
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = sA.m_cfg2;
+                       segments[1].m_cfg2 = sB.getConfig();
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sA.m_cfg2,sA.m_v2);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;          
+      
+               case sB_sA_sB_sA:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.getConfig();
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = sA.getConfig();
+                       segments[1].m_cfg2 = sB.m_cfg2;
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sB.m_cfg2,sB.m_v2);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;          
+      
+               case sA_sB_sB_sA:
+                       segments[0].m_cfg1 = sA.getConfig();
+                       segments[1].m_cfg1 = sB.m_cfg1;
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sB.m_cfg1,sB.m_v1);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = segments[0].m_cfg1;
+                       segments[1].m_cfg2 = sB.m_cfg2;
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sB.m_cfg2,sB.m_v2);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;
+      
+               case sB_sA_sA_sB:
+                       segments[0].m_cfg1 = sA.m_cfg1;
+                       segments[1].m_cfg1 = sB.getConfig();
+                       segments[0].m_v1 = BOP_getVertexIndex(mesh,points[1],sA.m_cfg1,sA.m_v1);
+                       segments[1].m_v1 = segments[0].m_v1;
+                       
+                       segments[0].m_cfg2 = sA.m_cfg2;
+                       segments[1].m_cfg2 = segments[1].m_cfg1;
+                       segments[0].m_v2 = BOP_getVertexIndex(mesh,points[2],sA.m_cfg2,sA.m_v2);
+                       segments[1].m_v2 = segments[0].m_v2;
+                       break;
+      
+               default:
+                       break; 
+               }
+       }
+       
+       segments[0].sort();
+       segments[1].sort();
+}
+
+/**
+ * Computes the vertex index of a point.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param point input point
+ * @param cfgA configuration of point on faceA
+ * @param cfgB configuration of point on faceB
+ * @param vA vertex index of point on faceA
+ * @param vB vertex index of point on faceB
+ * @param invert indicates if vA has priority over vB
+ * @return final vertex index in the mesh
+ */
+BOP_Index BOP_getVertexIndex(BOP_Mesh* mesh, 
+                                          MT_Point3 point, 
+                                          unsigned int       cfgA, 
+                                          unsigned int       cfgB, 
+                                          BOP_Index       vA, 
+                                          BOP_Index       vB, 
+                                          bool      invert)
+{
+       if (BOP_Segment::isVertex(cfgA)) { // exists vertex index on A
+               if (BOP_Segment::isVertex(cfgB)) { // exists vertex index on B
+                       // unify vertex indexs
+                       if (invert)
+                               return mesh->replaceVertexIndex(vA,vB);
+                       else 
+                               return mesh->replaceVertexIndex(vB,vA);
+               }
+               else
+                       return vA;
+       }
+       else {// does not exist vertex index on A
+               if (BOP_Segment::isVertex(cfgB)) // exists vertex index on B
+                       return vB;      
+               else {// does not exist vertex index on B
+                       return mesh->addVertex(point);
+               }
+       } 
+}
+
+/**
+ * Computes the vertex index of a point.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param cfg configuration of point
+ * @param v vertex index of point
+ * @return final vertex index in the mesh
+ */
+BOP_Index BOP_getVertexIndex(BOP_Mesh *mesh, MT_Point3 point, unsigned int cfg, BOP_Index v)
+{
+       if (BOP_Segment::isVertex(cfg)) // vertex existent
+               return v;       
+       else {
+               return mesh->addVertex(point);
+       }
+}
+
+/******************************************************************************/
+/*** TRIANGULATE                                                            ***/
+/******************************************************************************/
+
+/**
+ * Triangulates the input face according to the specified segment.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains the original face and the new triangulated faces
+ * @param face face to be triangulated
+ * @param s segment used to triangulate face
+ */
+void triangulate(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face *face, BOP_Segment s)
+{
+       if (BOP_Segment::isUndefined(s.m_cfg1)) {
+               // Nothing to do
+       }
+       else if (BOP_Segment::isVertex(s.m_cfg1)) {
+               // VERTEX(v1) + VERTEX(v2) => nothing to do
+       }
+       else if (BOP_Segment::isEdge(s.m_cfg1)) {
+               if (BOP_Segment::isVertex(s.m_cfg2) || BOP_Segment::isUndefined(s.m_cfg2)) {
+                       // EDGE(v1) + VERTEX(v2)
+                       BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1));
+                       BOP_triangulateA(mesh,faces,face,s.m_v1,BOP_Segment::getEdge(s.m_cfg1));
+                       BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge);
+                       if (opposite != NULL) {
+                         unsigned int e;
+                         opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e);
+                         BOP_triangulateA(mesh, faces, opposite, s.m_v1, e);
+                       }
+               }
+               else {
+                       //  EDGE(v1) + EDGE(v2)
+                       if (BOP_Segment::getEdge(s.m_cfg1) == BOP_Segment::getEdge(s.m_cfg2)) {
+                                // EDGE(v1) == EDGE(v2)
+                               BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1));
+                               BOP_triangulateD(mesh, faces, face, s.m_v1, s.m_v2, 
+                                                                BOP_Segment::getEdge(s.m_cfg1)); 
+                               BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge);
+                               if (opposite != NULL) {
+                                 unsigned int e;
+                                 opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e);
+                                 BOP_triangulateD(mesh, faces, opposite, s.m_v1, s.m_v2, e);
+                               }
+               }
+                       else { // EDGE(v1) != EDGE(v2)
+                               BOP_Edge *edge1 = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg1));
+                               BOP_Edge *edge2 = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg2));
+                               BOP_triangulateE(mesh, faces, face, s.m_v1, s.m_v2,
+                                                                BOP_Segment::getEdge(s.m_cfg1),
+                                                                BOP_Segment::getEdge(s.m_cfg2));
+                               BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge1);
+                               if (opposite != NULL) {
+                                 unsigned int e;
+                                 opposite->getEdgeIndex(edge1->getVertex1(), edge1->getVertex2(),e);
+                                 BOP_triangulateA(mesh, faces, opposite, s.m_v1, e);
+                               }
+                               opposite = BOP_getOppositeFace(mesh,faces,face,edge2);
+                               if (opposite != NULL) {
+                                 unsigned int e;
+                                 opposite->getEdgeIndex(edge2->getVertex1(), edge2->getVertex2(),e);
+                                 BOP_triangulateA(mesh, faces, opposite, s.m_v2, e);
+                               }
+                       }
+               }
+       }
+       else if (BOP_Segment::isIn(s.m_cfg1)) {
+               if (BOP_Segment::isVertex(s.m_cfg2) || BOP_Segment::isUndefined(s.m_cfg2)) {
+                       // IN(v1) + VERTEX(v2)
+                       BOP_triangulateB(mesh,faces,face,s.m_v1);
+               }
+               else if (BOP_Segment::isEdge(s.m_cfg2)) {
+                       // IN(v1) + EDGE(v2)
+                       BOP_Edge *edge = mesh->getEdge(face,BOP_Segment::getEdge(s.m_cfg2));
+                       BOP_triangulateF(mesh,faces,face,s.m_v1,s.m_v2,BOP_Segment::getEdge(s.m_cfg2));
+                       BOP_Face *opposite = BOP_getOppositeFace(mesh,faces,face,edge);
+                       if (opposite != NULL) {
+                         unsigned int e;
+                         opposite->getEdgeIndex(edge->getVertex1(), edge->getVertex2(),e);
+                         BOP_triangulateA(mesh, faces, opposite, s.m_v2, e);
+                       }
+               }
+               else // IN(v1) + IN(v2)
+                       BOP_triangulateC(mesh,faces,face,s.m_v1,s.m_v2);
+       }
+}
+
+/**
+ * Returns if a face is in the set of faces.
+ * @param faces set of faces
+ * @param face face to be searched
+ * @return if the face is inside faces
+ */
+bool BOP_containsFace(BOP_Faces *faces, BOP_Face *face)
+{
+  const BOP_IT_Faces facesEnd = faces->end();
+       for(BOP_IT_Faces it=faces->begin();it!=facesEnd;it++)
+       {
+               if (*it == face)
+               return true;
+       }
+       
+       return false;
+}
+
+/**
+ * Returns the first face of faces that shares the input edge of face.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces
+ * @param face input face
+ * @param edge face's edge
+ * @return first face that shares the edge of input face
+ */
+BOP_Face *BOP_getOppositeFace(BOP_Mesh*  mesh, 
+                                                         BOP_Faces* faces, 
+                                                         BOP_Face*  face,
+                                                         BOP_Edge*  edge)
+{
+       if (edge == NULL)
+         return NULL;
+  
+       BOP_Indexs auxfaces = edge->getFaces();
+       const BOP_IT_Indexs auxfacesEnd = auxfaces.end();
+       for(BOP_IT_Indexs it = auxfaces.begin(); it != auxfacesEnd; it++) {
+               BOP_Face *auxface = mesh->getFace(*it);
+               if ((auxface != face) && (auxface->getTAG()!=BROKEN) && 
+                       BOP_containsFace(faces,auxface)) {
+                       return auxface;
+               }
+       }        
+  
+       return NULL;
+}
+
+/******************************************************************************/ 
+/***  OVERLAPPING                                                           ***/
+/******************************************************************************/ 
+
+/**
+ * Removes faces from facesB that are overlapped with anyone from facesA.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param facesA set of faces from object A
+ * @param facesB set of faces from object B
+ */
+void BOP_removeOverlappedFaces(BOP_Mesh *mesh,  BOP_Faces *facesA,  BOP_Faces *facesB)
+{
+       for(unsigned int i=0;i<facesA->size();i++) {
+               BOP_Face *faceI = (*facesA)[i];       
+               if (faceI->getTAG()==BROKEN) continue;
+               bool overlapped = false;
+               MT_Point3 p1 = mesh->getVertex(faceI->getVertex(0))->getPoint();
+               MT_Point3 p2 = mesh->getVertex(faceI->getVertex(1))->getPoint();
+               MT_Point3 p3 = mesh->getVertex(faceI->getVertex(2))->getPoint();
+               for(unsigned int j=0;j<facesB->size();) {
+                       BOP_Face *faceJ = (*facesB)[j];
+                       if (faceJ->getTAG()!=BROKEN) {
+                         MT_Plane3 planeJ = faceJ->getPlane();
+                         if (BOP_containsPoint(planeJ,p1) && BOP_containsPoint(planeJ,p2) 
+                             && BOP_containsPoint(planeJ,p3)) {
+                           MT_Point3 q1 = mesh->getVertex(faceJ->getVertex(0))->getPoint();
+                           MT_Point3 q2 = mesh->getVertex(faceJ->getVertex(1))->getPoint();
+                           MT_Point3 q3 = mesh->getVertex(faceJ->getVertex(2))->getPoint();
+                           if (BOP_overlap(MT_Vector3(planeJ.x(),planeJ.y(),planeJ.z()),
+                                           p1,p2,p3,q1,q2,q3)) {
+                             facesB->erase(facesB->begin()+j,facesB->begin()+(j+1));
+                             faceJ->setTAG(BROKEN);
+                             overlapped = true;
+                           }
+                           else j++;
+                         }
+                         else j++;
+                       }else j++;
+               }
+               if (overlapped) faceI->setTAG(OVERLAPPED);
+       }
+}
+
+/**
+ * Computes if triangle p1,p2,p3 is overlapped with triangle q1,q2,q3.
+ * @param normal normal of the triangle p1,p2,p3
+ * @param p1 point of first triangle
+ * @param p2 point of first triangle
+ * @param p3 point of first triangle
+ * @param q1 point of second triangle
+ * @param q2 point of second triangle
+ * @param q3 point of second triangle
+ * @return if there is overlapping between both triangles
+ */
+bool BOP_overlap(MT_Vector3 normal, MT_Point3 p1, MT_Point3 p2, MT_Point3 p3, 
+                                 MT_Point3 q1, MT_Point3 q2, MT_Point3 q3)
+{
+       MT_Vector3 p1p2 = p2-p1;    
+       MT_Plane3 plane1(p1p2.cross(normal),p1);
+       
+       MT_Vector3 p2p3 = p3-p2;
+       MT_Plane3 plane2(p2p3.cross(normal),p2);
+       
+       MT_Vector3 p3p1 = p1-p3;    
+       MT_Plane3 plane3(p3p1.cross(normal),p3);
+  
+       BOP_TAG tag1 = BOP_createTAG(BOP_classify(q1,plane1));
+       BOP_TAG tag2 = BOP_createTAG(BOP_classify(q1,plane2));
+       BOP_TAG tag3 = BOP_createTAG(BOP_classify(q1,plane3));
+       BOP_TAG tagQ1 = BOP_createTAG(tag1,tag2,tag3);   
+       if (tagQ1 == IN_IN_IN) return true;    
+  
+       tag1 = BOP_createTAG(BOP_classify(q2,plane1));
+       tag2 = BOP_createTAG(BOP_classify(q2,plane2));
+       tag3 = BOP_createTAG(BOP_classify(q2,plane3));
+       BOP_TAG tagQ2 = BOP_createTAG(tag1,tag2,tag3);
+       if (tagQ2 == IN_IN_IN) return true;    
+       
+       tag1 = BOP_createTAG(BOP_classify(q3,plane1));
+       tag2 = BOP_createTAG(BOP_classify(q3,plane2));
+       tag3 = BOP_createTAG(BOP_classify(q3,plane3));
+       BOP_TAG tagQ3 = BOP_createTAG(tag1,tag2,tag3);
+       if (tagQ3 == IN_IN_IN) return true;    
+  
+       if ((tagQ1 & OUT_OUT_OUT) == 0 && (tagQ2 & OUT_OUT_OUT) == 0 && 
+               (tagQ3 & OUT_OUT_OUT) == 0) return true;
+       else return false;
+}
diff --git a/intern/boolop/intern/BOP_Face2Face.h b/intern/boolop/intern/BOP_Face2Face.h
new file mode 100644 (file)
index 0000000..09ed4ed
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_FACE2FACE_H
+#define BOP_FACE2FACE_H
+
+#include "BOP_Mesh.h"
+#include "BOP_Segment.h"
+#include "BOP_Triangulator.h"
+#include "BOP_Splitter.h"
+#include "BOP_BSPTree.h"
+
+void BOP_Face2Face(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB);
+void BOP_sew(BOP_Mesh *mesh, BOP_Faces *facesA, BOP_Faces *facesB);
+void BOP_removeOverlappedFaces(BOP_Mesh *mesh,  BOP_Faces *facesA,  BOP_Faces *facesB);
+
+#endif
diff --git a/intern/boolop/intern/BOP_Indexs.h b/intern/boolop/intern/BOP_Indexs.h
new file mode 100644 (file)
index 0000000..c5546e7
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_Indexs_H
+#define BOP_Indexs_H
+
+#include <vector>
+using namespace std;
+
+typedef unsigned int BOP_Index;
+typedef vector<BOP_Index> BOP_Indexs;
+typedef vector<BOP_Index>::iterator BOP_IT_Indexs;
+
+#endif
diff --git a/intern/boolop/intern/BOP_Interface.cpp b/intern/boolop/intern/BOP_Interface.cpp
new file mode 100644 (file)
index 0000000..0294534
--- /dev/null
@@ -0,0 +1,603 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include <iostream>
+#include <map>
+#include "../extern/BOP_Interface.h"
+#include "../../bsp/intern/BSP_CSGMesh_CFIterator.h"
+#include "BOP_BSPTree.h"
+#include "BOP_Mesh.h"
+#include "BOP_Face2Face.h"
+#include "BOP_Merge.h"
+#include "BOP_MaterialContainer.h"
+#include "BOP_Chrono.h"
+
+//#define DEBUG
+
+BoolOpState BOP_intersectionBoolOp(BOP_Mesh*  meshC,
+                                                                  BOP_Faces* facesA,
+                                                                  BOP_Faces* facesB,
+                                                                  bool       invertMeshA,
+                                                                  bool       invertMeshB);
+BOP_Face3* BOP_createFace(BOP_Mesh* mesh, 
+                                                 BOP_Index vertex1, 
+                                                 BOP_Index vertex2, 
+                                                 BOP_Index vertex3, 
+                                                 BOP_Index idxFace);
+void BOP_addMesh(BOP_Mesh*                     mesh,
+                                BOP_Faces*                    meshFacesId,
+                                BOP_MaterialContainer*        materials,
+                                CSG_MeshPropertyDescriptor    props,
+                                CSG_FaceIteratorDescriptor&   face_it,
+                                CSG_VertexIteratorDescriptor& vertex_it,
+                                bool                          invert);
+BSP_CSGMesh* BOP_newEmptyMesh(CSG_MeshPropertyDescriptor props);  
+BSP_CSGMesh* BOP_exportMesh(BOP_Mesh*                  inputMesh, 
+                                                       BOP_MaterialContainer*     materials, 
+                                                       CSG_MeshPropertyDescriptor props,
+                                                       bool                       invert);
+void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp);
+void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted);
+void BOP_meshClassify(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp);
+
+/**
+ * Performs a generic booleam operation, the entry point for external modules.
+ * @param opType Boolean operation type BOP_INTERSECTION, BOP_UNION, BOP_DIFFERENCE
+ * @param outputProps Output mesh properties
+ * @param outputMesh Output mesh, the final result (the object C)
+ * @param obAProps Object A properties
+ * @param obAFaces Object A faces list
+ * @param obAVertices Object A vertices list
+ * @param obBProps Object B properties
+ * @param obBFaces Object B faces list
+ * @param obBVertices Object B vertices list
+ * @param interpFunc Interpolating function
+ * @return operation state: BOP_OK, BOP_NO_SOLID, BOP_ERROR
+ */
+BoolOpState BOP_performBooleanOperation(BoolOpType                    opType,
+                                                                               CSG_MeshPropertyDescriptor    outputProps,
+                                                                               BSP_CSGMesh**                 outputMesh,
+                                                                               CSG_MeshPropertyDescriptor    obAProps,
+                                                                               CSG_FaceIteratorDescriptor    obAFaces,
+                                                                               CSG_VertexIteratorDescriptor  obAVertices,
+                                                                               CSG_MeshPropertyDescriptor    obBProps,
+                                                                               CSG_FaceIteratorDescriptor    obBFaces,
+                                                                               CSG_VertexIteratorDescriptor  obBVertices,
+                                                                               CSG_InterpolateUserFaceVertexDataFunc interpFunc)
+{
+       #ifdef DEBUG
+       cout << "BEGIN BOP_performBooleanOperation" << endl;
+       #endif
+
+       // Set invert flags depending on boolean operation type:
+       // INTERSECTION: A^B = and(A,B)
+       // UNION:        A|B = not(and(not(A),not(B)))
+       // DIFFERENCE:   A-B = and(A,not(B))
+       bool invertMeshA = (opType == BOP_UNION);
+       bool invertMeshB = (opType != BOP_INTERSECTION);
+       bool invertMeshC = (opType == BOP_UNION);
+       
+       // Faces list for both objects, used by boolean op.
+       BOP_Faces meshAFacesId;
+       BOP_Faces meshBFacesId;
+       
+       // Build C-mesh, the output mesh
+       BOP_Mesh meshC;
+
+       // Prepare the material container
+       BOP_MaterialContainer materials;
+       materials.setInterpFunc(interpFunc);
+
+       // Add A-mesh into C-mesh
+       BOP_addMesh(&meshC, &meshAFacesId, &materials, obAProps, obAFaces, obAVertices, invertMeshA);
+
+       // Add B-mesh into C-mesh
+       BOP_addMesh(&meshC, &meshBFacesId, &materials, obBProps, obBFaces, obBVertices, invertMeshB);
+
+       // Perform the intersection boolean operation.
+       BoolOpState result = BOP_intersectionBoolOp(&meshC, &meshAFacesId, &meshBFacesId, 
+                                                                                               invertMeshA, invertMeshB);
+
+       // Invert the output mesh if is required
+       *outputMesh = BOP_exportMesh(&meshC, &materials, outputProps, invertMeshC);
+
+       #ifdef DEBUG
+       cout << "END BOP_performBooleanOperation" << endl;
+       #endif
+       
+       return result;
+}
+
+/**
+ * Computes the intersection boolean operation. Creates a new mesh resulting from 
+ * an intersection of two meshes.
+ * @param meshC Input & Output mesh
+ * @param facesA Mesh A faces list
+ * @param facesB Mesh B faces list
+ * @param invertMeshA determines if object A is inverted
+ * @param invertMeshB determines if object B is inverted
+ * @return operation state: BOP_OK, BOP_NO_SOLID, BOP_ERROR
+ */
+BoolOpState BOP_intersectionBoolOp(BOP_Mesh*  meshC,
+                                                                  BOP_Faces* facesA,
+                                                                  BOP_Faces* facesB,
+                                                                  bool       invertMeshA,
+                                                                  bool       invertMeshB)
+{
+       #ifdef DEBUG
+       BOP_Chrono chrono;
+       float t = 0.0f;
+       float c = 0.0f;
+       chrono.start();  
+       cout << "---" << endl;
+       #endif
+
+       // Create BSPs trees for mesh A & B
+       BOP_BSPTree bspA;
+       bspA.addMesh(meshC, *facesA);
+       bspA.computeBox();
+
+       BOP_BSPTree bspB;
+       bspB.addMesh(meshC, *facesB);
+       bspB.computeBox();
+       
+       #ifdef DEBUG
+       c = chrono.stamp(); t += c;
+       cout << "Create BSP     " << c << endl; 
+       #endif
+
+       unsigned int numVertices = meshC->getNumVertexs();
+       
+       // mesh pre-filter
+       BOP_simplifiedMeshFilter(meshC, facesA, &bspB, invertMeshB);
+       if ((0.25*facesA->size()) > bspB.getDeep())
+         BOP_meshFilter(meshC, facesA, &bspB);
+
+       BOP_simplifiedMeshFilter(meshC, facesB, &bspA, invertMeshA);
+       if ((0.25*facesB->size()) > bspA.getDeep())
+         BOP_meshFilter(meshC, facesB, &bspA);
+       
+       #ifdef DEBUG
+       c = chrono.stamp(); t += c;
+       cout << "mesh Filter    " << c << endl; 
+       #endif
+
+       // Face 2 Face
+       BOP_Face2Face(meshC,facesA,facesB);
+
+       #ifdef DEBUG
+       c = chrono.stamp(); t += c;
+       cout << "Face2Face      " << c << endl;
+       #endif
+
+       // BSP classification
+       BOP_meshClassify(meshC,facesA,&bspB);
+       BOP_meshClassify(meshC,facesB,&bspA);
+       
+       #ifdef DEBUG
+       c = chrono.stamp(); t += c;
+       cout << "Classification " << c << endl;
+       #endif
+       
+       // Process overlapped faces
+       BOP_removeOverlappedFaces(meshC,facesA,facesB);
+       
+       #ifdef DEBUG
+       c = chrono.stamp(); t += c;
+       cout << "Remove overlap " << c << endl;
+       #endif
+
+       // Sew two meshes
+       BOP_sew(meshC,facesA,facesB);
+
+       #ifdef DEBUG
+       c = chrono.stamp(); t += c;
+       cout << "Sew            " << c << endl;
+       #endif
+
+       // Merge faces
+       BOP_Merge::getInstance().mergeFaces(meshC,numVertices);
+
+       #ifdef DEBUG
+       c = chrono.stamp(); t += c;
+       cout << "Merge faces    " << c << endl;
+       cout << "Total          " << t << endl;
+       // Test integrity
+       meshC->testMesh();
+       #endif
+       
+       return BOP_OK;
+}
+
+/**
+ * Preprocess to filter no collisioned faces.
+ * @param meshC Input & Output mesh data
+ * @param faces Faces list to test
+ * @param bsp BSP tree used to filter
+ */
+void BOP_meshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp)
+{
+       BOP_IT_Faces it;
+       BOP_TAG tag;
+       
+       it = faces->begin();
+       while (it!=faces->end()) {
+               BOP_Face *face = *it;
+               MT_Point3 p1 = meshC->getVertex(face->getVertex(0))->getPoint();
+               MT_Point3 p2 = meshC->getVertex(face->getVertex(1))->getPoint();
+               MT_Point3 p3 = meshC->getVertex(face->getVertex(2))->getPoint();
+               if ((tag = bsp->classifyFace(p1,p2,p3,face->getPlane()))==OUT||tag==OUTON) {
+                       face->setTAG(BROKEN);
+                       it = faces->erase(it);
+               }
+               else if (tag == IN) {
+                       it = faces->erase(it);
+               }else{
+                 it++;
+               }
+       }
+}
+
+/**
+ * Pre-process to filter no collisioned faces.
+ * @param meshC Input & Output mesh data
+ * @param faces Faces list to test
+ * @param bsp BSP tree used to filter
+ * @param inverted determines if the object is inverted
+ */
+void BOP_simplifiedMeshFilter(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp, bool inverted)
+{
+       BOP_IT_Faces it;
+       
+       it = faces->begin();
+       while (it!=faces->end()) {
+               BOP_Face *face = *it;
+               MT_Point3 p1 = meshC->getVertex(face->getVertex(0))->getPoint();
+               MT_Point3 p2 = meshC->getVertex(face->getVertex(1))->getPoint();
+               MT_Point3 p3 = meshC->getVertex(face->getVertex(2))->getPoint();
+               if (bsp->filterFace(p1,p2,p3,face)==OUT) {
+                       if (!inverted) face->setTAG(BROKEN);
+                       it = faces->erase(it);
+               }
+               else {
+                       it++;
+               }
+       }
+}
+
+/**
+ * Process to classify the mesh faces using a bsp tree.
+ * @param meshC Input & Output mesh data
+ * @param faces Faces list to classify
+ * @param bsp BSP tree used to face classify
+ */
+void BOP_meshClassify(BOP_Mesh* meshC, BOP_Faces* faces, BOP_BSPTree* bsp)
+{
+       for(BOP_IT_Faces face=faces->begin();face!=faces->end();face++) {
+               if ((*face)->getTAG()!=BROKEN) {
+                       MT_Point3 p1 = meshC->getVertex((*face)->getVertex(0))->getPoint();
+                       MT_Point3 p2 = meshC->getVertex((*face)->getVertex(1))->getPoint();
+                       MT_Point3 p3 = meshC->getVertex((*face)->getVertex(2))->getPoint();
+                       if (bsp->simplifiedClassifyFace(p1,p2,p3,(*face)->getPlane())!=IN) {
+                               (*face)->setTAG(BROKEN);
+                       }
+               }
+       }
+}
+
+/**
+ * Returns a new mesh triangle.
+ * @param meshC Input & Output mesh data
+ * @param vertex1 first vertex of the new face
+ * @param vertex2 second vertex of the new face
+ * @param vertex3 third vertex of the new face
+ * @param idxFace identifier of the new face
+ * @return new the new face
+ */
+BOP_Face3 *BOP_createFace3(BOP_Mesh* mesh, 
+                                                  BOP_Index       vertex1, 
+                                                  BOP_Index       vertex2, 
+                                                  BOP_Index       vertex3, 
+                                                  BOP_Index       idxFace)
+{
+       MT_Point3 p1 = mesh->getVertex(vertex1)->getPoint();
+       MT_Point3 p2 = mesh->getVertex(vertex2)->getPoint();
+       MT_Point3 p3 = mesh->getVertex(vertex3)->getPoint();
+       MT_Plane3 plane(p1,p2,p3);
+
+       return new BOP_Face3(vertex1, vertex2, vertex3, plane, idxFace);
+}
+
+/**
+ * Adds mesh information into destination mesh.
+ * @param mesh input/output mesh, destination for the new mesh data
+ * @param meshFacesId output mesh faces, contains an added faces list
+ * @param materials used to store material data
+ * @param props Properties of the input mesh data
+ * @param face_it faces iterator
+ * @param vertex_it vertices iterator
+ * @param inverted if TRUE adding inverted faces, non-inverted otherwise
+ */
+void BOP_addMesh(BOP_Mesh*                     mesh,
+                                BOP_Faces*                    meshFacesId,
+                                BOP_MaterialContainer*        materials,
+                                CSG_MeshPropertyDescriptor    props,
+                                CSG_FaceIteratorDescriptor&   face_it,
+                                CSG_VertexIteratorDescriptor& vertex_it,
+                                bool                          invert)
+{
+       unsigned int vtxIndexOffset = mesh->getNumVertexs();
+
+       // The size of the vertex data array will be at least the number of faces.
+       CSG_IVertex vertex;
+       while (!vertex_it.Done(vertex_it.it)) {
+               vertex_it.Fill(vertex_it.it,&vertex);
+               MT_Point3 pos(vertex.position);
+               mesh->addVertex(pos);
+               vertex_it.Step(vertex_it.it);
+       }
+
+       CSG_IFace face;
+       
+       // now for the polygons.
+       // we may need to decalare some memory for user defined face properties.
+       unsigned int sizeFace = props.user_data_size;
+       if (sizeFace) {
+               face.user_face_data = new char[sizeFace];
+       } 
+       else {
+               face.user_face_data = NULL;
+       }
+
+       unsigned int sizeVertex = props.user_face_vertex_data_size;
+       if (sizeVertex) {
+               char * fv_data2 = NULL;
+               fv_data2 = new char[4 * sizeVertex];
+               
+               face.user_face_vertex_data[0] = fv_data2;
+               face.user_face_vertex_data[1] = fv_data2 + sizeVertex;
+               face.user_face_vertex_data[2] = fv_data2 + 2*sizeVertex;
+               face.user_face_vertex_data[3] = fv_data2 + 3*sizeVertex;
+       } 
+       else {
+               face.user_face_vertex_data[0] = NULL;
+               face.user_face_vertex_data[1] = NULL;
+               face.user_face_vertex_data[2] = NULL;
+               face.user_face_vertex_data[3] = NULL;
+       }
+
+       unsigned int idFaceMaterial;
+       BOP_Material faceMaterial(sizeFace,sizeVertex);
+       BOP_Material* materialHandler;
+       BOP_Face3 *newface;
+       
+       while (!face_it.Done(face_it.it)) {
+               face_it.Fill(face_it.it,&face);
+
+               faceMaterial.setFaceMaterial((char *)face.user_face_data);
+               faceMaterial.setFaceVertexMaterial((char *)face.user_face_vertex_data[0]);
+               faceMaterial.setOriginalFace(mesh->getNumFaces());
+               faceMaterial.setIsQuad(face.vertex_number == 4);
+               idFaceMaterial = materials->addMaterial(faceMaterial);
+               materialHandler = materials->getMaterial(idFaceMaterial);
+
+               // Let's not rely on quads being coplanar - especially if they 
+               // are coming out of that soup of code from blender...
+               if (face.vertex_number == 4){
+                       // QUAD
+                       if (invert) {
+                               newface = BOP_createFace3(mesh,
+                                                                                 face.vertex_index[2] + vtxIndexOffset,
+                                                                                 face.vertex_index[0] + vtxIndexOffset,
+                                                                                 face.vertex_index[3] + vtxIndexOffset,
+                                                                                 idFaceMaterial);
+                               meshFacesId->push_back(newface);
+                               mesh->addFace(newface);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(0),2);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(1),0);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(2),3);
+                               newface = BOP_createFace3(mesh,
+                                                                                 face.vertex_index[2] + vtxIndexOffset,
+                                                                                 face.vertex_index[1] + vtxIndexOffset,
+                                                                                 face.vertex_index[0] + vtxIndexOffset,
+                                                                                 idFaceMaterial);
+                               meshFacesId->push_back(newface);
+                               mesh->addFace(newface);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(1),1);
+                       }
+                       else {
+                               newface = BOP_createFace3(mesh,
+                                                                                face.vertex_index[0] + vtxIndexOffset,
+                                                                                face.vertex_index[2] + vtxIndexOffset,
+                                                                                face.vertex_index[3] + vtxIndexOffset,
+                                                                                idFaceMaterial);
+                               meshFacesId->push_back(newface);
+                               mesh->addFace(newface);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(0),0);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(1),2);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(2),3);
+                               newface = BOP_createFace3(mesh,
+                                                                                face.vertex_index[0] + vtxIndexOffset,
+                                                                                face.vertex_index[1] + vtxIndexOffset,
+                                                                                face.vertex_index[2] + vtxIndexOffset,
+                                                                                idFaceMaterial);
+                               meshFacesId->push_back(newface);
+                               mesh->addFace(newface);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(1),1);
+                       }
+               }
+               else {
+                       // TRIANGLES
+                       if (invert) {
+                               newface = BOP_createFace3(mesh,
+                                                                                 face.vertex_index[2] + vtxIndexOffset,
+                                                                                 face.vertex_index[1] + vtxIndexOffset,
+                                                                                 face.vertex_index[0] + vtxIndexOffset,
+                                                                                 idFaceMaterial);
+                               meshFacesId->push_back(newface);
+                               mesh->addFace(newface);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(0),2);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(1),1);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(2),0);
+                       }
+                       else {
+                               newface = BOP_createFace3(mesh,
+                                                                                 face.vertex_index[0] + vtxIndexOffset,
+                                                                                 face.vertex_index[1] + vtxIndexOffset,
+                                                                                 face.vertex_index[2] + vtxIndexOffset,
+                                                                                 idFaceMaterial);
+                               meshFacesId->push_back(newface);
+                               mesh->addFace(newface);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(0),0);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(1),1);
+                               materialHandler->setOriginalFaceVertex(newface->getVertex(2),2);
+                       }
+               }
+               
+               face_it.Step(face_it.it);
+       }
+       
+       // delete temporal material data
+       if (face.user_face_data)
+               delete[] static_cast<char *>(face.user_face_data);
+       if (face.user_face_vertex_data)
+               delete[] static_cast<char *>(face.user_face_vertex_data[0]);
+}
+
+/**
+ * Returns an empty mesh with the specified properties.
+ * @param props Output mesh properties
+ * @return a new empty mesh
+ */
+BSP_CSGMesh* BOP_newEmptyMesh(CSG_MeshPropertyDescriptor props)
+{
+       BSP_CSGMesh* mesh = BSP_CSGMesh::New();
+       if (mesh == NULL) return mesh;
+
+       vector<BSP_MVertex>* vertices = new vector<BSP_MVertex>;
+       BSP_CSGUserData* faceData     = new BSP_CSGUserData(props.user_data_size);
+       BSP_CSGUserData* faceVtxData  = new BSP_CSGUserData(props.user_face_vertex_data_size);
+       
+       mesh->SetVertices(vertices);
+       mesh->SetFaceData(faceData);
+       mesh->SetFaceVertexData(faceVtxData);
+
+       return mesh;
+}
+
+/**
+ * Exports a BOP_Mesh to a BSP_CSGMesh.
+ * @param mesh Input mesh
+ * @param materials used to reconstruct original faces materials
+ * @param props Properties of output mesh
+ * @param invert if TRUE export with inverted faces, no inverted otherwise
+ * @return the corresponding new BSP_CSGMesh
+ */
+BSP_CSGMesh* BOP_exportMesh(BOP_Mesh*                  mesh, 
+                                                       BOP_MaterialContainer*     materials, 
+                                                       CSG_MeshPropertyDescriptor props,
+                                                       bool                       invert)
+{
+       BSP_CSGMesh* outputMesh = BOP_newEmptyMesh(props);
+
+       // User data handlers
+       BSP_CSGUserData* outputFaceVtxData = &(outputMesh->FaceVertexData());
+       BSP_CSGUserData* outputFaceData    = &(outputMesh->FaceData());
+  
+       // vtx index dictionary, to translate indeces from input to output.
+       map<int,unsigned int> dic;
+       map<int,unsigned int>::iterator itDic;
+
+       unsigned int count = 0;
+
+       // Add a new face for each face in the input list
+       BOP_Faces faces = mesh->getFaces();
+       BOP_Vertexs vertexs = mesh->getVertexs();
+
+       // Reserve temporal memory
+       char* tmpFaceVtxData = new char[props.user_face_vertex_data_size];
+                       
+       for (BOP_IT_Faces face = faces.begin(); face != faces.end(); face++) {
+               if ((*face)->getTAG()!=BROKEN){    
+                       // Add output face
+                       outputMesh->FaceSet().push_back(BSP_MFace());
+                       BSP_MFace& outFace = outputMesh->FaceSet().back();
+
+                       // Copy face
+                       outFace.m_verts.clear();
+                       outFace.m_fv_data.clear();
+                       outFace.m_plane = (*face)->getPlane();
+
+                       // Copy face user data from input mesh
+                       outputFaceData->Duplicate(materials->getFaceMaterial((*face)->getOriginalFace()));
+
+                       // invert face if is required
+                       if (invert) (*face)->invert();
+                       
+                       // Add the face vertex if not added yet
+                       for (unsigned int pos=0;pos<(*face)->size();pos++) {
+                               BSP_VertexInd outVtxId;
+                               BOP_Index idVertex = (*face)->getVertex(pos);
+                               itDic = dic.find(idVertex);
+                               if (itDic == dic.end()) {
+                                       // The vertex isn't added yet
+                                       outVtxId = BSP_VertexInd(outputMesh->VertexSet().size());
+                                       BSP_MVertex outVtx((mesh->getVertex(idVertex))->getPoint());
+                                       outVtx.m_edges.clear();
+                                       outputMesh->VertexSet().push_back(outVtx);
+                                       dic[idVertex] = outVtxId;
+                                       count++;
+                               }
+                               else {
+                                       // The vertex is added
+                                       outVtxId = BSP_VertexInd(itDic->second);
+                               }
+                               
+                               // Add vertex to output face
+                               outFace.m_verts.push_back(outVtxId);
+
+                               // Add face vertex user data
+                               char* faceVtxData = materials->getFaceVertexMaterial(mesh,
+                                                                                                                                       (*face)->getOriginalFace(),
+                                                                                                                                       (mesh->getVertex(idVertex))->getPoint(),
+                                                                                                                                       tmpFaceVtxData);
+                               BSP_UserFVInd userFVInd(outputFaceVtxData->Duplicate((void*) faceVtxData));
+                               outFace.m_fv_data.push_back(userFVInd);
+                       }
+               }
+       }
+       // free temporal memory
+       delete[] tmpFaceVtxData;
+       
+       // Build the mesh edges using topological informtion
+       outputMesh->BuildEdges();
+       
+       return outputMesh;
+}
diff --git a/intern/boolop/intern/BOP_Material.cpp b/intern/boolop/intern/BOP_Material.cpp
new file mode 100644 (file)
index 0000000..2d1e747
--- /dev/null
@@ -0,0 +1,176 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_Material.h"
+#include <iostream>
+using namespace std;
+
+/**
+ * Constructs a new material. 
+ * @param faceWidth face material size in bytes.
+ * @param faceVertexWidth verex face material size in bytes.
+ */
+BOP_Material::BOP_Material(int faceWidth, int faceVertexWidth)
+{
+       m_faceWidth = faceWidth;
+       m_faceVertexWidth = faceVertexWidth;
+       
+       m_faceMaterial = new char[m_faceWidth];
+       m_faceVertexMaterial = new char[N_FACE_VERTEX*m_faceVertexWidth];
+}
+
+/**
+ * Constructs a new material duplicating the other object data.
+ * @param other the other object to copy the data.
+ */
+BOP_Material::BOP_Material(const BOP_Material& other)
+{
+       m_faceWidth = other.getFaceWidth();
+       m_faceVertexWidth = other.getFaceVertexWidth();
+       
+       m_faceMaterial = new char[m_faceWidth];
+       m_faceVertexMaterial = new char[N_FACE_VERTEX*m_faceVertexWidth];
+       
+       duplicate(other);
+}
+
+/**
+ * Destroys a material. 
+ */
+BOP_Material::~BOP_Material()
+{
+       delete[] m_faceMaterial;
+       delete[] m_faceVertexMaterial;
+}
+
+/**
+ * Duplicates the face material passed by argument.
+ * @param faceMaterial pointer to face material data.
+ */
+void BOP_Material::setFaceMaterial(char* faceMaterial)
+{
+       memcpy(m_faceMaterial, faceMaterial, m_faceWidth);
+}
+
+/**
+ * Duplicates the all face vertex materials passed by argument. It's supossed
+ * that all face vertex materials positions are consecutive.
+ * @param faceVertexMaterial pointer to firts vertex face material.
+ */
+void BOP_Material::setFaceVertexMaterial(char* faceVertexMaterial)
+{
+       memcpy(m_faceVertexMaterial, faceVertexMaterial, N_FACE_VERTEX*m_faceVertexWidth);
+}
+
+/**
+ * Duplicates on i-position the face vertex material passed by argument.
+ * @param faceMaterial pointer to face vertex material.
+ * @param i destination position of new face vertex material (0<=i<4)
+ */
+void BOP_Material::setFaceVertexMaterial(char* faceVertexMaterial, int i)
+{
+       if (i>=0&&i<N_FACE_VERTEX)
+               memcpy(m_faceVertexMaterial+i*m_faceVertexWidth, faceVertexMaterial, m_faceVertexWidth);
+}
+
+/**
+ * Duplicates the other material object data.
+ * @param other the other material object.
+ */
+void BOP_Material::duplicate(const BOP_Material& other)
+{
+       setOriginalFace(other.getOriginalFace());
+       setIsQuad(other.isQuad());
+       for (int i=0;i<N_FACE_VERTEX;++i)
+               setOriginalFaceVertex(other.getOriginalFaceVertex(i),i);
+       setFaceMaterial(other.getFaceMaterial());
+       setFaceVertexMaterial(other.getFaceVertexMaterial(0));
+}
+
+/**
+ * Implements operator =
+ */
+BOP_Material& BOP_Material::operator = (BOP_Material& other)
+{
+       if (other.getFaceWidth() == m_faceWidth && other.getFaceVertexWidth() == m_faceVertexWidth)
+               duplicate(other);
+       return (*this);
+}
+
+/**
+ * Returns the original face vertex material using a input vtx id. The input vtx IDs
+ * are mapped to output ids, this one is used to obtain the original face vertex 
+ * material.
+ * @param originalFaceVertex input vertex id (0..3)
+ * @return pointer to original face vertex material if it exist, NULL otherwise.
+ */
+char* BOP_Material::getOriginalFaceVertexMaterial(int originalFaceVertex)
+{
+       int  N = isQuad() ? 4 : 3;
+       int  i = 0;
+       bool b = false;
+       while (i<N&&!b){
+               if (m_originalFaceVertices[i]==originalFaceVertex) b = true;
+               else i++;
+       }
+       return b ? getFaceVertexMaterial(i) : NULL;
+}
+
+/**
+ * Returns the face material pointer.
+ * @return pointer to face material.
+ */
+char* BOP_Material::getFaceMaterial() const
+{
+       return m_faceMaterial;
+}
+
+/**
+ * Returns the face vertex material at i position.
+ * @param i index of face vertex material.
+ * @return pointer to face vertex material.
+ */
+inline char* BOP_Material::getFaceVertexMaterial(int i) const
+{
+       return i>=0&&i<N_FACE_VERTEX ? m_faceVertexMaterial + i*m_faceVertexWidth : NULL;
+}
+
+/**
+ * Implements operator <<
+ */
+ostream &operator<<(ostream &stream, BOP_Material *m)
+{
+       cout << "(" << m->getOriginalFace() << ") < ";
+       int N  = m->isQuad() ? 4 : 3;
+       for (int i=0;i<N;++i) cout << m->getOriginalFaceVertex(i) << " ";
+       cout << ">" << endl;
+
+       return stream;
+}
diff --git a/intern/boolop/intern/BOP_Material.h b/intern/boolop/intern/BOP_Material.h
new file mode 100644 (file)
index 0000000..a057384
--- /dev/null
@@ -0,0 +1,80 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_MATERIAL_H
+#define BOP_MATERIAL_H
+
+#include <iostream>
+using namespace std;
+
+#define N_FACE_VERTEX 4
+
+class BOP_Material 
+{
+private:
+       char* m_faceMaterial;
+       char* m_faceVertexMaterial;
+       int   m_faceWidth;
+       int   m_faceVertexWidth;
+       int   m_originalFace;
+       int   m_originalFaceVertices[N_FACE_VERTEX];
+       bool  m_isQuad;
+
+public:
+       BOP_Material(int faceWidth, int faceVertexWidth);
+       BOP_Material(const BOP_Material& other);
+       ~BOP_Material();
+       void setFaceMaterial(char* faceMaterial);
+       void setFaceVertexMaterial(char* faceVertexMaterial);
+       void setFaceVertexMaterial(char* faceVertexMaterial, int i);
+       void duplicate(const BOP_Material& other);
+       BOP_Material& operator = (BOP_Material& other);
+       char* getFaceMaterial() const;
+       char* getFaceVertexMaterial(int i) const;
+       int getFaceWidth() const { return m_faceWidth; };
+       int getFaceVertexWidth() const { return m_faceVertexWidth; };
+
+       void setOriginalFace(int originalFace) {m_originalFace = originalFace;};
+       int getOriginalFace() const {return m_originalFace;};
+       void setOriginalFaceVertex(int originalFaceVertex, int i) {
+               if (0<=i&&i<N_FACE_VERTEX) m_originalFaceVertices[i] = originalFaceVertex;
+       };
+       int getOriginalFaceVertex(int i) const {
+               if (0<=i&&i<N_FACE_VERTEX) return m_originalFaceVertices[i];
+               else return -1;
+       };
+       char* getOriginalFaceVertexMaterial(int originalFaceVertex);
+       void setIsQuad(bool quad) {m_isQuad = quad;};
+       bool isQuad() const {return m_isQuad;};
+
+       friend ostream &operator<<(ostream &stream, BOP_Material *m);
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_MaterialContainer.cpp b/intern/boolop/intern/BOP_MaterialContainer.cpp
new file mode 100644 (file)
index 0000000..b8f38b3
--- /dev/null
@@ -0,0 +1,242 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include <iostream>
+#include "BOP_MaterialContainer.h"
+#include "BOP_MathUtils.h"
+#include "MEM_SmartPtr.h"
+
+/**
+ * Constructs a new material container.
+ */
+BOP_MaterialContainer::BOP_MaterialContainer()
+{
+       m_interpFunc = NULL;
+}
+
+/**
+ * Destroys a material container.
+ */
+BOP_MaterialContainer::~BOP_MaterialContainer()
+{
+}
+
+/**
+ * Adds a new material to this container.
+ * @param m material material object to add.
+ * @return the new material index.
+ */
+BOP_Index BOP_MaterialContainer::addMaterial(BOP_Material m)
+{
+       m_materialList.push_back(m);
+       return m_materialList.size()-1;
+}
+
+/**
+ * Updates the interpolation function of this container.
+ * @param interpFunc the interpolation function.
+ */
+void BOP_MaterialContainer::setInterpFunc(CSG_InterpolateUserFaceVertexDataFunc interpFunc)
+{
+       m_interpFunc = interpFunc;
+}
+
+/**
+ * Returns the material list.
+ * @return
+ */
+BOP_Materials& BOP_MaterialContainer::getMaterialList()
+{
+       return m_materialList;
+}
+
+/**
+ * Returns the material with the specified index.
+ * @param index material index.
+ * @return material with the specified index.
+ */
+BOP_Material* BOP_MaterialContainer::getMaterial(BOP_Index index)
+{
+       return index < m_materialList.size() ? &(m_materialList[index]) : NULL;
+}
+
+/**
+ * Returns the pointer to face material specified by index.
+ * @param index material index.
+ * @return pointer to face material.
+ */
+char* BOP_MaterialContainer::getFaceMaterial(BOP_Index index)
+{
+       if (index < m_materialList.size())
+               return m_materialList[index].getFaceMaterial();
+       else return NULL;
+}
+
+/**
+ * Returns a pointer to face vertex material, if is the material not exist, then
+ * returns an interpoled material.
+ * @param mesh original mesh data.
+ * @param originalFaceIndex index to the original mesh face.
+ * @param point point who needs a material.
+ * @param faceVertexMaterial pointer to mem region where the material will be 
+ * saved.
+ * @return pointer to the face vertex material.
+ */
+char* BOP_MaterialContainer::getFaceVertexMaterial(BOP_Mesh *mesh, 
+                                                                                                  BOP_Index originalFaceIndex, 
+                                                                                                  MT_Point3 point, 
+                                                                                                  char* faceVertexMaterial)
+{
+       if (originalFaceIndex>=m_materialList.size()) return NULL;
+
+       BOP_Material& material = m_materialList[originalFaceIndex];
+       
+       if (material.isQuad()) {
+               
+               BOP_Face *face1 = mesh->getFace(material.getOriginalFace());
+               BOP_Face *face2 = mesh->getFace(material.getOriginalFace()+1);
+               
+               if (!face1 || !face2) return NULL;
+               
+               // Search original point
+               for (unsigned int i=0;i<face1->size();i++) {
+                       if (point == mesh->getVertex(face1->getVertex(i))->getPoint()) {
+                               return material.getOriginalFaceVertexMaterial(face1->getVertex(i));
+                       }
+               }
+               for (unsigned int i=0;i<face2->size();i++) {
+                       if (point == mesh->getVertex(face2->getVertex(i))->getPoint()) {
+                               return material.getOriginalFaceVertexMaterial(face2->getVertex(i));
+                       }
+               }
+               // wich is the half quad where the point is?
+               MT_Vector3 N = face1->getPlane().Normal();
+               MT_Point3 p0 = mesh->getVertex(face1->getVertex(0))->getPoint();
+               MT_Point3 q(p0.x()+N.x(),p0.y()+N.y(),p0.z()+N.z());
+               MT_Point3 p2 = mesh->getVertex(face1->getVertex(1))->getPoint();
+               MT_Plane3 plane(p0,p2,q);
+               
+               if (BOP_sign(plane.signedDistance(point))==-1) {
+                       // first half quad
+                       faceVertexMaterial = interpolateMaterial(mesh, face1, material, point, faceVertexMaterial);
+               }
+               else {
+                       // second half quad
+                       faceVertexMaterial = interpolateMaterial(mesh, face2, material, point, faceVertexMaterial);
+               }
+       }
+       else {
+               BOP_Face *face1 = mesh->getFace(material.getOriginalFace());
+               
+               if (!face1) return NULL;
+               
+               // Search original point
+               for (unsigned int i=0;i<face1->size();i++) {
+                       if (point == mesh->getVertex(face1->getVertex(i))->getPoint())
+                               return material.getOriginalFaceVertexMaterial(face1->getVertex(i));
+               }
+               
+               faceVertexMaterial = interpolateMaterial(mesh, face1, material, point, faceVertexMaterial);
+       }
+       
+       return faceVertexMaterial;
+}
+
+/**
+ * Performs vertex data interpolation.
+ * @param mesh original mesh data.
+ * @param face face used to interpolate an interior face point material
+ * @param material face material, input data for implementation.
+ * @param point interpolated point.
+ * @param faceVertexMaterial pointer to memory region.
+ * @return pointer to face vertex material.
+ */
+char* BOP_MaterialContainer::interpolateMaterial(BOP_Mesh* mesh,
+                                                                                                BOP_Face* face, 
+                                                                                                BOP_Material& material,
+                                                                                                MT_Point3 point, 
+                                                                                                char* faceVertexMaterial)
+{
+       //  (p1)-----(I)------(p2)
+       //    \       |        /
+       //     \      |       /
+       //      \     |      /
+       //       \ (point)  /
+       //        \   |    /
+       //         \  |   /
+       //          \ |  /
+       //           (p3)
+
+       MT_Point3 p1 = mesh->getVertex(face->getVertex(0))->getPoint();
+       MT_Point3 p2 = mesh->getVertex(face->getVertex(1))->getPoint();
+       MT_Point3 p3 = mesh->getVertex(face->getVertex(2))->getPoint();
+       MT_Point3 I = BOP_4PointIntersect(p1, p2, p3, point);
+       MT_Scalar epsilon0 = 1.0-BOP_EpsilonDistance(p1, p2, I);
+       MT_Scalar epsilon1 = 1.0-BOP_EpsilonDistance(I, p3, point);
+       
+       // Interpolate data
+       if (m_interpFunc) {
+               // temporal data
+               char* faceVertexMaterialTemp = new char[material.getFaceVertexWidth()];
+               
+               (*m_interpFunc)(material.getOriginalFaceVertexMaterial(face->getVertex(0)),
+                                               material.getOriginalFaceVertexMaterial(face->getVertex(1)),
+                                               faceVertexMaterialTemp,
+                                               epsilon0);
+
+               (*m_interpFunc)(faceVertexMaterialTemp,
+                                               material.getOriginalFaceVertexMaterial(face->getVertex(2)),
+                                               faceVertexMaterial,
+                                               epsilon1);
+
+               // free temporal data
+               delete[] faceVertexMaterialTemp;
+               
+       }
+       else faceVertexMaterial = NULL;
+       
+       // return the result
+       return (char*) faceVertexMaterial;
+}
+
+/**
+ * Implements operator <<
+ */
+ostream &operator<<(ostream &stream, BOP_MaterialContainer *mc)
+{
+       stream << "***[ Material List ]***********************************************" << endl;
+       BOP_IT_Materials it;
+       for (it=mc->getMaterialList().begin();it!=mc->getMaterialList().end();++it) {
+               stream << "[" << it - mc->getMaterialList().begin() << "] ";
+               stream << &(*it);
+       }
+       stream << "*******************************************************************" << endl;
+       return stream;
+}
diff --git a/intern/boolop/intern/BOP_MaterialContainer.h b/intern/boolop/intern/BOP_MaterialContainer.h
new file mode 100644 (file)
index 0000000..c6de4cd
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_MATERIALCONTAINER_H
+#define BOP_MATERIALCONTAINER_H
+
+#include "BOP_Mesh.h"
+#include "BOP_Material.h"
+#include "BOP_Interface.h"
+#include <vector>
+using namespace std;
+
+typedef vector<BOP_Material> BOP_Materials;
+typedef vector<BOP_Material>::iterator BOP_IT_Materials;
+
+class BOP_MaterialContainer
+{
+private:
+       BOP_Materials m_materialList;
+       CSG_InterpolateUserFaceVertexDataFunc m_interpFunc;
+
+public:
+       BOP_MaterialContainer();
+       ~BOP_MaterialContainer();
+       BOP_Index addMaterial(BOP_Material m);
+       void setInterpFunc(CSG_InterpolateUserFaceVertexDataFunc interpFunc);
+       BOP_Materials& getMaterialList();
+       BOP_Material* getMaterial(BOP_Index index);
+       char* getFaceMaterial(BOP_Index index);
+       char* getFaceVertexMaterial(BOP_Mesh *mesh, 
+                                                               BOP_Index originalFaceIndex, 
+                                                               MT_Point3 point, 
+                                                               char* faceVertexMaterial);
+
+       friend ostream &operator<<(ostream &stream, BOP_MaterialContainer *mc);
+         
+private:
+       char* interpolateMaterial(BOP_Mesh* mesh,
+                                                         BOP_Face* face, 
+                                                         BOP_Material& material,
+                                                         MT_Point3 point, 
+                                                         char* faceVertexMaterial);
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_MathUtils.cpp b/intern/boolop/intern/BOP_MathUtils.cpp
new file mode 100644 (file)
index 0000000..0d84bb1
--- /dev/null
@@ -0,0 +1,419 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_MathUtils.h"
+#include <iostream>
+using namespace std;
+
+/**
+ * Compares two scalars with EPSILON accuracy.
+ * @param A scalar
+ * @param B scalar
+ * @return 1 if A > B, -1 if A < B, 0 otherwise
+ */
+int BOP_comp(const MT_Scalar A, const MT_Scalar B)
+{
+       if (A >= B + BOP_EPSILON) return 1;
+       else if (B >= A + BOP_EPSILON) return -1;
+       else return 0; 
+}
+
+/**
+ * Compares two scalar triplets with EPSILON accuracy.
+ * @param A scalar triplet
+ * @param B scalar triplet
+ * @return 1 if A > B, -1 if A < B, 0 otherwise
+ */
+int BOP_comp(const MT_Tuple3& A, const MT_Tuple3& B)
+{
+       if (A.x() >= (B.x() + BOP_EPSILON)) return 1;
+       else if (B.x() >= (A.x() + BOP_EPSILON)) return -1;
+       else if (A.y() >= (B.y() + BOP_EPSILON)) return 1;
+       else if (B.y() >= (A.y() + BOP_EPSILON)) return -1;
+       else if (A.z() >= (B.z() + BOP_EPSILON)) return 1;
+       else if (B.z() >= (A.z() + BOP_EPSILON)) return -1;
+       else return 0;
+}
+
+/**
+ * Compares two scalars strictly.
+ * @param A scalar
+ * @param B scalar
+ * @return 1 if A > B, -1 if A < B, 0 otherwise
+ */
+int BOP_exactComp(const MT_Scalar A, const MT_Scalar B)
+{
+       if (A > B) return 1;
+       else if (B > A) return -1;
+       else return 0; 
+}
+/**
+ * Compares two scalar strictly.
+ * @param A scalar triplet
+ * @param B scalar triplet
+ * @return 1 if A > B, -1 if A < B, 0 otherwise
+ */
+int BOP_exactComp(const MT_Tuple3& A, const MT_Tuple3& B)
+{
+       if (A.x() > B.x()) return 1;
+       else if (B.x() > A.x()) return -1;
+       else if (A.y() > B.y()) return 1;
+       else if (B.y() > A.y()) return -1;
+       else if (A.z() > B.z()) return 1;
+       else if (B.z() > A.z()) return -1;
+       else return 0;
+}
+
+/**
+ * Returns if p1 is between p2 and p3 and lay on the same line (are collinears).
+ * @param p1 point
+ * @param p2 point
+ * @param p3 point
+ * @return true if p1 is between p2 and p3 and lay on the same line, false otherwise
+ */
+bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3)
+{
+       MT_Scalar distance = p2.distance(p3);
+       return (p1.distance(p2) < distance && p1.distance(p3) < distance) && BOP_collinear(p1,p2,p3);
+}
+
+/**
+ * Returns if three points lay on the same line (are collinears).
+ * @param p1 point
+ * @param p2 point
+ * @param p3 point
+ * @return true if the three points lay on the same line, false otherwise
+ */
+bool BOP_collinear(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3)
+{
+       MT_Vector3 v1 = p2 - p1;
+       MT_Vector3 v2 = p3 - p2;
+       
+       MT_Vector3 w = v1.cross(v2);
+       
+       return (BOP_comp(w.x(),0.0) == 0) && (BOP_comp(w.y(),0.0) == 0) && (BOP_comp(w.z(),0.0) == 0);
+}
+
+/**
+ * Returns if a quad (coplanar) is convex.
+ * @return true if the quad is convex, false otherwise
+ */
+bool BOP_convex(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4)
+{
+       MT_Vector3 v1 = p3 - p1;
+       MT_Vector3 v2 = p4 - p2;
+       MT_Vector3 quadPlane = v1.cross(v2);
+       // plane1 is the perpendicular plane that contains the quad diagonal (p2,p4)
+       MT_Plane3 plane1(quadPlane.cross(v2),p2);
+       // if p1 and p3 are classified in the same region, the quad is not convex 
+       if (BOP_classify(p1,plane1) == BOP_classify(p3,plane1)) return false;
+       else {
+               // Test the other quad diagonal (p1,p3) and perpendicular plane
+               MT_Plane3 plane2(quadPlane.cross(v1),p1);
+               // if p2 and p4 are classified in the same region, the quad is not convex
+               return (BOP_classify(p2,plane2) != BOP_classify(p4,plane2));
+       }
+}
+
+/**
+ * Returns if a quad (coplanar) is concave and where is the split edge.
+ * @return 0 if is convex, 1 if is concave and split edge is p1-p3 and -1 if is
+ * cancave and split edge is p2-p4.
+ */
+int BOP_concave(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4)
+{
+       MT_Vector3 v1 = p3 - p1;
+       MT_Vector3 v2 = p4 - p2;
+       MT_Vector3 quadPlane = v1.cross(v2);
+       // plane1 is the perpendicular plane that contains the quad diagonal (p2,p4)
+       MT_Plane3 plane1(quadPlane.cross(v2),p2);
+       // if p1 and p3 are classified in the same region, the quad is not convex 
+       if (BOP_classify(p1,plane1) == BOP_classify(p3,plane1)) return 1;
+       else {
+               // Test the other quad diagonal (p1,p3) and perpendicular plane
+               MT_Plane3 plane2(quadPlane.cross(v1),p1);
+               // if p2 and p4 are classified in the same region, the quad is not convex
+               if (BOP_classify(p2,plane2) == BOP_classify(p4,plane2)) return -1;
+               else return 0;
+       }
+}
+
+/**
+ * Computes the intersection between two lines (on the same plane).
+ * @param vL1 first line vector
+ * @param pL1 first line point
+ * @param vL2 second line vector
+ * @param pL2 second line point
+ * @param intersection intersection point (if exists)
+ * @return false if lines are parallels, true otherwise
+ */
+bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, 
+                                  const MT_Point3& pL2, MT_Point3 &intersection)
+{
+       // NOTE: 
+    // If the lines aren't on the same plane, the intersection point will not be valid. 
+       // So be careful !!
+
+       MT_Scalar t = -1;
+       MT_Scalar den = (vL1.y()*vL2.x() - vL1.x() * vL2.y());
+       
+       if (BOP_comp(den,0)) {
+               t =  (pL2.y()*vL1.x() - vL1.y()*pL2.x() + pL1.x()*vL1.y() - pL1.y()*vL1.x()) / den ;
+       }
+       else {
+               den = (vL1.y()*vL2.z() - vL1.z() * vL2.y());
+               if (BOP_comp(den,0)) {
+                       t =  (pL2.y()*vL1.z() - vL1.y()*pL2.z() + pL1.z()*vL1.y() - pL1.y()*vL1.z()) / den ;
+               }
+               else {
+                       den = (vL1.x()*vL2.z() - vL1.z() * vL2.x());
+                       if (BOP_comp(den,0)) {
+                               t =  (pL2.x()*vL1.z() - vL1.x()*pL2.z() + pL1.z()*vL1.x() - pL1.x()*vL1.z()) / den ;
+                       }
+                       else {
+                               return false;
+                       }
+               }
+       }
+       
+       intersection.setValue(vL2.x()*t + pL2.x(), vL2.y()*t + pL2.y(), vL2.z()*t + pL2.z());
+       return true;
+}
+
+/**
+ * Returns the center of the circle defined by three points.
+ * @param p1 point
+ * @param p2 point
+ * @param p3 point
+ * @param center circle center
+ * @return false if points are collinears, true otherwise
+ */
+bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
+                                                MT_Point3& center)
+{
+       // Compute quad plane
+       MT_Vector3 p1p2 = p2-p1;
+       MT_Vector3 p1p3 = p3-p1;
+       MT_Plane3 plane1(p1,p2,p3);
+       MT_Vector3 plane = plane1.Normal();
+       
+       // Compute first line vector, perpendicular to plane vector and edge (p1,p2)
+       MT_Vector3 vL1 = p1p2.cross(plane);
+       vL1.normalize();
+       
+       // Compute first line point, middle point of edge (p1,p2)
+       MT_Point3 pL1 = p1.lerp(p2, 0.5);
+
+       // Compute second line vector, perpendicular to plane vector and edge (p1,p3)
+       MT_Vector3 vL2 = p1p3.cross(plane);
+       vL2.normalize();
+       
+       // Compute second line point, middle point of edge (p1,p3)
+       MT_Point3 pL2 = p1.lerp(p3, 0.5);
+
+       // Compute intersection (the lines lay on the same plane, so the intersection exists
+    // only if they are not parallel!!)
+       return BOP_intersect(vL1,pL1,vL2,pL2,center);
+}
+
+/**
+ * Returns if points q is inside the circle defined by p1, p2 and p3.
+ * @param p1 point
+ * @param p2 point
+ * @param p3 point
+ * @param q point
+ * @return true if p4 or p5 are inside the circle, false otherwise. If 
+ * the circle does not exist (p1, p2 and p3 are collinears) returns true
+ */
+bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
+                                               const MT_Point3& q)
+{
+       MT_Point3 center;
+
+       // Compute circle center
+       bool ok = BOP_getCircleCenter(p1,p2,p3,center);
+       
+       if (!ok) return true; // p1,p2 and p3 are collinears
+
+       // Check if q is inside the circle
+       MT_Scalar r = p1.distance(center);
+       MT_Scalar d = q.distance(center);    
+       return (BOP_comp(d,r) <= 0);
+}
+
+/**
+ * Returns if points p4 or p5 is inside the circle defined by p1, p2 and p3.
+ * @param p1 point
+ * @param p2 point
+ * @param p3 point
+ * @param p4 point
+ * @param p5 point
+ * @return true if p4 or p5 is inside the circle, false otherwise. If 
+ * the circle does not exist (p1, p2 and p3 are collinears) returns true
+ */
+bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
+                                               const MT_Point3& p4, const MT_Point3& p5)
+{
+       MT_Point3 center;
+       bool ok = BOP_getCircleCenter(p1,p2,p3,center);
+
+       if (!ok) return true; // Collinear points!
+
+       // Check if p4 or p5 is inside the circle
+       MT_Scalar r = p1.distance(center);
+       MT_Scalar d1 = p4.distance(center);
+       MT_Scalar d2 = p5.distance(center);
+       return (BOP_comp(d1,r) <= 0 || BOP_comp(d2,r) <= 0);
+}
+
+/**
+ * Returns if two planes share the same orientation.
+ * @return >0 if planes share the same orientation
+ */
+MT_Scalar BOP_orientation(const MT_Plane3& p1, const MT_Plane3& p2)
+{
+       // Dot product between plane normals
+       return (p1.x()*p2.x() + p1.y()*p2.y() + p1.z()*p2.z());
+}
+
+/**
+ * Classifies a point according to the specified plane with EPSILON accuracy.
+ * @param p point
+ * @param plane plane
+ * @return >0 if the point is above (OUT), 
+ *         =0 if the point is on (ON), 
+ *         <0 if the point is below (IN)
+ */
+int BOP_classify(const MT_Point3& p, const MT_Plane3& plane)
+{
+       // Compare plane - point distance with zero
+       return BOP_comp(plane.signedDistance(p),0);
+}
+
+/**
+ * Intersects a plane with the line that contains the specified points.
+ * @param plane split plane
+ * @param p1 first line point
+ * @param p2 second line point
+ * @return intersection between plane and line that contains p1 and p2
+ */
+MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2)
+{
+       // Compute intersection between plane and line ...
+    //
+       //       L: (p2-p1)lambda + p1
+       //
+       // supposes resolve equation ...
+       //
+       //       coefA*((p2.x - p1.y)*lambda + p1.x) + ... + coefD = 0
+       
+    MT_Point3 intersection;
+    MT_Scalar den = plane.x()*(p2.x()-p1.x()) + 
+                                       plane.y()*(p2.y()-p1.y()) + 
+                                       plane.z()*(p2.z()-p1.z());
+       if (den != 0) {
+               MT_Scalar lambda = (-plane.x()*p1.x()-plane.y()*p1.y()-plane.z()*p1.z()-plane.w()) / den;
+               intersection.setValue(p1.x() + (p2.x()-p1.x())*lambda, 
+                                                 p1.y() + (p2.y()-p1.y())*lambda, 
+                                                 p1.z() + (p2.z()-p1.z())*lambda);
+               return intersection;
+       }
+       return intersection;
+}
+
+/**
+ * Returns if a plane contains a point with EPSILON accuracy.
+ * @param plane plane
+ * @param point point
+ * @return true if the point is on the plane, false otherwise
+ */
+bool BOP_containsPoint(const MT_Plane3& plane, const MT_Point3& point)
+{
+       return BOP_comp(plane.signedDistance(point),0) == 0;
+}
+
+/**
+ * Pre: p0, p1 and p2 is a triangle and q is an interior point.
+ * @param p0 point
+ * @param p1 point
+ * @param p2 point
+ * @param q point
+ * @return intersection point I
+ *                v 
+ *  (p0)-----(I)----->(p1)
+ *    \       ^        /
+ *     \      |w      /
+ *      \     |      /
+ *       \   (q)    /
+ *        \   |    /
+ *         \  |   /
+ *          \ |  /
+ *           (p2)
+ *
+ * v = P1-P2
+ * w = P3-Q
+ * r0(t) = v*t+P1
+ * r1(t) = w*t+P3
+ * I = r0^r1
+ */
+MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, 
+                                                         const MT_Point3& q)
+{
+       MT_Vector3 v(p0.x()-p1.x(), p0.y()-p1.y(), p0.z()-p1.z());
+       MT_Vector3 w(p2.x()-q.x(), p2.y()-q.y(), p2.z()-q.z());
+       MT_Point3 I;
+       
+       BOP_intersect(v,p0,w,p2,I);
+       return I;
+}
+
+/**
+ * Pre: p0, p1 and q are collinears.
+ * @param p0 point
+ * @param p1 point
+ * @param q point
+ * @return 0 if q == p0, 1 if q == p1, or a value between 0 and 1 otherwise
+ *
+ * (p0)-----(q)------------(p1)
+ *   |<-d1-->|               |
+ *   |<---------d0---------->|
+ * 
+ */
+MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q)
+{
+       MT_Scalar d0 = p0.distance(p1);
+       MT_Scalar d1 = p0.distance(q);
+       MT_Scalar d;
+       
+       if (BOP_comp(d0,0)==0) d = 1.0;
+       else if (BOP_comp(d1,0)==0) d = 0.0;
+       else d = d1 / d0;
+       return d;
+}
diff --git a/intern/boolop/intern/BOP_MathUtils.h b/intern/boolop/intern/BOP_MathUtils.h
new file mode 100644 (file)
index 0000000..61458bd
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_MATHUTILS_H
+#define BOP_MATHUTILS_H
+
+#include <math.h>
+#include <float.h>
+#include "MT_Point3.h"
+#include "MT_Plane3.h"
+
+const MT_Scalar BOP_EPSILON(1.0e-5);
+
+inline int BOP_sign(MT_Scalar x) {
+    return x < 0.0 ? -1 : x > 0.0 ? 1 : 0;
+}
+inline MT_Scalar BOP_abs(MT_Scalar x) { return fabs(x); }
+inline bool      BOP_fuzzyZero(MT_Scalar x) { return BOP_abs(x) < BOP_EPSILON; }
+
+int BOP_comp(const MT_Scalar A, const MT_Scalar B);
+int BOP_comp(const MT_Tuple3& A, const MT_Tuple3& B);
+int BOP_exactComp(const MT_Scalar A, const MT_Scalar B);
+int BOP_exactComp(const MT_Tuple3& A, const MT_Tuple3& B);
+bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3);
+bool BOP_collinear(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3);
+bool BOP_convex(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
+                               const MT_Point3& p4);
+int BOP_concave(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4);
+bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, 
+                                  const MT_Point3& pL2, MT_Point3& intersection);
+bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
+                                                const MT_Point3& center);
+bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
+                                               const MT_Point3& p4, const MT_Point3& p5);
+bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, 
+                                               const MT_Point3& q);
+MT_Scalar BOP_orientation(const MT_Plane3& p1, const MT_Plane3& p2);
+int BOP_classify(const MT_Point3& p, const MT_Plane3& plane);
+MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2);
+bool BOP_containsPoint(const MT_Plane3& plane, const MT_Point3& point);
+MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, 
+                                                         const MT_Point3& q);
+MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q);
+
+#endif
diff --git a/intern/boolop/intern/BOP_Merge.cpp b/intern/boolop/intern/BOP_Merge.cpp
new file mode 100644 (file)
index 0000000..1165ac1
--- /dev/null
@@ -0,0 +1,796 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_Merge.h"
+
+/**
+ * SINGLETON (use method BOP_Merge.getInstance).
+ */
+BOP_Merge BOP_Merge::SINGLETON;
+
+/**
+ * Simplifies a mesh, merging its faces.
+ * @param m mesh
+ * @param v index of the first mergeable vertex (can be removed by merge) 
+ */
+void BOP_Merge::mergeFaces(BOP_Mesh *m, BOP_Index v)
+{
+       m_mesh = m;
+       m_firstVertex = v;
+
+       bool cont = false;
+
+       // Merge faces
+       mergeFaces();
+
+       do {
+               // Add quads ...
+               cont = createQuads();
+               if (cont) {
+                       // ... and merge new faces
+                       cont = mergeFaces();
+               }
+               // ... until the merge is not succesful
+       } while(cont);
+}
+
+/**
+ * Simplifies a mesh, merging its faces.
+ */
+bool BOP_Merge::mergeFaces()
+{
+       BOP_Indexs mergeVertices;
+       BOP_Vertexs vertices = m_mesh->getVertexs();
+       BOP_IT_Vertexs v = vertices.begin();
+       const BOP_IT_Vertexs verticesEnd = vertices.end();
+
+       // Advance to first mergeable vertex
+       advance(v,m_firstVertex);
+       BOP_Index pos = m_firstVertex;
+
+       // Add unbroken vertices to the list
+       while(v!=verticesEnd) {
+               if ((*v)->getTAG() != BROKEN) mergeVertices.push_back(pos);
+               v++;pos++;
+       }
+
+       // Merge faces with that vertices
+       return mergeFaces(mergeVertices);
+}
+
+
+/**
+ * Simplifies a mesh, merging the faces with the specified vertices.
+ * @param mergeVertices vertices to test
+ * @return true if a face merge was performed
+ */
+bool BOP_Merge::mergeFaces(BOP_Indexs &mergeVertices)
+{
+       // Check size > 0!
+       if (mergeVertices.size() == 0) return false;
+
+       // New faces added by merge
+       BOP_Faces newFaces;
+
+       // Old faces removed by merge
+       BOP_Faces oldFaces;
+
+       // Get the first vertex index and add it to 
+       // the current pending vertices to merge
+       BOP_Index v = mergeVertices[0];
+       BOP_Indexs pendingVertices;
+       pendingVertices.push_back(v);
+
+       // Get faces with index v that come from the same original face
+       BOP_LFaces facesByOriginalFace;
+       getFaces(facesByOriginalFace,v);
+
+       bool merged = true;
+
+       // Check it has any unbroken face
+       if (facesByOriginalFace.size()==0) {
+               // v has not any unbroken face (so it's a new BROKEN vertex)
+               (m_mesh->getVertex(v))->setTAG(BROKEN);
+               merged = false;
+       }
+
+       // Merge vertex faces   
+       const BOP_IT_LFaces facesEnd = facesByOriginalFace.end();
+       
+       for(BOP_IT_LFaces facesByOriginalFaceX = facesByOriginalFace.begin();
+               (facesByOriginalFaceX != facesEnd)&&merged;
+               facesByOriginalFaceX++) {               
+                       merged = mergeFaces((*facesByOriginalFaceX),oldFaces,newFaces,pendingVertices,v);
+       }
+
+       // Check if the are some pendingVertices to merge
+       if (pendingVertices.size() > 1 && merged) {
+               // There are pending vertices that we need to merge in order to merge v ...
+               for(unsigned int i=1;i<pendingVertices.size() && merged;i++) 
+                       merged = mergeFaces(oldFaces,newFaces,pendingVertices,pendingVertices[i]);
+       }
+
+       // If merge was succesful ...
+       if (merged) {
+               // Set old faces to BROKEN...
+         const BOP_IT_Faces oldFacesEnd = oldFaces.end();
+               for(BOP_IT_Faces face=oldFaces.begin();face!=oldFacesEnd;face++) 
+                       (*face)->setTAG(BROKEN);
+
+               // ... and add merged faces (that are the new merged faces without pending vertices)
+               const BOP_IT_Faces newFacesEnd = newFaces.end();
+               for(BOP_IT_Faces newFace=newFaces.begin();newFace!=newFacesEnd;newFace++) {
+                       m_mesh->addFace(*newFace);
+                       // Also, add new face vertices to the queue of vertices to merge if they weren't
+                       for(BOP_Index i = 0;i<(*newFace)->size();i++) {
+                               BOP_Index vertexIndex = (*newFace)->getVertex(i);
+                               if (vertexIndex >= m_firstVertex && !containsIndex(mergeVertices,vertexIndex))
+                                       mergeVertices.push_back(vertexIndex);
+                       }
+               }
+               // Set the merged vertices to BROKEN ...
+               const BOP_IT_Indexs pendingEnd = pendingVertices.end();
+               for(BOP_IT_Indexs pendingVertex = pendingVertices.begin(); pendingVertex != pendingEnd;pendingVertex++) {
+                       BOP_Index pV = *pendingVertex;
+                       m_mesh->getVertex(pV)->setTAG(BROKEN);
+                       // ... and remove them from mergeVertices queue
+                       const BOP_IT_Indexs mergeEnd = mergeVertices.end();
+                       for(BOP_IT_Indexs mergeVertex = mergeVertices.begin(); mergeVertex != mergeEnd;mergeVertex++) {
+                               BOP_Index mV = *mergeVertex;
+                               if (mV == pV) {
+                                       mergeVertices.erase(mergeVertex);
+                                       break;
+                               }
+                       }
+               }
+       }
+       else {
+               // The merge  was not succesful, remove the vertex frome merge vertices queue
+               mergeVertices.erase(mergeVertices.begin());
+               
+               // free the not used newfaces
+               const BOP_IT_Faces newFacesEnd = newFaces.end();
+               for(BOP_IT_Faces newFace=newFaces.begin();newFace!=newFacesEnd;newFace++) {
+                       delete (*newFace);
+               }
+       }
+
+       // Invoke mergeFaces and return the merge result
+       return (mergeFaces(mergeVertices) || merged);
+}
+
+
+/**
+ * Simplifies a mesh, merging the faces with vertex v that come from the same face.
+ * @param oldFaces sequence of old mesh faces obtained from the merge
+ * @param newFaces sequence of new mesh faces obtained from the merge
+ * @param vertices sequence of indexs (v1 ... vi = v ... vn) where :
+ *   v is the current vertex to test,
+ *   vj (j < i) are tested vertices, 
+ *   vk (k >= i) are vertices required to test to merge vj
+ * (so if a vertex vk can't be merged, the merge is not possible).
+ * @return true if the vertex v was 'merged' (obviously it could require to test
+ * some new vertices that will be added to the vertices list)
+ */
+bool BOP_Merge::mergeFaces(BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v) {
+
+       bool merged = true;
+
+       // Get faces with v that come from the same original face, (without the already 'merged' from vertices)
+       BOP_LFaces facesByOriginalFace;
+       getFaces(facesByOriginalFace,vertices,v);
+  
+       if (facesByOriginalFace.size()==0) {
+               // All the faces with this vertex were already merged!!!
+               return true;
+       }
+       else {
+               // Merge faces
+         const BOP_IT_LFaces facesEnd = facesByOriginalFace.end();
+               for(BOP_IT_LFaces facesByOriginalFaceX = facesByOriginalFace.begin();
+                       (facesByOriginalFaceX != facesEnd)&&merged;
+                       facesByOriginalFaceX++) {
+                               merged = mergeFaces((*facesByOriginalFaceX),oldFaces,newFaces,vertices,v);
+               }
+       }
+       return merged;
+}
+
+
+/**
+ * Merge a set of faces removing the vertex index v.
+ * @param faces set of faces
+ * @param oldFaces set of old faces obtained from the merge
+ * @param newFaces set of new faces obtained from the merge
+ * @param vertices sequence of indexs (v1 ... vi = v ... vn) where :
+ *   v is the current vertex to test,
+ *   vj (j < i) are tested vertices, 
+ *   vk (k >= i) are vertices required to test to merge vj
+ * (so if a vertex vk can't be merged, the merge is not possible).
+ * @param v vertex index
+ * @return true if the merge is succesful, false otherwise
+ */
+bool BOP_Merge::mergeFaces(BOP_Faces &faces, BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v)
+{
+
+       bool merged = false;
+
+       if (faces.size() == 2) {
+               // Merge a pair of faces into a new face without v
+               BOP_Face *faceI = faces[0];
+               BOP_Face *faceJ = faces[1];
+               BOP_Face *faceK = mergeFaces(faceI,faceJ,vertices,v);
+               if (faceK != NULL) {
+                       newFaces.push_back(faceK);
+                       oldFaces.push_back(faceI);
+                       oldFaces.push_back(faceJ);
+                       merged = true;
+               } 
+               else merged = false;
+       }
+       else if (faces.size() == 4) {
+               // Merge two pair of faces into a new pair without v
+               // First we try to perform a simplify merge to avoid more pending vertices
+               // (for example, if we have two triangles and two quads it will be better
+               // to do 3+4 and 3+4 than 3+3 and 4+4)
+               BOP_Face *oldFace1 = faces[0];
+               BOP_Face *oldFace2, *newFace1;
+               unsigned int indexJ = 1;
+               while (indexJ < faces.size() && !merged) {
+                       oldFace2 = faces[indexJ];
+                       newFace1 = mergeFaces(oldFace1,oldFace2,v);
+                       if (newFace1 != NULL) merged = true;
+                       else indexJ++;
+               }
+               if (merged) {
+                       // Merge the other pair of faces 
+                       unsigned int indexK, indexL;
+                       if (indexJ == 1) {indexK = 2;indexL = 3;}
+                       else if (indexJ == 2) {indexK = 1;indexL = 3;}
+                       else {indexK = 1;indexL = 2;}
+                       BOP_Face *oldFace3 = faces[indexK];
+                       BOP_Face *oldFace4 = faces[indexL];
+                       unsigned int oldSize = vertices.size();
+                       BOP_Face *newFace2 = mergeFaces(oldFace3,oldFace4,vertices,v);
+                       if (newFace2 != NULL) {
+                               newFaces.push_back(newFace1);
+                               newFaces.push_back(newFace2);
+                               oldFaces.push_back(oldFace1);
+                               oldFaces.push_back(oldFace2);
+                               oldFaces.push_back(oldFace3);
+                               oldFaces.push_back(oldFace4);
+                               merged = true;
+                       }
+                       else {
+                               // Undo all changes
+                               delete newFace1;
+                               merged = false;
+                               unsigned int count = vertices.size() - oldSize;
+                               if (count != 0)
+                                       vertices.erase(vertices.end() - count, vertices.end());
+                       }
+               }               
+               if (!merged) {
+                       // Try a complete merge
+                       merged = true;
+                       while (faces.size()>0 && merged) {
+                               indexJ = 1;
+                               BOP_Face *faceI = faces[0];
+                               merged = false;
+                               while (indexJ < faces.size()) {
+                                       BOP_Face *faceJ = faces[indexJ];
+                                       BOP_Face *faceK = mergeFaces(faceI,faceJ,vertices,v);
+                                       if (faceK != NULL) {
+                                               // faceK = faceI + faceJ and it does not include v!
+                                               faces.erase(faces.begin()+indexJ,faces.begin()+(indexJ+1));
+                                               faces.erase(faces.begin(),faces.begin()+1);
+                                               newFaces.push_back(faceK);
+                                               oldFaces.push_back(faceI);
+                                               oldFaces.push_back(faceJ);
+                                               merged = true;
+                                               break;
+                                       }
+                                       else indexJ++;
+                               }
+                       }
+               }
+       }
+       else merged = false; // there are N=1 or N=3 or N>4 faces!
+
+       // Return merge result
+       return merged;
+}
+
+/**
+ * Returns a new quad from the merge of two faces (one quad and one triangle) 
+ * that share the vertex v and come from the same original face.
+ * @param faceI mesh face (quad or triangle) with index v
+ * @param faceJ mesh face (quad or triangle) with index v
+ * @param v vertex index shared by both faces
+ * @return if the merge is possible, a new quad without v
+ */
+BOP_Face* BOP_Merge::mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v)
+{
+       if (faceI->size() == 3) {
+               if (faceJ->size() == 4)
+                       return mergeFaces((BOP_Face4*)faceJ,(BOP_Face3*)faceI,v);
+       }
+       else if (faceI->size() == 4) {
+               if (faceJ->size() == 3)
+                       return mergeFaces((BOP_Face4*)faceI,(BOP_Face3*)faceJ,v);
+       }
+       return NULL;
+}
+
+/**
+ * Returns a new face from the merge of two faces (quads or triangles) that
+ * share te vertex v and come from the same original face.
+ * @param faceI mesh face (quad or triangle) with index v
+ * @param faceJ mesh face (quad or triangle) with index v
+ * @param pending vector with pending vertices (required to merge two quads into 
+ * a new quad or one quad and one triangle into a new triangle; these merges 
+ * suppose to remove two vertexs, v and its neighbour, that will be a pending 
+ * vertex to merge if it wasn't)
+ * @param v vertex index shared by both faces
+ * @return if the merge is possible, a new face without v
+ */
+BOP_Face* BOP_Merge::mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Indexs &pending, BOP_Index v)
+{
+       if (faceI->size() == 3) {
+               if (faceJ->size() == 3)
+                       return mergeFaces((BOP_Face3*)faceI,(BOP_Face3*)faceJ,v);
+               else if (faceJ->size() == 4)
+                       return mergeFaces((BOP_Face4*)faceJ,(BOP_Face3*)faceI,pending,v);
+       }
+       else if (faceI->size() == 4) {
+               if (faceJ->size() == 3)
+                       return mergeFaces((BOP_Face4*)faceI,(BOP_Face3*)faceJ,pending,v);
+               else if (faceJ->size() == 4)
+                       return mergeFaces((BOP_Face4*)faceI,(BOP_Face4*)faceJ,pending,v);
+       }
+       return NULL;
+}
+
+/** 
+ * Returns a new triangle from the merge of two triangles that share the vertex
+ * v and come from the same original face.
+ * @param faceI mesh triangle
+ * @param faceJ mesh triangle
+ * @param v vertex index shared by both triangles
+ * @return If the merge is possible, a new triangle without v
+ */
+BOP_Face* BOP_Merge::mergeFaces(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v)
+{
+       BOP_Face *faceK = NULL;
+
+       // Get faces data
+       BOP_Index prevI, nextI, prevJ, nextJ;   
+       faceI->getNeighbours(v,prevI,nextI);
+       faceJ->getNeighbours(v,prevJ,nextJ);
+       MT_Point3 vertex = m_mesh->getVertex(v)->getPoint();
+       MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint();
+       MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint();
+       MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint();
+       MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint();
+
+       // Merge test
+       if (prevI == nextJ) {
+               // Both faces share the edge (prevI,v) == (v,nextJ)
+               if (BOP_between(vertex,vNextI,vPrevJ)) {
+                       faceK = new BOP_Face3(prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace());
+                       faceK->setTAG(faceI->getTAG());
+               }
+       }
+       else if (nextI == prevJ) {
+               // Both faces share the edge (v,nextI) == (prevJ,v)
+               if (BOP_between(vertex,vPrevI,vNextJ)) {
+                       faceK = new BOP_Face3(prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace());
+                       faceK->setTAG(faceI->getTAG());
+               }
+       }
+       return faceK;
+}
+
+/** 
+ * Returns a new quad from the merge of one quad and one triangle that share 
+ * the vertex v and come from the same original face.
+ * @param faceI mesh quad
+ * @param faceJ mesh triangle
+ * @param v vertex index shared by both faces
+ * @return If the merge is possible, a new quad without v
+ */
+BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Index v)
+{
+       BOP_Face *faceK = NULL;
+
+       // Get faces data
+       BOP_Index prevI, nextI, opp, prevJ, nextJ;
+       faceI->getNeighbours(v,prevI,nextI,opp);
+       faceJ->getNeighbours(v,prevJ,nextJ);
+       MT_Point3 vertex = m_mesh->getVertex(v)->getPoint();
+       MT_Point3 vOpp = m_mesh->getVertex(opp)->getPoint();
+       MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint();
+       MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint();
+       MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint();
+       MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint();
+
+       // Merge test
+       if (prevI == nextJ) {
+               if (BOP_between(vertex,vNextI,vPrevJ) && !BOP_collinear(vPrevJ,vPrevI,vOpp)
+                       && BOP_convex(vOpp,vPrevI,vPrevJ,vNextI)) {
+                       faceK = new BOP_Face4(opp,prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace());
+                       faceK->setTAG(faceI->getTAG());
+               }
+       }
+       else if (nextI == prevJ) {
+               if (BOP_between(vertex,vPrevI,vNextJ) && !BOP_collinear(vNextJ,vNextI,vOpp)
+                       && BOP_convex(vOpp,vPrevI,vNextJ,vNextI)) {
+                       faceK = new BOP_Face4(opp,prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace());
+                       faceK->setTAG(faceI->getTAG());
+               }
+       }
+       return faceK;
+}
+
+/** 
+ * Returns a new face (quad or triangle) from the merge of one quad and one 
+ * triangle that share the vertex v and come from the same original face.
+ * @param faceI mesh quad
+ * @param faceJ mesh triangle
+ * @param pending vector with pending vertices (required to merge one quad 
+ * and one triangle into a new triangle; it supposes to remove two vertexs,
+ * v and its neighbour, that will be a new pending vertex if it wasn't)
+ * @param v vertex index shared by both faces
+ * @return If the merge is possible, a new face without v
+ */
+BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Indexs &pending, BOP_Index v)
+{
+       BOP_Face *faceK = NULL;
+
+       // Get faces data
+       BOP_Index prevI, nextI, opp, prevJ, nextJ;
+       faceI->getNeighbours(v,prevI,nextI,opp);
+       faceJ->getNeighbours(v,prevJ,nextJ);
+       MT_Point3 vertex = m_mesh->getVertex(v)->getPoint();
+       MT_Point3 vOpp = m_mesh->getVertex(opp)->getPoint();
+       MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint();
+       MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint();
+       MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint();
+       MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint();
+
+       // Merge test
+       if (prevI == nextJ) {
+               if (BOP_between(vertex,vNextI,vPrevJ)) {
+                       if (!BOP_collinear(vPrevJ,vPrevI,vOpp) && BOP_convex(vOpp,vPrevI,vPrevJ,vNextI)) {
+                               // The result is a new quad
+                               faceK = new BOP_Face4(opp,prevI,prevJ,nextI,faceI->getPlane(),faceI->getOriginalFace());
+                               faceK->setTAG(faceI->getTAG());
+                       }
+                       else if (BOP_between(vPrevI,vPrevJ,vOpp)) {
+                               // The result is a triangle (only if prevI can be merged)
+                               if (prevI < m_firstVertex) return NULL; // It can't be merged
+                               faceK = new BOP_Face3(nextI,opp,prevJ,faceI->getPlane(),faceI->getOriginalFace());
+                               faceK->setTAG(faceI->getTAG());
+                               if (!containsIndex(pending, prevI)) pending.push_back(prevI);
+                       }
+               }
+       }
+       else if (nextI == prevJ) {
+               if (BOP_between(vertex,vPrevI,vNextJ)) {
+                       if (!BOP_collinear(vNextJ,vNextI,vOpp) && BOP_convex(vOpp,vPrevI,vNextJ,vNextI)) {
+                               // The result is a new quad
+                               faceK = new BOP_Face4(opp,prevI,nextJ,nextI,faceI->getPlane(),faceI->getOriginalFace());
+                               faceK->setTAG(faceI->getTAG());
+                       }
+                       else if (BOP_between(vNextI,vOpp,vNextJ)) {
+                               // The result is a triangle (only if nextI can be merged)
+                               if (nextI < m_firstVertex) return NULL;
+                               faceK = new BOP_Face3(prevI,nextJ,opp,faceI->getPlane(),faceI->getOriginalFace());
+                               faceK->setTAG(faceI->getTAG());
+                               if (!containsIndex(pending, nextI)) pending.push_back(nextI);
+                       }
+               }
+       }
+       return faceK;
+}
+
+/** 
+ * Returns a new quad from the merge of two quads that share 
+ * the vertex v and come from the same original face.
+ * @param faceI mesh quad
+ * @param faceJ mesh quad
+ * @param pending vector with pending vertices (required to merge the two
+ * quads supposes to remove two vertexs, v and its neighbour, 
+ * that will be a new pending vertex if it wasn't)
+ * @param v vertex index shared by both quads
+ * @return If the merge is possible, a new quad without v
+ */
+BOP_Face* BOP_Merge::mergeFaces(BOP_Face4 *faceI, BOP_Face4 *faceJ, BOP_Indexs &pending, BOP_Index v)
+{
+       BOP_Face *faceK = NULL;
+
+       // Get faces data
+       BOP_Index prevI, nextI, oppI, prevJ, nextJ, oppJ;
+       faceI->getNeighbours(v,prevI,nextI,oppI);
+       faceJ->getNeighbours(v,prevJ,nextJ,oppJ);
+       MT_Point3 vertex = m_mesh->getVertex(v)->getPoint();
+       MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint();
+       MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint();
+       MT_Point3 vOppI = m_mesh->getVertex(oppI)->getPoint();
+       MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint();
+       MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint();
+       MT_Point3 vOppJ = m_mesh->getVertex(oppJ)->getPoint();
+
+       // Merge test
+       if (prevI == nextJ) {
+               // prevI/nextJ will be a new vertex required to merge
+               if (prevI < m_firstVertex) return NULL; // It can't be merged
+               if (BOP_between(vertex,vPrevJ,vNextI) && BOP_between(vNextJ,vOppJ,vOppI)) {
+                       faceK = new BOP_Face4(oppJ,prevJ,nextI,oppI,faceI->getPlane(),faceI->getOriginalFace());
+                       faceK->setTAG(faceI->getTAG());
+                       // We add prevI to the pending list if it wasn't yet
+                       if (!containsIndex(pending, prevI)) pending.push_back(prevI);
+               }
+       }
+       else if (nextI == prevJ) {
+               // nextI/prevJ will be a new vertex required to merge
+               if (nextI < m_firstVertex) return NULL; // It can't be merged
+               if (BOP_between(vertex,vPrevI,vNextJ) && BOP_between(vNextI,vOppI,vOppJ)) {
+                       faceK = new BOP_Face4(oppI,prevI,nextJ,oppJ,faceI->getPlane(),faceI->getOriginalFace());
+                       faceK->setTAG(faceI->getTAG());
+                       // Add nextI to the pending list if it wasn't yet
+                       if (!containsIndex(pending, nextI)) pending.push_back(nextI);
+               }
+       }
+       return faceK;
+}
+
+
+/** 
+ * Simplifies the mesh, merging the pairs of triangles that come frome the
+ * same original face and define a quad.
+ * @return true if a quad was added, false otherwise
+ */
+bool BOP_Merge::createQuads()
+{
+  
+       BOP_Faces quads;
+       
+       // Get mesh faces
+       BOP_Faces faces = m_mesh->getFaces();
+       
+    // Merge mesh triangles
+       const BOP_IT_Faces facesIEnd = (faces.end()-1);
+       const BOP_IT_Faces facesJEnd = faces.end();
+       for(BOP_IT_Faces faceI=faces.begin();faceI!=facesIEnd;faceI++) {
+               if ((*faceI)->getTAG() == BROKEN || (*faceI)->size() != 3) continue;
+               for(BOP_IT_Faces faceJ=(faceI+1);faceJ!=facesJEnd;faceJ++) {
+                       if ((*faceJ)->getTAG() == BROKEN || (*faceJ)->size() != 3 ||
+                               (*faceJ)->getOriginalFace() != (*faceI)->getOriginalFace()) continue;
+
+                       // Test if both triangles share a vertex index
+                       BOP_Index v;
+                       bool found = false;
+                       for(unsigned int i=0;i<3 && !found;i++) {
+                               v = (*faceI)->getVertex(i);
+                               found = (*faceJ)->containsVertex(v);
+                               
+                       }
+                       if (!found) continue;
+
+                       BOP_Face *faceK = createQuad((BOP_Face3*)*faceI,(BOP_Face3*)*faceJ,v);
+                       if (faceK != NULL) {
+                               // Set triangles to BROKEN
+                               (*faceI)->setTAG(BROKEN);
+                               (*faceJ)->setTAG(BROKEN);
+                               quads.push_back(faceK);
+                               break;
+                       }
+               }
+       }
+
+    // Add quads to mesh
+       const BOP_IT_Faces quadsEnd = quads.end();
+       for(BOP_IT_Faces quad=quads.begin();quad!=quadsEnd;quad++) m_mesh->addFace(*quad);
+       return (quads.size() > 0);
+}
+
+/** 
+ * Returns a new quad (convex) from the merge of two triangles that share the
+ * vertex index v.
+ * @param faceI mesh triangle
+ * @param faceJ mesh triangle
+ * @param v vertex index shared by both triangles
+ * @return a new convex quad if the merge is possible
+ */
+BOP_Face* BOP_Merge::createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v)
+{
+       BOP_Face *faceK = NULL;
+
+       // Get faces data
+       BOP_Index prevI, nextI, prevJ, nextJ;
+       faceI->getNeighbours(v,prevI,nextI);
+       faceJ->getNeighbours(v,prevJ,nextJ);
+       MT_Point3 vertex = m_mesh->getVertex(v)->getPoint();
+       MT_Point3 vPrevI = m_mesh->getVertex(prevI)->getPoint();
+       MT_Point3 vNextI = m_mesh->getVertex(nextI)->getPoint();
+       MT_Point3 vPrevJ = m_mesh->getVertex(prevJ)->getPoint();
+       MT_Point3 vNextJ = m_mesh->getVertex(nextJ)->getPoint();
+
+       // Quad test
+       if (prevI == nextJ) {
+               if (!BOP_collinear(vNextI,vertex,vPrevJ) && !BOP_collinear(vNextI,vPrevI,vPrevJ) &&
+                       BOP_convex(vertex,vNextI,vPrevI,vPrevJ)) {
+                               faceK = new BOP_Face4(v,nextI,prevI,prevJ,faceI->getPlane(),faceI->getOriginalFace());
+                               faceK->setTAG(faceI->getTAG());
+               }
+       }
+       else if (nextI == prevJ) {
+               if (!BOP_collinear(vPrevI,vertex,vNextJ) && !BOP_collinear(vPrevI,vNextI,vNextJ) &&
+                       BOP_convex(vertex,vNextJ,vNextI,vPrevI)) {
+                               faceK = new BOP_Face4(v,nextJ,nextI,prevI,faceI->getPlane(),faceI->getOriginalFace());
+                               faceK->setTAG(faceI->getTAG());
+                       }
+       }
+       return faceK;
+}
+
+/**
+ * Returns if a index is inside a set of indexs.
+ * @param indexs set of indexs
+ * @param i index
+ * @return true if the index is inside the set, false otherwise
+ */
+bool BOP_Merge::containsIndex(BOP_Indexs indexs, BOP_Index i)
+{
+  const BOP_IT_Indexs indexsEnd = indexs.end();
+       for(BOP_IT_Indexs it=indexs.begin();it!=indexsEnd;it++) {
+               if (*it == i) return true;
+       }
+       return false;
+}
+
+/**
+ * Creates a list of lists L1, L2, ... LN where
+ *   LX = mesh faces with vertex v that come from the same original face
+ * @param facesByOriginalFace list of faces lists
+ * @param v vertex index
+ */
+void BOP_Merge::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Index v)
+{
+       // Get edges with vertex v
+       BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges();
+       const BOP_IT_Indexs edgeEnd = edgeIndexs.end();
+       for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) {    
+               // Foreach edge, add its no broken faces to the output list
+               BOP_Edge* edge = m_mesh->getEdge(*edgeIndex);
+               BOP_Indexs faceIndexs = edge->getFaces();
+               const BOP_IT_Indexs faceEnd = faceIndexs.end();
+               for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) {
+                       BOP_Face* face = m_mesh->getFace(*faceIndex);
+                       if (face->getTAG() != BROKEN) {
+                               bool found = false;
+                               // Search if we already have created a list for the 
+                               // faces that come from the same original face
+                               const BOP_IT_LFaces lfEnd = facesByOriginalFace.end();
+                               for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin();
+                               facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) {
+                                       if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) {
+                                               // Search that the face has not been added to the list before
+                                               for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) {
+                                                       if ((*facesByOriginalFaceX)[i] == face) {
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if (!found) {
+                                                       // Add the face to the list
+                                                 if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face);
+                                                 else facesByOriginalFaceX->push_back(face);
+                                                 found = true;
+                                               }
+                                               break;
+                                       }
+                               }
+                               if (!found) {
+                                       // Create a new list and add the current face
+                                       BOP_Faces facesByOriginalFaceX;
+                                       facesByOriginalFaceX.push_back(face);
+                                       facesByOriginalFace.push_back(facesByOriginalFaceX);
+                               }
+                       }
+               }
+       }
+}
+
+/**
+ * Creates a list of lists L1, L2, ... LN where
+ *   LX = mesh faces with vertex v that come from the same original face
+ *        and without any of the vertices that appear before v in vertices
+ * @param facesByOriginalFace list of faces lists
+ * @param vertices vector with vertices indexs that contains v
+ * @param v vertex index
+ */
+void BOP_Merge::getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v)
+{
+       // Get edges with vertex v
+       BOP_Indexs edgeIndexs = m_mesh->getVertex(v)->getEdges();
+       const BOP_IT_Indexs edgeEnd = edgeIndexs.end();
+       for(BOP_IT_Indexs edgeIndex = edgeIndexs.begin();edgeIndex != edgeEnd;edgeIndex++) {    
+               // Foreach edge, add its no broken faces to the output list
+               BOP_Edge* edge = m_mesh->getEdge(*edgeIndex);
+               BOP_Indexs faceIndexs = edge->getFaces();
+               const BOP_IT_Indexs faceEnd = faceIndexs.end();
+               for(BOP_IT_Indexs faceIndex=faceIndexs.begin();faceIndex!=faceEnd;faceIndex++) {
+                       BOP_Face* face = m_mesh->getFace(*faceIndex);
+                       if (face->getTAG() != BROKEN) {
+                               // Search if the face contains any of the forbidden vertices
+                               bool found = false;
+                               for(BOP_IT_Indexs vertex = vertices.begin();*vertex!= v;vertex++) {
+                                       if (face->containsVertex(*vertex)) {
+                                               // face contains a forbidden vertex!
+                                               found = true;
+                                               break;
+                               }
+                       }
+                       if (!found) {
+                               // Search if we already have created a list with the 
+                               // faces that come from the same original face
+                         const BOP_IT_LFaces lfEnd = facesByOriginalFace.end();
+                               for(BOP_IT_LFaces facesByOriginalFaceX=facesByOriginalFace.begin();
+                                       facesByOriginalFaceX!=lfEnd; facesByOriginalFaceX++) {
+                                       if (((*facesByOriginalFaceX)[0])->getOriginalFace() == face->getOriginalFace()) {
+                                               // Search that the face has not been added to the list before
+                                               for(unsigned int i = 0;i<(*facesByOriginalFaceX).size();i++) {
+                                                       if ((*facesByOriginalFaceX)[i] == face) {
+                                                               found = true;
+                                                               break;
+                                                       }
+                                               }
+                                               if (!found) {
+                                                 // Add face to the list
+                                                 if (face->getTAG()==OVERLAPPED) facesByOriginalFaceX->insert(facesByOriginalFaceX->begin(),face);
+                                                 else facesByOriginalFaceX->push_back(face);
+                                                 found = true;
+                                               }
+                                               break;
+                                       }
+                               }
+                               if (!found) {
+                                       // Create a new list and add the current face
+                                       BOP_Faces facesByOriginalFaceX;
+                                       facesByOriginalFaceX.push_back(face);
+                                       facesByOriginalFace.push_back(facesByOriginalFaceX);
+                               }
+                       }
+               }
+       }
+       }
+}
diff --git a/intern/boolop/intern/BOP_Merge.h b/intern/boolop/intern/BOP_Merge.h
new file mode 100644 (file)
index 0000000..2ccce8e
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_MERGE_H
+#define BOP_MERGE_H
+
+#include "BOP_Mesh.h"
+#include "BOP_Tag.h"
+#include "BOP_MathUtils.h"
+#include "MEM_SmartPtr.h"
+
+typedef vector< BOP_Faces > BOP_LFaces;
+typedef vector< BOP_Faces >::iterator BOP_IT_LFaces;
+
+class BOP_Merge {
+       private:
+               BOP_Mesh* m_mesh;
+               BOP_Index m_firstVertex;
+               static BOP_Merge SINGLETON;
+
+               BOP_Merge() {};
+               bool mergeFaces();
+               bool mergeFaces(BOP_Indexs &mergeVertices);
+               bool mergeFaces(BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v);
+               bool mergeFaces(BOP_Faces &faces, BOP_Faces &oldFaces, BOP_Faces &newFaces, BOP_Indexs &vertices, BOP_Index v);
+               BOP_Face *mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Index v);
+               BOP_Face *mergeFaces(BOP_Face *faceI, BOP_Face *faceJ, BOP_Indexs &pending, BOP_Index v);
+               BOP_Face *mergeFaces(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v);
+               BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Index v);
+               BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face3 *faceJ, BOP_Indexs &pending, BOP_Index v);
+               BOP_Face *mergeFaces(BOP_Face4 *faceI, BOP_Face4 *faceJ, BOP_Indexs &pending, BOP_Index v);
+               bool createQuads();
+               BOP_Face *createQuad(BOP_Face3 *faceI, BOP_Face3 *faceJ, BOP_Index v);
+               bool containsIndex(BOP_Indexs indexs, BOP_Index index);
+               void getFaces(BOP_LFaces &facesByOriginalFace, BOP_Index v);
+               void getFaces(BOP_LFaces &facesByOriginalFace, BOP_Indexs vertices, BOP_Index v);
+
+       public:
+
+               static BOP_Merge &getInstance() {
+                       return SINGLETON;
+               }
+
+               void mergeFaces(BOP_Mesh *m, BOP_Index v);
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_Mesh.cpp b/intern/boolop/intern/BOP_Mesh.cpp
new file mode 100644 (file)
index 0000000..d8193f9
--- /dev/null
@@ -0,0 +1,835 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_Mesh.h"
+#include "BOP_MathUtils.h"
+#include <iostream>
+#include <fstream>
+
+
+/**
+ * Destroys a mesh.
+ */
+BOP_Mesh::~BOP_Mesh()
+{
+       const BOP_IT_Vertexs vertexsEnd = m_vertexs.end();
+       for(BOP_IT_Vertexs it=m_vertexs.begin();it!=vertexsEnd;it++){
+               delete *it;
+       }
+       m_vertexs.clear();
+  
+       const BOP_IT_Edges edgesEnd = m_edges.end();
+       for(BOP_IT_Edges it=m_edges.begin();it!=edgesEnd;it++){
+               delete *it;
+       }
+       m_edges.clear();
+  
+       const BOP_IT_Faces facesEnd = m_faces.end();
+       for(BOP_IT_Faces it=m_faces.begin();it!=facesEnd;it++){
+               delete *it;
+       }
+       m_faces.clear();
+}
+
+/**
+ * Adds a new vertex.
+ * @param p vertex point
+ * @return mesh vertex index
+ */
+BOP_Index BOP_Mesh::addVertex(MT_Point3 p)
+{
+       m_vertexs.push_back(new BOP_Vertex(p));
+       return m_vertexs.size()-1;
+}
+
+/**
+ * Adds a new edge.
+ * @param v1 mesh vertex index
+ * @param v2 mesh vertex index
+ * @return mesh edge index
+ */
+BOP_Index BOP_Mesh::addEdge(BOP_Index v1, BOP_Index v2)
+{
+       m_edges.push_back(new BOP_Edge(v1,v2));
+       return (m_edges.size()-1);
+}
+
+/**
+ * Adds a new face.
+ * @param face mesh face
+ * @return mesh face index
+ */
+BOP_Index BOP_Mesh::addFace(BOP_Face *face)
+{
+       if (face->size()==3)
+               return addFace((BOP_Face3 *)face);
+       else
+               return addFace((BOP_Face4 *)face);
+}
+
+/**
+ * Adds a new triangle.
+ * @param face mesh triangle
+ * @return mesh face index
+ */
+BOP_Index BOP_Mesh::addFace(BOP_Face3 *face)
+{
+       BOP_Index indexface = m_faces.size();
+       
+       BOP_Index index1 = face->getVertex(0);
+       BOP_Index index2 = face->getVertex(1);
+       BOP_Index index3 = face->getVertex(2);
+
+       m_faces.push_back((BOP_Face *)face);  
+               
+       BOP_Index edge;
+
+       if (!getIndexEdge(index1,index2,edge)) {
+               edge = addEdge(index1,index2);
+               getVertex(index1)->addEdge(edge);
+               getVertex(index2)->addEdge(edge);
+       }
+               
+       getEdge(edge)->addFace(indexface);
+       
+       if (!getIndexEdge(index2,index3,edge)) {
+               edge = addEdge(index2,index3);
+               getVertex(index2)->addEdge(edge);
+               getVertex(index3)->addEdge(edge);
+       }
+    
+       getEdge(edge)->addFace(indexface);
+
+       if (!getIndexEdge(index3,index1,edge)) {
+               edge = addEdge(index3,index1);
+               getVertex(index3)->addEdge(edge);
+               getVertex(index1)->addEdge(edge);
+       }
+    
+       getEdge(edge)->addFace(indexface);
+       
+       if ((index1 == index2) || (index1 == index3) || (index2 == index3))
+               face->setTAG(BROKEN);
+
+       return indexface;  
+}
+
+/**
+ * Adds a new quad.
+ * @param face mesh quad
+ * @return mesh face index
+ */
+BOP_Index BOP_Mesh::addFace(BOP_Face4 *face)
+{
+       m_faces.push_back((BOP_Face *)face);
+       BOP_Index indexface = m_faces.size()-1;
+  
+       BOP_Index index1 = face->getVertex(0);
+       BOP_Index index2 = face->getVertex(1);
+       BOP_Index index3 = face->getVertex(2);
+       BOP_Index index4 = face->getVertex(3);
+  
+       BOP_Index edge;
+  
+       if (!getIndexEdge(index1,index2,edge)) {
+               edge = addEdge(index1,index2);
+               getVertex(index1)->addEdge(edge);
+               getVertex(index2)->addEdge(edge);
+       }
+  
+       getEdge(edge)->addFace(indexface);
+  
+       if (!getIndexEdge(index2,index3,edge)) {
+               edge = addEdge(index2,index3);
+               getVertex(index2)->addEdge(edge);
+               getVertex(index3)->addEdge(edge);
+       }
+  
+       getEdge(edge)->addFace(indexface);      
+  
+       if (!getIndexEdge(index3,index4,edge)) {
+               edge = addEdge(index3,index4);
+               getVertex(index3)->addEdge(edge);
+               getVertex(index4)->addEdge(edge);
+       }
+  
+       getEdge(edge)->addFace(indexface);      
+  
+       if (!getIndexEdge(index4,index1,edge)) {
+               edge = addEdge(index4,index1);
+               getVertex(index4)->addEdge(edge);
+               getVertex(index1)->addEdge(edge);
+       }
+  
+       getEdge(edge)->addFace(indexface);
+  
+       if ((index1 == index2) || (index1 == index3) || (index1 == index4) || 
+               (index2 == index3) || (index2 == index4) || (index3 == index4))
+               face->setTAG(BROKEN);
+
+       return m_faces.size()-1;
+}
+
+/**
+ * Returns if a faces set contains the specified face.
+ * @param faces faces set
+ * @param face face
+ * @return true if the set contains the specified face
+ */
+bool BOP_Mesh::containsFace(BOP_Faces *faces, BOP_Face *face) 
+{
+  const BOP_IT_Faces facesEnd = faces->end();
+       for(BOP_IT_Faces it = faces->begin();it!=facesEnd;it++) {
+               if (face == *it)
+                       return true;
+       }
+       
+       return false;
+}
+/**
+ * Returns the first edge with the specified vertex index from a list of edge indexs.
+ * @param edges edge indexs
+ * @param v vertex index
+ * @return first edge with the specified vertex index, NULL otherwise
+ */
+BOP_Edge* BOP_Mesh::getEdge(BOP_Indexs edges, BOP_Index v)
+{
+  const BOP_IT_Indexs edgesEnd = edges.end();
+       for(BOP_IT_Indexs it=edges.begin();it!=edgesEnd;it++){
+               BOP_Edge *edge = m_edges[*it];
+               if ((edge->getVertex1() == v) || (edge->getVertex2() == v))
+                       return edge;
+       }
+       return NULL;
+}
+
+/**
+ * Returns the mesh edge with the specified vertex indexs.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ * @return mesh edge with the specified vertex indexs, NULL otherwise
+ */
+BOP_Edge* BOP_Mesh::getEdge(BOP_Index v1, BOP_Index v2)
+{
+       const BOP_IT_Edges edgesEnd = m_edges.end();
+       for(BOP_IT_Edges edge=m_edges.begin();edge!=edgesEnd;edge++) {
+               if (((*edge)->getVertex1() == v1 && (*edge)->getVertex2() == v2) ||
+                       ((*edge)->getVertex1() == v2 && (*edge)->getVertex2() == v1)) 
+                       return *edge;
+       } 
+       return NULL;
+}
+
+/**
+ * Returns the mesh edge index with the specified vertex indexs.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ * @param e edge index with the specified vertex indexs
+ * @return true if there is a mesh edge with the specified vertex indexs, false otherwise
+ */
+bool BOP_Mesh::getIndexEdge(BOP_Index v1, BOP_Index v2, BOP_Index &e)
+{
+       BOP_Index pos=0;
+       const BOP_IT_Edges edgesEnd = m_edges.end();
+       for(BOP_IT_Edges edge=m_edges.begin();edge!=edgesEnd;edge++,pos++) {
+               if (((*edge)->getVertex1() == v1 && (*edge)->getVertex2() == v2) ||
+                   ((*edge)->getVertex1() == v2 && (*edge)->getVertex2() == v1)){
+                 e = pos;
+                 return true;
+               }
+       } 
+       return false;
+}
+
+/**
+ * Returns the mesh edge on the specified face and relative edge index.
+ * @param face mesh face
+ * @param edge face relative edge index
+ * @return mesh edge on the specified face and relative index, NULL otherwise
+ */
+BOP_Edge* BOP_Mesh::getEdge(BOP_Face *face, unsigned int edge)
+{
+       if (face->size()==3)
+               return getEdge((BOP_Face3 *)face,edge);
+       else
+               return getEdge((BOP_Face4 *)face,edge);
+}
+
+/**
+ * Returns the mesh edge on the specified triangle and relative edge index.
+ * @param face mesh triangle
+ * @param edge face relative edge index
+ * @return mesh edge on the specified triangle and relative index, NULL otherwise
+ */
+BOP_Edge* BOP_Mesh::getEdge(BOP_Face3 *face, unsigned int edge)
+{
+       switch(edge){
+       case 1:
+               return getEdge(m_vertexs[face->getVertex(0)]->getEdges(),face->getVertex(1));
+       case 2:
+               return getEdge(m_vertexs[face->getVertex(1)]->getEdges(),face->getVertex(2));
+       case 3:
+               return getEdge(m_vertexs[face->getVertex(2)]->getEdges(),face->getVertex(0));
+       };
+  
+       return NULL;
+}
+
+/**
+ * Returns the mesh edge on the specified quad and relative edge index.
+ * @param face mesh quad
+ * @param edge face relative edge index
+ * @return mesh edge on the specified quad and relative index, NULL otherwise
+ */
+BOP_Edge * BOP_Mesh::getEdge(BOP_Face4 *face, unsigned int edge)
+{
+       switch(edge){
+       case 1:
+               return getEdge(m_vertexs[face->getVertex(0)]->getEdges(),face->getVertex(1));
+       case 2:
+               return getEdge(m_vertexs[face->getVertex(1)]->getEdges(),face->getVertex(2));
+       case 3:
+               return getEdge(m_vertexs[face->getVertex(2)]->getEdges(),face->getVertex(3));
+       case 4:
+               return getEdge(m_vertexs[face->getVertex(3)]->getEdges(),face->getVertex(0));
+       };
+       
+       return NULL;
+}
+
+/**
+ * Returns the mesh face with the specified vertex indexs.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ * @param v3 vertex index
+ * @return mesh edge with the specified vertex indexs, NULL otherwise
+ */
+BOP_Face* BOP_Mesh::getFace(BOP_Index v1, BOP_Index v2, BOP_Index v3) 
+{
+       const BOP_IT_Faces facesEnd = m_faces.end();
+       for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++) {
+               if ((*face)->containsVertex(v1) && (*face)->containsVertex(v2) && 
+                       (*face)->containsVertex(v3))
+                       return (*face);
+       } 
+       return NULL;
+}
+
+/**
+ * Returns the mesh face index with the specified vertex indexs.
+ * @param v1 vertex index
+ * @param v2 vertex index
+ * @param v3 vertex index
+ * @param f face index with the specified vertex indexs
+ * @return true if there is a mesh face with the specified vertex indexs, false otherwise
+ */
+bool BOP_Mesh::getIndexFace(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index &f) 
+{
+       BOP_Index pos=0;
+       const BOP_IT_Faces facesEnd = m_faces.end();
+       for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++,pos++) {
+               if ((*face)->containsVertex(v1) && (*face)->containsVertex(v2) && 
+                   (*face)->containsVertex(v3)){
+                 f = pos;
+                 return true;
+               }
+       } 
+       return false;
+}
+
+/**
+ * Returns the vertices set of this mesh.
+ * @return vertices set
+ */
+BOP_Vertexs &BOP_Mesh::getVertexs() 
+{
+       return m_vertexs;
+} 
+
+/**
+ * Returns the edges set of this mesh.
+ * @return edges set
+ */
+BOP_Edges &BOP_Mesh::getEdges() 
+{
+       return m_edges;
+} 
+
+/**
+ * Returns the faces set of this mesh.
+ * @return faces set
+ */
+BOP_Faces &BOP_Mesh::getFaces() 
+{
+       return m_faces;
+} 
+
+/**
+ * Returns the mesh vertex with the specified index.
+ * @param i vertex index
+ * @return vertex with the specified index
+ */
+BOP_Vertex* BOP_Mesh::getVertex(BOP_Index i)
+{
+       return m_vertexs[i];
+}
+
+/**
+ * Returns the mesh edge with the specified index.
+ * @param i edge index
+ * @return edge with the specified index
+ */
+BOP_Edge* BOP_Mesh::getEdge(BOP_Index i) 
+{
+       return m_edges[i];
+}
+
+/**
+ * Returns the mesh face with the specified index.
+ * @param i face index
+ * @return face with the specified index
+ */
+BOP_Face* BOP_Mesh::getFace(BOP_Index i)
+{
+       return m_faces[i];
+}
+
+/**
+ * Returns the number of vertices of this mesh.
+ * @return number of vertices
+ */
+unsigned int BOP_Mesh::getNumVertexs() 
+{
+       return m_vertexs.size();
+}
+
+/**
+ * Returns the number of edges of this mesh.
+ * @return number of edges
+ */
+unsigned int BOP_Mesh::getNumEdges() 
+{
+       return m_edges.size();
+}
+
+/**
+ * Returns the number of faces of this mesh.
+ * @return number of faces
+ */
+unsigned int BOP_Mesh::getNumFaces() 
+{
+       return m_faces.size();
+}
+
+/**
+ * Returns the number of vertices of this mesh with the specified tag.
+ * @return number of vertices with the specified tag
+ */
+unsigned int BOP_Mesh::getNumVertexs(BOP_TAG tag) 
+{
+       unsigned int count = 0;
+       const BOP_IT_Vertexs vertexsEnd = m_vertexs.end();
+       for(BOP_IT_Vertexs vertex=m_vertexs.begin();vertex!=vertexsEnd;vertex++) {
+               if ((*vertex)->getTAG() == tag) count++;
+       }
+       return count;
+}
+/**
+ * Returns the number of faces of this mesh with the specified tag.
+ * @return number of faces with the specified tag
+ */
+unsigned int BOP_Mesh::getNumFaces(BOP_TAG tag) 
+{
+       unsigned int count = 0;
+       const BOP_IT_Faces facesEnd = m_faces.end();
+       for(BOP_IT_Faces face=m_faces.begin();face!=facesEnd;face++) {
+               if ((*face)->getTAG() == tag) count++;
+       }
+       return count;
+}
+
+/**
+ * Replaces a vertex index.
+ * @param oldIndex old vertex index
+ * @param newIndex new vertex index
+ */
+BOP_Index BOP_Mesh::replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex) 
+{
+       if (oldIndex==newIndex) return newIndex;
+  
+       // Update faces, edges and vertices  
+       BOP_Vertex *oldVertex = m_vertexs[oldIndex];
+       BOP_Vertex *newVertex = m_vertexs[newIndex];
+       BOP_Indexs oldEdges = oldVertex->getEdges();
+
+       BOP_Index edgeIdx=0;
+       bool found = false;
+
+       // Update faces to the newIndex
+       BOP_IT_Indexs oldEdgesEnd = oldEdges.end();
+       for(BOP_IT_Indexs oldEdgeIndex=oldEdges.begin();oldEdgeIndex!=oldEdgesEnd;
+                  oldEdgeIndex++) {
+               BOP_Edge *edge = m_edges[*oldEdgeIndex];
+               if ((edge->getVertex1()==oldIndex && edge->getVertex2()==newIndex) ||
+                       (edge->getVertex2()==oldIndex && edge->getVertex1()==newIndex)) {
+                       // Remove old edge  ==> set edge faces to BROKEN      
+                       BOP_Indexs edgeFaces = edge->getFaces();
+                       const BOP_IT_Indexs edgeFacesEnd = edgeFaces.end();
+                       for(BOP_IT_Indexs idxFace=edgeFaces.begin();idxFace!=edgeFacesEnd;
+                                  idxFace++) {
+                               m_faces[*idxFace]->setTAG(BROKEN);
+                       }
+                       edgeIdx = *oldEdgeIndex;
+                       found = true;
+               }
+               else {
+                       BOP_Indexs faces = edge->getFaces();
+                       const BOP_IT_Indexs facesEnd = faces.end();
+                       for(BOP_IT_Indexs face=faces.begin();face!=facesEnd;face++) {
+                               if (m_faces[*face]->getTAG()!=BROKEN)
+                                       m_faces[*face]->replaceVertexIndex(oldIndex,newIndex);
+                       }
+               }
+       } 
+       if (found) {
+               oldVertex->removeEdge(edgeIdx);
+               newVertex->removeEdge(edgeIdx);
+       }
+
+       oldEdgesEnd = oldEdges.end();
+       for(BOP_IT_Indexs oldEdgeIndex=oldEdges.begin();oldEdgeIndex!=oldEdgesEnd;
+                  oldEdgeIndex++) {
+               BOP_Edge * edge = m_edges[*oldEdgeIndex];
+               BOP_Edge * edge2;
+               BOP_Index v1 = edge->getVertex1();
+    
+               v1 = (v1==oldIndex?edge->getVertex2():v1);      
+               if ((edge2 = getEdge(newIndex,v1)) == NULL) {
+                       edge->replaceVertexIndex(oldIndex,newIndex);
+                       newVertex->addEdge(*oldEdgeIndex);
+               }
+               else {
+                       BOP_Indexs faces = edge->getFaces();
+                       const BOP_IT_Indexs facesEnd = faces.end();
+                       for(BOP_IT_Indexs f=faces.begin();f!=facesEnd;f++) {
+                               if (m_faces[*f]->getTAG()!=BROKEN)
+                               edge2->addFace(*f);
+                       }
+                       BOP_Vertex *oppositeVertex = m_vertexs[v1];
+                       oppositeVertex->removeEdge(*oldEdgeIndex);
+                       edge->replaceVertexIndex(oldIndex,newIndex);
+               }
+       }
+       oldVertex->setTAG(BROKEN);
+
+       return newIndex;
+}
+
+
+
+/** ***************************************************************************
+ * DEBUG METHODS                                                              * 
+ * This functions are used to test the mesh state and debug program errors.   *
+ ******************************************************************************/
+
+/**
+ * print
+ */
+void BOP_Mesh::print() 
+{
+       cout << "--Faces--" << endl;
+       for(unsigned int i=0;i<m_faces.size();i++){
+               cout << "Face " << i << ": " << m_faces[i] << endl;
+       }
+
+       cout << "--Vertices--" << endl;
+       for(unsigned int i=0;i<m_vertexs.size();i++){
+               cout << "Point " << i << ": " << m_vertexs[i]->getPoint() << endl;
+       }
+}
+
+/**
+ * printFormat
+ */
+void BOP_Mesh::printFormat(BOP_Faces *faces)
+{
+       if (faces->size()) {
+               for(unsigned int it=1;it<faces->size();it++) {
+                       if ((*faces)[it]->getTAG()!=BROKEN) {
+                               cout << m_vertexs[(*faces)[it]->getVertex(0)]->getPoint() << " ";
+                               cout << m_vertexs[(*faces)[it]->getVertex(1)]->getPoint() << " ";
+                               cout << m_vertexs[(*faces)[it]->getVertex(2)]->getPoint() << endl;
+                       }
+               }
+       }
+}
+
+/**
+ * saveFormat
+ */
+void BOP_Mesh::saveFormat(BOP_Faces *faces,char *filename)
+{
+       ofstream fout(filename);
+  
+       if (!fout.is_open()) {
+               cerr << "BOP_Mesh::saveFormat Error: Could not create file." << endl;
+               return;
+       }
+
+       unsigned int count = 0;
+       if (faces->size()) {
+               for(unsigned int it=0;it<faces->size();it++) {
+                       if ((*faces)[it]->getTAG()!=BROKEN) {
+                               count++;
+                       }
+               }
+       }
+
+       fout << count << endl;
+       if (faces->size()) {
+               for(unsigned int it=0;it<faces->size();it++) {
+                       if ((*faces)[it]->getTAG()!=BROKEN){
+                               fout << m_vertexs[(*faces)[it]->getVertex(0)]->getPoint() << " ";
+                               fout << m_vertexs[(*faces)[it]->getVertex(1)]->getPoint() << " ";
+                               fout << m_vertexs[(*faces)[it]->getVertex(2)]->getPoint() << endl;
+                       }
+               }
+       }
+
+       fout.close();
+}
+
+/**
+ * printFormat
+ */
+void BOP_Mesh::printFormat()
+{
+       cout << "--Vertices--" << endl;
+       if (m_vertexs.size()>0) {
+               cout << "{" << m_vertexs[0]->getPoint().x() << ",";
+               cout << m_vertexs[0]->getPoint().y() << ",";
+               cout << m_vertexs[0]->getPoint().z() << "}";
+               for(unsigned int i=1;i<m_vertexs.size();i++) {
+                       cout << ",{" << m_vertexs[i]->getPoint().x() << ",";
+                       cout << m_vertexs[i]->getPoint().y() << ",";
+                       cout << m_vertexs[i]->getPoint().z() << "}";
+               }
+               cout << endl;
+       }
+
+       cout << "--Faces--" << endl;
+       if (m_faces.size()>0) {
+               cout << "{" << m_faces[0]->getVertex(0) << ",";
+               cout << m_faces[0]->getVertex(1) << "," << m_faces[0]->getVertex(2) << "}";
+               for(unsigned int i=1;i<m_faces.size();i++) {
+                       cout << ",{" << m_faces[i]->getVertex(0) << ",";
+                       cout << m_faces[i]->getVertex(1) << "," << m_faces[i]->getVertex(2) << "}";
+               }
+               cout << endl;
+       }
+}
+
+/**
+ * printFace
+ */
+void BOP_Mesh::printFace(BOP_Face *face, int col)
+{
+  cout << "--Face" << endl;
+       cout << m_vertexs[face->getVertex(0)]->getPoint();
+       cout << " " << m_vertexs[face->getVertex(1)]->getPoint();
+       cout << " " << m_vertexs[face->getVertex(2)]->getPoint();
+       if (face->size()==4)
+         cout << " " << m_vertexs[face->getVertex(3)]->getPoint();
+       cout << " " << col << endl;
+}
+
+/**
+ * testMesh
+ */
+void BOP_Mesh::testMesh()
+{
+
+       BOP_Face* cares[10];
+       unsigned int nedges=0;
+       for(unsigned int i=0;i<m_edges.size();i++) {
+               BOP_Edge *edge = m_edges[i];
+               BOP_Indexs faces = edge->getFaces();
+               unsigned int count = 0;
+               const BOP_IT_Indexs facesEnd = faces.end();
+               for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) {
+                       if (m_faces[*it]->getTAG()!=BROKEN) {
+                               cares[count] = m_faces[*it];
+                               count++;
+                               
+                       }
+               }
+
+               if ((count%2)!=0) nedges++;
+       }
+       if (nedges)
+         cout << nedges << " wrong edges." << endl;
+       else
+         cout << "well edges." << endl;
+
+       unsigned int duplFaces = 0;
+       unsigned int wrongFaces = 0;
+       for(unsigned int i=0;i<m_faces.size();i++){
+         BOP_Face *faceI = m_faces[i];
+         if (faceI->getTAG()==BROKEN)
+           continue;
+
+         if (testFace(faceI)){
+           wrongFaces++;
+           cout << "Wrong Face: " << faceI << endl;
+         }
+
+         for(unsigned int j=i+1;j<m_faces.size();j++){
+           BOP_Face *faceJ = m_faces[j];
+
+           if (faceJ->getTAG()==BROKEN)
+             continue;
+
+           if (testFaces(faceI,faceJ)){
+             duplFaces++;
+             cout << "Duplicate FaceI: " << faceI << endl;
+             cout << "Duplicate FaceJ: " << faceJ << endl;
+           }
+         }
+       }
+
+       cout << duplFaces << " duplicate faces." << endl;
+       cout << wrongFaces << " wrong faces." << endl;
+}
+
+/**
+ * testFace
+ */
+bool BOP_Mesh::testFace(BOP_Face *face){
+  
+  for(unsigned int i=0;i<face->size();i++){
+    for(unsigned int j=i+1;j<face->size();j++){
+      if (face->getVertex(i)==face->getVertex(j))
+       return true;
+    }
+  }
+
+  return false;
+}
+
+/**
+ * testFaces
+ */
+bool BOP_Mesh::testFaces(BOP_Face *faceI, BOP_Face *faceJ){
+
+  if (faceI->size()<faceJ->size()){
+    for(unsigned int i=0;i<faceI->size();i++){
+      if (!faceJ->containsVertex(faceI->getVertex(i)))
+       return false;
+    }
+    //faceI->setTAG(BROKEN);
+  }
+  else{
+    for(unsigned int i=0;i<faceJ->size();i++){
+      if (!faceI->containsVertex(faceJ->getVertex(i)))
+       return false;
+    }
+    //faceJ->setTAG(BROKEN);
+  }
+
+  return true;
+}
+
+/**
+ * testPlane
+ */
+void BOP_Mesh::testPlane(BOP_Face *face)
+{
+       MT_Plane3 plane1(m_vertexs[face->getVertex(0)]->getPoint(), 
+                                        m_vertexs[face->getVertex(1)]->getPoint(),
+                                        m_vertexs[face->getVertex(2)]->getPoint());
+
+       if (BOP_orientation(plane1,face->getPlane()) < 0) {       
+               cout << "Test Plane " << face << " v1: ";
+               cout << m_vertexs[face->getVertex(0)]->getPoint() << " v2: ";
+               cout << m_vertexs[face->getVertex(1)]->getPoint() << " v3: ";
+               cout << m_vertexs[face->getVertex(2)]->getPoint() << " plane: ";
+               cout << face->getPlane() << endl;
+               cout << "Incorrect vertices order!!! plane1: " << plane1 << " (";
+               cout << BOP_orientation(plane1,face->getPlane()) << ") " <<  " invert ";
+               cout <<  MT_Plane3(m_vertexs[face->getVertex(2)]->getPoint(),
+                                                  m_vertexs[face->getVertex(1)]->getPoint(),
+                                                  m_vertexs[face->getVertex(0)]->getPoint()) << endl;
+               if (BOP_collinear(m_vertexs[face->getVertex(0)]->getPoint(),
+                                                 m_vertexs[face->getVertex(1)]->getPoint(),
+                                                 m_vertexs[face->getVertex(2)]->getPoint())) {
+                       cout << " COLLINEAR!!!" << endl;
+               }
+               else {
+                       cout << endl;
+               }
+       }
+}
+
+/**
+ * testEdges
+ */
+bool BOP_Mesh::testEdges(BOP_Faces *facesObj)
+{
+       for(unsigned int i=0;i<m_edges.size();i++) {
+               BOP_Edge *edge = m_edges[i];
+               BOP_Indexs faces = edge->getFaces();
+               unsigned int count = 0;
+               const BOP_IT_Indexs facesEnd = faces.end();
+               for(BOP_IT_Indexs it = faces.begin();it!=facesEnd;it++) {
+                       if ((m_faces[*it]->getTAG()!=BROKEN) && containsFace(facesObj,m_faces[*it]))
+                               count++;
+               }
+               if ((count%2)!=0) {
+                       return false;
+               }
+       }
+       
+       return true;
+}
+
+/**
+ * updatePlanes
+ */
+void BOP_Mesh::updatePlanes() 
+{
+  const BOP_IT_Faces facesEnd = m_faces.end();
+       for(BOP_IT_Faces it = m_faces.begin();it!=facesEnd;it++) {
+         BOP_Face *face = *it;
+         MT_Plane3 plane(m_vertexs[face->getVertex(0)]->getPoint(), 
+                         m_vertexs[face->getVertex(1)]->getPoint(),
+                         m_vertexs[face->getVertex(2)]->getPoint());
+         face->setPlane(plane);
+       }
+}
diff --git a/intern/boolop/intern/BOP_Mesh.h b/intern/boolop/intern/BOP_Mesh.h
new file mode 100644 (file)
index 0000000..6751df7
--- /dev/null
@@ -0,0 +1,97 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_MESH_H
+#define BOP_MESH_H
+
+#include "BOP_Vertex.h"
+#include "BOP_Edge.h"
+#include "BOP_Face.h"
+
+typedef vector<BOP_Vertex *> BOP_Vertexs;
+typedef vector<BOP_Edge *> BOP_Edges;
+
+typedef vector<BOP_Vertex *>::iterator BOP_IT_Vertexs;
+typedef vector<BOP_Edge *>::iterator BOP_IT_Edges;
+
+class BOP_Mesh
+{
+private:
+       BOP_Vertexs m_vertexs;
+       BOP_Edges   m_edges;
+       BOP_Faces   m_faces;
+       
+       BOP_Index addEdge(BOP_Index v1, BOP_Index v2);
+       BOP_Edge *getEdge(BOP_Indexs edges, BOP_Index v2);    
+       bool containsFace(BOP_Faces *faces, BOP_Face *face);
+
+       bool testEdges(BOP_Faces *faces);
+       bool testFaces(BOP_Face *faceI, BOP_Face *faceJ);
+       bool testFace(BOP_Face *face);
+
+public:
+       ~BOP_Mesh();
+       
+       BOP_Index addVertex(MT_Point3 point);
+       BOP_Index addFace(BOP_Face *face);
+       BOP_Index addFace(BOP_Face3 *face);
+       BOP_Index addFace(BOP_Face4 *face);
+       BOP_Vertex* getVertex(BOP_Index v);
+       BOP_Face*getFace(BOP_Index v);
+       BOP_Edge* getEdge(BOP_Index v);
+       BOP_Edge* getEdge(BOP_Face * face, unsigned int edge);            
+       BOP_Edge* getEdge(BOP_Face3 * face, unsigned int edge);            
+       BOP_Edge* getEdge(BOP_Face4 * face, unsigned int edge);            
+       BOP_Edge* getEdge(BOP_Index v1, BOP_Index v2);
+       bool getIndexEdge(BOP_Index v1, BOP_Index v2, BOP_Index &e);
+       BOP_Vertexs &getVertexs();
+       BOP_Edges &getEdges();
+       BOP_Faces &getFaces();
+       BOP_Face* getFace(BOP_Index v1, BOP_Index v2, BOP_Index v3);
+       bool getIndexFace(BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index &f);
+       unsigned int getNumVertexs();
+       unsigned int getNumEdges();
+       unsigned int getNumFaces();
+       unsigned int getNumVertexs(BOP_TAG tag);
+       unsigned int getNumFaces(BOP_TAG tag);
+       BOP_Index replaceVertexIndex(BOP_Index oldIndex, BOP_Index newIndex);
+       
+       // Debug functions
+       void print();
+       void printFormat();
+       void printFormat(BOP_Faces *faces);
+       void saveFormat(BOP_Faces *faces, char *filename);
+       void printFace(BOP_Face *face, int col = 0);
+       void testPlane(BOP_Face *face);
+       void testMesh();
+       void updatePlanes();
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_Segment.cpp b/intern/boolop/intern/BOP_Segment.cpp
new file mode 100644 (file)
index 0000000..2a81660
--- /dev/null
@@ -0,0 +1,247 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_Segment.h"
+
+#define UNDEFINED 0
+
+/**
+ * Constructs a new segment.
+ */
+BOP_Segment::BOP_Segment(){
+       m_cfg1  = UNDEFINED;
+       m_cfg2  = UNDEFINED;  
+}
+
+/**
+ * Returns the relative edge index between two relative vertex indices.
+ * @param v1 relative vertex index
+ * @param v2 relative vertex index
+ * @return relative edge index between two relative vertex indices, -1 otherwise
+ */
+int BOP_Segment::getEdgeBetween(unsigned int v1, unsigned int v2) 
+{
+       if ((v1 == 1 && v2 == 2) || (v1 == 2 && v2 == 1)) return 1;
+       if ((v1 == 3 && v2 == 2) || (v1 == 2 && v2 == 3)) return 2;
+       if ((v1 == 1 && v2 == 3) || (v1 == 3 && v2 == 1)) return 3;
+       return -1;
+}
+
+/** 
+ * Returns if a relative vertex index is on a relative edge index.
+ * @param v relative vertex index
+ * @param e relative edge index
+ * @return true if the relative vertex index is on the relative edge index, 
+ * false otherwise.
+ */
+bool BOP_Segment::isOnEdge(unsigned int v, unsigned int e)
+{
+       if (v == 1 && (e == 1 || e == 3)) return true;
+       if (v == 2 && (e == 1 || e == 2)) return true;
+       if (v == 3 && (e == 2 || e == 3)) return true;
+       return false;
+}
+
+/**
+ * Inverts the segment, swapping ends data.
+ */
+void BOP_Segment::invert()
+{
+       BOP_Index aux = m_v1;
+       m_v1    = m_v2;
+       m_v2    = aux;
+       aux     = m_cfg1;
+       m_cfg1  = m_cfg2;
+       m_cfg2  = aux;
+}
+
+/**
+ * Sorts the segment according to ends configuration.
+ * The criterion to sort is ...
+ *
+ *   UNDEFINED < VERTEX < EDGE < IN
+ *   cfg1 > cfg2
+ *
+ * so ... 
+ *
+ *   VERTEX(cfg1) => UNDEFINED(cfg2) || VERTEX(cfg2)
+ *   EDGE(cfg1) =>   UNDEFINED(cfg2) || VERTEX(cfg2) || EDGE(cfg2)
+ *   IN(cfg1) =>     UNDEFINED(cfg2) || VERTEX(cfg2) || EDGE(cfg2) || IN(cfg2)
+ */
+void BOP_Segment::sort()
+{
+       if (m_cfg1 < m_cfg2) invert();
+}
+
+/**
+ * Returns if the specified end segment configuration is IN.
+ * @return true if the specified end segment configuration is IN, false otherwise
+ */
+bool BOP_Segment::isIn(unsigned int cfg)
+{
+       return (cfg == 20);
+}
+
+/**
+ * Returns if the specified end segment configuration is EDGE.
+ * @return true if the specified end segment configuration is EDGE, false otherwise
+ */
+bool BOP_Segment::isEdge(unsigned int cfg)
+{
+       return (cfg > 10) && (cfg < 20);
+}
+
+/**
+ * Returns if the specified end segment configuration is VERTEX.
+ * @return true if the specified end segment configuration is VERTEX, false otherwise
+ */
+bool BOP_Segment::isVertex(unsigned int cfg)
+{
+       return (cfg!=UNDEFINED) && (cfg < 10);
+}
+
+/**
+ * Returns if the specified end segment configuration is DEFINED (not UNDEFINED).
+ * @return true if the specified end segment configuration is DEFINED, false otherwise
+ */
+bool BOP_Segment::isDefined(unsigned int cfg)
+{
+       return (cfg != UNDEFINED);
+}   
+
+/**
+ * Returns if the specified end segment configuration is UNDEFINED.
+ * @return true if the specified end segment configuration is UNDEFINED, false otherwise
+ */
+bool BOP_Segment::isUndefined(unsigned int cfg)
+{
+       return (cfg == UNDEFINED);
+}   
+
+/**
+ * Returns the relative edge index from the specified end segment configuration.
+ * @return relative edge index from the specified end segment configuration
+ */
+unsigned int BOP_Segment::getEdge(unsigned int cfg)
+{
+       return cfg-10;
+}   
+
+/**
+ * Returns the relative vertex index from the specified end segment configuration.
+ * @return relative vertex index from the specified end segment configuration
+ */
+BOP_Index BOP_Segment::getVertex(unsigned int cfg)
+{
+       return cfg;
+}   
+
+/**
+ * Returns the end segment configuration for the specified relative edge index.
+ * @return end segment configuration for the specified relative edge index
+ */
+unsigned int BOP_Segment::createEdgeCfg(unsigned int edge)
+{
+       return 10+edge;
+}
+
+/**
+ * Returns the end segment configuration for the specified relative vertex index.
+ * @return end segment configuration for the specified relative vertex index
+ */
+unsigned int BOP_Segment::createVertexCfg(BOP_Index vertex)
+{
+       return vertex;
+}
+
+/**
+ * Returns the end segment IN configuration.
+ * @return end segment IN configuration
+ */
+unsigned int BOP_Segment::createInCfg()
+{
+       return 20;
+}
+
+/**
+ * Returns the end segment UNDEFINED configuration.
+ * @return end segment UNDEFINED configuration
+ */
+unsigned int BOP_Segment::createUndefinedCfg()
+{
+       return UNDEFINED;
+}
+
+/**
+ * Returns the inner segment configuration.
+ * @return inner segment configuration
+ */
+unsigned int BOP_Segment::getConfig() 
+{
+       if (isUndefined(m_cfg1)) return m_cfg2;
+       else if (isUndefined(m_cfg2)) return m_cfg1;
+       else if (isVertex(m_cfg1)) {
+               // v1 is vertex
+               if (isVertex(m_cfg2)) {
+                       // v2 is vertex
+                       return createEdgeCfg(getEdgeBetween(getVertex(m_cfg1),getVertex(m_cfg2)));
+               }
+               else if (isEdge(m_cfg2)) {
+                       // v2 is edge
+                       if (isOnEdge(m_cfg1,getEdge(m_cfg2))) return m_cfg2;
+                       else return createInCfg(); //IN
+               } 
+               else return createInCfg(); //IN
+       }
+       else if (isEdge(m_cfg1)) {
+               // v1 is edge
+               if (isVertex(m_cfg2)) {
+                       // v2 is vertex
+                       if (isOnEdge(m_cfg2,getEdge(m_cfg1))) return m_cfg1;
+                       else return createInCfg(); //IN
+               }
+               else if (isEdge(m_cfg2)) {
+                       // v2 is edge
+                       if (m_cfg1 == m_cfg2) return m_cfg1;
+                       else return createInCfg(); // IN
+               }
+               else return createInCfg(); // IN
+       }
+       else return createInCfg(); // IN
+}
+
+/**
+ * Implements operator <<
+ */
+ostream &operator<<(ostream &stream, const BOP_Segment &c)
+{
+       cout << "m_v1: " << c.m_v1 << "(" << c.m_cfg1 << ") m_v2: " << c.m_v2 << "(" << c.m_cfg2 << ")";
+       return stream;
+}
diff --git a/intern/boolop/intern/BOP_Segment.h b/intern/boolop/intern/BOP_Segment.h
new file mode 100644 (file)
index 0000000..caa6157
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BOP_SEGMENT_H
+#define BOP_SEGMENT_H
+
+#include "BOP_Indexs.h"
+#include <iostream>
+using namespace std;
+
+class BOP_Segment
+{
+private:
+       int getEdgeBetween(unsigned int v1, unsigned int v2);
+       bool isOnEdge(unsigned int v, unsigned int e);
+
+public:
+       // Cfg : Configuration of the vertices
+       // Values:
+       //         20 IN,
+       //         1X Intersected edge X{1,2,3} of the face,
+       //         0X Coincident vertice X{1,2,3} of the face,
+       //         0 otherwise
+       unsigned int m_cfg1, m_cfg2; 
+       BOP_Index m_v1, m_v2;     // if cfgX >0, vX is the vertice index of the face
+       BOP_Segment();
+
+       static bool isIn(unsigned int cfg);
+       static bool isEdge(unsigned int cfg);
+       static bool isVertex(unsigned int cfg);
+       static bool isDefined(unsigned int cfg);
+       static bool isUndefined(unsigned int cfg);
+       static unsigned int getEdge(unsigned int cfg);
+       static BOP_Index getVertex(unsigned int cfg);
+       static unsigned int createEdgeCfg(unsigned int edge);
+       static unsigned int createVertexCfg(BOP_Index vertex);
+       static unsigned int createInCfg();
+       static unsigned int createUndefinedCfg();
+       void invert();  
+       void sort();
+       unsigned int getConfig();
+
+       friend   ostream &operator<<(ostream &stream, const BOP_Segment &c);
+};
+
+#endif
diff --git a/intern/boolop/intern/BOP_Splitter.cpp b/intern/boolop/intern/BOP_Splitter.cpp
new file mode 100644 (file)
index 0000000..07f1f4d
--- /dev/null
@@ -0,0 +1,193 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "BOP_Splitter.h"
+#include "BOP_Tag.h"
+
+#include <iostream>
+using namespace std;
+
+/**
+ * Returns the split point resulting from intersect a plane and a mesh face  
+ * according to its specified relative edge.
+ * @param plane split plane
+ * @param m mesh
+ * @param f face
+ * @param e relative edge index
+ * @return intersection point
+ */
+MT_Point3 BOP_splitEdge(MT_Plane3 plane, BOP_Mesh *m, BOP_Face *f, unsigned int e)
+{
+       int v1 = -1, v2 = -1;
+  
+       switch(e) {
+       case 1:
+               v1 = f->getVertex(0);
+               v2 = f->getVertex(1);
+               break;
+       case 2:
+               v1 = f->getVertex(1);
+               v2 = f->getVertex(2);
+               break;
+       case 3:
+               v1 = f->getVertex(2);
+               v2 = f->getVertex(0);
+               break;
+       default:
+               // wrong relative edge index!
+               break;
+       }
+  
+       MT_Point3 p1 = m->getVertex(v1)->getPoint();
+       MT_Point3 p2 = m->getVertex(v2)->getPoint();
+       return BOP_intersectPlane(plane,p1,p2);
+}
+
+/**
+ * Returns the segment resulting from intersect a plane and a mesh face.
+ * @param plane split plane
+ * @param m mesh
+ * @param f face
+ * @return segment if there is intersection, NULL otherwise
+ */
+BOP_Segment BOP_splitFace(MT_Plane3 plane, BOP_Mesh *m, BOP_Face *f)
+{    
+       BOP_Vertex *v1 = m->getVertex(f->getVertex(0));
+       BOP_Vertex *v2 = m->getVertex(f->getVertex(1));
+       BOP_Vertex *v3 = m->getVertex(f->getVertex(2));
+
+       // Classify face vertices
+       BOP_TAG tag1 = BOP_createTAG(BOP_classify(v1->getPoint(),plane));
+       BOP_TAG tag2 = BOP_createTAG(BOP_classify(v2->getPoint(),plane));
+       BOP_TAG tag3 = BOP_createTAG(BOP_classify(v3->getPoint(),plane));
+  
+       // Classify face according to its vertices classification
+       BOP_TAG tag = BOP_createTAG(tag1,tag2,tag3);
+  
+       BOP_Segment s;
+
+       switch(tag) {
+       case IN_IN_IN : 
+       case OUT_OUT_OUT :
+       case ON_ON_ON :
+               s.m_cfg1 = s.m_cfg2 = BOP_Segment::createUndefinedCfg();        
+               break;
+    
+       case ON_OUT_OUT :
+       case ON_IN_IN :
+               s.m_v1 = f->getVertex(0);
+               s.m_cfg1 = BOP_Segment::createVertexCfg(1);
+               s.m_cfg2 = BOP_Segment::createUndefinedCfg();
+               break;
+    
+       case OUT_ON_OUT :
+       case IN_ON_IN :
+               s.m_v1 = f->getVertex(1); 
+               s.m_cfg1 = BOP_Segment::createVertexCfg(2);
+               s.m_cfg2 = BOP_Segment::createUndefinedCfg();
+               break;
+    
+       case OUT_OUT_ON :      
+       case IN_IN_ON :
+               s.m_v1 = f->getVertex(2); 
+               s.m_cfg1 = BOP_Segment::createVertexCfg(3);
+               s.m_cfg2 = BOP_Segment::createUndefinedCfg();
+               break;
+    
+       case ON_ON_IN :
+       case ON_ON_OUT :
+               s.m_v1 = f->getVertex(0); 
+               s.m_v2 = f->getVertex(1);
+               s.m_cfg1 = BOP_Segment::createVertexCfg(1);
+               s.m_cfg2 = BOP_Segment::createVertexCfg(2);
+               break;
+    
+       case ON_OUT_ON :        
+       case ON_IN_ON :
+               s.m_v1 = f->getVertex(0); 
+               s.m_v2 = f->getVertex(2);
+               s.m_cfg1 = BOP_Segment::createVertexCfg(1);
+               s.m_cfg2 = BOP_Segment::createVertexCfg(3);
+               break;
+    
+       case OUT_ON_ON :
+       case IN_ON_ON :
+               s.m_v1 = f->getVertex(1); 
+               s.m_v2 = f->getVertex(2);
+               s.m_cfg1 = BOP_Segment::createVertexCfg(2);
+               s.m_cfg2 = BOP_Segment::createVertexCfg(3);
+               break;
+    
+       case IN_OUT_ON :
+       case OUT_IN_ON :
+               s.m_v2 = f->getVertex(2);
+               s.m_cfg1 = BOP_Segment::createEdgeCfg(1);
+               s.m_cfg2 = BOP_Segment::createVertexCfg(3);
+           break;
+    
+       case IN_ON_OUT :
+       case OUT_ON_IN :
+               s.m_v1 = f->getVertex(1);
+               s.m_cfg1 = BOP_Segment::createVertexCfg(2);
+               s.m_cfg2 = BOP_Segment::createEdgeCfg(3);
+               break;
+    
+       case ON_IN_OUT :
+       case ON_OUT_IN :
+               s.m_v1 = f->getVertex(0);
+               s.m_cfg1 = BOP_Segment::createVertexCfg(1);
+               s.m_cfg2 = BOP_Segment::createEdgeCfg(2);
+               break;
+    
+       case OUT_IN_IN :
+       case IN_OUT_OUT :
+               s.m_cfg1 = BOP_Segment::createEdgeCfg(1);
+               s.m_cfg2 = BOP_Segment::createEdgeCfg(3);
+               break;
+    
+       case OUT_IN_OUT :
+       case IN_OUT_IN :
+               s.m_cfg1 = BOP_Segment::createEdgeCfg(1);
+               s.m_cfg2 = BOP_Segment::createEdgeCfg(2);
+               break;
+    
+       case OUT_OUT_IN :
+       case IN_IN_OUT :
+               s.m_cfg1 = BOP_Segment::createEdgeCfg(2);
+               s.m_cfg2 = BOP_Segment::createEdgeCfg(3);
+               break;
+    
+       default: