]> OCCT Git - occt.git/commitdiff
0032214: Modeling Algorithms - 2d Offset produces wrong result
authorjgv <jgv@opencascade.com>
Mon, 22 Aug 2022 09:15:42 +0000 (12:15 +0300)
committerjfa <jfa@opencascade.com>
Thu, 13 Oct 2022 11:16:46 +0000 (14:16 +0300)
Add new option to convert input contours into ones consisting of 2D circular arcs and 2D linear segments only.

17 files changed:
src/BRepAlgo/BRepAlgo.cxx
src/BRepAlgo/BRepAlgo.hxx
src/BRepOffsetAPI/BRepOffsetAPI_MakeOffset.cxx
src/BRepOffsetAPI/BRepOffsetAPI_MakeOffset.hxx
src/BRepTest/BRepTest_CurveCommands.cxx
src/Geom2dConvert/FILES
src/Geom2dConvert/Geom2dConvert_ApproxArcsSegments.cxx [new file with mode: 0644]
src/Geom2dConvert/Geom2dConvert_ApproxArcsSegments.hxx [new file with mode: 0644]
src/Geom2dConvert/Geom2dConvert_PPoint.cxx [new file with mode: 0644]
src/Geom2dConvert/Geom2dConvert_PPoint.hxx [new file with mode: 0644]
src/Geom2dConvert/Geom2dConvert_SequenceOfPPoint.hxx [new file with mode: 0644]
tests/bugs/modalg_8/bug32214_1 [new file with mode: 0644]
tests/bugs/modalg_8/bug32214_2 [new file with mode: 0644]
tests/bugs/modalg_8/bug32214_3 [new file with mode: 0644]
tests/bugs/modalg_8/bug32214_4 [new file with mode: 0644]
tests/bugs/modalg_8/bug32214_5 [new file with mode: 0644]
tests/bugs/modalg_8/bug32214_6 [new file with mode: 0644]

index db36f5b3b064076d3a2b486409cd96a986f4ec13..3e03b6164e5dd7eda4719ca4f43fae52451ed029 100644 (file)
 // commercial license or contractual agreement.
 
 
+#include <BRep_Builder.hxx>
 #include <BRep_Tool.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
 #include <BRepAdaptor_Curve.hxx>
+#include <BRepAdaptor_Curve2d.hxx>
 #include <BRepAlgo.hxx>
 #include <BRepLib.hxx>
 #include <BRepLib_MakeEdge.hxx>
 #include <ElCLib.hxx>
 #include <Geom_Curve.hxx>
 #include <Geom_TrimmedCurve.hxx>
+#include <Geom2d_TrimmedCurve.hxx>
+#include <Geom2dConvert_ApproxArcsSegments.hxx>
 #include <GeomAbs_CurveType.hxx>
 #include <GeomConvert.hxx>
 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
 #include <GeomLProp.hxx>
+#include <NCollection_Vector.hxx>
 #include <gp_Pnt.hxx>
 #include <Precision.hxx>
 #include <ShapeFix_Shape.hxx>
@@ -41,6 +49,7 @@
 #include <TColStd_SequenceOfBoolean.hxx>
 #include <TColStd_SequenceOfReal.hxx>
 #include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
 #include <TopLoc_Location.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Edge.hxx>
 #//include <DrawTrSurf.hxx>
 
 
+// The minimal tolerance of approximation (edges can be defined with yet smaller tolerance)
+static const Standard_Real MINIMAL_TOLERANCE = 0.0001;
+
+namespace {
+
+struct OrientedCurve
+{
+  Handle(Geom2d_TrimmedCurve) Curve;
+  Standard_Boolean           IsReverse;
+  inline gp_Pnt2d Point (const Standard_Boolean isEnd) const
+  {
+    if (isEnd == IsReverse)
+      return Curve->StartPoint();
+    return Curve->EndPoint();
+  }  
+};
+
+}
+
+//=======================================================================
+//function : ConvertWire
+//purpose  : 
+//=======================================================================
+
+TopoDS_Wire BRepAlgo::ConvertWire(const TopoDS_Wire&          theWire,
+                                  const Standard_Real         theAngleTol,
+                                  const TopoDS_Face&          theFace)
+{
+  TopoDS_Wire aResult;
+  Standard_Real aMaxTol(0.);
+  const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(theFace);
+  NCollection_Vector<OrientedCurve> vecCurve;
+
+  BRepTools_WireExplorer anExpE(theWire, theFace);
+  // Explore the edges in the current wire, in their connection order
+  for (; anExpE.More(); anExpE.Next()) {
+    const TopoDS_Edge& anEdge = anExpE.Current();
+    BRepAdaptor_Curve2d aCurve(anEdge, theFace);
+    Standard_Real aTol = BRep_Tool::Tolerance(anEdge);
+    if (aTol < MINIMAL_TOLERANCE)
+      aTol = MINIMAL_TOLERANCE;
+    if (aTol > aMaxTol)
+      aMaxTol = aTol;
+    Geom2dConvert_ApproxArcsSegments anAlgo(aCurve, aTol, theAngleTol);
+    const TColGeom2d_SequenceOfCurve& aResultApprox = anAlgo.GetResult();
+
+    // Form the array of approximated elementary curves
+    if (anEdge.Orientation() == TopAbs_REVERSED) {
+      for (Standard_Integer iCrv = aResultApprox.Length(); iCrv > 0 ; iCrv--) {
+        const Handle(Geom2d_Curve)& aCrv = aResultApprox(iCrv);
+        if (aCrv.IsNull() == Standard_False) {
+          OrientedCurve& anOCurve = vecCurve.Append(OrientedCurve());
+          anOCurve.Curve = Handle(Geom2d_TrimmedCurve)::DownCast(aCrv);
+          anOCurve.IsReverse = Standard_True;
+        }
+      }
+    } else {
+      for (Standard_Integer iCrv = 1; iCrv <= aResultApprox.Length(); iCrv++) {
+        const Handle(Geom2d_Curve)& aCrv = aResultApprox(iCrv);
+        if (aCrv.IsNull() == Standard_False) {
+          OrientedCurve& anOCurve = vecCurve.Append(OrientedCurve());
+          anOCurve.Curve = Handle(Geom2d_TrimmedCurve)::DownCast(aCrv);
+          anOCurve.IsReverse = Standard_False;
+        }
+      }
+    }
+  }
+
+  if (vecCurve.Length() > 0)
+  {
+    // Build the first vertex
+    BRep_Builder aVBuilder;
+    gp_Pnt2d aPnt[2] = {
+      vecCurve(0).Point(Standard_False),
+      vecCurve(vecCurve.Length() - 1).Point(Standard_True)
+    };
+    Standard_Real aDist = aPnt[0].Distance(aPnt[1]);
+    if (aDist > aMaxTol + Precision::Confusion())
+      aDist = Precision::Confusion();
+    else {
+      aDist = 0.5 * aDist + Precision::Confusion();
+      aPnt[0] = 0.5 * (aPnt[0].XY() + aPnt[1].XY());
+    }
+    gp_Pnt aPnt3d;
+    aSurf->D0(aPnt[0].X(), aPnt[0].Y(), aPnt3d);
+    TopoDS_Vertex aFirstVertex;
+    aVBuilder.MakeVertex(aFirstVertex, aPnt3d, aDist);
+
+    // Loop creating edges
+    BRepBuilderAPI_MakeWire aMkWire;
+    TopoDS_Edge anEdgeRes;
+    TopoDS_Vertex aVertex = aFirstVertex;
+    for (Standard_Integer iCrv = 0; iCrv < vecCurve.Length(); iCrv++) {
+      const OrientedCurve& anOCurve = vecCurve(iCrv);
+      TopoDS_Vertex aNextVertex;
+      aPnt[0] = anOCurve.Point(Standard_True);
+      if (iCrv == vecCurve.Length() - 1) {
+        aPnt[1] = vecCurve(0).Point(Standard_False);
+        aDist = aPnt[0].Distance(aPnt[1]);
+        if (aDist > aMaxTol + Precision::Confusion()) {
+          aSurf->D0(aPnt[0].X(), aPnt[0].Y(), aPnt3d);
+          aVBuilder.MakeVertex(aNextVertex, aPnt3d, Precision::Confusion());
+        } else {
+          aNextVertex = aFirstVertex;
+        }
+      } else {
+        aPnt[1] = vecCurve(iCrv + 1).Point(Standard_False);
+        aDist = 0.5 * (aPnt[0].Distance(aPnt[1])) + Precision::Confusion();
+        aPnt[0] = 0.5 * (aPnt[0].XY() + aPnt[1].XY());
+        aSurf->D0(aPnt[0].X(), aPnt[0].Y(), aPnt3d);
+        aVBuilder.MakeVertex(aNextVertex, aPnt3d, aDist);
+      }
+      const Standard_Real aParam[2] = {
+        anOCurve.Curve->FirstParameter(),
+        anOCurve.Curve->LastParameter()
+      };
+      if (anOCurve.IsReverse) {
+        BRepBuilderAPI_MakeEdge aMkEdge(anOCurve.Curve, aSurf, aNextVertex,
+                                        aVertex, aParam[0], aParam[1]);
+        anEdgeRes = aMkEdge.Edge();
+        anEdgeRes.Orientation(TopAbs_REVERSED);
+      } else {
+        BRepBuilderAPI_MakeEdge aMkEdge(anOCurve.Curve, aSurf, aVertex,
+                                        aNextVertex, aParam[0], aParam[1]);
+        anEdgeRes = aMkEdge.Edge();
+      }
+      aVertex = aNextVertex;
+      aMkWire.Add(anEdgeRes);
+    }
+
+    if (aMkWire.IsDone())
+      aResult = aMkWire.Wire();
+  }
+  return aResult;
+}
+
+//=======================================================================
+//function : ConvertFace
+//purpose  : 
+//=======================================================================
+
+TopoDS_Face BRepAlgo::ConvertFace (const TopoDS_Face&  theFace,
+                                   const Standard_Real theAngleTolerance)
+{
+  TopoDS_Face aResult;
+  const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(theFace);
+  BRepBuilderAPI_MakeFace aMkFace(aSurf,Precision::Confusion());
+
+  TopExp_Explorer anExp(theFace, TopAbs_WIRE);
+  for (; anExp.More(); anExp.Next()) {
+    const TopoDS_Wire& aWire = TopoDS::Wire(anExp.Current());
+    const TopoDS_Wire aNewWire = ConvertWire(aWire, theAngleTolerance, theFace);
+    aMkFace.Add(aNewWire);
+  }
+  if (aMkFace.IsDone()) {
+    aResult = aMkFace.Face();
+  }
+  return aResult;
+}
+
 //=======================================================================
 //function : ConcatenateWire
 //purpose  : 
index 37c8a7d94db4409c36a4f21de10c0f5409b9279d..2512e692105c5df150d0bb19f3d676286775ed66 100644 (file)
@@ -27,6 +27,7 @@
 #include <TopTools_ListOfShape.hxx>
 class TopoDS_Wire;
 class TopoDS_Edge;
+class TopoDS_Face;
 class TopoDS_Shape;
 class BRepAlgo_BooleanOperation;
 class BRepAlgo_Fuse;
@@ -65,6 +66,28 @@ public:
   //! Junction points between edges of wire may be sharp,
   //! resulting curve of the resulting edge may be C0.
   Standard_EXPORT static TopoDS_Edge ConcatenateWireC0 (const TopoDS_Wire& Wire);
