Salome HOME
b5faabdfd1ac8a4349529a30fb3724b1a33090b4
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Projection.cpp
1 // Copyright (C) 2014-2023  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, theEdge);
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, theEdge);
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                                       const GeomEdgePtr& theOriginalEdge)
425 {
426   rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_Arc::ID());
427
428   GeomAPI_Circ aCircle(theArc);
429
430   double aNormalsDot = aCircle.normal()->dot(thePlane->direction());
431   if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
432     return false; // arc is not in the plane, parallel to the sketch plane
433
434   bool isInversed = aNormalsDot < 0.;
435
436   GeomCirclePtr anOriginalCircle = theOriginalEdge->circle();
437   if (anOriginalCircle) {
438     double aCirclesDot = anOriginalCircle->normal()->dot(aCircle.normal());
439     if (aCirclesDot < 0.)
440       isInversed = !isInversed;
441   }
442
443   GeomPointPtr aCenter = thePlane->project(aCircle.center());
444   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
445
446   GeomPointPtr aFirst = theArc->getPoint(theArc->startParam());
447   GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
448
449   GeomPointPtr aLast = theArc->getPoint(theArc->endParam());
450   GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
451
452   bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
453
454   // update attributes of projection
455   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
456       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
457       theProjection->attribute(SketchPlugin_Arc::CENTER_ID()));
458   std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
459       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
460       theProjection->attribute(SketchPlugin_Arc::START_ID()));
461   std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
462       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
463       theProjection->attribute(SketchPlugin_Arc::END_ID()));
464   aStartPnt->setValue(aFirstInSketch);
465   aEndPnt->setValue(aLastInSketch);
466   aCenterPnt->setValue(aCenterInSketch);
467   theProjection->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(isInversed);
468
469   theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
470   return true;
471 }
472
473 bool SketchPlugin_Projection::fillCircle(FeaturePtr& theProjection,
474                                          const GeomCurvePtr& theCircle,
475                                          const GeomPlanePtr& thePlane)
476 {
477   rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Circle::ID());
478
479   GeomAPI_Circ aCircle(theCircle);
480   GeomPointPtr aCenter = thePlane->project(aCircle.center());
481   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
482
483   // update attributes of projection
484   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
485       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
486       theProjection->attribute(SketchPlugin_Circle::CENTER_ID()));
487   aCenterPnt->setValue(aCenterInSketch);
488   theProjection->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircle.radius());
489   return true;
490 }
491
492 bool SketchPlugin_Projection::fillEllipse(FeaturePtr& theProjection,
493                                           const GeomCurvePtr& theEllipse,
494                                           const GeomPlanePtr& thePlane)
495 {
496   rebuildProjectedFeature(theProjection, CIRCLE_ELLIPSE_PROJECTION(), SketchPlugin_Ellipse::ID());
497
498   GeomAPI_Ellipse anEllipse(theEllipse);
499   GeomPointPtr aCenter = thePlane->project(anEllipse.center());
500   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
501   GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
502   GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
503
504   // update attributes of projection
505   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
506       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
507       theProjection->attribute(SketchPlugin_Ellipse::CENTER_ID()));
508   aCenterPnt->setValue(aCenterInSketch);
509   std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
510       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
511       theProjection->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()));
512   aFocusPnt->setValue(aFocusInSketch);
513   theProjection->real(SketchPlugin_Ellipse::MINOR_RADIUS_ID())->setValue(anEllipse.minorRadius());
514   return true;
515 }
516
517 bool SketchPlugin_Projection::fillEllipticArc(FeaturePtr& theProjection,
518                                               const GeomCurvePtr& theEllipticArc,
519                                               const GeomPlanePtr& thePlane,
520                                               const GeomEdgePtr& theOriginalEdge)
521 {
522   rebuildProjectedFeature(theProjection, ARC_PROJECTION(), SketchPlugin_EllipticArc::ID());
523
524   GeomAPI_Ellipse anEllipse(theEllipticArc);
525
526   double aNormalsDot = anEllipse.normal()->dot(thePlane->direction());
527   if (fabs(fabs(aNormalsDot) - 1.0) > tolerance)
528     return false; // arc is not in the plane, parallel to the sketch plane
529
530   bool isInversed = aNormalsDot < 0.;
531
532   GeomEllipsePtr anOriginalEllipse = theOriginalEdge->ellipse();
533   if (anOriginalEllipse) {
534     double anEllipsesDot = anOriginalEllipse->normal()->dot(anEllipse.normal());
535     if (anEllipsesDot < 0.)
536       isInversed = !isInversed;
537   }
538
539   GeomPointPtr aCenter = thePlane->project(anEllipse.center());
540   GeomPnt2dPtr aCenterInSketch = sketch()->to2D(aCenter);
541   GeomPointPtr aFocus = thePlane->project(anEllipse.firstFocus());
542   GeomPnt2dPtr aFocusInSketch = sketch()->to2D(aFocus);
543
544   GeomPointPtr aFirst = theEllipticArc->getPoint(theEllipticArc->startParam());
545   GeomPnt2dPtr aFirstInSketch = sketch()->to2D(thePlane->project(aFirst));
546   GeomPointPtr aLast = theEllipticArc->getPoint(theEllipticArc->endParam());
547   GeomPnt2dPtr aLastInSketch = sketch()->to2D(thePlane->project(aLast));
548
549   bool aWasBlocked = theProjection->data()->blockSendAttributeUpdated(true);
550
551   // update attributes of projection
552   std::shared_ptr<GeomDataAPI_Point2D> aCenterPnt =
553       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
554       theProjection->attribute(SketchPlugin_EllipticArc::CENTER_ID()));
555   std::shared_ptr<GeomDataAPI_Point2D> aFocusPnt =
556       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
557       theProjection->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID()));
558   std::shared_ptr<GeomDataAPI_Point2D> aStartPnt =
559       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
560       theProjection->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
561   std::shared_ptr<GeomDataAPI_Point2D> aEndPnt =
562       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
563       theProjection->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
564   aStartPnt->setValue(aFirstInSketch);
565   aEndPnt->setValue(aLastInSketch);
566   aCenterPnt->setValue(aCenterInSketch);
567   aFocusPnt->setValue(aFocusInSketch);
568   theProjection->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(isInversed);
569
570   theProjection->data()->blockSendAttributeUpdated(aWasBlocked);
571   return true;
572 }
573
574 bool SketchPlugin_Projection::fillBSpline(FeaturePtr& theProjection,
575                                           const GeomCurvePtr& theCurve,
576                                           const GeomPlanePtr& /*thePlane*/)
577 {
578   GeomAPI_BSpline aBSpline(theCurve);
579
580   rebuildProjectedFeature(theProjection, BSPLINE_PROJECTION(),
581       aBSpline.isPeriodic() ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
582
583   theProjection->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(aBSpline.degree());
584
585   AttributePoint2DArrayPtr aPolesAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
586       theProjection->attribute(SketchPlugin_BSpline::POLES_ID()));
587   std::list<GeomPointPtr> aPoles = aBSpline.poles();
588   aPolesAttr->setSize((int)aPoles.size());
589   std::list<GeomPointPtr>::iterator anIt = aPoles.begin();
590   for (int anIndex = 0; anIt != aPoles.end(); ++anIt, ++anIndex) {
591     GeomPnt2dPtr aPoleInSketch = sketch()->to2D(*anIt);
592     aPolesAttr->setPnt(anIndex, aPoleInSketch);
593   }
594
595   AttributeDoubleArrayPtr aWeightsAttr =
596       theProjection->data()->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
597   std::list<double> aWeights = aBSpline.weights();
598   if (aWeights.empty()) { // rational B-spline
599     int aSize = (int)aPoles.size();
600     aWeightsAttr->setSize(aSize);
601     for (int anIndex = 0; anIndex < aSize; ++anIndex)
602       aWeightsAttr->setValue(anIndex, 1.0);
603   }
604   else { // non-rational B-spline
605     aWeightsAttr->setSize((int)aWeights.size());
606     std::list<double>::iterator aWIt = aWeights.begin();
607     for (int anIndex = 0; aWIt != aWeights.end(); ++aWIt, ++anIndex)
608       aWeightsAttr->setValue(anIndex, *aWIt);
609   }
610
611   AttributeDoubleArrayPtr aKnotsAttr =
612       theProjection->data()->realArray(SketchPlugin_BSpline::KNOTS_ID());
613   std::list<double> aKnots = aBSpline.knots();
614   int aSize = (int)aKnots.size();
615   aKnotsAttr->setSize(aSize);
616   std::list<double>::iterator aKIt = aKnots.begin();
617   for (int index = 0; index < aSize; ++index, ++aKIt)
618     aKnotsAttr->setValue(index, *aKIt);
619
620   AttributeIntArrayPtr aMultsAttr =
621       theProjection->data()->intArray(SketchPlugin_BSpline::MULTS_ID());
622   std::list<int> aMultiplicities = aBSpline.mults();
623   aSize = (int)aMultiplicities.size();
624   aMultsAttr->setSize(aSize);
625   std::list<int>::iterator aMIt = aMultiplicities.begin();
626   for (int index = 0; index < aSize; ++index, ++aMIt)
627     aMultsAttr->setValue(index, *aMIt);
628
629   return true;
630 }