From cb2e41f927b8a815cf0d269a61b67f17fdeaaaf5 Mon Sep 17 00:00:00 2001 From: oan Date: Mon, 4 Nov 2019 22:04:04 +0300 Subject: [PATCH] Exact intersection of discrete segments --- src/BRepMesh/BRepMesh_Delaun.cxx | 3 +- src/BRepMesh/BRepMesh_FaceChecker.cxx | 219 +----------------- src/BRepMesh/BRepMesh_FaceChecker.hxx | 51 +--- .../BRepMesh_FaceIntersectionsSplitter.cxx | 100 ++++++++ .../BRepMesh_FaceIntersectionsSplitter.hxx | 55 +++++ src/BRepMesh/BRepMesh_GeomTool.cxx | 8 +- src/BRepMesh/BRepMesh_GeomTool.hxx | 3 +- src/BRepMesh/BRepMesh_ModelHealer.cxx | 8 +- src/BRepMesh/BRepMesh_SegmentedFace.cxx | 204 ++++++++++++++++ src/BRepMesh/BRepMesh_SegmentedFace.hxx | 169 ++++++++++++++ src/BRepMesh/FILES | 4 + src/IMeshData/IMeshData_Types.hxx | 5 +- src/QABugs/QABugs_19.cxx | 2 +- 13 files changed, 565 insertions(+), 266 deletions(-) create mode 100644 src/BRepMesh/BRepMesh_FaceIntersectionsSplitter.cxx create mode 100644 src/BRepMesh/BRepMesh_FaceIntersectionsSplitter.hxx create mode 100644 src/BRepMesh/BRepMesh_SegmentedFace.cxx create mode 100644 src/BRepMesh/BRepMesh_SegmentedFace.hxx diff --git a/src/BRepMesh/BRepMesh_Delaun.cxx b/src/BRepMesh/BRepMesh_Delaun.cxx index 761dabdcf2..81490f2568 100644 --- a/src/BRepMesh/BRepMesh_Delaun.cxx +++ b/src/BRepMesh/BRepMesh_Delaun.cxx @@ -2434,8 +2434,9 @@ BRepMesh_GeomTool::IntFlag BRepMesh_Delaun::intSegSeg( p3 = GetVertex( theEdg2.FirstNode() ).Coord(); p4 = GetVertex( theEdg2.LastNode() ).Coord(); + Standard_Real aIntParams[2]; return BRepMesh_GeomTool::IntSegSeg(p1, p2, p3, p4, - isConsiderEndPointTouch, isConsiderPointOnEdge, theIntPnt); + isConsiderEndPointTouch, isConsiderPointOnEdge, theIntPnt, aIntParams); } //============================================================================= diff --git a/src/BRepMesh/BRepMesh_FaceChecker.cxx b/src/BRepMesh/BRepMesh_FaceChecker.cxx index cc2491df70..8820bc2b41 100644 --- a/src/BRepMesh/BRepMesh_FaceChecker.cxx +++ b/src/BRepMesh/BRepMesh_FaceChecker.cxx @@ -19,191 +19,6 @@ #include #include -namespace -{ - const Standard_Real MaxTangentAngle = 5. * M_PI / 180.; - - //! Functor to be used to fill segments and bounding box tree in parallel. - class SegmentsFiller - { - public: - //! Constructor. - SegmentsFiller(const IMeshData::IFaceHandle& theDFace, - Handle(BRepMesh_FaceChecker::ArrayOfSegments)& theWiresSegments, - Handle(BRepMesh_FaceChecker::ArrayOfBndBoxTree)& theWiresBndBoxTree) - : myDFace(theDFace), - myWiresSegments(theWiresSegments), - myWiresBndBoxTree(theWiresBndBoxTree) - { - myWiresSegments = new BRepMesh_FaceChecker::ArrayOfSegments (0, myDFace->WiresNb() - 1); - myWiresBndBoxTree = new BRepMesh_FaceChecker::ArrayOfBndBoxTree (0, myDFace->WiresNb() - 1); - } - - //! Performs initialization of wire with the given index. - void operator()(const Standard_Integer theWireIndex) const - { - const IMeshData::IWireHandle& aDWire = myDFace->GetWire(theWireIndex); - - Handle(NCollection_IncAllocator) aTmpAlloc1 = new NCollection_IncAllocator(); - - Handle(BRepMesh_FaceChecker::Segments) aSegments = - new BRepMesh_FaceChecker::Segments(aDWire->EdgesNb(), aTmpAlloc1); - Handle(IMeshData::BndBox2dTree) aBndBoxTree = new IMeshData::BndBox2dTree(aTmpAlloc1); - - myWiresSegments ->ChangeValue(theWireIndex) = aSegments; - myWiresBndBoxTree->ChangeValue(theWireIndex) = aBndBoxTree; - - Handle(NCollection_IncAllocator) aTmpAlloc2 = new NCollection_IncAllocator(); - IMeshData::BndBox2dTreeFiller aBndBoxTreeFiller(*aBndBoxTree, aTmpAlloc2); - - for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt) - { - // TODO: check 2d wire for consistency. - - const IMeshData::IEdgePtr& aDEdge = aDWire->GetEdge(aEdgeIt); - const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(myDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt)); - - for (Standard_Integer aPointIt = 1; aPointIt < aPCurve->ParametersNb(); ++aPointIt) - { - gp_Pnt2d& aPnt1 = aPCurve->GetPoint(aPointIt - 1); - gp_Pnt2d& aPnt2 = aPCurve->GetPoint(aPointIt); - - Bnd_Box2d aBox; - aBox.Add(aPnt1); - aBox.Add(aPnt2); - aBox.Enlarge(Precision::Confusion()); - - aBndBoxTreeFiller.Add(aSegments->Size(), aBox); - aSegments->Append(BRepMesh_FaceChecker::Segment(aDEdge, &aPnt1, &aPnt2)); - } - } - - aBndBoxTreeFiller.Fill(); - } - - private: - - SegmentsFiller (const SegmentsFiller& theOther); - - void operator=(const SegmentsFiller& theOther); - - private: - - const IMeshData::IFaceHandle& myDFace; - Handle(BRepMesh_FaceChecker::ArrayOfSegments)& myWiresSegments; - Handle(BRepMesh_FaceChecker::ArrayOfBndBoxTree)& myWiresBndBoxTree; - }; - - //! Selector. - //! Used to identify segments with overlapped bounding boxes. - class BndBox2dTreeSelector : public IMeshData::BndBox2dTree::Selector - { - public: - //! Constructor. - BndBox2dTreeSelector(const Standard_Real theTolerance) - : myMaxLoopSize(M_PI * theTolerance * theTolerance), - mySelfSegmentIndex(-1), - myIndices(256, new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)) - { - } - - //! Sets working set of segments. - void SetSegments(const Handle(BRepMesh_FaceChecker::Segments)& theSegments) - { - mySegments = theSegments; - } - - //! Resets current selector. - void Reset(const BRepMesh_FaceChecker::Segment* theSegment, - const Standard_Integer theSelfSegmentIndex) - { - myIndices.Clear(); - - mySelfSegmentIndex = theSelfSegmentIndex; - mySegment = theSegment; - - myBox.SetVoid(); - myBox.Add(*mySegment->Point1); - myBox.Add(*mySegment->Point2); - myBox.Enlarge(Precision::Confusion()); - } - - //! Indicates should the given box be rejected or not. - virtual Standard_Boolean Reject(const Bnd_Box2d& theBox) const - { - return myBox.IsOut(theBox); - } - - //! Accepts segment with the given index in case if it fits conditions. - virtual Standard_Boolean Accept(const Standard_Integer& theSegmentIndex) - { - const BRepMesh_FaceChecker::Segment& aSegment = mySegments->Value(theSegmentIndex); - - gp_Pnt2d aIntPnt; - const BRepMesh_GeomTool::IntFlag aIntStatus = BRepMesh_GeomTool::IntSegSeg( - mySegment->Point1->XY(), mySegment->Point2->XY(), - aSegment.Point1->XY(), aSegment.Point2->XY(), - Standard_False, Standard_False, aIntPnt); - - if (aIntStatus == BRepMesh_GeomTool::Cross) - { - const Standard_Real aAngle = gp_Vec2d(mySegment->Point1->XY(), mySegment->Point2->XY()).Angle( - gp_Vec2d(aSegment.Point1->XY(), aSegment.Point2->XY())); - - if (Abs(aAngle) < MaxTangentAngle) - { - return Standard_False; - } - - if (mySelfSegmentIndex != -1) - { - gp_XY aPrevVec; - Standard_Real aSumS = 0.; - const gp_XY& aRefPnt = aIntPnt.Coord(); - for (Standard_Integer i = mySelfSegmentIndex; i < theSegmentIndex; ++i) - { - const BRepMesh_FaceChecker::Segment& aCurrSegment = mySegments->Value(i); - gp_XY aCurVec = aCurrSegment.Point2->XY() - aRefPnt; - - if (aCurVec.SquareModulus() < gp::Resolution()) - continue; - - if (aPrevVec.SquareModulus() > gp::Resolution()) - aSumS += aPrevVec ^ aCurVec; - - aPrevVec = aCurVec; - } - - if (Abs(aSumS / 2.) < myMaxLoopSize) - { - return Standard_False; - } - } - - myIndices.Append(theSegmentIndex); - return Standard_True; - } - - return Standard_False; - } - - //! Returns indices of intersecting segments. - const IMeshData::VectorOfInteger& Indices() const - { - return myIndices; - } - - private: - - Standard_Real myMaxLoopSize; - Standard_Integer mySelfSegmentIndex; - Handle(BRepMesh_FaceChecker::Segments) mySegments; - const BRepMesh_FaceChecker::Segment* mySegment; - Bnd_Box2d myBox; - IMeshData::VectorOfInteger myIndices; - }; -} - //======================================================================= //function : Constructor //purpose : @@ -211,8 +26,7 @@ namespace BRepMesh_FaceChecker::BRepMesh_FaceChecker( const IMeshData::IFaceHandle& theFace, const IMeshTools_Parameters& theParameters) - : myDFace(theFace), - myParameters(theParameters) + : BRepMesh_SegmentedFace (theFace, theParameters) { } @@ -230,50 +44,39 @@ BRepMesh_FaceChecker::~BRepMesh_FaceChecker() //======================================================================= Standard_Boolean BRepMesh_FaceChecker::Perform() { - myIntersectingEdges = new IMeshData::MapOfIEdgePtr; collectSegments(); + myIntersectingEdges = new IMeshData::MapOfIEdgePtr; + myWiresIntersectingEdges = new ArrayOfMapOfIEdgePtr(0, myDFace->WiresNb() - 1); + OSD_Parallel::For(0, myDFace->WiresNb(), *this, !isParallel()); collectResult(); - myWiresBndBoxTree.Nullify(); - myWiresSegments.Nullify(); + myWiresBndBoxTree .Nullify(); + myWiresSegments .Nullify(); myWiresIntersectingEdges.Nullify(); return myIntersectingEdges->IsEmpty(); } -//======================================================================= -//function : collectSegments -//purpose : -//======================================================================= -void BRepMesh_FaceChecker::collectSegments() -{ - SegmentsFiller aSegmentsFiller(myDFace, myWiresSegments, myWiresBndBoxTree); - OSD_Parallel::For(0, myDFace->WiresNb(), aSegmentsFiller, !isParallel()); - - myWiresIntersectingEdges = new ArrayOfMapOfIEdgePtr(0, myDFace->WiresNb() - 1); -} - //======================================================================= //function : perform //purpose : //======================================================================= void BRepMesh_FaceChecker::perform(const Standard_Integer theWireIndex) const { - const Handle(Segments)& aSegments1 = myWiresSegments->Value(theWireIndex); + const Handle(Segments)& aSegments1 = myWiresSegments ->Value (theWireIndex); Handle(IMeshData::MapOfIEdgePtr)& aIntersections = myWiresIntersectingEdges->ChangeValue(theWireIndex); - // TODO: Tolerance is set to twice value of face deflection in order to fit regressions. - BndBox2dTreeSelector aSelector(2 * myDFace->GetDeflection()); + BRepMesh_SegmentedFace::BndBox2dTreeSelector aSelector (Standard_False); for (Standard_Integer aWireIt = theWireIndex; aWireIt < myDFace->WiresNb(); ++aWireIt) { const Handle(IMeshData::BndBox2dTree)& aBndBoxTree2 = myWiresBndBoxTree->Value(aWireIt); - const Handle(Segments)& aSegments2 = myWiresSegments->Value(aWireIt); + const Handle(Segments)& aSegments2 = myWiresSegments ->Value(aWireIt); aSelector.SetSegments(aSegments2); for (Standard_Integer aSegmentIt = 0; aSegmentIt < aSegments1->Size(); ++aSegmentIt) { - const BRepMesh_FaceChecker::Segment& aSegment1 = aSegments1->Value(aSegmentIt); + const BRepMesh_SegmentedFace::Segment& aSegment1 = aSegments1->Value(aSegmentIt); aSelector.Reset(&aSegment1, (aWireIt == theWireIndex) ? aSegmentIt : -1); if (aBndBoxTree2->Select(aSelector) != 0) { @@ -287,7 +90,7 @@ void BRepMesh_FaceChecker::perform(const Standard_Integer theWireIndex) const const IMeshData::VectorOfInteger& aSegments = aSelector.Indices(); for (Standard_Integer aSelIt = 0; aSelIt < aSegments.Size(); ++aSelIt) { - const BRepMesh_FaceChecker::Segment& aSegment2 = aSegments2->Value(aSegments(aSelIt)); + const BRepMesh_SegmentedFace::Segment& aSegment2 = aSegments2->Value(aSegments(aSelIt)); aIntersections->Add(aSegment2.EdgePtr); } } diff --git a/src/BRepMesh/BRepMesh_FaceChecker.hxx b/src/BRepMesh/BRepMesh_FaceChecker.hxx index 93f574a45d..16a9787f45 100644 --- a/src/BRepMesh/BRepMesh_FaceChecker.hxx +++ b/src/BRepMesh/BRepMesh_FaceChecker.hxx @@ -16,49 +16,18 @@ #ifndef _BRepMesh_FaceChecker_HeaderFile #define _BRepMesh_FaceChecker_HeaderFile -#include -#include -#include -#include -#include +#include //! Auxiliary class checking wires of target face for self-intersections. //! Explodes wires of discrete face on sets of segments using tessellation //! data stored in model. Each segment is then checked for intersection with //! other ones. All collisions are registerd and returned as result of check. -class BRepMesh_FaceChecker : public Standard_Transient +class BRepMesh_FaceChecker : public BRepMesh_SegmentedFace { public: //! @name mesher API - //! Identifies segment inside face. - struct Segment - { - IMeshData::IEdgePtr EdgePtr; - gp_Pnt2d* Point1; // \ Use explicit pointers to points instead of accessing - gp_Pnt2d* Point2; // / using indices. - - Segment() - : Point1(NULL) - , Point2(NULL) - { - } - - Segment(const IMeshData::IEdgePtr& theEdgePtr, - gp_Pnt2d* thePoint1, - gp_Pnt2d* thePoint2) - : EdgePtr(theEdgePtr) - , Point1(thePoint1) - , Point2(thePoint2) - { - } - }; - - typedef NCollection_Shared > Segments; - typedef NCollection_Shared > ArrayOfSegments; - typedef NCollection_Shared > ArrayOfBndBoxTree; typedef NCollection_Shared > ArrayOfMapOfIEdgePtr; - //! Default constructor Standard_EXPORT BRepMesh_FaceChecker(const IMeshData::IFaceHandle& theFace, const IMeshTools_Parameters& theParameters); @@ -82,19 +51,10 @@ public: //! @name mesher API perform(theWireIndex); } - DEFINE_STANDARD_RTTI_INLINE(BRepMesh_FaceChecker, Standard_Transient) + DEFINE_STANDARD_RTTI_INLINE(BRepMesh_FaceChecker, BRepMesh_SegmentedFace) private: - //! Returns True in case if check can be performed in parallel mode. - inline Standard_Boolean isParallel() const - { - return (myParameters.InParallel && myDFace->WiresNb() > 1); - } - - //! Collects face segments. - void collectSegments(); - //! Collects intersecting edges. void collectResult(); @@ -109,11 +69,6 @@ private: private: - IMeshData::IFaceHandle myDFace; - const IMeshTools_Parameters& myParameters; - - Handle(ArrayOfSegments) myWiresSegments; - Handle(ArrayOfBndBoxTree) myWiresBndBoxTree; Handle(ArrayOfMapOfIEdgePtr) myWiresIntersectingEdges; Handle(IMeshData::MapOfIEdgePtr) myIntersectingEdges; diff --git a/src/BRepMesh/BRepMesh_FaceIntersectionsSplitter.cxx b/src/BRepMesh/BRepMesh_FaceIntersectionsSplitter.cxx new file mode 100644 index 0000000000..5a56eca4d4 --- /dev/null +++ b/src/BRepMesh/BRepMesh_FaceIntersectionsSplitter.cxx @@ -0,0 +1,100 @@ +// Created on: 2016-07-04 +// Copyright (c) 2016 OPEN CASCADE SAS +// Created by: Oleg AGASHIN +// +// 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 : Constructor +//purpose : +//======================================================================= +BRepMesh_FaceIntersectionsSplitter::BRepMesh_FaceIntersectionsSplitter( + const IMeshData::IFaceHandle& theFace, + const IMeshTools_Parameters& theParameters) + : BRepMesh_SegmentedFace (theFace, theParameters) +{ +} + +//======================================================================= +//function : Destructor +//purpose : +//======================================================================= +BRepMesh_FaceIntersectionsSplitter::~BRepMesh_FaceIntersectionsSplitter() +{ +} + +//======================================================================= +//function : Perform +//purpose : +//======================================================================= +Standard_Boolean BRepMesh_FaceIntersectionsSplitter::Perform() +{ + for (Standard_Integer aWireIt = 0; aWireIt < myDFace->WiresNb(); ++aWireIt) + { + Standard_Boolean isSplit = Standard_True; + while (isSplit) + { + collectSegments(); + + isSplit = perform(aWireIt); + + myWiresSegments .Nullify(); + myWiresBndBoxTree.Nullify(); + } + } + + return Standard_False; +} + +//======================================================================= +//function : perform +//purpose : +//======================================================================= +Standard_Boolean BRepMesh_FaceIntersectionsSplitter::perform( + const Standard_Integer theWireIndex) +{ + const Handle(Segments)& aSegments1 = myWiresSegments->Value (theWireIndex); + + BRepMesh_SegmentedFace::BndBox2dTreeSelector aSelector (Standard_True); + for (Standard_Integer aWireIt = theWireIndex; aWireIt < myDFace->WiresNb(); ++aWireIt) + { + const Handle(IMeshData::BndBox2dTree)& aBndBoxTree2 = myWiresBndBoxTree->Value(aWireIt); + const Handle(Segments)& aSegments2 = myWiresSegments ->Value(aWireIt); + + aSelector.SetSegments(aSegments2); + for (Standard_Integer aSegmentIt = 0; aSegmentIt < aSegments1->Size(); ++aSegmentIt) + { + const BRepMesh_SegmentedFace::Segment& aSegment1 = aSegments1->Value(aSegmentIt); + aSelector.Reset(&aSegment1, (aWireIt == theWireIndex) ? aSegmentIt : -1); + if (aBndBoxTree2->Select(aSelector) != 0) + { + const IMeshData::VectorOfInteger& aSegments = aSelector.Indices(); + const BRepMesh_SegmentedFace::VectorOfIntersectionParams& aIntParams = aSelector.IntParams(); + for (Standard_Integer aSelIt = 0; aSelIt < aSegments.Size(); ++aSelIt) + { + const BRepMesh_SegmentedFace::Segment& aSegment2 = aSegments2->Value(aSegments(aSelIt)); + + //aIntersections->Add(aSegment1.EdgePtr); + //aIntersections->Add(aSegment2.EdgePtr); + } + + //return Standard_False; + } + } + } + + return Standard_False; +} diff --git a/src/BRepMesh/BRepMesh_FaceIntersectionsSplitter.hxx b/src/BRepMesh/BRepMesh_FaceIntersectionsSplitter.hxx new file mode 100644 index 0000000000..a80df1b4c7 --- /dev/null +++ b/src/BRepMesh/BRepMesh_FaceIntersectionsSplitter.hxx @@ -0,0 +1,55 @@ +// Created on: 2016-07-04 +// Copyright (c) 2016 OPEN CASCADE SAS +// Created by: Oleg AGASHIN +// +// 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 _BRepMesh_FaceIntersectionsSplitter_HeaderFile +#define _BRepMesh_FaceIntersectionsSplitter_HeaderFile + +#include + +//! Auxiliary class splitting intersecting segments of wires of target face. +//! Explodes wires of discrete face on sets of segments using tessellation +//! data stored in model. Each segment is then checked for intersection with +//! other ones and split on intersection point. +class BRepMesh_FaceIntersectionsSplitter : public BRepMesh_SegmentedFace +{ +public: //! @name mesher API + + //! Default constructor + Standard_EXPORT BRepMesh_FaceIntersectionsSplitter( + const IMeshData::IFaceHandle& theFace, + const IMeshTools_Parameters& theParameters); + + //! Destructor + Standard_EXPORT virtual ~BRepMesh_FaceIntersectionsSplitter(); + + //! Performs split of intersecting segments of wires of the face. + //! @return True if there is no intersection, False elsewhere. + Standard_EXPORT Standard_Boolean Perform(); + + DEFINE_STANDARD_RTTI_INLINE(BRepMesh_FaceIntersectionsSplitter, BRepMesh_SegmentedFace) + +private: + + //! Splits wire with the given index at first intersection point with others. + Standard_Boolean perform(const Standard_Integer theWireIndex); + +private: + + BRepMesh_FaceIntersectionsSplitter (const BRepMesh_FaceIntersectionsSplitter& theOther); + + void operator=(const BRepMesh_FaceIntersectionsSplitter& theOther); +}; + +#endif diff --git a/src/BRepMesh/BRepMesh_GeomTool.cxx b/src/BRepMesh/BRepMesh_GeomTool.cxx index ae3126741c..688ee09ff7 100644 --- a/src/BRepMesh/BRepMesh_GeomTool.cxx +++ b/src/BRepMesh/BRepMesh_GeomTool.cxx @@ -333,7 +333,8 @@ BRepMesh_GeomTool::IntFlag BRepMesh_GeomTool::IntSegSeg( const gp_XY& theEndPnt2, const Standard_Boolean isConsiderEndPointTouch, const Standard_Boolean isConsiderPointOnSegment, - gp_Pnt2d& theIntPnt) + gp_Pnt2d& theIntPnt, + Standard_Real (&theParamOnSegment)[2]) { Standard_Integer aPointHash[] = { classifyPoint(theStartPnt1, theEndPnt1, theStartPnt2), @@ -393,9 +394,8 @@ BRepMesh_GeomTool::IntFlag BRepMesh_GeomTool::IntSegSeg( else if ( aPosHash == 2 ) return BRepMesh_GeomTool::Glued; - Standard_Real aParam[2]; IntFlag aIntFlag = IntLinLin(theStartPnt1, theEndPnt1, - theStartPnt2, theEndPnt2, theIntPnt.ChangeCoord(), aParam); + theStartPnt2, theEndPnt2, theIntPnt.ChangeCoord(), theParamOnSegment); if (aIntFlag == BRepMesh_GeomTool::NoIntersection) return BRepMesh_GeomTool::NoIntersection; @@ -416,7 +416,7 @@ BRepMesh_GeomTool::IntFlag BRepMesh_GeomTool::IntSegSeg( const Standard_Real aEndPrec = 1 - aPrec; for (Standard_Integer i = 0; i < 2; ++i) { - if(aParam[i] < aPrec || aParam[i] > aEndPrec ) + if(theParamOnSegment[i] < aPrec || theParamOnSegment[i] > aEndPrec ) return BRepMesh_GeomTool::NoIntersection; } diff --git a/src/BRepMesh/BRepMesh_GeomTool.hxx b/src/BRepMesh/BRepMesh_GeomTool.hxx index 6d69c4bd76..540fc644c1 100644 --- a/src/BRepMesh/BRepMesh_GeomTool.hxx +++ b/src/BRepMesh/BRepMesh_GeomTool.hxx @@ -194,7 +194,8 @@ public: //! @name static API const gp_XY& theEndPnt2, const Standard_Boolean isConsiderEndPointTouch, const Standard_Boolean isConsiderPointOnSegment, - gp_Pnt2d& theIntPnt); + gp_Pnt2d& theIntPnt, + Standard_Real (&theParamOnSegment)[2]); //! Compute deflection of the given segment. static Standard_Real SquareDeflectionOfSegment( diff --git a/src/BRepMesh/BRepMesh_ModelHealer.cxx b/src/BRepMesh/BRepMesh_ModelHealer.cxx index 6ad9b83f56..7d1835c2d1 100644 --- a/src/BRepMesh/BRepMesh_ModelHealer.cxx +++ b/src/BRepMesh/BRepMesh_ModelHealer.cxx @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -150,7 +151,12 @@ Standard_Boolean BRepMesh_ModelHealer::performInternal( { const IMeshData::IFaceHandle aDFace = aFaceIt.Key(); aDFace->SetStatus(IMeshData_SelfIntersectingWire); - aDFace->SetStatus(IMeshData_Failure); + + BRepMesh_FaceIntersectionsSplitter aSplitter (aDFace, myParameters); + if (!aSplitter.Perform()) + { + aDFace->SetStatus(IMeshData_Failure); + } } } diff --git a/src/BRepMesh/BRepMesh_SegmentedFace.cxx b/src/BRepMesh/BRepMesh_SegmentedFace.cxx new file mode 100644 index 0000000000..a33b41a897 --- /dev/null +++ b/src/BRepMesh/BRepMesh_SegmentedFace.cxx @@ -0,0 +1,204 @@ +// Created on: 2016-07-04 +// Copyright (c) 2016 OPEN CASCADE SAS +// Created by: Oleg AGASHIN +// +// 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 +#include + +namespace +{ + //! Functor to be used to fill segments and bounding box tree in parallel. + class SegmentsFiller + { + public: + //! Constructor. + SegmentsFiller(const IMeshData::IFaceHandle& theDFace, + Handle(BRepMesh_SegmentedFace::ArrayOfSegments)& theWiresSegments, + Handle(BRepMesh_SegmentedFace::ArrayOfBndBoxTree)& theWiresBndBoxTree) + : myDFace(theDFace), + myWiresSegments(theWiresSegments), + myWiresBndBoxTree(theWiresBndBoxTree) + { + myWiresSegments = new BRepMesh_SegmentedFace::ArrayOfSegments (0, myDFace->WiresNb() - 1); + myWiresBndBoxTree = new BRepMesh_SegmentedFace::ArrayOfBndBoxTree (0, myDFace->WiresNb() - 1); + } + + //! Performs initialization of wire with the given index. + void operator()(const Standard_Integer theWireIndex) const + { + const IMeshData::IWireHandle& aDWire = myDFace->GetWire(theWireIndex); + + Handle(NCollection_IncAllocator) aTmpAlloc1 = new NCollection_IncAllocator(); + + Handle(BRepMesh_SegmentedFace::Segments) aSegments = + new BRepMesh_SegmentedFace::Segments(aDWire->EdgesNb(), aTmpAlloc1); + Handle(IMeshData::BndBox2dTree) aBndBoxTree = new IMeshData::BndBox2dTree(aTmpAlloc1); + + myWiresSegments ->ChangeValue(theWireIndex) = aSegments; + myWiresBndBoxTree->ChangeValue(theWireIndex) = aBndBoxTree; + + Handle(NCollection_IncAllocator) aTmpAlloc2 = new NCollection_IncAllocator(); + IMeshData::BndBox2dTreeFiller aBndBoxTreeFiller(*aBndBoxTree, aTmpAlloc2); + + for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt) + { + // TODO: check 2d wire for consistency. + + const IMeshData::IEdgePtr& aDEdge = aDWire->GetEdge(aEdgeIt); + const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(myDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt)); + + for (Standard_Integer aPointIt = 1; aPointIt < aPCurve->ParametersNb(); ++aPointIt) + { + gp_Pnt2d& aPnt1 = aPCurve->GetPoint(aPointIt - 1); + gp_Pnt2d& aPnt2 = aPCurve->GetPoint(aPointIt); + + Bnd_Box2d aBox; + aBox.Add(aPnt1); + aBox.Add(aPnt2); + aBox.Enlarge(Precision::Confusion()); + + aBndBoxTreeFiller.Add(aSegments->Size(), aBox); + aSegments->Append(BRepMesh_SegmentedFace::Segment( + aDEdge, aPCurve.get(), + &aPnt1, aPointIt - 1, + &aPnt2, aPointIt)); + } + } + + aBndBoxTreeFiller.Fill(); + } + + private: + + SegmentsFiller (const SegmentsFiller& theOther); + + void operator=(const SegmentsFiller& theOther); + + private: + + const IMeshData::IFaceHandle& myDFace; + Handle(BRepMesh_SegmentedFace::ArrayOfSegments)& myWiresSegments; + Handle(BRepMesh_SegmentedFace::ArrayOfBndBoxTree)& myWiresBndBoxTree; + }; +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +BRepMesh_SegmentedFace::BndBox2dTreeSelector::BndBox2dTreeSelector( + const Standard_Boolean isCollectIntersectionParams) + : myCollectIntersectionParams (isCollectIntersectionParams) + , mySelfSegmentIndex(-1) + , myIndices(256, new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)) +{ +} + +//======================================================================= +//function : Reset +//purpose : +//======================================================================= +void BRepMesh_SegmentedFace::BndBox2dTreeSelector::Reset( + const BRepMesh_SegmentedFace::Segment* theSegment, + const Standard_Integer theSelfSegmentIndex) +{ + myIndices .Clear(); + myIntParams.Clear(); + + mySelfSegmentIndex = theSelfSegmentIndex; + mySegment = theSegment; + + myBox.SetVoid(); + myBox.Add(*mySegment->Point1); + myBox.Add(*mySegment->Point2); + myBox.Enlarge(Precision::Confusion()); +} + +//======================================================================= +//function : Reject +//purpose : +//======================================================================= +Standard_Boolean BRepMesh_SegmentedFace::BndBox2dTreeSelector::Reject( + const Bnd_Box2d& theBox) const +{ + return myBox.IsOut(theBox); +} + +//======================================================================= +//function : Accept +//purpose : +//======================================================================= +Standard_Boolean BRepMesh_SegmentedFace::BndBox2dTreeSelector::Accept( + const Standard_Integer& theSegmentIndex) +{ + const BRepMesh_SegmentedFace::Segment& aSegment = mySegments->Value(theSegmentIndex); + + IntersectionParams aIntNode; + aIntNode.Type = BRepMesh_GeomTool::IntSegSeg( + mySegment->Point1->XY(), mySegment->Point2->XY(), + aSegment .Point1->XY(), aSegment .Point2->XY(), + Standard_False, Standard_False, + aIntNode.Point, aIntNode.Params); + + if (aIntNode.Type == BRepMesh_GeomTool::Cross || + aIntNode.Type == BRepMesh_GeomTool::PointOnSegment || + aIntNode.Type == BRepMesh_GeomTool::Glued) + { + + myIndices.Append(theSegmentIndex); + + if (myCollectIntersectionParams) + { + myIntParams.Append(aIntNode); + } + return Standard_True; + } + + return Standard_False; +} + + + + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +BRepMesh_SegmentedFace::BRepMesh_SegmentedFace( + const IMeshData::IFaceHandle& theFace, + const IMeshTools_Parameters& theParameters) + : myDFace (theFace), + myParameters(theParameters) +{ +} + +//======================================================================= +//function : Destructor +//purpose : +//======================================================================= +BRepMesh_SegmentedFace::~BRepMesh_SegmentedFace() +{ +} + +//======================================================================= +//function : collectSegments +//purpose : +//======================================================================= +void BRepMesh_SegmentedFace::collectSegments() +{ + SegmentsFiller aSegmentsFiller(myDFace, myWiresSegments, myWiresBndBoxTree); + OSD_Parallel::For(0, myDFace->WiresNb(), aSegmentsFiller, !isParallel()); +} diff --git a/src/BRepMesh/BRepMesh_SegmentedFace.hxx b/src/BRepMesh/BRepMesh_SegmentedFace.hxx new file mode 100644 index 0000000000..ef291aa809 --- /dev/null +++ b/src/BRepMesh/BRepMesh_SegmentedFace.hxx @@ -0,0 +1,169 @@ +// Created on: 2016-07-04 +// Copyright (c) 2016 OPEN CASCADE SAS +// Created by: Oleg AGASHIN +// +// 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 _BRepMesh_SegmentedFace_HeaderFile +#define _BRepMesh_SegmentedFace_HeaderFile + +#include +#include +#include +#include +#include +#include + +//! Auxiliary class providing common functionality for exploding wires of +//! discrete face on sets of segments using tessellation data stored in model. +class BRepMesh_SegmentedFace : public Standard_Transient +{ +public: //! @name mesher API + + //! Identifies segment inside face. + //! Uses explicit pointers to points instead of accessing using indices. + struct Segment + { + IMeshData::IEdgePtr EdgePtr; + IMeshData::IPCurvePtr PCurvePtr; + gp_Pnt2d* Point1; + Standard_Integer Param1; + gp_Pnt2d* Point2; + Standard_Integer Param2; + + Segment() + : EdgePtr (NULL) + , PCurvePtr(NULL) + , Point1 (NULL) + , Param1 (0) + , Point2 (NULL) + , Param2 (0) + { + } + + Segment(const IMeshData::IEdgePtr& theEdgePtr, + const IMeshData::IPCurvePtr& thePCurvePtr, + gp_Pnt2d* thePoint1, + const Standard_Integer theParam1, + gp_Pnt2d* thePoint2, + const Standard_Integer theParam2) + : EdgePtr (theEdgePtr) + , PCurvePtr(thePCurvePtr) + , Point1 (thePoint1) + , Param1 (theParam1) + , Point2 (thePoint2) + , Param2 (theParam2) + { + } + }; + + //! Keeps parameters of intersection of two segments. + //! Params are in range relative to distance between points of corresponding segment. + struct IntersectionParams + { + BRepMesh_GeomTool::IntFlag Type; + gp_Pnt2d Point; + Standard_Real Params[2]; + }; + + typedef NCollection_Vector VectorOfIntersectionParams; + typedef NCollection_Shared > Segments; + typedef NCollection_Shared > ArrayOfSegments; + typedef NCollection_Shared > ArrayOfBndBoxTree; + + + //! Default constructor + Standard_EXPORT BRepMesh_SegmentedFace(const IMeshData::IFaceHandle& theFace, + const IMeshTools_Parameters& theParameters); + + //! Destructor + Standard_EXPORT virtual ~BRepMesh_SegmentedFace(); + + DEFINE_STANDARD_RTTI_INLINE(BRepMesh_SegmentedFace, Standard_Transient) + +protected: + + //! Returns True in case if check can be performed in parallel mode. + inline Standard_Boolean isParallel() const + { + return (myParameters.InParallel && myDFace->WiresNb() > 1); + } + + //! Collects face segments. + void collectSegments(); + +private: + + BRepMesh_SegmentedFace (const BRepMesh_SegmentedFace& theOther); + + void operator=(const BRepMesh_SegmentedFace& theOther); + +protected: + + //! Selector. + //! Used to identify segments with overlapped bounding boxes. + class BndBox2dTreeSelector : public IMeshData::BndBox2dTree::Selector + { + public: + //! Constructor. + BndBox2dTreeSelector(const Standard_Boolean isCollectIntersectionParams); + + //! Sets working set of segments. + inline void SetSegments(const Handle(BRepMesh_SegmentedFace::Segments)& theSegments) + { + mySegments = theSegments; + } + + //! Returns indices of intersecting segments. + inline const IMeshData::VectorOfInteger& Indices() const + { + return myIndices; + } + + //! Returns intersection parameters. + inline const BRepMesh_SegmentedFace::VectorOfIntersectionParams& IntParams() const + { + return myIntParams; + } + + //! Resets current selector. + void Reset(const BRepMesh_SegmentedFace::Segment* theSegment, + const Standard_Integer theSelfSegmentIndex); + + //! Indicates should the given box be rejected or not. + virtual Standard_Boolean Reject(const Bnd_Box2d& theBox) const; + + //! Accepts segment with the given index in case if it fits conditions. + virtual Standard_Boolean Accept(const Standard_Integer& theSegmentIndex); + + private: + + Standard_Boolean myCollectIntersectionParams; + Standard_Integer mySelfSegmentIndex; + Handle(BRepMesh_SegmentedFace::Segments) mySegments; + const BRepMesh_SegmentedFace::Segment* mySegment; + Bnd_Box2d myBox; + IMeshData::VectorOfInteger myIndices; + BRepMesh_SegmentedFace::VectorOfIntersectionParams myIntParams; + }; + +protected: + + IMeshData::IFaceHandle myDFace; + const IMeshTools_Parameters& myParameters; + + Handle(ArrayOfSegments) myWiresSegments; + Handle(ArrayOfBndBoxTree) myWiresBndBoxTree; + +}; + +#endif diff --git a/src/BRepMesh/FILES b/src/BRepMesh/FILES index a37a4504e4..865886bcb9 100755 --- a/src/BRepMesh/FILES +++ b/src/BRepMesh/FILES @@ -41,6 +41,8 @@ BRepMesh_EdgeTessellationExtractor.cxx BRepMesh_EdgeTessellationExtractor.hxx BRepMesh_FaceChecker.cxx BRepMesh_FaceChecker.hxx +BRepMesh_FaceIntersectionsSplitter.cxx +BRepMesh_FaceIntersectionsSplitter.hxx BRepMesh_FaceDiscret.cxx BRepMesh_FaceDiscret.hxx BRepMesh_FactoryError.hxx @@ -68,6 +70,8 @@ BRepMesh_OrientedEdge.hxx BRepMesh_PairOfIndex.hxx BRepMesh_PluginEntryType.hxx BRepMesh_PluginMacro.hxx +BRepMesh_SegmentedFace.cxx +BRepMesh_SegmentedFace.hxx BRepMesh_SelectorOfDataStructureOfDelaun.cxx BRepMesh_SelectorOfDataStructureOfDelaun.hxx BRepMesh_ShapeTool.cxx diff --git a/src/IMeshData/IMeshData_Types.hxx b/src/IMeshData/IMeshData_Types.hxx index 0b52effc0a..0d57ba5018 100644 --- a/src/IMeshData/IMeshData_Types.hxx +++ b/src/IMeshData/IMeshData_Types.hxx @@ -77,8 +77,9 @@ namespace IMeshData const size_t MEMORY_BLOCK_SIZE_HUGE = 512 * 1024; #endif - typedef IMeshData_Edge* IEdgePtr; - typedef IMeshData_Face* IFacePtr; + typedef IMeshData_Edge* IEdgePtr; + typedef IMeshData_PCurve* IPCurvePtr; + typedef IMeshData_Face* IFacePtr; typedef Handle(IMeshData_Edge) IEdgeHandle; typedef Handle(IMeshData_Wire) IWireHandle; diff --git a/src/QABugs/QABugs_19.cxx b/src/QABugs/QABugs_19.cxx index 2f835f5784..ea47f9a97d 100644 --- a/src/QABugs/QABugs_19.cxx +++ b/src/QABugs/QABugs_19.cxx @@ -3152,7 +3152,7 @@ static Standard_Integer OCC25547( aIntFlag = BRepMesh_GeomTool::IntSegSeg( aRefPnts[0], aRefPnts[1], aRefPnts[2], aRefPnts[3], - Standard_False, Standard_False, aIntPnt); + Standard_False, Standard_False, aIntPnt, aParams); aDiff = aIntPnt.Distance(gp::Origin2d()); if (aIntFlag != BRepMesh_GeomTool::Cross || aDiff > Precision::PConfusion()) -- 2.39.5