Salome HOME
36a59c652ef1090eae4be5cc2eac0c4a5b8250d2
[modules/geom.git] / src / SKETCHER / Sketcher_Utils.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  File   : Sketcher_Utils.cxx
24 //  Author : Sergey KHROMOV
25 //  Module : GEOM
26
27
28 #include "Sketcher_Utils.hxx"
29
30 #include <BRepBuilderAPI_MakeEdge.hxx>
31 #include <BRepBuilderAPI_MakeVertex.hxx>
32 #include <BRepBuilderAPI_MakeWire.hxx>
33 #include <ElSLib.hxx>
34 #include <GeomAPI_Interpolate.hxx>
35 #include <TColgp_Array1OfVec.hxx>
36 #include <TColgp_HArray1OfPnt.hxx>
37 #include <TColStd_HArray1OfBoolean.hxx>
38 #include <TopoDS_Wire.hxx>
39
40 const double POINT_CONFUSION_TOLERANCE = 0.0001;
41
42
43 //=======================================================================
44 // function : MakePolyline
45 // purpose  : 
46 //=======================================================================
47 TopoDS_Shape Sketcher_Utils::MakePolyline
48                               (const std::list <double> &theCoords2D,
49                                const Standard_Boolean    IsClosed,
50                                const gp_Ax3             &thePlane)
51 {
52   std::list <gp_Pnt> aPoints;
53   TopoDS_Shape       aResult;
54
55   To3D(theCoords2D, thePlane, aPoints);
56
57   Standard_Integer aNbPnts = aPoints.size();
58
59   if (aNbPnts > 1) {
60     if (IsClosed &&
61         aPoints.front().IsEqual(aPoints.back(), POINT_CONFUSION_TOLERANCE)) {
62       // The polyline should be closed, first and last points are confused.
63       // Remove the last point.
64       aPoints.pop_back();
65       --aNbPnts;
66     }
67   }
68
69   if (aNbPnts == 1) {
70     // The result is vertex.
71     aResult = BRepBuilderAPI_MakeVertex(aPoints.front()).Vertex();
72   } else if (aNbPnts > 1) {
73     // There are several points. Make a polyline.
74     std::list <gp_Pnt>::const_iterator anIter    = aPoints.begin();
75     TopoDS_Vertex                      aVtxFirst =
76                        BRepBuilderAPI_MakeVertex(*anIter).Vertex();
77     TopoDS_Vertex                      aVtx[2];
78     TopoDS_Edge                        aSegment;
79     BRepBuilderAPI_MakeWire            aMkWire;
80
81     aVtx[0] = aVtxFirst;
82
83     for (++anIter; anIter != aPoints.end(); ++anIter) {
84       aVtx[1]  = BRepBuilderAPI_MakeVertex(*anIter).Vertex();
85       aSegment = BRepBuilderAPI_MakeEdge(aVtx[0], aVtx[1]).Edge();
86       aMkWire.Add(aSegment);
87       aVtx[0]  = aVtx[1];
88     }
89
90     if (IsClosed) {
91       // Create a closing segment.
92       aSegment = BRepBuilderAPI_MakeEdge(aVtx[0], aVtxFirst).Edge();
93       aMkWire.Add(aSegment);
94     }
95
96     aResult = aMkWire.Wire();
97   }
98
99   return aResult;
100 }
101
102 //=======================================================================
103 // function : constructBSpline
104 // purpose  : See function 'constructBSpline' in file 'CurveCreator_Utils.cxx'.
105 //=======================================================================
106 static bool constructBSpline(
107   const Handle(TColgp_HArray1OfPnt)& thePoints,
108   const Standard_Boolean theIsClosed,
109   Handle(Geom_BSplineCurve)& theBSpline)
110 {
111   const int aPointCount = thePoints->Length();
112   if (aPointCount <= 1)
113   {
114     return false;
115   }
116
117   // Calculate the tangents.
118   TColgp_Array1OfVec aTangents(1, aPointCount);
119   Handle(TColStd_HArray1OfBoolean) aTangentFlags =
120     new TColStd_HArray1OfBoolean(1, aPointCount);
121   GeomAPI_Interpolate aInterpolator(thePoints, theIsClosed, 0);
122   if (aPointCount == 2)
123   {
124     aTangentFlags->SetValue(1, Standard_False);
125     aTangentFlags->SetValue(2, Standard_False);
126   }
127   else
128   {
129     for (Standard_Integer aPN = 1; aPN <= aPointCount; ++aPN)
130     {
131       gp_Vec aTangent;
132       if (aPN != 1 || theIsClosed)
133       {
134         const Standard_Integer aPN1 = (aPN != 1) ? (aPN - 1) : aPointCount;
135         aTangent = gp_Vec(thePoints->Value(aPN1),
136           thePoints->Value(aPN)).Normalized();
137       }
138       if (aPN < aPointCount || theIsClosed)
139       {
140         const Standard_Integer aPN2 = (aPN != aPointCount) ? (aPN + 1) : 1;
141         const gp_Vec aTangent2 = aTangent +
142           gp_Vec(thePoints->Value(aPN), thePoints->Value(aPN2)).Normalized();
143         if (aTangent2.SquareMagnitude() >= Precision::SquareConfusion())
144         {
145           aTangent = aTangent2.Normalized();
146         }
147         else
148         {
149           aTangent = -aTangent;
150         }
151       }
152       aTangents.SetValue(aPN, aTangent);
153       aTangentFlags->SetValue(aPN, Standard_True);
154     }
155   }
156
157   // Interpolate.
158   aInterpolator.Load(aTangents, aTangentFlags, Standard_False);
159   aInterpolator.Perform();
160   const bool aResult = (aInterpolator.IsDone() == Standard_True);
161   if (aResult)
162   {
163     theBSpline = aInterpolator.Curve();
164   }
165   return aResult;
166 }
167
168 //=======================================================================
169 // function : MakeInterpolation
170 // purpose  : 
171 //=======================================================================
172 TopoDS_Shape Sketcher_Utils::MakeInterpolation(
173   const std::list<double>& theCoords2D,
174   const Standard_Boolean theIsClosed,
175   const gp_Ax3& thePlane)
176 {
177   if (theCoords2D.size() == 0)
178   {
179     return TopoDS_Shape();
180   }
181
182   // Get the different points.
183   std::list<gp_Pnt> aTmpPoints;
184   To3D(theCoords2D, thePlane, aTmpPoints);
185   gp_Pnt aFirstPoint = aTmpPoints.front();
186   gp_Pnt aPoint = aFirstPoint;
187   std::list<gp_Pnt>::iterator aPIt = aTmpPoints.begin();
188   for (++aPIt; aPIt != aTmpPoints.end();)
189   {
190     const gp_Pnt aPoint2 = *aPIt;
191     if (!aPoint.IsEqual(aPoint2, POINT_CONFUSION_TOLERANCE))
192     {
193       aPoint = aPoint2;
194       ++aPIt;
195     }
196     else
197     {
198       aTmpPoints.erase(aPIt);
199     }
200   }
201   if (theIsClosed)
202   {
203     while (--aPIt != aTmpPoints.begin() &&
204       aFirstPoint.IsEqual(*aPIt, POINT_CONFUSION_TOLERANCE))
205     {
206       aTmpPoints.erase(aPIt);
207     }
208   }
209
210   // Process the single point case.
211   const int aPointCount = aTmpPoints.size();
212   if (aPointCount == 1)
213   {
214     return BRepBuilderAPI_MakeVertex(aTmpPoints.front());
215   }
216
217   // Process the other cases.
218   Handle(TColgp_HArray1OfPnt) aPoints =
219     new TColgp_HArray1OfPnt(1, aPointCount);
220   aPIt = aTmpPoints.begin();
221   for (Standard_Integer aPN = 1; aPIt != aTmpPoints.end(); ++aPIt, ++aPN)
222   {
223     aPoints->SetValue(aPN, *aPIt);
224   }
225   Handle(Geom_BSplineCurve) aBSpline;
226   if (constructBSpline(aPoints, theIsClosed, aBSpline))
227   {
228     return BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(aBSpline));
229   }
230   return TopoDS_Shape();
231 }
232
233 //=======================================================================
234 // function : To3D
235 // purpose  : 
236 //=======================================================================
237 void Sketcher_Utils::To3D(const std::list <double> &theCoords2D,
238                           const gp_Ax3             &thePlane,
239                                 std::list <gp_Pnt> &thePoints)
240 {
241   thePoints.clear();
242
243   if (theCoords2D.empty() || theCoords2D.size() % 2 == 1) {
244     // Odd number of coordinates or empty list. Invalid case.
245     return;
246   }
247
248   std::list <double>::const_iterator anIter = theCoords2D.begin();
249   Standard_Real    aX     = *anIter;
250   Standard_Real    aY     = *(++anIter);
251   gp_Pnt           aPLast = ElSLib::PlaneValue (aX, aY, thePlane);
252   gp_Pnt           aPnt;
253
254   thePoints.push_back(aPLast);
255
256   for (++anIter; anIter != theCoords2D.end(); ++anIter) {
257     aX   = *anIter;
258     aY   = *(++anIter);
259     aPnt =  ElSLib::PlaneValue (aX, aY, thePlane);
260
261     if (!aPLast.IsEqual(aPnt, POINT_CONFUSION_TOLERANCE)) {
262       thePoints.push_back(aPnt);
263       aPLast = aPnt;
264     }
265   }
266 }