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