Salome HOME
Implementation of SketchCopy feature
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Projection.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <SketchPlugin_Projection.h>
21
22 #include <SketchPlugin_Arc.h>
23 #include <SketchPlugin_BSpline.h>
24 #include <SketchPlugin_BSplinePeriodic.h>
25 #include <SketchPlugin_Circle.h>
26 #include <SketchPlugin_Ellipse.h>
27 #include <SketchPlugin_EllipticArc.h>
28 #include <SketchPlugin_Line.h>
29 #include <SketchPlugin_Point.h>
30 #include <SketchPlugin_Sketch.h>
31 #include <SketchPlugin_ConstraintRigid.h>
32
33 #include <ModelAPI_AttributeRefAttr.h>
34 #include <ModelAPI_AttributeSelection.h>
35 #include <ModelAPI_AttributeDouble.h>
36 #include <ModelAPI_AttributeDoubleArray.h>
37 #include <ModelAPI_AttributeInteger.h>
38 #include <ModelAPI_ResultConstruction.h>
39 #include <ModelAPI_Session.h>
40 #include <ModelAPI_Validator.h>
41 #include <ModelAPI_Tools.h>
42 #include <ModelAPI_Events.h>
43
44 #include <Events_Loop.h>
45
46 #include <GeomAPI_BSpline.h>
47 #include <GeomAPI_Circ.h>
48 #include <GeomAPI_Edge.h>
49 #include <GeomAPI_Ellipse.h>
50 #include <GeomAPI_Lin.h>
51 #include <GeomAPI_Pnt.h>
52 #include <GeomAPI_Pnt2d.h>
53 #include <GeomAPI_Vertex.h>
54 #include <GeomAlgoAPI_EdgeBuilder.h>
55 #include <GeomAlgoAPI_Projection.h>
56 #include <GeomDataAPI_Point2D.h>
57 #include <GeomDataAPI_Point2DArray.h>
58
59 #include <cmath>
60
61 static const double tolerance = 1.e-7;
62
63
64 SketchPlugin_Projection::SketchPlugin_Projection()
65     : SketchPlugin_SketchEntity(),
66       myIsComputing(false)
67 {
68 }
69
70 void SketchPlugin_Projection::initDerivedClassAttributes()
71 {
72   data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId());
73   data()->addAttribute(PROJECTED_FEATURE_ID(), ModelAPI_AttributeRefAttr::typeId());
74   data()->attribute(PROJECTED_FEATURE_ID())->setIsArgument(false);
75
76   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
77   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
78
79   data()->addAttribute(INCLUDE_INTO_RESULT(), ModelAPI_AttributeBoolean::typeId());
80
81   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID());
82 }
83
84 void SketchPlugin_Projection::execute()
85 {
86   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
87   if (!aRefAttr || !aRefAttr->isInitialized())
88     return;
89   FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
90
91   if (!lastResult().get()) {
92     bool hasProjResult = aProjection->lastResult().get() != NULL;
93     ResultConstructionPtr aConstr = document()->createConstruction(data());
94     if (hasProjResult)
95       aConstr->setShape(aProjection->lastResult()->shape());
96     aConstr->setIsInHistory(false);
97     aConstr->setDisplayed(false);
98     setResult(aConstr);
99
100     if (hasProjResult)
101       aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
102   }
103
104   // is sketch plane is changed (issue 1791), attribute of projection is not changed, but
105   // projection must be fully recomputed
106   computeProjection(EXTERNAL_FEATURE_ID());
107 }
108
109 void SketchPlugin_Projection::attributeChanged(const std::string& theID)
110 {
111   if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) {
112     myIsComputing = true;
113     computeProjection(theID);
114     myIsComputing = false;
115   }
116 }
117
118 static const std::set<std::string>& POINT_PROJECTION()
119 {
120   static std::set<std::string> aProj;
121   if (aProj.empty())
122     aProj.insert(SketchPlugin_Point::ID());
123   return aProj;
124 }
125
126 static const std::set<std::string>& LINE_PROJECTION()
127 {
128   static std::set<std::string> aProj;
129   if (aProj.empty())
130     aProj.insert(SketchPlugin_Line::ID());
131   return aProj;
132 }
133
134 static const std::set<std::string>& CIRCLE_ELLIPSE_PROJECTION()
135 {
136   static std::set<std::string> aProj;
137   if (aProj.empty()) {
138     aProj.insert(SketchPlugin_Circle::ID());
139     aProj.insert(SketchPlugin_Ellipse::ID());
140   }
141   return aProj;
142 }
143
144 static const std::set<std::string>& ARC_PROJECTION()
145 {
146   static std::set<std::string> aProj;
147   if (aProj.empty()) {
148     aProj.insert(SketchPlugin_Arc::ID());
149     aProj.insert(SketchPlugin_EllipticArc::ID());
150   }
151   return aProj;
152 }
153
154 static const std::set<std::string>& BSPLINE_PROJECTION()
155 {
156   static std::set<std::string> aProj;
157   if (aProj.empty()) {
158     aProj.insert(SketchPlugin_BSpline::ID());
159     aProj.insert(SketchPlugin_BSplinePeriodic::ID());
160   }
161   return aProj;
162 }
163
164
165 static const std::set<std::string>& possibleProjectionTypes(GeomEdgePtr theEdge,
166                                                             GeomVertexPtr theVertex)
167 {
168   if (theVertex)
169     return POINT_PROJECTION();
170   if (theEdge) {
171     if (theEdge->isLine())
172       return LINE_PROJECTION();
173     else if (theEdge->isCircle() || theEdge->isArc() || theEdge->isEllipse()) {
174       if (theEdge->isClosed())
175         return CIRCLE_ELLIPSE_PROJECTION();
176       else
177         return ARC_PROJECTION();
178     }
179     else
180       return BSPLINE_PROJECTION();
181   }
182   static const std::set<std::string> DUMMY;
183   return DUMMY;
184 }
185
186 void SketchPlugin_Projection::computeProjection(const std::string& theID)
187 {
188   AttributeSelectionPtr aExtFeature =
189       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(attribute(EXTERNAL_FEATURE_ID()));
190
191   GeomShapePtr aShape;
192   GeomEdgePtr anEdge;
193   GeomVertexPtr aVertex;
194   if (aExtFeature)
195     aShape = aExtFeature->value();
196   if (!aShape && aExtFeature->context())
197     aShape = aExtFeature->context()->shape();
198   if (aShape) {
199     if (aShape->isEdge())
200       anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
201     else if (aShape->isVertex())
202       aVertex = GeomVertexPtr(new GeomAPI_Vertex(aShape));
203   }
204   if (!anEdge && !aVertex)
205     return;
206
207   const std::set<std::string>& aProjType = possibleProjectionTypes(anEdge, aVertex);
208
209   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
210   FeaturePtr aProjection;
211   if (aRefAttr && aRefAttr->isInitialized())
212     aProjection = ModelAPI_Feature::feature(aRefAttr->object());
213
214   // if the type of feature differs with already selected, remove it and create once again
215   bool isRebuild = rebuildProjectedFeature(aProjection, aProjType);
216
217   ResultConstructionPtr aResult =
218       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(lastResult());
219   if (!isRebuild && aResult && aResult->shape() && theID == EXTERNAL_FEATURE_ID()) {
220     aResult->setShape(std::shared_ptr<GeomAPI_Edge>());
221     if (aProjection)
222       aProjection->selection(EXTERNAL_ID())->setValue(ResultPtr(), GeomShapePtr());
223   }
224
225   keepCurrentFeature();
226
227   bool isProjected = false;
228   if (aVertex)
229     isProjected = projectPoint(aProjection, aVertex->point());
230   else
231     isProjected = projectEdge(aProjection, anEdge);
232
233   if (!isProjected)
234     return; // projection is not computed, stop processing
235
236   aProjection->boolean(COPY_ID())->setValue(true);
237   aProjection->execute();
238   aRefAttr->setObject(aProjection);
239
240   restoreCurrentFeature();
241
242   if (theID == EXTERNAL_FEATURE_ID()) {
243     selection(EXTERNAL_ID())->selectValue(aExtFeature);
244
245     if (aResult) {
246       aResult->setShape(aProjection->lastResult()->shape());
247       setResult(aResult);
248       GeomShapePtr anEmptyVal;
249       aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal);
250
251       static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
252       ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false);
253     }
254   }
255 }
256
257 bool SketchPlugin_Projection::rebuildProjectedFeature(
258     FeaturePtr& theProjection,
259     const std::set<std::string>& theSupportedTypes,
260     const std::string& theRequestedFeature)
261 {
262   bool isRebuild = false;
263   if (theProjection &&
264       (theSupportedTypes.find(theProjection->getKind()) == theSupportedTypes.end() ||
265       (!theRequestedFeature.empty() && theProjection->getKind() != theRequestedFeature))) {
266     DocumentPtr aDoc = sketch()->document();
267
268     AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
269     aRefAttr->setObject(data()->owner()); // to not remove of this remove reference to aProjection
270     std::set<FeaturePtr> aFeaturesToBeRemoved;
271     aFeaturesToBeRemoved.insert(theProjection);
272     ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
273     theProjection = FeaturePtr();
274     aRefAttr->setObject(theProjection);
275     isRebuild = true;
276   }
277
278   if (!theProjection && !theRequestedFeature.empty())
279     theProjection = sketch()->addFeature(theRequestedFeature);
280   return isRebuild;
281 }
282
283 bool SketchPlugin_Projection::projectPoint(FeaturePtr& theProjection, const GeomPointPtr& thePoint)
284 {
285   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
286
287   std::shared_ptr<GeomAPI_Pnt> aPrjPnt = aSketchPlane->project(thePoint);
288   std::shared_ptr<GeomAPI_Pnt2d> aPntInSketch = sketch()->to2D(aPrjPnt);
289
290   rebuildProjectedFeature(theProjection, POINT_PROJECTION(), SketchPlugin_Point::ID());
291
292   // update coordinates of projection
293   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
294       theProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch);
295   return true;
296 }
297
298 bool SketchPlugin_Projection::projectSegment(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
299 {
300   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
301
302   std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(theEdge->firstPoint());
303   std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(theEdge->lastPoint());
304
305   std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
306   std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
307   if (aFirstInSketch->distance(aLastInSketch) < tolerance)
308     return false; // line is semi-orthogonal to the sketch plane
309
310   rebuildProjectedFeature(theProjection, LINE_PROJECTION(), SketchPlugin_Line::ID());
311
312   // update attributes of projection
313   std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
314       theProjection->attribute(SketchPlugin_Line::START_ID()));
315   std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
316       theProjection->attribute(SketchPlugin_Line::END_ID()));
317   aStartPnt->setValue(aFirstInSketch);
318   aEndPnt->setValue(aLastInSketch);
319
320   return true;
321 }
322
323 bool SketchPlugin_Projection::projectEdge(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
324 {
325   if (theEdge->isLine())
326     return projectSegment(theProjection, theEdge);
327
328   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
329
330   GeomAlgoAPI_Projection aProjAlgo(aSketchPlane);
331   GeomCurvePtr aProjectedCurve = aProjAlgo.project(theEdge);
332
333   bool isOk = false;
334   if (aProjectedCurve->isCircle()) {
335     if (aProjectedCurve->isTrimmed()) {
336       // ARC is a projection
337       isOk = fillArc(theProjection, aProjectedCurve, aSketchPlane);
338     }
339     else {
340       // CIRCLE is a projection
341       isOk = fillCircle(theProjection, aProjectedCurve, aSketchPlane);
342     }
343   }
344   else if (aProjectedCurve->isEllipse()) {
345     if (aProjectedCurve->isTrimmed()) {
346       // ELLIPTIC ARC is a projection
347       isOk = fillEllipticArc(theProjection, aProjectedCurve, aSketchPlane);
348     }
349     else {
350       // ELLIPSE is a projection
351       isOk = fillEllipse(theProjection, aProjectedCurve, aSketchPlane);
352     }
353   }
354   else
355     isOk = fillBSpline(theProjection, aProjectedCurve, aSketchPlane);
356
357   return isOk;
358 }
359
360 bool SketchPlugin_Projection::fillArc(FeaturePtr& theProjection,
361                                       const GeomCurvePtr& theArc,
362                                       const GeomPlanePtr& thePlane)
363 {
364   rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID());
365
366   GeomAPI_Circ aCircle(theArc);
367
368   double aNormalsDot = aCircle.normal()->dot(thePlane->direction());
369   if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
370     return false; // arc is not in the plane, parallel to the sketch plane
371
372   bool isInversed = aNormalsDot < 0.;
373
374   GeomPointPtr aCenter = thePlane->project(aCircle.center());
375   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
376
377   GeomPointPtr aFirst = theArc->getPoint(theArc->startParam());
378   GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
379
380   GeomPointPtr aLast = theArc->getPoint(theArc->endParam());
381   GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
382
383   bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
384
385   // update attributes of projection
386   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
387       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
388       theProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
389   std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
390       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
391       theProjection->attribute(SketchPlugin_Arc::START_ID()));
392   std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
393       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
394       theProjection->attribute(SketchPlugin_Arc::END_ID()));
395   aStartPnt->setValue(aFirstInSketch);
396   aEndPnt->setValue(aLastInSketch);
397   aCenterPnt->setValue(aCenterInSketch);
398   theProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
399
400   theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
401   return true;
402 }
403
404 bool SketchPlugin_Projection::fillCircle(FeaturePtr& theProjection,
405                                          const GeomCurvePtr& theCircle,
406                                          const GeomPlanePtr& thePlane)
407 {
408   rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Circle::ID());
409
410   GeomAPI_Circ aCircle(theCircle);
411   GeomPointPtr aCenter = thePlane->project(aCircle.center());
412   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
413
414   // update attributes of projection
415   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
416       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
417       theProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
418   aCenterPnt->setValue(aCenterInSketch);
419   theProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius());
420   return true;
421 }
422
423 bool SketchPlugin_Projection::fillEllipse(FeaturePtr& theProjection,
424                                           const GeomCurvePtr& theEllipse,
425                                           const GeomPlanePtr& thePlane)
426 {
427   rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Ellipse::ID());
428
429   GeomAPI_Ellipse anEllipse(theEllipse);
430   GeomPointPtr aCenter = thePlane->project(anEllipse.center());
431   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
432   GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
433   GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
434
435   // update attributes of projection
436   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
437       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
438       theProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
439   aCenterPnt->setValue(aCenterInSketch);
440   std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
441       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
442       theProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
443   aFocusPnt->setValue(aFocusInSketch);
444   theProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(anEllipse.minorRadius());
445   return true;
446 }
447
448 bool SketchPlugin_Projection::fillEllipticArc(FeaturePtr& theProjection,
449                                               const GeomCurvePtr& theEllipticArc,
450                                               const GeomPlanePtr& thePlane)
451 {
452   rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID());
453
454   GeomAPI_Ellipse anEllipse(theEllipticArc);
455
456   double aNormalsDot = anEllipse.normal()->dot(thePlane->direction());
457   if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
458     return false; // arc is not in the plane, parallel to the sketch plane
459
460   bool isInversed = aNormalsDot < 0.;
461
462   GeomPointPtr aCenter = thePlane->project(anEllipse.center());
463   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
464   GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
465   GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
466
467   GeomPointPtr aFirst = theEllipticArc->getPoint(theEllipticArc->startParam());
468   GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
469   GeomPointPtr aLast = theEllipticArc->getPoint(theEllipticArc->endParam());
470   GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
471
472   bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
473
474   // update attributes of projection
475   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
476       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
477       theProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
478   std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
479       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
480       theProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
481   std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
482       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
483       theProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
484   std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
485       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
486       theProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
487   aStartPnt->setValue(aFirstInSketch);
488   aEndPnt->setValue(aLastInSketch);
489   aCenterPnt->setValue(aCenterInSketch);
490   aFocusPnt->setValue(aFocusInSketch);
491   theProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed);
492
493   theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
494   return true;
495 }
496
497 bool SketchPlugin_Projection::fillBSpline(FeaturePtr& theProjection,
498                                           const GeomCurvePtr& theCurve,
499                                           const GeomPlanePtr& thePlane)
500 {
501   GeomAPI_BSpline aBSpline(theCurve);
502
503   rebuildProjectedFeature(theProjection, BSPLINE_PROJECTION(),
504       aBSpline.isPeriodic() ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
505
506   theProjection->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(aBSpline.degree());
507
508   AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
509       theProjection->attribute(SketchPlugin_BSpline::POLES_ID()));
510   std::list<GeomPointPtr> aPoles = aBSpline.poles();
511   aPolesAttr->setSize((int)aPoles.size());
512   std::list<GeomPointPtr>::iterator anIt = aPoles.begin();
513   for (int anIndex = 0; anIt != aPoles.end(); ++anIt, ++anIndex) {
514     GeomPnt2dPtr aPoleInSketch = sketch()->to2D(*anIt);
515     aPolesAttr->setPnt(anIndex, aPoleInSketch);
516   }
517
518   AttributeDoubleArrayPtr aWeightsAttr =
519       theProjection->data()->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
520   std::list<double> aWeights = aBSpline.weights();
521   if (aWeights.empty()) { // rational B-spline
522     int aSize = (int)aPoles.size();
523     aWeightsAttr->setSize(aSize);
524     for (int anIndex = 0; anIndex < aSize; ++anIndex)
525       aWeightsAttr->setValue(anIndex, 1.0);
526   }
527   else { // non-rational B-spline
528     aWeightsAttr->setSize((int)aWeights.size());
529     std::list<double>::iterator anIt = aWeights.begin();
530     for (int anIndex = 0; anIt != aWeights.end(); ++anIt, ++anIndex)
531       aWeightsAttr->setValue(anIndex, *anIt);
532   }
533
534   AttributeDoubleArrayPtr aKnotsAttr =
535       theProjection->data()->realArray(SketchPlugin_BSpline::KNOTS_ID());
536   std::list<double> aKnots = aBSpline.knots();
537   int aSize = (int)aKnots.size();
538   aKnotsAttr->setSize(aSize);
539   std::list<double>::iterator aKIt = aKnots.begin();
540   for (int index = 0; index < aSize; ++index, ++aKIt)
541     aKnotsAttr->setValue(index, *aKIt);
542
543   AttributeIntArrayPtr aMultsAttr =
544       theProjection->data()->intArray(SketchPlugin_BSpline::MULTS_ID());
545   std::list<int> aMultiplicities = aBSpline.mults();
546   aSize = (int)aMultiplicities.size();
547   aMultsAttr->setSize(aSize);
548   std::list<int>::iterator aMIt = aMultiplicities.begin();
549   for (int index = 0; index < aSize; ++index, ++aMIt)
550     aMultsAttr->setValue(index, *aMIt);
551
552   return true;
553 }