+GeomEdgePtr GeomAlgoAPI_CurveBuilder::approximate(const std::list<GeomPointPtr>& thePoints,
+ const bool thePeriodic,
+ const double thePrecision)
+{
+ // Prepare points array to be able to build a surface.
+ // This surface is based on two sets of points: the first is an original and
+ // the second is shifted along orthogonal direction.
+ // This is a workaround, because GeomAPI_PointsToBSpline algorithm cannot produce
+ // the periodic curve, but GeomAPI_PointsToBSplineSurface can.
+ TColgp_Array2OfPnt aPoints(1, (int)thePoints.size(), 1, 2);
+ gp_Pnt aPlaneBase[3]; // base points to calculate the normal direction
+ int aNbPlanePoints = 0;
+ gp_Dir aNormal;
+ std::list<GeomPointPtr>::const_iterator anIt = thePoints.begin();
+ for (int i = 1; anIt != thePoints.end(); anIt++, i++) {
+ const gp_Pnt& aPoint = (*anIt)->impl<gp_Pnt>();
+ aPoints.SetValue(i, 1, aPoint);
+ aPoints.SetValue(i, 2, aPoint);
+ if (aNbPlanePoints < 3) {
+ if (aNbPlanePoints == 0 ||
+ aPoint.SquareDistance(aPlaneBase[0]) > Precision::SquareConfusion())
+ aPlaneBase[aNbPlanePoints++] = aPoint;
+ if (aNbPlanePoints == 3) {
+ gp_Vec aVec12(aPlaneBase[0], aPlaneBase[1]);
+ gp_Vec aVec13(aPlaneBase[0], aPlaneBase[2]);
+ if (aVec12.CrossSquareMagnitude(aVec13) > Precision::SquareConfusion())
+ aNormal = gp_Dir(aVec12 ^ aVec13);
+ else
+ --aNbPlanePoints;
+ }
+ }
+ }
+ if (aNbPlanePoints < 3)
+ aNormal = gp::DZ();
+ // shifted points
+ for (int i = aPoints.LowerRow(); i <= aPoints.UpperRow(); i++)
+ aPoints.ChangeValue(i, 2).ChangeCoord() += aNormal.XYZ();
+
+ // If the curve to be closed - remove last point if it is too close to the first one
+ bool isClose = aPoints.Value(aPoints.LowerRow(), 1).Distance(
+ aPoints.Value(aPoints.UpperRow(), 1)) <= gp::Resolution();
+ if (isClose && thePeriodic) {
+ aPoints.Resize(aPoints.LowerRow(), aPoints.UpperRow() - 1,
+ aPoints.LowerCol(), aPoints.UpperCol(), Standard_True);
+ }
+
+ // Initialize and perform approximator
+ static const Standard_Integer DEGREE_MIN = 3;
+ static const Standard_Integer DEGREE_MAX = 8;
+ GeomAPI_PointsToBSplineSurface anApprox;
+ anApprox.Init(aPoints, Approx_ChordLength, DEGREE_MIN, DEGREE_MAX,
+ GeomAbs_C2, thePrecision, thePeriodic);
+
+ // Set result in form of edge
+ TopoDS_Edge anEdge;
+ if (anApprox.IsDone()) {
+ // build a curve along U-direction of the surface
+ Handle(Geom_BSplineSurface) aSurface = anApprox.Surface();
+ Handle(Geom_Curve) aCurve = aSurface->VIso(aSurface->VKnots().First());
+
+ anEdge = BRepBuilderAPI_MakeEdge(aCurve).Edge();
+ }
+
+ GeomEdgePtr aResultShape(new GeomAPI_Edge);
+ aResultShape->setImpl(new TopoDS_Shape(anEdge));
+
+ return aResultShape;
+}
+
+void GeomAlgoAPI_CurveBuilder::reorderPoints(std::list<GeomPointPtr>& thePoints)