diff options
author | Alexander Ewering <blender@instinctive.de> | 2005-10-29 00:17:27 +0400 |
---|---|---|
committer | Alexander Ewering <blender@instinctive.de> | 2005-10-29 00:17:27 +0400 |
commit | d243bfb61ef6c906f446085e5ae1993263aa85a8 (patch) | |
tree | a312dced8f8b2cbc4586c0aaf61906d5c4071e02 /intern | |
parent | d3dd5c5b7aa185265ce7816dab996e8fa9288bc6 (diff) |
New files from new booleans
Diffstat (limited to 'intern')
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 + + |