X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGeomAlgoAPI%2FGeomAlgoAPI_SketchBuilder.cpp;h=5dd1a6a901eb69975047a41d8ba7a1ee46ac1cd7;hb=4c86b629d1bf8daa737f90b64e934c7bd22f6525;hp=8096443c1b2b2f6ff7bf613b3a336cfa0b612f2c;hpb=f433b07b58eb10ebfe657ec9116129840c0d88bf;p=modules%2Fshaper.git diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp index 8096443c1..5dd1a6a90 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp @@ -1,28 +1,50 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: GeomAlgoAPI_SketchBuilder.cpp -// Created: 02 Jun 2014 -// Author: Artem ZHIDKOV +// Copyright (C) 2014-2024 CEA, EDF +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include #include +#include + #include #include +#include #include #include +#include #include #include #include #include #include #include +#include +#include #include - +#include +#include static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape) { + static const double aTol = Precision::PConfusion(); + TopExp_Explorer anExp(theShape, TopAbs_VERTEX); TopoDS_Vertex aStart = TopoDS::Vertex(anExp.Current()); gp_Pnt aStartPnt(BRep_Tool::Pnt(aStart)); @@ -32,10 +54,10 @@ static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape) for (anExp.Next(); anExp.More(); anExp.Next()) { aCurrent = TopoDS::Vertex(anExp.Current()); aCurrentPnt = BRep_Tool::Pnt(aCurrent); - if ((aCurrentPnt.X() > aStartPnt.X()) || - (aCurrentPnt.X() == aStartPnt.X() && aCurrentPnt.Y() > aStartPnt.Y()) || - (aCurrentPnt.X() == aStartPnt.X() && aCurrentPnt.Y() == aStartPnt.Y() && - aCurrentPnt.Z() > aStartPnt.Z())) { + if ((aCurrentPnt.X() > aStartPnt.X() + aTol) || + (aCurrentPnt.X() > aStartPnt.X() - aTol && aCurrentPnt.Y() > aStartPnt.Y() + aTol) || + (aCurrentPnt.X() > aStartPnt.X() - aTol && aCurrentPnt.Y() > aStartPnt.Y() - aTol && + aCurrentPnt.Z() > aStartPnt.Z() + aTol)) { aStart = aCurrent; aStartPnt = aCurrentPnt; } @@ -43,41 +65,189 @@ static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape) return aStart; } -void GeomAlgoAPI_SketchBuilder::createFaces( +static TopoDS_Vertex findStartVertex(const TopoDS_Wire& theWire, const TopoDS_Face& theFace, + const std::list >& theInitialShapes) +{ + // Try to find edge lying on the one of original edges. + // First found edge will be taken as a start edge for the result wire + std::list >::const_iterator aFeatIt = theInitialShapes.begin(); + for (; aFeatIt != theInitialShapes.end(); aFeatIt++) { + std::shared_ptr aShape(*aFeatIt); + const TopoDS_Edge& anEdge = aShape->impl(); + if (anEdge.ShapeType() != TopAbs_EDGE) + continue; + + double aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) + aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve(); + + BRepTools_WireExplorer anExp(theWire, theFace); + for (; anExp.More(); anExp.Next()) { + const TopoDS_Edge& aShapeEdge = anExp.Current(); + double aF, aL; + Handle(Geom_Curve) aShapeCurve = BRep_Tool::Curve(aShapeEdge, aF, aL); + if (aShapeCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) + aShapeCurve = Handle(Geom_TrimmedCurve)::DownCast(aShapeCurve)->BasisCurve(); + + if (aCurve != aShapeCurve) + continue; + + // the edge is found, search vertex + TopoDS_Vertex aV1, aV2; + TopExp::Vertices(aShapeEdge, aV1, aV2); + return fabs(aF - aFirst) <= fabs(aL - aFirst) ? aV1 : aV2; + } + } + + // start vertex is not found, use algorithm to search vertex with the greatest coordinates + return findStartVertex(theWire); +} + +// returns true if the first shape must be located earlier than the second +bool isFirst(const TopoDS_Shape& theFirst, const TopoDS_Shape& theSecond, + NCollection_DataMap >& theAreaToIndex, + const NCollection_DataMap& theCurveToIndex) +{ + // fill theAreaToIndex for both shapes if needed + for(int aShapeNum = 1; aShapeNum <= 2; aShapeNum++) { + TopoDS_Shape aShape = aShapeNum == 1 ? theFirst : theSecond; + if (!theAreaToIndex.IsBound(aShape)) { // fill the list of curve indices + NCollection_List aNewList; + TopExp_Explorer anEdgesExp(aShape, TopAbs_EDGE); + for (; anEdgesExp.More(); anEdgesExp.Next()) { + double aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve( + TopoDS::Edge(anEdgesExp.Current()), aFirst, aLast); + if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) + aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve(); + if (theCurveToIndex.IsBound(aCurve)) { + aNewList.Append(theCurveToIndex.Find(aCurve)); + } + } + if (aNewList.Extent()) { + NCollection_Array1 aNewArray(1, aNewList.Extent()); + NCollection_List::Iterator aListIter(aNewList); + for (int anIndex = 1; aListIter.More(); aListIter.Next(), anIndex++) { + aNewArray.SetValue(anIndex, aListIter.Value()); + } + std::sort(aNewArray.begin(), aNewArray.end()); + theAreaToIndex.Bind(aShape, aNewArray); + } + } + } + bool isFirst; + bool aGeomCompare = !theAreaToIndex.IsBound(theFirst) || !theAreaToIndex.IsBound(theSecond); + if (!aGeomCompare) { + // compare lists of indices one by one to find chich list indices are lower + NCollection_Array1::Iterator aFirstList(theAreaToIndex.ChangeFind(theFirst)); + NCollection_Array1::Iterator aSecondList(theAreaToIndex.ChangeFind(theSecond)); + for (; aFirstList.More() && aSecondList.More(); aFirstList.Next(), aSecondList.Next()) { + if (aFirstList.Value() < aSecondList.Value()) return true; + if (aFirstList.Value() > aSecondList.Value()) return false; + } + aGeomCompare = !aFirstList.More() && !aSecondList.More(); + isFirst = !aFirstList.More(); + } else { + isFirst = !theAreaToIndex.IsBound(theFirst); + } + // if faces are identical by curves names (circle splitted by line in seam-point), use parameters + if (aGeomCompare) { + GProp_GProps aGProps; + BRepGProp::SurfaceProperties(theFirst, aGProps); + gp_Pnt aCentre1 = aGProps.CentreOfMass(); + BRepGProp::SurfaceProperties(theSecond, aGProps); + gp_Pnt aCentre2 = aGProps.CentreOfMass(); + return aCentre1.X() + aCentre1.Y() + aCentre1.Z() < aCentre2.X() + aCentre2.Y() + aCentre2.Z(); + } + // if in first list there is no elements left, it is the first + return isFirst; +} + +// sorts faces (in theAreas list) to make persistent order: by initial shapes edges +static void sortAreas(TopTools_ListOfShape& theAreas, + const std::list >& theInitialShapes) +{ + // collect indices of all edges to operate them quickly + NCollection_DataMap aCurveToIndex; // curve -> index in initial shapes + std::list >::const_iterator aFeatIt = theInitialShapes.begin(); + for (int anIndex = 0; aFeatIt != theInitialShapes.end(); aFeatIt++) { + std::shared_ptr aShape(*aFeatIt); + const TopoDS_Edge& anEdge = aShape->impl(); + if (anEdge.ShapeType() != TopAbs_EDGE) + continue; + + double aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) + aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve(); + if (!aCurveToIndex.IsBound(aCurve)) + aCurveToIndex.Bind(aCurve, anIndex++); + } + // map from area to the most first indices of curves (to compare) in it + NCollection_DataMap > anAreaToIndex; + // sort areas + TopTools_ListOfShape::Iterator anArea1(theAreas); + for(; anArea1.More(); anArea1.Next()) { + TopTools_ListOfShape::Iterator anArea2 = anArea1; + for(anArea2.Next(); anArea2.More(); anArea2.Next()) { + if (!isFirst(anArea1.Value(), anArea2.Value(), anAreaToIndex, aCurveToIndex)) { // exchange + TopoDS_Shape aTmp = anArea1.Value(); + anArea1.ChangeValue() = anArea2.Value(); + anArea2.ChangeValue() = aTmp; + } + } + } +} + +void GeomAlgoAPI_SketchBuilder::build( const std::shared_ptr& theOrigin, const std::shared_ptr& theDirX, const std::shared_ptr& theNorm, - const std::list >& theFeatures, - std::list >& theResultFaces) + const std::list >& theEdges) { - if (theFeatures.empty()) + myResultFaces.clear(); + setDone(false); + if (theEdges.empty()) return; BRep_Builder aBuilder; // Planar face, where the sketch was built - Handle(Geom_Surface) aPlane(new Geom_Plane(theOrigin->impl(), theNorm->impl())); + gp_Ax3 aPlnAxes(theOrigin->impl(), theNorm->impl(), theDirX->impl()); + Handle(Geom_Surface) aPlane(new Geom_Plane(aPlnAxes)); TopoDS_Face aPlnFace; aBuilder.MakeFace(aPlnFace, aPlane, Precision::Confusion()); // Use General Fuse algorithm to prepare all subfaces, bounded by given list of edges - BOPAlgo_Builder aBB; - aBB.AddArgument(aPlnFace); + BOPAlgo_Builder* aBB = new BOPAlgo_Builder; + aBB->AddArgument(aPlnFace); + // Set fuzzy value for BOP, because PlaneGCS can solve the set of constraints with + // the precision up to 5.e-5 if the sketch contains arcs. + static const double THE_FUZZY_TOL = 5.e-5; + aBB->SetFuzzyValue(THE_FUZZY_TOL); - BOPCol_ListOfShape anEdges; - BOPCol_ListIteratorOfListOfShape aShapeIt; - std::list >::const_iterator aFeatIt = theFeatures.begin(); - for (; aFeatIt != theFeatures.end(); aFeatIt++) { + setImpl(aBB); + setBuilderType(OCCT_BOPAlgo_Builder); + + NCollection_List anEdges; + NCollection_List::Iterator aShapeIt; + std::list >::const_iterator aFeatIt = theEdges.begin(); + for (; aFeatIt != theEdges.end(); aFeatIt++) { std::shared_ptr aShape(*aFeatIt); const TopoDS_Edge& anEdge = aShape->impl(); if (anEdge.ShapeType() == TopAbs_EDGE) - aBB.AddArgument(anEdge); + aBB->AddArgument(anEdge); } - aBB.Perform(); - if (aBB.ErrorStatus()) + aBB->Perform(); + if (aBB->HasErrors()) return; + TopoDS_Compound aResult; + aBuilder.MakeCompound(aResult); + // Collect faces - const TopTools_ListOfShape& anAreas = aBB.Modified(aPlnFace); + TopTools_ListOfShape anAreas = aBB->Modified(aPlnFace); + sortAreas(anAreas, theEdges); // sort faces by the edges in them TopTools_ListIteratorOfListOfShape anIt(anAreas); for (; anIt.More(); anIt.Next()) { TopoDS_Face aFace = TopoDS::Face(anIt.Value()); @@ -90,14 +260,25 @@ void GeomAlgoAPI_SketchBuilder::createFaces( TopoDS_Face aNewFace; aBuilder.MakeFace(aNewFace, aPlane, Precision::Confusion()); - // iterate on wires + // sort inner wires according to the original edges as well as faces + TopTools_ListOfShape aWires; TopExp_Explorer aWireExp(aFace, TopAbs_WIRE); - for (; aWireExp.More(); aWireExp.Next()) { - TopoDS_Wire aWire = TopoDS::Wire(aWireExp.Current()); + for (; aWireExp.More(); aWireExp.Next()) + aWires.Append(aWireExp.Current()); + if (aWires.Size() > 2) { + TopoDS_Shape anOuterWire = aWires.First(); + aWires.RemoveFirst(); + sortAreas(aWires, theEdges); + aWires.Prepend(anOuterWire); + } + + // iterate on wires + for (TopTools_ListIteratorOfListOfShape aWIt(aWires); aWIt.More(); aWIt.Next()) { + TopoDS_Wire aWire = TopoDS::Wire(aWIt.Value()); // to make faces equal on different platforms, we will find - // a vertex with greater coordinates and start wire from it - TopoDS_Vertex aStartVertex = findStartVertex(aWire); + // a vertex lying on an edge with the lowest index in the list of initial edges + TopoDS_Vertex aStartVertex = findStartVertex(aWire, aFace, theEdges); TopoDS_Wire aNewWire; aBuilder.MakeWire(aNewWire); @@ -105,14 +286,14 @@ void GeomAlgoAPI_SketchBuilder::createFaces( bool aStartFound = false; // remove internal edges from faces and make wire start from found vertex - TopExp_Explorer anExp(aWire, TopAbs_EDGE); + BRepTools_WireExplorer anExp(aWire, aFace); for (; anExp.More(); anExp.Next()) { if (anExp.Current().Orientation() == TopAbs_INTERNAL) continue; if (!aStartFound) { - const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + const TopoDS_Edge& anEdge = anExp.Current(); TopoDS_Vertex aV1, aV2; - TopExp::Vertices(anEdge, aV1, aV2); + TopExp::Vertices(anEdge, aV1, aV2, Standard_True); if (aV1.IsSame(aStartVertex) == Standard_True) aStartFound = true; else @@ -127,36 +308,49 @@ void GeomAlgoAPI_SketchBuilder::createFaces( aBuilder.Add(aNewWire, *aSkIt); // check the wire is empty - anExp.Init(aNewWire, TopAbs_EDGE); + anExp.Init(aNewWire); if (anExp.More()) aBuilder.Add(aNewFace, aNewWire); } // store face - aFace = aNewFace; + aBuilder.Add(aResult, aNewFace); std::shared_ptr aResFace(new GeomAPI_Shape); - aResFace->setImpl(new TopoDS_Face(aFace)); - theResultFaces.push_back(aResFace); + aResFace->setImpl(new TopoDS_Face(aNewFace)); + myResultFaces.push_back(aResFace); } + + // update results + GeomShapePtr aResShape(new GeomAPI_Shape); + aResShape->setImpl(new TopoDS_Shape(aResult)); + setShape(aResShape); + setDone(true); } -void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr& theOrigin, - const std::shared_ptr& theDirX, - const std::shared_ptr& theNorm, - const std::shared_ptr& theWire, - std::list >& theResultFaces) +GeomAlgoAPI_SketchBuilder::GeomAlgoAPI_SketchBuilder( + const std::shared_ptr& thePlane, + const std::list >& theEdges) +{ + build(thePlane->location(), thePlane->xDirection(), thePlane->direction(), theEdges); +} + +GeomAlgoAPI_SketchBuilder::GeomAlgoAPI_SketchBuilder( + const std::shared_ptr& theOrigin, + const std::shared_ptr& theDirX, + const std::shared_ptr& theNorm, + const std::shared_ptr& theWire) { - std::shared_ptr aWire = + std::shared_ptr aWire = std::dynamic_pointer_cast(theWire); if(aWire) { // Filter wires, return only faces. - createFaces(theOrigin, theDirX, theNorm, aWire->getEdges(), theResultFaces); + build(theOrigin, theDirX, theNorm, aWire->getEdges()); } 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); + build(theOrigin, theDirX, theNorm, aList); } } }