Salome HOME
Refactoring: Split and Trim features of SketchPlugin.
[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_ConstraintCoincidence.h"
24 #include "SketchPlugin_ConstraintCoincidenceInternal.h"
25 #include "SketchPlugin_ConstraintLength.h"
26 #include "SketchPlugin_ConstraintTangent.h"
27 #include "SketchPlugin_Ellipse.h"
28 #include "SketchPlugin_EllipticArc.h"
29 #include "SketchPlugin_Line.h"
30 #include "SketchPlugin_Point.h"
31 #include "SketchPlugin_Projection.h"
32 #include "SketchPlugin_SketchEntity.h"
33 #include "SketchPlugin_Split.h"
34 #include "SketchPlugin_Trim.h"
35
36 #include <SketcherPrs_Tools.h>
37
38 #include <ModelAPI_AttributeDouble.h>
39
40 #include <ModelGeomAlgo_Point2D.h>
41 #include <ModelGeomAlgo_Shape.h>
42
43 #include <GeomAPI_Dir2d.h>
44 #include <GeomAPI_Edge.h>
45 #include <GeomAPI_Pnt2d.h>
46 #include <GeomAPI_XY.h>
47
48 #include <GeomAlgoAPI_CompoundBuilder.h>
49 #include <GeomAlgoAPI_ShapeTools.h>
50
51 #include <GeomDataAPI_Point.h>
52 #include <GeomDataAPI_Point2D.h>
53
54 #ifdef DEBUG_TRIM
55 #include <iostream>
56 #endif
57
58 namespace SketchPlugin_Tools {
59
60 void clearExpressions(AttributeDoublePtr theAttribute)
61 {
62   theAttribute->setText(std::string());
63 }
64
65 void clearExpressions(AttributePointPtr theAttribute)
66 {
67   theAttribute->setText(std::string(), std::string(), std::string());
68 }
69
70 void clearExpressions(AttributePoint2DPtr theAttribute)
71 {
72   theAttribute->setText(std::string(), std::string());
73 }
74
75 void clearExpressions(AttributePtr theAttribute)
76 {
77   // Double
78   AttributeDoublePtr anAttributeDouble =
79       std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
80   if (anAttributeDouble.get())
81     clearExpressions(anAttributeDouble);
82   // Point
83   AttributePointPtr anAttributePoint =
84       std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
85   if (anAttributePoint.get())
86     clearExpressions(anAttributePoint);
87   // Point2D
88   AttributePoint2DPtr anAttributePoint2D =
89       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
90   if (anAttributePoint2D.get())
91     clearExpressions(anAttributePoint2D);
92 }
93
94 void clearExpressions(FeaturePtr theFeature)
95 {
96   if (!theFeature.get())
97     return;
98
99   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
100   std::list<AttributePtr>::iterator anAttributeIt = anAttributes.begin();
101   for (; anAttributeIt != anAttributes.end(); ++anAttributeIt) {
102     clearExpressions(*anAttributeIt);
103   }
104 }
105
106 std::shared_ptr<GeomAPI_Pnt2d> getCoincidencePoint(const FeaturePtr theStartCoin)
107 {
108   std::shared_ptr<GeomAPI_Pnt2d> aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(),
109                                                           SketchPlugin_Constraint::ENTITY_A());
110   if (aPnt.get() == NULL)
111     aPnt = SketcherPrs_Tools::getPoint(theStartCoin.get(), SketchPlugin_Constraint::ENTITY_B());
112   return aPnt;
113 }
114
115 std::set<FeaturePtr> findCoincidentConstraints(const FeaturePtr& theFeature)
116 {
117   std::set<FeaturePtr> aCoincident;
118   const std::set<AttributePtr>& aRefsList = theFeature->data()->refsToMe();
119   std::set<AttributePtr>::const_iterator aIt;
120   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
121     FeaturePtr aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aIt)->owner());
122     if (aConstrFeature && aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID())
123       aCoincident.insert(aConstrFeature);
124   }
125   return aCoincident;
126 }
127
128 void findCoincidences(const FeaturePtr theStartCoin,
129                       const std::string& theAttr,
130                       std::set<FeaturePtr>& theList,
131                       const bool theIsAttrOnly)
132 {
133   AttributeRefAttrPtr aPnt = theStartCoin->refattr(theAttr);
134   if(!aPnt) {
135     return;
136   }
137   FeaturePtr aObj = ModelAPI_Feature::feature(aPnt->object());
138   if(theList.find(aObj) == theList.end()) {
139     std::shared_ptr<GeomAPI_Pnt2d> aOrig = getCoincidencePoint(theStartCoin);
140     if(aOrig.get() == NULL) {
141       return;
142     }
143     if(!theIsAttrOnly || !aPnt->isObject()) {
144       theList.insert(aObj);
145     }
146     std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(aObj);
147     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
148     for (; aCIt != aCoincidences.end(); ++aCIt) {
149       FeaturePtr aConstrFeature = *aCIt;
150       std::shared_ptr<GeomAPI_Pnt2d> aPnt = getCoincidencePoint(aConstrFeature);
151       if(aPnt.get() && aOrig->isEqual(aPnt)) {
152         findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_A(),
153                          theList, theIsAttrOnly);
154         findCoincidences(aConstrFeature, SketchPlugin_ConstraintCoincidence::ENTITY_B(),
155                          theList, theIsAttrOnly);
156       }
157     }
158   }
159 }
160
161 std::set<FeaturePtr> findFeaturesCoincidentToPoint(const AttributePoint2DPtr& thePoint)
162 {
163   std::set<FeaturePtr> aCoincidentFeatures;
164
165   FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
166   aCoincidentFeatures.insert(anOwner);
167
168   std::set<FeaturePtr> aCoincidences = findCoincidentConstraints(anOwner);
169   std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
170   for (; aCIt != aCoincidences.end(); ++aCIt) {
171     bool isPointUsedInCoincidence = false;
172     AttributeRefAttrPtr anOtherCoincidentAttr;
173     for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
174       AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
175       if (!aRefAttr)
176         continue;
177       if (!aRefAttr->isObject() && aRefAttr->attr() == thePoint)
178         isPointUsedInCoincidence = true;
179       else
180         anOtherCoincidentAttr = aRefAttr;
181     }
182
183     if (isPointUsedInCoincidence) {
184       ObjectPtr anObj;
185       if (anOtherCoincidentAttr->isObject())
186         anObj = anOtherCoincidentAttr->object();
187       else
188         anObj = anOtherCoincidentAttr->attr()->owner();
189       aCoincidentFeatures.insert(ModelAPI_Feature::feature(anObj));
190     }
191   }
192
193   return aCoincidentFeatures;
194 }
195
196 // Container for point-point coincidences.
197 // Useful to find points coincident to a given point.
198 class CoincidentPoints
199 {
200 public:
201   void addCoincidence(const AttributePoint2DPtr& thePoint1,
202                       const AttributePoint2DPtr& thePoint2 = AttributePoint2DPtr())
203   {
204     std::list< std::set<AttributePoint2DPtr> >::iterator aFound1 = find(thePoint1);
205     std::list< std::set<AttributePoint2DPtr> >::iterator aFound2 = find(thePoint2);
206     if (aFound1 == myCoincidentPoints.end()) {
207       if (aFound2 == myCoincidentPoints.end()) {
208         std::set<AttributePoint2DPtr> aNewSet;
209         aNewSet.insert(thePoint1);
210         if (thePoint2)
211           aNewSet.insert(thePoint2);
212         myCoincidentPoints.push_back(aNewSet);
213       } else
214         aFound2->insert(thePoint1);
215     } else if (aFound2 == myCoincidentPoints.end()) {
216       if (thePoint2)
217         aFound1->insert(thePoint2);
218     } else {
219       aFound1->insert(aFound2->begin(), aFound2->end());
220       myCoincidentPoints.erase(aFound2);
221     }
222   }
223
224   std::set<AttributePoint2DPtr> coincidentPoints(const AttributePoint2DPtr& thePoint)
225   {
226     collectCoincidentPoints(thePoint);
227
228     std::list< std::set<AttributePoint2DPtr> >::iterator aFound = find(thePoint);
229     if (aFound == myCoincidentPoints.end())
230       return std::set<AttributePoint2DPtr>();
231     return *aFound;
232   }
233
234 private:
235   void coincidences(const FeaturePtr& theFeature,
236                     std::set<FeaturePtr>& theCoincidences) const
237   {
238     // iterate through coincideces for the given feature
239     std::set<FeaturePtr> aCoincidences = SketchPlugin_Tools::findCoincidentConstraints(theFeature);
240     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
241     for (; aCIt != aCoincidences.end(); ++aCIt)
242     {
243       if (theCoincidences.find(*aCIt) != theCoincidences.end())
244         continue; // already processed
245       theCoincidences.insert(*aCIt);
246       // iterate on coincident attributes
247       for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
248         AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
249         if (aRefAttr && !aRefAttr->isObject())
250         {
251           FeaturePtr anOwner = ModelAPI_Feature::feature(aRefAttr->attr()->owner());
252           if (anOwner != theFeature)
253             coincidences(anOwner, theCoincidences);
254         }
255       }
256     }
257   }
258
259   // Iteratively search points coincident to the given point
260   // (two points may be coincident through the third point)
261   void collectCoincidentPoints(const AttributePoint2DPtr& thePoint)
262   {
263     AttributePoint2DPtr aPoints[2];
264
265     FeaturePtr anOwner = ModelAPI_Feature::feature(thePoint->owner());
266     std::set<FeaturePtr> aCoincidences;
267     coincidences(anOwner, aCoincidences);
268
269     std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
270     for (; aCIt != aCoincidences.end(); ++aCIt) {
271       aPoints[0] = AttributePoint2DPtr();
272       aPoints[1] = AttributePoint2DPtr();
273       for (int i = 0, aPtInd = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
274         AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
275         if (aRefAttr && !aRefAttr->isObject())
276           aPoints[aPtInd++] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
277       }
278
279       if (aPoints[0] && aPoints[1])
280         addCoincidence(aPoints[0], aPoints[1]);
281     }
282   }
283
284   std::list< std::set<AttributePoint2DPtr> >::iterator find(const AttributePoint2DPtr& thePoint)
285   {
286     std::list< std::set<AttributePoint2DPtr> >::iterator aSeek = myCoincidentPoints.begin();
287     for (; aSeek != myCoincidentPoints.end(); ++aSeek)
288       if (aSeek->find(thePoint) != aSeek->end())
289         return aSeek;
290     return myCoincidentPoints.end();
291   }
292
293 private:
294   std::list< std::set<AttributePoint2DPtr> > myCoincidentPoints;
295 };
296
297 std::set<AttributePoint2DPtr> findPointsCoincidentToPoint(const AttributePoint2DPtr& thePoint)
298 {
299   CoincidentPoints aCoincidentPoints;
300   return aCoincidentPoints.coincidentPoints(thePoint);
301 }
302
303 void resetAttribute(SketchPlugin_Feature* theFeature,
304                     const std::string& theId)
305 {
306   AttributePtr anAttr = theFeature->attribute(theId);
307   if(anAttr.get()) {
308     anAttr->reset();
309   }
310 }
311
312 void createCoincidenceOrTangency(SketchPlugin_Feature* theFeature,
313                                  const std::string& theId,
314                                  const AttributePtr theAttr,
315                                  const ObjectPtr theObject,
316                                  const bool theIsCanBeTangent)
317 {
318   AttributeRefAttrPtr aRefAttr = theFeature->refattr(theId);
319   if(aRefAttr.get() && aRefAttr->isInitialized()) {
320     FeaturePtr aConstraint;
321     if(!theIsCanBeTangent) {
322       aConstraint = theFeature->sketch()
323                               ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
324     } else {
325       if(aRefAttr->isObject()) {
326         ObjectPtr anObject = aRefAttr->object();
327         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
328         if(aFeature->getKind() == SketchPlugin_Point::ID()) {
329           aConstraint = theFeature->sketch()
330                                   ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
331         } else {
332           aConstraint = theFeature->sketch()
333                                   ->addFeature(SketchPlugin_ConstraintTangent::ID());
334         }
335       } else {
336         aConstraint = theFeature->sketch()
337                                 ->addFeature(SketchPlugin_ConstraintCoincidence::ID());
338       }
339     }
340     AttributeRefAttrPtr aRefAttrA = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
341     aRefAttr->isObject() ? aRefAttrA->setObject(aRefAttr->object())
342                          : aRefAttrA->setAttr(aRefAttr->attr());
343     AttributeRefAttrPtr aRefAttrB = aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
344     if(theObject.get()) {
345       aRefAttrB->setObject(theObject);
346     } else if(theAttr.get()) {
347       aRefAttrB->setAttr(theAttr);
348     }
349   }
350 }
351
352 void convertRefAttrToPointOrTangentCurve(const AttributeRefAttrPtr&      theRefAttr,
353                                          const AttributePtr&             theDefaultAttr,
354                                          std::shared_ptr<GeomAPI_Shape>& theTangentCurve,
355                                          std::shared_ptr<GeomAPI_Pnt2d>& thePassingPoint)
356 {
357   AttributePtr anAttr = theDefaultAttr;
358   if (theRefAttr->isObject()) {
359     FeaturePtr aTgFeature = ModelAPI_Feature::feature(theRefAttr->object());
360     if (aTgFeature) {
361       if (aTgFeature->getKind() != SketchPlugin_Point::ID()) {
362         theTangentCurve = aTgFeature->lastResult()->shape();
363         return;
364       }
365       anAttr = aTgFeature->attribute(SketchPlugin_Point::COORD_ID());
366     }
367   } else
368     anAttr = theRefAttr->attr();
369
370   thePassingPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr)->pnt();
371 }
372
373
374 FeaturePtr createConstraintAttrAttr(SketchPlugin_Sketch* theSketch,
375                                     const std::string& theConstraintId,
376                                     const AttributePtr& theFirstAttribute,
377                                     const AttributePtr& theSecondAttribute)
378 {
379   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
380   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
381                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
382   aRefAttr->setAttr(theFirstAttribute);
383
384   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
385                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
386   aRefAttr->setAttr(theSecondAttribute);
387
388 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
389   std::cout << "<createConstraint to attribute> :"
390             << " first attribute - " << theFirstAttribute->id()
391             << " second attribute - " << theSecondAttribute->id()
392             << std::endl;
393 #endif
394
395   return aConstraint;
396 }
397
398 FeaturePtr createConstraintAttrObject(SketchPlugin_Sketch* theSketch,
399                                       const std::string& theConstraintId,
400                                       const AttributePtr& theFirstAttribute,
401                                       const ObjectPtr& theSecondObject)
402 {
403   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
404   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
405                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
406   aRefAttr->setAttr(theFirstAttribute);
407
408   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
409                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
410   aRefAttr->setObject(theSecondObject);
411
412 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
413   std::cout << "<createConstraint to attribute> :"
414             << " first attribute - " << theFirstAttribute->id()
415             << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
416             << std::endl;
417 #endif
418
419   return aConstraint;
420 }
421
422 FeaturePtr createConstraintObjectObject(SketchPlugin_Sketch* theSketch,
423                                         const std::string& theConstraintId,
424                                         const ObjectPtr& theFirstObject,
425                                         const ObjectPtr& theSecondObject)
426 {
427   FeaturePtr aConstraint = theSketch->addFeature(theConstraintId);
428   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
429                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
430   aRefAttr->setObject(theFirstObject);
431
432   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
433                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
434   aRefAttr->setObject(theSecondObject);
435
436 #if defined(DEBUG_TRIM) || defined(DEBUG_SPLIT)
437   std::cout << "<createConstraint to attribute> :"
438             << " first object - " << ModelAPI_Feature::feature(theFirstObject)->getKind()
439             << " second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
440             << std::endl;
441 #endif
442
443   return aConstraint;
444 }
445
446 void createAuxiliaryPointOnEllipse(const FeaturePtr& theEllipseFeature,
447                                    const std::string& theEllipsePoint)
448 {
449   SketchPlugin_Sketch* aSketch =
450       std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
451
452   FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
453   aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
454   aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
455
456   AttributePoint2DPtr anElPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
457     theEllipseFeature->attribute(theEllipsePoint));
458
459   AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
460     aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
461   aCoord->setValue(anElPoint->x(), anElPoint->y());
462
463   aPointFeature->execute();
464   std::string aName = theEllipseFeature->name() + "_" + theEllipsePoint;
465   aPointFeature->data()->setName(aName);
466   aPointFeature->lastResult()->data()->setName(aName);
467
468   createConstraintAttrAttr(aSketch,
469       SketchPlugin_ConstraintCoincidenceInternal::ID(), anElPoint, aCoord);
470 }
471
472 void createAuxiliaryAxisOfEllipse(const FeaturePtr& theEllipseFeature,
473                                   const std::string& theStartPoint,
474                                   const std::string& theEndPoint)
475 {
476   SketchPlugin_Sketch* aSketch =
477       std::dynamic_pointer_cast<SketchPlugin_Feature>(theEllipseFeature)->sketch();
478
479   FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
480   aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
481   aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theEllipseFeature);
482
483   AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
484     theEllipseFeature->attribute(theStartPoint));
485   AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
486     theEllipseFeature->attribute(theEndPoint));
487
488   AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
489     aLineFeature->attribute(SketchPlugin_Line::START_ID()));
490   aLineStart->setValue(aStartPoint->x(), aStartPoint->y());
491
492   AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
493     aLineFeature->attribute(SketchPlugin_Line::END_ID()));
494   aLineEnd->setValue(aEndPoint->x(), aEndPoint->y());
495
496   aLineFeature->execute();
497   std::string aName = theEllipseFeature->name() + "_" +
498     (theStartPoint == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID() ? "major_axis" : "minor_axis");
499   aLineFeature->data()->setName(aName);
500   aLineFeature->lastResult()->data()->setName(aName);
501
502   createConstraintAttrAttr(aSketch,
503       SketchPlugin_ConstraintCoincidenceInternal::ID(), aStartPoint, aLineStart);
504   createConstraintAttrAttr(aSketch,
505       SketchPlugin_ConstraintCoincidenceInternal::ID(), aEndPoint, aLineEnd);
506 }
507
508 GeomPnt2dPtr flyoutPointCoordinates(const ConstraintPtr& theConstraint)
509 {
510   // currently process Length constraints only
511   if (theConstraint->getKind() != SketchPlugin_ConstraintLength::ID())
512     return GeomPnt2dPtr();
513
514   AttributeRefAttrPtr aLineAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
515   if (!aLineAttr || !aLineAttr->isObject())
516     return GeomPnt2dPtr();
517   FeaturePtr aLine = ModelAPI_Feature::feature(aLineAttr->object());
518   if (!aLine || aLine->getKind() != SketchPlugin_Line::ID())
519     return GeomPnt2dPtr();
520
521   std::shared_ptr<GeomAPI_XY> aStartPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
522       aLine->attribute(SketchPlugin_Line::START_ID()))->pnt()->xy();
523   std::shared_ptr<GeomAPI_XY> aEndPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
524       aLine->attribute(SketchPlugin_Line::END_ID()))->pnt()->xy();
525
526   std::shared_ptr<GeomDataAPI_Point2D> aFlyoutAttr =
527       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
528       theConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()));
529   std::shared_ptr<GeomAPI_Pnt2d> aFltPnt = aFlyoutAttr->pnt();
530
531   std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
532
533   double X = aStartPnt->x() + aFltPnt->x() * aLineDir->x() - aFltPnt->y() * aLineDir->y();
534   double Y = aStartPnt->y() + aFltPnt->x() * aLineDir->y() + aFltPnt->y() * aLineDir->x();
535
536   return GeomPnt2dPtr(new GeomAPI_Pnt2d(X, Y));
537 }
538
539 } // namespace SketchPlugin_Tools
540
541
542 // =================================================================================================
543 //                 namespace SketchPlugin_SegmentationTools
544 // =================================================================================================
545
546 void SketchPlugin_SegmentationTools::getFeaturePoints(const FeaturePtr& theFeature,
547                                                       AttributePoint2DPtr& theStartPointAttr,
548                                                       AttributePoint2DPtr& theEndPointAttr)
549 {
550   std::string aFeatureKind = theFeature->getKind();
551   std::string aStartAttributeName, anEndAttributeName;
552   if (aFeatureKind == SketchPlugin_Line::ID()) {
553     aStartAttributeName = SketchPlugin_Line::START_ID();
554     anEndAttributeName = SketchPlugin_Line::END_ID();
555   }
556   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
557     aStartAttributeName = SketchPlugin_Arc::START_ID();
558     anEndAttributeName = SketchPlugin_Arc::END_ID();
559   }
560   else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) {
561     aStartAttributeName = SketchPlugin_EllipticArc::START_POINT_ID();
562     anEndAttributeName = SketchPlugin_EllipticArc::END_POINT_ID();
563   }
564   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
565     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
566         theFeature->attribute(aStartAttributeName));
567     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
568         theFeature->attribute(anEndAttributeName));
569   }
570 }
571
572
573 void SketchPlugin_SegmentationTools::getRefAttributes(
574     const FeaturePtr& theFeature,
575     std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
576     std::list<AttributePtr>& theRefsToFeature)
577 {
578   theRefs.clear();
579
580   std::list<AttributePtr> aPointAttributes =
581     theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
582   std::set<AttributePtr> aPointAttributesSet;
583
584   std::list<AttributePtr>::const_iterator aPIt =
585     aPointAttributes.begin(), aPLast = aPointAttributes.end();
586   for (; aPIt != aPLast; aPIt++)
587     aPointAttributesSet.insert(*aPIt);
588
589   std::set<AttributePtr> aRefsAttributes = theFeature->lastResult()->data()->refsToMe();
590   std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
591   aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
592
593   std::set<AttributePtr>::const_iterator aIt;
594   for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
595     AttributePtr anAttr = (*aIt);
596     FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
597     if (!anAttrFeature->isMacro() && // <- skip reference from Trim or Split feature
598         anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
599       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
600       if (!aRefAttr->isObject()) { // find attributes referenced to feature point attributes
601         AttributePtr anAttrInRef = aRefAttr->attr();
602         if (anAttrInRef.get() &&
603             aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
604           if (theRefs.find(anAttrInRef) != theRefs.end())
605             theRefs[anAttrInRef].push_back(aRefAttr);
606           else {
607             std::list<AttributePtr> anAttrList;
608             anAttrList.push_back(aRefAttr);
609             theRefs[anAttrInRef] = anAttrList;
610           }
611         }
612       }
613       else { // find attributes referenced to feature itself
614         theRefsToFeature.push_back(anAttr);
615       }
616     }
617   }
618 }
619
620 GeomShapePtr SketchPlugin_SegmentationTools::getSubShape(
621     SketchPlugin_Feature* theFeature,
622     const std::string& theObjectAttributeId,
623     const std::string& thePointAttributeId,
624     std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
625     std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints)
626 {
627   GeomShapePtr aBaseShape;
628
629   AttributeReferencePtr anObjectAttr = theFeature->reference(theObjectAttributeId);
630   ObjectPtr aBaseObject = anObjectAttr->value();
631   if (!aBaseObject.get())
632     return aBaseShape;
633
634   // point on feature
635   AttributePoint2DPtr aPointAttr =
636       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theFeature->attribute(thePointAttributeId));
637   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPointAttr->pnt();
638   std::shared_ptr<GeomAPI_Pnt> anAttributePnt =
639       theFeature->sketch()->to3D(anAttributePnt2d->x(), anAttributePnt2d->y());
640
641   if (theCashedShapes.find(aBaseObject) == theCashedShapes.end())
642     fillObjectShapes(theFeature, aBaseObject, theCashedShapes, theObjectToPoints);
643
644   std::shared_ptr<GeomAPI_Pnt> aStartPoint;
645   std::shared_ptr<GeomAPI_Pnt> aSecondPoint;
646   const std::set<GeomShapePtr>& aShapes = theCashedShapes[aBaseObject];
647   std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
648   for (; anIt != aLast; anIt++) {
649     GeomShapePtr aCurrentShape = *anIt;
650     std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
651     if (ModelGeomAlgo_Point2D::isPointOnEdge(aCurrentShape, anAttributePnt, aProjectedPoint)) {
652       if (theFeature->getKind() == SketchPlugin_Split::ID()) {
653         // for Split operation collect start and end points of the shape
654         if (aCurrentShape->shapeType() == GeomAPI_Shape::EDGE) {
655           std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aCurrentShape));
656           aStartPoint = anEdge->firstPoint();
657           aSecondPoint = anEdge->lastPoint();
658         }
659       }
660       else
661         aBaseShape = aCurrentShape;
662       break;
663     }
664   }
665
666   if (!aStartPoint.get() || !aSecondPoint.get())
667     return aBaseShape;
668
669   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
670   if (anObjectAttr->isInitialized() && aBaseFeature.get() && aPointAttr->isInitialized()) {
671     ResultPtr aResult = aBaseFeature->lastResult();
672     GeomShapePtr aResultShape = aResult->shape();
673     std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
674
675     aPoints.push_back(aStartPoint);
676     aPoints.push_back(aSecondPoint);
677
678     std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
679     GeomAlgoAPI_ShapeTools::splitShape_p(aResultShape, aPoints, aSplitShapes);
680     aBaseShape = GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
681   }
682   return aBaseShape;
683 }
684
685 void SketchPlugin_SegmentationTools::fillObjectShapes(
686     SketchPlugin_Feature* theOpFeature,
687     const ObjectPtr& theObject,
688     std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
689     std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap>& theObjectToPoints)
690 {
691   SketchPlugin_Sketch* aSketch = theOpFeature->sketch();
692
693   GeomAlgoAPI_ShapeTools::PointToRefsMap aPoints;
694   std::set<GeomShapePtr> aShapes;
695
696   std::set<AttributePoint2DPtr > aRefAttributes;
697   // current feature
698   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
699   std::set<ResultPtr> anEdgeShapes;
700   // edges on feature
701   ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
702   if (!anEdgeShapes.empty()) {
703     GeomShapePtr aFeatureShape = (*anEdgeShapes.begin())->shape();
704
705     // coincidences to the feature
706     ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
707                          aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
708     // layed on feature coincidences to divide it on several shapes
709     std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
710     std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
711         aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
712     std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
713         aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
714     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
715         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
716     std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
717
718     ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
719                                                   aX->dir(), aY, aPoints);
720
721     if (theOpFeature->getKind() == SketchPlugin_Trim::ID()) {
722       // collect all intersection points with other edges for Trim operation only
723       std::list<FeaturePtr> aFeatures;
724       for (int i = 0; i < aSketch->numberOfSubs(); i++) {
725         FeaturePtr aFeature = aSketch->subFeature(i);
726         if (aFeature.get() && aFeature->getKind() != SketchPlugin_Projection::ID())
727           aFeatures.push_back(aFeature);
728       }
729       ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPoints);
730     }
731
732     if (!aPoints.empty())
733       GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPoints, aShapes);
734   }
735   theObjectToPoints[theObject] = aPoints;
736   theCashedShapes[theObject] = aShapes;
737 }
738
739 void SketchPlugin_SegmentationTools::updateRefAttConstraints(
740     const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
741     const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
742 {
743 #if defined DEBUG_SPLIT || defined DEBUG_TRIM
744   std::cout << "updateRefAttConstraints" << std::endl;
745 #endif
746
747   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
748     anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
749   for (; anIt != aLast; anIt++) {
750     AttributePtr anAttribute = anIt->first;
751     AttributePtr aNewAttribute = anIt->second;
752
753     // not found in references
754     if (!aNewAttribute.get() ||
755         theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
756       continue;
757     std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
758     std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
759                                             aRLast = aRefAttributes.end();
760
761     for (; aRefIt != aRLast; aRefIt++) {
762       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
763       if (aRefAttr.get()) {
764         aRefAttr->setAttr(aNewAttribute);
765 #ifdef DEBUG_SPLIT
766         FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
767         std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
768 #endif
769       }
770     }
771   }
772 }
773
774 void SketchPlugin_SegmentationTools::updateFeaturesAfterOperation(
775     const std::set<FeaturePtr>& theFeaturesToUpdate)
776 {
777   std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
778                                        aLast = theFeaturesToUpdate.end();
779   for (; anIt != aLast; anIt++) {
780     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
781     std::string aRefFeatureKind = aRefFeature->getKind();
782     if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
783       std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
784                               std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
785       if (aLenghtFeature.get()) {
786         std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
787             ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
788         double aValue;
789         if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
790           aValueAttr->setValue(aValue);
791       }
792     }
793   }
794 }
795
796 AISObjectPtr SketchPlugin_SegmentationTools::getAISObject(
797     AISObjectPtr thePrevious,
798     SketchPlugin_Feature* theOpFeature,
799     const std::string& thePreviewObjectAttrName,
800     const std::string& thePreviewPointAttrName,
801     const std::string& theSelectedObjectAttrName,
802     const std::string& theSelectedPointAttrName)
803 {
804 #if defined DEBUG_SPLIT || defined DEBUG_TRIM_METHODS
805   std::cout << "getAISObject: " << theOpFeature->data()->name() << std::endl;
806 #endif
807
808   AISObjectPtr anAIS = thePrevious;
809
810   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
811   std::map<ObjectPtr, std::set<GeomShapePtr> > aCashedShapes;
812   std::map<ObjectPtr, GeomAlgoAPI_ShapeTools::PointToRefsMap> aObjectToPoints;
813   GeomShapePtr aPreviewShape = getSubShape(theOpFeature,
814       thePreviewObjectAttrName, thePreviewPointAttrName, aCashedShapes, aObjectToPoints);
815   if (aPreviewShape.get())
816     aShapes.push_back(aPreviewShape);
817   GeomShapePtr aSelectedShape = getSubShape(theOpFeature,
818       theSelectedObjectAttrName, theSelectedPointAttrName, aCashedShapes, aObjectToPoints);
819   if (aSelectedShape.get())
820     aShapes.push_back(aSelectedShape);
821
822   if (aShapes.empty())
823     return AISObjectPtr();
824
825   GeomShapePtr aBaseShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
826   if (!aBaseShape.get())
827     return AISObjectPtr();
828
829   if (aBaseShape.get()) {
830     if (!anAIS)
831       anAIS = AISObjectPtr(new GeomAPI_AISObject);
832     anAIS->createShape(aBaseShape);
833
834     std::vector<int> aColor;
835     aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color");
836     double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
837     int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
838     anAIS->setColor(aColor[0], aColor[1], aColor[2]);
839     // width when there is not base object should be extened in several points
840     // in order to see this preview over highlight
841     anAIS->setWidth(aWidth+4);
842     anAIS->setLineStyle(aLineStyle);
843   }
844   else
845     anAIS = AISObjectPtr();
846   return anAIS;
847 }