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