diff --git a/src/BRepExtrema/BRepExtrema_ElementFilter.hxx b/src/BRepExtrema/BRepExtrema_ElementFilter.hxx new file mode 100644 index 0000000000..d81c94eddb --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_ElementFilter.hxx @@ -0,0 +1,48 @@ +// Created on: 2015-05-07 +// Created by: Denis BOGOLEPOV +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _BRepExtrema_ElementFilter_HeaderFile +#define _BRepExtrema_ElementFilter_HeaderFile + +#include + +//! Filtering tool used to detect if two given mesh elements +//! should be tested for overlapping/intersection or not. +struct BRepExtrema_ElementFilter +{ + //! Result of filtering function. + enum FilterResult + { + NoCheck, + Overlap, + DoCheck + }; + + //! Releases resources of element filter. + virtual ~BRepExtrema_ElementFilter() + { + // + } + + //! Checks if two mesh elements should be tested for overlapping/intersection + //! (used for detection correct/incorrect cases of shared edges and vertices). + virtual FilterResult PreCheckElements (const Standard_Integer /*theIndex1*/, + const Standard_Integer /*theIndex2*/) + { + return DoCheck; + } +}; + +#endif // _BRepExtrema_ElementFilter_HeaderFile \ No newline at end of file diff --git a/src/BRepExtrema/BRepExtrema_MapOfIntegerPackedMapOfInteger.hxx b/src/BRepExtrema/BRepExtrema_MapOfIntegerPackedMapOfInteger.hxx new file mode 100644 index 0000000000..47e8c24f4e --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_MapOfIntegerPackedMapOfInteger.hxx @@ -0,0 +1,20 @@ +// Created on: 2015-05-13 +// Created by: Denis BOGOLEPOV +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include +#include + +//! Set of overlapped sub-shapes. +typedef NCollection_DataMap BRepExtrema_MapOfIntegerPackedMapOfInteger; \ No newline at end of file diff --git a/src/BRepExtrema/BRepExtrema_OverlapTool.cxx b/src/BRepExtrema/BRepExtrema_OverlapTool.cxx new file mode 100644 index 0000000000..464e1e84e5 --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_OverlapTool.cxx @@ -0,0 +1,831 @@ +// Created on: 2015-04-26 +// Created by: Denis BOGOLEPOV +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include + +//======================================================================= +//function : BRepExtrema_OverlapTool +//purpose : +//======================================================================= +BRepExtrema_OverlapTool::BRepExtrema_OverlapTool() +: myFilter (NULL) +{ + myIsDone = Standard_False; +} + +//======================================================================= +//function : BRepExtrema_OverlapTool +//purpose : +//======================================================================= +BRepExtrema_OverlapTool::BRepExtrema_OverlapTool (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2) +: myFilter (NULL) +{ + LoadTriangleSets (theSet1, theSet2); +} + +//======================================================================= +//function : LoadTriangleSets +//purpose : +//======================================================================= +void BRepExtrema_OverlapTool::LoadTriangleSets (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2) +{ + mySet1 = theSet1; + mySet2 = theSet2; + + myIsDone = Standard_False; +} + +#ifndef DBL_EPSILON + #define DBL_EPSILON std::numeric_limits::epsilon() +#endif + +namespace +{ + //! Tool class to describe stack item in traverse function. + struct BRepExtrema_StackItem + { + Standard_Integer Node1; + Standard_Integer Node2; + + BRepExtrema_StackItem (const Standard_Integer theNode1 = 0, + const Standard_Integer theNode2 = 0) + : Node1 (theNode1), + Node2 (theNode2) + { + // + } + }; + + //! Bounding triangular prism for specified triangle. + class BRepExtrema_BoundingPrism + { + public: + + //! Vertices of the prism. + BVH_Vec3d Vertices[6]; + + //! Edges of the prism. + BVH_Vec3d Edges[3]; + + //! Normal to prism caps. + BVH_Vec3d Normal; + + //! Normals to prism edges. + BVH_Vec3d EdgeNormals[3]; + + //! Is prism initialized? + Standard_Boolean IsInited; + + public: + + //! Creates uninitialized bounding prism. + BRepExtrema_BoundingPrism() : IsInited (Standard_False) + { + // + } + + //! Creates new bounding prism for the given triangle. + BRepExtrema_BoundingPrism (const BVH_Vec3d& theVertex0, + const BVH_Vec3d& theVertex1, + const BVH_Vec3d& theVertex2, + const Standard_Real theDeflect) + { + Init (theVertex0, + theVertex1, + theVertex2, + theDeflect); + } + + //! Calculates bounding prism for the given triangle. + void Init (const BVH_Vec3d& theVertex0, + const BVH_Vec3d& theVertex1, + const BVH_Vec3d& theVertex2, + const Standard_Real theDeflect) + { + Edges[0] = theVertex1 - theVertex0; + Edges[1] = theVertex2 - theVertex0; + Edges[2] = theVertex2 - theVertex1; + + Normal = BVH_Vec3d::Cross (Edges[0], Edges[1]); + + EdgeNormals[0] = BVH_Vec3d::Cross (Edges[0], Normal); + EdgeNormals[1] = BVH_Vec3d::Cross (Edges[1], Normal); + EdgeNormals[2] = BVH_Vec3d::Cross (Edges[2], Normal); + + EdgeNormals[0] *= 1.0 / Max (EdgeNormals[0].Modulus(), Precision::Confusion()); + EdgeNormals[1] *= 1.0 / Max (EdgeNormals[1].Modulus(), Precision::Confusion()); + EdgeNormals[2] *= 1.0 / Max (EdgeNormals[2].Modulus(), Precision::Confusion()); + + const BVH_Vec3d aDirect01 = EdgeNormals[0] - EdgeNormals[1]; + const BVH_Vec3d aDirect02 = EdgeNormals[0] + EdgeNormals[2]; + const BVH_Vec3d aDirect12 = EdgeNormals[2] - EdgeNormals[1]; + + Vertices[0] = Vertices[3] = theVertex0 + aDirect01 * (theDeflect / aDirect01.Dot (EdgeNormals[0])); + Vertices[1] = Vertices[4] = theVertex1 + aDirect02 * (theDeflect / aDirect02.Dot (EdgeNormals[2])); + Vertices[2] = Vertices[5] = theVertex2 + aDirect12 * (theDeflect / aDirect12.Dot (EdgeNormals[2])); + + const BVH_Vec3d aNormOffset = Normal * (theDeflect / Max (Normal.Modulus(), Precision::Confusion())); + + for (Standard_Integer aVertIdx = 0; aVertIdx < 3; ++aVertIdx) + { + Vertices[aVertIdx + 0] += aNormOffset; + Vertices[aVertIdx + 3] -= aNormOffset; + } + + IsInited = Standard_True; + } + + //! Checks if two prisms are separated along the given axis. + Standard_Boolean Separated (const BRepExtrema_BoundingPrism& thePrism, const BVH_Vec3d& theAxis) const + { + Standard_Real aMin1 = DBL_MAX; + Standard_Real aMax1 = -DBL_MAX; + + Standard_Real aMin2 = DBL_MAX; + Standard_Real aMax2 = -DBL_MAX; + + for (Standard_Integer aVertIdx = 0; aVertIdx < 6; ++aVertIdx) + { + const Standard_Real aProj1 = Vertices[aVertIdx].Dot (theAxis); + + aMin1 = Min (aMin1, aProj1); + aMax1 = Max (aMax1, aProj1); + + const Standard_Real aProj2 = thePrism.Vertices[aVertIdx].Dot (theAxis); + + aMin2 = Min (aMin2, aProj2); + aMax2 = Max (aMax2, aProj2); + + if (aMin1 <= aMax2 && aMax1 >= aMin2) + { + return Standard_False; + } + } + + return aMin1 > aMax2 || aMax1 < aMin2; + } + }; + + // ======================================================================= + // function : sign + // purpose : + // ======================================================================= + Standard_Real sign (const BVH_Vec3d& theVertex0, + const BVH_Vec3d& theVertex1, + const BVH_Vec3d& theVertex2, + const Standard_Integer theX, + const Standard_Integer theY) + { + return (theVertex0[theX] - theVertex2[theX]) * (theVertex1[theY] - theVertex2[theY]) - + (theVertex1[theX] - theVertex2[theX]) * (theVertex0[theY] - theVertex2[theY]); + } + + // ======================================================================= + // function : pointInTriangle + // purpose : + // ======================================================================= + Standard_Boolean pointInTriangle (const BVH_Vec3d& theTestPnt, + const BVH_Vec3d& theTrgVtx0, + const BVH_Vec3d& theTrgVtx1, + const BVH_Vec3d& theTrgVtx2, + const Standard_Integer theX, + const Standard_Integer theY) + { + const Standard_Boolean aSign0 = sign (theTestPnt, theTrgVtx0, theTrgVtx1, theX, theY) <= 0.0; + const Standard_Boolean aSign1 = sign (theTestPnt, theTrgVtx1, theTrgVtx2, theX, theY) <= 0.0; + const Standard_Boolean aSign2 = sign (theTestPnt, theTrgVtx2, theTrgVtx0, theX, theY) <= 0.0; + + return (aSign0 == aSign1) && (aSign1 == aSign2); + } + + // ======================================================================= + // function : segmentsIntersected + // purpose : Checks if two line segments are intersected + // ======================================================================= + Standard_Boolean segmentsIntersected (const BVH_Vec2d& theOriginSeg0, + const BVH_Vec2d& theOriginSeg1, + const BVH_Vec2d& theDirectSeg0, + const BVH_Vec2d& theDirectSeg1) + { + const Standard_Real aDet = -theDirectSeg1.x() * theDirectSeg0.y() + + theDirectSeg0.x() * theDirectSeg1.y(); + + if (fabs (aDet) < DBL_EPSILON) // segments are parallel + { + const BVH_Vec2d aDirect = theDirectSeg0 * (1.0 / theDirectSeg0.Modulus()); + + const Standard_Real aEdge0Time0 = theOriginSeg0.Dot (aDirect); + const Standard_Real aEdge1Time0 = theOriginSeg1.Dot (aDirect); + + const Standard_Real aEdge0Time1 = aEdge0Time0 + theDirectSeg0.Dot (aDirect); + const Standard_Real aEdge1Time1 = aEdge1Time0 + theDirectSeg1.Dot (aDirect); + + const Standard_Real aEdge0Min = Min (aEdge0Time0, aEdge0Time1); + const Standard_Real aEdge1Min = Min (aEdge1Time0, aEdge1Time1); + const Standard_Real aEdge0Max = Max (aEdge0Time0, aEdge0Time1); + const Standard_Real aEdge1Max = Max (aEdge1Time0, aEdge1Time1); + + if (Max (aEdge0Min, aEdge1Min) > Min (aEdge0Max, aEdge1Max)) + { + return Standard_False; + } + + const BVH_Vec2d aNormal (-aDirect.y(), aDirect.x()); + + return fabs (theOriginSeg0.Dot (aNormal) - theOriginSeg1.Dot (aNormal)) < DBL_EPSILON; + } + + const BVH_Vec2d aDelta = theOriginSeg0 - theOriginSeg1; + + const Standard_Real aU = (-theDirectSeg0.y() * aDelta.x() + theDirectSeg0.x() * aDelta.y()) / aDet; + const Standard_Real aV = ( theDirectSeg1.x() * aDelta.y() - theDirectSeg1.y() * aDelta.x()) / aDet; + + return aU >= 0.0 && aU <= 1.0 && aV >= 0.0 && aV <= 1.0; + } + + // ======================================================================= + // function : trianglesIntersected + // purpose : Checks if two triangles are intersected + // ("A Fast Triangle-Triangle Intersection Test" by T. Moller) + // ======================================================================= + Standard_Boolean trianglesIntersected (const BVH_Vec3d& theTrng0Vert0, + const BVH_Vec3d& theTrng0Vert1, + const BVH_Vec3d& theTrng0Vert2, + const BVH_Vec3d& theTrng1Vert0, + const BVH_Vec3d& theTrng1Vert1, + const BVH_Vec3d& theTrng1Vert2) + { + const BVH_Vec3d aTrng1Normal = BVH_Vec3d::Cross (theTrng1Vert1 - theTrng1Vert0, + theTrng1Vert2 - theTrng1Vert0).Normalized(); + + const Standard_Real aTrng1PlaneDist = aTrng1Normal.Dot (-theTrng1Vert0); + + Standard_Real aDistTrng0Vert0 = aTrng1Normal.Dot (theTrng0Vert0) + aTrng1PlaneDist; + Standard_Real aDistTrng0Vert1 = aTrng1Normal.Dot (theTrng0Vert1) + aTrng1PlaneDist; + Standard_Real aDistTrng0Vert2 = aTrng1Normal.Dot (theTrng0Vert2) + aTrng1PlaneDist; + + if ((aDistTrng0Vert0 < 0.0 && aDistTrng0Vert1 < 0.0 && aDistTrng0Vert2 < 0.0) + || (aDistTrng0Vert0 > 0.0 && aDistTrng0Vert1 > 0.0 && aDistTrng0Vert2 > 0.0)) + { + return Standard_False; // 1st triangle lies on one side of the 2nd triangle + } + + if (fabs (aDistTrng0Vert0) > Precision::Confusion() + || fabs (aDistTrng0Vert1) > Precision::Confusion() + || fabs (aDistTrng0Vert2) > Precision::Confusion()) // general 3D case + { + const BVH_Vec3d aTrng0Normal = BVH_Vec3d::Cross (theTrng0Vert1 - theTrng0Vert0, + theTrng0Vert2 - theTrng0Vert0).Normalized(); + + const Standard_Real aTrng0PlaneDist = aTrng0Normal.Dot (-theTrng0Vert0); + + Standard_Real aDistTrng1Vert0 = aTrng0Normal.Dot (theTrng1Vert0) + aTrng0PlaneDist; + Standard_Real aDistTrng1Vert1 = aTrng0Normal.Dot (theTrng1Vert1) + aTrng0PlaneDist; + Standard_Real aDistTrng1Vert2 = aTrng0Normal.Dot (theTrng1Vert2) + aTrng0PlaneDist; + + if ((aDistTrng1Vert0 < 0.0 && aDistTrng1Vert1 < 0.0 && aDistTrng1Vert2 < 0.0) + || (aDistTrng1Vert0 > 0.0 && aDistTrng1Vert1 > 0.0 && aDistTrng1Vert2 > 0.0)) + { + return Standard_False; // 2nd triangle lies on one side of the 1st triangle + } + + const BVH_Vec3d aCrossLine = BVH_Vec3d::Cross (aTrng0Normal, + aTrng1Normal); + + Standard_Real aProjTrng0Vert0 = theTrng0Vert0.Dot (aCrossLine); + Standard_Real aProjTrng0Vert1 = theTrng0Vert1.Dot (aCrossLine); + Standard_Real aProjTrng0Vert2 = theTrng0Vert2.Dot (aCrossLine); + + if (aDistTrng0Vert0 * aDistTrng0Vert1 > 0.0) + { + std::swap (aDistTrng0Vert1, aDistTrng0Vert2); + std::swap (aProjTrng0Vert1, aProjTrng0Vert2); + } + else if (aDistTrng0Vert1 * aDistTrng0Vert2 > 0.0) + { + std::swap (aDistTrng0Vert1, aDistTrng0Vert0); + std::swap (aProjTrng0Vert1, aProjTrng0Vert0); + } + + Standard_Real aTime1 = fabs (aDistTrng0Vert0) <= DBL_EPSILON ? aProjTrng0Vert0 : + aProjTrng0Vert0 + (aProjTrng0Vert1 - aProjTrng0Vert0) * aDistTrng0Vert0 / (aDistTrng0Vert0 - aDistTrng0Vert1); + Standard_Real aTime2 = fabs (aDistTrng0Vert2) <= DBL_EPSILON ? aProjTrng0Vert2 : + aProjTrng0Vert2 + (aProjTrng0Vert1 - aProjTrng0Vert2) * aDistTrng0Vert2 / (aDistTrng0Vert2 - aDistTrng0Vert1); + + const Standard_Real aTimeMin1 = Min (aTime1, aTime2); + const Standard_Real aTimeMax1 = Max (aTime1, aTime2); + + Standard_Real aProjTrng1Vert0 = theTrng1Vert0.Dot (aCrossLine); + Standard_Real aProjTrng1Vert1 = theTrng1Vert1.Dot (aCrossLine); + Standard_Real aProjTrng1Vert2 = theTrng1Vert2.Dot (aCrossLine); + + if (aDistTrng1Vert0 * aDistTrng1Vert1 > 0.0) + { + std::swap (aDistTrng1Vert1, aDistTrng1Vert2); + std::swap (aProjTrng1Vert1, aProjTrng1Vert2); + } + else if (aDistTrng1Vert1 * aDistTrng1Vert2 > 0.0) + { + std::swap (aDistTrng1Vert1, aDistTrng1Vert0); + std::swap (aProjTrng1Vert1, aProjTrng1Vert0); + } + + aTime1 = fabs (aDistTrng1Vert0) <= DBL_EPSILON ? aProjTrng1Vert0 : + aProjTrng1Vert0 + (aProjTrng1Vert1 - aProjTrng1Vert0) * aDistTrng1Vert0 / (aDistTrng1Vert0 - aDistTrng1Vert1); + aTime2 = fabs (aDistTrng1Vert2) <= DBL_EPSILON ? aProjTrng1Vert2 : + aProjTrng1Vert2 + (aProjTrng1Vert1 - aProjTrng1Vert2) * aDistTrng1Vert2 / (aDistTrng1Vert2 - aDistTrng1Vert1); + + const Standard_Real aTimeMin2 = Min (aTime1, aTime2); + const Standard_Real aTimeMax2 = Max (aTime1, aTime2); + + aTime1 = Max (aTimeMin1, aTimeMin2); + aTime2 = Min (aTimeMax1, aTimeMax2); + + return aTime1 <= aTime2; // intervals intersected --> triangles overlapped + } + else // triangles are co-planar + { + Standard_Integer anX; + Standard_Integer anY; + + if (fabs (aTrng1Normal[0]) > fabs (aTrng1Normal[1])) + { + anX = fabs (aTrng1Normal[0]) > fabs (aTrng1Normal[2]) ? 1 : 0; + anY = fabs (aTrng1Normal[0]) > fabs (aTrng1Normal[2]) ? 2 : 1; + } + else + { + anX = fabs (aTrng1Normal[1]) > fabs (aTrng1Normal[2]) ? 0 : 0; + anY = fabs (aTrng1Normal[1]) > fabs (aTrng1Normal[2]) ? 2 : 1; + } + + const BVH_Vec2d aOriginSeg0 [] = {BVH_Vec2d (theTrng0Vert0[anX], theTrng0Vert0[anY]), + BVH_Vec2d (theTrng0Vert1[anX], theTrng0Vert1[anY]), + BVH_Vec2d (theTrng0Vert2[anX], theTrng0Vert2[anY]) }; + + const BVH_Vec2d aDirectSeg0 [] = {aOriginSeg0[1] - aOriginSeg0[0], + aOriginSeg0[2] - aOriginSeg0[1], + aOriginSeg0[0] - aOriginSeg0[2] }; + + const BVH_Vec2d aOriginSeg1 [] = {BVH_Vec2d (theTrng1Vert0[anX], theTrng1Vert0[anY]), + BVH_Vec2d (theTrng1Vert1[anX], theTrng1Vert1[anY]), + BVH_Vec2d (theTrng1Vert2[anX], theTrng1Vert2[anY]) }; + + const BVH_Vec2d aDirectSeg1 [] = {aOriginSeg1[1] - aOriginSeg1[0], + aOriginSeg1[2] - aOriginSeg1[1], + aOriginSeg1[0] - aOriginSeg1[2] }; + + for (Standard_Integer aTrg0Edge = 0; aTrg0Edge < 3; ++aTrg0Edge) + { + for (Standard_Integer aTrg1Edge = 0; aTrg1Edge < 3; ++aTrg1Edge) + { + if (segmentsIntersected (aOriginSeg0[aTrg0Edge], + aOriginSeg1[aTrg1Edge], + aDirectSeg0[aTrg0Edge], + aDirectSeg1[aTrg1Edge])) + { + return Standard_True; // edges intersected --> triangles overlapped + } + } + } + + if (pointInTriangle (theTrng1Vert0, + theTrng0Vert0, + theTrng0Vert1, + theTrng0Vert2, + anX, + anY)) + { + return Standard_True; // 1st triangle inside 2nd --> triangles overlapped + } + + if (pointInTriangle (theTrng0Vert0, + theTrng1Vert0, + theTrng1Vert1, + theTrng1Vert2, + anX, + anY)) + { + return Standard_True; // 2nd triangle inside 1st --> triangles overlapped + } + } + + return Standard_False; + } + + // ======================================================================= + // function : prismsIntersected + // purpose : Checks if two triangular prisms are intersected + // (test uses SAT - Separating Axis Theorem) + // ======================================================================= + Standard_Boolean prismsIntersected (const BRepExtrema_BoundingPrism& thePrism1, + const BRepExtrema_BoundingPrism& thePrism2) + { + if (thePrism1.Separated (thePrism2, thePrism1.Normal)) + { + return Standard_False; + } + + if (thePrism1.Separated (thePrism2, thePrism2.Normal)) + { + return Standard_False; + } + + for (Standard_Integer anIdx = 0; anIdx < 3; ++anIdx) + { + if (thePrism1.Separated (thePrism2, thePrism1.EdgeNormals[anIdx])) + { + return Standard_False; + } + } + + for (Standard_Integer anIdx = 0; anIdx < 3; ++anIdx) + { + if (thePrism1.Separated (thePrism2, thePrism2.EdgeNormals[anIdx])) + { + return Standard_False; + } + } + + for (Standard_Integer anIdx1 = 0; anIdx1 < 4; ++anIdx1) + { + const BVH_Vec3d& aEdge1 = (anIdx1 == 3) ? thePrism1.Normal : thePrism1.Edges[anIdx1]; + + for (Standard_Integer anIdx2 = 0; anIdx2 < 4; ++anIdx2) + { + const BVH_Vec3d& aEdge2 = (anIdx2 == 3) ? thePrism2.Normal : thePrism2.Edges[anIdx2]; + + if (thePrism1.Separated (thePrism2, BVH_Vec3d::Cross (aEdge1, aEdge2))) + { + return Standard_False; + } + } + } + + return Standard_True; + } + + // ======================================================================= + // function : overlapBoxes + // purpose : Checks if two boxes (AABBs) are overlapped + // ======================================================================= + inline Standard_Boolean overlapBoxes (const BVH_Vec3d& theBoxMin1, + const BVH_Vec3d& theBoxMax1, + const BVH_Vec3d& theBoxMin2, + const BVH_Vec3d& theBoxMax2, + const Standard_Real theTolerance) + { + // Check for overlap + return !(theBoxMin1.x() > theBoxMax2.x() + theTolerance || + theBoxMax1.x() < theBoxMin2.x() - theTolerance || + theBoxMin1.y() > theBoxMax2.y() + theTolerance || + theBoxMax1.y() < theBoxMin2.y() - theTolerance || + theBoxMin1.z() > theBoxMax2.z() + theTolerance || + theBoxMax1.z() < theBoxMin2.z() - theTolerance); + } + + //======================================================================= + //function : getSetOfFaces + //purpose : + //======================================================================= + TColStd_PackedMapOfInteger& getSetOfFaces ( + BRepExtrema_MapOfIntegerPackedMapOfInteger& theFaces, const Standard_Integer theFaceIdx) + { + if (!theFaces.IsBound (theFaceIdx)) + { + theFaces.Bind (theFaceIdx, TColStd_PackedMapOfInteger()); + } + + return theFaces.ChangeFind (theFaceIdx); + } +} + +//======================================================================= +//function : intersectTriangleRangesExact +//purpose : +//======================================================================= +void BRepExtrema_OverlapTool::intersectTriangleRangesExact (const BVH_Vec4i& theLeaf1, + const BVH_Vec4i& theLeaf2) +{ + for (Standard_Integer aTrgIdx1 = theLeaf1.y(); aTrgIdx1 <= theLeaf1.z(); ++aTrgIdx1) + { + const Standard_Integer aFaceIdx1 = mySet1->GetFaceID (aTrgIdx1); + + BVH_Vec3d aTrg1Vert1; + BVH_Vec3d aTrg1Vert2; + BVH_Vec3d aTrg1Vert3; + + mySet1->GetVertices (aTrgIdx1, + aTrg1Vert1, + aTrg1Vert2, + aTrg1Vert3); + + const Standard_Boolean aIsInSet = myOverlapSubShapes1.IsBound (aFaceIdx1); + + for (Standard_Integer aTrgIdx2 = theLeaf2.y(); aTrgIdx2 <= theLeaf2.z(); ++aTrgIdx2) + { + const Standard_Integer aFaceIdx2 = mySet2->GetFaceID (aTrgIdx2); + + if (aIsInSet && myOverlapSubShapes1.Find (aFaceIdx1).Contains (aFaceIdx2)) + { + continue; + } + + BRepExtrema_ElementFilter::FilterResult aResult = myFilter == NULL ? + BRepExtrema_ElementFilter::DoCheck : myFilter->PreCheckElements (aTrgIdx1, aTrgIdx2); + + if (aResult == BRepExtrema_ElementFilter::Overlap) + { + getSetOfFaces (myOverlapSubShapes1, aFaceIdx1).Add (aFaceIdx2); + getSetOfFaces (myOverlapSubShapes2, aFaceIdx2).Add (aFaceIdx1); + +#ifdef OVERLAP_TOOL_OUTPUT_TRIANGLES + if (mySet1 == mySet2) + { + myOverlapTriangles1.Add (aTrgIdx1); + myOverlapTriangles1.Add (aTrgIdx2); + } + else + { + myOverlapTriangles1.Add (aTrgIdx1); + myOverlapTriangles2.Add (aTrgIdx2); + } +#endif + } + else if (aResult == BRepExtrema_ElementFilter::DoCheck) + { + BVH_Vec3d aTrg2Vert1; + BVH_Vec3d aTrg2Vert2; + BVH_Vec3d aTrg2Vert3; + + mySet2->GetVertices (aTrgIdx2, aTrg2Vert1, aTrg2Vert2, aTrg2Vert3); + + if (trianglesIntersected (aTrg1Vert1, + aTrg1Vert2, + aTrg1Vert3, + aTrg2Vert1, + aTrg2Vert2, + aTrg2Vert3)) + { + getSetOfFaces (myOverlapSubShapes1, aFaceIdx1).Add (aFaceIdx2); + getSetOfFaces (myOverlapSubShapes2, aFaceIdx2).Add (aFaceIdx1); + +#ifdef OVERLAP_TOOL_OUTPUT_TRIANGLES + if (mySet1 == mySet2) + { + myOverlapTriangles1.Add (aTrgIdx1); + myOverlapTriangles1.Add (aTrgIdx2); + } + else + { + myOverlapTriangles1.Add (aTrgIdx1); + myOverlapTriangles2.Add (aTrgIdx2); + } +#endif + } + } + } + } +} + +//======================================================================= +//function : intersectTriangleRangesToler +//purpose : +//======================================================================= +void BRepExtrema_OverlapTool::intersectTriangleRangesToler (const BVH_Vec4i& theLeaf1, + const BVH_Vec4i& theLeaf2, + const Standard_Real theToler) +{ + for (Standard_Integer aTrgIdx1 = theLeaf1.y(); aTrgIdx1 <= theLeaf1.z(); ++aTrgIdx1) + { + const Standard_Integer aFaceIdx1 = mySet1->GetFaceID (aTrgIdx1); + + BVH_Vec3d aTrg1Vert1; + BVH_Vec3d aTrg1Vert2; + BVH_Vec3d aTrg1Vert3; + + mySet1->GetVertices (aTrgIdx1, + aTrg1Vert1, + aTrg1Vert2, + aTrg1Vert3); + + BRepExtrema_BoundingPrism aPrism1; // not initialized + + const Standard_Boolean aIsInSet = myOverlapSubShapes1.IsBound (aFaceIdx1); + + for (Standard_Integer aTrgIdx2 = theLeaf2.y(); aTrgIdx2 <= theLeaf2.z(); ++aTrgIdx2) + { + const Standard_Integer aFaceIdx2 = mySet2->GetFaceID (aTrgIdx2); + + if (aIsInSet && myOverlapSubShapes1.Find (aFaceIdx1).Contains (aFaceIdx2)) + { + continue; + } + + BRepExtrema_ElementFilter::FilterResult aResult = myFilter == NULL ? + BRepExtrema_ElementFilter::DoCheck : myFilter->PreCheckElements (aTrgIdx1, aTrgIdx2); + + if (aResult == BRepExtrema_ElementFilter::Overlap) + { + getSetOfFaces (myOverlapSubShapes1, aFaceIdx1).Add (aFaceIdx2); + getSetOfFaces (myOverlapSubShapes2, aFaceIdx2).Add (aFaceIdx1); + +#ifdef OVERLAP_TOOL_OUTPUT_TRIANGLES + if (mySet1 == mySet2) + { + myOverlapTriangles1.Add (aTrgIdx1); + myOverlapTriangles1.Add (aTrgIdx2); + } + else + { + myOverlapTriangles1.Add (aTrgIdx1); + myOverlapTriangles2.Add (aTrgIdx2); + } +#endif + } + else if (aResult == BRepExtrema_ElementFilter::DoCheck) + { + if (!aPrism1.IsInited) + { + aPrism1.Init (aTrg1Vert1, aTrg1Vert2, aTrg1Vert3, theToler); + } + + BVH_Vec3d aTrg2Vert1; + BVH_Vec3d aTrg2Vert2; + BVH_Vec3d aTrg2Vert3; + + mySet2->GetVertices (aTrgIdx2, + aTrg2Vert1, + aTrg2Vert2, + aTrg2Vert3); + + BRepExtrema_BoundingPrism aPrism2 (aTrg2Vert1, + aTrg2Vert2, + aTrg2Vert3, + theToler); + + if (prismsIntersected (aPrism1, aPrism2)) + { + getSetOfFaces (myOverlapSubShapes1, aFaceIdx1).Add (aFaceIdx2); + getSetOfFaces (myOverlapSubShapes2, aFaceIdx2).Add (aFaceIdx1); + } + } + } + } +} + +//======================================================================= +//function : Perform +//purpose : Performs search for overlapped faces +//======================================================================= +void BRepExtrema_OverlapTool::Perform (const Standard_Real theTolerance) +{ + if (mySet1.IsNull() || mySet2.IsNull()) + { + return; + } + + BRepExtrema_StackItem aStack[96]; + + const NCollection_Handle >& aBVH1 = mySet1->BVH(); + const NCollection_Handle >& aBVH2 = mySet2->BVH(); + + if (aBVH1.IsNull() || aBVH2.IsNull()) + { + return; + } + + BRepExtrema_StackItem aNodes; // current pair of nodes + + Standard_Integer aHead = -1; // stack head position + + for (;;) + { + BVH_Vec4i aNodeData1 = aBVH1->NodeInfoBuffer()[aNodes.Node1]; + BVH_Vec4i aNodeData2 = aBVH2->NodeInfoBuffer()[aNodes.Node2]; + + if (aNodeData1.x() != 0 && aNodeData2.x() != 0) // leaves + { + if (theTolerance == 0.0) + { + intersectTriangleRangesExact (aNodeData1, aNodeData2); + } + else + { + intersectTriangleRangesToler (aNodeData1, aNodeData2, theTolerance); + } + + if (aHead < 0) + break; + + aNodes = aStack[aHead--]; + } + else + { + BRepExtrema_StackItem aPairsToProcess[4]; + + Standard_Integer aNbPairs = 0; + + if (aNodeData1.x() == 0) // inner node + { + const BVH_Vec3d& aMinPntLft1 = aBVH1->MinPoint (aNodeData1.y()); + const BVH_Vec3d& aMaxPntLft1 = aBVH1->MaxPoint (aNodeData1.y()); + const BVH_Vec3d& aMinPntRgh1 = aBVH1->MinPoint (aNodeData1.z()); + const BVH_Vec3d& aMaxPntRgh1 = aBVH1->MaxPoint (aNodeData1.z()); + + if (aNodeData2.x() == 0) // inner node + { + const BVH_Vec3d& aMinPntLft2 = aBVH2->MinPoint (aNodeData2.y()); + const BVH_Vec3d& aMaxPntLft2 = aBVH2->MaxPoint (aNodeData2.y()); + const BVH_Vec3d& aMinPntRgh2 = aBVH2->MinPoint (aNodeData2.z()); + const BVH_Vec3d& aMaxPntRgh2 = aBVH2->MaxPoint (aNodeData2.z()); + + if (overlapBoxes (aMinPntLft1, aMaxPntLft1, aMinPntLft2, aMaxPntLft2, theTolerance)) + { + aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.y(), aNodeData2.y()); + } + if (overlapBoxes (aMinPntLft1, aMaxPntLft1, aMinPntRgh2, aMaxPntRgh2, theTolerance)) + { + aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.y(), aNodeData2.z()); + } + if (overlapBoxes (aMinPntRgh1, aMaxPntRgh1, aMinPntLft2, aMaxPntLft2, theTolerance)) + { + aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.z(), aNodeData2.y()); + } + if (overlapBoxes (aMinPntRgh1, aMaxPntRgh1, aMinPntRgh2, aMaxPntRgh2, theTolerance)) + { + aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.z(), aNodeData2.z()); + } + } + else + { + const BVH_Vec3d& aMinPntLeaf = aBVH2->MinPoint (aNodes.Node2); + const BVH_Vec3d& aMaxPntLeaf = aBVH2->MaxPoint (aNodes.Node2); + + if (overlapBoxes (aMinPntLft1, aMaxPntLft1, aMinPntLeaf, aMaxPntLeaf, theTolerance)) + { + aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.y(), aNodes.Node2); + } + if (overlapBoxes (aMinPntRgh1, aMaxPntRgh1, aMinPntLeaf, aMaxPntLeaf, theTolerance)) + { + aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.z(), aNodes.Node2); + } + } + } + else + { + const BVH_Vec3d& aMinPntLeaf = aBVH1->MinPoint (aNodes.Node1); + const BVH_Vec3d& aMaxPntLeaf = aBVH1->MaxPoint (aNodes.Node1); + + const BVH_Vec3d& aMinPntLft2 = aBVH2->MinPoint (aNodeData2.y()); + const BVH_Vec3d& aMaxPntLft2 = aBVH2->MaxPoint (aNodeData2.y()); + const BVH_Vec3d& aMinPntRgh2 = aBVH2->MinPoint (aNodeData2.z()); + const BVH_Vec3d& aMaxPntRgh2 = aBVH2->MaxPoint (aNodeData2.z()); + + if (overlapBoxes (aMinPntLft2, aMaxPntLft2, aMinPntLeaf, aMaxPntLeaf, theTolerance)) + { + aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodes.Node1, aNodeData2.y()); + } + if (overlapBoxes (aMinPntRgh2, aMaxPntRgh2, aMinPntLeaf, aMaxPntLeaf, theTolerance)) + { + aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodes.Node1, aNodeData2.z()); + } + } + + if (aNbPairs > 0) + { + aNodes = aPairsToProcess[0]; + + for (Standard_Integer anIdx = 1; anIdx < aNbPairs; ++anIdx) + { + aStack[++aHead] = aPairsToProcess[anIdx]; + } + } + else + { + if (aHead < 0) + break; + + aNodes = aStack[aHead--]; + } + } + } + + myIsDone = Standard_True; +} diff --git a/src/BRepExtrema/BRepExtrema_OverlapTool.hxx b/src/BRepExtrema/BRepExtrema_OverlapTool.hxx new file mode 100644 index 0000000000..4ea3ef2030 --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_OverlapTool.hxx @@ -0,0 +1,118 @@ +// Created on: 2015-04-26 +// Created by: Denis BOGOLEPOV +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _BRepExtrema_OverlapTool_HeaderFile +#define _BRepExtrema_OverlapTool_HeaderFile + +#include +#include +#include +#include + +//! Enables storing of individual overlapped triangles (useful for debug). +// #define OVERLAP_TOOL_OUTPUT_TRIANGLES + +//! Tool class for for detection of overlapping of two BVH primitive sets. +//! This tool is not intended to be used independently, and is integrated +//! in other classes, implementing algorithms based on shape tessellation +//! (BRepExtrema_ShapeProximity and BRepExtrema_SelfIntersection). +//! +//! Note that input element sets may correspond to different shapes or to +//! the same shape. In first case, tessellations of two given shapes will +//! be tested for intersection (or overlapping, if tolerance is not zero). +//! In second case, tessellation of single shape will be tested for self- +//! intersections. Please note that algorithm results are approximate and +//! depend greatly on the quality of input tessellation(s). +class BRepExtrema_OverlapTool +{ +public: + + //! Creates new unitialized overlap tool. + BRepExtrema_OverlapTool(); + + //! Creates new overlap tool for the given element sets. + BRepExtrema_OverlapTool (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2); + +public: + + //! Loads the given element sets into the overlap tool. + void LoadTriangleSets (const Handle(BRepExtrema_TriangleSet)& theSet1, + const Handle(BRepExtrema_TriangleSet)& theSet2); + + //! Performs searching of overlapped mesh elements. + void Perform (const Standard_Real theTolerance = 0.0); + + //! Is overlap test completed? + Standard_Boolean IsDone() const { return myIsDone; } + + //! Marks test results as outdated. + void MarkDirty() { myIsDone = Standard_False; } + + //! Returns set of overlapped sub-shapes of 1st shape (currently only faces are detected). + const BRepExtrema_MapOfIntegerPackedMapOfInteger& OverlapSubShapes1() const { return myOverlapSubShapes1; } + + //! Returns set of overlapped sub-shapes of 2nd shape (currently only faces are detected). + const BRepExtrema_MapOfIntegerPackedMapOfInteger& OverlapSubShapes2() const { return myOverlapSubShapes2; } + +#ifdef OVERLAP_TOOL_OUTPUT_TRIANGLES + //! Returns set of overlapped triangles from the 1st shape (for debug). + const TColStd_PackedMapOfInteger& OverlapTriangles1() const { return myOverlapTriangles1; } + + //! Returns set of overlapped triangles from the 2nd shape (for debug). + const TColStd_PackedMapOfInteger& OverlapTriangles2() const { return myOverlapTriangles2; } +#endif + + //! Sets filtering tool for preliminary checking pairs of mesh elements. + void SetElementFilter (BRepExtrema_ElementFilter* theFilter) { myFilter = theFilter; } + +protected: + + //! Performs narrow-phase of overlap test (exact intersection). + void intersectTriangleRangesExact (const BVH_Vec4i& theLeaf1, + const BVH_Vec4i& theLeaf2); + + //! Performs narrow-phase of overlap test (intersection with non-zero tolerance). + void intersectTriangleRangesToler (const BVH_Vec4i& theLeaf1, + const BVH_Vec4i& theLeaf2, + const Standard_Real theToler); + +private: + + //! Set of all mesh elements (triangles) of the 1st shape. + Handle(BRepExtrema_TriangleSet) mySet1; + //! Set of all mesh elements (triangles) of the 2nd shape. + Handle(BRepExtrema_TriangleSet) mySet2; + + //! Filter for preliminary checking pairs of mesh elements. + BRepExtrema_ElementFilter* myFilter; + + //! Resulted set of overlapped sub-shapes of 1st shape (only faces). + BRepExtrema_MapOfIntegerPackedMapOfInteger myOverlapSubShapes1; + //! Resulted set of overlapped sub-shapes of 2nd shape (only faces). + BRepExtrema_MapOfIntegerPackedMapOfInteger myOverlapSubShapes2; + +#ifdef OVERLAP_TOOL_OUTPUT_TRIANGLES + //! Set of overlapped elements from the 1st shape (only triangles). + TColStd_PackedMapOfInteger myOverlapTriangles1; + //! Set of overlapped elements from the 2nd shape (only triangles). + TColStd_PackedMapOfInteger myOverlapTriangles2; +#endif + + //! Is overlap test test completed? + Standard_Boolean myIsDone; +}; + +#endif // _BRepExtrema_OverlapTool_HeaderFile diff --git a/src/BRepExtrema/BRepExtrema_SelfIntersection.cxx b/src/BRepExtrema/BRepExtrema_SelfIntersection.cxx new file mode 100644 index 0000000000..1f99c205e6 --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_SelfIntersection.cxx @@ -0,0 +1,312 @@ +// Created on: 2015-04-26 +// Created by: Denis BOGOLEPOV +// Copyright (c) 2014 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#include + +#include +#include + +//======================================================================= +//function : BRepExtrema_SelfIntersection +//purpose : +//======================================================================= +BRepExtrema_SelfIntersection::BRepExtrema_SelfIntersection (const Standard_Real theTolerance) +: myTolerance (theTolerance) +{ + myIsInit = Standard_False; +} + +//======================================================================= +//function : BRepExtrema_SelfIntersection +//purpose : +//======================================================================= +BRepExtrema_SelfIntersection::BRepExtrema_SelfIntersection (const TopoDS_Shape& theShape, const Standard_Real theTolerance) +: myTolerance (theTolerance) +{ + LoadShape (theShape); +} + +//======================================================================= +//function : LoadShape +//purpose : +//======================================================================= +Standard_Boolean BRepExtrema_SelfIntersection::LoadShape (const TopoDS_Shape& theShape) +{ + myFaceList.Clear(); + + for (TopExp_Explorer anIter (theShape, TopAbs_FACE); anIter.More(); anIter.Next()) + { + myFaceList.Append (static_cast (anIter.Current())); + } + + if (myElementSet.IsNull()) + { + myElementSet = new BRepExtrema_TriangleSet; + } + + myIsInit = myElementSet->Init (myFaceList); + + if (myIsInit) + { + myOverlapTool.LoadTriangleSets (myElementSet, + myElementSet); + } + + return myIsInit; +} + +#define ZERO_VEC BVH_Vec3d (0.0, 0.0, 0.0) + +namespace +{ + // ======================================================================= + // function : ccw + // purpose : Check if triple is in counterclockwise order + // ======================================================================= + Standard_Boolean ccw (const BVH_Vec3d& theVertex0, + const BVH_Vec3d& theVertex1, + const BVH_Vec3d& theVertex2, + const Standard_Integer theX, + const Standard_Integer theY) +{ + const Standard_Real aSum = + (theVertex1[theX] - theVertex0[theX]) * (theVertex1[theY] + theVertex0[theY]) + + (theVertex2[theX] - theVertex1[theX]) * (theVertex2[theY] + theVertex1[theY]) + + (theVertex0[theX] - theVertex2[theX]) * (theVertex0[theY] + theVertex2[theY]); + + return aSum < 0.0; +} + + // ======================================================================= + // function : rayInsideAngle + // purpose : Check the given ray is inside the angle + // ======================================================================= + Standard_Boolean rayInsideAngle (const BVH_Vec3d& theDirec, + const BVH_Vec3d& theEdge0, + const BVH_Vec3d& theEdge1, + const Standard_Integer theX, + const Standard_Integer theY) +{ + const Standard_Boolean aCCW = ccw (ZERO_VEC, theEdge0, theEdge1, theX, theY); + + return ccw (ZERO_VEC, theEdge0, theDirec, theX, theY) == aCCW + && ccw (ZERO_VEC, theDirec, theEdge1, theX, theY) == aCCW; +} + + // ======================================================================= + // function : getProjectionAxes + // purpose : + // ======================================================================= + void getProjectionAxes (const BVH_Vec3d& theNorm, + Standard_Integer& theAxisX, + Standard_Integer& theAxisY) +{ + if (fabs (theNorm[0]) > fabs (theNorm[1])) + { + theAxisX = fabs (theNorm[0]) > fabs (theNorm[2]) ? 1 : 0; + theAxisY = fabs (theNorm[0]) > fabs (theNorm[2]) ? 2 : 1; + } + else + { + theAxisX = fabs (theNorm[1]) > fabs (theNorm[2]) ? 0 : 0; + theAxisY = fabs (theNorm[1]) > fabs (theNorm[2]) ? 2 : 1; + } +} +} + +//======================================================================= +//function : isRegularSharedVertex +//purpose : +//======================================================================= +BRepExtrema_ElementFilter::FilterResult BRepExtrema_SelfIntersection::isRegularSharedVertex (const BVH_Vec3d& theSharedVert, + const BVH_Vec3d& theTrng0Vtxs1, + const BVH_Vec3d& theTrng0Vtxs2, + const BVH_Vec3d& theTrng1Vtxs1, + const BVH_Vec3d& theTrng1Vtxs2) +{ + const BVH_Vec3d aTrng0Edges[] = { (theTrng0Vtxs1 - theSharedVert).Normalized(), + (theTrng0Vtxs2 - theSharedVert).Normalized() }; + + const BVH_Vec3d aTrng1Edges[] = { (theTrng1Vtxs1 - theSharedVert).Normalized(), + (theTrng1Vtxs2 - theSharedVert).Normalized() }; + + const BVH_Vec3d aTrng0Normal = BVH_Vec3d::Cross (aTrng0Edges[0], aTrng0Edges[1]); + const BVH_Vec3d aTrng1Normal = BVH_Vec3d::Cross (aTrng1Edges[0], aTrng1Edges[1]); + + BVH_Vec3d aCrossLine = BVH_Vec3d::Cross (aTrng0Normal, + aTrng1Normal); + + Standard_Integer anX; + Standard_Integer anY; + + if (aCrossLine.SquareModulus() < Precision::SquareConfusion()) // coplanar case + { + getProjectionAxes (aTrng0Normal, anX, anY); + + if (rayInsideAngle (aTrng1Edges[0], aTrng0Edges[0], aTrng0Edges[1], anX, anY) + || rayInsideAngle (aTrng1Edges[1], aTrng0Edges[0], aTrng0Edges[1], anX, anY) + || rayInsideAngle (aTrng0Edges[0], aTrng1Edges[0], aTrng1Edges[1], anX, anY) + || rayInsideAngle (aTrng0Edges[1], aTrng1Edges[0], aTrng1Edges[1], anX, anY)) + { + return BRepExtrema_ElementFilter::Overlap; + } + + return BRepExtrema_ElementFilter::NoCheck; + } + else // shared line should lie outside at least one triangle + { + getProjectionAxes (aTrng0Normal, anX, anY); + + const Standard_Boolean aPosOutTrgn0 = !rayInsideAngle ( aCrossLine, aTrng0Edges[0], aTrng0Edges[1], anX, anY); + const Standard_Boolean aNegOutTrgn0 = !rayInsideAngle (-aCrossLine, aTrng0Edges[0], aTrng0Edges[1], anX, anY); + + Standard_ASSERT_RAISE (aPosOutTrgn0 || aNegOutTrgn0, + "Failed to detect if shared vertex is regular or not"); + + if (aPosOutTrgn0 && aNegOutTrgn0) + { + return BRepExtrema_ElementFilter::NoCheck; + } + + getProjectionAxes (aTrng1Normal, anX, anY); + + const Standard_Boolean aPosOutTrgn1 = !rayInsideAngle ( aCrossLine, aTrng1Edges[0], aTrng1Edges[1], anX, anY); + const Standard_Boolean aNegOutTrgn1 = !rayInsideAngle (-aCrossLine, aTrng1Edges[0], aTrng1Edges[1], anX, anY); + + Standard_ASSERT_RAISE (aPosOutTrgn1 || aNegOutTrgn1, + "Failed to detect if shared vertex is regular or not"); + + if (aPosOutTrgn1 && aNegOutTrgn1) + { + return BRepExtrema_ElementFilter::NoCheck; + } + + return (aPosOutTrgn0 || aPosOutTrgn1) && (aNegOutTrgn0 || aNegOutTrgn1) ? + BRepExtrema_ElementFilter::NoCheck : BRepExtrema_ElementFilter::Overlap; + } +} + +//======================================================================= +//function : isRegularSharedEdge +//purpose : +//======================================================================= +BRepExtrema_ElementFilter::FilterResult BRepExtrema_SelfIntersection::isRegularSharedEdge (const BVH_Vec3d& theTrng0Vtxs0, + const BVH_Vec3d& theTrng0Vtxs1, + const BVH_Vec3d& theTrng0Vtxs2, + const BVH_Vec3d& theTrng1Vtxs2) +{ + const BVH_Vec3d aSharedEdge = (theTrng0Vtxs1 - theTrng0Vtxs0).Normalized(); + + const BVH_Vec3d aUniqueEdges[] = { (theTrng0Vtxs2 - theTrng0Vtxs0).Normalized(), + (theTrng1Vtxs2 - theTrng0Vtxs0).Normalized() }; + + const BVH_Vec3d aTrng0Normal = BVH_Vec3d::Cross (aSharedEdge, aUniqueEdges[0]); + const BVH_Vec3d aTrng1Normal = BVH_Vec3d::Cross (aSharedEdge, aUniqueEdges[1]); + + BVH_Vec3d aCrossLine = BVH_Vec3d::Cross (aTrng0Normal, + aTrng1Normal); + + if (aCrossLine.SquareModulus() > Precision::SquareConfusion()) // non-coplanar case + { + return BRepExtrema_ElementFilter::NoCheck; + } + + Standard_Integer anX; + Standard_Integer anY; + + getProjectionAxes (aTrng0Normal, anX, anY); + + return ccw (ZERO_VEC, aSharedEdge, aUniqueEdges[0], anX, anY) != + ccw (ZERO_VEC, aSharedEdge, aUniqueEdges[1], anX, anY) ? BRepExtrema_ElementFilter::NoCheck + : BRepExtrema_ElementFilter::Overlap; +} + +//======================================================================= +//function : PreCheckElements +//purpose : +//======================================================================= +BRepExtrema_ElementFilter::FilterResult BRepExtrema_SelfIntersection::PreCheckElements (const Standard_Integer theIndex1, + const Standard_Integer theIndex2) +{ + if (myElementSet->GetFaceID (theIndex1) == myElementSet->GetFaceID (theIndex2)) + { + return BRepExtrema_ElementFilter::NoCheck; // triangles are from the same face + } + + BVH_Vec3d aTrng0Vtxs[3]; + BVH_Vec3d aTrng1Vtxs[3]; + + myElementSet->GetVertices (theIndex1, + aTrng0Vtxs[0], + aTrng0Vtxs[1], + aTrng0Vtxs[2]); + + myElementSet->GetVertices (theIndex2, + aTrng1Vtxs[0], + aTrng1Vtxs[1], + aTrng1Vtxs[2]); + + std::vector > aSharedVtxs; + + for (Standard_Integer aVertIdx1 = 0; aVertIdx1 < 3; ++aVertIdx1) + { + for (Standard_Integer aVertIdx2 = 0; aVertIdx2 < 3; ++aVertIdx2) + { + if ((aTrng0Vtxs[aVertIdx1] - aTrng1Vtxs[aVertIdx2]).SquareModulus() < Precision::SquareConfusion()) + { + aSharedVtxs.push_back (std::pair (aVertIdx1, aVertIdx2)); + + break; // go to next vertex of the 1st triangle + } + } + } + + if (aSharedVtxs.size() == 2) // check shared edge + { + return isRegularSharedEdge (aTrng0Vtxs[aSharedVtxs[0].first], + aTrng0Vtxs[aSharedVtxs[1].first], + aTrng0Vtxs[3 - aSharedVtxs[0]. first - aSharedVtxs[1]. first], + aTrng1Vtxs[3 - aSharedVtxs[0].second - aSharedVtxs[1].second]); + } + else if (aSharedVtxs.size() == 1) // check shared vertex + { + std::swap (*aTrng0Vtxs, aTrng0Vtxs[aSharedVtxs.front(). first]); + std::swap (*aTrng1Vtxs, aTrng1Vtxs[aSharedVtxs.front().second]); + + return isRegularSharedVertex (aTrng0Vtxs[0], + aTrng0Vtxs[1], + aTrng0Vtxs[2], + aTrng1Vtxs[1], + aTrng1Vtxs[2]); + } + + return BRepExtrema_ElementFilter::DoCheck; +} + +//======================================================================= +//function : Perform +//purpose : +//======================================================================= +void BRepExtrema_SelfIntersection::Perform() +{ + if (!myIsInit || myOverlapTool.IsDone()) + { + return; + } + + myOverlapTool.SetElementFilter (this); + + myOverlapTool.Perform (myTolerance); +} diff --git a/src/BRepExtrema/BRepExtrema_SelfIntersection.hxx b/src/BRepExtrema/BRepExtrema_SelfIntersection.hxx new file mode 100644 index 0000000000..b1cd1d98f7 --- /dev/null +++ b/src/BRepExtrema/BRepExtrema_SelfIntersection.hxx @@ -0,0 +1,134 @@ +// Created on: 2015-04-26 +// Created by: Denis BOGOLEPOV +// Copyright (c) 2015 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _BRepExtrema_SelfIntersection_HeaderFile +#define _BRepExtrema_SelfIntersection_HeaderFile + +#include + +//! Tool class for detection of self-sections in the given shape. +//! This class is based on BRepExtrema_OverlapTool and thus uses +//! shape tessellation to detect incorrect mesh fragments (pairs +//! of overlapped triangles belonging to different faces). Thus, +//! a result depends critically on the quality of mesh generator +//! (e.g., BREP mesh is not always a good choice, because it can +//! contain gaps between adjacent face triangulations, which may +//! not share vertices on common edge; thus false overlap can be +//! detected). As a result, this tool can be used for relatively +//! fast approximated test which provides sub-set of potentially +//! overlapped faces. +class BRepExtrema_SelfIntersection : public BRepExtrema_ElementFilter +{ + friend class BRepExtrema_OverlapTool; + +public: + + //! Creates unitialized self-intersection tool. + Standard_EXPORT BRepExtrema_SelfIntersection (const Standard_Real theTolerance = 0.0); + + //! Creates self-intersection tool for the given shape. + Standard_EXPORT BRepExtrema_SelfIntersection (const TopoDS_Shape& theShape, const Standard_Real theTolerance = 0.0); + +public: + + //! Returns tolerance value used for self-intersection test. + Standard_Real Tolerance() const + { + return myTolerance; + } + + //! Sets tolerance value used for self-intersection test. + void SetTolerance (const Standard_Real theTolerance) + { + myTolerance = theTolerance; + } + + //! Loads shape for detection of self-intersections. + Standard_EXPORT Standard_Boolean LoadShape (const TopoDS_Shape& theShape); + + //! Performs detection of self-intersections. + Standard_EXPORT void Perform(); + + //! True if the detection is completed. + Standard_Boolean IsDone() const + { + return myOverlapTool.IsDone(); + } + + //! Returns set of IDs of overlapped sub-shapes (started from 0). + const BRepExtrema_MapOfIntegerPackedMapOfInteger& OverlapElements() const + { + return myOverlapTool.OverlapSubShapes1(); + } + + //! Returns sub-shape from the shape for the given index (started from 0). + const TopoDS_Face& GetSubShape (const Standard_Integer theID) const + { + return myFaceList.Value (theID); + } + + //! Returns set of all the face triangles of the shape. + const Handle(BRepExtrema_TriangleSet)& ElementSet() const + { + return myElementSet; + } + +#ifdef OVERLAP_TOOL_OUTPUT_TRIANGLES + //! Returns set of overlapped mesh elements (only triangles). + const TColStd_PackedMapOfInteger& OverlapTriangles() const + { + return myOverlapTool.OverlapTriangles1(); + } +#endif + +protected: + + //! Filter out correct adjacent mesh elements. + virtual BRepExtrema_ElementFilter::FilterResult PreCheckElements (const Standard_Integer theIndex1, + const Standard_Integer theIndex2); + + //! Checks if the given triangles have only single common vertex. + BRepExtrema_ElementFilter::FilterResult isRegularSharedVertex (const BVH_Vec3d& theSharedVert, + const BVH_Vec3d& theTrng1Vtxs1, + const BVH_Vec3d& theTrng1Vtxs2, + const BVH_Vec3d& theTrng2Vtxs1, + const BVH_Vec3d& theTrng2Vtxs2); + + //! Checks if the given triangles have only single common edge. + BRepExtrema_ElementFilter::FilterResult isRegularSharedEdge (const BVH_Vec3d& theTrng1Vtxs0, + const BVH_Vec3d& theTrng1Vtxs1, + const BVH_Vec3d& theTrng1Vtxs2, + const BVH_Vec3d& theTrng2Vtxs2); + +private: + + //! Self-intersection tolerance. + Standard_Real myTolerance; + + //! Is the input shape inited? + Standard_Boolean myIsInit; + + //! List of triangulated faces of the shape. + BRepExtrema_ShapeList myFaceList; + + //! Set of all the face triangles of the shape. + Handle(BRepExtrema_TriangleSet) myElementSet; + + //! Overlap tool used for self-intersection test. + BRepExtrema_OverlapTool myOverlapTool; + +}; + +#endif // _BRepExtrema_SelfIntersection_HeaderFile diff --git a/src/BRepExtrema/BRepExtrema_ShapeProximity.cxx b/src/BRepExtrema/BRepExtrema_ShapeProximity.cxx index fb2774875c..65b2e69589 100644 --- a/src/BRepExtrema/BRepExtrema_ShapeProximity.cxx +++ b/src/BRepExtrema/BRepExtrema_ShapeProximity.cxx @@ -20,15 +20,15 @@ //======================================================================= //function : BRepExtrema_ShapeProximity -//purpose : Creates empty proximity tool +//purpose : Creates uninitialized proximity tool //======================================================================= BRepExtrema_ShapeProximity::BRepExtrema_ShapeProximity (const Standard_Real theTolerance) -: myTolerance (theTolerance), - myPrimitiveSet1 (new BRepExtrema_TriangleSet), - myPrimitiveSet2 (new BRepExtrema_TriangleSet) +: myTolerance (theTolerance), + myElementSet1 (new BRepExtrema_TriangleSet), + myElementSet2 (new BRepExtrema_TriangleSet) { // Should be initialized later - myIsDone = myIsInitS1 = myIsInitS2 = Standard_False; + myIsInitS1 = myIsInitS2 = Standard_False; } //======================================================================= @@ -38,9 +38,9 @@ BRepExtrema_ShapeProximity::BRepExtrema_ShapeProximity (const Standard_Real theT BRepExtrema_ShapeProximity::BRepExtrema_ShapeProximity (const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2, const Standard_Real theTolerance) -: myTolerance (theTolerance), - myPrimitiveSet1 (new BRepExtrema_TriangleSet), - myPrimitiveSet2 (new BRepExtrema_TriangleSet) +: myTolerance (theTolerance), + myElementSet1 (new BRepExtrema_TriangleSet), + myElementSet2 (new BRepExtrema_TriangleSet) { LoadShape1 (theShape1); LoadShape2 (theShape2); @@ -59,9 +59,9 @@ Standard_Boolean BRepExtrema_ShapeProximity::LoadShape1 (const TopoDS_Shape& the myFaceList1.Append (static_cast (anIter.Current())); } - myIsDone = Standard_False; + myOverlapTool.MarkDirty(); - return myIsInitS1 = myPrimitiveSet1->Init (myFaceList1); + return myIsInitS1 = myElementSet1->Init (myFaceList1); } //======================================================================= @@ -77,569 +77,24 @@ Standard_Boolean BRepExtrema_ShapeProximity::LoadShape2 (const TopoDS_Shape& the myFaceList2.Append (static_cast (anIter.Current())); } - myIsDone = Standard_False; + myOverlapTool.MarkDirty(); - return myIsInitS2 = myPrimitiveSet2->Init (myFaceList2); -} - -namespace -{ - //! Tool class to describe stack item in traverse function. - struct BRepExtrema_StackItem - { - Standard_Integer Node1; - Standard_Integer Node2; - - BRepExtrema_StackItem (const Standard_Integer theNode1 = 0, - const Standard_Integer theNode2 = 0) - : Node1 (theNode1), - Node2 (theNode2) - { - // - } - }; - - //! Bounding triangular prism for specified triangle. - class BRepExtrema_BoundingPrism - { - public: - - //! Vertices of the prism. - BVH_Vec3d Vertices[6]; - - //! Edges of the prism. - BVH_Vec3d Edges[3]; - - //! Normal to prism caps. - BVH_Vec3d Normal; - - //! Normals to prism edges. - BVH_Vec3d EdgeNormals[3]; - - //! Is prism initialized? - Standard_Boolean IsInited; - - public: - - //! Creates uninitialized bounding prism. - BRepExtrema_BoundingPrism() : IsInited (Standard_False) - { - // - } - - //! Creates new bounding prism for the given triangle. - BRepExtrema_BoundingPrism (const BVH_Vec3d& theVertex0, - const BVH_Vec3d& theVertex1, - const BVH_Vec3d& theVertex2, - const Standard_Real theDeflect) - { - Init (theVertex0, - theVertex1, - theVertex2, - theDeflect); - } - - //! Calculates bounding prism for the given triangle. - void Init (const BVH_Vec3d& theVertex0, - const BVH_Vec3d& theVertex1, - const BVH_Vec3d& theVertex2, - const Standard_Real theDeflect) - { - Edges[0] = theVertex1 - theVertex0; - Edges[1] = theVertex2 - theVertex0; - Edges[2] = theVertex2 - theVertex1; - - Normal = BVH_Vec3d::Cross (Edges[0], Edges[1]); - - EdgeNormals[0] = BVH_Vec3d::Cross (Edges[0], Normal); - EdgeNormals[1] = BVH_Vec3d::Cross (Edges[1], Normal); - EdgeNormals[2] = BVH_Vec3d::Cross (Edges[2], Normal); - - EdgeNormals[0] *= 1.0 / Max (EdgeNormals[0].Modulus(), Precision::Confusion()); - EdgeNormals[1] *= 1.0 / Max (EdgeNormals[1].Modulus(), Precision::Confusion()); - EdgeNormals[2] *= 1.0 / Max (EdgeNormals[2].Modulus(), Precision::Confusion()); - - const BVH_Vec3d aDirect01 = EdgeNormals[0] - EdgeNormals[1]; - const BVH_Vec3d aDirect02 = EdgeNormals[0] + EdgeNormals[2]; - const BVH_Vec3d aDirect12 = EdgeNormals[2] - EdgeNormals[1]; - - Vertices[0] = Vertices[3] = theVertex0 + aDirect01 * (theDeflect / aDirect01.Dot (EdgeNormals[0])); - Vertices[1] = Vertices[4] = theVertex1 + aDirect02 * (theDeflect / aDirect02.Dot (EdgeNormals[2])); - Vertices[2] = Vertices[5] = theVertex2 + aDirect12 * (theDeflect / aDirect12.Dot (EdgeNormals[2])); - - const BVH_Vec3d aNormOffset = Normal * (theDeflect / Max (Normal.Modulus(), Precision::Confusion())); - - for (Standard_Integer aVertIdx = 0; aVertIdx < 3; ++aVertIdx) - { - Vertices[aVertIdx + 0] += aNormOffset; - Vertices[aVertIdx + 3] -= aNormOffset; - } - - IsInited = Standard_True; - } - - //! Checks if two prisms are separated along the given axis. - Standard_Boolean Separated (const BRepExtrema_BoundingPrism& thePrism, const BVH_Vec3d& theAxis) const - { - Standard_Real aMin1 = DBL_MAX; - Standard_Real aMax1 = -DBL_MAX; - - Standard_Real aMin2 = DBL_MAX; - Standard_Real aMax2 = -DBL_MAX; - - for (Standard_Integer aVertIdx = 0; aVertIdx < 6; ++aVertIdx) - { - const Standard_Real aProj1 = Vertices[aVertIdx].Dot (theAxis); - - aMin1 = Min (aMin1, aProj1); - aMax1 = Max (aMax1, aProj1); - - const Standard_Real aProj2 = thePrism.Vertices[aVertIdx].Dot (theAxis); - - aMin2 = Min (aMin2, aProj2); - aMax2 = Max (aMax2, aProj2); - - if (aMin1 <= aMax2 && aMax1 >= aMin2) - { - return Standard_False; - } - } - - return aMin1 > aMax2 || aMax1 < aMin2; - } - }; - - // ======================================================================= - // function : Separated - // purpose : Checks if triangles can be separated along the given axis - // (projects vertices on this axis and performs interval test) - // ======================================================================= - inline Standard_Boolean SeparateTriangles (const BVH_Vec3d& theTrg1Vert0, - const BVH_Vec3d& theTrg1Vert1, - const BVH_Vec3d& theTrg1Vert2, - const BVH_Vec3d& theTrg2Vert0, - const BVH_Vec3d& theTrg2Vert1, - const BVH_Vec3d& theTrg2Vert2, - const BVH_Vec3d& theSplitAxis) - { - const Standard_Real aA1 = theTrg1Vert0.Dot (theSplitAxis); - const Standard_Real aB1 = theTrg1Vert1.Dot (theSplitAxis); - const Standard_Real aC1 = theTrg1Vert2.Dot (theSplitAxis); - - const Standard_Real aA2 = theTrg2Vert0.Dot (theSplitAxis); - const Standard_Real aB2 = theTrg2Vert1.Dot (theSplitAxis); - const Standard_Real aC2 = theTrg2Vert2.Dot (theSplitAxis); - - const Standard_Real aMin1 = Min (aA1, Min (aB1, aC1)); - const Standard_Real aMax1 = Max (aA1, Max (aB1, aC1)); - - if (aMax1 < Min (aA2, Min (aB2, aC2))) - { - return Standard_True; - } - - return aMin1 > Max (aA2, Max (aB2, aC2)); - } - - // ======================================================================= - // function : TrianglesIntersected - // purpose : Checks if two triangles are intersected - // (test uses SAT - Separating Axis Theorem) - // ======================================================================= - Standard_Boolean TrianglesIntersected (const BVH_Vec3d& theTrg1Vert0, - const BVH_Vec3d& theTrg1Vert1, - const BVH_Vec3d& theTrg1Vert2, - const BVH_Vec3d& theTrg2Vert0, - const BVH_Vec3d& theTrg2Vert1, - const BVH_Vec3d& theTrg2Vert2) - { - const BVH_Vec3d aEdges1[3] = { theTrg1Vert1 - theTrg1Vert0, - theTrg1Vert2 - theTrg1Vert0, - theTrg1Vert2 - theTrg1Vert1 }; - - const BVH_Vec3d aTrg1Normal = BVH_Vec3d::Cross (aEdges1[0], aEdges1[1]); - - if (SeparateTriangles (theTrg1Vert0, - theTrg1Vert1, - theTrg1Vert2, - theTrg2Vert0, - theTrg2Vert1, - theTrg2Vert2, - aTrg1Normal)) - { - return Standard_False; - } - - const BVH_Vec3d aEdges2[3] = { theTrg2Vert1 - theTrg2Vert0, - theTrg2Vert2 - theTrg2Vert0, - theTrg2Vert2 - theTrg2Vert1 }; - - const BVH_Vec3d aTrg2Normal = BVH_Vec3d::Cross (aEdges2[0], aEdges2[1]); - - if (SeparateTriangles (theTrg1Vert0, - theTrg1Vert1, - theTrg1Vert2, - theTrg2Vert0, - theTrg2Vert1, - theTrg2Vert2, - aTrg2Normal)) - { - return Standard_False; - } - - for (Standard_Integer anIdx1 = 0; anIdx1 < 3; ++anIdx1) - { - for (Standard_Integer anIdx2 = 0; anIdx2 < 3; ++anIdx2) - { - const BVH_Vec3d aSplitAxis = BVH_Vec3d::Cross (aEdges1[anIdx1], aEdges2[anIdx2]); - - if (SeparateTriangles (theTrg1Vert0, - theTrg1Vert1, - theTrg1Vert2, - theTrg2Vert0, - theTrg2Vert1, - theTrg2Vert2, - aSplitAxis)) - { - return Standard_False; - } - } - } - - return Standard_True; - } - - // ======================================================================= - // function : PrismsIntersected - // purpose : Checks if two triangular prisms are intersected - // (test uses SAT - Separating Axis Theorem) - // ======================================================================= - Standard_Boolean PrismsIntersected (const BRepExtrema_BoundingPrism& thePrism1, - const BRepExtrema_BoundingPrism& thePrism2) - { - if (thePrism1.Separated (thePrism2, thePrism1.Normal)) - { - return Standard_False; - } - - if (thePrism1.Separated (thePrism2, thePrism2.Normal)) - { - return Standard_False; - } - - for (Standard_Integer anIdx = 0; anIdx < 3; ++anIdx) - { - if (thePrism1.Separated (thePrism2, thePrism1.EdgeNormals[anIdx])) - { - return Standard_False; - } - } - - for (Standard_Integer anIdx = 0; anIdx < 3; ++anIdx) - { - if (thePrism1.Separated (thePrism2, thePrism2.EdgeNormals[anIdx])) - { - return Standard_False; - } - } - - for (Standard_Integer anIdx1 = 0; anIdx1 < 4; ++anIdx1) - { - const BVH_Vec3d& aEdge1 = (anIdx1 == 3) ? thePrism1.Normal : thePrism1.Edges[anIdx1]; - - for (Standard_Integer anIdx2 = 0; anIdx2 < 4; ++anIdx2) - { - const BVH_Vec3d& aEdge2 = (anIdx2 == 3) ? thePrism2.Normal : thePrism2.Edges[anIdx2]; - - if (thePrism1.Separated (thePrism2, BVH_Vec3d::Cross (aEdge1, aEdge2))) - { - return Standard_False; - } - } - } - - return Standard_True; - } - - // ======================================================================= - // function : OverlapBoxes - // purpose : Checks if two boxes (AABBs) are overlapped - // ======================================================================= - inline Standard_Boolean OverlapBoxes (const BVH_Vec3d& theBoxMin1, - const BVH_Vec3d& theBoxMax1, - const BVH_Vec3d& theBoxMin2, - const BVH_Vec3d& theBoxMax2, - const Standard_Real theTolerance) - { - // Check for overlap - return !(theBoxMin1.x() > theBoxMax2.x() + theTolerance || - theBoxMax1.x() < theBoxMin2.x() - theTolerance || - theBoxMin1.y() > theBoxMax2.y() + theTolerance || - theBoxMax1.y() < theBoxMin2.y() - theTolerance || - theBoxMin1.z() > theBoxMax2.z() + theTolerance || - theBoxMax1.z() < theBoxMin2.z() - theTolerance); - } - - //======================================================================= - //function : getSetOfFaces - //purpose : - //======================================================================= - TColStd_PackedMapOfInteger& getSetOfFaces (BRepExtrema_OverlappedSubShapes& theShapes, - const Standard_Integer theFaceIdx) - { - if (!theShapes.IsBound (theFaceIdx)) - { - theShapes.Bind (theFaceIdx, TColStd_PackedMapOfInteger()); - } - - return theShapes.ChangeFind (theFaceIdx); - } -} - -//======================================================================= -//function : IntersectLeavesExact -//purpose : Narrow-phase of overlap test (exact intersection) -//======================================================================= -void BRepExtrema_ShapeProximity::IntersectLeavesExact (const BVH_Vec4i& theLeaf1, - const BVH_Vec4i& theLeaf2) -{ - for (Standard_Integer aTrgIdx1 = theLeaf1.y(); aTrgIdx1 <= theLeaf1.z(); ++aTrgIdx1) - { - const Standard_Integer aFaceIdx1 = myPrimitiveSet1->GetFaceID (aTrgIdx1); - - BVH_Vec3d aTrg1Vert1; - BVH_Vec3d aTrg1Vert2; - BVH_Vec3d aTrg1Vert3; - - myPrimitiveSet1->GetVertices (aTrgIdx1, - aTrg1Vert1, - aTrg1Vert2, - aTrg1Vert3); - - const Standard_Boolean aIsInSet = myOverlapSubShapes1.IsBound (aFaceIdx1); - - for (Standard_Integer aTrgIdx2 = theLeaf2.y(); aTrgIdx2 <= theLeaf2.z(); ++aTrgIdx2) - { - const Standard_Integer aFaceIdx2 = myPrimitiveSet2->GetFaceID (aTrgIdx2); - - if (!aIsInSet || !myOverlapSubShapes1.Find (aFaceIdx1).Contains (aFaceIdx2)) - { - BVH_Vec3d aTrg2Vert1; - BVH_Vec3d aTrg2Vert2; - BVH_Vec3d aTrg2Vert3; - - myPrimitiveSet2->GetVertices (aTrgIdx2, aTrg2Vert1, aTrg2Vert2, aTrg2Vert3); - - if (TrianglesIntersected (aTrg1Vert1, - aTrg1Vert2, - aTrg1Vert3, - aTrg2Vert1, - aTrg2Vert2, - aTrg2Vert3)) - { - getSetOfFaces (myOverlapSubShapes1, aFaceIdx1).Add (aFaceIdx2); - getSetOfFaces (myOverlapSubShapes2, aFaceIdx2).Add (aFaceIdx1); - } - } - } - } -} - -//======================================================================= -//function : IntersectLeavesToler -//purpose : Narrow-phase of overlap test (with non-zero tolerance) -//======================================================================= -void BRepExtrema_ShapeProximity::IntersectLeavesToler (const BVH_Vec4i& theLeaf1, - const BVH_Vec4i& theLeaf2) -{ - for (Standard_Integer aTrgIdx1 = theLeaf1.y(); aTrgIdx1 <= theLeaf1.z(); ++aTrgIdx1) - { - const Standard_Integer aFaceIdx1 = myPrimitiveSet1->GetFaceID (aTrgIdx1); - - BVH_Vec3d aTrg1Vert1; - BVH_Vec3d aTrg1Vert2; - BVH_Vec3d aTrg1Vert3; - - myPrimitiveSet1->GetVertices (aTrgIdx1, - aTrg1Vert1, - aTrg1Vert2, - aTrg1Vert3); - - BRepExtrema_BoundingPrism aPrism1; // not initialized - - const Standard_Boolean aIsInSet = myOverlapSubShapes1.IsBound (aFaceIdx1); - - for (Standard_Integer aTrgIdx2 = theLeaf2.y(); aTrgIdx2 <= theLeaf2.z(); ++aTrgIdx2) - { - const Standard_Integer aFaceIdx2 = myPrimitiveSet2->GetFaceID (aTrgIdx2); - - if (!aIsInSet || !myOverlapSubShapes1.Find (aFaceIdx1).Contains (aFaceIdx2)) - { - if (!aPrism1.IsInited) - { - aPrism1.Init (aTrg1Vert1, aTrg1Vert2, aTrg1Vert3, myTolerance); - } - - BVH_Vec3d aTrg2Vert1; - BVH_Vec3d aTrg2Vert2; - BVH_Vec3d aTrg2Vert3; - - myPrimitiveSet2->GetVertices (aTrgIdx2, - aTrg2Vert1, - aTrg2Vert2, - aTrg2Vert3); - - BRepExtrema_BoundingPrism aPrism2 (aTrg2Vert1, - aTrg2Vert2, - aTrg2Vert3, - myTolerance); - - if (PrismsIntersected (aPrism1, aPrism2)) - { - getSetOfFaces (myOverlapSubShapes1, aFaceIdx1).Add (aFaceIdx2); - getSetOfFaces (myOverlapSubShapes2, aFaceIdx2).Add (aFaceIdx1); - } - } - } - } + return myIsInitS2 = myElementSet2->Init (myFaceList2); } //======================================================================= //function : Perform -//purpose : Performs search for overlapped faces +//purpose : Performs search of overlapped faces //======================================================================= void BRepExtrema_ShapeProximity::Perform() { - if (myIsDone || !myIsInitS1 || !myIsInitS2) + if (!myIsInitS1 || !myIsInitS2 || myOverlapTool.IsDone()) { return; } - BRepExtrema_StackItem aStack[96]; + myOverlapTool.LoadTriangleSets (myElementSet1, + myElementSet2); - const NCollection_Handle >& aBVH1 = myPrimitiveSet1->BVH(); - const NCollection_Handle >& aBVH2 = myPrimitiveSet2->BVH(); - - if (aBVH1.IsNull() || aBVH2.IsNull()) - { - return; - } - - BRepExtrema_StackItem aNodes; // current pair of nodes - - Standard_Integer aHead = -1; // stack head position - - for (;;) - { - BVH_Vec4i aNodeData1 = aBVH1->NodeInfoBuffer()[aNodes.Node1]; - BVH_Vec4i aNodeData2 = aBVH2->NodeInfoBuffer()[aNodes.Node2]; - - if (aNodeData1.x() != 0 && aNodeData2.x() != 0) // leaves - { - if (myTolerance == 0.0) - { - IntersectLeavesExact (aNodeData1, aNodeData2); - } - else - { - IntersectLeavesToler (aNodeData1, aNodeData2); - } - - if (aHead < 0) - break; - - aNodes = aStack[aHead--]; - } - else - { - BRepExtrema_StackItem aPairsToProcess[4]; - - Standard_Integer aNbPairs = 0; - - if (aNodeData1.x() == 0) // inner node - { - const BVH_Vec3d& aMinPntLft1 = aBVH1->MinPoint (aNodeData1.y()); - const BVH_Vec3d& aMaxPntLft1 = aBVH1->MaxPoint (aNodeData1.y()); - const BVH_Vec3d& aMinPntRgh1 = aBVH1->MinPoint (aNodeData1.z()); - const BVH_Vec3d& aMaxPntRgh1 = aBVH1->MaxPoint (aNodeData1.z()); - - if (aNodeData2.x() == 0) // inner node - { - const BVH_Vec3d& aMinPntLft2 = aBVH2->MinPoint (aNodeData2.y()); - const BVH_Vec3d& aMaxPntLft2 = aBVH2->MaxPoint (aNodeData2.y()); - const BVH_Vec3d& aMinPntRgh2 = aBVH2->MinPoint (aNodeData2.z()); - const BVH_Vec3d& aMaxPntRgh2 = aBVH2->MaxPoint (aNodeData2.z()); - - if (OverlapBoxes (aMinPntLft1, aMaxPntLft1, aMinPntLft2, aMaxPntLft2, myTolerance)) - { - aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.y(), aNodeData2.y()); - } - if (OverlapBoxes (aMinPntLft1, aMaxPntLft1, aMinPntRgh2, aMaxPntRgh2, myTolerance)) - { - aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.y(), aNodeData2.z()); - } - if (OverlapBoxes (aMinPntRgh1, aMaxPntRgh1, aMinPntLft2, aMaxPntLft2, myTolerance)) - { - aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.z(), aNodeData2.y()); - } - if (OverlapBoxes (aMinPntRgh1, aMaxPntRgh1, aMinPntRgh2, aMaxPntRgh2, myTolerance)) - { - aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.z(), aNodeData2.z()); - } - } - else - { - const BVH_Vec3d& aMinPntLeaf = aBVH2->MinPoint (aNodes.Node2); - const BVH_Vec3d& aMaxPntLeaf = aBVH2->MaxPoint (aNodes.Node2); - - if (OverlapBoxes (aMinPntLft1, aMaxPntLft1, aMinPntLeaf, aMaxPntLeaf, myTolerance)) - { - aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.y(), aNodes.Node2); - } - if (OverlapBoxes (aMinPntRgh1, aMaxPntRgh1, aMinPntLeaf, aMaxPntLeaf, myTolerance)) - { - aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodeData1.z(), aNodes.Node2); - } - } - } - else - { - const BVH_Vec3d& aMinPntLeaf = aBVH1->MinPoint (aNodes.Node1); - const BVH_Vec3d& aMaxPntLeaf = aBVH1->MaxPoint (aNodes.Node1); - - const BVH_Vec3d& aMinPntLft2 = aBVH2->MinPoint (aNodeData2.y()); - const BVH_Vec3d& aMaxPntLft2 = aBVH2->MaxPoint (aNodeData2.y()); - const BVH_Vec3d& aMinPntRgh2 = aBVH2->MinPoint (aNodeData2.z()); - const BVH_Vec3d& aMaxPntRgh2 = aBVH2->MaxPoint (aNodeData2.z()); - - if (OverlapBoxes (aMinPntLft2, aMaxPntLft2, aMinPntLeaf, aMaxPntLeaf, myTolerance)) - { - aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodes.Node1, aNodeData2.y()); - } - if (OverlapBoxes (aMinPntRgh2, aMaxPntRgh2, aMinPntLeaf, aMaxPntLeaf, myTolerance)) - { - aPairsToProcess[aNbPairs++] = BRepExtrema_StackItem (aNodes.Node1, aNodeData2.z()); - } - } - - if (aNbPairs > 0) - { - aNodes = aPairsToProcess[0]; - - for (Standard_Integer anIdx = 1; anIdx < aNbPairs; ++anIdx) - { - aStack[++aHead] = aPairsToProcess[anIdx]; - } - } - else - { - if (aHead < 0) - break; - - aNodes = aStack[aHead--]; - } - } - } - - myIsDone = Standard_True; + myOverlapTool.Perform (myTolerance); } diff --git a/src/BRepExtrema/BRepExtrema_ShapeProximity.hxx b/src/BRepExtrema/BRepExtrema_ShapeProximity.hxx index ef349c266a..0cdb4aba76 100644 --- a/src/BRepExtrema/BRepExtrema_ShapeProximity.hxx +++ b/src/BRepExtrema/BRepExtrema_ShapeProximity.hxx @@ -17,12 +17,11 @@ #define _BRepExtrema_ShapeProximity_HeaderFile #include -#include -#include #include +#include -//! Set of overlapped sub-shapes. -typedef NCollection_DataMap BRepExtrema_OverlappedSubShapes; +#include +#include //! Tool class for shape proximity detection. //! For two given shapes and given tolerance (offset from the mesh) the algorithm allows @@ -38,7 +37,7 @@ typedef NCollection_DataMap BRepE //! on distance less than the given tolerance from each other. class BRepExtrema_ShapeProximity { - public: +public: //! Creates empty proximity tool. Standard_EXPORT BRepExtrema_ShapeProximity (const Standard_Real theTolerance = 0.0); @@ -68,58 +67,50 @@ public: //! Loads 2nd shape into proximity tool. Standard_EXPORT Standard_Boolean LoadShape2 (const TopoDS_Shape& theShape2); - //! Performs search for overlapped faces. + //! Performs search of overlapped faces. Standard_EXPORT void Perform(); //! True if the search is completed. Standard_Boolean IsDone() const { - return myIsDone; + return myOverlapTool.IsDone(); } - //! Returns set of all the face triangles of the 1st shape. - const NCollection_Handle& PrimitiveSet1() const + //! Returns set of IDs of overlapped faces of 1st shape (started from 0). + const BRepExtrema_MapOfIntegerPackedMapOfInteger& OverlapSubShapes1() const { - return myPrimitiveSet1; + return myOverlapTool.OverlapSubShapes1(); } - //! Returns set of all the face triangles of the 2nd shape. - const NCollection_Handle& PrimitiveSet2() const + //! Returns set of IDs of overlapped faces of 2nd shape (started from 0). + const BRepExtrema_MapOfIntegerPackedMapOfInteger& OverlapSubShapes2() const { - return myPrimitiveSet2; + return myOverlapTool.OverlapSubShapes2(); } - //! Returns set of IDs of overlapped faces of 1st shape. - const BRepExtrema_OverlappedSubShapes& OverlapSubShapes1() const - { - return myOverlapSubShapes1; - } - - //! Returns set of IDs of overlapped faces of 2nd shape. - const BRepExtrema_OverlappedSubShapes& OverlapSubShapes2() const - { - return myOverlapSubShapes2; - } - - //! Returns sub-shape from 1st shape with the given index. + //! Returns sub-shape from 1st shape with the given index (started from 0). const TopoDS_Face& GetSubShape1 (const Standard_Integer theID) const { return myFaceList1.Value (theID); } - //! Returns sub-shape from 1st shape with the given index. + //! Returns sub-shape from 1st shape with the given index (started from 0). const TopoDS_Face& GetSubShape2 (const Standard_Integer theID) const { return myFaceList2.Value (theID); } -protected: + //! Returns set of all the face triangles of the 1st shape. + const Handle(BRepExtrema_TriangleSet)& ElementSet1() const + { + return myElementSet1; + } - //! Performs narrow-phase of overlap test (exact intersection). - void IntersectLeavesExact (const BVH_Vec4i& theLeaf1, const BVH_Vec4i& theLeaf2); - - //! Performs narrow-phase of overlap test (intersection with non-zero tolerance). - void IntersectLeavesToler (const BVH_Vec4i& theLeaf1, const BVH_Vec4i& theLeaf2); + //! Returns set of all the face triangles of the 2nd shape. + const Handle(BRepExtrema_TriangleSet)& ElementSet2() const + { + return myElementSet2; + } private: @@ -137,17 +128,12 @@ private: BRepExtrema_ShapeList myFaceList2; //! Set of all the face triangles of the 1st shape. - NCollection_Handle myPrimitiveSet1; + Handle(BRepExtrema_TriangleSet) myElementSet1; //! Set of all the face triangles of the 2nd shape. - NCollection_Handle myPrimitiveSet2; + Handle(BRepExtrema_TriangleSet) myElementSet2; - //! Set of overlapped faces of 1st shape. - BRepExtrema_OverlappedSubShapes myOverlapSubShapes1; - //! Set of overlapped faces of 2nd shape. - BRepExtrema_OverlappedSubShapes myOverlapSubShapes2; - - //! Is overlap test completed? - Standard_Boolean myIsDone; + //! Overlap tool used for intersection/overlap test. + BRepExtrema_OverlapTool myOverlapTool; }; diff --git a/src/BRepExtrema/BRepExtrema_TriangleSet.cxx b/src/BRepExtrema/BRepExtrema_TriangleSet.cxx index 4c689a513b..dd5d850154 100644 --- a/src/BRepExtrema/BRepExtrema_TriangleSet.cxx +++ b/src/BRepExtrema/BRepExtrema_TriangleSet.cxx @@ -21,6 +21,9 @@ #include #include +IMPLEMENT_STANDARD_HANDLE (BRepExtrema_TriangleSet, Standard_Transient) +IMPLEMENT_STANDARD_RTTIEXT(BRepExtrema_TriangleSet, Standard_Transient) + //======================================================================= //function : BRepExtrema_TriangleSet //purpose : Creates empty triangle set @@ -224,3 +227,4 @@ Standard_Boolean BRepExtrema_TriangleSet::Init (const BRepExtrema_ShapeList& the return Standard_True; } + diff --git a/src/BRepExtrema/BRepExtrema_TriangleSet.hxx b/src/BRepExtrema/BRepExtrema_TriangleSet.hxx index 072f28904d..b11b68e123 100644 --- a/src/BRepExtrema/BRepExtrema_TriangleSet.hxx +++ b/src/BRepExtrema/BRepExtrema_TriangleSet.hxx @@ -17,14 +17,13 @@ #define _BRepExtrema_TriangleSet_HeaderFile #include - #include //! List of shapes and their IDs for collision detection. typedef NCollection_Vector BRepExtrema_ShapeList; //! Triangle set corresponding to specific face. -class BRepExtrema_TriangleSet : public BVH_PrimitiveSet +class BRepExtrema_TriangleSet : public BVH_PrimitiveSet, public Standard_Transient { public: @@ -79,6 +78,12 @@ protected: //! Array of vertex coordinates. BVH_Array3d myVertexArray; +public: + + DEFINE_STANDARD_RTTI(BRepExtrema_TriangleSet) + }; +DEFINE_STANDARD_HANDLE (BRepExtrema_TriangleSet, Standard_Transient) + #endif // _BRepExtrema_TriangleSet_HeaderFile diff --git a/src/BRepExtrema/FILES b/src/BRepExtrema/FILES index 63e0c6f0fe..85d0537ffe 100644 --- a/src/BRepExtrema/FILES +++ b/src/BRepExtrema/FILES @@ -19,5 +19,11 @@ BRepExtrema_SolutionElem.hxx BRepExtrema_SupportType.hxx BRepExtrema_TriangleSet.hxx BRepExtrema_TriangleSet.cxx +BRepExtrema_OverlapTool.hxx +BRepExtrema_OverlapTool.cxx +BRepExtrema_ElementFilter.hxx BRepExtrema_ShapeProximity.hxx BRepExtrema_ShapeProximity.cxx +BRepExtrema_SelfIntersection.hxx +BRepExtrema_SelfIntersection.cxx +BRepExtrema_MapOfIntegerPackedMapOfInteger.hxx diff --git a/src/BRepTest/BRepTest_ExtremaCommands.cxx b/src/BRepTest/BRepTest_ExtremaCommands.cxx index c6db1f20f3..395c8e22c2 100644 --- a/src/BRepTest/BRepTest_ExtremaCommands.cxx +++ b/src/BRepTest/BRepTest_ExtremaCommands.cxx @@ -21,8 +21,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -233,18 +235,18 @@ static int ShapeProximity (Draw_Interpretor& theDI, Standard_Integer theNbArgs, if (aProfile) { - theDI << "Number of primitives in shape 1: " << aTool.PrimitiveSet1()->Size() << "\n"; - theDI << "Number of primitives in shape 2: " << aTool.PrimitiveSet2()->Size() << "\n"; + theDI << "Number of primitives in shape 1: " << aTool.ElementSet1()->Size() << "\n"; + theDI << "Number of primitives in shape 2: " << aTool.ElementSet2()->Size() << "\n"; theDI << "Building data structures: " << aInitTime << "\n"; theDI << "Executing proximity test: " << aWorkTime << "\n"; } - TopoDS_Builder aCompBuilder; + TopoDS_Builder aCompBuilder; TopoDS_Compound aFaceCompound1; aCompBuilder.MakeCompound (aFaceCompound1); - for (BRepExtrema_OverlappedSubShapes::Iterator anIt1 (aTool.OverlapSubShapes1()); anIt1.More(); anIt1.Next()) + for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt1 (aTool.OverlapSubShapes1()); anIt1.More(); anIt1.Next()) { TCollection_AsciiString aStr = TCollection_AsciiString (theArgs[1]) + "_" + (anIt1.Key() + 1); @@ -258,7 +260,7 @@ static int ShapeProximity (Draw_Interpretor& theDI, Standard_Integer theNbArgs, TopoDS_Compound aFaceCompound2; aCompBuilder.MakeCompound (aFaceCompound2); - for (BRepExtrema_OverlappedSubShapes::Iterator anIt2 (aTool.OverlapSubShapes2()); anIt2.More(); anIt2.Next()) + for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt2 (aTool.OverlapSubShapes2()); anIt2.More(); anIt2.Next()) { TCollection_AsciiString aStr = TCollection_AsciiString (theArgs[2]) + "_" + (anIt2.Key() + 1); @@ -275,6 +277,123 @@ static int ShapeProximity (Draw_Interpretor& theDI, Standard_Integer theNbArgs, return 0; } +//============================================================================== +//function : ShapeSelfIntersection +//purpose : +//============================================================================== +static int ShapeSelfIntersection (Draw_Interpretor& theDI, Standard_Integer theNbArgs, const char** theArgs) +{ + if (theNbArgs < 2 || theNbArgs > 5) + { + std::cout << "Usage: " << theArgs[0] << + " Shape [-tol ] [-profile]" << std::endl; + + return 1; + } + + TopoDS_Shape aShape = DBRep::Get (theArgs[1]); + + if (aShape.IsNull()) + { + std::cout << "Error: Failed to find specified shape" << std::endl; + return 1; + } + + Standard_Real aTolerance = 0.0; + Standard_Boolean aToProfile = Standard_False; + + for (Standard_Integer anArgIdx = 2; anArgIdx < theNbArgs; ++anArgIdx) + { + TCollection_AsciiString aFlag (theArgs[anArgIdx]); + aFlag.LowerCase(); + + if (aFlag == "-tol") + { + if (++anArgIdx >= theNbArgs) + { + std::cout << "Error: wrong syntax at argument '" << aFlag << std::endl; + return 1; + } + + const Standard_Real aValue = Draw::Atof (theArgs[anArgIdx]); + if (aValue < 0.0) + { + std::cout << "Error: Tolerance value should be non-negative" << std::endl; + return 1; + } + else + { + aTolerance = aValue; + } + } + + if (aFlag == "-profile") + { + aToProfile = Standard_True; + } + } + + OSD_Timer aTimer; + + Standard_Real aInitTime = 0.0; + Standard_Real aWorkTime = 0.0; + + if (aToProfile) + { + aTimer.Start(); + } + + BRepExtrema_SelfIntersection aTool (aShape, aTolerance); + + if (aToProfile) + { + aInitTime = aTimer.ElapsedTime(); + + aTimer.Reset(); + aTimer.Start(); + } + + // Perform shape self-intersection test + aTool.Perform(); + + if (!aTool.IsDone()) + { + std::cout << "Error: Failed to perform proximity test" << std::endl; + return 1; + } + + if (aToProfile) + { + aWorkTime = aTimer.ElapsedTime(); + aTimer.Stop(); + + theDI << "Building data structure (BVH): " << aInitTime << "\n"; + theDI << "Executing self-intersection test: " << aWorkTime << "\n"; + } + + // Extract output faces + TopoDS_Builder aCompBuilder; + TopoDS_Compound aFaceCompound; + + aCompBuilder.MakeCompound (aFaceCompound); + + for (BRepExtrema_MapOfIntegerPackedMapOfInteger::Iterator anIt (aTool.OverlapElements()); anIt.More(); anIt.Next()) + { + TCollection_AsciiString aStr = TCollection_AsciiString (theArgs[1]) + "_" + (anIt.Key() + 1); + + const TopoDS_Face& aFace = aTool.GetSubShape (anIt.Key()); + aCompBuilder.Add (aFaceCompound, aFace); + DBRep::Set (aStr.ToCString(), aFace); + + theDI << aStr << " \n"; + } + + theDI << "Compound of overlapped sub-faces: " << theArgs[1] << "_overlapped\n"; + DBRep::Set ((TCollection_AsciiString (theArgs[1]) + "_" + "overlapped").ToCString(), aFaceCompound); + + return 0; +} + //======================================================================= //function : ExtremaCommands //purpose : @@ -313,4 +432,17 @@ void BRepTest::ExtremaCommands (Draw_Interpretor& theCommands) __FILE__, ShapeProximity, aGroup); + + theCommands.Add ("selfintersect", + "selfintersect Shape [-tol ] [-profile]" + "\n\t\t: Searches for intersected/overlapped faces in the given shape." + "\n\t\t: The algorithm uses shape tessellation (should be computed in" + "\n\t\t: advance), and provides approximate results. The options are:" + "\n\t\t: -tol : non-negative tolerance value used for overlapping" + "\n\t\t: test (for zero tolerance, the strict intersection" + "\n\t\t: test will be performed)" + "\n\t\t: -profile : outputs execution time for main algorithm stages", + __FILE__, + ShapeSelfIntersection, + aGroup); } diff --git a/tests/bugs/modalg_6/bug26180 b/tests/bugs/modalg_6/bug26180 new file mode 100644 index 0000000000..0c567f6179 --- /dev/null +++ b/tests/bugs/modalg_6/bug26180 @@ -0,0 +1,42 @@ +puts "========" +puts "OCC26180" +puts "========" +puts "" +################################################################## +## Modeling Algorithms - Provide shape self-intersection detector +################################################################## + +list aBoxNames + +set BOX_SIZE 5 +set BOX_GRID_SIZE 30 + +for {set i 0} {$i < $BOX_GRID_SIZE} {incr i} { + for {set j 0} {$j < $BOX_GRID_SIZE} {incr j} { + box b_[expr $i]_[expr $j] [expr $i * 6] [expr $j * 6] 0 5 5 5 + lappend aBoxNames b_[expr $i]_[expr $j] + lappend aBoxNames " " + } +} + +psphere s 30 +ttranslate s 90.0 90.0 0.0 +incmesh s 0.002 +trinfo s + +set aCompName "C" +compound {*}$aBoxNames s $aCompName + +vinit +vsetdispmode 1 +vdisplay $aCompName +vsettransparency $aCompName 0.8 +vdump $imagedir/${casename}_1.png + +selfintersect $aCompName -tol 0.0 -profile + +vdisplay [set aCompName]_overlapped +vsetcolor [set aCompName]_overlapped red +vsettransparency [set aCompName]_overlapped 0.5 +vfit +vdump $imagedir/${casename}_2.png