1 // Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "GEOMImpl_SplineDriver.hxx"
25 #include "GEOMImpl_ISpline.hxx"
26 #include "GEOMImpl_Types.hxx"
27 #include "GEOMImpl_ICurveParametric.hxx"
29 #include "GEOM_Function.hxx"
30 #include "GEOMUtils.hxx"
32 #include <BRepBuilderAPI_MakeEdge.hxx>
33 #include <BRepBuilderAPI_MakeVertex.hxx>
34 #include <BRep_Tool.hxx>
39 #include <TopoDS_Shape.hxx>
40 #include <TopoDS_Edge.hxx>
41 #include <TopoDS_Vertex.hxx>
43 #include <Geom_BezierCurve.hxx>
44 #include <GeomAPI_Interpolate.hxx>
48 #include <gp_Circ.hxx>
49 #include <Precision.hxx>
50 #include <TColgp_Array1OfPnt.hxx>
51 #include <TColgp_HArray1OfPnt.hxx>
53 #include <Standard_NullObject.hxx>
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
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
68 Handle(TColgp_HArray1OfPnt) pointsFromCoords(Handle(TColStd_HArray1OfReal) coords)
70 Standard_Integer length = coords->Length() / 3;
72 Handle(TColgp_HArray1OfPnt) points = new TColgp_HArray1OfPnt(1, length);
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));
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
90 Handle(TColgp_HArray1OfPnt) pointsFromObjs(Handle(TColStd_HSequenceOfTransient) objects)
92 Standard_Integer length = objects->Length();
94 Handle(TColgp_HArray1OfPnt) points = new TColgp_HArray1OfPnt(1, length);
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)));
108 //=======================================================================
111 //=======================================================================
112 const Standard_GUID& GEOMImpl_SplineDriver::GetID()
114 static Standard_GUID aSplineDriver("FF1BBB33-5D14-4df2-980B-3A668264EA16");
115 return aSplineDriver;
119 //=======================================================================
120 //function : GEOMImpl_SplineDriver
122 //=======================================================================
123 GEOMImpl_SplineDriver::GEOMImpl_SplineDriver()
127 //=======================================================================
130 //=======================================================================
131 Standard_Integer GEOMImpl_SplineDriver::Execute(TFunction_Logbook& log) const
133 if (Label().IsNull()) return 0;
134 Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
136 GEOMImpl_ISpline aCI (aFunction);
137 Standard_Integer aType = aFunction->GetType();
141 if (aType == SPLINE_BEZIER ||
142 aType == SPLINE_INTERPOLATION ||
143 aType == SPLINE_INTERPOL_TANGENTS) {
145 bool useCoords = aCI.GetConstructorType() == COORD_CONSTRUCTOR;
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();
151 if (length < 2) return 0; // error: not enough points in the input list
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);
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()) {
166 if (nearest > 0 && nearest != i + 1) {
167 // Keep given order of points to use it in case of equidistant candidates
170 // o o o c o->o->o->o->n o o
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);
179 } // end of reordering
181 bool closed = points->Value(1).Distance(points->Value(length)) <= gp::Resolution();
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;
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));
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())
197 curvePoints.SetValue(i, p);
202 // error: not enough points to create curve
203 Standard_ConstructionError::Raise("Points for Bezier Curve are too close");
205 // set last point equal to first for the closed Bezier curve
206 if (addFirst) curvePoints.SetValue(length+1, curvePoints.Value(1));
208 // create Bezier curve
209 Handle(Geom_BezierCurve) GBC = new Geom_BezierCurve(curvePoints);
210 aShape = BRepBuilderAPI_MakeEdge(GBC).Edge();
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;
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;
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;
277 // initial set-up of curve creator
278 GeomAPI_Interpolate GBC(points, isClosed, gp::Resolution());
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();
285 if (aVec1Ref.IsNull() || aVec2Ref.IsNull())
286 // error: bad vector parameter is specified
287 Standard_NullObject::Raise("Null object is given for a vector");
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);
293 // push constraint vectors to the curve creator
294 GBC.Load(aV1, aV2, /*Scale*/Standard_True);
297 // create bspline curve
300 aShape = BRepBuilderAPI_MakeEdge(GBC.Curve()).Edge();
306 if (aShape.IsNull()) return 0; // error: bad result
308 aFunction->SetValue(aShape);
310 log.SetTouched(Label());
315 //================================================================================
317 * \brief Returns a name of creation operation and names and values of creation parameters
319 //================================================================================
321 bool GEOMImpl_SplineDriver::
322 GetCreationInformation(std::string& theOperationName,
323 std::vector<GEOM_Param>& theParams)
325 if (Label().IsNull()) return 0;
326 Handle(GEOM_Function) function = GEOM_Function::GetFunction(Label());
328 GEOMImpl_ISpline aCI( function );
329 GEOMImpl_ICurveParametric aPI( function );
330 Standard_Integer aType = function->GetType();
332 theOperationName = "CURVE";
336 case SPLINE_INTERPOLATION:
337 case SPLINE_INTERPOL_TANGENTS:
339 AddParam( theParams, "Type", ( aType == SPLINE_BEZIER ? "Bezier" : "Interpolation"));
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() );
351 AddParam( theParams, "t step", aPI.GetParamStep() );
355 if ( aCI.GetConstructorType() == COORD_CONSTRUCTOR )
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++ ) << " ) ";
367 AddParam( theParams, "Points", aCI.GetPoints() );
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 );
382 IMPLEMENT_STANDARD_HANDLE (GEOMImpl_SplineDriver,GEOM_BaseDriver);
383 IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_SplineDriver,GEOM_BaseDriver);