1 // Copyright (C) 2007-2016 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 2
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(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()) {
156 gp_Pnt pPrev = points->Value(1);
157 for (int i = 1; i < length - 1; i++) {
158 gp_Pnt pi = points->Value(i);
160 double minDist = RealLast();
161 for (int j = i+1; j <= length; j++) {
162 double dist = pi.SquareDistance(points->Value(j));
163 if (dist < minDist && (minDist - dist) > Precision::Confusion()) {
168 if (nearest > 0 && nearest != i + 1) {
169 // Keep given order of points to use it in case of equidistant candidates
172 // o o o c o->o->o->o->n o o
175 gp_Pnt p = points->Value(nearest);
176 for (int j = nearest; j > i+1; j--)
177 points->SetValue(j, points->Value(j-1));
178 points->SetValue(i+1, p);
180 if ( pPrev.Distance(points->Value(i+1)) <= Precision::Confusion() )
183 pPrev = points->Value(i+1);
186 Handle(TColgp_HArray1OfPnt) tmpPoints = new TColgp_HArray1OfPnt(1, length-nbDup);
188 for (int i = 1; i <= length; i++) {
189 if (i == 1 || pPrev.Distance(points->Value(i)) > Precision::Confusion() ) {
190 tmpPoints->SetValue(j++, points->Value(i));
191 pPrev = points->Value(i);
195 length = points->Length();
197 } // end of reordering
199 bool closed = points->Value(1).Distance(points->Value(length)) <= gp::Resolution();
201 if (aType == SPLINE_BEZIER) {
202 // for Bezier curve we should append first point to the list if:
203 // a) "closed" flag is set, and
204 // b) first and last vertices are not too close
205 bool addFirst = aCI.GetIsClosed() && !closed;
207 // re-fill points and check that there's enough points to create a curve
208 bool isValid = false;
209 TColgp_Array1OfPnt curvePoints(1, length + (addFirst ? 1 : 0));
211 for (int i = 1; i <= length; i++) {
212 gp_Pnt p = points->Value(i);
213 if (!isValid && i > 1 && p.Distance(pp) > Precision::Confusion())
215 curvePoints.SetValue(i, p);
220 // error: not enough points to create curve
221 Standard_ConstructionError::Raise("Points for Bezier Curve are too close");
223 // set last point equal to first for the closed Bezier curve
224 if (addFirst) curvePoints.SetValue(length+1, curvePoints.Value(1));
226 // create Bezier curve
227 Handle(Geom_BezierCurve) GBC = new Geom_BezierCurve(curvePoints);
228 aShape = BRepBuilderAPI_MakeEdge(GBC).Edge();
231 // Below described processing of closed points set case
232 // is not done for constrained bsplined
233 bool typeok = aType == SPLINE_INTERPOLATION;
234 #if BSPLINE_PROCESS_CLOSED_PNTSET == 1
235 // Last point is removed from the list if:
236 // a) first and last vertices are equal;
237 // b) "closed" flag is not taken into account.
238 // If first and last points are equal, we force "closed" flag to be set to true.
239 // For the case when first and last vertices are equal, this approach causes
240 // result different that would be if last point had NOT be removed and "closed" flag is false.
241 bool isClosed = typeok && (aCI.GetIsClosed() || closed);
242 bool removeLast = typeok && closed;
243 bool addFirst = false;
244 #elif BSPLINE_PROCESS_CLOSED_PNTSET == 2
245 // Last point is removed from the list if:
246 // a) first and last vertices are equal;
247 // b) "closed" flag is set to true.
248 // Flag "closed" is taken "as is".
249 // For the case when first and last vertices are equal, this approach causes
250 // different results with "closed" flag set to true and false.
251 bool isClosed = typeok && aCI.GetIsClosed();
252 bool removeLast = typeok && aCI.GetIsClosed() && closed;
253 bool addFirst = false;
254 #elif BSPLINE_PROCESS_CLOSED_PNTSET == 3
255 // Points are passed "as is" to the creator.
256 // If first and last points are equal, we force "closed" flag to be set to false.
257 // For the case when first and last vertices are equal, this approach gives
258 // the same results with "closed" flag set to true and false.
259 bool isClosed = typeok && aCI.GetIsClosed() && !closed;
260 bool removeLast = false;
261 bool addFirst = false;
262 #elif BSPLINE_PROCESS_CLOSED_PNTSET == 4
263 // First point is added to the list if:
264 // a) first and last vertices are not equal;
265 // b) "closed" flag is set to true.
266 // In this case "closed" flag is forcidly set to false - bspline creator is
267 // capable to create closed edge in this case.
268 // This approach gives the same results with "closed" flag set to true not
269 // depending on if set of points is closed or no.
270 // Also, it gives equal reqults in both case if set of points is closed or not
271 // and "closed" flag is set to true, in contrast to solution 3 above.
272 bool isClosed = false;
273 bool removeLast = false;
274 bool addFirst = typeok && aCI.GetIsClosed() && !closed;
276 // Points are passed "as is" to the creator.
277 // This causes an error when first point is equal to last one and
278 // "closed" flag is set to true; see bug 0022885.
279 bool isClosed = typeok && aCI.GetIsClosed();
280 bool removeLast = false;
281 bool addFirst = false;
284 // remove last point or append first one if the conditions are observed (see above)
285 if (removeLast || addFirst) {
286 int extra = removeLast ? -1 : (addFirst ? 1 : 0 );
287 int nb = removeLast ? length-1 : length;
288 Handle(TColgp_HArray1OfPnt) curvePoints = new TColgp_HArray1OfPnt (1, length+extra);
289 for (int i = 1; i <= nb; i++)
290 curvePoints->SetValue(i, points->Value(i));
291 if (addFirst) curvePoints->SetValue(length+1, points->Value(1));
292 points = curvePoints;
295 // initial set-up of curve creator
296 GeomAPI_Interpolate GBC(points, isClosed, gp::Resolution());
298 // add tangent vectors constraints
299 if (aType == SPLINE_INTERPOL_TANGENTS) {
300 Handle(GEOM_Function) aVec1Ref = aCI.GetFirstVector();
301 Handle(GEOM_Function) aVec2Ref = aCI.GetLastVector();
303 if (aVec1Ref.IsNull() || aVec2Ref.IsNull())
304 // error: bad vector parameter is specified
305 Standard_NullObject::Raise("Null object is given for a vector");
307 // take orientation of edge into account to avoid regressions, as it was implemented so
308 gp_Vec aV1 = GEOMUtils::GetVector(aVec1Ref->GetValue(), Standard_True);
309 gp_Vec aV2 = GEOMUtils::GetVector(aVec2Ref->GetValue(), Standard_True);
311 // push constraint vectors to the curve creator
312 GBC.Load(aV1, aV2, /*Scale*/Standard_True);
315 // create bspline curve
318 aShape = BRepBuilderAPI_MakeEdge(GBC.Curve()).Edge();
324 if (aShape.IsNull()) return 0; // error: bad result
326 aFunction->SetValue(aShape);
328 #if OCC_VERSION_MAJOR < 7
329 log.SetTouched(Label());
331 log->SetTouched(Label());
337 //================================================================================
339 * \brief Returns a name of creation operation and names and values of creation parameters
341 //================================================================================
343 bool GEOMImpl_SplineDriver::
344 GetCreationInformation(std::string& theOperationName,
345 std::vector<GEOM_Param>& theParams)
347 if (Label().IsNull()) return 0;
348 Handle(GEOM_Function) function = GEOM_Function::GetFunction(Label());
350 GEOMImpl_ISpline aCI( function );
351 GEOMImpl_ICurveParametric aPI( function );
352 Standard_Integer aType = function->GetType();
354 theOperationName = "CURVE";
358 case SPLINE_INTERPOLATION:
359 case SPLINE_INTERPOL_TANGENTS:
361 AddParam( theParams, "Type", ( aType == SPLINE_BEZIER ? "Bezier" : "Interpolation"));
365 AddParam( theParams, "X(t) equation", aPI.GetExprX() );
366 AddParam( theParams, "Y(t) equation", aPI.GetExprY() );
367 AddParam( theParams, "Z(t) equation", aPI.GetExprZ() );
368 AddParam( theParams, "Min t", aPI.GetParamMin() );
369 AddParam( theParams, "Max t", aPI.GetParamMax() );
370 if ( aPI.GetParamNbStep() )
371 AddParam( theParams, "Number of steps", aPI.GetParamNbStep() );
373 AddParam( theParams, "t step", aPI.GetParamStep() );
377 if ( aCI.GetConstructorType() == COORD_CONSTRUCTOR )
379 Handle(TColStd_HArray1OfReal) coords = aCI.GetCoordinates();
380 GEOM_Param& pntParam = AddParam( theParams, "Points");
381 pntParam << ( coords->Length() ) / 3 << " points: ";
382 for ( int i = coords->Lower(), nb = coords->Upper(); i <= nb; )
383 pntParam << "( " << coords->Value( i++ )
384 << ", " << coords->Value( i++ )
385 << ", " << coords->Value( i++ ) << " ) ";
389 AddParam( theParams, "Points", aCI.GetPoints() );
391 Handle(GEOM_Function) v1 = aCI.GetFirstVector();
392 Handle(GEOM_Function) v2 = aCI.GetLastVector();
393 if ( !v1.IsNull() ) AddParam( theParams, "First tangent vector", v1 );
394 if ( !v2.IsNull() ) AddParam( theParams, "Last tangent vector", v2 );
404 OCCT_IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_SplineDriver,GEOM_BaseDriver);