+
+  //! Method of wire conversion, calls BRepAlgo_Approx internally.
+  //! @param theWire
+  //!   Input Wire object.
+  //! @param theAngleTolerance
+  //!   Angle (in radians) defining the continuity of the wire: if two vectors
+  //!   differ by less than this angle, the result will be smooth (zero angle of
+  //!   tangent lines between curve elements).
+  //! @return
+  //!   The new TopoDS_Wire object consisting of edges each representing an arc
+  //!   of circle or a linear segment. The accuracy of conversion is defined
+  //!   as the maximal tolerance of edges in theWire.
+  static Standard_EXPORT TopoDS_Wire ConvertWire
+                                (const TopoDS_Wire&  theWire,
+                                 const Standard_Real theAngleTolerance,
+                                 const TopoDS_Face&  theFace);
+
+  //! Method of face conversion. The API corresponds to the method ConvertWire.
+  //! This is a shortcut for calling ConvertWire() for each wire in theFace.
+  static Standard_EXPORT TopoDS_Face ConvertFace
+                                (const TopoDS_Face&  theFace,
+                                 const Standard_Real theAngleTolerance);
   
   //! Checks if the  shape is "correct". If not, returns
   //! <Standard_False>, else returns <Standard_True>.
index df157f5b05c08ef3f1568558b3173ccfee0cffbb..7324cd7131cb2040ce85b7b98a9bd8fb688beca2 100644 (file)
 
 #include <BRep_Builder.hxx>
 #include <BRep_Tool.hxx>
+#include <BRepAdaptor_Curve.hxx>
 #include <BRepAdaptor_Surface.hxx>
+#include <BRepAlgo.hxx>
 #include <BRepAlgo_FaceRestrictor.hxx>
 #include <BRepBuilderAPI_MakeFace.hxx>
 #include <BRepFill_ListIteratorOfListOfOffsetWire.hxx>
 #include <BRepFill_OffsetWire.hxx>
+#include <BRepLib.hxx>
 #include <BRepOffsetAPI_MakeOffset.hxx>
 #include <BRepTopAdaptor_FClass2d.hxx>
 #include <Extrema_ExtPS.hxx>
 static Standard_Boolean AffichSpine = Standard_False;
 #endif
 
+static Standard_Boolean NeedsConvertion (const TopoDS_Wire& theWire)
+{
+  TopoDS_Iterator anIter (theWire);
+  for (; anIter.More(); anIter.Next())
+  {
+    const TopoDS_Edge& anEdge = TopoDS::Edge (anIter.Value());
+    BRepAdaptor_Curve aBAcurve (anEdge);
+    GeomAbs_CurveType aType = aBAcurve.GetType();
+    if (aType != GeomAbs_Line &&
+        aType != GeomAbs_Circle)
+      return Standard_True;
+  }
+
+  return Standard_False;
+}
+
+static TopoDS_Face ConvertFace (const TopoDS_Face&  theFace,
+                                const Standard_Real theAngleTolerance)
+{
+  TopAbs_Orientation anOr = theFace.Orientation();
+  TopoDS_Face aFace = theFace;
+  aFace.Orientation (TopAbs_FORWARD);
+
+  TopoDS_Face aNewFace = TopoDS::Face (aFace.EmptyCopied());
+  BRep_Builder aBB;
+  TopoDS_Iterator anIter (aFace);
+  for (; anIter.More(); anIter.Next())
+  {
+    TopoDS_Wire aWire = TopoDS::Wire (anIter.Value());
+    if (NeedsConvertion (aWire))
+    {
+      TopAbs_Orientation anOrOfWire = aWire.Orientation();
+      aWire = BRepAlgo::ConvertWire (aWire, theAngleTolerance, aFace);
+      BRepLib::BuildCurves3d (aWire);
+      aWire.Orientation (anOrOfWire);
+    }
+    aBB.Add (aNewFace, aWire);
+  }
+  aNewFace.Orientation (anOr);
+
+  return aNewFace;
+}
+
 //=======================================================================
 //function : BRepOffsetAPI_MakeOffset
 //purpose  : 
@@ -52,7 +98,8 @@ static Standard_Boolean AffichSpine = Standard_False;
 BRepOffsetAPI_MakeOffset::BRepOffsetAPI_MakeOffset()
   : myIsInitialized( Standard_False),
     myJoin(GeomAbs_Arc),
-    myIsOpenResult(Standard_False)
+    myIsOpenResult(Standard_False),
+    myIsToApprox(Standard_False)
 {
 }
 
