]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_MacroArc.cpp
Salome HOME
Issue #2068: change of arc is by jump even due to smooth mouse movement
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroArc.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        SketchPlugin_MacroArc.cpp
4 // Created:     26 Apr 2014
5 // Author:      Artem ZHIDKOV
6
7 #include "SketchPlugin_MacroArc.h"
8
9 #include "SketchPlugin_Arc.h"
10 #include "SketchPlugin_ConstraintTangent.h"
11 #include "SketchPlugin_Sketch.h"
12 #include "SketchPlugin_Tools.h"
13 #include "SketchPlugin_MacroArcReentrantMessage.h"
14
15 #include <ModelAPI_AttributeDouble.h>
16 #include <ModelAPI_AttributeRefAttr.h>
17 #include <ModelAPI_AttributeString.h>
18 #include <ModelAPI_Events.h>
19 #include <ModelAPI_Session.h>
20 #include <ModelAPI_Validator.h>
21
22 #include <GeomAPI_Circ.h>
23 #include <GeomAPI_Circ2d.h>
24 #include <GeomAPI_Curve.h>
25 #include <GeomAPI_Dir2d.h>
26 #include <GeomAPI_Edge.h>
27 #include <GeomAPI_Lin.h>
28 #include <GeomAPI_Lin2d.h>
29 #include <GeomAPI_Pnt2d.h>
30 #include <GeomAPI_Vertex.h>
31 #include <GeomAPI_XY.h>
32
33 #include <GeomDataAPI_Point2D.h>
34 #include <GeomDataAPI_Dir.h>
35
36 #include <GeomAlgoAPI_Circ2dBuilder.h>
37 #include <GeomAlgoAPI_EdgeBuilder.h>
38 #include <GeomAlgoAPI_CompoundBuilder.h>
39 #include <GeomAlgoAPI_PointBuilder.h>
40
41 // for sqrt on Linux
42 #include <math.h>
43
44 const double tolerance = 1e-7;
45 const double paramTolerance = 1.e-4;
46 const double PI = 3.141592653589793238463;
47
48 static void projectPointOnCircle(AttributePoint2DPtr& thePoint, const GeomAPI_Circ2d& theCircle)
49 {
50   std::shared_ptr<GeomAPI_Pnt2d> aProjection = theCircle.project(thePoint->pnt());
51   if(aProjection.get())
52     thePoint->setValue(aProjection);
53 }
54
55
56 SketchPlugin_MacroArc::SketchPlugin_MacroArc()
57 : SketchPlugin_SketchEntity(),
58   myParamBefore(0.0)
59 {
60 }
61
62 void SketchPlugin_MacroArc::initAttributes()
63 {
64   data()->addAttribute(ARC_TYPE(), ModelAPI_AttributeString::typeId());
65
66   data()->addAttribute(CENTER_POINT_ID(), GeomDataAPI_Point2D::typeId());
67   data()->addAttribute(START_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
68   data()->addAttribute(END_POINT_1_ID(), GeomDataAPI_Point2D::typeId());
69
70   data()->addAttribute(START_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
71   data()->addAttribute(END_POINT_2_ID(), GeomDataAPI_Point2D::typeId());
72   data()->addAttribute(PASSED_POINT_ID(), GeomDataAPI_Point2D::typeId());
73
74   data()->addAttribute(TANGENT_POINT_ID(), ModelAPI_AttributeRefAttr::typeId());
75   data()->addAttribute(END_POINT_3_ID(), GeomDataAPI_Point2D::typeId());
76
77   data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId());
78
79   data()->addAttribute(RADIUS_ID(), ModelAPI_AttributeDouble::typeId());
80   data()->addAttribute(ANGLE_ID(), ModelAPI_AttributeDouble::typeId());
81
82   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
83
84   data()->addAttribute(CENTER_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
85   data()->addAttribute(START_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
86   data()->addAttribute(END_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
87   data()->addAttribute(PASSED_POINT_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
88
89   data()->addAttribute(EDIT_ARC_TYPE_ID(), ModelAPI_AttributeString::typeId());
90
91   boolean(REVERSED_ID())->setValue(false);
92   string(EDIT_ARC_TYPE_ID())->setValue("");
93
94   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_POINT_REF_ID());
95   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START_POINT_REF_ID());
96   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END_POINT_REF_ID());
97   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PASSED_POINT_REF_ID());
98   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_ARC_TYPE_ID());
99 }
100
101 void SketchPlugin_MacroArc::attributeChanged(const std::string& theID)
102 {
103   std::string anArcType = string(ARC_TYPE())->value();
104
105   // If arc type switched reset according attributes.
106   if(theID == ARC_TYPE()) {
107     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_ID());
108     SketchPlugin_Tools::resetAttribute(this, CENTER_POINT_REF_ID());
109     SketchPlugin_Tools::resetAttribute(this, START_POINT_1_ID());
110     SketchPlugin_Tools::resetAttribute(this, START_POINT_REF_ID());
111     SketchPlugin_Tools::resetAttribute(this, END_POINT_1_ID());
112     SketchPlugin_Tools::resetAttribute(this, END_POINT_REF_ID());
113     SketchPlugin_Tools::resetAttribute(this, START_POINT_2_ID());
114     SketchPlugin_Tools::resetAttribute(this, END_POINT_2_ID());
115     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_ID());
116     SketchPlugin_Tools::resetAttribute(this, PASSED_POINT_REF_ID());
117     SketchPlugin_Tools::resetAttribute(this, TANGENT_POINT_ID());
118     SketchPlugin_Tools::resetAttribute(this, END_POINT_3_ID());
119     SketchPlugin_Tools::resetAttribute(this, REVERSED_ID());
120     SketchPlugin_Tools::resetAttribute(this, RADIUS_ID());
121     SketchPlugin_Tools::resetAttribute(this, ANGLE_ID());
122
123     myCenter.reset();
124     myStart.reset();
125     myEnd.reset();
126     boolean(REVERSED_ID())->setValue(false);
127     myParamBefore = 0.0;
128   } else if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS())
129     fillByCenterAndTwoPassed();
130   else if(anArcType == ARC_TYPE_BY_THREE_POINTS())
131     fillByThreePassedPoints();
132   else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE())
133     fillByTangentEdge();
134
135   double aRadius = 0;
136   double anAngle = 0;
137   if(myCenter.get() && myStart.get()) {
138     aRadius = myCenter->distance(myStart);
139     if(myEnd.get()) {
140       if(myStart->isEqual(myEnd)) {
141         anAngle = 360;
142       } else {
143         GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
144         double aStartParam, anEndParam;
145         aCircleForArc.parameter(myStart, paramTolerance, aStartParam);
146         aCircleForArc.parameter(myEnd, paramTolerance, anEndParam);
147         anAngle = (anEndParam - aStartParam) / PI * 180.0;
148         if(boolean(REVERSED_ID())->value()) anAngle = 360.0 - anAngle;
149       }
150     }
151   }
152
153   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
154   real(RADIUS_ID())->setValue(aRadius);
155   real(ANGLE_ID())->setValue(anAngle);
156   data()->blockSendAttributeUpdated(aWasBlocked, false);
157 }
158
159 GeomShapePtr SketchPlugin_MacroArc::getArcShape()
160 {
161   if(!myStart.get() || !myEnd.get() || !myCenter.get()) {
162     return GeomShapePtr();
163   }
164
165   SketchPlugin_Sketch* aSketch = sketch();
166   if(!aSketch) {
167     return GeomShapePtr();
168   }
169
170   std::shared_ptr<GeomAPI_Pnt> aCenter(aSketch->to3D(myCenter->x(), myCenter->y()));
171   std::shared_ptr<GeomAPI_Pnt> aStart(aSketch->to3D(myStart->x(), myStart->y()));
172   std::shared_ptr<GeomAPI_Pnt> anEnd(aSketch->to3D(myEnd->x(), myEnd->y()));
173   std::shared_ptr<GeomDataAPI_Dir> aNDir =
174     std::dynamic_pointer_cast<GeomDataAPI_Dir>(aSketch->attribute(SketchPlugin_Sketch::NORM_ID()));
175   std::shared_ptr<GeomAPI_Dir> aNormal(new GeomAPI_Dir(aNDir->x(), aNDir->y(), aNDir->z()));
176
177   GeomShapePtr anArcShape = boolean(REVERSED_ID())->value() ?
178       GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, anEnd, aStart, aNormal)
179     : GeomAlgoAPI_EdgeBuilder::lineCircleArc(aCenter, aStart, anEnd, aNormal);
180
181   return anArcShape;
182 }
183
184 AISObjectPtr SketchPlugin_MacroArc::getAISObject(AISObjectPtr thePrevious)
185 {
186   if(!myStart.get() || !myEnd.get() || !myCenter.get()) {
187     return AISObjectPtr();
188   }
189
190   SketchPlugin_Sketch* aSketch = sketch();
191   if(!aSketch) {
192     return AISObjectPtr();
193   }
194
195   GeomShapePtr anArcShape = getArcShape();
196   std::shared_ptr<GeomAPI_Pnt> aCenter = aSketch->to3D(myCenter->x(), myCenter->y());;
197   GeomShapePtr aCenterPointShape = GeomAlgoAPI_PointBuilder::vertex(aCenter);
198
199   if(!anArcShape.get() || !aCenterPointShape.get()) {
200     return AISObjectPtr();
201   }
202
203   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
204   aShapes.push_back(anArcShape);
205   aShapes.push_back(aCenterPointShape);
206
207   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
208   AISObjectPtr anAIS = thePrevious;
209   if(!anAIS.get()) {
210     anAIS.reset(new GeomAPI_AISObject());
211   }
212   anAIS->createShape(aCompound);
213   return anAIS;
214 }
215
216 void SketchPlugin_MacroArc::execute()
217 {
218   FeaturePtr anArcFeature = createArcFeature();
219
220   myCenter.reset();
221   myStart.reset();
222   myEnd.reset();
223
224   // Create constraints.
225   std::string anArcType = string(ARC_TYPE())->value();
226   if(anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
227     SketchPlugin_Tools::createConstraint(this,
228                                          CENTER_POINT_REF_ID(),
229                                          anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
230                                          ObjectPtr(),
231                                          false);
232     SketchPlugin_Tools::createConstraint(this,
233                                          START_POINT_REF_ID(),
234                                          anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
235                                          ObjectPtr(),
236                                          false);
237     SketchPlugin_Tools::createConstraint(this,
238                                          END_POINT_REF_ID(),
239                                          anArcFeature->attribute(SketchPlugin_Arc::END_ID()),
240                                          ObjectPtr(),
241                                          false);
242   } else if(anArcType == ARC_TYPE_BY_THREE_POINTS()) {
243     SketchPlugin_Tools::createConstraint(this,
244                                          START_POINT_REF_ID(),
245                                          anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
246                                          ObjectPtr(),
247                                          false);
248     SketchPlugin_Tools::createConstraint(this,
249                                          END_POINT_REF_ID(),
250                                          anArcFeature->attribute(SketchPlugin_Arc::END_ID()),
251                                          ObjectPtr(),
252                                          false);
253     SketchPlugin_Tools::createConstraint(this,
254                                          PASSED_POINT_REF_ID(),
255                                          AttributePtr(),
256                                          anArcFeature->lastResult(),
257                                          true);
258   } else if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
259     // constraints for tangent arc
260     SketchPlugin_Tools::createConstraint(this,
261                                          TANGENT_POINT_ID(),
262                                          anArcFeature->attribute(SketchPlugin_Arc::START_ID()),
263                                          ObjectPtr(),
264                                          false);
265     FeaturePtr aTangent = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
266     AttributeRefAttrPtr aRefAttrA = aTangent->refattr(SketchPlugin_Constraint::ENTITY_A());
267     AttributeRefAttrPtr aTgPntRefAttr = refattr(TANGENT_POINT_ID());
268     FeaturePtr aTgFeature = ModelAPI_Feature::feature(aTgPntRefAttr->attr()->owner());
269     aRefAttrA->setObject(aTgFeature->lastResult());
270     AttributeRefAttrPtr aRefAttrB = aTangent->refattr(SketchPlugin_Constraint::ENTITY_B());
271     aRefAttrB->setObject(anArcFeature->lastResult());
272     // constraint for end point
273     SketchPlugin_Tools::createConstraint(this,
274                                          END_POINT_REF_ID(),
275                                          anArcFeature->attribute(SketchPlugin_Arc::END_ID()),
276                                          ObjectPtr(),
277                                          false);
278   }
279
280   // message to init reentrant operation
281   static Events_ID anId = SketchPlugin_MacroArcReentrantMessage::eventId();
282   std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aMessage = std::shared_ptr
283     <SketchPlugin_MacroArcReentrantMessage>(new SketchPlugin_MacroArcReentrantMessage(anId, 0));
284
285   std::string anEditArcType = string(EDIT_ARC_TYPE_ID())->value();
286   aMessage->setTypeOfCreation(!anEditArcType.empty() ? anEditArcType : anArcType);
287   aMessage->setCreatedFeature(anArcFeature);
288   Events_Loop::loop()->send(aMessage);
289 }
290
291 std::string SketchPlugin_MacroArc::processEvent(const std::shared_ptr<Events_Message>& theMessage)
292 {
293   std::string aFilledAttributeName;
294   std::shared_ptr<SketchPlugin_MacroArcReentrantMessage> aReentrantMessage =
295         std::dynamic_pointer_cast<SketchPlugin_MacroArcReentrantMessage>(theMessage);
296   if (aReentrantMessage.get()) {
297     FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
298     std::string anArcType = aReentrantMessage->typeOfCreation();
299
300     string(ARC_TYPE())->setValue(anArcType);
301
302     aFilledAttributeName = ARC_TYPE();
303     if(anArcType == ARC_TYPE_BY_TANGENT_EDGE()) {
304       aFilledAttributeName = TANGENT_POINT_ID();
305       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
306                                                         attribute(aFilledAttributeName));
307       FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
308       aRefAttr->setAttr(aCreatedFeature->attribute(SketchPlugin_Arc::END_ID()));
309     }
310     else {
311       ObjectPtr anObject = aReentrantMessage->selectedObject();
312       AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
313       std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
314
315       if (aClickedPoint.get() && (anObject.get() || anAttribute.get())) {
316         if (anArcType == ARC_TYPE_BY_CENTER_AND_POINTS() ||
317             anArcType == ARC_TYPE_BY_THREE_POINTS()) {
318           std::string aReferenceAttributeName;
319           if (anArcType == ARC_TYPE_BY_CENTER_AND_POINTS()) {
320             aFilledAttributeName = CENTER_POINT_ID();
321             aReferenceAttributeName = CENTER_POINT_REF_ID();
322           }
323           else {
324             aFilledAttributeName = START_POINT_2_ID();
325             aReferenceAttributeName = START_POINT_REF_ID();
326           }
327           // fill 2d point attribute
328           AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
329                                                             attribute(aFilledAttributeName));
330           aPointAttr->setValue(aClickedPoint);
331           // fill reference attribute
332           AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
333                                                             attribute(aReferenceAttributeName));
334           if (aRefAttr.get()) {
335             if (anAttribute.get())
336               aRefAttr->setAttr(anAttribute);
337             else if (anObject.get()) {
338               // if presentation of previous reentrant macro arc is used, the object is invalid,
339               // we should use result of previous feature of the message(Arc)
340               if (!anObject->data()->isValid()) {
341                 FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
342                 anObject = aCreatedFeature->lastResult();
343               }
344               aRefAttr->setObject(anObject);
345             }
346           }
347         }
348       }
349     }
350     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
351   }
352   return aFilledAttributeName;
353 }
354
355 FeaturePtr SketchPlugin_MacroArc::createArcFeature()
356 {
357   FeaturePtr anArcFeature = sketch()->addFeature(SketchPlugin_Arc::ID());
358   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
359       anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(myCenter);
360   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
361       anArcFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(myStart);
362   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
363       anArcFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(myEnd);
364   anArcFeature->boolean(SketchPlugin_Arc::REVERSED_ID())
365                 ->setValue(boolean(REVERSED_ID())->value());
366   anArcFeature->boolean(SketchPlugin_Arc::AUXILIARY_ID())
367                 ->setValue(boolean(AUXILIARY_ID())->value());
368   anArcFeature->execute();
369
370   return anArcFeature;
371 }
372
373 void SketchPlugin_MacroArc::fillByCenterAndTwoPassed()
374 {
375   AttributePoint2DPtr aCenterPointAttr =
376       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_POINT_ID()));
377   if (!aCenterPointAttr->isInitialized())
378       return;
379
380   AttributePoint2DPtr aStartPointAttr =
381       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_1_ID()));
382   if (!aStartPointAttr->isInitialized())
383     return;
384
385   myCenter = aCenterPointAttr->pnt();
386   myStart = aStartPointAttr->pnt();
387   myEnd = myStart;
388
389   AttributePoint2DPtr anEndPointAttr =
390       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_1_ID()));
391   if (!anEndPointAttr->isInitialized())
392     return;
393
394   GeomAPI_Circ2d aCircleForArc(myCenter, myStart);
395
396   // End point should be a projection on circle.
397   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
398   projectPointOnCircle(anEndPointAttr, aCircleForArc);
399   data()->blockSendAttributeUpdated(aWasBlocked, false);
400   myEnd = anEndPointAttr->pnt();
401
402   // update the REVERSED flag
403   recalculateReversedFlagByEnd(aCircleForArc);
404 }
405
406 void SketchPlugin_MacroArc::recalculateReversedFlagByEnd(const GeomAPI_Circ2d& theCurrentCircular)
407 {
408   double aParameterNew = 0.0;
409   if(theCurrentCircular.parameter(myEnd, paramTolerance, aParameterNew)) {
410     if(myParamBefore <= PI / 2.0 && aParameterNew >= PI * 1.5) {
411       boolean(REVERSED_ID())->setValue(true);
412     } else if(myParamBefore >= PI * 1.5 && aParameterNew <= PI / 2.0) {
413       boolean(REVERSED_ID())->setValue(false);
414     }
415   }
416   myParamBefore = aParameterNew;
417 }
418
419 void SketchPlugin_MacroArc::fillByThreePassedPoints()
420 {
421   AttributePoint2DPtr aStartPointAttr =
422       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_2_ID()));
423   if (!aStartPointAttr->isInitialized())
424     return;
425
426   AttributePoint2DPtr anEndPointAttr =
427       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_2_ID()));
428   if (!anEndPointAttr->isInitialized())
429     return;
430
431   myStart = aStartPointAttr->pnt();
432   myEnd = anEndPointAttr->pnt();
433
434   AttributePoint2DPtr aPassedPointAttr =
435       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
436   if (aPassedPointAttr->isInitialized()) {
437     std::shared_ptr<GeomAPI_Pnt2d> aPassedPnt;
438     std::shared_ptr<GeomAPI_Shape> aTangentCurve;
439     SketchPlugin_Tools::convertRefAttrToPointOrTangentCurve(
440         refattr(PASSED_POINT_REF_ID()), aPassedPointAttr, aTangentCurve, aPassedPnt);
441
442     GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
443     aCircBuilder.addPassingPoint(myStart);
444     aCircBuilder.addPassingPoint(myEnd);
445     if (aTangentCurve) {
446       aCircBuilder.addTangentCurve(aTangentCurve);
447       aCircBuilder.setClosestPoint(aPassedPointAttr->pnt());
448     } else
449       aCircBuilder.addPassingPoint(aPassedPnt);
450
451     std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
452     if (!aCircle)
453       return;
454     myCenter = aCircle->center();
455
456     aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
457     recalculateReversedFlagByPassed(*aCircle);
458   } else
459     myCenter.reset(new GeomAPI_Pnt2d(myStart->xy()->added(myEnd->xy())->multiplied(0.5)));
460 }
461
462 void SketchPlugin_MacroArc::recalculateReversedFlagByPassed(
463     const GeomAPI_Circ2d& theCurrentCircular)
464 {
465   AttributePoint2DPtr aPassedAttr =
466       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(PASSED_POINT_ID()));
467   std::shared_ptr<GeomAPI_Pnt2d> aPassed = theCurrentCircular.project(aPassedAttr->pnt());
468
469   double aEndParam, aPassedParam;
470   theCurrentCircular.parameter(myEnd, paramTolerance, aEndParam);
471   theCurrentCircular.parameter(aPassed, paramTolerance, aPassedParam);
472
473   if(aPassedParam > aEndParam)
474     boolean(REVERSED_ID())->setValue(true);
475   else
476     boolean(REVERSED_ID())->setValue(false);
477
478   myParamBefore = aEndParam;
479 }
480
481 void SketchPlugin_MacroArc::fillByTangentEdge()
482 {
483   AttributeRefAttrPtr aTangentAttr = refattr(TANGENT_POINT_ID());
484   if (!aTangentAttr->isInitialized())
485     return;
486
487   AttributePoint2DPtr aTangentPointAttr =
488       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aTangentAttr->attr());
489   if (!aTangentPointAttr->isInitialized())
490     return;
491
492   AttributePoint2DPtr anEndPointAttr =
493       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_3_ID()));
494   if (!anEndPointAttr->isInitialized())
495     return;
496
497   myStart = aTangentPointAttr->pnt();
498   myEnd = anEndPointAttr->pnt();
499   if (myStart->isEqual(myEnd))
500     return;
501
502   // obtain a shape the tangent point belongs to
503   FeaturePtr aTangentFeature = ModelAPI_Feature::feature(aTangentPointAttr->owner());
504   std::shared_ptr<GeomAPI_Shape> aTangentShape = aTangentFeature->lastResult()->shape();
505
506   GeomAlgoAPI_Circ2dBuilder aCircBuilder(SketchPlugin_Sketch::plane(sketch()));
507   aCircBuilder.addPassingPoint(myStart);
508   aCircBuilder.addPassingPoint(myEnd);
509   aCircBuilder.addTangentCurve(aTangentShape);
510
511   std::shared_ptr<GeomAPI_Circ2d> aCircle = aCircBuilder.circle();
512   myCenter = aCircle->center();
513
514   // rebuild circle to set start point equal to zero parameter
515   aCircle = std::shared_ptr<GeomAPI_Circ2d>(new GeomAPI_Circ2d(myCenter, myStart));
516   recalculateReversedFlagByEnd(*aCircle);
517 }