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