@@ -83,6 +130,7 @@ void BRepOffsetAPI_MakeOffset::Init(const TopoDS_Face&     Spine,
   myIsInitialized = Standard_True;
   myJoin          = Join;
   myIsOpenResult  = IsOpenResult;
+  myIsToApprox = Standard_False;
   TopExp_Explorer exp;
   for (exp.Init(myFace,TopAbs_WIRE); exp.More();exp.Next()) {
     myWires.Append(exp.Current());
@@ -102,6 +150,7 @@ BRepOffsetAPI_MakeOffset::BRepOffsetAPI_MakeOffset(const TopoDS_Wire& Spine,
   myIsInitialized = Standard_True;
   myJoin = Join;
   myIsOpenResult  = IsOpenResult;
+  myIsToApprox = Standard_False;
 }
 
 //=======================================================================
@@ -116,6 +165,18 @@ void BRepOffsetAPI_MakeOffset::Init(const GeomAbs_JoinType Join,
   myIsOpenResult  = IsOpenResult;
 }
 
+//=======================================================================
+//function : SetApprox
+//purpose  : Set approximation flag
+//           for convertion input contours into ones consisting of
+//           2D circular arcs and 2D linear segments only
+//=======================================================================
+
+void BRepOffsetAPI_MakeOffset::SetApprox(const Standard_Boolean ToApprox)
+{
+  myIsToApprox = ToApprox;
+}
+
 //=======================================================================
 //function : BRepOffsetAPI_MakeOffset
 //purpose  : 
@@ -290,6 +351,46 @@ void BRepOffsetAPI_MakeOffset::Perform(const Standard_Real Offset,
 
   try
   {
+    if (myIsToApprox)
+    {
+      Standard_Real aTol = 0.01;
+      if (myFace.IsNull())
+      {
+        TopoDS_Face aFace;
+        Standard_Boolean OnlyPlane = Standard_True;
+        TopTools_ListIteratorOfListOfShape anItl (myWires);
+        for (; anItl.More(); anItl.Next())
+        {
+          BRepBuilderAPI_MakeFace aFaceMaker (TopoDS::Wire(anItl.Value()), OnlyPlane);
+          if (aFaceMaker.Error() == BRepBuilderAPI_FaceDone)
+          {
+            aFace = aFaceMaker.Face();
+            break;
+          }
+        }
+        for (anItl.Initialize(myWires); anItl.More(); anItl.Next())
+        {
+          const TopoDS_Wire& aWire = TopoDS::Wire(anItl.Value());
+          if (NeedsConvertion (aWire))
+          {
+            TopoDS_Wire aNewWire = BRepAlgo::ConvertWire (aWire, aTol, aFace);
+            BRepLib::BuildCurves3d (aNewWire);
+            aNewWire.Orientation (aWire.Orientation());
+            anItl.ChangeValue() = aNewWire;
+          }
+        }
+      }
+      else
+      {
+        myFace = ConvertFace (myFace, aTol);
+        BRepLib::BuildCurves3d (myFace);
+        myWires.Clear();
+        TopoDS_Iterator anIter (myFace);
+        for (; anIter.More(); anIter.Next())
+          myWires.Append (anIter.Value());
+      }
+    }
+    
     Standard_Integer i = 1;
     BRepFill_ListIteratorOfListOfOffsetWire itOW;
     TopoDS_Compound Res;
index 93e781b68f63c30c2f79595f1ee57635b9854cec..a9ea0bed5e75fa280963e452ed369ab1aeb7d93f 100644 (file)
@@ -69,6 +69,11 @@ public:
   //! Initialize the evaluation of Offseting.
   Standard_EXPORT void Init (const GeomAbs_JoinType Join = GeomAbs_Arc, const Standard_Boolean IsOpenResult = Standard_False);
   
+  //! Set approximation flag
+  //! for convertion input contours into ones consisting of
+  //! 2D circular arcs and 2D linear segments only.
+  Standard_EXPORT void SetApprox (const Standard_Boolean ToApprox);
+  
   //! Initializes the algorithm to construct parallels to the wire Spine.
   Standard_EXPORT void AddWire (const TopoDS_Wire& Spine);
   
@@ -102,6 +107,7 @@ private:
   Standard_Boolean myLastIsLeft;
   GeomAbs_JoinType myJoin;
   Standard_Boolean myIsOpenResult;
+  Standard_Boolean myIsToApprox;
   TopoDS_Face myFace;
   TopTools_ListOfShape myWires;
   BRepFill_ListOfOffsetWire myLeft;
index 3bc29731b6bf81ed9d75527141cdd9a4ab802fc0..54bb5d2dbc267e60e6080c2944536e973663d2e5 100644 (file)
@@ -1536,10 +1536,23 @@ Standard_Integer mkoffset(Draw_Interpretor& di,
   char name[100];
 
   BRepOffsetAPI_MakeOffset Paral;
+
+  Standard_Boolean ToApprox = Standard_False;
   GeomAbs_JoinType theJoinType = GeomAbs_Arc;
-  if (n >= 6 && strcmp(a[5], "i") == 0)
-    theJoinType = GeomAbs_Intersection;
-  Paral.Init(theJoinType);
+  
+  Standard_Integer anIndArg = 6;
+  if (n >= 6)
+  {
+    if (strcmp(a[5], "-approx") == 0)
+    {
+      ToApprox = Standard_True;
+      anIndArg++;
+    }
+  
+    if (n >= anIndArg && strcmp(a[anIndArg-1], "i") == 0)
+      theJoinType = GeomAbs_Intersection;
+  }
+  
   TopoDS_Shape Base = DBRep::Get(a[2],TopAbs_FACE);
 
   if ( Base.IsNull())
@@ -1559,6 +1572,7 @@ Standard_Integer mkoffset(Draw_Interpretor& di,
     Base.Orientation(TopAbs_FORWARD);
     Paral.Init(TopoDS::Face(Base), theJoinType);
   }
+  Paral.SetApprox (ToApprox);
 
   Standard_Real U, dU;
   Standard_Integer Nb;
@@ -1566,8 +1580,8 @@ Standard_Integer mkoffset(Draw_Interpretor& di,
   Nb = Draw::Atoi(a[3]);
 
   Standard_Real Alt = 0.;
-  if ( n == 7)
-    Alt = Draw::Atof(a[6]);
+  if (n > anIndArg)
+    Alt = Draw::Atof(a[anIndArg]);
 
   Standard_Integer Compt = 1;
 
@@ -1604,16 +1618,30 @@ Standard_Integer openoffset(Draw_Interpretor& di,
   char name[100];
 
   BRepOffsetAPI_MakeOffset Paral;
+  
+  Standard_Boolean ToApprox = Standard_False;
   GeomAbs_JoinType theJoinType = GeomAbs_Arc;
-  if (n == 6 && strcmp(a[5], "i") == 0)
-    theJoinType = GeomAbs_Intersection;
-  Paral.Init(theJoinType, Standard_True);
+  
+  Standard_Integer anIndArg = 6;
+  if (n >= 6)
+  {
+    if (strcmp(a[5], "-approx") == 0)
+    {
+      ToApprox = Standard_True;
+      anIndArg++;
+    }
+  
+    if (n >= anIndArg && strcmp(a[anIndArg-1], "i") == 0)
+      theJoinType = GeomAbs_Intersection;
+  }
+  
   TopoDS_Shape Base = DBRep::Get(a[2] ,TopAbs_FACE);
 
   if ( Base.IsNull())
   {
     Base = DBRep::Get(a[2], TopAbs_WIRE);
     if (Base.IsNull()) return 1;
+    Paral.Init(theJoinType, Standard_True);
     Paral.AddWire(TopoDS::Wire(Base));
   }
   else
@@ -1621,6 +1649,7 @@ Standard_Integer openoffset(Draw_Interpretor& di,
     Base.Orientation(TopAbs_FORWARD);
     Paral.Init(TopoDS::Face(Base), theJoinType, Standard_True);
   }
+  Paral.SetApprox (ToApprox);
 
   Standard_Real U, dU;
   Standard_Integer Nb;
@@ -1761,6 +1790,72 @@ Standard_Integer edgeintersector(Draw_Interpretor& di,
 
 }
 
+//=================================================================================
+//function : arclinconvert
+//purpose  : Convert a single face to a face with contour made of arcs and segments
+//=================================================================================
+
+static Standard_Integer arclinconvert (Draw_Interpretor& /*dout*/, Standard_Integer n, const char** a)
+{
+  // Check the command arguments
+  if (n < 3) {
+    std::cout<<"Error: "<<a[0]<<" - invalid number of arguments"<<std::endl;
+    std::cout<<"Usage: type help "<<a[0]<<std::endl;
+    return 1; //TCL_ERROR
+  }
+
+  //read shape
+  const TopoDS_Shape aShape = DBRep::Get(a[2]);
+  if (aShape.IsNull()) {
+    std::cout<<"Error: "<<a[2]<<" is null"<<std::endl;
+    return 1; //TCL_ERROR
+  }
+
+  TopAbs_ShapeEnum aType = aShape.ShapeType();
+  if (aType != TopAbs_WIRE &&
+      aType != TopAbs_FACE)
+  {
+    std::cout<<"Error: "<<a[2]<<" is neither wire no face"<<std::endl;
+    return 1; //TCL_ERROR
+  }
+
+  //read tolerance
+  Standard_Real aTol = 0.01;
+  if (n > 3)
+    aTol = Draw::Atof(a[3]);
+  std::cout<<"Info: tolerance is set to "<<aTol<<std::endl;
+
+  TopoDS_Shape aResult;
+  
+  if (aType == TopAbs_WIRE)
+  {
+    Standard_Boolean OnlyPlane = Standard_False;
+    BRepBuilderAPI_MakeFace aFaceMaker (TopoDS::Wire(aShape), OnlyPlane);
+    if (aFaceMaker.Error() != BRepBuilderAPI_FaceDone)
+    {
+      std::cout<<"Error: failed to find a face for the wire "<<a[2]<<std::endl;
+      return 1; //TCL_ERROR
+    }
+    TopoDS_Face aFace = aFaceMaker.Face();
+    TopoDS_Iterator anIter (aFace);
+    TopoDS_Wire aWire = TopoDS::Wire (anIter.Value());
+    aResult = BRepAlgo::ConvertWire (aWire, aTol, aFace);
+  }
+  else if (aType == TopAbs_FACE)
+  {
+    TopoDS_Face aFace = TopoDS::Face(aShape);
+    aResult = BRepAlgo::ConvertFace (aFace, aTol);
+  }
+
+  if (aResult.IsNull()) {
+    std::cout<<"Error: could not convert "<<a[2]<<std::endl;
+    return 1; //TCL_ERROR
+  }
+
+  DBRep::Set(a[1], aResult);
+  return 0; //TCL_OK
+}
+
 //=======================================================================
 //function : concatC0wire
 //purpose  : 
@@ -1914,12 +2009,12 @@ void  BRepTest::CurveCommands(Draw_Interpretor& theCommands)
     profile2d,g);
 
   theCommands.Add("mkoffset",
-    "mkoffset result face/compound of wires  nboffset stepoffset [jointype(a/i) [alt]]",__FILE__,
-    mkoffset);
+    "mkoffset result face/compound of wires  nboffset stepoffset [-approx] [jointype(a/i) [alt]]",__FILE__,
+    mkoffset,g);
 
   theCommands.Add("openoffset",
-    "openoffset result face/wire nboffset stepoffset [jointype(a/i)]",__FILE__,
-    openoffset);
+    "openoffset result face/wire nboffset stepoffset [-approx] [jointype(a/i)]",__FILE__,
+    openoffset,g);
 
   theCommands.Add("mkedge",
     "mkedge edge curve [surface] [pfirst plast] [vfirst [pfirst] vlast [plast]] ",__FILE__,
@@ -1974,6 +2069,12 @@ void  BRepTest::CurveCommands(Draw_Interpretor& theCommands)
     "reducepcurves shape1 shape2 ...",
     reducepcurves, g);
 
+  theCommands.Add("arclinconvert",
+    "arclinconvert result wire/face [tol]",
+    __FILE__,
+    arclinconvert,
+    g);
+
   theCommands.Add("concatC0wire",
     "concatC0wire result wire",
     __FILE__,
index 2ea8287e4ca55c3c74ad045d00088aba23ec000c..29fc777627e998b716c3a39d350678d2df071c56 100644 (file)
@@ -1,5 +1,7 @@
 Geom2dConvert.cxx
 Geom2dConvert.hxx
+Geom2dConvert_ApproxArcsSegments.cxx
+Geom2dConvert_ApproxArcsSegments.hxx
 Geom2dConvert_ApproxCurve.cxx
 Geom2dConvert_ApproxCurve.hxx
 Geom2dConvert_BSplineCurveKnotSplitting.cxx
@@ -8,3 +10,6 @@ Geom2dConvert_BSplineCurveToBezierCurve.cxx
 Geom2dConvert_BSplineCurveToBezierCurve.hxx
 Geom2dConvert_CompCurveToBSplineCurve.cxx
 Geom2dConvert_CompCurveToBSplineCurve.hxx
+Geom2dConvert_PPoint.cxx
+Geom2dConvert_PPoint.hxx
+Geom2dConvert_SequenceOfPPoint.hxx
diff --git a/src/Geom2dConvert/Geom2dConvert_ApproxArcsSegments.cxx b/src/Geom2dConvert/Geom2dConvert_ApproxArcsSegments.cxx
new file mode 100644 (file)
index 0000000..4dd6dfc
--- /dev/null
@@ -0,0 +1,911 @@
+// Created: 2009-01-21
+// 
+// Copyright (c) 2009-2013 OPEN CASCADE SAS
+// 
+// This file is part of commercial software by OPEN CASCADE SAS, 
+// furnished in accordance with the terms and conditions of the contract 
+// and with the inclusion of this copyright notice. 
+// This file or any part thereof may not be provided or otherwise 
+// made available to any third party. 
+// 
+// No ownership title to the software is transferred hereby. 
+// 
+// OPEN CASCADE SAS makes no representation or warranties with respect to the 
+// performance of this software, and specifically disclaims any responsibility 
+// for any damages, special or consequential, connected with its use. 
+
+#include <Geom2dConvert_ApproxArcsSegments.hxx>
+
+#include <Adaptor2d_Curve2d.hxx>
+#include <ElCLib.hxx>
+#include <GCE2d_MakeArcOfCircle.hxx>
+#include <GCE2d_MakeSegment.hxx>
+#include <GCPnts_QuasiUniformDeflection.hxx>
+#include <Geom2d_Circle.hxx>
+#include <Geom2d_Line.hxx>
+#include <Geom2d_TrimmedCurve.hxx>
+#include <NCollection_IncAllocator.hxx>
+#include <Precision.hxx>
+#include <Standard_Version.hxx>
+#include <gp.hxx>
+#include <gp_Ax2d.hxx>
+#include <gp_Lin2d.hxx>
+
+static const Standard_Integer MAXPOINTS         = 100;
+static const Standard_Real MyCurvatureTolerance = 0.0001;
+
+static Standard_Boolean checkContinuity   (const Handle(Geom2d_Curve)& theCurve1,
+                                           const Handle(Geom2d_Curve)& theCurve2,
+                                           const Standard_Real      theAnglTol);
+
+static Geom2dConvert_PPoint getParameter  (const gp_XY&             theXY1,
+                                           const Standard_Real      theFirstPar,
+                                           const Standard_Real      theLastPar,
+                                           const Adaptor2d_Curve2d& theCurve);
+
+static Standard_Boolean isInflectionPoint (const Standard_Real      theParam,
+                                           const Adaptor2d_Curve2d& theCurve);
+
+static Standard_Boolean isInflectionPoint (const Standard_Real         theParam,
+                                           const Geom2dConvert_PPoint& theFirstInf,
+                                           const Adaptor2d_Curve2d&    theCurve,
+                                           const Standard_Real         theAnglTol);
+
+
+//=======================================================================
+//function : Geom2dConvert_ApproxArcsSegments()
+//purpose  : Constructor
+//=======================================================================
+
+Geom2dConvert_ApproxArcsSegments::Geom2dConvert_ApproxArcsSegments
+                        (const Adaptor2d_Curve2d&                theCurve,
+                         const Standard_Real                     theTolerance,
+                         const Standard_Real                     theAngleTol)
+  : myCurve             (theCurve),
+    myAlloc             (new NCollection_IncAllocator(4000)),
+    myTolerance         (theTolerance),
+    myAngleTolerance    (theAngleTol),
+    mySeqParams         (myAlloc),
+    myStatus            (StatusNotDone)
+{
+  myExt[0] = Geom2dConvert_PPoint(myCurve.FirstParameter(), myCurve);
+  myExt[1] = Geom2dConvert_PPoint(myCurve.LastParameter(), myCurve);
+
+  switch (myCurve.GetType())
+  {
+    case GeomAbs_Line:
+    {
+      // Create a single line segment. 
+      const Standard_Real aDist = myExt[0].Dist(myExt[1]);
+      if (aDist > Precision::Confusion()) {
+        const gp_Ax2d anAx2d(myExt[0].Point(), gp_Vec2d(myExt[0].Point(),
+                                                        myExt[1].Point()));
+        const Handle(Geom2d_Line) aLine = new Geom2d_Line(anAx2d);
+        mySeqCurves.Append(new Geom2d_TrimmedCurve(aLine, 0., aDist));
+        myStatus = StatusOK;
+      }
+    }
+    break;
+    case GeomAbs_Circle:
+    {
+      // Create a couple of arcs of equal size.
+      const Geom2dConvert_PPoint aPP(.5 *(myExt[0].Parameter() +
+                                          myExt[1].Parameter()), myCurve);
+      Handle(Geom2d_Curve) aCurve = makeCircle (myExt[0], aPP);
+      if (aCurve.IsNull() == Standard_False) {
+        mySeqCurves.Append(aCurve);
+        aCurve = makeCircle (aPP, myExt[1]);
+        if (aCurve.IsNull() == Standard_False)
+          mySeqCurves.Append(aCurve);
+      }
+    }
+    break;
+    default:
+      makeFreeform();
+  }
+
+  // Check status of the calculation
+  if (myStatus == StatusNotDone) {
+    if (mySeqCurves.IsEmpty() == Standard_False)
+      myStatus = StatusOK;
+    else {
+      //std::cout << "GeomConv2d_Approx: no geometry converted." << std::endl;
+      myStatus = StatusError;
+    }
+  }
+}
+
+//=======================================================================
+//function : makeCircle
+//purpose  : method for creation of circle
+//=======================================================================
+
+Handle(Geom2d_Curve) Geom2dConvert_ApproxArcsSegments::makeCircle
+                                (const Geom2dConvert_PPoint& theFirst,
+                                 const Geom2dConvert_PPoint& theLast) const
+{
+  Handle(Geom2d_Curve) aResult;
+  gp_Pnt2d aPointM (0.0,0.0);
+  const Standard_Real aParaM = (theFirst.Parameter() + theLast.Parameter()) *.5;
+  myCurve.D0(aParaM, aPointM);
+  GCE2d_MakeArcOfCircle aMakeArc1(theFirst.Point(), aPointM, theLast.Point());
+
+  if (aMakeArc1.IsDone())
+    aResult = aMakeArc1.Value();
+  //else
+    //std::cout << "makeCircle(): Circle not built" << std::endl;
+  return aResult;
+}
+
+//=======================================================================
+//function : makeArc
+//purpose  : creation arcs by two points and derivative in the first point
+///        : parameter isFirst specified direction of the arc.
+//=======================================================================
+
+Standard_Boolean Geom2dConvert_ApproxArcsSegments::makeArc
+                (const Geom2dConvert_PPoint&    theParam1,
+                 Geom2dConvert_PPoint&          theParam2,
+                 const Standard_Boolean         isFirst,
+                 Handle(Geom2d_TrimmedCurve)&   theCurve) const
+{
+  const gp_XY aP1  (theParam1.Point());
+  const gp_XY aP2  (theParam2.Point());
+  const gp_XY aVec (isFirst? theParam1.D1() : -theParam1.D1());
+
+  // Detect the sense (CCW means positive)
+  const gp_XY aDelta = aP2 - aP1;
+  Standard_Real aSense = aVec ^ aDelta;
+  if (aSense > Precision::Angular())
+    aSense = 1.;
+  else if (aSense < -Precision::Angular())
+    aSense = -1.;
+  else {
+    //std::cout << "makeArc(): Arc Not Built" << std::endl;
+    return Standard_False;
+  }
+
+  // Find the centre of the circle
+  const gp_XY         aMiddle = (aP2 + aP1) * 0.5;
+  const Standard_Real prodP1V = aP1 * aVec;
+  const Standard_Real prodDeM = aDelta * aMiddle;
+  const Standard_Real vprodVD = aVec ^ aDelta;
+  const Standard_Real aResolution = gp::Resolution();
+
+  if (vprodVD < -aResolution || vprodVD > aResolution) {
+    const gp_Pnt2d aCenter((prodP1V * aDelta.Y() - prodDeM * aVec.Y())/vprodVD,
+                           (prodDeM * aVec.X() - prodP1V * aDelta.X())/vprodVD);
+    const Standard_Real aRad =
+        (aCenter.Distance(aP1) + aCenter.Distance(aP2)) * 0.5;
+    const gp_Ax22d ax22d (aCenter, gp_Dir2d(1., 0.), gp_Dir2d(0., 1.));
+    const gp_Circ2d aCir (ax22d, aRad);
+    const Handle(Geom2d_Circle) Circ = new Geom2d_Circle(aCir);
+
+      //calculation parameters first and last points of arc.
+    Standard_Real anAlpha1, anAlpha2;
+    if (isFirst) {
+      anAlpha1 = ElCLib::Parameter(aCir, aP1);
+      anAlpha2 = ElCLib::Parameter(aCir, aP2);
+    } else {
+      anAlpha1 = ElCLib::Parameter(aCir, aP2);
+      anAlpha2 = ElCLib::Parameter(aCir, aP1);
+      aSense = -aSense;
+    }
+
+    if (fabs (anAlpha1 - anAlpha2) < 1e-100)
+      // very small value, just to avoid exact match
+      return Standard_False;
+
+    // Reverse the circle if the sense is negative
+    if (aSense < 0.) {
+      anAlpha1 = Circ->ReversedParameter(anAlpha1);
+      anAlpha2 = Circ->ReversedParameter(anAlpha2);
+      Circ->Reverse();
+    }
+    theCurve = new Geom2d_TrimmedCurve(Circ, anAlpha1, anAlpha2);
+    // Correct the direction in the opposite point
+    const gp_XY aRadV = theParam2.Point() - aCenter.XY();
+    theParam2.SetD1(gp_XY(- aRadV.Y() * aSense, aRadV.X() * aSense));
+    return Standard_True;
+  }
+
+  // Algorithm failed, possibly because aVec is normal to the chorde
+  return Standard_False;
+}
+
+//=======================================================================
+//function : makeLine
+//purpose  : method for creation of line
+//=======================================================================
+
+Handle(Geom2d_TrimmedCurve) Geom2dConvert_ApproxArcsSegments::makeLine
+                                (Geom2dConvert_PPoint&     theFirst,
+                                 Geom2dConvert_PPoint&     theLast,
+                                 const Standard_Boolean isCheck) const
+{
+  Handle(Geom2d_TrimmedCurve) aResult;
+
+  gp_XY aSlope = theLast.Point() - theFirst.Point();
+  if (fabs(aSlope.SquareModulus()) < gp::Resolution())
+     return aResult;
+  gp_Dir2d aDirLine(aSlope);
+
+  if (isCheck) {
+    if (theFirst.D1().SquareModulus() < gp::Resolution() ||
+        theLast.D1().SquareModulus() < gp::Resolution())
+      return aResult;
+
+    // Angular continuity (G1) is only checked when the end of the line is not
+    // on the extremity of the curve
+    Standard_Real absAngle[2] = { 0., 0. };
+    if (theFirst != myExt[0]) {
+      const Standard_Real anAng = aDirLine.Angle(theFirst.D1());
+      absAngle[0] = (anAng > 0. ? anAng : -anAng);
+    }
+    if (theLast != myExt[1]) {
+      const Standard_Real anAng = aDirLine.Angle(theLast.D1());
+      absAngle[1] = (anAng > 0. ? anAng : -anAng);
+    }
+
+    // if the derivatives in the end points differ from the derivative line
+    // more than value of the specified continuity tolerance
+    // then a biarc should be build instead of a line.
+    const Standard_Real aContTolerance = ::Max(myAngleTolerance, 0.01);
+    if (absAngle[0] > aContTolerance || absAngle[1] > aContTolerance) {
+      //std::cout << "makeLine(): Line not built" << std::endl;
+      return aResult;
+    }
+  } // end if (isCheck)
+
+  //bulding segment of line
+  GCE2d_MakeSegment aMakeSeg (theFirst.Point(), theLast.Point());
+  if (aMakeSeg.IsDone()) {
+    Handle(Geom2d_TrimmedCurve) aCurve = aMakeSeg.Value();
+    if (checkCurve (aCurve, theFirst.Parameter(), theLast.Parameter())) {
+      aResult = aCurve;
+      // correct the derivatives fields in both arguments
+      const gp_XY aNewD1 (theLast.Point() - theFirst.Point());
+      theFirst.SetD1(aNewD1);
+      theLast.SetD1(aNewD1);
+    }
+  }
+  //else
+    //std::cout << "makeLine(): Line not built" << std::endl;
+  return aResult;
+}
+
+//=======================================================================
+//function : makeFreeform
+//purpose  : get a sequence of Geom curves from one curve
+//=======================================================================
+
+Standard_Boolean Geom2dConvert_ApproxArcsSegments::makeFreeform()
+{
+  Geom2dConvert_SequenceOfPPoint seqParamPoints(myAlloc);
+  Geom2dConvert_PPoint*  aPrevParam = &myExt[0];
+
+  //calculation of the inflection points.
+  getLinearParts(seqParamPoints);
+  const Standard_Boolean isNoInfPoints = seqParamPoints.IsEmpty();
+
+  TColGeom2d_SequenceOfCurve aSeqLinearParts;
+  Standard_Boolean isDone (Standard_True);
+  Standard_Integer i;
+  for (i = 1; i < seqParamPoints.Length(); i += 2)
+  {
+    Handle(Geom2d_Curve) aLineCurve;
+    Geom2dConvert_PPoint& aParam0 = seqParamPoints.ChangeValue(i);
+    Geom2dConvert_PPoint& aParam1 = seqParamPoints.ChangeValue(i+1);
+    if (aParam0 != aParam1)
+      //linear part of the curve lies between odd and even values of i.
+      //parameters from parameter's sequence.
+      aLineCurve = makeLine (aParam0, aParam1, Standard_False);
+    aSeqLinearParts.Append(aLineCurve);
+  }
+
+  for (i = 1; i < seqParamPoints.Length(); i += 2)
+  {
+    //approximation for non-linear part preceding the linear part
+    if (seqParamPoints(i) != * aPrevParam) {
+      const Standard_Integer aLastInd = mySeqCurves.Length();
+      isDone = makeApproximation (* aPrevParam, seqParamPoints(i));
+      if (isDone && aLastInd && mySeqCurves.Length() > aLastInd)
+        isDone = checkContinuity(mySeqCurves.Value(aLastInd),
+                                 mySeqCurves.Value(aLastInd+1),
+                                 myAngleTolerance);
+      if (!isDone) {
+        myStatus = StatusError;
+        break;
+      }
+    }
+
+    const Handle(Geom2d_Curve)& aCurve = aSeqLinearParts.Value((i+1)/2);
+    if (aCurve.IsNull() == Standard_False)
+      mySeqCurves.Append(aCurve);
+    else {
+      Geom2dConvert_PPoint& aParam0 = seqParamPoints.ChangeValue(i);
+      Geom2dConvert_PPoint& aParam1 = seqParamPoints.ChangeValue(i+1);
+      const Standard_Integer aLastInd = mySeqCurves.Length();
+      isDone = makeApproximation (aParam0, aParam1);
+      if (isDone && aLastInd && mySeqCurves.Length() > aLastInd)
+        isDone = checkContinuity(mySeqCurves.Value(aLastInd),
+                                 mySeqCurves.Value(aLastInd+1),
+                                 myAngleTolerance);
+
+      if (!isDone) {
+        myStatus = StatusError;
+        //std::cout << "makeOther: Line not built" << std::endl;
+        break;
+      }
+    }
+    aPrevParam = &seqParamPoints(i+1);
+  }
+
+  //approximation for non-linear part following the last linear part
+  if (isDone && (* aPrevParam != myExt[1]))
+  {
+    // Case of a closed edge like an ellipse
+    if (isNoInfPoints &&
+        (myExt[0].Point() - myExt[1].Point()).Modulus() < myTolerance)
+    {
+      Geom2dConvert_PPoint aPPoint(0.5 * (myExt[0].Parameter() +
+                                          myExt[1].Parameter()), myCurve);
+      isDone = makeApproximation (myExt[0], aPPoint);
+      if (isDone)
+        isDone = makeApproximation (aPPoint, myExt[1]);
+    } else {
+      isDone = makeApproximation (* aPrevParam, myExt[1]);
+    }
+    if (!isDone) {
+      myStatus = StatusError;
+      //std::cout << "makeOther: Line not built" << std::endl;
+    }
+  }
+
+  return (mySeqCurves.Length() && myStatus != StatusError);
+}
+
+//=======================================================================
+//function : getLinearParts
+//purpose  : method for geting inflection points
+//=======================================================================
+
+void Geom2dConvert_ApproxArcsSegments::getLinearParts (Geom2dConvert_SequenceOfPPoint& theSeqPar)
+{
+  Standard_Integer i;
+  // Fill the sequences with values along the curve
+  mySeqParams.Clear();
+  Adaptor2d_Curve2d& myCurveMut = const_cast<Adaptor2d_Curve2d&>(myCurve);
+  GCPnts_QuasiUniformDeflection aQUDefAlgo (myCurveMut, myTolerance * 0.5);
+  Standard_Boolean isUniformDone = aQUDefAlgo.IsDone();
+
+  gp_XY aLastPnt(myExt[0].Point());
+  if (isUniformDone) {
+    for (i = 1; i <= aQUDefAlgo.NbPoints(); i++) {
+      const Geom2dConvert_PPoint aPP (aQUDefAlgo.Parameter(i), myCurve);
+      mySeqParams.Append(aPP);
+      aLastPnt = aPP.Point();
+    }
+  } else {
+    const Standard_Real aParamStep =
+      (myExt[1].Parameter() - myExt[0].Parameter()) / MAXPOINTS;
+    for (i = 1; i <= MAXPOINTS; i++) {
+      const Standard_Real aParam = myExt[0].Parameter() + aParamStep * i;
+      const Geom2dConvert_PPoint aPP (aParam, myCurve);
+      mySeqParams.Append(aPP);
+      aLastPnt = aPP.Point();
+    }
+  }
+
+  //check if the curve may be linearised
+  gp_XY aDir = myExt[1].Point() - myExt[0].Point();
+  const Standard_Real aMod2 = aDir.SquareModulus();
+  if (aMod2 > Precision::Confusion())
+  {
+    Standard_Boolean isLinear = Standard_True;
+    aDir /= sqrt(aMod2);
+    for (i = 1; i <= mySeqParams.Length(); i++) {
+      // Distance from point "i" to the segment between two extremities
+      const Standard_Real aDist = aDir ^ (mySeqParams(i).Point() -
+                                          myExt[0].Point());
+      if (aDist > myTolerance * 0.5 || aDist < -myTolerance * 0.5) {
+        isLinear = Standard_False;
+        break;
+      }
+    }
+    if (isLinear) {
+      theSeqPar.Append(myExt[0]);
+      theSeqPar.Append(myExt[1]);
+      return;
+    }
+  }
+
+  //check if point for First Parameter is inflection point.
+  Standard_Integer indStartLinear (0);
+  Geom2dConvert_PPoint aLastInflParam  = myExt[0];
+  Geom2dConvert_PPoint aFirstInflParam = myExt[0];
+
+  // Getting further inflection points with step by parameter.
+  // The point with index 1 is the same as myExt[0]
+  for (i = 1; i <= mySeqParams.Length(); i++)
+  {
+    const Geom2dConvert_PPoint& aCurParam = mySeqParams(i);
+    if (indStartLinear) {
+      Standard_Boolean isStillInflectionFirst =
+        isInflectionPoint (aFirstInflParam.Parameter(), aCurParam,
+                           myCurve, myAngleTolerance);
+      if (isInflectionPoint (aCurParam.Parameter(), aFirstInflParam,
+                             myCurve, myAngleTolerance))
+      {
+        aLastInflParam = mySeqParams(i);
+        while (isStillInflectionFirst == Standard_False) {
+          if (++indStartLinear >= i) {
+            indStartLinear = 0;
+            break;
+          }
+          aFirstInflParam = mySeqParams(indStartLinear);
+          isStillInflectionFirst =
+            isInflectionPoint (aFirstInflParam.Parameter(), aCurParam,
+                               myCurve, myAngleTolerance);
+        }
+      } else {
+        // Add the interval in the output sequence
+        // The interval is added only if it is more than 10 times the tolerance
+        aLastInflParam = findInflection (aLastInflParam, aCurParam);
+        if (!isInflectionPoint (aFirstInflParam.Parameter(), aLastInflParam,
+                                myCurve, myAngleTolerance))
+        {
+          aFirstInflParam = findInflection (aLastInflParam, aFirstInflParam);
+        }
+        const Standard_Real aDist((aFirstInflParam.Point() -
+                                   aLastInflParam.Point()).Modulus());
+        if (aFirstInflParam.Parameter() < aLastInflParam.Parameter() &&
+            aDist > 10 * myTolerance)
+        {
+          theSeqPar.Append(aFirstInflParam);
+          theSeqPar.Append(aLastInflParam);
+        }
+        indStartLinear = 0;
+      }
+    } else
+      if (isInflectionPoint (aCurParam.Parameter(), myCurve)) {
+        aLastInflParam = aCurParam;
+        if (i > 1)
+          aFirstInflParam = findInflection (aCurParam, mySeqParams(i-1));
+        indStartLinear = i;
+      }
+  }
+
+  const Standard_Real aDist((aFirstInflParam.Point() -
+                             myExt[1].Point()).Modulus());
+  if (indStartLinear && aDist > 10 * myTolerance)
+  {
+    theSeqPar.Append(aFirstInflParam);
+    theSeqPar.Append(myExt[1]);
+  }
+}
+
+//=======================================================================
+//function : findInflection
+//purpose  : Dichotomic search of the boundary of inflection interval, between
+//           two parameters on the Curve
+//=======================================================================
+
+Geom2dConvert_PPoint Geom2dConvert_ApproxArcsSegments::findInflection
+                                (const Geom2dConvert_PPoint& theParamIsInfl,
+                                 const Geom2dConvert_PPoint& theParamNoInfl) const
+{
+  Standard_Real aLower  (theParamIsInfl.Parameter());
+  Standard_Real anUpper (theParamNoInfl.Parameter());
+  Standard_Real aTest(0.);
+  for (Standard_Integer i = 0; i < 3; i++) {    // 3 iterations
+    aTest = (aLower + anUpper) * 0.5;
+    if (isInflectionPoint (aTest, theParamIsInfl, myCurve, myAngleTolerance))
+      aLower = aTest;
+    else
+      anUpper = aTest;
+  }
+  return Geom2dConvert_PPoint(aTest, myCurve);
+}
+
+//=======================================================================
+//function : makeApproximation
+//purpose  : make approximation non-linear part of the other curve
+//=======================================================================
+
+Standard_Boolean Geom2dConvert_ApproxArcsSegments::makeApproximation
+                                (Geom2dConvert_PPoint& theFirstParam,
+                                 Geom2dConvert_PPoint& theLastParam)
+{
+  // if difference between parameters is less than Precision::PConfusion
+  //approximation was not made.
+  Standard_Boolean isDone = Standard_False;
+  if (theLastParam != theFirstParam) {
+    const Standard_Real aDistance =
+      (theFirstParam.Point() - theLastParam.Point()).Modulus();
+    if (aDistance < myTolerance)
+    {
+      const Handle(Geom2d_Curve) aCurve = makeLine(theFirstParam, theLastParam,
+                                                   Standard_True);
+      isDone = !aCurve.IsNull();
+      if (isDone && mySeqCurves.Length())
+        isDone = checkContinuity(mySeqCurves.Last(), aCurve, myAngleTolerance);
+      if (isDone || aDistance < Precision::Confusion()) {
+        mySeqCurves.Append(aCurve);
+        return isDone;
+      }
+    }
+    //calculate biarc
+    isDone = calculateBiArcs (theFirstParam, theLastParam);
+
+    // if biarc was not calculated calculation is repeated on half the interval.
+    if (!isDone)
+    {
+      Geom2dConvert_PPoint aParaM
+        (theFirstParam.Parameter() +
+         (theLastParam.Parameter() - theFirstParam.Parameter()) * 0.55,
+         myCurve);
+      isDone = makeApproximation (theFirstParam, aParaM);
+      if (isDone)
+        isDone = makeApproximation (aParaM, theLastParam);
+    }
+  }
+  return isDone;
+}
+
+//=======================================================================
+//function : calculateBiArcs
+//purpose  : method for calculation of the biarcs.
+//=======================================================================
+
+Standard_Boolean Geom2dConvert_ApproxArcsSegments::calculateBiArcs
+                                        (Geom2dConvert_PPoint& theFirstParam,
+                                         Geom2dConvert_PPoint& theLastParam)
+{
+  const Standard_Real aResolution = gp::Resolution();
+
+  if (theFirstParam.D1().SquareModulus() < aResolution ||
+      theLastParam.D1().SquareModulus()  < aResolution)
+  {
+    //std::cout << "calculateBiArcs(): bad initial data" << std::endl;
+    return Standard_False;
+  }
+  const gp_XY aPnt[2] = {
+    theFirstParam.Point(),
+    theLastParam.Point()
+  };
+  gp_Dir2d aDir[2] = {
+    theFirstParam.D1(),
+    theLastParam.D1()
+  };
+
+  // Try to approximate the curve by a single arc. The criterion for that is
+  // more rigid if the curve is the entire input curve
+  // (possible pb. connecting with other boundaries)
+  const gp_Vec2d aDelta (aPnt[1] - aPnt[0]);
+  Standard_Real anAngle1 = aDelta.Angle(gp_Vec2d(aDir[0]));
+  if (anAngle1 < 0.)
+    anAngle1 = -anAngle1;
+  Standard_Real anAngle2 = aDelta.Angle(gp_Vec2d(aDir[1]));
+  if (anAngle2 < 0.)
+    anAngle2 = -anAngle2;
+
+  //in the case when two angles are equal one arc can be built.
+  Standard_Real anAngleThreshold (Precision::Angular() * 10.);
+  if (theFirstParam != myExt[0] || theLastParam != myExt[1])
+    anAngleThreshold = myAngleTolerance * 0.1;
+  if (fabs(anAngle1 - anAngle2) < anAngleThreshold)
+  {
+    Handle(Geom2d_TrimmedCurve) aCurve;
+    // protect the theLastParam from modification of D1, when
+    // the created arc is rejected.
+    Geom2dConvert_PPoint aLastParam (theLastParam);
+    if (!makeArc (theFirstParam, aLastParam, Standard_True, aCurve))
+      return Standard_False;
+    if (checkCurve(aCurve, theFirstParam.Parameter(), aLastParam.Parameter()))
+    {
+      theLastParam = aLastParam;
+      mySeqCurves.Append(aCurve);
+      return Standard_True;
+    }
+  }
+
+  // if one arc was not built or for other cases biarc will be built
+  // method for building biarc was taken from article Ahmad H. Nasri et al.
+  // "A Recursive Subdivision Algorithm for Piecewise Circular Spline",
+  // Computer Graphics Forum, 2001.
+
+  // definition of point of intersection two tangent directions in the points
+  // corresponding FirstParameter and LastParameter.
+  aDir[1].Reverse();
+
+  // Direct calculation of intersection point, replaces a class call below
+  const Standard_Real aProd [3] = {
+    aPnt[0] ^ aDir[0].XY(),
+    aPnt[1] ^ aDir[1].XY(),
+    aDir[1] ^ aDir[0].XY()
+  };
+  gp_XY aIntPoint((aProd[0] * aDir[1].X() - aProd[1] * aDir[0].X()) / aProd[2],
+                  (aProd[0] * aDir[1].Y() - aProd[1] * aDir[0].Y()) / aProd[2]);
+  const gp_XY aDiff[2] = {
+    aIntPoint - aPnt[0],
+    aIntPoint - aPnt[1]
+  };
+  if (aDiff[0] * aDir[0].XY() < 0. || aDiff[1] * aDir[1].XY() < 0.)
+  {
+    return Standard_False;
+  }
+
+  //calculation middle point for building biarc.
+  const Standard_Real ad1 = aDiff[0].Modulus();
+  const Standard_Real ad2 = aDiff[1].Modulus();
+  const Standard_Real ad12 = aDelta.Magnitude();
+
+  const Standard_Real aB1 = ad1 / (ad1 + ad2);
+  if (fabs(aB1 - 0.5) < 0.0001)
+    return Standard_False;
+
+  gp_XY aXY[2] = {
+    aPnt[0] + aDir[0].XY() * ad12 * ad1 / (ad12 + ad1 + ad2),
+    aPnt[1] + aDir[1].XY() * ad12 * ad2 / (ad12 + ad1 + ad2)
+  };
+
+  const gp_XY aXYmidArc  (aXY[0] + aB1*(aXY[1]  - aXY[0]));
+  Geom2dConvert_PPoint aParamMidArc =
+    getParameter (aXYmidArc, theFirstParam.Parameter(),
+                  theLastParam.Parameter(), myCurve);
+
+  //building first arc from biarc.
+  Handle(Geom2d_TrimmedCurve) aCurve1, aCurve2;
+  if (!makeArc (theFirstParam, aParamMidArc, Standard_True, aCurve1))
+    return Standard_False;
+
+  if (!checkCurve (aCurve1, theFirstParam.Parameter(),
+                   aParamMidArc.Parameter()))
+    return Standard_False;
+
+  //building second arc from biarc.
+  if (makeArc (theLastParam, aParamMidArc, Standard_False, aCurve2)) {
+    if (checkCurve (aCurve2, aParamMidArc.Parameter(),
+                    theLastParam.Parameter())) {
+      mySeqCurves.Append(aCurve1);
+      mySeqCurves.Append(aCurve2);
+      return Standard_True;
+    }
+  }
+  return Standard_False;
+}
+
+//=======================================================================
+//function : calculateLines
+//purpose  : method for calculation of the linear interpolation.
+//=======================================================================
+
+Standard_Boolean Geom2dConvert_ApproxArcsSegments::calculateLines
+                                        (Geom2dConvert_PPoint& theFirstParam,
+                                         Geom2dConvert_PPoint& theLastParam)
+{
+  Geom2dConvert_PPoint* aPrevParam = &theFirstParam;
+  for (int i = 1; i <= mySeqParams.Length(); i++) 
+  {
+    Geom2dConvert_PPoint& aCurParam = mySeqParams.ChangeValue(i);
+    if (aCurParam.Parameter() < (*aPrevParam).Parameter()) {
+      continue;
+    }
+    if (aCurParam.Parameter() > theLastParam.Parameter()) {
+      break;
+    }
+
+    // build line segment
+    if (aCurParam != *aPrevParam)
+    {
+      const Standard_Real aDistance = 
+        (aCurParam.Point() - (*aPrevParam).Point()).Modulus();
+      if (aDistance > myTolerance)
+      {
+        const Handle(Geom2d_Curve) aCurve = 
+          makeLine(*aPrevParam, aCurParam, Standard_False);
+        if (aCurve.IsNull()) {
+          return Standard_False;
+        }
+
+        mySeqCurves.Append(aCurve);
+        aPrevParam = &mySeqParams(i);
+      }
+    }
+  }
+  return Standard_True;
+}
+
+//=======================================================================
+//function : checkCurve
+//purpose  : method for checking max deflection Geom curve from Adaptor Curve
+//=======================================================================
+
+Standard_Boolean Geom2dConvert_ApproxArcsSegments::checkCurve
+                        (const Handle(Geom2d_Curve)&    aCurve,
+                         const Standard_Real            theFirstParam,
+                         const Standard_Real            theLastParam) const
+{
+  if (aCurve.IsNull())
+    return Standard_False;              // check fails on empty input
+  Standard_Boolean isUniformDone = !mySeqParams.IsEmpty();
+  //calcualtion sequence of the parameters or step by parameter.
+  Standard_Integer aNbPnts = (isUniformDone ? mySeqParams.Length() :MAXPOINTS);
+  Standard_Real aParamStep = (theLastParam - theFirstParam)/MAXPOINTS;
+
+  Handle(Geom2d_Curve) aCurve1 = aCurve;
+  Handle(Geom2d_TrimmedCurve) aTrCurve =
+    Handle(Geom2d_TrimmedCurve)::DownCast(aCurve);
+  if (!aTrCurve.IsNull())
+    aCurve1 = aTrCurve->BasisCurve();
+  gp_Lin2d aLin2d;
+  gp_Circ2d aCirc2d;
+  Handle(Geom2d_Line) aGeomLine = Handle(Geom2d_Line)::DownCast(aCurve1);
+  Standard_Boolean isLine = (!aGeomLine.IsNull());
+  Standard_Boolean isCircle = (!isLine);
+  if (isLine)
+    aLin2d = aGeomLine->Lin2d();
+
+  else {
+    Handle(Geom2d_Circle) aGeomCircle =
+      Handle(Geom2d_Circle)::DownCast(aCurve1);
+    isCircle = (!aGeomCircle.IsNull());
+    if (isCircle)
+      aCirc2d = aGeomCircle->Circ2d();
+    else
+      return Standard_False;
+  }
+
+  //calculation of the max deflection points from CurveAdaptor from Geom curve.
+  Standard_Boolean isLess = Standard_True;
+  Standard_Integer i = 1;
+  for (; i <= aNbPnts && isLess; i++)
+  {
+
+    Standard_Real aParam = (isUniformDone ? mySeqParams.Value(i).Parameter() :
+                             (theFirstParam + i*aParamStep));
+    if (aParam < (theFirstParam - Precision::PConfusion()) ||
+        aParam > (theLastParam + Precision::PConfusion())) continue;
+
+    //getting point from adaptor curve by specified parameter.
+    gp_Pnt2d aPointAdaptor(0., 0.);
+    gp_Pnt2d aProjPoint(0., 0.);
+    myCurve.D0(aParam, aPointAdaptor);
+    Standard_Real aParameterCurve = 0.0;
+
+    //getting point from geom curve by specified parameter.
+    if (isLine)
+    {
+      aParameterCurve = ElCLib::Parameter(aLin2d, aPointAdaptor);
+      aProjPoint = ElCLib::Value(aParameterCurve, aLin2d);
+    }
+    else if (isCircle)
+    {
+
+      aParameterCurve = ElCLib::Parameter(aCirc2d, aPointAdaptor);
+      aProjPoint = ElCLib::Value(aParameterCurve, aCirc2d);
+    }
+    else isLess = Standard_False;
+
+    isLess = (aProjPoint.Distance(aPointAdaptor) <
+              myTolerance + Precision::PConfusion());
+  }
+  return isLess;
+}
+
+//=======================================================================
+//function : checkContinuity
+//purpose  : check continuty first derivative between two curves.
+//=======================================================================
+
+Standard_Boolean checkContinuity (const Handle(Geom2d_Curve)& theCurve1,
+                                  const Handle(Geom2d_Curve)& theCurve2,
+                                  const Standard_Real         theAngleTol)
+{
+  gp_Vec2d v11,v21;
+  gp_Pnt2d p1, p2;
+  theCurve1->D1(theCurve1->LastParameter(),  p1, v11);
+  theCurve2->D1(theCurve2->FirstParameter(), p2, v21);
+
+  //check continuity with the specified tolerance.
+  return (v11.IsParallel(v21, theAngleTol));
+}
+
+//=======================================================================
+//function : getParameter
+//purpose  : getting the nearest point on AdaptorCurve to the specified point.
+//=======================================================================
+
+Geom2dConvert_PPoint getParameter (const gp_XY&             theXY1,
+                                   const Standard_Real      theFirstParam,
+                                   const Standard_Real      theLastParam,
+                                   const Adaptor2d_Curve2d& theCurve)
+{
+  Geom2dConvert_PPoint aResult;
+  Standard_Real prevParam = theFirstParam;
+  Standard_Real af1 = theFirstParam;
+  Standard_Real af2 = theLastParam;
+
+  // for finding nearest point use method half division.
+  Standard_Real aMinDist = RealLast();
+  Standard_Integer i = 1;
+  for (; i <= MAXPOINTS; i++)
+  {
+    aResult = Geom2dConvert_PPoint(af1, theCurve);
+    Standard_Real adist1 = (theXY1 - aResult.Point()).Modulus();
+    if (adist1 < Precision::Confusion())
+    {
+      return aResult;
+    }
+
+    aResult = Geom2dConvert_PPoint(af2, theCurve);
+    Standard_Real adist2 = (theXY1 - aResult.Point()).Modulus();
+    if (adist2 < Precision::Confusion())
+    {
+      return aResult;
+    }
+
+    if (aMinDist <= adist2 -Precision::Confusion() &&
+        aMinDist <= adist1 -Precision::Confusion())
+    {
+      break;
+    }
+
+    if (adist1 < adist2 -Precision::Confusion())
+    {
+      prevParam = af1;
+      aMinDist = adist1;
+      af2 = (af1 + af2) * 0.5;
+    }
+    else
+    {
+      prevParam = af2;
+      aMinDist = adist2;
+      af1 = (af1 + af2) * 0.5;
+    }
+  }
+  aResult = Geom2dConvert_PPoint(prevParam, theCurve);
+  return aResult;
+}
+
+//=======================================================================
+//function : isInflectionPoint
+//purpose  : method calculating that point specified by parameter
+//           is inflection point
+//=======================================================================
+
+Standard_Boolean isInflectionPoint (const Standard_Real      theParam,
+                                    const Adaptor2d_Curve2d& theCurve)
+{
+  gp_Pnt2d aP1;
+  gp_Vec2d aD1, aD2;
+  theCurve.D2(theParam, aP1, aD1, aD2);
+  const Standard_Real aSqMod = aD1.XY().SquareModulus();
+  const Standard_Real aCurvature = 
+    fabs (aD1.XY() ^ aD2.XY()) / (aSqMod * sqrt(aSqMod));
+  return (aCurvature < MyCurvatureTolerance);
+}
+
+//=======================================================================
+//function : isInflectionPoint
+//purpose  : method calculating that point specified by parameter
+//           is inflection point
+//=======================================================================
+
+Standard_Boolean isInflectionPoint (const Standard_Real         theParam,
+                                    const Geom2dConvert_PPoint& theFirstInfl,
+                                    const Adaptor2d_Curve2d&    theCurve,
+                                    const Standard_Real         theAngleTol)
+{
+  gp_Pnt2d aP1;
+  gp_Vec2d aD1, aD2;
+  theCurve.D2(theParam, aP1, aD1, aD2);
+  const Standard_Real aSqMod = aD1.XY().SquareModulus();
+  const Standard_Real aCurvature = 
+    fabs (aD1.XY() ^ aD2.XY()) / (aSqMod * sqrt(aSqMod));
+  Standard_Real aContAngle =
+    fabs(gp_Vec2d(aP1.XY() - theFirstInfl.Point()).Angle(aD1));
+  aContAngle = ::Min(aContAngle, fabs(M_PI - aContAngle));
+  return (aCurvature < MyCurvatureTolerance && aContAngle < theAngleTol);
+}
diff --git a/src/Geom2dConvert/Geom2dConvert_ApproxArcsSegments.hxx b/src/Geom2dConvert/Geom2dConvert_ApproxArcsSegments.hxx
new file mode 100644 (file)
index 0000000..0bab7f5
--- /dev/null
@@ -0,0 +1,113 @@
+// Created: 2009-01-20
+// 
+// Copyright (c) 2009-2013 OPEN CASCADE SAS
+// 
+// This file is part of commercial software by OPEN CASCADE SAS, 
+// furnished in accordance with the terms and conditions of the contract 
+// and with the inclusion of this copyright notice. 
+// This file or any part thereof may not be provided or otherwise 
+// made available to any third party. 
+// 
+// No ownership title to the software is transferred hereby. 
+// 
+// OPEN CASCADE SAS makes no representation or warranties with respect to the 
+// performance of this software, and specifically disclaims any responsibility 
+// for any damages, special or consequential, connected with its use. 
+
+#ifndef _Geom2dConvert_ApproxArcsSegments_HeaderFile
+#define _Geom2dConvert_ApproxArcsSegments_HeaderFile
+
+#include <TColGeom2d_SequenceOfCurve.hxx>
+#include <Geom2dConvert_PPoint.hxx>
+#include <Geom2dConvert_SequenceOfPPoint.hxx>
+#include <Geom2d_TrimmedCurve.hxx>
+
+//! Approximation of a free-form curve by a sequence of arcs+segments.
+class Geom2dConvert_ApproxArcsSegments
+{
+ public:
+  // ---------- PUBLIC METHODS ----------
+
+  enum Status {
+    StatusOK = 0,
+    StatusNotDone,
+    StatusError
+  };
+
+  //! Constructor.
+  Standard_EXPORT Geom2dConvert_ApproxArcsSegments (const Adaptor2d_Curve2d&  theCurve,
+                                                    const Standard_Real       theTolerance,
+                                                    const Standard_Real       theAngleTol);
+
+  //! Get the result curve after approximation.
+  const TColGeom2d_SequenceOfCurve& GetResult() const
+  { return mySeqCurves; }
+
+private:
+
+  //! Create arc of circle by three points (knowing that myCurve is circle).
+  Handle(Geom2d_Curve)
+                   makeCircle     (const Geom2dConvert_PPoint& theFirst,
+                                   const Geom2dConvert_PPoint& theLast) const;
+
+  //! Create an arc of circle using 2 points and a derivative in the first point.
+  Standard_Boolean makeArc        (const Geom2dConvert_PPoint&  theParam1,
+                                   Geom2dConvert_PPoint&        theParam2,
+                                   const Standard_Boolean       isFirst,
+                                   Handle(Geom2d_TrimmedCurve)& theCurve) const;
+
+  //! Make a line from myCurve in the limits by parameter from theFirst to theLast
+  Handle(Geom2d_TrimmedCurve)
+                   makeLine       (Geom2dConvert_PPoint&  theFirst,
+                                   Geom2dConvert_PPoint&  theLast,
+                                   const Standard_Boolean isCheck) const;
+
+  //! Create a sequence of elementary curves from a free-form adaptor curve.
+  Standard_Boolean makeFreeform   ();
+
+  //! Obtain the linear intervals on the curve using as criteria
+  //! curvature tolerance (indicating either linear part or inflection)
+  void             getLinearParts (Geom2dConvert_SequenceOfPPoint& theSeqParam);
+
+  //! Dichotomic search of the boundary of inflection interval, between
+  //! two parameters on the Curve
+  Geom2dConvert_PPoint findInflection(const Geom2dConvert_PPoint& theParamIsIn,
+                                      const Geom2dConvert_PPoint& theParamNoIn) const;
+
+  //! Make approximation non-linear part of the other curve.
+  Standard_Boolean makeApproximation
+                                  (Geom2dConvert_PPoint& theFirstParam,
+                                   Geom2dConvert_PPoint& theLastParam);
+
+  //! Method for calculation of a biarc.
+  Standard_Boolean calculateBiArcs(Geom2dConvert_PPoint& theFirstParam,
+                                   Geom2dConvert_PPoint& theLastParam);
+
+  //! Method for calculation of a linear interpolation.
+  Standard_Boolean calculateLines(Geom2dConvert_PPoint& theFirstParam,
+                                  Geom2dConvert_PPoint& theLastParam);
+
+  //! Checking max deflection Geom curve from Adaptor Curve
+  Standard_Boolean checkCurve     (const Handle(Geom2d_Curve)& aCurve,
+                                   const Standard_Real    theFirstParam,
+                                   const Standard_Real    theLastParam) const;
+
+ private:
+  // ---------- PRIVATE FIELDS ----------
+
+  const Adaptor2d_Curve2d&              myCurve;
+  Geom2dConvert_PPoint                  myExt[2];
+
+  Handle(NCollection_BaseAllocator)     myAlloc;
+  Standard_Real                         myTolerance;
+  Standard_Real                         myAngleTolerance;
+
+  Geom2dConvert_SequenceOfPPoint        mySeqParams;
+  TColGeom2d_SequenceOfCurve            mySeqCurves;
+  Status                                myStatus;
+
+  //! Protection against compiler warning
+  void operator= (const Geom2dConvert_ApproxArcsSegments&);
+};
+
+#endif
diff --git a/src/Geom2dConvert/Geom2dConvert_PPoint.cxx b/src/Geom2dConvert/Geom2dConvert_PPoint.cxx
new file mode 100644 (file)
index 0000000..bf9264f
--- /dev/null
@@ -0,0 +1,54 @@
+// Created: 2009-02-02
+// 
+// Copyright (c) 2009-2013 OPEN CASCADE SAS
+// 
+// This file is part of commercial software by OPEN CASCADE SAS, 
+// furnished in accordance with the terms and conditions of the contract 
+// and with the inclusion of this copyright notice. 
+// This file or any part thereof may not be provided or otherwise 
+// made available to any third party. 
+// 
+// No ownership title to the software is transferred hereby. 
+// 
+// OPEN CASCADE SAS makes no representation or warranties with respect to the 
+// performance of this software, and specifically disclaims any responsibility 
+// for any damages, special or consequential, connected with its use. 
+
+#include <Geom2dConvert_PPoint.hxx>
+
+#include <Adaptor2d_Curve2d.hxx>
+#include <Precision.hxx>
+
+//=======================================================================
+//function : Geom2dConvert_PPoint
+//purpose  : Constructor
+//=======================================================================
+
+Geom2dConvert_PPoint::Geom2dConvert_PPoint (const Standard_Real      theParameter,
+                                            const Adaptor2d_Curve2d& theAdaptor)
+  : myParameter (theParameter)
+{
+  theAdaptor.D1(theParameter, myPoint, myD1);
+}
+
+//=======================================================================
+//function : Geom2dConvert_PPoint::operator ==
+//purpose  : Compare two values of this type.
+//=======================================================================
+
+Standard_Boolean Geom2dConvert_PPoint::operator ==
+                (const Geom2dConvert_PPoint& theOther) const
+{
+  return (fabs(myParameter - theOther.Parameter()) <= Precision::PConfusion());
+}
+
+//=======================================================================
+//function : Geom2dConvert_PPoint::operator !=
+//purpose  : Compare two values of this type.
+//=======================================================================
+
+Standard_Boolean Geom2dConvert_PPoint::operator !=
+                (const Geom2dConvert_PPoint& theOther) const
+{
+  return (fabs(myParameter - theOther.Parameter()) > Precision::PConfusion());
+}
diff --git a/src/Geom2dConvert/Geom2dConvert_PPoint.hxx b/src/Geom2dConvert/Geom2dConvert_PPoint.hxx
new file mode 100644 (file)
index 0000000..2e35fa6
--- /dev/null
@@ -0,0 +1,76 @@
+// Created: 2009-01-21
+// 
+// Copyright (c) 2009-2013 OPEN CASCADE SAS
+// 
+// This file is part of commercial software by OPEN CASCADE SAS, 
+// furnished in accordance with the terms and conditions of the contract 
+// and with the inclusion of this copyright notice. 
+// This file or any part thereof may not be provided or otherwise 
+// made available to any third party. 
+// 
+// No ownership title to the software is transferred hereby. 
+// 
+// OPEN CASCADE SAS makes no representation or warranties with respect to the 
+// performance of this software, and specifically disclaims any responsibility 
+// for any damages, special or consequential, connected with its use. 
+
+#ifndef _Geom2dConvert_PPoint_HeaderFile
+#define _Geom2dConvert_PPoint_HeaderFile
+
+#include <gp_Pnt2d.hxx>
+#include <gp_Vec2d.hxx>
+
+class Adaptor2d_Curve2d;
+
+//! Class representing a point on curve, with 2D coordinate and the tangent
+class Geom2dConvert_PPoint
+{
+public:
+  //! Empty constructor.
+  Standard_EXPORT inline Geom2dConvert_PPoint ()
+    : myParameter (::RealLast()),
+      myPoint     (0., 0.),
+      myD1        (0., 0.) {}
+
+  //! Constructor.
+  Standard_EXPORT inline Geom2dConvert_PPoint (const Standard_Real theParameter,
+                                               const gp_XY&        thePoint,
+                                               const gp_XY&        theD1)
+    : myParameter (theParameter),
+      myPoint     (thePoint),
+      myD1        (theD1) {}
+
+  //! Constructor.
+  Standard_EXPORT Geom2dConvert_PPoint (const Standard_Real      theParameter,
+                                        const Adaptor2d_Curve2d& theAdaptor);
+
+  //! Compute the distance betwwen two 2d points.
+  inline Standard_Real        Dist      (const Geom2dConvert_PPoint& theOth) const
+  { return myPoint.Distance(theOth.myPoint); }
+
+  //! Query the parmeter value.
+  inline Standard_Real        Parameter () const { return myParameter; }
+
+  //! Query the point location.
+  inline const gp_XY&         Point     () const { return myPoint.XY(); }
+
+  //! Query the first derivatives.
+  inline const gp_XY&         D1        () const { return myD1.XY(); }
+    
+  //! Change the value of the derivative at the point.
+  inline void                 SetD1     (const gp_XY& theD1)
+  { myD1.SetXY (theD1); }
+
+  //! Compare two values of this type.
+  Standard_EXPORT Standard_Boolean operator == (const Geom2dConvert_PPoint&) const;
+
+  //! Compare two values of this type.
+  Standard_EXPORT Standard_Boolean operator != (const Geom2dConvert_PPoint&) const;
+
+private:
+  Standard_Real    myParameter; //! Parameter value
+  gp_Pnt2d  myPoint; //! Point location
+  gp_Vec2d  myD1;    //! derivatives by parameter (components of the tangent).
+};
+
+#endif
diff --git a/src/Geom2dConvert/Geom2dConvert_SequenceOfPPoint.hxx b/src/Geom2dConvert/Geom2dConvert_SequenceOfPPoint.hxx
new file mode 100644 (file)
index 0000000..e87f5c8
--- /dev/null
@@ -0,0 +1,25 @@
+// Created: 2009-01-09
+// 
+// Copyright (c) 2009-2013 OPEN CASCADE SAS
+// 
+// This file is part of commercial software by OPEN CASCADE SAS, 
+// furnished in accordance with the terms and conditions of the contract 
+// and with the inclusion of this copyright notice. 
+// This file or any part thereof may not be provided or otherwise 
+// made available to any third party. 
+// 
+// No ownership title to the software is transferred hereby. 
+// 
+// OPEN CASCADE SAS makes no representation or warranties with respect to the 
+// performance of this software, and specifically disclaims any responsibility 
+// for any damages, special or consequential, connected with its use. 
+
+#ifndef _Geom2dConvert_SequenceOfPPoint_HeaderFile
+#define _Geom2dConvert_SequenceOfPPoint_HeaderFile
+
+#include <NCollection_Sequence.hxx>
+class Geom2dConvert_PPoint;
+
+typedef NCollection_Sequence<Geom2dConvert_PPoint> Geom2dConvert_SequenceOfPPoint;
+
+#endif
diff --git a/tests/bugs/modalg_8/bug32214_1 b/tests/bugs/modalg_8/bug32214_1
new file mode 100644 (file)
index 0000000..591f839
--- /dev/null
@@ -0,0 +1,23 @@
+puts "========================================="
+puts "OCC32214: 2d Offset produces wrong result"
+puts "========================================="
+puts ""
+
+restore [locate_data_file bug32214.brep] a
+wire ww a
+
+arclinconvert result ww
+build3d result
+
+checkshape result
+
+checknbshapes result -t -vertex 50 -edge 49 -wire 1
+
+set tolres [checkmaxtol result]
+
+if { ${tolres} > 1.001e-7} {
+   puts "Error: bad tolerance of result"
+}
+
+checkprops result -l 1.88301
+
diff --git a/tests/bugs/modalg_8/bug32214_2 b/tests/bugs/modalg_8/bug32214_2
new file mode 100644 (file)
index 0000000..82c0fdd
--- /dev/null
@@ -0,0 +1,24 @@
+puts "========================================="
+puts "OCC32214: 2d Offset produces wrong result"
+puts "========================================="
+puts ""
+
+restore [locate_data_file bug31992.brep] a
+wire a a
+mkplane a a
+
+arclinconvert result a
+build3d result
+
+checkshape result
+
+checknbshapes result -t -vertex 187 -edge 187 -wire 1 -face 1
+
+set tolres [checkmaxtol result]
+
+if { ${tolres} > 1.001e-7} {
+   puts "Error: bad tolerance of result"
+}
+
+checkprops result -s 3.13603
+
diff --git a/tests/bugs/modalg_8/bug32214_3 b/tests/bugs/modalg_8/bug32214_3
new file mode 100644 (file)
index 0000000..36d9848
--- /dev/null
@@ -0,0 +1,30 @@
+puts "========================================="
+puts "OCC32214: 2d Offset produces wrong result"
+puts "========================================="
+puts ""
+
+beziercurve c1 9  3 3 0 10  0 10 0 100  -3 3 0 10  -10 0 0 100  -3 -3 0 10  0 -10 0 100  3 -3 0 10  10 0 0 100  3 3 0 10
+beziercurve c2 5  3 0 0  0 3 0  -3 0 0  0 -3 0  3 0 0
+mkedge e1 c1
+mkedge e2 c2
+wire w1 e1
+wire w2 e2
+orientation w2 R
+mkplane a w1
+add w2 a
+
+arclinconvert result a
+build3d result
+
+checkshape result
+
+checknbshapes result -t -vertex 170 -edge 170 -wire 2 -face 1
+
+set tolres [checkmaxtol result]
+
+if { ${tolres} > 1.001e-7} {
+   puts "Error: bad tolerance of result"
+}
+
+checkprops result -s 106.6
+
diff --git a/tests/bugs/modalg_8/bug32214_4 b/tests/bugs/modalg_8/bug32214_4
new file mode 100644 (file)
index 0000000..31d1217
--- /dev/null
@@ -0,0 +1,52 @@
+puts "========================================="
+puts "OCC32214: 2d Offset produces wrong result"
+puts "========================================="
+puts ""
+
+restore [locate_data_file bug32214.brep] a
+wire ww a
+donly ww
+
+mkoffset result ww 14 0.1 -approx
+
+front
+fit
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png
+
+for {set i 1} {$i<=14} {incr i} {
+       checkshape result_${i}
+       set tolres [checkmaxtol result_${i}]
+       if { ${tolres} > 1.001e-7} {
+               puts "Error: bad tolerance of result"
+       }
+}
+
+checknbshapes result_1 -t -vertex 114 -edge 114 -wire 1
+checkprops result_1 -l 4.39365
+checknbshapes result_2 -t -vertex 110 -edge 110 -wire 1
+checkprops result_2 -l 5.02084
+checknbshapes result_3 -t -vertex 104 -edge 104 -wire 1
+checkprops result_3 -l 5.64778
+checknbshapes result_4 -t -vertex 101 -edge 101 -wire 1
+checkprops result_4 -l 6.27443
+checknbshapes result_5 -t -vertex 95 -edge 95 -wire 1
+checkprops result_5 -l 6.89816
+checknbshapes result_6 -t -vertex 92 -edge 92 -wire 1
+checkprops result_6 -l 7.51255
+checknbshapes result_7 -t -vertex 88 -edge 88 -wire 1
+checkprops result_7 -l 8.12807
+checknbshapes result_8 -t -vertex 81 -edge 81 -wire 1
+checkprops result_8 -l 8.74586
+checknbshapes result_9 -t -vertex 72 -edge 72 -wire 1
+checkprops result_9 -l 9.36292
+checknbshapes result_10 -t -vertex 65 -edge 65 -wire 1
+checkprops result_10 -l 9.97455
+checknbshapes result_11 -t -vertex 60 -edge 60 -wire 1
+checkprops result_11 -l 10.5864
+checknbshapes result_12 -t -vertex 59 -edge 59 -wire 1
+checkprops result_12 -l 11.2017
+checknbshapes result_13 -t -vertex 57 -edge 57 -wire 1
+checkprops result_13 -l 11.8196
+checknbshapes result_14 -t -vertex 55 -edge 55 -wire 1
+checkprops result_14 -l 12.4395
diff --git a/tests/bugs/modalg_8/bug32214_5 b/tests/bugs/modalg_8/bug32214_5
new file mode 100644 (file)
index 0000000..fa6eb5c
--- /dev/null
@@ -0,0 +1,52 @@
+puts "========================================="
+puts "OCC32214: 2d Offset produces wrong result"
+puts "========================================="
+puts ""
+
+restore [locate_data_file bug32214.brep] a
+wire ww a
+donly ww
+
+openoffset result ww 14 0.1 -approx
+
+front
+fit
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png
+
+for {set i 1} {$i<=14} {incr i} {
+       checkshape result_${i}
+       set tolres [checkmaxtol result_${i}]
+       if { ${tolres} > 1.001e-7} {
+               puts "Error: bad tolerance of result"
+       }
+}
+
+checknbshapes result_1 -t -vertex 61 -edge 60 -wire 1
+checkprops result_1 -l 2.04858
+checknbshapes result_2 -t -vertex 61 -edge 60 -wire 1
+checkprops result_2 -l 2.21414
+checknbshapes result_3 -t -vertex 61 -edge 60 -wire 1
+checkprops result_3 -l 2.37971
+checknbshapes result_4 -t -vertex 61 -edge 60 -wire 1
+checkprops result_4 -l 2.54528
+checknbshapes result_5 -t -vertex 61 -edge 60 -wire 1
+checkprops result_5 -l 2.71084
+checknbshapes result_6 -t -vertex 61 -edge 60 -wire 1
+checkprops result_6 -l 2.87641
+checknbshapes result_7 -t -vertex 61 -edge 60 -wire 1
+checkprops result_7 -l 3.04198
+checknbshapes result_8 -t -vertex 56 -edge 55 -wire 1
+checkprops result_8 -l 3.20723
+checknbshapes result_9 -t -vertex 50 -edge 49 -wire 1
+checkprops result_9 -l 3.38587
+checknbshapes result_10 -t -vertex 48 -edge 47 -wire 1
+checkprops result_10 -l 3.58204
+checknbshapes result_11 -t -vertex 45 -edge 44 -wire 1
+checkprops result_11 -l 3.73715
+checknbshapes result_12 -t -vertex 45 -edge 44 -wire 1
+checkprops result_12 -l 3.97323
+checknbshapes result_13 -t -vertex 43 -edge 42 -wire 1
+checkprops result_13 -l 4.14242
+checknbshapes result_14 -t -vertex 43 -edge 42 -wire 1
+checkprops result_14 -l 4.37544
diff --git a/tests/bugs/modalg_8/bug32214_6 b/tests/bugs/modalg_8/bug32214_6
new file mode 100644 (file)
index 0000000..732073b
--- /dev/null
@@ -0,0 +1,52 @@
+puts "========================================="
+puts "OCC32214: 2d Offset produces wrong result"
+puts "========================================="
+puts ""
+
+restore [locate_data_file bug32214.brep] a
+wire ww a
+donly ww
+
+openoffset result ww 14 -0.1 -approx
+
+front
+fit
+
+checkview -screenshot -2d -path ${imagedir}/${test_image}.png
+
+for {set i 1} {$i<=14} {incr i} {
+       checkshape result_${i}
+       set tolres [checkmaxtol result_${i}]
+       if { ${tolres} > 1.001e-7} {
+               puts "Error: bad tolerance of result"
+       }
+}
+
+checknbshapes result_1 -t -vertex 50 -edge 49 -wire 1
+checkprops result_1 -l 1.66475
+checknbshapes result_2 -t -vertex 46 -edge 45 -wire 1
+checkprops result_2 -l 1.57655
+checknbshapes result_3 -t -vertex 40 -edge 39 -wire 1
+checkprops result_3 -l 1.48755
+checknbshapes result_4 -t -vertex 37 -edge 36 -wire 1
+checkprops result_4 -l 1.39682
+checknbshapes result_5 -t -vertex 31 -edge 30 -wire 1
+checkprops result_5 -l 1.30715
+checknbshapes result_6 -t -vertex 28 -edge 27 -wire 1
+checkprops result_6 -l 1.27033
+checknbshapes result_7 -t -vertex 24 -edge 23 -wire 1
+checkprops result_7 -l 1.1996
+checknbshapes result_8 -t -vertex 22 -edge 21 -wire 1
+checkprops result_8 -l 1.1737
+checknbshapes result_9 -t -vertex 18 -edge 17 -wire 1
+checkprops result_9 -l 1.17713
+checknbshapes result_10 -t -vertex 17 -edge 16 -wire 1
+checkprops result_10 -l 1.22711
+checknbshapes result_11 -t -vertex 14 -edge 13 -wire 1
+checkprops result_11 -l 1.2663
+checknbshapes result_12 -t -vertex 14 -edge 13 -wire 1
+checkprops result_12 -l 1.33108
+checknbshapes result_13 -t -vertex 14 -edge 13 -wire 1
+checkprops result_13 -l 1.39586
+checknbshapes result_14 -t -vertex 14 -edge 13 -wire 1
+checkprops result_14 -l 1.46064