Salome HOME
updated copyright message
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Tools.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
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_Arc.h"
23 #include "SketchPlugin_BSpline.h"
24 #include "SketchPlugin_Circle.h"
25 #include "SketchPlugin_ConstraintCoincidence.h"
26 #include "SketchPlugin_ConstraintCoincidenceInternal.h"
27 #include "SketchPlugin_ConstraintLength.h"
28 #include "SketchPlugin_ConstraintTangent.h"
29 #include "SketchPlugin_Ellipse.h"
30 #include "SketchPlugin_EllipticArc.h"
31 #include "SketchPlugin_Line.h"
32 #include "SketchPlugin_Point.h"
33 #include "SketchPlugin_Projection.h"
34 #include "SketchPlugin_SketchEntity.h"
35 #include "SketchPlugin_Split.h"
36 #include "SketchPlugin_Trim.h"
37
38 #include <SketcherPrs_Tools.h>
39
40 #include <Locale_Convert.h>
41
42 #include <ModelAPI_AttributeDouble.h>
43 #include <ModelAPI_AttributeInteger.h>
44 #include <ModelAPI_Tools.h>
45
46 #include <ModelGeomAlgo_Point2D.h>
47 #include <ModelGeomAlgo_Shape.h>
48
49 #include <GeomAPI_Dir2d.h>
50 #include <GeomAPI_Edge.h>
51 #include <GeomAPI_Pnt2d.h>
52 #include <GeomAPI_XY.h>
53
54 #include <GeomAlgoAPI_CompoundBuilder.h>
55 #include <GeomAlgoAPI_ShapeTools.h>
56
57 #include <GeomDataAPI_Point.h>
58 #include <GeomDataAPI_Point2D.h>
59
60 #ifdef DEBUG_TRIM
61 #include <iostream>
62 #endif
63
64 namespace SketchPlugin_Tools {
65
66 void clearExpressions(AttributeDoublePtr theAttribute)
67 {
68   theAttribute->setText(std::wstring());
69 }
70
71 void clearExpressions(AttributePointPtr theAttribute)
72 {
73   theAttribute->setText(std::wstring(), std::wstring(), std::wstring());
74 }
75
76 void clearExpressions(AttributePoint2DPtr theAttribute)
77 {
78   theAttribute->setText(std::wstring(), std::wstring());
79 }
80
81 void clearExpressions(AttributePtr theAttribute)
82 {
83   // Double
84   AttributeDoublePtr anAttributeDouble =
85       std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
86   if (anAttributeDouble.get())
87     clearExpressions(anAttributeDouble);
88   // Point
89   AttributePointPtr anAttributePoint =
90       std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
91   if (anAttributePoint.get())
92     clearExpressions(anAttributePoint);
93   // Point2D
94   AttributePoint2DPtr anAttributePoint2D =
95       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
96   if (anAttributePoint2D.get())
97     clearExpressions(anAttributePoint2D);
98 }
99
100 void clearExpressions(FeaturePtr theFeature)
101 {
102   if (!theFeature.get())
103     return;
104
105   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
106   std::list<AttributePtr>::iterator anAttributeIt = anAttributes.begin();
107   for (; anAttributeIt != anAttributes.end(); ++anAttributeIt) {
108     clearExpressions(*anAttributeIt);
109   }
110 }
111
112 std::shared_ptr<GeomAPI_Pnt2d> getCoincidencePoint(const FeaturePtr theStartCoin)
113 {
114   std::shared_ptr<GeomAPI_Pnt2d> aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(),
115                                                           SketchPlugin_Constraint::ENTITY_A());
116   if (aPnt.get() == NULL)
117     aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(), SketchPlugin_Constraint::ENTITY_B());
118   return aPnt;
119 }
120
121 std::set<FeaturePtr> findCoincidentConstraints(const ObjectPtr& theObject)
122 {
123   std::set<FeaturePtr> aCoincident;
124   const std::set<AttributePtr>& aRefsList = theObject->data()->refsToMe();
125   std::set<AttributePtr>::const_iterator aIt;
126   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
127     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
128     if (aConstrFeature && (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
129         aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()))
130       aCoincident.insert(aConstrFeature);
131   }
132   return aCoincident;
133 }
134
135 void findCoincidences(const FeaturePtr theStartCoin,
136                       const std::string& theAttr,
137                       std::set<FeaturePtr>& theList,
138                       const bool theIsAttrOnly)
139 {
140   AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
141   if(!aPnt) {
142     return;
143   }
144   FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
145   if(theList.find(aObj) == theList.end()) {
146     std::shared_ptr<GeomAPI_Pnt2d> aOrig = getCoincidencePoint(theStartCoin);
147     if(aOrig.get() == NULL) {
148       return;
149     }
150     if(!theIsAttrOnly || !aPnt->isObject()) {
151       theList.insert(aObj);
152     }
153     std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(aObj);
154     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
155     for (; aCIt != aCoincidences.end(); ++aCIt) {
156       FeaturePtr aConstrFeature = *aCIt;
157       std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = getCoincidencePoint(aConstrFeature);
158       if(aPnt2d.get() && aOrig->isEqual(aPnt2d)) {
159         findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A(),
160                          theList, theIsAttrOnly);
161         findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B(),
162                          theList, theIsAttrOnly);
163       }
164     }
165   }
166 }
167
168 std::set<FeaturePtr> findFeaturesCoincidentToPoint(const AttributePoint2DPtr& thePoint)
169 {
170   std::set<FeaturePtr> aCoincidentFeatures;
171
172   FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
173   aCoincidentFeatures.insert(anOwner);
174
175   std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(anOwner);
176   std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
177   for (; aCIt != aCoincidences.end(); ++aCIt) {
178     bool isPointUsedInCoincidence = false;
179     AttributeRefAttrPtr anOtherCoincidentAttr;
180     for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
181       AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
182       if (!aRefAttr)
183         continue;
184       if (!aRefAttr->isObject() && aRefAttr->attr() == thePoint)
185         isPointUsedInCoincidence = true;
186       else
187         anOtherCoincidentAttr = aRefAttr;
188     }
189
190     if (isPointUsedInCoincidence) {
191       ObjectPtr anObj;
192       if (anOtherCoincidentAttr->isObject())
193         anObj = anOtherCoincidentAttr->object();
194       else
195         anObj = anOtherCoincidentAttr->attr()->owner();
196       aCoincidentFeatures.insert(ModelAPI_Feature::feature(anObj));
197     }
198   }
199
200   return aCoincidentFeatures;
201 }
202
203 // Container for point-point coincidences.
204 // Useful to find points coincident to a given point.
205 class CoincidentPoints
206 {
207   static const int THE_DEFAULT_INDEX = -1;
208
209 public:
210   void addCoincidence(const AttributePtr& thePoint1, const int theIndex1,
211                       const AttributePtr& thePoint2, const int theIndex2)
212   {
213     auto aFound1 = find(thePoint1, theIndex1);
214     auto aFound2 = find(thePoint2, theIndex2);
215     if (aFound1 == myCoincidentPoints.end()) {
216       if (aFound2 == myCoincidentPoints.end()) {
217         std::map<AttributePtr, std::set<int> > aNewSet;
218         aNewSet[thePoint1].insert(theIndex1);
219         if (thePoint2)
220           aNewSet[thePoint2].insert(theIndex2);
221         myCoincidentPoints.push_back(aNewSet);
222       } else
223         (*aFound2)[thePoint1].insert(theIndex1);
224     } else if (aFound2 == myCoincidentPoints.end()) {
225       if (thePoint2)
226         (*aFound1)[thePoint2].insert(theIndex2);
227     } else {
228       for (auto it = aFound2->begin(); it != aFound2->end(); ++it)
229         (*aFound1)[it->first].insert(it->second.begin(), it->second.end());
230       myCoincidentPoints.erase(aFound2);
231     }
232   }
233
234   std::set<AttributePoint2DPtr> coincidentPoints(const AttributePoint2DPtr& thePoint)
235   {
236     collectCoincidentPoints(thePoint);
237
238     std::set<AttributePoint2DPtr> aCoincPoints;
239     auto aFound = find(thePoint, THE_DEFAULT_INDEX);
240     if (aFound != myCoincidentPoints.end()) {
241       for (auto it = aFound->begin(); it != aFound->end(); ++it) {
242         AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(it->first);
243         if (aPoint)
244           aCoincPoints.insert(aPoint);
245         else {
246           AttributePoint2DArrayPtr aPointArray =
247               std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(it->first);
248           if (aPointArray) {
249             // this is a B-spline feature, the connection is possible
250             // to the first or the last point
251             FeaturePtr anOwner = ModelAPI_Feature::feature(aPointArray->owner());
252             if (it->second.find(0) != it->second.end()) {
253               AttributePoint2DPtr aFirstPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
254                   anOwner->attribute(SketchPlugin_BSpline::START_ID()));
255               aCoincPoints.insert(aFirstPoint);
256             }
257             if (it->second.find(aPointArray->size() - 1) != it->second.end()) {
258               AttributePoint2DPtr aFirstPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
259                   anOwner->attribute(SketchPlugin_BSpline::END_ID()));
260               aCoincPoints.insert(aFirstPoint);
261             }
262           }
263         }
264       }
265     }
266     return aCoincPoints;
267   }
268
269 private:
270   void coincidences(const FeaturePtr& theFeature,
271                     std::set<FeaturePtr>& theCoincidences) const
272   {
273     // iterate through coincideces for the given feature
274     std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(theFeature);
275     if (theFeature->getKind() == SketchPlugin_Point::ID()) {
276       std::set<FeaturePtr> aCoincToRes =
277           SketchPlugin_Tools::findCoincidentConstraints(theFeature->lastResult());
278       aCoincidences.insert(aCoincToRes.begin(), aCoincToRes.end());
279     }
280     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
281     for (; aCIt != aCoincidences.end(); ++aCIt)
282     {
283       if (theCoincidences.find(*aCIt) != theCoincidences.end())
284         continue; // already processed
285       theCoincidences.insert(*aCIt);
286       // iterate on coincident attributes
287       for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
288         AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
289         if (!aRefAttr)
290           continue;
291         FeaturePtr anOwner;
292         if (aRefAttr->isObject()) {
293           FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
294           if (aFeature->getKind() == SketchPlugin_Point::ID())
295             anOwner = aFeature;
296         }
297         else
298           anOwner = ModelAPI_Feature::feature(aRefAttr->attr()->owner());
299         if (anOwner && anOwner != theFeature)
300           coincidences(anOwner, theCoincidences);
301       }
302     }
303   }
304
305   // Iteratively search points coincident to the given point
306   // (two points may be coincident through the third point)
307   void collectCoincidentPoints(const AttributePoint2DPtr& thePoint)
308   {
309     AttributePtr aPoints[2];
310     int anIndicesInArray[2];
311
312     FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
313     std::set<FeaturePtr> aCoincidences;
314     coincidences(anOwner, aCoincidences);
315
316     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
317     for (; aCIt != aCoincidences.end(); ++aCIt) {
318       aPoints[0] = aPoints[1] = AttributePtr();
319       anIndicesInArray[0] = anIndicesInArray[1] = THE_DEFAULT_INDEX;
320       for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
321         AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
322         if (!aRefAttr)
323           continue;
324         if (aRefAttr->isObject()) {
325           FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
326           if (aFeature && aFeature->getKind() == SketchPlugin_Point::ID())
327             aPoints[aPtInd++] = aFeature->attribute(SketchPlugin_Point::COORD_ID());
328         }
329         else {
330           AttributePoint2DPtr aPointAttr =
331               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
332           AttributePoint2DArrayPtr aPointArray =
333               std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(aRefAttr->attr());
334           if (aPointAttr)
335             aPoints[aPtInd++] = aPointAttr;
336           else if (aPointArray) {
337             AttributeIntegerPtr anIndexAttr = (*aCIt)->integer(i == 0 ?
338                 SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
339                 SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
340             aPoints[aPtInd] = aPointArray;
341             anIndicesInArray[aPtInd++] = anIndexAttr->value();
342           }
343         }
344       }
345
346       if (aPoints[0] && aPoints[1])
347         addCoincidence(aPoints[0], anIndicesInArray[0], aPoints[1], anIndicesInArray[1]);
348     }
349   }
350
351   std::list< std::map<AttributePtr, std::set<int> > >::iterator find(const AttributePtr& thePoint,
352                                                                      const int theIndex)
353   {
354     auto aSeek = myCoincidentPoints.begin();
355     for (; aSeek != myCoincidentPoints.end(); ++aSeek) {
356       auto aFound = aSeek->find(thePoint);
357       if (aFound != aSeek->end() && aFound->second.find(theIndex) != aFound->second.end())
358         return aSeek;
359     }
360     // nothing is found, but if the point is a B-spline boundary point, lets check it as poles array
361     FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
362     if (anOwner->getKind() == SketchPlugin_BSpline::ID()) {
363       AttributePtr aPointsArray;
364       int anIndex = -1;
365       if (thePoint->id() == SketchPlugin_BSpline::START_ID()) {
366         aPointsArray = anOwner->attribute(SketchPlugin_BSpline::POLES_ID());
367         anIndex = 0;
368       }
369       else if (thePoint->id() == SketchPlugin_BSpline::END_ID()) {
370         aPointsArray = anOwner->attribute(SketchPlugin_BSpline::POLES_ID());
371         anIndex = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(aPointsArray)->size() - 1;
372       }
373       if (aPointsArray)
374         return find(aPointsArray, anIndex);
375     }
376     return myCoincidentPoints.end();
377   }
378
379 private:
380   std::list< std::map<AttributePtr, std::set<int> > > myCoincidentPoints;
381 };
382
383 std::set<AttributePoint2DPtr> findPointsCoincidentToPoint(const AttributePoint2DPtr& thePoint)
384 {
385   CoincidentPoints aCoincidentPoints;
386   return aCoincidentPoints.coincidentPoints(thePoint);
387 }
388
389
390 void resetAttribute(SketchPlugin_Feature* theFeature,
391                     const std::string& theId)
392 {
393   AttributePtr anAttr = theFeature->attribute(theId);
394   if(anAttr.get()) {
395     anAttr->reset();
396   }
397 }
398
399 void createCoincidenceOrTangency(SketchPlugin_Feature* theFeature,
400                                  const std::string& theId,
401                                  const AttributePtr theAttr,
402                                  const ObjectPtr theObject,
403                                  const bool theIsCanBeTangent)
404 {
405   AttributeRefAttrPtr aRefAttr = theFeature->refattr(theId);
406   if(aRefAttr.get() && aRefAttr->isInitialized()) {
407     FeaturePtr aConstraint;
408     if(!theIsCanBeTangent) {
409       aConstraint = theFeature->sketch()
410                               ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
411     } else {
412       if(aRefAttr->isObject()) {
413         ObjectPtr anObject = aRefAttr->object();
414         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
415         if(aFeature->getKind() == SketchPlugin_Point::ID()) {
416           aConstraint = theFeature->sketch()
417                                   ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
418         } else {
419           aConstraint = theFeature->sketch()
420                                   ->addFeature(SketchPlugin_ConstraintTangent::ID());
421         }
422       } else {
423         aConstraint = theFeature->sketch()
424                                 ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
425       }
426     }
427     AttributeRefAttrPtr aRefAttrA = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
428     aRefAttr->isObject() ? aRefAttrA->setObject(aRefAttr->object())
429                          : aRefAttrA->setAttr(aRefAttr->attr());
430     AttributeRefAttrPtr aRefAttrB = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
431     if(theObject.get()) {
432       aRefAttrB->setObject(theObject);
433     } else if(theAttr.get()) {
434       aRefAttrB->setAttr(theAttr);
435     }
436   }
437 }
438
439 void convertRefAttrToPointOrTangentCurve(const AttributeRefAttrPtr&      theRefAttr,
440                                          const AttributePtr&             theDefaultAttr,
441                                          std::shared_ptr<GeomAPI_Shape>& theTangentCurve,
442                                          std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
443 {
444   AttributePtr anAttr = theDefaultAttr;
445   if (theRefAttr->isObject()) {
446     FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
447     if (aTgFeature) {
448       if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
449         theTangentCurve = aTgFeature->lastResult()->shape();
450         return;
451       }
452       anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
453     }
454   } else
455     anAttr = theRefAttr->attr();
456
457   thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
458 }
459
460
461 FeaturePtr createConstraintAttrAttr(SketchPlugin_Sketch* theSketch,
462                                     const std::string& theConstraintId,
463                                     const AttributePtr& theFirstAttribute,
464                                     const AttributePtr& theSecondAttribute)
465 {
466   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
467   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
468                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
469   aRefAttr->setAttr(theFirstAttribute);
470
471   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
472                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
473   aRefAttr->setAttr(theSecondAttribute);
474
475 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
476   std::cout << "<createConstraint to attribute> :"
477             << " first attribute - " << theFirstAttribute->id()
478             << " second attribute - " << theSecondAttribute->id()
479             << std::endl;
480 #endif
481
482   return aConstraint;
483 }
484
485 FeaturePtr createConstraintAttrObject(SketchPlugin_Sketch* theSketch,
486                                       const std::string& theConstraintId,
487                                       const AttributePtr& theFirstAttribute,
488                                       const ObjectPtr& theSecondObject)
489 {
490   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
491   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
492                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
493   aRefAttr->setAttr(theFirstAttribute);
494
495   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
496                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
497   aRefAttr->setObject(theSecondObject);
498
499 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
500   std::cout << "<createConstraint to attribute> :"
501             << " first attribute - " << theFirstAttribute->id()
502             << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
503             << std::endl;
504 #endif
505
506   return aConstraint;
507 }
508
509 FeaturePtr createConstraintObjectObject(SketchPlugin_Sketch* theSketch,
510                                         const std::string& theConstraintId,
511                                         const ObjectPtr& theFirstObject,
512                                         const ObjectPtr& theSecondObject)
513 {
514   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
515   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
516                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
517   aRefAttr->setObject(theFirstObject);
518
519   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
520                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
521   aRefAttr->setObject(theSecondObject);
522
523 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
524   std::cout << "<createConstraint to attribute> :"
525             << " first object - " << ModelAPI_Feature::feature(theFirstObject)->getKind()
526             << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
527             << std::endl;
528 #endif
529
530   return aConstraint;
531 }
532
533 void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature,
534                                    const std::string& theEllipsePoint)
535 {
536   SketchPlugin_Sketch* aSketch =
537       std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
538
539   FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
540   aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
541   aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
542
543   AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
544     theEllipseFeature->attribute(theEllipsePoint));
545
546   AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
547     aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
548   aCoord->setValue(anElPoint->x(), anElPoint->y());
549
550   aPointFeature->execute();
551   std::wstring aName = theEllipseFeature->name() + L"_" +
552     Locale::Convert::toWString(theEllipsePoint);
553   aPointFeature->data()->setName(aName);
554   aPointFeature->lastResult()->data()->setName(aName);
555
556   createConstraintAttrAttr(aSketch,
557       SketchPlugin_ConstraintCoincidenceInternal::ID(), anElPoint, aCoord);
558 }
559
560 void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature,
561                                   const std::string& theStartPoint,
562                                   const std::string& theEndPoint)
563 {
564   SketchPlugin_Sketch* aSketch =
565       std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
566
567   FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
568   aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
569   aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
570
571   AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
572     theEllipseFeature->attribute(theStartPoint));
573   AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
574     theEllipseFeature->attribute(theEndPoint));
575
576   AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
577     aLineFeature->attribute(SketchPlugin_Line::START_ID()));
578   aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
579
580   AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
581     aLineFeature->attribute(SketchPlugin_Line::END_ID()));
582   aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
583
584   aLineFeature->execute();
585   std::wstring aName = theEllipseFeature->name() + L"_" +
586     (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? L"major_axis" : L"minor_axis");
587   aLineFeature->data()->setName(aName);
588   aLineFeature->lastResult()->data()->setName(aName);
589
590   createConstraintAttrAttr(aSketch,
591       SketchPlugin_ConstraintCoincidenceInternal::ID(), aStartPoint, aLineStart);
592   createConstraintAttrAttr(aSketch,
593       SketchPlugin_ConstraintCoincidenceInternal::ID(), aEndPoint, aLineEnd);
594 }
595
596 GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
597 {
598   // currently process Length constraints only
599   if (theConstraint->getKind() != SketchPlugin_ConstraintLength::ID())
600     return GeomPnt2dPtr();
601
602   AttributeRefAttrPtr aLineAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
603   if (!aLineAttr || !aLineAttr->isObject())
604     return GeomPnt2dPtr();
605   FeaturePtr aLine = ModelAPI_Feature::feature(aLineAttr->object());
606   if (!aLine || aLine->getKind() != SketchPlugin_Line::ID())
607     return GeomPnt2dPtr();
608
609   std::shared_ptr<GeomAPI_XY> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
610       aLine->attribute(SketchPlugin_Line::START_ID()))->pnt()->xy();
611   std::shared_ptr<GeomAPI_XY> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
612       aLine->attribute(SketchPlugin_Line::END_ID()))->pnt()->xy();
613
614   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
615       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
616       theConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
617   std::shared_ptr<GeomAPI_Pnt2d> aFltPnt = aFlyoutAttr->pnt();
618
619   std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
620
621   double X = aStartPnt->x() + aFltPnt->x() * aLineDir->x() - aFltPnt->y() * aLineDir->y();
622   double Y = aStartPnt->y() + aFltPnt->x() * aLineDir->y() + aFltPnt->y() * aLineDir->x();
623
624   return GeomPnt2dPtr(new GeomAPI_Pnt2d(X, Y));
625 }
626
627
628 void customizeFeaturePrs(const AISObjectPtr& thePrs, bool isAxiliary)
629 {
630   std::vector<int> aColor;
631   int aWidth = 1;
632   if (isAxiliary) {
633     thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY());
634     aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color");
635     aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
636   }
637   else {
638     thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE());
639     aColor = Config_PropManager::color("Visualization", "sketch_entity_color");
640     aWidth = Config_PropManager::integer("Visualization", "sketch_line_width");
641   }
642   thePrs->setWidth(aWidth);
643   thePrs->setColor(aColor[0], aColor[1], aColor[2]);
644 }
645
646 void setDimensionColor(const AISObjectPtr& theDimPrs)
647 {
648   std::vector<int> aColor = Config_PropManager::color("Visualization", "sketch_dimension_color");
649   if (aColor.size() == 3)
650     theDimPrs->setColor(aColor[0], aColor[1], aColor[2]);
651 }
652
653 void replaceInName(ObjectPtr theObject, const std::wstring& theSource, const std::wstring& theDest)
654 {
655   std::wstring aName = theObject->data()->name();
656   size_t aPos = aName.find(theSource);
657   if (aPos != std::wstring::npos) {
658     std::wstring aNewName = aName.substr(0, aPos) + theDest
659                           + aName.substr(aPos + theSource.size());
660     theObject->data()->setName(aNewName);
661   }
662 }
663
664 } // namespace SketchPlugin_Tools
665
666
667 // =================================================================================================
668 //                 namespace SketchPlugin_SegmentationTools
669 // =================================================================================================
670
671 void SketchPlugin_SegmentationTools::getFeaturePoints(const FeaturePtr& theFeature,
672                                                       AttributePoint2DPtr& theStartPointAttr,
673                                                       AttributePoint2DPtr& theEndPointAttr)
674 {
675   std::string aFeatureKind = theFeature->getKind();
676   std::string aStartAttributeName, anEndAttributeName;
677   if (aFeatureKind == SketchPlugin_Line::ID()) {
678     aStartAttributeName = SketchPlugin_Line::START_ID();
679     anEndAttributeName = SketchPlugin_Line::END_ID();
680   }
681   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
682     aStartAttributeName = SketchPlugin_Arc::START_ID();
683     anEndAttributeName = SketchPlugin_Arc::END_ID();
684   }
685   else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) {
686     aStartAttributeName = SketchPlugin_EllipticArc::START_POINT_ID();
687     anEndAttributeName = SketchPlugin_EllipticArc::END_POINT_ID();
688   }
689   else if (aFeatureKind == SketchPlugin_BSpline::ID()) {
690     aStartAttributeName = SketchPlugin_BSpline::START_ID();
691     anEndAttributeName = SketchPlugin_BSpline::END_ID();
692   }
693   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
694     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
695         theFeature->attribute(aStartAttributeName));
696     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
697         theFeature->attribute(anEndAttributeName));
698   }
699 }
700
701
702 void SketchPlugin_SegmentationTools::getRefAttributes(
703     const FeaturePtr& theFeature,
704     std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
705     std::list<AttributePtr>& theRefsToFeature)
706 {
707   theRefs.clear();
708
709   std::list<AttributePtr> aPointAttributes =
710     theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
711   std::set<AttributePtr> aPointAttributesSet;
712
713   std::list<AttributePtr>::const_iterator aPIt =
714     aPointAttributes.begin(), aPLast = aPointAttributes.end();
715   for (; aPIt != aPLast; aPIt++)
716     aPointAttributesSet.insert(*aPIt);
717
718   std::set<AttributePtr> aRefsAttributes = theFeature->lastResult()->data()->refsToMe();
719   std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
720   aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
721
722   std::set<AttributePtr>::const_iterator aIt;
723   for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
724     AttributePtr anAttr = (*aIt);
725     FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
726     if (!anAttrFeature->isMacro() && // <- skip reference from Trim or Split feature
727         anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
728       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
729       if (!aRefAttr->isObject()) { // find attributes referenced to feature point attributes
730         AttributePtr anAttrInRef = aRefAttr->attr();
731         if (anAttrInRef.get() &&
732             aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
733           if (theRefs.find(anAttrInRef) != theRefs.end())
734             theRefs[anAttrInRef].push_back(aRefAttr);
735           else {
736             std::list<AttributePtr> anAttrList;
737             anAttrList.push_back(aRefAttr);
738             theRefs[anAttrInRef] = anAttrList;
739           }
740         }
741       }
742       else { // find attributes referenced to feature itself
743         theRefsToFeature.push_back(anAttr);
744       }
745     }
746   }
747 }
748
749 GeomShapePtr SketchPlugin_SegmentationTools::getSubShape(
750     SketchPlugin_Feature* theFeature,
751     const std::string& theObjectAttributeId,
752     const std::string& thePointAttributeId,
753     std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
754     std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints)
755 {
756   GeomShapePtr aBaseShape;
757
758   AttributeReferencePtr anObjectAttr = theFeature->reference(theObjectAttributeId);
759   ObjectPtr aBaseObject = anObjectAttr->value();
760   if (!aBaseObject.get())
761     return aBaseShape;
762
763   // point on feature
764   AttributePoint2DPtr aPointAttr =
765       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(thePointAttributeId));
766   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPointAttr->pnt();
767   std::shared_ptr<GeomAPI_Pnt> anAttributePnt =
768       theFeature->sketch()->to3D(anAttributePnt2d->x(), anAttributePnt2d->y());
769
770   if (theCashedShapes.find(aBaseObject) == theCashedShapes.end())
771     fillObjectShapes(theFeature, aBaseObject, theCashedShapes, theObjectToPoints);
772
773   std::shared_ptr<GeomAPI_Pnt> aStartPoint;
774   std::shared_ptr<GeomAPI_Pnt> aSecondPoint;
775   const std::set<GeomShapePtr>& aShapes = theCashedShapes[aBaseObject];
776   std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
777   for (; anIt != aLast; anIt++) {
778     GeomShapePtr aCurrentShape = *anIt;
779     std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
780     if (ModelGeomAlgo_Point2D::isPointOnEdge(aCurrentShape, anAttributePnt, aProjectedPoint)) {
781       if (theFeature->getKind() == SketchPlugin_Split::ID()) {
782         // for Split operation collect start and end points of the shape
783         if (aCurrentShape->shapeType() == GeomAPI_Shape::EDGE) {
784           std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aCurrentShape));
785           aStartPoint = anEdge->firstPoint();
786           aSecondPoint = anEdge->lastPoint();
787         }
788       }
789       else
790         aBaseShape = aCurrentShape;
791       break;
792     }
793   }
794
795   if (!aStartPoint.get() || !aSecondPoint.get())
796     return aBaseShape;
797
798   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
799   if (anObjectAttr->isInitialized() && aBaseFeature.get() && aPointAttr->isInitialized()) {
800     ResultPtr aResult = aBaseFeature->lastResult();
801     GeomShapePtr aResultShape = aResult->shape();
802     std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
803
804     aPoints.push_back(aStartPoint);
805     aPoints.push_back(aSecondPoint);
806
807     std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
808     GeomAlgoAPI_ShapeTools::splitShape_p(aResultShape, aPoints, aSplitShapes);
809     aBaseShape = GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
810   }
811   return aBaseShape;
812 }
813
814 void SketchPlugin_SegmentationTools::fillObjectShapes(
815     SketchPlugin_Feature* theOpFeature,
816     const ObjectPtr& theObject,
817     std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
818     std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints)
819 {
820   SketchPlugin_Sketch* aSketch = theOpFeature->sketch();
821
822   GeomAlgoAPI_ShapeTools::PointToRefsMap aPoints;
823   std::set<GeomShapePtr> aShapes;
824
825   std::set<AttributePoint2DPtr > aRefAttributes;
826   // current feature
827   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
828   std::set<ResultPtr> anEdgeShapes;
829   // edges on feature
830   ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
831   if (!anEdgeShapes.empty()) {
832     GeomShapePtr aFeatureShape = (*anEdgeShapes.begin())->shape();
833
834     // coincidences to the feature
835     ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
836                          aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
837     // layed on feature coincidences to divide it on several shapes
838     std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
839     std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
840         aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
841     std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
842         aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
843     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
844         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
845     std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
846
847     ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
848                                                   aX->dir(), aY, aPoints);
849
850     if (theOpFeature->getKind() == SketchPlugin_Trim::ID()) {
851       // collect all intersection points with other edges for Trim operation only
852       std::list<FeaturePtr> aFeatures;
853       for (int i = 0; i < aSketch->numberOfSubs(); i++) {
854         FeaturePtr aSubFeature = aSketch->subFeature(i);
855         if (aSubFeature.get() && aSubFeature->getKind() != SketchPlugin_Projection::ID())
856           aFeatures.push_back(aSubFeature);
857       }
858       ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPoints);
859     }
860
861     if (!aPoints.empty())
862       GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPoints, aShapes);
863   }
864   theObjectToPoints[theObject] = aPoints;
865   theCashedShapes[theObject] = aShapes;
866 }
867
868 void SketchPlugin_SegmentationTools::updateRefAttConstraints(
869     const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
870     const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
871 {
872 #if defined DEBUG_SPLIT || defined DEBUG_TRIM
873   std::cout << "updateRefAttConstraints" << std::endl;
874 #endif
875
876   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
877     anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
878   for (; anIt != aLast; anIt++) {
879     AttributePtr anAttribute = anIt->first;
880     AttributePtr aNewAttribute = anIt->second;
881
882     // not found in references
883     if (!aNewAttribute.get() ||
884         theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
885       continue;
886     std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
887     std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
888                                             aRLast = aRefAttributes.end();
889
890     for (; aRefIt != aRLast; aRefIt++) {
891       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
892       if (aRefAttr.get()) {
893         aRefAttr->setAttr(aNewAttribute);
894 #ifdef DEBUG_SPLIT
895         FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
896         std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
897 #endif
898       }
899     }
900   }
901 }
902
903 void SketchPlugin_SegmentationTools::updateFeaturesAfterOperation(
904     const std::set<FeaturePtr>& theFeaturesToUpdate)
905 {
906   std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
907                                        aLast = theFeaturesToUpdate.end();
908   for (; anIt != aLast; anIt++) {
909     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
910     std::string aRefFeatureKind = aRefFeature->getKind();
911     if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
912       std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
913                               std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
914       if (aLenghtFeature.get()) {
915         std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
916             ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
917         double aValue;
918         if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
919           aValueAttr->setValue(aValue);
920       }
921     }
922   }
923 }
924
925 AISObjectPtr SketchPlugin_SegmentationTools::getAISObject(
926     AISObjectPtr thePrevious,
927     SketchPlugin_Feature* theOpFeature,
928     const std::string& thePreviewObjectAttrName,
929     const std::string& thePreviewPointAttrName,
930     const std::string& theSelectedObjectAttrName,
931     const std::string& theSelectedPointAttrName)
932 {
933 #if defined DEBUG_SPLIT || defined DEBUG_TRIM_METHODS
934   std::cout << "getAISObject: " << theOpFeature->data()->name() << std::endl;
935 #endif
936
937   AISObjectPtr anAIS = thePrevious;
938
939   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
940   std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
941   std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap> aObjectToPoints;
942   GeomShapePtr aPreviewShape = getSubShape(theOpFeature,
943       thePreviewObjectAttrName, thePreviewPointAttrName, aCashedShapes, aObjectToPoints);
944   if (aPreviewShape.get())
945     aShapes.push_back(aPreviewShape);
946   GeomShapePtr aSelectedShape = getSubShape(theOpFeature,
947       theSelectedObjectAttrName, theSelectedPointAttrName, aCashedShapes, aObjectToPoints);
948   if (aSelectedShape.get())
949     aShapes.push_back(aSelectedShape);
950
951   if (aShapes.empty())
952     return AISObjectPtr();
953
954   GeomShapePtr aBaseShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
955   if (!aBaseShape.get())
956     return AISObjectPtr();
957
958   if (aBaseShape.get()) {
959     if (!anAIS)
960       anAIS = AISObjectPtr(new GeomAPI_AISObject);
961     anAIS->createShape(aBaseShape);
962
963     std::vector<int> aColor;
964     aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color");
965     double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
966     int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
967     anAIS->setColor(aColor[0], aColor[1], aColor[2]);
968     // width when there is not base object should be extened in several points
969     // in order to see this preview over highlight
970     anAIS->setWidth(aWidth+4);
971     anAIS->setLineStyle(aLineStyle);
972   }
973   else
974     anAIS = AISObjectPtr();
975   return anAIS;
976 }
977
978 #define GEOM_DATA_POINT2D(f, a) std::dynamic_pointer_cast<GeomDataAPI_Point2D>((f)->attribute(a))
979
980 FeaturePtr SketchPlugin_SegmentationTools::createLineFeature(
981     const FeaturePtr& theBaseFeature,
982     const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
983     const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
984 {
985   FeaturePtr aFeature;
986   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
987       std::dynamic_pointer_cast<SketchPlugin_Feature>(theBaseFeature);
988   SketchPlugin_Sketch* aSketch = aSketchFeature->sketch();
989   if (!aSketch || !theBaseFeature.get())
990     return aFeature;
991
992   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
993
994   GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::START_ID())->setValue(theFirstPoint);
995   GEOM_DATA_POINT2D(aFeature, SketchPlugin_Line::END_ID())->setValue(theSecondPoint);
996
997   aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
998       theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
999   aFeature->execute(); // to obtain result
1000
1001   return aFeature;
1002 }
1003
1004 struct ArcAttributes
1005 {
1006   std::string myKind;
1007   std::string myCenter;
1008   std::string myFocus;
1009   std::string myStart;
1010   std::string myEnd;
1011   std::string myReversed;
1012
1013   ArcAttributes() {}
1014
1015   ArcAttributes(const std::string& theKind) : myKind(theKind)
1016   {
1017     if (myKind == SketchPlugin_Arc::ID()) {
1018       myCenter = SketchPlugin_Arc::CENTER_ID();
1019       myStart = SketchPlugin_Arc::START_ID();
1020       myEnd = SketchPlugin_Arc::END_ID();
1021       myReversed = SketchPlugin_Arc::REVERSED_ID();
1022     }
1023     else if (myKind == SketchPlugin_Circle::ID()) {
1024       myCenter = SketchPlugin_Circle::CENTER_ID();
1025     }
1026     else if (myKind == SketchPlugin_Ellipse::ID()) {
1027       myCenter = SketchPlugin_Ellipse::CENTER_ID();
1028       myFocus = SketchPlugin_Ellipse::FIRST_FOCUS_ID();
1029     }
1030     else if (myKind == SketchPlugin_EllipticArc::ID()) {
1031       myCenter = SketchPlugin_EllipticArc::CENTER_ID();
1032       myFocus = SketchPlugin_EllipticArc::FIRST_FOCUS_ID();
1033       myStart = SketchPlugin_EllipticArc::START_POINT_ID();
1034       myEnd = SketchPlugin_EllipticArc::END_POINT_ID();
1035       myReversed = SketchPlugin_EllipticArc::REVERSED_ID();
1036     }
1037   }
1038 };
1039
1040 FeaturePtr SketchPlugin_SegmentationTools::createArcFeature(
1041     const FeaturePtr& theBaseFeature,
1042     const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
1043     const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
1044 {
1045   FeaturePtr aFeature;
1046   std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
1047       std::dynamic_pointer_cast<SketchPlugin_Feature>(theBaseFeature);
1048   SketchPlugin_Sketch* aSketch = aSketchFeature->sketch();
1049   if (!aSketch || !theBaseFeature.get())
1050     return aFeature;
1051
1052   ArcAttributes aBaseAttrs(theBaseFeature->getKind());
1053   ArcAttributes aTargetAttrs;
1054   if (aBaseAttrs.myKind == SketchPlugin_Arc::ID() ||
1055       aBaseAttrs.myKind == SketchPlugin_Circle::ID())
1056     aTargetAttrs = ArcAttributes(SketchPlugin_Arc::ID());
1057   else if (aBaseAttrs.myKind == SketchPlugin_Ellipse::ID() ||
1058            aBaseAttrs.myKind == SketchPlugin_EllipticArc::ID())
1059     aTargetAttrs = ArcAttributes(SketchPlugin_EllipticArc::ID());
1060
1061   if (aTargetAttrs.myKind.empty())
1062     return aFeature;
1063
1064   aFeature = aSketch->addFeature(aTargetAttrs.myKind);
1065   // update fillet arc: make the arc correct for sure, so, it is not needed to process
1066   // the "attribute updated"
1067   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1068   bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
1069
1070   GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myCenter)->setValue(
1071       GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myCenter)->pnt());
1072   if (!aTargetAttrs.myFocus.empty()) {
1073     GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myFocus)->setValue(
1074         GEOM_DATA_POINT2D(theBaseFeature, aBaseAttrs.myFocus)->pnt());
1075   }
1076   GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myStart)->setValue(theFirstPoint);
1077   GEOM_DATA_POINT2D(aFeature, aTargetAttrs.myEnd)->setValue(theSecondPoint);
1078
1079   aFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
1080       theBaseFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value());
1081
1082   /// fill referersed state of created arc as it is on the base arc
1083   bool aReversed = aBaseAttrs.myReversed.empty() ? false :
1084                    theBaseFeature->boolean(aBaseAttrs.myReversed)->value();
1085   aFeature->boolean(aTargetAttrs.myReversed)->setValue(aReversed);
1086
1087   aFeature->execute(); // to obtain result (need to calculate arc parameters before sending Update)
1088   aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
1089
1090   return aFeature;
1091 }