da1ee398bcf18603d0b6cede53c157159984839a
[occt.git] / src / ShapeCustom / ShapeCustom_Curve2d.cxx
1 // Created on: 2001-12-20
2 // Created by: Pavel TELKOV
3 // Copyright (c) 2001-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 // Last modification:
17
18 #include <ElCLib.hxx>
19 #include <Geom2d_BezierCurve.hxx>
20 #include <Geom2d_BSplineCurve.hxx>
21 #include <Geom2d_Curve.hxx>
22 #include <Geom2d_Line.hxx>
23 #include <gp_Dir2d.hxx>
24 #include <gp_Lin2d.hxx>
25 #include <gp_Pnt2d.hxx>
26 #include <gp_Vec2d.hxx>
27 #include <Precision.hxx>
28 #include <ShapeCustom_Curve2d.hxx>
29 #include <Standard_ErrorHandler.hxx>
30
31 //=======================================================================
32 //function : GetLine
33 //purpose  : static
34 //=======================================================================
35 static gp_Lin2d GetLine (const gp_Pnt2d& P1, const gp_Pnt2d& P2,
36                          const Standard_Real c1, Standard_Real& cf, Standard_Real& cl)
37 {
38   gp_Vec2d avec (P1,P2);
39   gp_Dir2d adir (avec);
40   gp_Lin2d alin (P1,adir);
41   alin.SetLocation (ElCLib::Value (c1, alin));
42   cf = ElCLib::Parameter (alin, P1);
43   cl = ElCLib::Parameter (alin, P2);
44   return alin;
45 }
46
47
48 //=======================================================================
49 //function : IsLinear
50 //purpose  : static
51 //=======================================================================
52
53 Standard_Boolean ShapeCustom_Curve2d::IsLinear(const TColgp_Array1OfPnt2d& thePoles,
54                                                const Standard_Real tolerance,
55                                                Standard_Real& Deviation)
56 {
57   Standard_Integer nbPoles = thePoles.Length();
58   if(nbPoles < 2)
59     return Standard_False;
60   
61   Standard_Real dMax = 0;
62   Standard_Integer iMax1=0,iMax2=0;
63   
64   Standard_Integer i;
65   for(i = 1; i < nbPoles; i++)
66     for(Standard_Integer j = i+1; j <= nbPoles; j++) {
67       Standard_Real dist = thePoles(i).SquareDistance(thePoles(j));
68       if(dist > dMax) {
69         dMax = dist;
70         iMax1 = i;
71         iMax2 = j;
72       }
73     }
74   
75   Standard_Real dPreci = Precision::PConfusion()*Precision::PConfusion();
76   if(dMax < dPreci)
77     return Standard_False;
78   
79   Standard_Real tol2 = tolerance*tolerance;
80   gp_Vec2d avec (thePoles(iMax1),thePoles(iMax2));
81   gp_Dir2d adir (avec);
82   gp_Lin2d alin (thePoles(iMax1),adir);
83   
84   Standard_Real aMax = 0.;
85   for(i = 1; i <= nbPoles; i++) {
86     Standard_Real dist = alin.SquareDistance(thePoles(i));
87     if(dist > tol2)
88       return Standard_False;
89     if(dist > aMax)
90       aMax = dist;
91   }
92   Deviation = sqrt(aMax);
93   
94   return Standard_True;
95 }
96
97 //=======================================================================
98 //function : ConvertToLine2d
99 //purpose  : static
100 //=======================================================================
101
102 Handle(Geom2d_Line) ShapeCustom_Curve2d::ConvertToLine2d (const Handle(Geom2d_Curve)& theCurve,
103                                                           const Standard_Real c1,
104                                                           const Standard_Real c2,
105                                                           const Standard_Real theTolerance,
106                                                           Standard_Real& cf,
107                                                           Standard_Real& cl,
108                                                           Standard_Real& theDeviation)
109 {
110   Handle(Geom2d_Line) aLine2d;
111   gp_Pnt2d P1 = theCurve->Value(c1);
112   gp_Pnt2d P2 = theCurve->Value(c2);
113   Standard_Real dPreci = theTolerance*theTolerance;
114   if(P1.SquareDistance(P2) < dPreci)
115     return aLine2d; // it is not a line
116   
117   Handle(Geom2d_BSplineCurve) bsc = Handle(Geom2d_BSplineCurve)::DownCast(theCurve);
118   if (!bsc.IsNull()) {
119     Standard_Integer nbPoles = bsc->NbPoles();
120     TColgp_Array1OfPnt2d Poles(1,nbPoles);
121     bsc->Poles(Poles);
122     if(!ShapeCustom_Curve2d::IsLinear(Poles,theTolerance,theDeviation))
123       return aLine2d;  // non
124     gp_Lin2d alin = GetLine (P1,P2,c1,cf,cl);
125     aLine2d = new Geom2d_Line (alin);
126     return aLine2d;
127   }
128   
129   Handle(Geom2d_BezierCurve) bzc = Handle(Geom2d_BezierCurve)::DownCast(theCurve);
130   if (!bzc.IsNull()) {
131     Standard_Integer nbPoles = bzc->NbPoles();
132     TColgp_Array1OfPnt2d Poles(1,nbPoles);
133     bzc->Poles(Poles);
134     if(!ShapeCustom_Curve2d::IsLinear(Poles,theTolerance,theDeviation))
135       return aLine2d;  // non
136     gp_Lin2d alin = GetLine (P1,P2,c1,cf,cl);
137     aLine2d = new Geom2d_Line (alin);
138     return aLine2d;
139   }
140   
141   return aLine2d;
142 }
143
144 //=======================================================================
145 //function : SimplifyBSpline2d
146 //purpose  : 
147 //=======================================================================
148
149 Standard_Boolean ShapeCustom_Curve2d::SimplifyBSpline2d (Handle(Geom2d_BSplineCurve)& theBSpline2d,
150                                                          const Standard_Real theTolerance)
151 {
152   Standard_Integer aInitNbK;
153   Standard_Integer NbK = aInitNbK = theBSpline2d->NbKnots();
154   // search knot to remove
155   Standard_Boolean IsToRemove = Standard_True;
156   Standard_Integer aKnotIndx = NbK-1;
157   while (IsToRemove && NbK > 2)
158   {
159     Standard_Integer aMult = theBSpline2d->Multiplicity(aKnotIndx);
160     Standard_Integer DegMult = theBSpline2d->Degree() - aMult;
161     if ((DegMult > 1) && theBSpline2d->IsCN(DegMult))
162     {
163       Standard_Real U = theBSpline2d->Knot(aKnotIndx);
164       gp_Vec2d aVec1 = theBSpline2d->LocalDN(U, aKnotIndx-1, aKnotIndx, DegMult);
165       gp_Vec2d aVec2 = theBSpline2d->LocalDN(U, aKnotIndx, aKnotIndx+1, DegMult);
166       // check the derivations are have the "same" angle
167       if (aVec1.IsParallel(aVec2, Precision::Angular()))
168       {
169         // remove knot
170         try
171         {
172           OCC_CATCH_SIGNALS
173           theBSpline2d->RemoveKnot(aKnotIndx,
174                                  aMult-1,
175                                  theTolerance);
176         }
177         catch(Standard_Failure)
178         {
179         }
180       }
181     }
182     aKnotIndx--;
183     
184     NbK = theBSpline2d->NbKnots();
185     if (aKnotIndx == 1 || aKnotIndx == NbK)
186       IsToRemove = Standard_False;
187   }
188   return (aInitNbK > NbK);
189 }