Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Ewering <blender@instinctive.de>2005-10-29 00:17:27 +0400
committerAlexander Ewering <blender@instinctive.de>2005-10-29 00:17:27 +0400
commitd243bfb61ef6c906f446085e5ae1993263aa85a8 (patch)
treea312dced8f8b2cbc4586c0aaf61906d5c4071e02 /intern/boolop
parentd3dd5c5b7aa185265ce7816dab996e8fa9288bc6 (diff)
New files from new booleans
Diffstat (limited to 'intern/boolop')
-rw-r--r--intern/boolop/Makefile59
-rw-r--r--intern/boolop/extern/BOP_Interface.h53
-rw-r--r--intern/boolop/intern/BOP_BBox.cpp62
-rw-r--r--intern/boolop/intern/BOP_BBox.h96
-rw-r--r--intern/boolop/intern/BOP_BSPNode.cpp671
-rw-r--r--intern/boolop/intern/BOP_BSPNode.h104
-rw-r--r--intern/boolop/intern/BOP_BSPTree.cpp212
-rw-r--r--intern/boolop/intern/BOP_BSPTree.h75
-rw-r--r--intern/boolop/intern/BOP_Chrono.h52
-rw-r--r--intern/boolop/intern/BOP_Edge.cpp81
-rw-r--r--intern/boolop/intern/BOP_Edge.h55
-rw-r--r--intern/boolop/intern/BOP_Face.cpp416
-rw-r--r--intern/boolop/intern/BOP_Face.h105
-rw-r--r--intern/boolop/intern/BOP_Face2Face.cpp1270
-rw-r--r--intern/boolop/intern/BOP_Face2Face.h44
-rw-r--r--intern/boolop/intern/BOP_Indexs.h41
-rw-r--r--intern/boolop/intern/BOP_Interface.cpp603
-rw-r--r--intern/boolop/intern/BOP_Material.cpp176
-rw-r--r--intern/boolop/intern/BOP_Material.h80
-rw-r--r--intern/boolop/intern/BOP_MaterialContainer.cpp242
-rw-r--r--intern/boolop/intern/BOP_MaterialContainer.h72
-rw-r--r--intern/boolop/intern/BOP_MathUtils.cpp419
-rw-r--r--intern/boolop/intern/BOP_MathUtils.h72
-rw-r--r--intern/boolop/intern/BOP_Merge.cpp796
-rw-r--r--intern/boolop/intern/BOP_Merge.h74
-rw-r--r--intern/boolop/intern/BOP_Mesh.cpp835
-rw-r--r--intern/boolop/intern/BOP_Mesh.h97
-rw-r--r--intern/boolop/intern/BOP_Segment.cpp247
-rw-r--r--intern/boolop/intern/BOP_Segment.h73
-rw-r--r--intern/boolop/intern/BOP_Splitter.cpp193
-rw-r--r--intern/boolop/intern/BOP_Splitter.h44
-rw-r--r--intern/boolop/intern/BOP_Tag.cpp142
-rw-r--r--intern/boolop/intern/BOP_Tag.h145
-rw-r--r--intern/boolop/intern/BOP_Triangulator.cpp515
-rw-r--r--intern/boolop/intern/BOP_Triangulator.h44
-rw-r--r--intern/boolop/intern/BOP_Vertex.cpp94
-rw-r--r--intern/boolop/intern/BOP_Vertex.h60
-rw-r--r--intern/boolop/intern/Makefile48
38 files changed, 8467 insertions, 0 deletions
diff --git a/intern/boolop/Makefile b/intern/boolop/Makefile
new file mode 100644
index 00000000000..85e6754132e
--- /dev/null
+++ b/intern/boolop/Makefile
@@ -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
index 00000000000..446dd1b79f7
--- /dev/null
+++ b/intern/boolop/extern/BOP_Interface.h
@@ -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
index 00000000000..767847e1e09
--- /dev/null
+++ b/intern/boolop/intern/BOP_BBox.cpp
@@ -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
index 00000000000..473a9828a1a
--- /dev/null
+++ b/intern/boolop/intern/BOP_BBox.h
@@ -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
index 00000000000..afe48586d33
--- /dev/null
+++ b/intern/boolop/intern/BOP_BSPNode.cpp
@@ -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
index 00000000000..d4f7f1c28a1
--- /dev/null
+++ b/intern/boolop/intern/BOP_BSPNode.h
@@ -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
index 00000000000..4e5c171bc83
--- /dev/null
+++ b/intern/boolop/intern/BOP_BSPTree.cpp
@@ -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
index 00000000000..7e5b5a4fa76
--- /dev/null
+++ b/intern/boolop/intern/BOP_BSPTree.h
@@ -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
index 00000000000..5ce64f7a57c
--- /dev/null
+++ b/intern/boolop/intern/BOP_Chrono.h
@@ -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
index 00000000000..31411133878
--- /dev/null
+++ b/intern/boolop/intern/BOP_Edge.cpp
@@ -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
index 00000000000..abf5dd0a8c8
--- /dev/null
+++ b/intern/boolop/intern/BOP_Edge.h
@@ -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
index 00000000000..80c917f2838
--- /dev/null
+++ b/intern/boolop/intern/BOP_Face.cpp
@@ -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
index 00000000000..7db5ab1fe5c
--- /dev/null
+++ b/intern/boolop/intern/BOP_Face.h
@@ -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
index 00000000000..6d7c671870d
--- /dev/null
+++ b/intern/boolop/intern/BOP_Face2Face.cpp
@@ -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
index 00000000000..09ed4edd076
--- /dev/null
+++ b/intern/boolop/intern/BOP_Face2Face.h
@@ -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
index 00000000000..c5546e73252
--- /dev/null
+++ b/intern/boolop/intern/BOP_Indexs.h
@@ -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
index 00000000000..02945340d55
--- /dev/null
+++ b/intern/boolop/intern/BOP_Interface.cpp
@@ -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
index 00000000000..2d1e747eb49
--- /dev/null
+++ b/intern/boolop/intern/BOP_Material.cpp
@@ -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
index 00000000000..a057384bf01
--- /dev/null
+++ b/intern/boolop/intern/BOP_Material.h
@@ -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
index 00000000000..b8f38b35651
--- /dev/null
+++ b/intern/boolop/intern/BOP_MaterialContainer.cpp
@@ -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
index 00000000000..c6de4cd96e5
--- /dev/null
+++ b/intern/boolop/intern/BOP_MaterialContainer.h
@@ -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
index 00000000000..0d84bb1778c
--- /dev/null
+++ b/intern/boolop/intern/BOP_MathUtils.cpp
@@ -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
index 00000000000..61458bd8a78
--- /dev/null
+++ b/intern/boolop/intern/BOP_MathUtils.h
@@ -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
index 00000000000..1165ac10a8f
--- /dev/null
+++ b/intern/boolop/intern/BOP_Merge.cpp
@@ -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
index 00000000000..2ccce8e137b
--- /dev/null
+++ b/intern/boolop/intern/BOP_Merge.h
@@ -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
index 00000000000..d8193f9c4b0
--- /dev/null
+++ b/intern/boolop/intern/BOP_Mesh.cpp
@@ -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
index 00000000000..6751df7c4e7
--- /dev/null
+++ b/intern/boolop/intern/BOP_Mesh.h
@@ -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
index 00000000000..2a81660c4ff
--- /dev/null
+++ b/intern/boolop/intern/BOP_Segment.cpp
@@ -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
index 00000000000..caa6157346c
--- /dev/null
+++ b/intern/boolop/intern/BOP_Segment.h
@@ -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
index 00000000000..07f1f4d6c96
--- /dev/null
+++ b/intern/boolop/intern/BOP_Splitter.cpp
@@ -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:
+ // wrong TAG!
+ break;
+ }
+
+ return s;
+}
diff --git a/intern/boolop/intern/BOP_Splitter.h b/intern/boolop/intern/BOP_Splitter.h
new file mode 100644
index 00000000000..02cbdd2aa72
--- /dev/null
+++ b/intern/boolop/intern/BOP_Splitter.h
@@ -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_SPLITTER_H
+#define BOP_SPLITTER_H
+
+#include "BOP_MathUtils.h"
+#include "BOP_Segment.h"
+#include "BOP_Mesh.h"
+
+#include "MT_Plane3.h"
+#include "MT_Point3.h"
+
+MT_Point3 BOP_splitEdge(MT_Plane3 plane, BOP_Mesh *mesh, BOP_Face *face, unsigned int edge);
+BOP_Segment BOP_splitFace(MT_Plane3 plane, BOP_Mesh *mesh, BOP_Face *face);
+
+#endif
diff --git a/intern/boolop/intern/BOP_Tag.cpp b/intern/boolop/intern/BOP_Tag.cpp
new file mode 100644
index 00000000000..6a8832870fa
--- /dev/null
+++ b/intern/boolop/intern/BOP_Tag.cpp
@@ -0,0 +1,142 @@
+/**
+ * ***** 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_Tag.h"
+
+/**
+ * Gets the tag description.
+ * @param t tag
+ * @param dest tag description
+ */
+void BOP_stringTAG(BOP_TAG t, char *dest) {
+
+ switch(t){
+ case IN_IN_IN:
+ sprintf(dest, "IN_IN_IN");
+ break;
+ case IN_IN_ON:
+ sprintf(dest, "IN_IN_ON");
+ break;
+ case IN_ON_IN:
+ sprintf(dest, "IN_ON_IN");
+ break;
+ case IN_ON_ON:
+ sprintf(dest, "IN_ON_ON");
+ break;
+ case ON_IN_IN:
+ sprintf(dest, "ON_IN_IN");
+ break;
+ case ON_IN_ON:
+ sprintf(dest, "ON_IN_ON");
+ break;
+ case ON_ON_IN:
+ sprintf(dest, "ON_ON_IN");
+ break;
+ case ON_ON_ON:
+ sprintf(dest, "ON_ON_ON");
+ break;
+ case OUT_OUT_OUT:
+ sprintf(dest, "OUT_OUT_OUT");
+ break;
+ case OUT_OUT_ON:
+ sprintf(dest, "OUT_OUT_ON");
+ break;
+ case OUT_ON_OUT:
+ sprintf(dest, "OUT_ON_OUT");
+ break;
+ case OUT_ON_ON:
+ sprintf(dest, "OUT_ON_ON");
+ break;
+ case ON_OUT_OUT:
+ sprintf(dest, "ON_OUT_OUT");
+ break;
+ case ON_OUT_ON:
+ sprintf(dest, "ON_OUT_ON");
+ break;
+ case ON_ON_OUT:
+ sprintf(dest, "ON_ON_OUT");
+ break;
+ case OUT_OUT_IN:
+ sprintf(dest, "OUT_OUT_IN");
+ break;
+ case OUT_IN_OUT:
+ sprintf(dest, "OUT_IN_OUT");
+ break;
+ case OUT_IN_IN:
+ sprintf(dest, "OUT_IN_IN");
+ break;
+ case IN_OUT_OUT:
+ sprintf(dest, "IN_OUT_OUT");
+ break;
+ case IN_OUT_IN:
+ sprintf(dest, "IN_OUT_IN");
+ break;
+ case IN_IN_OUT:
+ sprintf(dest, "IN_IN_OUT");
+ break;
+ case OUT_ON_IN:
+ sprintf(dest, "OUT_ON_IN");
+ break;
+ case OUT_IN_ON:
+ sprintf(dest, "OUT_IN_ON");
+ break;
+ case IN_ON_OUT:
+ sprintf(dest, "IN_ON_OUT");
+ break;
+ case IN_OUT_ON:
+ sprintf(dest, "IN_OUT_ON");
+ break;
+ case ON_IN_OUT:
+ sprintf(dest, "ON_IN_OUT");
+ break;
+ case ON_OUT_IN:
+ sprintf(dest, "ON_OUT_IN");
+ break;
+ case UNCLASSIFIED:
+ sprintf(dest, "UNCLASSIFIED");
+ break;
+ case BROKEN:
+ sprintf(dest, "BROKEN");
+ break;
+ case PHANTOM:
+ sprintf(dest, "PHANTOM");
+ break;
+ case OVERLAPPED:
+ sprintf(dest, "OVERLAPPED");
+ break;
+ case INOUT:
+ sprintf(dest, "INOUT");
+ break;
+ default:
+ sprintf(dest, "DESCONEGUT %d",t);
+ break;
+ }
+
+}
diff --git a/intern/boolop/intern/BOP_Tag.h b/intern/boolop/intern/BOP_Tag.h
new file mode 100644
index 00000000000..2b6ff93b679
--- /dev/null
+++ b/intern/boolop/intern/BOP_Tag.h
@@ -0,0 +1,145 @@
+/**
+ * ***** 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 <string.h>
+#include <stdio.h>
+
+#ifndef BOP_TAG_H
+#define BOP_TAG_H
+
+#define IN_TAG 0x02 // Below the plane
+#define ON_TAG 0x00 // On the plane
+#define OUT_TAG 0x01 // Above the plane
+#define INOUT_TAG 0x0E // Above and below the plane
+#define INON_TAG 0x12 // Below and on the plane
+#define OUTON_TAG 0x11 // Above and on the plane
+#define UNCLASSIFIED_TAG 0x0F // Expecting to be classified
+
+#define PHANTOM_TAG 0x0C // Phantom face
+#define OVERLAPPED_TAG 0x0D // Overlapped face
+#define BROKEN_TAG 0x0B // Splitted and unused ...
+
+#define ON_ON_IN_TAG IN_TAG
+#define ON_IN_ON_TAG IN_TAG << 2
+#define IN_ON_ON_TAG IN_TAG << 4
+
+#define ON_ON_OUT_TAG OUT_TAG
+#define ON_OUT_ON_TAG OUT_TAG << 2
+#define OUT_ON_ON_TAG OUT_TAG << 4
+
+#define ON_ON_ON_TAG ON_TAG
+#define IN_IN_IN_TAG IN_ON_ON_TAG | ON_IN_ON_TAG | ON_ON_IN_TAG
+#define OUT_OUT_OUT_TAG OUT_ON_ON_TAG | ON_OUT_ON_TAG | ON_ON_OUT_TAG
+
+#define IN_IN_ON_TAG IN_ON_ON_TAG | ON_IN_ON_TAG
+#define IN_ON_IN_TAG IN_ON_ON_TAG | ON_ON_IN_TAG
+#define ON_IN_IN_TAG ON_IN_ON_TAG | ON_ON_IN_TAG
+
+#define OUT_OUT_ON_TAG OUT_ON_ON_TAG | ON_OUT_ON_TAG
+#define OUT_ON_OUT_TAG OUT_ON_ON_TAG | ON_ON_OUT_TAG
+#define ON_OUT_OUT_TAG ON_OUT_ON_TAG | ON_ON_OUT_TAG
+
+#define IN_OUT_OUT_TAG IN_ON_ON_TAG | ON_OUT_OUT_TAG
+#define OUT_IN_OUT_TAG ON_IN_ON_TAG | OUT_ON_OUT_TAG
+#define OUT_OUT_IN_TAG ON_ON_IN_TAG | OUT_OUT_ON_TAG
+
+#define OUT_IN_IN_TAG ON_IN_IN_TAG | OUT_ON_ON_TAG
+#define IN_OUT_IN_TAG IN_ON_IN_TAG | ON_OUT_ON_TAG
+#define IN_IN_OUT_TAG IN_IN_ON_TAG | ON_ON_OUT_TAG
+
+#define IN_ON_OUT_TAG IN_ON_ON_TAG | ON_ON_OUT_TAG
+#define IN_OUT_ON_TAG IN_ON_ON_TAG | ON_OUT_ON_TAG
+#define ON_IN_OUT_TAG ON_IN_ON_TAG | ON_ON_OUT_TAG
+#define ON_OUT_IN_TAG ON_ON_IN_TAG | ON_OUT_ON_TAG
+#define OUT_IN_ON_TAG ON_IN_ON_TAG | OUT_ON_ON_TAG
+#define OUT_ON_IN_TAG ON_ON_IN_TAG | OUT_ON_ON_TAG
+
+typedef enum BOP_TAGEnum {
+ IN = IN_TAG,
+ ON = ON_TAG,
+ OUT = OUT_TAG,
+ INOUT = INOUT_TAG,
+ INON = INON_TAG,
+ OUTON = OUTON_TAG,
+ UNCLASSIFIED = UNCLASSIFIED_TAG,
+ PHANTOM = PHANTOM_TAG,
+ OVERLAPPED = OVERLAPPED_TAG,
+ BROKEN = BROKEN_TAG,
+ IN_ON_ON = IN_ON_ON_TAG,
+ ON_IN_ON = ON_IN_ON_TAG,
+ ON_ON_IN = ON_ON_IN_TAG,
+ OUT_ON_ON = OUT_ON_ON_TAG,
+ ON_OUT_ON = ON_OUT_ON_TAG,
+ ON_ON_OUT = ON_ON_OUT_TAG,
+ ON_ON_ON = ON_ON_ON_TAG,
+ IN_IN_IN = IN_IN_IN_TAG,
+ OUT_OUT_OUT = OUT_OUT_OUT_TAG,
+ IN_IN_ON = IN_IN_ON_TAG,
+ IN_ON_IN = IN_ON_IN_TAG,
+ ON_IN_IN = ON_IN_IN_TAG,
+ OUT_OUT_ON = OUT_OUT_ON_TAG,
+ OUT_ON_OUT = OUT_ON_OUT_TAG,
+ ON_OUT_OUT = ON_OUT_OUT_TAG,
+ IN_OUT_OUT = IN_OUT_OUT_TAG,
+ OUT_IN_OUT = OUT_IN_OUT_TAG,
+ OUT_OUT_IN = OUT_OUT_IN_TAG,
+ OUT_IN_IN = OUT_IN_IN_TAG,
+ IN_OUT_IN = IN_OUT_IN_TAG,
+ IN_IN_OUT = IN_IN_OUT_TAG,
+ IN_ON_OUT = IN_ON_OUT_TAG,
+ IN_OUT_ON = IN_OUT_ON_TAG,
+ ON_IN_OUT = ON_IN_OUT_TAG,
+ ON_OUT_IN = ON_OUT_IN_TAG,
+ OUT_IN_ON = OUT_IN_ON_TAG,
+ OUT_ON_IN = OUT_ON_IN_TAG } BOP_TAG;
+
+inline BOP_TAG BOP_createTAG(BOP_TAG tag1, BOP_TAG tag2, BOP_TAG tag3)
+{
+ return (BOP_TAG) (tag1 << 4 | tag2 << 2 | tag3);
+}
+
+inline BOP_TAG BOP_createTAG(int i)
+{
+ return i < 0 ? IN : i > 0 ? OUT : ON;
+}
+
+inline BOP_TAG BOP_addON(BOP_TAG tag)
+{
+ return (tag==IN?INON:(tag==OUT?OUTON:tag));
+}
+
+void BOP_stringTAG(BOP_TAG tag, char *dest);
+
+inline bool BOP_compTAG(BOP_TAG tag1, BOP_TAG tag2)
+{
+ return (tag1==tag2) || (BOP_addON(tag1) == BOP_addON(tag2));
+}
+
+#endif
diff --git a/intern/boolop/intern/BOP_Triangulator.cpp b/intern/boolop/intern/BOP_Triangulator.cpp
new file mode 100644
index 00000000000..fa604d44f2d
--- /dev/null
+++ b/intern/boolop/intern/BOP_Triangulator.cpp
@@ -0,0 +1,515 @@
+/**
+ * ***** 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_Triangulator.h"
+#include <iostream>
+using namespace std;
+
+void BOP_addFace(BOP_Mesh* mesh, BOP_Faces *faces, BOP_Face* face, BOP_TAG tag);
+void BOP_splitQuad(BOP_Mesh* mesh, MT_Plane3 plane, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4,
+ BOP_Face* triangles[], BOP_Index original);
+BOP_Index BOP_getTriangleVertex(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4);
+BOP_Index BOP_getNearestVertex(BOP_Mesh* mesh, BOP_Index u, BOP_Index v1, BOP_Index v2);
+bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5);
+bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index w);
+void BOP_triangulateC_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face,
+ BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5);
+void BOP_triangulateD_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face,
+ BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5);
+
+/**
+ * Triangulates the face in two new faces by splitting one edge.
+ *
+ * *
+ * /|\
+ * / | \
+ * / | \
+ * / | \
+ * / | \
+ * *-----x-----*
+ *
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains face and will contains new faces
+ * @param face input face to be triangulate
+ * @param v vertex index that intersects the edge
+ * @param e relative edge index used to triangulate the face
+ */
+
+
+void BOP_triangulateA(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v, unsigned int e)
+{
+ BOP_Face *face1, *face2;
+ if (e == 1) {
+ face1 = new BOP_Face3(face->getVertex(0), v, face->getVertex(2), face->getPlane(),
+ face->getOriginalFace());
+ face2 = new BOP_Face3(v, face->getVertex(1), face->getVertex(2), face->getPlane(),
+ face->getOriginalFace());
+ }
+ else if (e == 2) {
+ face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(),
+ face->getOriginalFace());
+ face2 = new BOP_Face3(face->getVertex(0), v, face->getVertex(2), face->getPlane(),
+ face->getOriginalFace());
+ }
+ else if (e == 3) {
+ face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(),
+ face->getOriginalFace());
+ face2 = new BOP_Face3(face->getVertex(1), face->getVertex(2), v, face->getPlane(),
+ face->getOriginalFace());
+ }
+ else {
+ return;
+ }
+
+ BOP_addFace(mesh, faces, face1, face->getTAG());
+ BOP_addFace(mesh, faces, face2, face->getTAG());
+
+ face->setTAG(BROKEN);
+}
+
+/**
+ * Triangulates the face in three new faces by one inner point.
+ *
+ * *
+ * / \
+ * / \
+ * / \
+ * / x \
+ * / \
+ * *-----------*
+ *
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains face and will contains new faces
+ * @param face input face to be triangulate
+ * @param v vertex index that lays inside face
+ */
+void BOP_triangulateB(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v)
+{
+ BOP_Face *face1 = new BOP_Face3(face->getVertex(0), face->getVertex(1), v, face->getPlane(),
+ face->getOriginalFace());
+ BOP_Face *face2 = new BOP_Face3(face->getVertex(1), face->getVertex(2), v, face->getPlane(),
+ face->getOriginalFace());
+ BOP_Face *face3 = new BOP_Face3(face->getVertex(2), face->getVertex(0), v, face->getPlane(),
+ face->getOriginalFace());
+
+ BOP_addFace(mesh,faces,face1,face->getTAG());
+ BOP_addFace(mesh,faces,face2,face->getTAG());
+ BOP_addFace(mesh,faces,face3,face->getTAG());
+ face->setTAG(BROKEN);
+}
+
+
+/**
+ * Triangulates the face in five new faces by two inner points.
+ *
+ * *
+ * / \
+ * / \
+ * / \
+ * / x x \
+ * / \
+ * *-----------*
+ *
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains face and will contains new faces
+ * @param face input face to be triangulate
+ * @param v1 first vertex index that lays inside face
+ * @param v2 second vertex index that lays inside face
+ */
+void BOP_triangulateC(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v1, BOP_Index v2)
+{
+ if (!BOP_isInsideCircle(mesh, face->getVertex(0), v1, v2, face->getVertex(1), face->getVertex(2))) {
+ BOP_triangulateC_split(mesh, faces, face, face->getVertex(0), face->getVertex(1),
+ face->getVertex(2), v1, v2);
+ }
+ else if (!BOP_isInsideCircle(mesh, face->getVertex(1), v1, v2, face->getVertex(0), face->getVertex(2))) {
+ BOP_triangulateC_split(mesh, faces, face, face->getVertex(1), face->getVertex(2),
+ face->getVertex(0), v1, v2);
+ }
+ else if (!BOP_isInsideCircle(mesh, face->getVertex(2), v1, v2, face->getVertex(0), face->getVertex(1))) {
+ BOP_triangulateC_split(mesh, faces, face, face->getVertex(2), face->getVertex(0),
+ face->getVertex(1), v1, v2);
+ }
+ else {
+ BOP_triangulateC_split(mesh, faces, face, face->getVertex(2), face->getVertex(0),
+ face->getVertex(1), v1, v2);
+ }
+}
+
+/**
+ * Triangulates the face (v1,v2,v3) in five new faces by two inner points (v4,v5), where
+ * v1 v4 v5 defines the nice triangle and v4 v5 v2 v3 defines the quad to be tesselated.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains face and will contains new faces
+ * @param face input face to be triangulate
+ * @param v1 first vertex index that defines the original triangle
+ * @param v2 second vertex index that defines the original triangle
+ * @param v3 third vertex index that defines the original triangle
+ * @param v4 first vertex index that lays inside face
+ * @param v5 second vertex index that lays inside face
+ */
+void BOP_triangulateC_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face,
+ BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5)
+{
+ BOP_Index v = BOP_getTriangleVertex(mesh, v1, v2, v4, v5);
+ BOP_Index w = (v == v4 ? v5 : v4);
+
+ // v1 v w defines the nice triangle in the correct order
+ // v1 v2 v defines one lateral triangle in the correct order
+ // v1 w v3 defines the other lateral triangle in the correct order
+ // w v v2 v3 defines the quad in the correct order
+
+ BOP_addFace(mesh, faces, new BOP_Face3(v1, v, w, face->getPlane(),
+ face->getOriginalFace()), face->getTAG());
+ BOP_addFace(mesh, faces, new BOP_Face3(v1, v2, v, face->getPlane(),
+ face->getOriginalFace()), face->getTAG());
+ BOP_addFace(mesh, faces, new BOP_Face3(v1, w, v3, face->getPlane(),
+ face->getOriginalFace()), face->getTAG());
+
+ BOP_Face *faces45[2];
+
+ BOP_splitQuad(mesh, face->getPlane(), v2, v3, w, v, faces45, face->getOriginalFace());
+ BOP_addFace(mesh, faces, faces45[0], face->getTAG());
+ BOP_addFace(mesh, faces, faces45[1], face->getTAG());
+
+ face->setTAG(BROKEN);
+}
+
+
+/**
+ * Triangulates the face in three new faces by splitting twice an edge.
+ *
+ * *
+ * / \
+ * / \
+ * / \
+ * / \
+ * / \
+ * *---x---x---*
+ *
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains face and will contains new faces
+ * @param face input face to be triangulate
+ * @param v1 first vertex index that intersects the edge
+ * @param v2 second vertex index that intersects the edge
+ * @param e relative edge index used to triangulate the face
+ */
+void BOP_triangulateD(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_Index v1,
+ BOP_Index v2, unsigned int e)
+{
+ if (e == 1) {
+ BOP_triangulateD_split(mesh, faces, face, face->getVertex(0), face->getVertex(1),
+ face->getVertex(2), v1, v2);
+ }
+ else if (e == 2) {
+ BOP_triangulateD_split(mesh, faces, face, face->getVertex(1), face->getVertex(2),
+ face->getVertex(0), v1, v2);
+ }
+ else if (e == 3) {
+ BOP_triangulateD_split(mesh, faces, face, face->getVertex(2), face->getVertex(0),
+ face->getVertex(1), v1, v2);
+ }
+}
+
+/**
+ * Triangulates the face (v1,v2,v3) in three new faces by splitting twice an edge.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains face and will contains new faces
+ * @param face input face to be triangulate
+ * @param v1 first vertex index that defines the original triangle
+ * @param v2 second vertex index that defines the original triangle
+ * @param v3 third vertex index that defines the original triangle
+ * @param v4 first vertex index that lays on the edge
+ * @param v5 second vertex index that lays on the edge
+ */
+void BOP_triangulateD_split(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face,
+ BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5)
+{
+ BOP_Index v = BOP_getNearestVertex(mesh, v1, v4, v5);
+ BOP_Index w = (v == v4 ? v5 : v4);
+
+ BOP_addFace(mesh, faces, new BOP_Face3(v1, v, v3, face->getPlane(),
+ face->getOriginalFace()), face->getTAG());
+ BOP_addFace(mesh, faces, new BOP_Face3(v, w, v3, face->getPlane(),
+ face->getOriginalFace()), face->getTAG());
+ BOP_addFace(mesh, faces, new BOP_Face3(w, v2, v3, face->getPlane(),
+ face->getOriginalFace()), face->getTAG());
+
+ face->setTAG(BROKEN);
+}
+
+
+/**
+ * Triangulates the face in three new faces by splitting two edges.
+ *
+ * *
+ * / \
+ * / \
+ * x x
+ * / \
+ * / \
+ * *-----------*
+ *
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains face and will contains new faces
+ * @param face input face to be triangulate
+ * @param v1 vertex index that intersects the first edge
+ * @param v1 vertex index that intersects the second edge
+ * @param e1 first relative edge index used to triangulate the face
+ * @param e2 second relative edge index used to triangulate the face
+ */
+void BOP_triangulateE(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face,
+ BOP_Index v1, BOP_Index v2, unsigned int e1, unsigned int e2)
+{
+ // Sort the edges to reduce the cases
+ if (e1 > e2) {
+ unsigned int aux = e1;
+ e1 = e2;
+ e2 = aux;
+ aux = v1;
+ v1 = v2;
+ v2 = aux;
+ }
+ // e1 < e2!
+ BOP_Face *face1;
+ BOP_Face *faces23[2];
+ if (e1 == 1 && e2 == 2) {
+ // the vertex is 2
+ face1 = new BOP_Face3(face->getVertex(1), v2, v1, face->getPlane(),
+ face->getOriginalFace());
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v1, v2,
+ faces23, face->getOriginalFace());
+ }
+ else if (e1 == 1 && e2 == 3) {
+ // the vertex is 1
+ face1 = new BOP_Face3(face->getVertex(0), v1, v2, face->getPlane(),
+ face->getOriginalFace());
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v2, v1,
+ faces23, face->getOriginalFace());
+ }
+ else if (e1 == 2 && e2 == 3) {
+ // the vertex is 3
+ face1 = new BOP_Face3(face->getVertex(2), v2, v1, face->getPlane(),
+ face->getOriginalFace());
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v1, v2,
+ faces23, face->getOriginalFace());
+ }
+ else {
+ return;
+ }
+
+ BOP_addFace(mesh, faces, face1, face->getTAG());
+ BOP_addFace(mesh, faces, faces23[0], face->getTAG());
+ BOP_addFace(mesh, faces, faces23[1], face->getTAG());
+ face->setTAG(BROKEN);
+}
+
+/**
+ * Triangulates the face in four new faces by one edge and one inner point.
+ *
+ * *
+ * / \
+ * / \
+ * x x \
+ * / \
+ * / \
+ * *-----------*
+ *
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains face and will contains new faces
+ * @param face input face to be triangulate
+ * @param v1 vertex index that lays inside face
+ * @param v2 vertex index that intersects the edge
+ * @param e relative edge index used to triangulate the face
+ */
+void BOP_triangulateF(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face,
+ BOP_Index v1, BOP_Index v2, unsigned int e)
+{
+ BOP_Face *faces12[2];
+ BOP_Face *faces34[2];
+ if (e == 1) {
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v2, v1,
+ faces12, face->getOriginalFace());
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v1, v2,
+ faces34, face->getOriginalFace());
+ }
+ else if (e == 2) {
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v2, v1,
+ faces12, face->getOriginalFace());
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(2), face->getVertex(0), v1, v2,
+ faces34, face->getOriginalFace());
+ }
+ else if (e==3) {
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(1), face->getVertex(2), v2, v1,
+ faces12, face->getOriginalFace());
+ BOP_splitQuad(mesh, face->getPlane(), face->getVertex(0), face->getVertex(1), v1, v2,
+ faces34, face->getOriginalFace());
+ }
+ else {
+ return;
+ }
+
+ BOP_addFace(mesh, faces, faces12[0], face->getTAG());
+ BOP_addFace(mesh, faces, faces12[1], face->getTAG());
+ BOP_addFace(mesh, faces, faces34[0], face->getTAG());
+ BOP_addFace(mesh, faces, faces34[1], face->getTAG());
+
+ face->setTAG(BROKEN);
+}
+
+/**
+ * Adds the new face into the faces set and the mesh and sets it a new tag.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param faces set of faces that contains oldFace
+ * @param face input face to be added
+ * @param tag tag of the new face
+ */
+void BOP_addFace(BOP_Mesh* mesh, BOP_Faces* faces, BOP_Face* face, BOP_TAG tag)
+{
+ face->setTAG(tag);
+ faces->push_back(face);
+ mesh->addFace(face);
+}
+
+/**
+ * Computes the best quad triangulation.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param plane plane used to create the news faces
+ * @param v1 first vertex index
+ * @param v2 second vertex index
+ * @param v3 third vertex index
+ * @param v4 fourth vertex index
+ * @param triangles array of faces where the new two faces will be saved
+ * @param original face index to the new faces
+ */
+void BOP_splitQuad(BOP_Mesh* mesh, MT_Plane3 plane, BOP_Index v1, BOP_Index v2,
+ BOP_Index v3, BOP_Index v4, BOP_Face* triangles[], BOP_Index original)
+{
+ MT_Point3 p1 = mesh->getVertex(v1)->getPoint();
+ MT_Point3 p2 = mesh->getVertex(v2)->getPoint();
+ MT_Point3 p3 = mesh->getVertex(v3)->getPoint();
+ MT_Point3 p4 = mesh->getVertex(v4)->getPoint();
+
+ int res = BOP_concave(p1,p2,p3,p4);
+
+ if (res==0) {
+ MT_Plane3 plane1(p1, p2, p3);
+ MT_Plane3 plane2(p1, p3, p4);
+
+ if (BOP_isInsideCircle(mesh, v1, v2, v4, v3) &&
+ BOP_orientation(plane1, plane) &&
+ BOP_orientation(plane2, plane)) {
+ triangles[0] = new BOP_Face3(v1, v2, v3, plane, original);
+ triangles[1] = new BOP_Face3(v1, v3, v4, plane, original);
+ }
+ else {
+ triangles[0] = new BOP_Face3(v1, v2, v4, plane, original);
+ triangles[1] = new BOP_Face3(v2, v3, v4, plane, original);
+ }
+ }
+ else if (res==-1) {
+ triangles[0] = new BOP_Face3(v1, v2, v4, plane, original);
+ triangles[1] = new BOP_Face3(v2, v3, v4, plane, original);
+ }
+ else {
+ triangles[0] = new BOP_Face3(v1, v2, v3, plane, original);
+ triangles[1] = new BOP_Face3(v1, v3, v4, plane, original);
+ }
+}
+
+/**
+ * Returns the vertex (v3 or v4) that splits the quad (v1,v2,v3,v4) in the best pair of triangles.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param v1 first vertex index
+ * @param v2 second vertex index
+ * @param v3 third vertex index
+ * @param v4 fourth vertex index
+ * @return v3 if the best split triangles are (v1,v2,v3) and (v1,v3,v4), v4 otherwise
+ */
+BOP_Index BOP_getTriangleVertex(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4)
+{
+ if (BOP_isInsideCircle(mesh, v1, v2, v4, v3)) {
+ return v3;
+ }
+ return v4;
+}
+
+/**
+ * Returns which of vertex v1 or v2 is nearest to u.
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param u reference vertex index
+ * @param v1 first vertex index
+ * @param v2 second vertex index
+ * @return the nearest vertex index
+ */
+BOP_Index BOP_getNearestVertex(BOP_Mesh* mesh, BOP_Index u, BOP_Index v1, BOP_Index v2)
+{
+ MT_Point3 q = mesh->getVertex(u)->getPoint();
+ MT_Point3 p1 = mesh->getVertex(v1)->getPoint();
+ MT_Point3 p2 = mesh->getVertex(v2)->getPoint();
+ if (BOP_comp(q.distance(p1), q.distance(p2)) > 0) return v2;
+ else return v1;
+}
+
+/**
+ * Computes if vertexs v4 and v5 are not inside the circle defined by v1,v2,v3 (seems to be a nice triangle)
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param v1 first vertex index
+ * @param v2 second vertex index
+ * @param v3 third vertex index
+ * @param v4 fourth vertex index
+ * @param v5 five vertex index
+ * @return if v1,v2,v3 defines a nice triangle against v4,v5
+ */
+bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index v4, BOP_Index v5)
+{
+ return BOP_isInsideCircle(mesh->getVertex(v1)->getPoint(),
+ mesh->getVertex(v2)->getPoint(),
+ mesh->getVertex(v3)->getPoint(),
+ mesh->getVertex(v4)->getPoint(),
+ mesh->getVertex(v5)->getPoint());
+}
+
+/**
+ * Computes if vertex w is not inside the circle defined by v1,v2,v3 (seems to be a nice triangle)
+ * @param mesh mesh that contains the faces, edges and vertices
+ * @param v1 first vertex index
+ * @param v2 second vertex index
+ * @param v3 third vertex index
+ * @param w fourth vertex index
+ * @return if v1,v2,v3 defines a nice triangle against w
+ */
+bool BOP_isInsideCircle(BOP_Mesh* mesh, BOP_Index v1, BOP_Index v2, BOP_Index v3, BOP_Index w)
+{
+ return BOP_isInsideCircle(mesh->getVertex(v1)->getPoint(),
+ mesh->getVertex(v2)->getPoint(),
+ mesh->getVertex(v3)->getPoint(),
+ mesh->getVertex(w)->getPoint());
+}
diff --git a/intern/boolop/intern/BOP_Triangulator.h b/intern/boolop/intern/BOP_Triangulator.h
new file mode 100644
index 00000000000..12223e1ea1f
--- /dev/null
+++ b/intern/boolop/intern/BOP_Triangulator.h
@@ -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_TRIANGULATOR_H
+#define BOP_TRIANGULATOR_H
+
+#include "BOP_MathUtils.h"
+#include "BOP_Mesh.h"
+
+void BOP_triangulateA(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v, unsigned int e);
+void BOP_triangulateB(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v);
+void BOP_triangulateC(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2);
+void BOP_triangulateD(BOP_Mesh * mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e);
+void BOP_triangulateE(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e1, unsigned int e2);
+void BOP_triangulateF(BOP_Mesh *mesh, BOP_Faces *faces, BOP_Face * face, BOP_Index v1, BOP_Index v2, unsigned int e);
+
+#endif
diff --git a/intern/boolop/intern/BOP_Vertex.cpp b/intern/boolop/intern/BOP_Vertex.cpp
new file mode 100644
index 00000000000..c039df5775d
--- /dev/null
+++ b/intern/boolop/intern/BOP_Vertex.cpp
@@ -0,0 +1,94 @@
+/**
+ * ***** 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_Vertex.h"
+
+/**
+ * Constructs a new vertex with the specified coordinates.
+ * @param x X-axis coordinate
+ * @param y Y-axis coordinate
+ * @param z Z-axis coordinate
+ */
+BOP_Vertex::BOP_Vertex(double x, double y, double z)
+{
+ m_point.setValue(x,y,z);
+ m_tag = UNCLASSIFIED;
+}
+
+/**
+ * Constructs a new vertex with the specified point.
+ * @param p point XYZ
+ */
+BOP_Vertex::BOP_Vertex(MT_Point3 p)
+{
+ m_point = p;
+ m_tag = UNCLASSIFIED;
+}
+
+/**
+ * Adds a new edge index to this vertex.
+ * @param i edge index
+ */
+void BOP_Vertex::addEdge(BOP_Index i)
+{
+ if (!containsEdge(i))
+ m_edges.push_back(i);
+}
+
+/**
+ * Removes an edge index from this vertex.
+ * @param i edge index
+ */
+void BOP_Vertex::removeEdge(BOP_Index i)
+{
+ for(BOP_IT_Indexs it = m_edges.begin();it!=m_edges.end();it++) {
+ if ((*it)==i) {
+ m_edges.erase(it);
+ return;
+ }
+ }
+}
+
+/**
+ * Returns if this vertex contains the specified edge index.
+ * @param i edge index
+ * @return true if this vertex contains the specified edge index, false otherwise
+ */
+bool BOP_Vertex::containsEdge(BOP_Index i)
+{
+ int pos=0;
+ for(BOP_IT_Indexs it = m_edges.begin();it!=m_edges.end();pos++,it++) {
+ if ((*it)==i){
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/intern/boolop/intern/BOP_Vertex.h b/intern/boolop/intern/BOP_Vertex.h
new file mode 100644
index 00000000000..a781407af34
--- /dev/null
+++ b/intern/boolop/intern/BOP_Vertex.h
@@ -0,0 +1,60 @@
+/**
+ * ***** 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_VERTEX_H
+#define BOP_VERTEX_H
+
+#include "BOP_Tag.h"
+#include "BOP_Indexs.h"
+#include "MT_Point3.h"
+
+class BOP_Vertex
+{
+private:
+ MT_Point3 m_point;
+ BOP_Indexs m_edges;
+ BOP_TAG m_tag;
+
+ bool containsEdge(BOP_Index i);
+
+public:
+ BOP_Vertex(double x, double y, double z);
+ BOP_Vertex(MT_Point3 d);
+ void addEdge(BOP_Index i);
+ void removeEdge(BOP_Index i);
+ inline BOP_Index getEdge(unsigned int i) { return m_edges[i];};
+ inline unsigned int getNumEdges() { return m_edges.size();};
+ inline BOP_Indexs &getEdges() { return m_edges;};
+ inline MT_Point3 getPoint() const { return m_point;};
+ inline BOP_TAG getTAG() { return m_tag;};
+ inline void setTAG(BOP_TAG t) { m_tag = t;};
+};
+
+#endif
diff --git a/intern/boolop/intern/Makefile b/intern/boolop/intern/Makefile
new file mode 100644
index 00000000000..e098665eabf
--- /dev/null
+++ b/intern/boolop/intern/Makefile
@@ -0,0 +1,48 @@
+#
+# $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): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+# string intern Makefile
+#
+
+LIBNAME = boolop
+DIR = $(OCGDIR)/intern/$(LIBNAME)
+DIRS = common
+
+include nan_compile.mk
+
+CCFLAGS += $(LEVEL_2_CPP_WARNINGS)
+
+CPPFLAGS += -I../extern
+CPPFLAGS += -I$(NAN_MOTO)/include
+CPPFLAGS += -I$(NAN_MEMUTIL)/include
+CPPFLAGS += -I$(NAN_CONTAINER)/include
+CPPFLAGS += -Icommon
+
+