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