Salome HOME
Task 2.12. New entities: ellipses and arcs of ellipses (issue #3003)
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Tools.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_Tools.h"
21
22 #include "SketchPlugin_ConstraintCoincidence.h"
23 #include "SketchPlugin_ConstraintCoincidenceInternal.h"
24 #include "SketchPlugin_ConstraintLength.h"
25 #include "SketchPlugin_ConstraintTangent.h"
26 #include "SketchPlugin_Ellipse.h"
27 #include "SketchPlugin_Line.h"
28 #include "SketchPlugin_Point.h"
29 #include "SketchPlugin_SketchEntity.h"
30
31 #include <SketcherPrs_Tools.h>
32
33 #include <ModelAPI_AttributeDouble.h>
34
35 #include <GeomAPI_Dir2d.h>
36 #include <GeomAPI_Pnt2d.h>
37 #include <GeomAPI_XY.h>
38
39 #include <GeomDataAPI_Point.h>
40 #include <GeomDataAPI_Point2D.h>
41
42 #ifdef DEBUG_TRIM
43 #include <iostream>
44 #endif
45
46 namespace SketchPlugin_Tools {
47
48 void clearExpressions(AttributeDoublePtr theAttribute)
49 {
50   theAttribute->setText(std::string());
51 }
52
53 void clearExpressions(AttributePointPtr theAttribute)
54 {
55   theAttribute->setText(std::string(), std::string(), std::string());
56 }
57
58 void clearExpressions(AttributePoint2DPtr theAttribute)
59 {
60   theAttribute->setText(std::string(), std::string());
61 }
62
63 void clearExpressions(AttributePtr theAttribute)
64 {
65   // Double
66   AttributeDoublePtr anAttributeDouble =
67       std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
68   if (anAttributeDouble.get())
69     clearExpressions(anAttributeDouble);
70   // Point
71   AttributePointPtr anAttributePoint =
72       std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
73   if (anAttributePoint.get())
74     clearExpressions(anAttributePoint);
75   // Point2D
76   AttributePoint2DPtr anAttributePoint2D =
77       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
78   if (anAttributePoint2D.get())
79     clearExpressions(anAttributePoint2D);
80 }
81
82 void clearExpressions(FeaturePtr theFeature)
83 {
84   if (!theFeature.get())
85     return;
86
87   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
88   std::list<AttributePtr>::iterator anAttributeIt = anAttributes.begin();
89   for (; anAttributeIt != anAttributes.end(); ++anAttributeIt) {
90     clearExpressions(*anAttributeIt);
91   }
92 }
93
94 std::shared_ptr<GeomAPI_Pnt2d> getCoincidencePoint(const FeaturePtr theStartCoin)
95 {
96   std::shared_ptr<GeomAPI_Pnt2d> aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(),
97                                                           SketchPlugin_Constraint::ENTITY_A());
98   if (aPnt.get() == NULL)
99     aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(), SketchPlugin_Constraint::ENTITY_B());
100   return aPnt;
101 }
102
103 std::set<FeaturePtr> findCoincidentConstraints(const FeaturePtr& theFeature)
104 {
105   std::set<FeaturePtr> aCoincident;
106   const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
107   std::set<AttributePtr>::const_iterator aIt;
108   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
109     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
110     if (aConstrFeature && aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID())
111       aCoincident.insert(aConstrFeature);
112   }
113   return aCoincident;
114 }
115
116 void findCoincidences(const FeaturePtr theStartCoin,
117                       const std::string& theAttr,
118                       std::set<FeaturePtr>& theList,
119                       const bool theIsAttrOnly)
120 {
121   AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
122   if(!aPnt) {
123     return;
124   }
125   FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
126   if(theList.find(aObj) == theList.end()) {
127     std::shared_ptr<GeomAPI_Pnt2d> aOrig = getCoincidencePoint(theStartCoin);
128     if(aOrig.get() == NULL) {
129       return;
130     }
131     if(!theIsAttrOnly || !aPnt->isObject()) {
132       theList.insert(aObj);
133     }
134     std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(aObj);
135     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
136     for (; aCIt != aCoincidences.end(); ++aCIt) {
137       FeaturePtr aConstrFeature = *aCIt;
138       std::shared_ptr<GeomAPI_Pnt2d> aPnt = getCoincidencePoint(aConstrFeature);
139       if(aPnt.get() && aOrig->isEqual(aPnt)) {
140         findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A(),
141                          theList, theIsAttrOnly);
142         findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B(),
143                          theList, theIsAttrOnly);
144       }
145     }
146   }
147 }
148
149 std::set<FeaturePtr> findFeaturesCoincidentToPoint(const AttributePoint2DPtr& thePoint)
150 {
151   std::set<FeaturePtr> aCoincidentFeatures;
152
153   FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
154   aCoincidentFeatures.insert(anOwner);
155
156   std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(anOwner);
157   std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
158   for (; aCIt != aCoincidences.end(); ++aCIt) {
159     bool isPointUsedInCoincidence = false;
160     AttributeRefAttrPtr anOtherCoincidentAttr;
161     for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
162       AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
163       if (!aRefAttr)
164         continue;
165       if (!aRefAttr->isObject() && aRefAttr->attr() == thePoint)
166         isPointUsedInCoincidence = true;
167       else
168         anOtherCoincidentAttr = aRefAttr;
169     }
170
171     if (isPointUsedInCoincidence) {
172       ObjectPtr anObj;
173       if (anOtherCoincidentAttr->isObject())
174         anObj = anOtherCoincidentAttr->object();
175       else
176         anObj = anOtherCoincidentAttr->attr()->owner();
177       aCoincidentFeatures.insert(ModelAPI_Feature::feature(anObj));
178     }
179   }
180
181   return aCoincidentFeatures;
182 }
183
184 // Container for point-point coincidences.
185 // Useful to find points coincident to a given point.
186 class CoincidentPoints
187 {
188 public:
189   void addCoincidence(const AttributePoint2DPtr& thePoint1,
190                       const AttributePoint2DPtr& thePoint2 = AttributePoint2DPtr())
191   {
192     std::list< std::set<AttributePoint2DPtr> >::iterator aFound1 = find(thePoint1);
193     std::list< std::set<AttributePoint2DPtr> >::iterator aFound2 = find(thePoint2);
194     if (aFound1 == myCoincidentPoints.end()) {
195       if (aFound2 == myCoincidentPoints.end()) {
196         std::set<AttributePoint2DPtr> aNewSet;
197         aNewSet.insert(thePoint1);
198         if (thePoint2)
199           aNewSet.insert(thePoint2);
200         myCoincidentPoints.push_back(aNewSet);
201       } else
202         aFound2->insert(thePoint1);
203     } else if (aFound2 == myCoincidentPoints.end()) {
204       if (thePoint2)
205         aFound1->insert(thePoint2);
206     } else {
207       aFound1->insert(aFound2->begin(), aFound2->end());
208       myCoincidentPoints.erase(aFound2);
209     }
210   }
211
212   std::set<AttributePoint2DPtr> coincidentPoints(const AttributePoint2DPtr& thePoint)
213   {
214     collectCoincidentPoints(thePoint);
215
216     std::list< std::set<AttributePoint2DPtr> >::iterator aFound = find(thePoint);
217     if (aFound == myCoincidentPoints.end())
218       return std::set<AttributePoint2DPtr>();
219     return *aFound;
220   }
221
222 private:
223   void coincidences(const FeaturePtr& theFeature,
224                     std::set<FeaturePtr>& theCoincidences) const
225   {
226     // iterate through coincideces for the given feature
227     std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(theFeature);
228     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
229     for (; aCIt != aCoincidences.end(); ++aCIt)
230     {
231       if (theCoincidences.find(*aCIt) != theCoincidences.end())
232         continue; // already processed
233       theCoincidences.insert(*aCIt);
234       // iterate on coincident attributes
235       for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
236         AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
237         if (aRefAttr && !aRefAttr->isObject())
238         {
239           FeaturePtr anOwner = ModelAPI_Feature::feature(aRefAttr->attr()->owner());
240           if (anOwner != theFeature)
241             coincidences(anOwner, theCoincidences);
242         }
243       }
244     }
245   }
246
247   // Iteratively search points coincident to the given point
248   // (two points may be coincident through the third point)
249   void collectCoincidentPoints(const AttributePoint2DPtr& thePoint)
250   {
251     AttributePoint2DPtr aPoints[2];
252
253     FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
254     std::set<FeaturePtr> aCoincidences;
255     coincidences(anOwner, aCoincidences);
256
257     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
258     for (; aCIt != aCoincidences.end(); ++aCIt) {
259       aPoints[0] = AttributePoint2DPtr();
260       aPoints[1] = AttributePoint2DPtr();
261       for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
262         AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
263         if (aRefAttr && !aRefAttr->isObject())
264           aPoints[aPtInd++] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
265       }
266
267       if (aPoints[0] && aPoints[1])
268         addCoincidence(aPoints[0], aPoints[1]);
269     }
270   }
271
272   std::list< std::set<AttributePoint2DPtr> >::iterator find(const AttributePoint2DPtr& thePoint)
273   {
274     std::list< std::set<AttributePoint2DPtr> >::iterator aSeek = myCoincidentPoints.begin();
275     for (; aSeek != myCoincidentPoints.end(); ++aSeek)
276       if (aSeek->find(thePoint) != aSeek->end())
277         return aSeek;
278     return myCoincidentPoints.end();
279   }
280
281 private:
282   std::list< std::set<AttributePoint2DPtr> > myCoincidentPoints;
283 };
284
285 std::set<AttributePoint2DPtr> findPointsCoincidentToPoint(const AttributePoint2DPtr& thePoint)
286 {
287   CoincidentPoints aCoincidentPoints;
288   return aCoincidentPoints.coincidentPoints(thePoint);
289 }
290
291 void resetAttribute(SketchPlugin_Feature* theFeature,
292                     const std::string& theId)
293 {
294   AttributePtr anAttr = theFeature->attribute(theId);
295   if(anAttr.get()) {
296     anAttr->reset();
297   }
298 }
299
300 void createCoincidenceOrTangency(SketchPlugin_Feature* theFeature,
301                                  const std::string& theId,
302                                  const AttributePtr theAttr,
303                                  const ObjectPtr theObject,
304                                  const bool theIsCanBeTangent)
305 {
306   AttributeRefAttrPtr aRefAttr = theFeature->refattr(theId);
307   if(aRefAttr.get() && aRefAttr->isInitialized()) {
308     FeaturePtr aConstraint;
309     if(!theIsCanBeTangent) {
310       aConstraint = theFeature->sketch()
311                               ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
312     } else {
313       if(aRefAttr->isObject()) {
314         ObjectPtr anObject = aRefAttr->object();
315         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
316         if(aFeature->getKind() == SketchPlugin_Point::ID()) {
317           aConstraint = theFeature->sketch()
318                                   ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
319         } else {
320           aConstraint = theFeature->sketch()
321                                   ->addFeature(SketchPlugin_ConstraintTangent::ID());
322         }
323       } else {
324         aConstraint = theFeature->sketch()
325                                 ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
326       }
327     }
328     AttributeRefAttrPtr aRefAttrA = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
329     aRefAttr->isObject() ? aRefAttrA->setObject(aRefAttr->object())
330                          : aRefAttrA->setAttr(aRefAttr->attr());
331     AttributeRefAttrPtr aRefAttrB = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
332     if(theObject.get()) {
333       aRefAttrB->setObject(theObject);
334     } else if(theAttr.get()) {
335       aRefAttrB->setAttr(theAttr);
336     }
337   }
338 }
339
340 void convertRefAttrToPointOrTangentCurve(const AttributeRefAttrPtr&      theRefAttr,
341                                          const AttributePtr&             theDefaultAttr,
342                                          std::shared_ptr<GeomAPI_Shape>& theTangentCurve,
343                                          std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
344 {
345   AttributePtr anAttr = theDefaultAttr;
346   if (theRefAttr->isObject()) {
347     FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
348     if (aTgFeature) {
349       if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
350         theTangentCurve = aTgFeature->lastResult()->shape();
351         return;
352       }
353       anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
354     }
355   } else
356     anAttr = theRefAttr->attr();
357
358   thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
359 }
360
361
362 FeaturePtr createConstraintAttrAttr(SketchPlugin_Sketch* theSketch,
363                                     const std::string& theConstraintId,
364                                     const AttributePtr& theFirstAttribute,
365                                     const AttributePtr& theSecondAttribute)
366 {
367   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
368   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
369                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
370   aRefAttr->setAttr(theFirstAttribute);
371
372   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
373                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
374   aRefAttr->setAttr(theSecondAttribute);
375
376 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
377   std::cout << "<createConstraint to attribute> :"
378             << " first attribute - " << theFirstAttribute->id()
379             << " second attribute - " << theSecondAttribute->id()
380             << std::endl;
381 #endif
382
383   return aConstraint;
384 }
385
386 FeaturePtr createConstraintAttrObject(SketchPlugin_Sketch* theSketch,
387                                       const std::string& theConstraintId,
388                                       const AttributePtr& theFirstAttribute,
389                                       const ObjectPtr& theSecondObject)
390 {
391   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
392   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
393                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
394   aRefAttr->setAttr(theFirstAttribute);
395
396   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
397                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
398   aRefAttr->setObject(theSecondObject);
399
400 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
401   std::cout << "<createConstraint to attribute> :"
402             << " first attribute - " << theFirstAttribute->id()
403             << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
404             << std::endl;
405 #endif
406
407   return aConstraint;
408 }
409
410 FeaturePtr createConstraintObjectObject(SketchPlugin_Sketch* theSketch,
411                                         const std::string& theConstraintId,
412                                         const ObjectPtr& theFirstObject,
413                                         const ObjectPtr& theSecondObject)
414 {
415   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
416   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
417                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
418   aRefAttr->setObject(theFirstObject);
419
420   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
421                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
422   aRefAttr->setObject(theSecondObject);
423
424 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
425   std::cout << "<createConstraint to attribute> :"
426             << " first object - " << ModelAPI_Feature::feature(theFirstObject)->getKind()
427             << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
428             << std::endl;
429 #endif
430
431   return aConstraint;
432 }
433
434 void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature,
435                                    const std::string& theEllipsePoint)
436 {
437   SketchPlugin_Sketch* aSketch =
438       std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
439
440   FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
441   aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
442   aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
443
444   AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
445     theEllipseFeature->attribute(theEllipsePoint));
446
447   AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
448     aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
449   aCoord->setValue(anElPoint->x(), anElPoint->y());
450
451   aPointFeature->execute();
452   std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint;
453   aPointFeature->data()->setName(aName);
454   aPointFeature->lastResult()->data()->setName(aName);
455
456   createConstraintAttrAttr(aSketch,
457       SketchPlugin_ConstraintCoincidenceInternal::ID(), anElPoint, aCoord);
458 }
459
460 void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature,
461                                   const std::string& theStartPoint,
462                                   const std::string& theEndPoint)
463 {
464   SketchPlugin_Sketch* aSketch =
465       std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
466
467   FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
468   aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
469   aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
470
471   AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
472     theEllipseFeature->attribute(theStartPoint));
473   AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
474     theEllipseFeature->attribute(theEndPoint));
475
476   AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
477     aLineFeature->attribute(SketchPlugin_Line::START_ID()));
478   aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
479
480   AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
481     aLineFeature->attribute(SketchPlugin_Line::END_ID()));
482   aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
483
484   aLineFeature->execute();
485   std::string aName = theEllipseFeature->name() + "_" +
486     (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis");
487   aLineFeature->data()->setName(aName);
488   aLineFeature->lastResult()->data()->setName(aName);
489
490   createConstraintAttrAttr(aSketch,
491       SketchPlugin_ConstraintCoincidenceInternal::ID(), aStartPoint, aLineStart);
492   createConstraintAttrAttr(aSketch,
493       SketchPlugin_ConstraintCoincidenceInternal::ID(), aEndPoint, aLineEnd);
494 }
495
496 GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
497 {
498   // currently process Length constraints only
499   if (theConstraint->getKind() != SketchPlugin_ConstraintLength::ID())
500     return GeomPnt2dPtr();
501
502   AttributeRefAttrPtr aLineAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
503   if (!aLineAttr || !aLineAttr->isObject())
504     return GeomPnt2dPtr();
505   FeaturePtr aLine = ModelAPI_Feature::feature(aLineAttr->object());
506   if (!aLine || aLine->getKind() != SketchPlugin_Line::ID())
507     return GeomPnt2dPtr();
508
509   std::shared_ptr<GeomAPI_XY> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
510       aLine->attribute(SketchPlugin_Line::START_ID()))->pnt()->xy();
511   std::shared_ptr<GeomAPI_XY> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
512       aLine->attribute(SketchPlugin_Line::END_ID()))->pnt()->xy();
513
514   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
515       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
516       theConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
517   std::shared_ptr<GeomAPI_Pnt2d> aFltPnt = aFlyoutAttr->pnt();
518
519   std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
520
521   double X = aStartPnt->x() + aFltPnt->x() * aLineDir->x() - aFltPnt->y() * aLineDir->y();
522   double Y = aStartPnt->y() + aFltPnt->x() * aLineDir->y() + aFltPnt->y() * aLineDir->x();
523
524   return GeomPnt2dPtr(new GeomAPI_Pnt2d(X, Y));
525 }
526
527 } // namespace SketchPlugin_Tools