]> SALOME platform Git repositories - modules/geom.git/blob - src/GEOMImpl/GEOMImpl_SplineDriver.cxx
Salome HOME
52657: Wrong State in Creation Info of GetShapesOnShapeAsCompound()
[modules/geom.git] / src / GEOMImpl / GEOMImpl_SplineDriver.cxx
1 // Copyright (C) 2007-2015  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 #include "GEOMImpl_SplineDriver.hxx"
24
25 #include "GEOMImpl_ISpline.hxx"
26 #include "GEOMImpl_Types.hxx"
27 #include "GEOMImpl_ICurveParametric.hxx"
28
29 #include "GEOM_Function.hxx"
30 #include "GEOMUtils.hxx"
31
32 #include <BRepBuilderAPI_MakeEdge.hxx>
33 #include <BRepBuilderAPI_MakeVertex.hxx>
34 #include <BRep_Tool.hxx>
35
36 #include <TopAbs.hxx>
37 #include <TopExp.hxx>
38 #include <TopoDS.hxx>
39 #include <TopoDS_Shape.hxx>
40 #include <TopoDS_Edge.hxx>
41 #include <TopoDS_Vertex.hxx>
42
43 #include <Geom_BezierCurve.hxx>
44 #include <GeomAPI_Interpolate.hxx>
45
46 #include <gp.hxx>
47 #include <gp_Pnt.hxx>
48 #include <gp_Circ.hxx>
49 #include <Precision.hxx>
50 #include <TColgp_Array1OfPnt.hxx>
51 #include <TColgp_HArray1OfPnt.hxx>
52
53 #include <Standard_NullObject.hxx>
54
55 // Below macro specifies how the closed point set is processed (issue 0022885).
56 // See below for more information.
57 // Currently solution 4 is chosen!
58 #define BSPLINE_PROCESS_CLOSED_PNTSET 4
59
60 namespace
61 {
62   /*!
63     \brief Generate list of points from the list of (x,y,z) coordinates
64     \param coords list of values specifying (x y z) coordinates of points
65     \return list of points
66     \internal
67   */
68   Handle(TColgp_HArray1OfPnt) pointsFromCoords(Handle(TColStd_HArray1OfReal) coords)
69   {
70     Standard_Integer length = coords->Length() / 3;
71
72     Handle(TColgp_HArray1OfPnt) points = new TColgp_HArray1OfPnt(1, length);
73     
74     for (int i = 0; i < length; i ++) {
75       Standard_Real x = coords->Value( i*3+1 );
76       Standard_Real y = coords->Value( i*3+2 );
77       Standard_Real z = coords->Value( i*3+3 );
78       points->SetValue(i+1, gp_Pnt(x, y, z));
79     }
80
81     return points;
82   }
83
84   /*!
85     \brief Generate list of points from the sequence of input objects
86     \param coords list of objects as it is stored within the CAF tree
87     \return list of points
88     \internal
89   */
90   Handle(TColgp_HArray1OfPnt) pointsFromObjs(Handle(TColStd_HSequenceOfTransient) objects)
91   {
92     Standard_Integer length = objects->Length();
93
94     Handle(TColgp_HArray1OfPnt) points = new TColgp_HArray1OfPnt(1, length);
95     
96     for (int i = 1; i <= length; i ++) {
97       TopoDS_Shape shape = Handle(GEOM_Function)::DownCast(objects->Value(i))->GetValue();
98       if (shape.ShapeType() != TopAbs_VERTEX)
99         // error: only vertices are allowed in the input
100         Standard_ConstructionError::Raise("Input should contain only vertices");
101       points->SetValue(i, BRep_Tool::Pnt(TopoDS::Vertex(shape)));
102     }
103
104     return points;
105   }
106 }
107
108 //=======================================================================
109 //function : GetID
110 //purpose  :
111 //=======================================================================
112 const Standard_GUID& GEOMImpl_SplineDriver::GetID()
113 {
114   static Standard_GUID aSplineDriver("FF1BBB33-5D14-4df2-980B-3A668264EA16");
115   return aSplineDriver;
116 }
117
118
119 //=======================================================================
120 //function : GEOMImpl_SplineDriver
121 //purpose  :
122 //=======================================================================
123 GEOMImpl_SplineDriver::GEOMImpl_SplineDriver()
124 {
125 }
126
127 //=======================================================================
128 //function : Execute
129 //purpose  :
130 //=======================================================================
131 Standard_Integer GEOMImpl_SplineDriver::Execute(TFunction_Logbook& log) const
132 {
133   if (Label().IsNull()) return 0;
134   Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
135
136   GEOMImpl_ISpline aCI (aFunction);
137   Standard_Integer aType = aFunction->GetType();
138
139   TopoDS_Shape aShape;
140
141   if (aType == SPLINE_BEZIER ||
142       aType == SPLINE_INTERPOLATION ||
143       aType == SPLINE_INTERPOL_TANGENTS) {
144
145     bool useCoords = aCI.GetConstructorType() == COORD_CONSTRUCTOR;
146
147     // collect points from input parameters: objects or coordinates
148     Handle(TColgp_HArray1OfPnt) points = useCoords ? pointsFromCoords(aCI.GetCoordinates()) : pointsFromObjs(aCI.GetPoints());
149     int length = points->Length();
150
151     if (length < 2) return 0; // error: not enough points in the input list
152
153     // reorder points if required (bspline only)
154     if ((aType == SPLINE_INTERPOLATION || aType == SPLINE_INTERPOL_TANGENTS) && aCI.GetDoReordering()) {
155       for (int i = 1; i < length - 1; i++) {
156         gp_Pnt pi = points->Value(i);
157         int nearest = 0;
158         double minDist = RealLast();
159         for (int j = i+1; j <= length; j++) {
160           double dist = pi.SquareDistance(points->Value(j));
161           if (dist < minDist && (minDist - dist) > Precision::Confusion()) {
162             nearest = j;
163             minDist = dist;
164           }
165         }
166         if (nearest > 0 && nearest != i + 1) {
167           // Keep given order of points to use it in case of equidistant candidates
168           //               .-<---<-.
169           //              /         \
170           // o  o  o  c  o->o->o->o->n  o  o
171           //          |  |           |
172           //          i i+1       nearest
173           gp_Pnt p = points->Value(nearest);
174           for (int j = nearest; j > i+1; j--)
175             points->SetValue(j, points->Value(j-1));
176           points->SetValue(i+1, p);
177         }
178       }
179     } // end of reordering
180
181     bool closed = points->Value(1).Distance(points->Value(length)) <= gp::Resolution();
182
183     if (aType == SPLINE_BEZIER) {
184       // for Bezier curve we should append first point to the list if:
185       // a) "closed" flag is set, and
186       // b) first and last vertices are not too close
187       bool addFirst = aCI.GetIsClosed() && !closed;
188       
189       // re-fill points and check that there's enough points to create a curve
190       bool isValid = false;
191       TColgp_Array1OfPnt curvePoints(1, length + (addFirst ? 1 : 0));
192       gp_Pnt pp;
193       for (int i = 1; i <= length; i++) {
194         gp_Pnt p = points->Value(i);
195         if (!isValid && i > 1 && p.Distance(pp) > Precision::Confusion())
196           isValid = true;
197         curvePoints.SetValue(i, p);
198         pp = p;
199       }
200
201       if (!isValid)
202         // error: not enough points to create curve
203         Standard_ConstructionError::Raise("Points for Bezier Curve are too close");
204       
205       // set last point equal to first for the closed Bezier curve
206       if (addFirst) curvePoints.SetValue(length+1, curvePoints.Value(1));
207       
208       // create Bezier curve
209       Handle(Geom_BezierCurve) GBC = new Geom_BezierCurve(curvePoints);
210       aShape = BRepBuilderAPI_MakeEdge(GBC).Edge();
211     }
212     else {
213       // Below described processing of closed points set case
214       // is not done for constrained bsplined
215       bool typeok = aType == SPLINE_INTERPOLATION;
216 #if BSPLINE_PROCESS_CLOSED_PNTSET == 1
217       // Last point is removed from the list if:
218       // a) first and last vertices are equal;
219       // b) "closed" flag is not taken into account.
220       // If first and last points are equal, we force "closed" flag to be set to true.
221       // For the case when first and last vertices are equal, this approach causes
222       // result different that would be if last point had NOT be removed and "closed" flag is false.
223       bool isClosed = typeok && (aCI.GetIsClosed() || closed);
224       bool removeLast = typeok && closed;
225       bool addFirst = false;
226 #elif BSPLINE_PROCESS_CLOSED_PNTSET == 2
227       // Last point is removed from the list if:
228       // a) first and last vertices are equal;
229       // b) "closed" flag is set to true.
230       // Flag "closed" is taken "as is".
231       // For the case when first and last vertices are equal, this approach causes
232       // different results with "closed" flag set to true and false.
233       bool isClosed = typeok && aCI.GetIsClosed();
234       bool removeLast = typeok && aCI.GetIsClosed() && closed;
235       bool addFirst = false;
236 #elif BSPLINE_PROCESS_CLOSED_PNTSET == 3
237       // Points are passed "as is" to the creator.
238       // If first and last points are equal, we force "closed" flag to be set to false.
239       // For the case when first and last vertices are equal, this approach gives
240       // the same results with "closed" flag set to true and false.
241       bool isClosed = typeok && aCI.GetIsClosed() && !closed;
242       bool removeLast = false;
243       bool addFirst = false;
244 #elif BSPLINE_PROCESS_CLOSED_PNTSET == 4
245       // First point is added to the list if:
246       // a) first and last vertices are not equal;
247       // b) "closed" flag is set to true.
248       // In this case "closed" flag is forcidly set to false - bspline creator is 
249       // capable to create closed edge in this case.
250       // This approach gives the same results with "closed" flag set to true not
251       // depending on if set of points is closed or no.
252       // Also, it gives equal reqults in both case if set of points is closed or not
253       // and "closed" flag is set to true, in contrast to solution 3 above.
254       bool isClosed = false;
255       bool removeLast = false;
256       bool addFirst = typeok && aCI.GetIsClosed() && !closed;
257 #else
258       // Points are passed "as is" to the creator.
259       // This causes an error when first point is equal to last one and
260       // "closed" flag is set to true; see bug 0022885.
261       bool isClosed = typeok && aCI.GetIsClosed();
262       bool removeLast = false;
263       bool addFirst = false;
264 #endif
265
266       // remove last point or append first one if the conditions are observed (see above)
267       if (removeLast || addFirst) {
268         int extra = removeLast ? -1 : (addFirst ? 1 : 0 );
269         int nb = removeLast ? length-1 : length;
270         Handle(TColgp_HArray1OfPnt) curvePoints = new TColgp_HArray1OfPnt (1, length+extra);
271         for (int i = 1; i <= nb; i++)
272           curvePoints->SetValue(i, points->Value(i));
273         if (addFirst) curvePoints->SetValue(length+1, points->Value(1));
274         points = curvePoints;
275       }
276
277       // initial set-up of curve creator
278       GeomAPI_Interpolate GBC(points, isClosed, gp::Resolution());
279
280       // add tangent vectors constraints
281       if (aType == SPLINE_INTERPOL_TANGENTS) {
282         Handle(GEOM_Function) aVec1Ref = aCI.GetFirstVector();
283         Handle(GEOM_Function) aVec2Ref = aCI.GetLastVector();
284
285         if (aVec1Ref.IsNull() || aVec2Ref.IsNull())
286           // error: bad vector parameter is specified
287           Standard_NullObject::Raise("Null object is given for a vector");
288
289         // take orientation of edge into account to avoid regressions, as it was implemented so
290         gp_Vec aV1 = GEOMUtils::GetVector(aVec1Ref->GetValue(), Standard_True);
291         gp_Vec aV2 = GEOMUtils::GetVector(aVec2Ref->GetValue(), Standard_True);
292
293         // push constraint vectors to the curve creator
294         GBC.Load(aV1, aV2, /*Scale*/Standard_True);
295       }
296
297       // create bspline curve
298       GBC.Perform();
299       if (GBC.IsDone())
300         aShape = BRepBuilderAPI_MakeEdge(GBC.Curve()).Edge();
301     }
302   }
303   else {
304   }
305
306   if (aShape.IsNull()) return 0; // error: bad result
307
308   aFunction->SetValue(aShape);
309
310   log.SetTouched(Label());
311
312   return 1;
313 }
314
315 //================================================================================
316 /*!
317  * \brief Returns a name of creation operation and names and values of creation parameters
318  */
319 //================================================================================
320
321 bool GEOMImpl_SplineDriver::
322 GetCreationInformation(std::string&             theOperationName,
323                        std::vector<GEOM_Param>& theParams)
324 {
325   if (Label().IsNull()) return 0;
326   Handle(GEOM_Function) function = GEOM_Function::GetFunction(Label());
327
328   GEOMImpl_ISpline          aCI( function );
329   GEOMImpl_ICurveParametric aPI( function );
330   Standard_Integer aType = function->GetType();
331
332   theOperationName = "CURVE";
333
334   switch ( aType ) {
335   case SPLINE_BEZIER:
336   case SPLINE_INTERPOLATION:
337   case SPLINE_INTERPOL_TANGENTS:
338
339     AddParam( theParams, "Type", ( aType == SPLINE_BEZIER ? "Bezier" : "Interpolation"));
340
341     if ( aPI.HasData() )
342     {
343       AddParam( theParams, "X(t) equation", aPI.GetExprX() );
344       AddParam( theParams, "Y(t) equation", aPI.GetExprY() );
345       AddParam( theParams, "Z(t) equation", aPI.GetExprZ() );
346       AddParam( theParams, "Min t", aPI.GetParamMin() );
347       AddParam( theParams, "Max t", aPI.GetParamMax() );
348       if ( aPI.GetParamNbStep() )
349         AddParam( theParams, "Number of steps", aPI.GetParamNbStep() );
350       else
351         AddParam( theParams, "t step", aPI.GetParamStep() );
352     }
353     else
354     {
355       if ( aCI.GetConstructorType() == COORD_CONSTRUCTOR )
356       {
357         Handle(TColStd_HArray1OfReal) coords = aCI.GetCoordinates();
358         GEOM_Param& pntParam = AddParam( theParams, "Points");
359         pntParam << ( coords->Length() ) / 3 << " points: ";
360         for ( int i = coords->Lower(), nb = coords->Upper(); i <= nb; )
361           pntParam << "( " << coords->Value( i++ )
362                    << ", " << coords->Value( i++ )
363                    << ", " << coords->Value( i++ ) << " ) ";
364       }
365       else
366       {
367         AddParam( theParams, "Points", aCI.GetPoints() );
368       }
369       Handle(GEOM_Function) v1 = aCI.GetFirstVector();
370       Handle(GEOM_Function) v2 = aCI.GetLastVector();
371       if ( !v1.IsNull() ) AddParam( theParams, "First tangent vector", v1 );
372       if ( !v2.IsNull() ) AddParam( theParams, "Last tangent vector", v2 );
373     }
374     break;
375   default:
376     return false;
377   }
378
379   return true;
380 }
381
382 IMPLEMENT_STANDARD_HANDLE (GEOMImpl_SplineDriver,GEOM_BaseDriver);
383 IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_SplineDriver,GEOM_BaseDriver);