#include <GeomAlgoAPI_Filling.h>
#include <GeomAlgoAPI_ShapeTools.h>
#include <GeomAlgoAPI_Tools.h>
+#include <GeomAlgoAPI_WireBuilder.h>
+#include <GeomAPI_Curve.h>
#include <GeomAPI_Pnt.h>
#include <GeomAPI_ShapeExplorer.h>
#include <GeomAPI_Wire.h>
+#include <GeomAPI_WireExplorer.h>
#include <cmath>
bool isApprox;
};
+static bool isReverseClosedCurve(const GeomEdgePtr& theEdge1,
+ const GeomEdgePtr& theEdge2);
+static bool isReverseOpenedCurve(const GeomEdgePtr& theEdge1,
+ const GeomEdgePtr& theEdge2,
+ const double theTolerance);
+static void shiftStartPoint(GeomWirePtr& theWire,
+ const GeomEdgePtr& theRefEdge,
+ const double theTolerance);
+
//=================================================================================================
BuildPlugin_Filling::BuildPlugin_Filling()
for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
GeomEdgePtr anEdge = toEdge(aSelection->value(), aParameters.method);
- if (!anEdge) {
- myLastEdgeStartPoint = GeomPointPtr();
- myLastEdgeEndPoint = GeomPointPtr();
+ if (!anEdge)
return;
- }
aFilling->add(anEdge);
}
- myLastEdgeStartPoint = GeomPointPtr();
- myLastEdgeEndPoint = GeomPointPtr();
+ myLastEdge = GeomEdgePtr();
// build result
aFilling->build(aParameters.isApprox);
//=================================================================================================
GeomEdgePtr BuildPlugin_Filling::toEdge(const GeomShapePtr& theShape, const std::string& theMethod)
{
+ static const double TOLERANCE = 1.e-7;
+
GeomEdgePtr anEdge;
switch (theShape->shapeType()) {
case GeomAPI_Shape::EDGE:
anEdge = GeomEdgePtr(new GeomAPI_Edge(GeomAlgoAPI_Copy(theShape).shape()));
break;
- case GeomAPI_Shape::WIRE:
- anEdge = GeomAlgoAPI_ShapeTools::wireToEdge(
- GeomWirePtr(new GeomAPI_Wire(theShape)));
+ case GeomAPI_Shape::WIRE: {
+ GeomWirePtr aWire(new GeomAPI_Wire(theShape));
+ if (myLastEdge && theMethod == Method::AUTO_CORRECT_ORIENTATION())
+ shiftStartPoint(aWire, myLastEdge, TOLERANCE);
+ anEdge = GeomAlgoAPI_ShapeTools::wireToEdge(aWire);
break;
+ }
default:
break;
}
// correct edge orientation according to filling method
if (theMethod == Method::AUTO_CORRECT_ORIENTATION()) {
// check the distance to previous edge boundaries, reverse edge if necessary
- GeomPointPtr aStartPnt = anEdge->firstPoint();
- GeomPointPtr aEndPnt = anEdge->lastPoint();
- if (anEdge->orientation() == GeomAPI_Shape::REVERSED) {
- aStartPnt = anEdge->lastPoint();
- aEndPnt = anEdge->firstPoint();
- }
bool isReverse = false;
- if (myLastEdgeStartPoint) {
- double d1 = myLastEdgeStartPoint->distance(aStartPnt)
- + myLastEdgeEndPoint->distance(aEndPnt);
- double d2 = myLastEdgeStartPoint->distance(aEndPnt)
- + myLastEdgeEndPoint->distance(aStartPnt);
- if (fabs(d1 - d2) < 1.e-7) {
- // undefined case => check distance to start point only
- d1 = myLastEdgeStartPoint->distance(aStartPnt);
- d2 = myLastEdgeStartPoint->distance(aEndPnt);
- }
- isReverse = d2 < d1;
+ if (myLastEdge) {
+ if (myLastEdge->firstPoint()->distance(myLastEdge->lastPoint()) < TOLERANCE &&
+ anEdge->firstPoint()->distance(anEdge->lastPoint()) < TOLERANCE)
+ isReverse = isReverseClosedCurve(myLastEdge, anEdge);
+ else
+ isReverse = isReverseOpenedCurve(myLastEdge, anEdge, TOLERANCE);
}
- if (isReverse) {
+ myLastEdge = anEdge;
+ if (isReverse)
anEdge->reverse();
- myLastEdgeStartPoint = aEndPnt;
- myLastEdgeEndPoint = aStartPnt;
- } else {
- myLastEdgeStartPoint = aStartPnt;
- myLastEdgeEndPoint = aEndPnt;
- }
}
else if (theMethod == Method::USE_CURVE_INFORMATION()) {
// make all edges FORWARD to avoid reversing the curves by GeomAlgoAPI_Filling algorithm
real(TOLERANCE_3D_ID())->setValue(TOLERANCE_3D_DEFAULT());
boolean(APPROXIMATION_ID())->setValue(APPROXIMATION_DEFAULT());
}
+
+
+//============ Auxiliary functions ========================================================
+
+static std::pair<GeomPointPtr, GeomPointPtr> edgeBoundaries(const GeomEdgePtr& theEdge)
+{
+ GeomPointPtr aStart = theEdge->firstPoint();
+ GeomPointPtr anEnd = theEdge->lastPoint();
+ if (theEdge->orientation() == GeomAPI_Shape::REVERSED)
+ std::swap(aStart, anEnd);
+ return std::pair<GeomPointPtr, GeomPointPtr>(aStart, anEnd);
+}
+
+static void edgePoints(const GeomEdgePtr& theEdge, std::list<GeomPointPtr>& thePoints)
+{
+ GeomAPI_Curve aCurve(theEdge);
+ static const int aNbSegments = 10;
+ double aStart = aCurve.startParam();
+ double aEnd = aCurve.endParam();
+ for (int i = 0; i <= aNbSegments; ++i)
+ thePoints.push_back(aCurve.getPoint(aStart * (1.0 - (double)i / aNbSegments) +
+ aEnd * (double)i / aNbSegments ));
+ if (theEdge->orientation() == GeomAPI_Shape::REVERSED)
+ thePoints.reverse();
+}
+
+bool isReverseClosedCurve(const GeomEdgePtr& theEdge1,
+ const GeomEdgePtr& theEdge2)
+{
+ std::list<GeomPointPtr> anEdge1Points, anEdge2Points;
+ edgePoints(theEdge1, anEdge1Points);
+ edgePoints(theEdge2, anEdge2Points);
+
+ double d1 = 0.0;
+ double d2 = 0.0;
+ std::list<GeomPointPtr>::const_iterator anIt1 = anEdge1Points.begin();
+ std::list<GeomPointPtr>::const_iterator anIt2 = anEdge2Points.begin();
+ std::list<GeomPointPtr>::const_reverse_iterator anIt2Rev = anEdge2Points.rbegin();
+ for (; anIt1 != anEdge1Points.end(); ++anIt1, ++anIt2, ++anIt2Rev) {
+ d1 += (*anIt1)->distance(*anIt2);
+ d2 += (*anIt1)->distance(*anIt2Rev);
+ }
+ return d2 < d1;
+}
+
+bool isReverseOpenedCurve(const GeomEdgePtr& theEdge1,
+ const GeomEdgePtr& theEdge2,
+ const double theTolerance)
+{
+ std::pair<GeomPointPtr, GeomPointPtr> anEdge1Points = edgeBoundaries(theEdge1);
+ std::pair<GeomPointPtr, GeomPointPtr> anEdge2Points = edgeBoundaries(theEdge2);
+ double d1 = anEdge1Points.first->distance(anEdge2Points.first)
+ + anEdge1Points.second->distance(anEdge2Points.second);
+ double d2 = anEdge1Points.first->distance(anEdge2Points.second)
+ + anEdge1Points.second->distance(anEdge2Points.first);
+ if (fabs(d1 - d2) < theTolerance) {
+ // undefined case => check distance to start point only
+ d1 = anEdge1Points.first->distance(anEdge2Points.first);
+ d2 = anEdge1Points.first->distance(anEdge2Points.second);
+ }
+ return d2 < d1;
+}
+
+void shiftStartPoint(GeomWirePtr& theWire, const GeomEdgePtr& theRefEdge, const double theTolerance)
+{
+ if (!theWire->isClosed()) {
+ GeomVertexPtr aV1, aV2;
+ GeomAlgoAPI_ShapeTools::findBounds(theWire, aV1, aV2);
+ if (aV1->point()->distance(aV2->point()) > theTolerance)
+ return;
+ }
+
+ // find closest vertex on the wire to the start point on the edge
+ GeomPointPtr aFirstRefPnt = theRefEdge->firstPoint();
+ ListOfShape aBegin, aEnd;
+ double aMinDist = 1.e100;
+ for (GeomAPI_WireExplorer anExp(theWire); anExp.more(); anExp.next()) {
+ double aDist = anExp.currentVertex()->point()->distance(aFirstRefPnt);
+ if (aDist < aMinDist) {
+ aMinDist = aDist;
+ aEnd.insert(aEnd.end(), aBegin.begin(), aBegin.end());
+ aBegin.clear();
+ }
+ aBegin.push_back(anExp.current());
+ }
+ aBegin.insert(aBegin.end(), aEnd.begin(), aEnd.end());
+
+ GeomShapePtr aShape = GeomAlgoAPI_WireBuilder::wire(aBegin);
+ theWire.reset(new GeomAPI_Wire(aShape));
+}
--- /dev/null
+# Copyright (C) 2020 CEA/DEN, EDF R&D
+#
+# 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
+#
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchProjection
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+
+### Create SketchBSpline
+SketchBSpline_1_poles = [(0, 0),
+ (64.69989977297864, 3.820449445888325),
+ (63.227018959685, 42.02181716036146),
+ (19.7442263567145, 66.94290132940253),
+ (0, 0)
+ ]
+SketchBSpline_1 = Sketch_1.addSpline(poles = SketchBSpline_1_poles)
+[SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5, SketchPoint_6] = SketchBSpline_1.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+[SketchLine_1, SketchLine_2, SketchLine_3, SketchLine_4] = SketchBSpline_1.controlPolygon(auxiliary = [0, 1, 2, 3])
+Sketch_1.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchPoint_1.result())
+Sketch_1.setCoincident(SketchAPI_Point(SketchPoint_6).coordinates(), SketchPoint_1.result())
+model.do()
+
+### Create Plane
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Sketch_1/Face-SketchBSpline_1f"), 10, False)
+
+### Create Sketch
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Plane_1"))
+
+### Create SketchProjection
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_7 = SketchProjection_2.createdFeature()
+
+### Create SketchBSpline
+SketchBSpline_2_poles = [(0, 0),
+ (8.839087148173476, 45.21301708610518),
+ (53.18579907801947, 39.22586299994072),
+ (47.99568029170977, 4.506542817571567),
+ (0, 0)
+ ]
+SketchBSpline_2 = Sketch_2.addSpline(poles = SketchBSpline_2_poles)
+[SketchPoint_8, SketchPoint_9, SketchPoint_10, SketchPoint_11, SketchPoint_12] = SketchBSpline_2.controlPoles(auxiliary = [0, 1, 2, 3, 4])
+[SketchLine_5, SketchLine_6, SketchLine_7, SketchLine_8] = SketchBSpline_2.controlPolygon(auxiliary = [0, 1, 2, 3])
+Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_8).coordinates(), SketchPoint_7.result())
+Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_12).coordinates(), SketchPoint_7.result())
+model.do()
+
+### Create Wire
+Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchBSpline_1")], False)
+
+### Create Wire
+Wire_2 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_2/SketchBSpline_2")], False)
+
+### Create Filling
+Filling_1 = model.addFilling(Part_1_doc, [model.selection("WIRE", "Wire_1_1"), model.selection("WIRE", "Wire_2_1")])
+
+model.end()
+
+from GeomAPI import *
+
+model.testNbResults(Filling_1, 1)
+model.testNbSubResults(Filling_1, [0])
+model.testNbSubShapes(Filling_1, GeomAPI_Shape.SOLID, [0])
+model.testNbSubShapes(Filling_1, GeomAPI_Shape.FACE, [1])
+model.testNbSubShapes(Filling_1, GeomAPI_Shape.EDGE, [4])
+model.testNbSubShapes(Filling_1, GeomAPI_Shape.VERTEX, [8])
+model.testResultsVolumes(Filling_1, [1872.0403629667237])
+
+assert(model.checkPythonDump())