Salome HOME
Task #3235: Projection without link to source shape
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Projection.cpp
1 // Copyright (C) 2014-2020  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_AttributeString.h>
39 #include <ModelAPI_ResultConstruction.h>
40 #include <ModelAPI_Session.h>
41 #include <ModelAPI_Validator.h>
42 #include <ModelAPI_Tools.h>
43 #include <ModelAPI_Events.h>
44
45 #include <Events_Loop.h>
46
47 #include <GeomAPI_BSpline.h>
48 #include <GeomAPI_Circ.h>
49 #include <GeomAPI_Edge.h>
50 #include <GeomAPI_Ellipse.h>
51 #include <GeomAPI_Lin.h>
52 #include <GeomAPI_Pnt.h>
53 #include <GeomAPI_Pnt2d.h>
54 #include <GeomAPI_Vertex.h>
55 #include <GeomAlgoAPI_EdgeBuilder.h>
56 #include <GeomAlgoAPI_Projection.h>
57 #include <GeomDataAPI_Point2D.h>
58 #include <GeomDataAPI_Point2DArray.h>
59
60 #include <cmath>
61
62 static const double tolerance = 1.e-7;
63 static const std::string THE_KEEP_REF("true");
64
65 static bool isKeepReference(AttributeStringPtr theAttr)
66 {
67   return !theAttr || !theAttr->isInitialized() || theAttr->value() == THE_KEEP_REF;
68 }
69
70
71 SketchPlugin_Projection::SketchPlugin_Projection()
72     : SketchPlugin_SketchEntity(),
73       myIsComputing(false)
74 {
75 }
76
77 void SketchPlugin_Projection::initDerivedClassAttributes()
78 {
79   data()->addAttribute(EXTERNAL_FEATURE_ID(), ModelAPI_AttributeSelection::typeId());
80   data()->addAttribute(PROJECTED_FEATURE_ID(), ModelAPI_AttributeRefAttr::typeId());
81   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PROJECTED_FEATURE_ID());
82   data()->attribute(PROJECTED_FEATURE_ID())->setIsArgument(false);
83
84   data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
85   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
86
87   data()->addAttribute(INCLUDE_INTO_RESULT(), ModelAPI_AttributeBoolean::typeId());
88
89   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), AUXILIARY_ID());
90 }
91
92 void SketchPlugin_Projection::initDerivedClassAttributes2()
93 {
94   AttributePtr aKeepRefAttr =
95       data()->addAttribute(KEEP_REFERENCE_ID(), ModelAPI_AttributeString::typeId());
96   if (!aKeepRefAttr->isInitialized()) {
97     std::dynamic_pointer_cast<ModelAPI_AttributeString>(aKeepRefAttr)->setValue(THE_KEEP_REF);
98   }
99
100   data()->addAttribute(MAKE_FIXED(), ModelAPI_AttributeBoolean::typeId());
101   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), MAKE_FIXED());
102
103   data()->addAttribute(FIXED_CONSTRAINT_ID(), ModelAPI_AttributeReference::typeId());
104   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FIXED_CONSTRAINT_ID());
105   data()->attribute(FIXED_CONSTRAINT_ID())->setIsArgument(false);
106 }
107
108 void SketchPlugin_Projection::execute()
109 {
110   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
111   if (!aRefAttr || !aRefAttr->isInitialized())
112     return;
113   FeaturePtr aProjection = ModelAPI_Feature::feature(aRefAttr->object());
114
115   if (isKeepReference(string(KEEP_REFERENCE_ID())) && !lastResult().get()) {
116     bool hasProjResult = aProjection->lastResult().get() != NULL;
117     ResultConstructionPtr aConstr = document()->createConstruction(data());
118     if (hasProjResult)
119       aConstr->setShape(aProjection->lastResult()->shape());
120     aConstr->setIsInHistory(false);
121     aConstr->setDisplayed(false);
122     setResult(aConstr);
123
124     if (hasProjResult)
125       aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), lastResult()->shape());
126   }
127
128   // is sketch plane is changed (issue 1791), attribute of projection is not changed, but
129   // projection must be fully recomputed
130   computeProjection(EXTERNAL_FEATURE_ID());
131 }
132
133 bool SketchPlugin_Projection::isMacro() const
134 {
135   if (!data() || !data()->isValid())
136     return false;
137
138   AttributeStringPtr aKeepRefAttr =
139       const_cast<SketchPlugin_Projection*>(this)->string(KEEP_REFERENCE_ID());
140   return !isKeepReference(aKeepRefAttr);
141 }
142
143 void SketchPlugin_Projection::attributeChanged(const std::string& theID)
144 {
145   if ((theID == EXTERNAL_FEATURE_ID() || theID == EXTERNAL_ID()) && !myIsComputing) {
146     myIsComputing = true;
147     computeProjection(theID);
148     myIsComputing = false;
149   }
150 }
151
152 static const std::set<std::string>& POINT_PROJECTION()
153 {
154   static std::set<std::string> aProj;
155   if (aProj.empty())
156     aProj.insert(SketchPlugin_Point::ID());
157   return aProj;
158 }
159
160 static const std::set<std::string>& LINE_PROJECTION()
161 {
162   static std::set<std::string> aProj;
163   if (aProj.empty())
164     aProj.insert(SketchPlugin_Line::ID());
165   return aProj;
166 }
167
168 static const std::set<std::string>& CIRCLE_ELLIPSE_PROJECTION()
169 {
170   static std::set<std::string> aProj;
171   if (aProj.empty()) {
172     aProj.insert(SketchPlugin_Circle::ID());
173     aProj.insert(SketchPlugin_Ellipse::ID());
174   }
175   return aProj;
176 }
177
178 static const std::set<std::string>& ARC_PROJECTION()
179 {
180   static std::set<std::string> aProj;
181   if (aProj.empty()) {
182     aProj.insert(SketchPlugin_Arc::ID());
183     aProj.insert(SketchPlugin_EllipticArc::ID());
184   }
185   return aProj;
186 }
187
188 static const std::set<std::string>& BSPLINE_PROJECTION()
189 {
190   static std::set<std::string> aProj;
191   if (aProj.empty()) {
192     aProj.insert(SketchPlugin_BSpline::ID());
193     aProj.insert(SketchPlugin_BSplinePeriodic::ID());
194   }
195   return aProj;
196 }
197
198
199 static const std::set<std::string>& possibleProjectionTypes(GeomEdgePtr theEdge,
200                                                             GeomVertexPtr theVertex)
201 {
202   if (theVertex)
203     return POINT_PROJECTION();
204   if (theEdge) {
205     if (theEdge->isLine())
206       return LINE_PROJECTION();
207     else if (theEdge->isCircle() || theEdge->isArc() || theEdge->isEllipse()) {
208       if (theEdge->isClosed())
209         return CIRCLE_ELLIPSE_PROJECTION();
210       else
211         return ARC_PROJECTION();
212     }
213     else
214       return BSPLINE_PROJECTION();
215   }
216   static const std::set<std::string> DUMMY;
217   return DUMMY;
218 }
219
220 void SketchPlugin_Projection::computeProjection(const std::string& theID)
221 {
222   AttributeSelectionPtr aExtFeature =
223       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(attribute(EXTERNAL_FEATURE_ID()));
224
225   GeomShapePtr aShape;
226   GeomEdgePtr anEdge;
227   GeomVertexPtr aVertex;
228   if (aExtFeature)
229     aShape = aExtFeature->value();
230   if (!aShape && aExtFeature->context())
231     aShape = aExtFeature->context()->shape();
232   if (aShape) {
233     if (aShape->isEdge())
234       anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
235     else if (aShape->isVertex())
236       aVertex = GeomVertexPtr(new GeomAPI_Vertex(aShape));
237   }
238   if (!anEdge && !aVertex)
239     return;
240
241   const std::set<std::string>& aProjType = possibleProjectionTypes(anEdge, aVertex);
242
243   AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
244   FeaturePtr aProjection;
245   if (aRefAttr && aRefAttr->isInitialized())
246     aProjection = ModelAPI_Feature::feature(aRefAttr->object());
247
248   // if the type of feature differs with already selected, remove it and create once again
249   bool isRebuild = rebuildProjectedFeature(aProjection, aProjType);
250
251   ResultConstructionPtr aResult =
252       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(lastResult());
253   if (!isRebuild && aResult && aResult->shape() && theID == EXTERNAL_FEATURE_ID()) {
254     aResult->setShape(std::shared_ptr<GeomAPI_Edge>());
255     if (aProjection)
256       aProjection->selection(EXTERNAL_ID())->setValue(ResultPtr(), GeomShapePtr());
257   }
258
259   keepCurrentFeature();
260
261   bool isProjected = false;
262   if (aVertex)
263     isProjected = projectPoint(aProjection, aVertex->point());
264   else
265     isProjected = projectEdge(aProjection, anEdge);
266
267   if (!isProjected)
268     return; // projection is not computed, stop processing
269
270   bool keepBackRef = isKeepReference(string(KEEP_REFERENCE_ID()));
271
272   aProjection->boolean(COPY_ID())->setValue(keepBackRef);
273   aProjection->execute();
274   aRefAttr->setObject(aProjection);
275
276   restoreCurrentFeature();
277
278   AttributeBooleanPtr aMakeFixedAttr = boolean(MAKE_FIXED());
279   bool isMakeFixed = aMakeFixedAttr && aMakeFixedAttr->isInitialized() && aMakeFixedAttr->value();
280
281   AttributeReferencePtr aFixedConstrAttr = reference(FIXED_CONSTRAINT_ID());
282   FeaturePtr aFixedConstraint;
283   if (aFixedConstrAttr && aFixedConstrAttr->isInitialized())
284     aFixedConstraint = ModelAPI_Feature::feature(aFixedConstrAttr->value());
285
286   if (keepBackRef) {
287     if (theID == EXTERNAL_FEATURE_ID()) {
288       selection(EXTERNAL_ID())->selectValue(aExtFeature);
289
290       if (aResult) {
291         aResult->setShape(aProjection->lastResult()->shape());
292         setResult(aResult);
293         GeomShapePtr anEmptyVal;
294         aProjection->selection(EXTERNAL_ID())->setValue(lastResult(), anEmptyVal);
295       }
296     }
297   }
298   else if (isMakeFixed) {
299     // fix the projected entity with the Fixed constraint
300     if (!aFixedConstraint)
301       aFixedConstraint = sketch()->addFeature(SketchPlugin_ConstraintRigid::ID());
302     aFixedConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(
303                               aProjection->lastResult());
304   }
305
306
307   // remove Fixed constraint in case of redundance
308   if (aFixedConstraint && (keepBackRef || !isMakeFixed)) {
309     document()->removeFeature(aFixedConstraint);
310     aFixedConstraint = FeaturePtr();
311   }
312   aFixedConstrAttr->setValue(aFixedConstraint);
313
314   static const Events_ID anEvent = Events_Loop::eventByName(EVENT_VISUAL_ATTRIBUTES);
315   ModelAPI_EventCreator::get()->sendUpdated(aProjection, anEvent, false);
316 }
317
318 bool SketchPlugin_Projection::rebuildProjectedFeature(
319     FeaturePtr& theProjection,
320     const std::set<std::string>& theSupportedTypes,
321     const std::string& theRequestedFeature)
322 {
323   bool isRebuild = false;
324   if (theProjection &&
325       (theSupportedTypes.find(theProjection->getKind()) == theSupportedTypes.end() ||
326       (!theRequestedFeature.empty() && theProjection->getKind() != theRequestedFeature))) {
327     DocumentPtr aDoc = sketch()->document();
328
329     AttributeRefAttrPtr aRefAttr = data()->refattr(PROJECTED_FEATURE_ID());
330     aRefAttr->setObject(data()->owner()); // to not remove of this remove reference to aProjection
331     std::set<FeaturePtr> aFeaturesToBeRemoved;
332     aFeaturesToBeRemoved.insert(theProjection);
333     ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToBeRemoved);
334     theProjection = FeaturePtr();
335     aRefAttr->setObject(theProjection);
336     isRebuild = true;
337   }
338
339   if (!theProjection && !theRequestedFeature.empty())
340     theProjection = sketch()->addFeature(theRequestedFeature);
341   return isRebuild;
342 }
343
344 bool SketchPlugin_Projection::projectPoint(FeaturePtr& theProjection, const GeomPointPtr& thePoint)
345 {
346   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
347
348   std::shared_ptr<GeomAPI_Pnt> aPrjPnt = aSketchPlane->project(thePoint);
349   std::shared_ptr<GeomAPI_Pnt2d> aPntInSketch = sketch()->to2D(aPrjPnt);
350
351   rebuildProjectedFeature(theProjection, POINT_PROJECTION(), SketchPlugin_Point::ID());
352
353   // update coordinates of projection
354   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
355       theProjection->attribute(SketchPlugin_Point::COORD_ID()))->setValue(aPntInSketch);
356   return true;
357 }
358
359 bool SketchPlugin_Projection::projectSegment(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
360 {
361   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
362
363   std::shared_ptr<GeomAPI_Pnt> aFirst = aSketchPlane->project(theEdge->firstPoint());
364   std::shared_ptr<GeomAPI_Pnt> aLast = aSketchPlane->project(theEdge->lastPoint());
365
366   std::shared_ptr<GeomAPI_Pnt2d> aFirstInSketch = sketch()->to2D(aFirst);
367   std::shared_ptr<GeomAPI_Pnt2d> aLastInSketch = sketch()->to2D(aLast);
368   if (aFirstInSketch->distance(aLastInSketch) < tolerance)
369     return false; // line is semi-orthogonal to the sketch plane
370
371   rebuildProjectedFeature(theProjection, LINE_PROJECTION(), SketchPlugin_Line::ID());
372
373   // update attributes of projection
374   std::shared_ptr<GeomDataAPI_Point2D> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
375       theProjection->attribute(SketchPlugin_Line::START_ID()));
376   std::shared_ptr<GeomDataAPI_Point2D> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
377       theProjection->attribute(SketchPlugin_Line::END_ID()));
378   aStartPnt->setValue(aFirstInSketch);
379   aEndPnt->setValue(aLastInSketch);
380
381   return true;
382 }
383
384 bool SketchPlugin_Projection::projectEdge(FeaturePtr& theProjection, const GeomEdgePtr& theEdge)
385 {
386   if (theEdge->isLine())
387     return projectSegment(theProjection, theEdge);
388
389   std::shared_ptr<GeomAPI_Pln> aSketchPlane = sketch()->plane();
390
391   GeomAlgoAPI_Projection aProjAlgo(aSketchPlane);
392   GeomCurvePtr aProjectedCurve = aProjAlgo.project(theEdge);
393
394   bool isOk = false;
395   if (aProjectedCurve->isCircle()) {
396     if (aProjectedCurve->isTrimmed()) {
397       // ARC is a projection
398       isOk = fillArc(theProjection, aProjectedCurve, aSketchPlane);
399     }
400     else {
401       // CIRCLE is a projection
402       isOk = fillCircle(theProjection, aProjectedCurve, aSketchPlane);
403     }
404   }
405   else if (aProjectedCurve->isEllipse()) {
406     if (aProjectedCurve->isTrimmed()) {
407       // ELLIPTIC ARC is a projection
408       isOk = fillEllipticArc(theProjection, aProjectedCurve, aSketchPlane);
409     }
410     else {
411       // ELLIPSE is a projection
412       isOk = fillEllipse(theProjection, aProjectedCurve, aSketchPlane);
413     }
414   }
415   else
416     isOk = fillBSpline(theProjection, aProjectedCurve, aSketchPlane);
417
418   return isOk;
419 }
420
421 bool SketchPlugin_Projection::fillArc(FeaturePtr& theProjection,
422                                       const GeomCurvePtr& theArc,
423                                       const GeomPlanePtr& thePlane)
424 {
425   rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID());
426
427   GeomAPI_Circ aCircle(theArc);
428
429   double aNormalsDot = aCircle.normal()->dot(thePlane->direction());
430   if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
431     return false; // arc is not in the plane, parallel to the sketch plane
432
433   bool isInversed = aNormalsDot < 0.;
434
435   GeomPointPtr aCenter = thePlane->project(aCircle.center());
436   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
437
438   GeomPointPtr aFirst = theArc->getPoint(theArc->startParam());
439   GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
440
441   GeomPointPtr aLast = theArc->getPoint(theArc->endParam());
442   GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
443
444   bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
445
446   // update attributes of projection
447   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
448       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
449       theProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
450   std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
451       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
452       theProjection->attribute(SketchPlugin_Arc::START_ID()));
453   std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
454       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
455       theProjection->attribute(SketchPlugin_Arc::END_ID()));
456   aStartPnt->setValue(aFirstInSketch);
457   aEndPnt->setValue(aLastInSketch);
458   aCenterPnt->setValue(aCenterInSketch);
459   theProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
460
461   theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
462   return true;
463 }
464
465 bool SketchPlugin_Projection::fillCircle(FeaturePtr& theProjection,
466                                          const GeomCurvePtr& theCircle,
467                                          const GeomPlanePtr& thePlane)
468 {
469   rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Circle::ID());
470
471   GeomAPI_Circ aCircle(theCircle);
472   GeomPointPtr aCenter = thePlane->project(aCircle.center());
473   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
474
475   // update attributes of projection
476   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
477       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
478       theProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
479   aCenterPnt->setValue(aCenterInSketch);
480   theProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius());
481   return true;
482 }
483
484 bool SketchPlugin_Projection::fillEllipse(FeaturePtr& theProjection,
485                                           const GeomCurvePtr& theEllipse,
486                                           const GeomPlanePtr& thePlane)
487 {
488   rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Ellipse::ID());
489
490   GeomAPI_Ellipse anEllipse(theEllipse);
491   GeomPointPtr aCenter = thePlane->project(anEllipse.center());
492   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
493   GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
494   GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
495
496   // update attributes of projection
497   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
498       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
499       theProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
500   aCenterPnt->setValue(aCenterInSketch);
501   std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
502       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
503       theProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
504   aFocusPnt->setValue(aFocusInSketch);
505   theProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(anEllipse.minorRadius());
506   return true;
507 }
508
509 bool SketchPlugin_Projection::fillEllipticArc(FeaturePtr& theProjection,
510                                               const GeomCurvePtr& theEllipticArc,
511                                               const GeomPlanePtr& thePlane)
512 {
513   rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID());
514
515   GeomAPI_Ellipse anEllipse(theEllipticArc);
516
517   double aNormalsDot = anEllipse.normal()->dot(thePlane->direction());
518   if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
519     return false; // arc is not in the plane, parallel to the sketch plane
520
521   bool isInversed = aNormalsDot < 0.;
522
523   GeomPointPtr aCenter = thePlane->project(anEllipse.center());
524   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
525   GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
526   GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
527
528   GeomPointPtr aFirst = theEllipticArc->getPoint(theEllipticArc->startParam());
529   GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
530   GeomPointPtr aLast = theEllipticArc->getPoint(theEllipticArc->endParam());
531   GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
532
533   bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
534
535   // update attributes of projection
536   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
537       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
538       theProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
539   std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
540       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
541       theProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
542   std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
543       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
544       theProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
545   std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
546       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
547       theProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
548   aStartPnt->setValue(aFirstInSketch);
549   aEndPnt->setValue(aLastInSketch);
550   aCenterPnt->setValue(aCenterInSketch);
551   aFocusPnt->setValue(aFocusInSketch);
552   theProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed);
553
554   theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
555   return true;
556 }
557
558 bool SketchPlugin_Projection::fillBSpline(FeaturePtr& theProjection,
559                                           const GeomCurvePtr& theCurve,
560                                           const GeomPlanePtr& /*thePlane*/)
561 {
562   GeomAPI_BSpline aBSpline(theCurve);
563
564   rebuildProjectedFeature(theProjection, BSPLINE_PROJECTION(),
565       aBSpline.isPeriodic() ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
566
567   theProjection->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(aBSpline.degree());
568
569   AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
570       theProjection->attribute(SketchPlugin_BSpline::POLES_ID()));
571   std::list<GeomPointPtr> aPoles = aBSpline.poles();
572   aPolesAttr->setSize((int)aPoles.size());
573   std::list<GeomPointPtr>::iterator anIt = aPoles.begin();
574   for (int anIndex = 0; anIt != aPoles.end(); ++anIt, ++anIndex) {
575     GeomPnt2dPtr aPoleInSketch = sketch()->to2D(*anIt);
576     aPolesAttr->setPnt(anIndex, aPoleInSketch);
577   }
578
579   AttributeDoubleArrayPtr aWeightsAttr =
580       theProjection->data()->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
581   std::list<double> aWeights = aBSpline.weights();
582   if (aWeights.empty()) { // rational B-spline
583     int aSize = (int)aPoles.size();
584     aWeightsAttr->setSize(aSize);
585     for (int anIndex = 0; anIndex < aSize; ++anIndex)
586       aWeightsAttr->setValue(anIndex, 1.0);
587   }
588   else { // non-rational B-spline
589     aWeightsAttr->setSize((int)aWeights.size());
590     std::list<double>::iterator aWIt = aWeights.begin();
591     for (int anIndex = 0; aWIt != aWeights.end(); ++aWIt, ++anIndex)
592       aWeightsAttr->setValue(anIndex, *aWIt);
593   }
594
595   AttributeDoubleArrayPtr aKnotsAttr =
596       theProjection->data()->realArray(SketchPlugin_BSpline::KNOTS_ID());
597   std::list<double> aKnots = aBSpline.knots();
598   int aSize = (int)aKnots.size();
599   aKnotsAttr->setSize(aSize);
600   std::list<double>::iterator aKIt = aKnots.begin();
601   for (int index = 0; index < aSize; ++index, ++aKIt)
602     aKnotsAttr->setValue(index, *aKIt);
603
604   AttributeIntArrayPtr aMultsAttr =
605       theProjection->data()->intArray(SketchPlugin_BSpline::MULTS_ID());
606   std::list<int> aMultiplicities = aBSpline.mults();
607   aSize = (int)aMultiplicities.size();
608   aMultsAttr->setSize(aSize);
609   std::list<int>::iterator aMIt = aMultiplicities.begin();
610   for (int index = 0; index < aSize; ++index, ++aMIt)
611     aMultsAttr->setValue(index, *aMIt);
612
613   return true;
614 }