From 6755cb75f722eab87766a25f66d0ab6ea6847193 Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 15 Jan 2016 16:43:07 +0300 Subject: [PATCH] Invalid shape after extrusion (issue #1203) 1. Use General Fuse to build areas of a sketch 2. Update unit tests --- src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp | 735 ++---------------- src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h | 20 +- src/ModelAPI/Test/Test1064.py | 2 +- src/PythonAPI/examples/Platine.py | 10 +- 4 files changed, 58 insertions(+), 709 deletions(-) diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp index 75b707138..9713fda50 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp @@ -7,81 +7,15 @@ #include #include -#include - -#include -#include - #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include #include -#include +#include #include +#include #include -#include -#include -#include - -#include - -#include - -#ifndef DBL_MAX -#define DBL_MAX 1.7976931348623158e+308 -#endif - -const double tolerance = Precision::Confusion(); -// This value helps to find direction on the boundaries of curve. -// It is not significant for lines, but is used for circles to avoid -// wrong directions of movement (when two edges are tangent on the certain vertex) -const double shift = acos(1.0 - 3.0 * tolerance); - -/// \brief Search first vertex - the vertex with lowest x coordinate, which is used in 2 edges at least -static const TopoDS_Vertex& findStartVertex(const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE, - const gp_Dir& theDirX, const gp_Dir& theDirY); - -static gp_Dir calculateStartNormal(const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE, - const TopoDS_Vertex& theStart, const gp_Dir& theNormal); - -/// \brief Search the vertex on the sketch candidate to be the next one in the loop -static void findNextVertex(const TopoDS_Vertex& theStartVertex, - const BOPCol_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap, - const gp_Dir& theStartDir, const gp_Dir& theNormal, - TopoDS_Vertex& theNextVertex, TopoDS_Edge& theNextEdge, - gp_Dir& theNextDir); - -/// \brief Create planar face using the edges surrounding it -static void createFace(const TopoDS_Vertex& theStartVertex, - const std::list::iterator& theStartEdge, - const std::list::iterator& theEndOfEdges, - const gp_Pln& thePlane, TopoDS_Face& theResFace); - -/// \bief Create planar wire -static void createWireList(const TopoDS_Vertex& theStartVertex, - const std::list::iterator& theStartEdge, - const std::list::iterator& theEndOfEdges, - const std::set& theEdgesInLoops, - std::list& theResWires); - -/// \brief Calculate outer tengency on the edge in specified vertex -static gp_Dir getOuterEdgeDirection(const TopoDS_Edge& theEdge, const TopoDS_Vertex& theVertex); - -/// \brief Unnecessary edges will be removed from the map. -/// Positions of iterator will be updated -static void removeWasteEdges(std::list::iterator& theStartVertex, - std::list::iterator& theStartEdge, - const std::list::iterator& theEndOfVertexes, - const std::list::iterator& theEndOfEdges, - BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE); +#include void GeomAlgoAPI_SketchBuilder::createFaces( @@ -89,315 +23,66 @@ void GeomAlgoAPI_SketchBuilder::createFaces( const std::shared_ptr& theDirX, const std::shared_ptr& theNorm, const std::list >& theFeatures, - std::list >& theResultFaces, - std::list >& theResultWires) + std::list >& theResultFaces) { if (theFeatures.empty()) return; - // Create the list of edges with shared vertexes - BOPAlgo_Builder aBuilder; - BOPAlgo_PaveFiller aPF; - TopoDS_Shape aFeaturesCompound; + BRep_Builder aBuilder; + // Planar face, where the sketch was built + Handle(Geom_Surface) aPlane(new Geom_Plane(theOrigin->impl(), theNorm->impl())); + TopoDS_Face aPlnFace; + aBuilder.MakeFace(aPlnFace, aPlane, Precision::Confusion()); - // Obtain only edges from the features list - std::list > anEdges; + // Use General Fuse algorithm to prepare all subfaces, bounded by given list of edges + BOPAlgo_Builder aBB; + aBB.AddArgument(aPlnFace); + + BOPCol_ListOfShape anEdges; + BOPCol_ListIteratorOfListOfShape aShapeIt; std::list >::const_iterator aFeatIt = theFeatures.begin(); for (; aFeatIt != theFeatures.end(); aFeatIt++) { std::shared_ptr aShape(*aFeatIt); const TopoDS_Edge& anEdge = aShape->impl(); if (anEdge.ShapeType() == TopAbs_EDGE) - anEdges.push_back(aShape); - } - - if (anEdges.size() == 1) { // If there is only one feature, BOPAlgo_Builder will decline to work. Need to process it anyway - aFeaturesCompound = anEdges.front()->impl(); - } else { - std::list >::const_iterator anIt = anEdges.begin(); - for (; anIt != anEdges.end(); anIt++) { - std::shared_ptr aPreview(*anIt); - aBuilder.AddArgument(aPreview->impl()); - } - aPF.SetArguments(aBuilder.Arguments()); - aPF.Perform(); - int aErr = aPF.ErrorStatus(); - if (aErr) - return; - aBuilder.PerformWithFiller(aPF); - aErr = aBuilder.ErrorStatus(); - if (aErr) - return; - aFeaturesCompound = aBuilder.Shape(); + aBB.AddArgument(anEdge); } - - BOPCol_IndexedDataMapOfShapeListOfShape aMapVE; // map between vertexes and edges - BOPTools::MapShapesAndAncestors(aFeaturesCompound, TopAbs_VERTEX, TopAbs_EDGE, aMapVE); - if (aMapVE.IsEmpty()) // in case of not-initialized circle + aBB.Perform(); + if (aBB.ErrorStatus()) return; - gp_Dir aDirX = theDirX->impl(); - gp_Dir aNorm = theNorm->impl(); - gp_Dir aDirY = aNorm.Crossed(aDirX); - - gp_Pln aPlane(theOrigin->impl(), aNorm); - - // Set of edges used in loops - std::set anEdgesInLoops; - // Lists for processed vertexes and edges - std::list aProcVertexes; - std::list aProcEdges; - - // Search the start vertex - TopoDS_Vertex aCurVertex = findStartVertex(aMapVE, aDirX, aDirY); - aProcVertexes.push_back(aCurVertex); - gp_Dir aCurDir = aDirY.Reversed(); - gp_Dir aCurNorm = calculateStartNormal(aMapVE, aCurVertex, aNorm); - - // Go through the edges and find loops - TopoDS_Vertex aNextVertex; - TopoDS_Edge aBindingEdge; - gp_Dir aNextDir; - bool hasBranches = false; - while (aMapVE.Extent() > 0) { - if (aCurVertex.IsNull()) - return; - if (!aProcEdges.empty()) - aBindingEdge = aProcEdges.back(); - findNextVertex(aCurVertex, aMapVE, aCurDir, aCurNorm, aNextVertex, aBindingEdge, aNextDir); - if (aMapVE.FindFromKey(aCurVertex).Size() > 2) - hasBranches = true; - aCurNorm = aNorm; + // Collect faces + const TopTools_ListOfShape& anAreas = aBB.Modified(aPlnFace); + TopTools_ListIteratorOfListOfShape anIt(anAreas); + for (; anIt.More(); anIt.Next()) { + TopoDS_Face aFace = TopoDS::Face(anIt.Value()); + // avoid infinite faces + BRepTopAdaptor_FClass2d aFClass(aFace, Precision::Confusion()); + if (aFClass.PerformInfinitePoint() == TopAbs_IN) + continue; - // Try to find next vertex in the list of already processed - bool isLoopFound = false; - std::list::iterator aVertIter = aProcVertexes.begin(); - std::list::iterator anEdgeIter = aProcEdges.begin(); - for (; aVertIter != aProcVertexes.end(); aVertIter++) { - if (aVertIter->IsSame(aNextVertex)) { - isLoopFound = true; + // remove internal edges from faces + TopExp_Explorer anExp(aFace, TopAbs_EDGE); + for (; anExp.More(); anExp.Next()) + if (anExp.Current().Orientation() == TopAbs_INTERNAL) break; - } - if (anEdgeIter != aProcEdges.end()) - anEdgeIter++; - } - - bool isCircleFound = (isLoopFound && anEdgeIter == aProcEdges.end()); - aProcVertexes.push_back(aNextVertex); - aProcEdges.push_back(aBindingEdge); - - if (isLoopFound) { - // If the binding edge is a full circle, then it may be added recently. Need to update edge iterator - if (isCircleFound) { - anEdgeIter = aProcEdges.end(); - anEdgeIter--; - } - else if (hasBranches) { - // Check the orientation of the loop - gp_Dir aCN = getOuterEdgeDirection(*anEdgeIter, *aVertIter); - gp_Dir aCP = getOuterEdgeDirection(aProcEdges.back(), *aVertIter); - aCN.Reverse(); - aCP.Reverse(); - bool isWrongOrient = false; - double aDotCross = aCN.DotCross(aCP, aNorm); - if (aDotCross < -tolerance) - isWrongOrient = true; - else if (aDotCross < 0.1) { - std::list::iterator aEIt = anEdgeIter, aEIt1 = aProcEdges.end(); - ++aEIt; --aEIt1; - if (aEIt != aEIt1) { - gp_XYZ aStartV = BRep_Tool::Pnt(*aVertIter).XYZ(); - // verify all vertices in the loop to be inside the angle between aCN and aCP - std::list::iterator aVIt = aVertIter; - std::list::iterator aEndIt = aProcVertexes.end(); - ++aVIt; ++aVIt; --aEndIt; --aEndIt; - for (; aVIt != aEndIt && !isWrongOrient; ++aVIt) { - gp_XYZ aDir(BRep_Tool::Pnt(*aVIt).XYZ() - aStartV); - isWrongOrient = aCN.XYZ().DotCross(aDir, aNorm.XYZ()) < -tolerance; - } - } - } - - if (isWrongOrient) { - // The found loop has wrong orientation and may contain sub-loops. - // Need to check it once again with another initial direction. - aCurVertex = *aVertIter; - do { - aProcVertexes.pop_back(); - aProcEdges.pop_back(); - } while (aCurVertex != aProcVertexes.back()); - aCurDir = aCN.Reversed(); - aCurNorm = aNorm.Reversed(); - continue; - } - } - - if (!isCircleFound && anEdgeIter != aProcEdges.end() && - anEdgeIter->IsSame(aProcEdges.back())) { // The loop on the same edge taken twice - aProcVertexes.pop_back(); - aProcEdges.pop_back(); - aCurVertex = aProcVertexes.back(); - aCurDir = getOuterEdgeDirection(aProcEdges.back(), aCurVertex); - aCurNorm = aNorm.Reversed(); - continue; - } - - hasBranches = false; - - // When the orientation is correct or the edges looped through - // the first element, create new face and remove unnecessary edges. - TopoDS_Face aPatch; - createFace(*aVertIter, anEdgeIter, aProcEdges.end(), aPlane, aPatch); - if (!aPatch.IsNull()) { - std::shared_ptr aFace(new GeomAPI_Shape); - aFace->setImpl(new TopoDS_Face(aPatch)); - theResultFaces.push_back(aFace); - } - // push the edges used in the loop to the map - std::list::iterator anIter; - for (anIter = anEdgeIter; anIter != aProcEdges.end(); anIter++) - anEdgesInLoops.insert(&(*anIter)); - // remove unnecessary edges - std::list::iterator aCopyVLoop = aVertIter; - std::list::iterator aCopyELoop = anEdgeIter; - removeWasteEdges(aVertIter, anEdgeIter, aProcVertexes.end(), aProcEdges.end(), aMapVE); - - // revert the list of remaining edges - std::list aRemainVertexes; - for (; aVertIter != aProcVertexes.end(); aVertIter++) - aRemainVertexes.push_front(*aVertIter); - std::list aRemainEdges; - for (; anEdgeIter != aProcEdges.end(); anEdgeIter++) - aRemainEdges.push_front(*anEdgeIter); - // remove edges and vertexes used in the loop and add remaining ones - if (aCopyVLoop != aProcVertexes.begin()) { - aVertIter = aCopyVLoop; - aVertIter--; - } else - aVertIter = aProcVertexes.end(); - aProcVertexes.erase(aCopyVLoop, aProcVertexes.end()); - aProcVertexes.insert(aProcVertexes.end(), aRemainVertexes.begin(), aRemainVertexes.end()); - if (aCopyELoop != aProcEdges.begin()) { - anEdgeIter = aCopyELoop; - anEdgeIter--; - } else - anEdgeIter = aProcEdges.end(); - aProcEdges.erase(aCopyELoop, aProcEdges.end()); - aProcEdges.insert(aProcEdges.end(), aRemainEdges.begin(), aRemainEdges.end()); - - if (aVertIter == aProcVertexes.end()) - aVertIter = aProcVertexes.begin(); - else - aVertIter++; - if (anEdgeIter == aProcEdges.end()) - anEdgeIter = aProcEdges.begin(); - else - anEdgeIter++; - aCopyVLoop = aVertIter; - aCopyELoop = anEdgeIter; - - if (aVertIter != aProcVertexes.end() && - aMapVE.Contains(*aVertIter) && aMapVE.FindFromKey(*aVertIter).Extent() <= 1) - removeWasteEdges(aVertIter, anEdgeIter, aProcVertexes.end(), aProcEdges.end(), aMapVE); - if (aCopyVLoop != aVertIter) - aProcVertexes.erase(aCopyVLoop, aVertIter); - if (aCopyELoop != anEdgeIter) - aProcEdges.erase(aCopyELoop, anEdgeIter); - - // Check whether the next vertex already exists - if (aVertIter != aProcVertexes.end()) - aVertIter++; - if (aVertIter != aProcVertexes.end() && anEdgeIter != aProcEdges.end()) { - aNextVertex = *aVertIter; - aNextDir = getOuterEdgeDirection(*anEdgeIter, aNextVertex); - aProcVertexes.erase(++aVertIter, aProcVertexes.end()); - aProcEdges.erase(++anEdgeIter, aProcEdges.end()); - } else { - // Recalculate current vertex and current direction - aProcEdges.clear(); - aProcVertexes.clear(); - if (aMapVE.Extent() > 0) { - aNextVertex = findStartVertex(aMapVE, aDirX, aDirY); - aProcVertexes.push_back(aNextVertex); - } - aNextDir = aDirY.Reversed(); - aCurNorm = aNorm.Reversed(); - } - } - - // if next vertex connected only to alone edge, this is a part of wire (not a closed loop), - // we need to go back through the list of already checked edges to find a branching vertex - if (!aMapVE.IsEmpty() && aMapVE.Contains(aNextVertex) - && aMapVE.FindFromKey(aNextVertex).Size() == 1) { - std::list::reverse_iterator aVRIter = aProcVertexes.rbegin(); - std::list::reverse_iterator aERIter = aProcEdges.rbegin(); - if (aVRIter != aProcVertexes.rend()) - aVRIter++; - if (aERIter != aProcEdges.rend()) - aERIter++; - - for (; aERIter != aProcEdges.rend(); aERIter++, aVRIter++) - if (aMapVE.FindFromKey(*aVRIter).Size() > 2) - break; - if (aERIter != aProcEdges.rend() - || (aVRIter != aProcVertexes.rend() && aMapVE.FindFromKey(*aVRIter).Size() == 1)) { // the branching vertex was found or current list of edges is a wire without branches - std::list::iterator aEIter; - TopoDS_Edge aCurEdge; - if (aERIter != aProcEdges.rend()) { - aEIter = aERIter.base(); - aCurEdge = *aERIter; - } else - aEIter = aProcEdges.begin(); - std::list aTail; - createWireList(*aVRIter, aEIter, aProcEdges.end(), anEdgesInLoops, aTail); - std::list::const_iterator aTailIter = aTail.begin(); - for (; aTailIter != aTail.end(); aTailIter++) - if (!aTailIter->IsNull()) { - std::shared_ptr aWire(new GeomAPI_Shape); - aWire->setImpl(new TopoDS_Shape(*aTailIter)); - theResultWires.push_back(aWire); - } - std::list::iterator aVIter = aVRIter.base(); - std::list::iterator aEItCopy = aEIter; - removeWasteEdges(--aVIter, aEItCopy, aProcVertexes.end(), aProcEdges.end(), aMapVE); - - aProcEdges.erase(aEIter, aProcEdges.end()); - aVIter = aVRIter.base(); - aProcVertexes.erase(aVIter, aProcVertexes.end()); - - if (!aProcVertexes.empty()) { - aNextVertex = aProcVertexes.back(); - aProcVertexes.clear(); - aProcEdges.clear(); - aProcVertexes.push_back(aNextVertex); - } - } else { // there is no branching vertex in the list of proceeded, - // so we should revert the list and go the opposite way - aProcVertexes.reverse(); - aProcEdges.reverse(); - aNextVertex = aProcVertexes.back(); - aNextDir = - aProcEdges.empty() ? aDirY : getOuterEdgeDirection(aProcEdges.back(), aNextVertex); - } - } - - // When all edges of current component of connectivity are processed, - // we should repeat procedure for finding initial vertex in the remaining - if (!aMapVE.IsEmpty() && !aMapVE.Contains(aNextVertex)) { - aProcVertexes.clear(); - aProcEdges.clear(); - - aNextVertex = findStartVertex(aMapVE, aDirX, aDirY); - aProcVertexes.push_back(aNextVertex); - aNextDir = aDirY.Reversed(); - aCurNorm = calculateStartNormal(aMapVE, aNextVertex, aNorm); + if (anExp.More()) { + TopoDS_Face aNewFace; + aBuilder.MakeFace(aNewFace, aPlane, Precision::Confusion()); + TopoDS_Wire aWire; + aBuilder.MakeWire(aWire); + for (anExp.ReInit(); anExp.More(); anExp.Next()) + if (anExp.Current().Orientation() != TopAbs_INTERNAL) + aBuilder.Add(aWire, anExp.Current()); + aBuilder.Add(aNewFace, aWire); + aFace = aNewFace; } - aCurVertex = aNextVertex; - aCurDir = aNextDir; + // Store face + std::shared_ptr aResFace(new GeomAPI_Shape); + aResFace->setImpl(new TopoDS_Face(aFace)); + theResultFaces.push_back(aResFace); } - - if (theResultFaces.size() > 1) - fixIntersections(theResultFaces); } void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr& theOrigin, @@ -406,341 +91,17 @@ void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr& const std::shared_ptr& theWire, std::list >& theResultFaces) { - std::list > aFilteredWires; std::shared_ptr aWire = std::dynamic_pointer_cast(theWire); if(aWire) { // Filter wires, return only faces. - createFaces(theOrigin, theDirX, theNorm, - aWire->getEdges(), theResultFaces, aFilteredWires); - - return; + createFaces(theOrigin, theDirX, theNorm, aWire->getEdges(), theResultFaces); } else { // it may be only one circle std::shared_ptr anEdge = std::dynamic_pointer_cast(theWire); if (anEdge) { std::list > aList; aList.push_back(anEdge); - createFaces(theOrigin, theDirX, theNorm, - aList, theResultFaces, aFilteredWires); + createFaces(theOrigin, theDirX, theNorm, aList, theResultFaces); } } } - - -void GeomAlgoAPI_SketchBuilder::fixIntersections( - std::list >& theFaces) -{ - BRepClass_FaceClassifier aClassifier; - - std::list >::iterator anIter1 = theFaces.begin(); - std::list >::iterator anIter2; - for (; anIter1 != theFaces.end(); anIter1++) { - anIter2 = anIter1; - for (++anIter2; anIter2 != theFaces.end(); anIter2++) { - const TopoDS_Face& aF1 = (*anIter1)->impl(); - assert(aF1.ShapeType() == TopAbs_FACE); // all items in result list should be faces - TopExp_Explorer aVert2((*anIter2)->impl(), TopAbs_VERTEX); - for (; aVert2.More(); aVert2.Next()) { - const TopoDS_Vertex& aV = (const TopoDS_Vertex&)aVert2.Current(); - aClassifier.Perform(aF1, BRep_Tool::Pnt(aV), tolerance); - TopAbs_State aState = aClassifier.State(); - if (aState != TopAbs_IN && aState != TopAbs_ON) - break; - } - if (aVert2.More()) { // second shape is not inside first, change the shapes order and repeat comparision - const TopoDS_Face& aF2 = (*anIter2)->impl(); - assert(aF2.ShapeType() == TopAbs_FACE); // all items in result list should be faces - TopExp_Explorer aVert1((*anIter1)->impl(), TopAbs_VERTEX); - for (; aVert1.More(); aVert1.Next()) { - const TopoDS_Vertex& aV = (const TopoDS_Vertex&)aVert2.Current(); - aClassifier.Perform(aF2, BRep_Tool::Pnt(aV), tolerance); - TopAbs_State aState = aClassifier.State(); - if (aState != TopAbs_IN && aState != TopAbs_ON) - break; - } - if (!aVert1.More()) { // first shape should be cut from the second - BRepAlgoAPI_Cut aCut((*anIter2)->impl(), (*anIter1)->impl()); - aCut.Build(); - TopExp_Explorer anExp(aCut.Shape(), TopAbs_FACE); - bool isFirstFace = true; - for (; anExp.More(); anExp.Next()) { - if (anExp.Current().ShapeType() != TopAbs_FACE) continue; - if (isFirstFace) { - (*anIter2)->setImpl(new TopoDS_Shape(anExp.Current())); - isFirstFace = false; - } else { - std::shared_ptr aShape(new GeomAPI_Shape); - aShape->setImpl(new TopoDS_Shape(anExp.Current())); - theFaces.push_back(aShape); - } - } - } - } else { // second shape should be cut from the first - BRepAlgoAPI_Cut aCut((*anIter1)->impl(), (*anIter2)->impl()); - aCut.Build(); - TopExp_Explorer anExp(aCut.Shape(), TopAbs_FACE); - bool isFirstFace = true; - for (; anExp.More(); anExp.Next()) { - if (anExp.Current().ShapeType() != TopAbs_FACE) continue; - if (isFirstFace) { - (*anIter1)->setImpl(new TopoDS_Shape(anExp.Current())); - isFirstFace = false; - } else { - std::shared_ptr aShape(new GeomAPI_Shape); - aShape->setImpl(new TopoDS_Shape(anExp.Current())); - theFaces.push_back(aShape); - } - } - } - } - } -} - -// =================== Auxiliary functions ==================================== -const TopoDS_Vertex& findStartVertex(const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE, - const gp_Dir& theDirX, const gp_Dir& theDirY) -{ - int aStartVertexInd = 1; - double aMaxX = -DBL_MAX; - double aMaxY = -DBL_MAX; - int aNbVert = theMapVE.Extent(); - for (int i = 1; i <= aNbVert; i++) { - const TopoDS_Vertex& aV = (const TopoDS_Vertex&) theMapVE.FindKey(i); - const gp_Pnt& aVertPnt = BRep_Tool::Pnt(aV); - - double aX = aVertPnt.XYZ().Dot(theDirX.XYZ()); - double aY = aVertPnt.XYZ().Dot(theDirY.XYZ()); - if ((aX > aMaxX || (fabs(aX - aMaxX) < tolerance && aY > aMaxY)) - && theMapVE.FindFromIndex(i).Extent() > 1) { - aMaxX = aX; - aMaxY = aY; - aStartVertexInd = i; - } - } - return static_cast(theMapVE.FindKey(aStartVertexInd)); -} - -gp_Dir calculateStartNormal(const BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE, - const TopoDS_Vertex& theStart, const gp_Dir& theNormal) -{ - gp_Dir aNorm = theNormal.Reversed(); - - const BOPCol_ListOfShape& anEdgesList = theMapVE.FindFromKey(theStart); - BOPCol_ListOfShape::Iterator aEdIter(anEdgesList); - for (; aEdIter.More(); aEdIter.Next()) { - const TopoDS_Edge& anEdge = static_cast(aEdIter.Value()); - gp_Dir aTang = getOuterEdgeDirection(anEdge, theStart); - if (aTang.X() < 0.0) { - aNorm = theNormal; - break; - } - } - return aNorm; -} - -void findNextVertex(const TopoDS_Vertex& theStartVertex, - const BOPCol_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap, - const gp_Dir& theStartDir, const gp_Dir& theNormal, TopoDS_Vertex& theNextVertex, - TopoDS_Edge& theNextEdge, gp_Dir& theNextDir) -{ - theNextVertex = TopoDS_Vertex(); - const BOPCol_ListOfShape& anEdgesList = theVertexEdgeMap.FindFromKey(theStartVertex); - int anEdgesNum = anEdgesList.Extent(); - BOPCol_ListOfShape::Iterator aEdIter(anEdgesList); - double aBestEdgeProj = DBL_MAX; - for (; aEdIter.More(); aEdIter.Next()) { - const TopoDS_Edge& anEdge = static_cast(aEdIter.Value()); - gp_Dir aTang = getOuterEdgeDirection(anEdge, theStartVertex); - aTang.Reverse(); - - // The projection is normalized in segment (-1, 1), - // where (-1, 0] corresponds to the angles (pi/2, 0] between theStartDir and aTang - // and [0, 1) corresponds to the angles [0, -pi/2) - double aProj = (aTang.Dot(theStartDir) - 1.0) * 0.5; - if (anEdgesNum > 1 && fabs(fabs(aProj) - 1) < tolerance) - continue; - if (theStartDir.DotCross(aTang, theNormal) < tolerance) - aProj *= -1.0; - - if (aProj < aBestEdgeProj) { - aBestEdgeProj = aProj; - theNextEdge = anEdge; - TopExp_Explorer aVertExp(theNextEdge, TopAbs_VERTEX); - for (; aVertExp.More(); aVertExp.Next()) - if (!aVertExp.Current().IsSame(theStartVertex)) { - theNextVertex = static_cast(aVertExp.Current()); - theNextDir = getOuterEdgeDirection(anEdge, theNextVertex); - break; - } - if (!aVertExp.More()) { // This edge is a full circle - TopoDS_Vertex aV1, aV2; - TopExp::Vertices(theNextEdge, aV1, aV2); - if (aV1.Orientation() == theStartVertex.Orientation()) - theNextVertex = aV2; - else - theNextVertex = aV1; - theNextDir = getOuterEdgeDirection(anEdge, theNextVertex); - } - } - } - - // Probably there are two tangent edges. We will take the edge differs from current one - if (theNextVertex.IsNull() && anEdgesNum == 2) { - BOPCol_ListOfShape::Iterator aEdIter(anEdgesList); - if (aEdIter.Value() == theNextEdge) - aEdIter.Next(); - theNextEdge = static_cast(aEdIter.Value()); - TopoDS_Vertex aV1, aV2; - TopExp::Vertices(theNextEdge, aV1, aV2); - theNextVertex = theStartVertex.IsSame(aV1) ? aV2 : aV1; - theNextDir = getOuterEdgeDirection(theNextEdge, theNextVertex); - } -} - -static void addEdgeToWire(const TopoDS_Edge& theEdge, const BRep_Builder& theBuilder, - TopoDS_Shape& theSpliceVertex, TopoDS_Wire& theWire) -{ - TopoDS_Edge anEdge = theEdge; - bool isCurVertChanged = false; - TopoDS_Shape aCurVertChanged; - - TopExp_Explorer aVertExp(theEdge, TopAbs_VERTEX); - for (; aVertExp.More(); aVertExp.Next()) { - const TopoDS_Shape& aVertex = aVertExp.Current(); - if (aVertex.IsSame(theSpliceVertex) - && aVertex.Orientation() != theEdge.Orientation()) { // Current vertex is the last for the edge, so its orientation is wrong, need to revert the edge - anEdge.Reverse(); - break; - } - if (!aVertex.IsSame(theSpliceVertex)) { - aCurVertChanged = aVertex; - isCurVertChanged = true; - } - } - theSpliceVertex = isCurVertChanged ? aCurVertChanged : aVertExp.Current(); - - theBuilder.Add(theWire, anEdge); -} - -void createFace(const TopoDS_Vertex& theStartVertex, - const std::list::iterator& theStartEdge, - const std::list::iterator& theEndOfEdges, - const gp_Pln& thePlane, - TopoDS_Face& theResFace) -{ - TopoDS_Wire aResWire; - BRep_Builder aBuilder; - aBuilder.MakeWire(aResWire); - - TopoDS_Vertex aCurVertex = theStartVertex; - std::list::const_iterator anEdgeIter = theStartEdge; - for (; anEdgeIter != theEndOfEdges; anEdgeIter++) { - if (!anEdgeIter->IsNull()) - addEdgeToWire(*anEdgeIter, aBuilder, aCurVertex, aResWire); - } - - BRepBuilderAPI_MakeFace aFaceBuilder(thePlane, aResWire); - if (aFaceBuilder.Error() == BRepBuilderAPI_FaceDone) - theResFace = aFaceBuilder.Face(); -} - -void createWireList(const TopoDS_Vertex& theStartVertex, - const std::list::iterator& theStartEdge, - const std::list::iterator& theEndOfEdges, - const std::set& theEdgesInLoops, - std::list& theResWires) -{ - BRep_Builder aBuilder; - bool needNewWire = true; - TopoDS_Vertex aCurVertex = theStartVertex; - - std::list::iterator anIter = theStartEdge; - while (anIter != theEndOfEdges) { - while (anIter != theEndOfEdges && needNewWire && theEdgesInLoops.count(&(*anIter)) != 0) { - TopExp_Explorer aVertExp(*anIter, TopAbs_VERTEX); - for (; aVertExp.More(); aVertExp.Next()) - if (!aVertExp.Current().IsSame(aCurVertex)) { - aCurVertex = static_cast(aVertExp.Current()); - break; - } - anIter++; - } - if (anIter == theEndOfEdges) - break; - - if (needNewWire) { // The new wire should be created - TopoDS_Wire aWire; - aBuilder.MakeWire(aWire); - theResWires.push_back(aWire); - needNewWire = false; - } else if (theEdgesInLoops.count(&(*anIter)) != 0) { // There was found the edge already used in loop. - // Current wire should be released and new one should started - needNewWire = true; - continue; - } - - addEdgeToWire(*anIter, aBuilder, aCurVertex, theResWires.back()); - anIter++; - } -} - -gp_Dir getOuterEdgeDirection(const TopoDS_Edge& theEdge, const TopoDS_Vertex& theVertex) -{ - gp_Pnt aVertexPnt = BRep_Tool::Pnt(theVertex); - - // Convert the edge to the curve to calculate the tangency. - // There should be only one curve in the edge. - double aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast); - - gp_Pnt aPnt; - gp_Vec aTang; - // A direction is determined not in the boundary points but in the points with small shift. - // It was done to avoid tangency between circle and other edge in the shared vertex. - aCurve->D1(aFirst + shift > aLast ? aFirst : aFirst + shift, aPnt, aTang); - aCurve->D0(aFirst, aPnt); - if (aVertexPnt.IsEqual(aPnt, tolerance)) - return gp_Dir(aTang.Reversed()); - - aCurve->D1(aLast - shift < aFirst ? aLast : aLast - shift, aPnt, aTang); - return gp_Dir(aTang); -} - -void removeWasteEdges(std::list::iterator& theStartVertex, - std::list::iterator& theStartEdge, - const std::list::iterator& theEndOfVertexes, - const std::list::iterator& theEndOfEdges, - BOPCol_IndexedDataMapOfShapeListOfShape& theMapVE) -{ - bool isVertStep = true; - while (theStartVertex != theEndOfVertexes && theStartEdge != theEndOfEdges) { - BOPCol_ListOfShape& aBunch = theMapVE.ChangeFromKey(*theStartVertex); - BOPCol_ListOfShape::Iterator anApprEdge(aBunch); - for (; anApprEdge.More(); anApprEdge.Next()) - if (anApprEdge.Value().IsSame(*theStartEdge)) - break; - if (anApprEdge.More()) - aBunch.Remove(anApprEdge); - - if (isVertStep) - theStartVertex++; - else { - theStartEdge++; - // check current vertex to be a branching point - // if so, it will be a new starting point to find a loop - if (aBunch.Size() > 1) - break; - } - isVertStep = !isVertStep; - } - - // The map of vertex-edges may be changed - BOPCol_IndexedDataMapOfShapeListOfShape aMapVECopy; - BOPCol_IndexedDataMapOfShapeListOfShape::Iterator aMapIter(theMapVE); - for (int ind = 1; aMapIter.More(); aMapIter.Next(), ind++) - if (!aMapIter.Value().IsEmpty()) - aMapVECopy.Add(theMapVE.FindKey(ind), aMapIter.Value()); - theMapVE.Clear(); - theMapVE.Exchange(aMapVECopy); -} - diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h index f442df89d..4ebeb9029 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.h @@ -23,24 +23,20 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_SketchBuilder { public: - /** \brief Creates list of faces and unclosed wires on basis of the features of the sketch + /** \brief Creates list of faces based on the features of the sketch * \param[in] theOrigin origin point of the sketch * \param[in] theDirX x-direction of the sketch * \param[in] theNorm normal of the sketch * \param[in] theFeatures initial features of the sketch * \param[out] theResultFaces faces based on closed wires - * \param[out] theResultWires unclosed wires of the sketch * - * The algorithm searches all loops of edges surrounding lesser squares. - * It finds the vertex with minimal coordinates along X axis (theDirX) and then - * goes through the edges passing the surrounding area on the left. + * The algorithm searches all loops of edges surrounding lesser areas. */ static void createFaces(const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, const std::shared_ptr& theNorm, const std::list >& theFeatures, - std::list >& theResultFaces, - std::list >& theResultWires); + std::list >& theResultFaces); /** \brief Creates list of faces and unclosed wires on basis of the features of the sketch * \param[in] theOrigin origin point of the sketch @@ -49,21 +45,13 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_SketchBuilder * \param[in] theWire a wire which contains all edges * \param[out] theResultFaces faces based on closed wires * - * The algorithm searches all loops of edges surrounding lesser squares. - * It finds the vertex with minimal coordinates along X axis (theDirX) and then - * goes through the edges passing the surrounding area on the left. + * The algorithm searches all loops of edges surrounding lesser areas. */ static void createFaces(const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, const std::shared_ptr& theNorm, const std::shared_ptr& theWire, std::list >& theResultFaces); - - /** \brief Searches intersections between the faces in the list - * and make holes in the faces to avoid intersections - * \param[in,out] theFaces list of faces to proccess - */ - static void fixIntersections(std::list >& theFaces); }; #endif diff --git a/src/ModelAPI/Test/Test1064.py b/src/ModelAPI/Test/Test1064.py index c73dfd17d..e5c24f218 100644 --- a/src/ModelAPI/Test/Test1064.py +++ b/src/ModelAPI/Test/Test1064.py @@ -73,7 +73,7 @@ aSession.setActiveDocument(aPartSet) aPlane = aPartSet.addFeature("Plane") aPlane.string("CreationMethod").setValue("PlaneByFaceAndDistance") aPlane.real("distance").setValue(0) -aPlane.selection("planeFace").selectSubShape("face", "Part_1/Extrusion_1_1/LateralFace_3") +aPlane.selection("planeFace").selectSubShape("face", "Part_1/Extrusion_1_1/LateralFace_2") aSession.finishOperation() #========================================================================= diff --git a/src/PythonAPI/examples/Platine.py b/src/PythonAPI/examples/Platine.py index 420a2c3a0..96afd1ac0 100644 --- a/src/PythonAPI/examples/Platine.py +++ b/src/PythonAPI/examples/Platine.py @@ -54,7 +54,7 @@ def vertical_body(): def bottom_body(): # Create XOY sketch - sketch = model.addSketch(part, "Extrusion_1_1/LateralFace_2") + sketch = model.addSketch(part, "Extrusion_1_1/LateralFace_5") # Create base polygon points = [(0, 0), (0, L), (P, L), (P, 16 + 16), (P - 20, 16 + 16), (P - 20, 16), (P, 16), (P, 0)] @@ -87,7 +87,7 @@ def bottom_body(): sketch.setCoincident(arc.endPoint(), h1.startPoint()) # Binding - left_e = sketch.addLine("Extrusion_1_1/LateralFace_2&Extrusion_1_1/ToFace_1") + left_e = sketch.addLine("Extrusion_1_1/LateralFace_5&Extrusion_1_1/ToFace_1") sketch.setCoincident(left_e.startPoint(), left.endPoint()) sketch.setCoincident(left_e.endPoint(), left.startPoint()) @@ -109,7 +109,7 @@ def bottom_body(): def body_3(): # Create XOZ sketch - sketch = model.addSketch(part, "Boolean_1_1/Modified_3") + sketch = model.addSketch(part, "Boolean_1_1/Modified_4") # Create base polygon H, L, l, r = 28, 40, 8, 12 @@ -147,7 +147,7 @@ def body_3(): sketch.setRadius(arc.result(), r) # Binding - bottom_e = sketch.addLine("Boolean_1_1/Modified_1&Boolean_1_1/Modified_3") + bottom_e = sketch.addLine("Boolean_1_1/Modified_1&Boolean_1_1/Modified_4") sketch.setCoincident(bottom_e.result(), bottom.startPoint()) sketch.setCoincident(bottom_e.startPoint(), bottom.endPoint()) @@ -175,7 +175,7 @@ def body_4(): sketch.setCoincident(bottom_e.endPoint(), bottom.startPoint()) sketch.setCoincident(bottom_e.startPoint(), left.startPoint()) - left_e = sketch.addLine("Boolean_2_1/Modified_3&Boolean_2_1/Modified_2") + left_e = sketch.addLine("Boolean_2_1/Modified_4&Boolean_2_1/Modified_2") sketch.setCoincident(left_e.startPoint(), left.endPoint()) model.do() #!!! -- 2.39.2