Salome HOME
#2027 Sketcher Trim feature - highlight should be cleared when the mouse is moved...
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Trim.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:    SketchPlugin_Trim.cpp
4 // Created: 22 Feb 2017
5 // Author:  Natalia ERMOLAEVA
6
7 #include "SketchPlugin_Trim.h"
8
9 #include <GeomAPI_Dir2d.h>
10 #include <GeomAPI_Edge.h>
11 #include <GeomAPI_Pnt2d.h>
12 #include <GeomAPI_XY.h>
13 #include <GeomDataAPI_Point2D.h>
14 #include <GeomAlgoAPI_ShapeTools.h>
15
16 #include <ModelAPI_AttributeReference.h>
17 #include <ModelAPI_AttributeString.h>
18 #include <ModelAPI_AttributeRefAttr.h>
19 #include <ModelAPI_Tools.h>
20 #include <ModelAPI_AttributeBoolean.h>
21
22 #include <ModelAPI_Validator.h>
23 #include <ModelAPI_Session.h>
24 #include <ModelAPI_AttributeDouble.h>
25
26 #include <SketchPlugin_Arc.h>
27 #include <SketchPlugin_ConstraintMiddle.h>
28 #include <SketchPlugin_Circle.h>
29 #include <SketchPlugin_ConstraintCoincidence.h>
30 #include <SketchPlugin_ConstraintEqual.h>
31 //#include <SketchPlugin_ConstraintParallel.h>
32 #include <SketchPlugin_ConstraintTangent.h>
33 #include <SketchPlugin_ConstraintLength.h>
34 #include <SketchPlugin_ConstraintMirror.h>
35 #include <SketchPlugin_ConstraintCollinear.h>
36 #include <SketchPlugin_Line.h>
37 #include <SketchPlugin_MultiRotation.h>
38 #include <SketchPlugin_MultiTranslation.h>
39 #include <SketchPlugin_Point.h>
40
41 #include <ModelAPI_Events.h>
42 #include <SketchPlugin_Line.h>
43 #include <SketchPlugin_Arc.h>
44 #include <SketchPlugin_Circle.h>
45
46 #include <ModelGeomAlgo_Point2D.h>
47 #include <Events_Loop.h>
48
49 #include <cmath>
50
51 #define DEBUG_TRIM
52 #ifdef DEBUG_TRIM
53 #include <iostream>
54 #endif
55
56 static const double PI = 3.141592653589793238463;
57
58 static const std::string OPERATION_HIGHLIGHT_COLOR() { return "128, 0, 0"; }
59 static const std::string OPERATION_REMOVE_FEATURE_COLOR() { return "255, 174, 201"; }
60
61 SketchPlugin_Trim::SketchPlugin_Trim()
62 {
63 }
64
65 void SketchPlugin_Trim::initAttributes()
66 {
67   data()->addAttribute(SketchPlugin_Trim::BASE_OBJECT(), ModelAPI_AttributeReference::typeId());
68   data()->addAttribute(ENTITY_POINT(), GeomDataAPI_Point2D::typeId());
69 }
70
71 void SketchPlugin_Trim::findShapePoints(std::shared_ptr<GeomAPI_Pnt>& aStartPoint,
72                                         std::shared_ptr<GeomAPI_Pnt>& aLastPoint)
73 {
74   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
75                                             data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
76   ObjectPtr aBaseObject = aBaseObjectAttr->value();
77
78   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
79                                                             data()->attribute(ENTITY_POINT()));
80   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
81   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
82                                                                anAttributePnt2d->y());
83
84   if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
85     fillObjectShapes(aBaseObject);
86
87   const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
88   if (!aShapes.empty()) {
89     std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
90     for (; anIt != aLast; anIt++) {
91       GeomShapePtr aBaseShape = *anIt;
92       std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
93       if (ModelGeomAlgo_Point2D::isPointOnEdge(aBaseShape, anAttributePnt, aProjectedPoint)) {
94
95         if (aBaseShape->shapeType() == GeomAPI_Shape::EDGE) {
96           std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aBaseShape));
97           aStartPoint = anEdge->lastPoint();
98           aLastPoint = anEdge->firstPoint();
99         }
100       }
101     }
102   }
103 #ifdef DEBUG_TRIM
104   std::cout << "<findShapePoints> => "
105             << "Start Point: ["
106             << aStartPoint->x() << ", " << aStartPoint->y() << ", " << aStartPoint->z() << "]"
107             << "Last Point: ["
108             << aLastPoint->x() << ", " << aLastPoint->y() << ", " << aLastPoint->z() << "]"
109             << std::endl;
110 #endif
111 }
112
113 std::shared_ptr<GeomAPI_Pnt2d> SketchPlugin_Trim::convertPoint(
114                                                    const std::shared_ptr<GeomAPI_Pnt>& thePoint)
115 {
116   std::shared_ptr<GeomAPI_Pnt2d> aPoint;
117
118   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
119                                             data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
120   ObjectPtr aBaseObject = aBaseObjectAttr->value();
121   if (myObjectToPoints.find(aBaseObject) == myObjectToPoints.end())
122     return aPoint;
123
124   bool aFound = false;
125   const PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject);
126   for (PointToRefsMap::const_iterator aPointIt = aRefsMap.begin();
127        aPointIt != aRefsMap.end() && !aFound; aPointIt++) {
128     if (aPointIt->first->isEqual(thePoint)) {
129       const std::pair<std::list<AttributePoint2DPtr >,
130                std::list<ObjectPtr > >& anInfo = aPointIt->second;
131       const std::list<AttributePoint2DPtr >& anAttributes = anInfo.first;
132       if (!anAttributes.empty()) {
133         aPoint = anAttributes.front()->pnt();
134         aFound = true;
135       }
136       else {
137         std::shared_ptr<GeomAPI_Pln> aPlane = sketch()->plane();
138         aPoint = thePoint->to2D(aPlane);
139         aFound = true;
140       }
141     }
142   }
143   if (!aFound) {
144     // returns an end of the shape to define direction of split if feature's attribute participates
145     std::shared_ptr<GeomAPI_Pln> aPlane = sketch()->plane();
146     aPoint = thePoint->to2D(aPlane);
147   }
148   return aPoint;
149 }
150
151 void SketchPlugin_Trim::execute()
152 {
153 #ifdef DEBUG_TRIM
154   std::cout << "SketchPlugin_Trim::execute" << std::endl;
155 #endif
156
157   SketchPlugin_Sketch* aSketch = sketch();
158   if (!aSketch)
159     return;
160
161   // Check the base objects are initialized.
162   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
163                                             data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
164   if(!aBaseObjectAttr->isInitialized()) {
165     setError("Error: Base object is not initialized.");
166     return;
167   }
168   ObjectPtr aBaseObject = aBaseObjectAttr->value();
169   if (!aBaseObject.get())
170     return;
171   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
172
173   /// points of trim
174   std::shared_ptr<GeomAPI_Pnt> aStartShapePoint, aLastShapePoint;
175   findShapePoints(aStartShapePoint, aLastShapePoint);
176   std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint2d = convertPoint(aStartShapePoint);
177
178   std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint2d = convertPoint(aLastShapePoint);
179
180   std::set<FeaturePtr> aFeaturesToDelete;
181   getConstraints(aFeaturesToDelete);
182
183   std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
184   std::list<AttributePtr> aRefsToFeature;
185   getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
186
187
188   // coincidence to result points
189   // find coincidences to the base object, it should be used when attribute is found
190   // in myObjectToPoints
191   std::map<AttributePtr, FeaturePtr> aCoincidencesToBaseFeature;
192   getCoincidencesToObject(aBaseObject, aCoincidencesToBaseFeature);
193
194   std::set<AttributePoint2DPtr> aFurtherCoincidences;
195   std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
196   const std::string& aKind = aBaseFeature->getKind();
197   FeaturePtr aReplacingFeature;
198   if (aKind == SketchPlugin_Circle::ID()) {
199     aReplacingFeature = trimCircle(aStartShapePoint2d, aLastShapePoint2d,
200                aFurtherCoincidences, aModifiedAttributes);
201
202     aFeaturesToDelete.insert(aBaseFeature);
203     // as circle is removed, temporary fill this attribute
204     aBaseObjectAttr->setObject(ResultPtr());
205   }
206   else if (aKind == SketchPlugin_Line::ID()) {
207     trimLine(aStartShapePoint2d, aLastShapePoint2d,
208              aFurtherCoincidences, aModifiedAttributes);
209   }
210   else if (aKind == SketchPlugin_Arc::ID()) {
211     trimArc(aStartShapePoint2d, aLastShapePoint2d,
212             aFurtherCoincidences, aModifiedAttributes);
213   }
214
215   //
216   const PointToRefsMap& aRefsMap = myObjectToPoints.at(aBaseObject);
217   std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
218                                                 aLast = aFurtherCoincidences.end();
219   for (; anIt != aLast; anIt++) {
220     AttributePoint2DPtr aPointAttribute = (*anIt);
221     std::shared_ptr<GeomAPI_Pnt2d> aPoint2d = aPointAttribute->pnt();
222
223     std::shared_ptr<GeomAPI_Pnt> aPoint;
224     if (aStartShapePoint2d.get() && aPoint2d->isEqual(aStartShapePoint2d))
225       aPoint = aStartShapePoint;
226     else if (aLastShapePoint2d.get() && aPoint2d->isEqual(aLastShapePoint2d))
227       aPoint = aLastShapePoint;
228
229     if (!aPoint.get())
230       continue;
231
232     std::pair<std::list<AttributePoint2DPtr >, std::list<ObjectPtr > > anInfo;
233     for (PointToRefsMap::const_iterator aRefIt = aRefsMap.begin(); aRefIt != aRefsMap.end();
234          aRefIt++)
235     {
236       if (aRefIt->first->isEqual(aPoint)) {
237         anInfo = aRefIt->second;
238         break;
239       }
240     }
241     const std::list<AttributePoint2DPtr >& anAttributes = anInfo.first;
242     for (std::list<AttributePoint2DPtr>::const_iterator anAttrIt = anAttributes.begin();
243           anAttrIt != anAttributes.end(); anAttrIt++) {
244       AttributePtr anAttribute = *anAttrIt;
245       if (aCoincidencesToBaseFeature.find(anAttribute) != aCoincidencesToBaseFeature.end())
246       {
247         FeaturePtr anAttrFeature = aCoincidencesToBaseFeature.at(anAttribute);
248         AttributePtr anOtherAttribute;
249         if (std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
250            (anAttrFeature->attribute(SketchPlugin_Constraint::ENTITY_A()))->attr() == anAttribute)
251           anOtherAttribute = anAttrFeature->attribute(SketchPlugin_Constraint::ENTITY_B());
252         else if (std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
253           (anAttrFeature->attribute(SketchPlugin_Constraint::ENTITY_B()))->attr() == anAttribute)
254           anOtherAttribute = anAttrFeature->attribute(SketchPlugin_Constraint::ENTITY_A());
255         else
256           continue;
257         AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
258                                        (anOtherAttribute);
259         if (aRefAttr.get())
260           aRefAttr->setAttr(aPointAttribute);
261       }
262     }
263
264     const std::list<ObjectPtr>& anObjects = anInfo.second;
265     for (std::list<ObjectPtr>::const_iterator anObjectIt = anObjects.begin();
266       anObjectIt != anObjects.end(); anObjectIt++) {
267       createConstraintToObject(SketchPlugin_ConstraintCoincidence::ID(), aPointAttribute,
268                                *anObjectIt);
269     }
270   }
271
272   // move constraints from base feature to replacing feature: ignore coincidences to feature
273   // if attributes of coincidence participated in split
274   if (aReplacingFeature.get()) {
275     ResultPtr aReplacingResult = getFeatureResult(aReplacingFeature);
276     std::list<AttributePtr>::const_iterator anIt = aRefsToFeature.begin(),
277                                             aLast = aRefsToFeature.end();
278     for (; anIt != aLast; anIt++) {
279       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
280       if (!aRefAttr.get())
281         continue;
282       FeaturePtr anAttrFeature = ModelAPI_Feature::feature(aRefAttr->owner());
283       if (anAttrFeature.get() &&
284           anAttrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID())
285       {
286         if (anAttrFeature->attribute(SketchPlugin_Constraint::ENTITY_A()) == aRefAttr ||
287             anAttrFeature->attribute(SketchPlugin_Constraint::ENTITY_B()) == aRefAttr)
288           continue;
289       }
290       aRefAttr->setObject(aReplacingResult);
291     }
292   }
293
294   // Wait all constraints being created, then send update events
295   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
296   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
297   if (isUpdateFlushed)
298     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
299
300   updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes, aFeaturesToDelete);
301
302   // delete constraints
303 #ifdef DEBUG_TRIM
304   std::cout << "remove features and references:" << std::endl;
305   std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
306                                        aDLast = aFeaturesToDelete.end();
307   for (; aDIt != aDLast; aDIt++) {
308     //std::cout << getFeatureInfo(*aDIt, false) << std::endl;
309     //std::cout << std::endl;
310   }
311 #endif
312   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
313   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
314
315   // Send events to update the sub-features by the solver.
316   if(isUpdateFlushed) {
317     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
318   }
319
320 #ifdef DEBUG_TRIM
321   std::cout << "SketchPlugin_Trim::done" << std::endl;
322 #endif
323 }
324
325 bool SketchPlugin_Trim::isMacro() const
326 {
327   return true;
328 }
329
330 AISObjectPtr SketchPlugin_Trim::getAISObject(AISObjectPtr thePrevious)
331 {
332   AISObjectPtr anAIS = thePrevious;
333   // feature for trim
334   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
335                                            data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
336   ObjectPtr aBaseObject = aBaseObjectAttr->value();
337   if (!aBaseObject.get())
338     return AISObjectPtr();
339   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
340
341   // point on feature
342   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
343                                            data()->attribute(ENTITY_POINT()));
344   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
345   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
346                                                                anAttributePnt2d->y());
347
348   if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
349     fillObjectShapes(aBaseObject);
350
351   GeomShapePtr aBaseShape;
352
353   const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
354   if (!aShapes.empty()) {
355     std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
356     for (; anIt != aLast; anIt++) {
357       GeomShapePtr aShape = *anIt;
358       std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
359       if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, anAttributePnt, aProjectedPoint))
360         aBaseShape = aShape;
361     }
362   }
363
364   if (aBaseShape.get()) {
365     if (!anAIS)
366       anAIS = AISObjectPtr(new GeomAPI_AISObject);
367     anAIS->createShape(aBaseShape);
368
369     std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
370             aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
371
372     bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
373     std::vector<int> aColor;
374     aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color",
375                                         OPERATION_REMOVE_FEATURE_COLOR());
376     double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
377     int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
378     if (isConstruction) {
379       aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
380       aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY();
381     }
382     anAIS->setColor(aColor[0], aColor[1], aColor[2]);
383     // width is extened in several points in order to see this preview over highlight
384     anAIS->setWidth(aWidth + 2);
385     anAIS->setLineStyle(aLineStyle);
386   }
387   else
388     anAIS = AISObjectPtr();
389
390   return anAIS;
391 }
392
393 void SketchPlugin_Trim::getFeaturePoints(const FeaturePtr& theFeature,
394                                          AttributePoint2DPtr& theStartPointAttr,
395                                          AttributePoint2DPtr& theEndPointAttr)
396 {
397   std::string aFeatureKind = theFeature->getKind();
398   std::string aStartAttributeName, anEndAttributeName;
399   if (aFeatureKind == SketchPlugin_Line::ID()) {
400     aStartAttributeName = SketchPlugin_Line::START_ID();
401     anEndAttributeName = SketchPlugin_Line::END_ID();
402   }
403   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
404     aStartAttributeName = SketchPlugin_Arc::START_ID();
405     anEndAttributeName = SketchPlugin_Arc::END_ID();
406   }
407   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
408     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
409                                          theFeature->attribute(aStartAttributeName));
410     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
411                                          theFeature->attribute(anEndAttributeName));
412   }
413 }
414
415 void SketchPlugin_Trim::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete)
416 {
417   std::shared_ptr<ModelAPI_Data> aData = data();
418
419   // Check the base objects are initialized.
420   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
421                                             aData->attribute(SketchPlugin_Trim::BASE_OBJECT()));
422   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
423   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
424
425   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
426   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
427   aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
428
429   std::set<AttributePtr>::const_iterator aIt;
430   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
431     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
432     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
433     std::string aRefFeatureKind = aRefFeature->getKind();
434     if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
435         aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
436         aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
437         aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
438       theFeaturesToDelete.insert(aRefFeature);
439   }
440 }
441
442 void SketchPlugin_Trim::getRefAttributes(const FeaturePtr& theFeature,
443                                     std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
444                                     std::list<AttributePtr>& theRefsToFeature)
445 {
446   theRefs.clear();
447
448   std::list<AttributePtr> aPointAttributes =
449     theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
450   std::set<AttributePtr> aPointAttributesSet;
451
452   std::list<AttributePtr>::const_iterator aPIt =
453     aPointAttributes.begin(), aPLast = aPointAttributes.end();
454   for (; aPIt != aPLast; aPIt++)
455     aPointAttributesSet.insert(*aPIt);
456
457   std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
458   std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
459   aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
460
461   std::set<AttributePtr>::const_iterator aIt;
462   for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
463     AttributePtr anAttr = (*aIt);
464     FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
465     if (anAttrFeature.get() != this &&
466         anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
467       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
468       if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
469         AttributePtr anAttrInRef = aRefAttr->attr();
470         if (anAttrInRef.get() &&
471             aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
472           if (theRefs.find(anAttrInRef) != theRefs.end())
473             theRefs[anAttrInRef].push_back(aRefAttr);
474           else {
475             std::list<AttributePtr> anAttrList;
476             anAttrList.push_back(aRefAttr);
477             theRefs[anAttrInRef] = anAttrList;
478           }
479         }
480       }
481       else { /// find attributes referenced to feature itself
482         theRefsToFeature.push_back(anAttr);
483       }
484     }
485   }
486 }
487
488 void SketchPlugin_Trim::getCoincidencesToObject(const ObjectPtr& theObject,
489                    std::map<AttributePtr, FeaturePtr>& theCoincidencesToBaseFeature)
490 {
491   const std::set<AttributePtr>& aRefsList = theObject->data()->refsToMe();
492   std::set<AttributePtr>::const_iterator aIt;
493   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
494     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
495     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
496     if (aRefFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
497       continue;
498     AttributePtr anAttribute;
499     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
500                                   (aRefFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
501     if (aRefAttr->isObject() && aRefAttr->object() == theObject)
502     {
503       anAttribute = aRefFeature->attribute(SketchPlugin_Constraint::ENTITY_B());
504     }
505     else {
506       aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
507                                     (aRefFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
508       if (aRefAttr->isObject() && aRefAttr->object() == theObject)
509       {
510         anAttribute = aRefFeature->attribute(SketchPlugin_Constraint::ENTITY_A());
511       }
512       if (anAttribute.get())
513       {
514         aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
515                                     (anAttribute);
516         anAttribute = aRefAttr->attr();
517         if (anAttribute.get())
518           theCoincidencesToBaseFeature[anAttribute] = aRefFeature;
519       }
520     }
521   }
522 }
523
524 void SketchPlugin_Trim::updateRefAttConstraints(
525                     const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
526                     const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes,
527                     std::set<FeaturePtr>& theFeaturesToDelete)
528 {
529 #ifdef DEBUG_TRIM
530   std::cout << "SketchPlugin_Trim::updateRefAttConstraints" << std::endl;
531 #endif
532
533   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
534     anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
535   for (; anIt != aLast; anIt++) {
536     AttributePtr anAttribute = anIt->first;
537
538     /// not found in references
539     if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
540       continue;
541     std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
542     std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
543                                             aRLast = aRefAttributes.end();
544
545     AttributePtr aNewAttribute = anIt->second;
546     for (; aRefIt != aRLast; aRefIt++) {
547       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
548       if (aRefAttr.get()) {
549         if (aNewAttribute.get())
550           aRefAttr->setAttr(aNewAttribute);
551         else
552           theFeaturesToDelete.insert(ModelAPI_Feature::feature(aRefAttr->owner()));
553 #ifdef DEBUG_TRIM
554         //FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
555         //std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
556 #endif
557       }
558     }
559   }
560 }
561
562 void SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
563                                  const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
564                                  std::set<AttributePoint2DPtr>& thePoints,
565                   std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
566 {
567   // Check the base objects are initialized.
568   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
569                                             data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
570   ObjectPtr aBaseObject = aBaseObjectAttr->value();
571   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
572
573   /// points of trim
574   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
575   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
576
577   std::shared_ptr<GeomAPI_Pnt2d> aStartFeaturePoint = aStartPointAttrOfBase->pnt();
578   std::shared_ptr<GeomAPI_Pnt2d> aLastFeaturePoint = anEndPointAttrOfBase->pnt();
579
580   std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
581   std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
582   arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
583                       aStartShapePoint, aLastShapePoint);
584 #ifdef DEBUG_TRIM
585   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
586   if (aStartShapePoint.get())
587     std::cout << "Start point: [" << aStartShapePoint->x() << ", " <<
588                                        aStartShapePoint->y() << "]" << std::endl;
589   std::cout << "1st point:   [" << aStartFeaturePoint->x() << ", " <<
590                                    aStartFeaturePoint->y() << "]" << std::endl;
591   if (aLastShapePoint.get())
592     std::cout << "2st point:   [" << aLastShapePoint->x() << ", " <<
593                                      aLastShapePoint->y() << "]" << std::endl;
594   std::cout << "End point:   [" << aLastFeaturePoint->x() << ", " <<
595                                    aLastFeaturePoint->y() << "]" << std::endl;
596 #endif
597
598   bool isStartPoint = !aStartShapePoint.get() || aStartFeaturePoint->isEqual(aStartShapePoint);
599   bool isLastPoint = !aLastShapePoint.get() || aLastFeaturePoint->isEqual(aLastShapePoint);
600   if (isStartPoint || isLastPoint) {
601     // result is one line: changed existing line
602     std::string aModifiedAttribute = isStartPoint ? SketchPlugin_Line::START_ID()
603                                                   : SketchPlugin_Line::END_ID();
604     std::shared_ptr<GeomAPI_Pnt2d> aPoint;
605     if (aStartShapePoint.get() && aLastShapePoint.get())
606       aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
607     else
608       aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
609
610     fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
611     theModifiedAttributes.insert(
612       std::make_pair(aBaseFeature->attribute(aModifiedAttribute), AttributePtr()));
613
614     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
615                                (aBaseFeature->attribute(aModifiedAttribute)));
616   }
617   else {
618     // result is two lines: start line point - start shape point, last shape point - last line point
619     // create second line
620     FeaturePtr anNewFeature = createLineFeature(aBaseFeature, aLastShapePoint, aLastFeaturePoint);
621     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
622                                (anNewFeature->attribute(SketchPlugin_Line::START_ID())));
623
624     std::string aModifiedAttribute = SketchPlugin_Line::END_ID();
625     theModifiedAttributes.insert(
626       std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
627                                    anNewFeature->attribute(SketchPlugin_Line::END_ID())));
628
629     // modify base arc
630     fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
631
632     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
633                                (aBaseFeature->attribute(aModifiedAttribute)));
634
635     // Collinear constraint for lines
636     createConstraintForObjects(SketchPlugin_ConstraintCollinear::ID(),
637                                getFeatureResult(aBaseFeature),
638                                getFeatureResult(anNewFeature));
639
640   }
641 }
642
643 void SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
644                                 const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
645                                 std::set<AttributePoint2DPtr>& thePoints,
646                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
647 {
648   // Check the base objects are initialized.
649   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
650                                             data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
651   ObjectPtr aBaseObject = aBaseObjectAttr->value();
652   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
653
654   /// points of trim
655   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
656   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
657
658   std::shared_ptr<GeomAPI_Pnt2d> aStartArcPoint = aStartPointAttrOfBase->pnt();
659   std::shared_ptr<GeomAPI_Pnt2d> aLastArcPoint = anEndPointAttrOfBase->pnt();
660
661   std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
662   std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
663   arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
664                      aStartShapePoint, aLastShapePoint);
665 #ifdef DEBUG_TRIM
666   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
667   if (aStartShapePoint.get())
668     std::cout << "Start point: [" << aStartShapePoint->x() << ", " <<
669                                        aStartShapePoint->y() << "]" << std::endl;
670   std::cout << "1st point:   [" << aStartArcPoint->x() << ", " <<
671                                    aStartArcPoint->y() << "]" << std::endl;
672   if (aLastShapePoint.get())
673     std::cout << "2st point:   [" << aLastShapePoint->x() << ", " <<
674                                      aLastShapePoint->y() << "]" << std::endl;
675   std::cout << "End point:   [" << aLastArcPoint->x() << ", " <<
676                                    aLastArcPoint->y() << "]" << std::endl;
677 #endif
678
679   bool isStartPoint = !aStartShapePoint.get() || aStartArcPoint->isEqual(aStartShapePoint);
680   bool isLastPoint = !aLastShapePoint.get() || aLastArcPoint->isEqual(aLastShapePoint);
681   if (isStartPoint || isLastPoint) {
682     // result is one arc: changed existing arc
683     std::string aModifiedAttribute = isStartPoint ? SketchPlugin_Arc::START_ID()
684                                                   : SketchPlugin_Arc::END_ID();
685     std::shared_ptr<GeomAPI_Pnt2d> aPoint;
686     if (aStartShapePoint.get() && aLastShapePoint.get())
687       aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
688     else
689       aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
690
691     fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
692     theModifiedAttributes.insert(
693       std::make_pair(aBaseFeature->attribute(aModifiedAttribute), AttributePtr()));
694
695     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
696                                (aBaseFeature->attribute(aModifiedAttribute)));
697   }
698   else {
699     // result is two arcs: start arc point - start shape point, last shape point - last arc point
700     // create second arc
701     FeaturePtr anArcFeature = createArcFeature(aBaseFeature, aLastShapePoint, aLastArcPoint);
702     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
703                                (anArcFeature->attribute(SketchPlugin_Arc::START_ID())));
704
705     std::string aModifiedAttribute = SketchPlugin_Arc::END_ID();
706     theModifiedAttributes.insert(
707       std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
708                                    anArcFeature->attribute(SketchPlugin_Arc::END_ID())));
709
710     // modify base arc
711     fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
712
713     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
714                                (aBaseFeature->attribute(aModifiedAttribute)));
715
716     // equal Radius constraint for arcs
717     createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
718                                getFeatureResult(aBaseFeature),
719                                getFeatureResult(anArcFeature));
720     // coincident centers constraint
721     createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
722                      aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
723                      anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
724   }
725 }
726
727 FeaturePtr SketchPlugin_Trim::trimCircle(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
728                                    const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
729                                    std::set<AttributePoint2DPtr>& thePoints,
730                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
731 {
732   // Check the base objects are initialized.
733   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
734                                             data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
735   ObjectPtr aBaseObject = aBaseObjectAttr->value();
736   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
737
738   /// points of trim
739   //AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
740   //getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
741
742   /// trim feature
743   FeaturePtr anArcFeature = createArcFeature(aBaseFeature, theStartShapePoint, theLastShapePoint);
744
745   theModifiedAttributes.insert(
746     std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
747                    anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID())));
748
749   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
750                              (anArcFeature->attribute(SketchPlugin_Arc::START_ID())));
751   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
752                              (anArcFeature->attribute(SketchPlugin_Arc::END_ID())));
753
754   return anArcFeature;
755 }
756
757 void SketchPlugin_Trim::arrangePointsOnLine(const AttributePoint2DPtr& theStartPointAttr,
758                                             const AttributePoint2DPtr& theEndPointAttr,
759                                             std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
760                                             std::shared_ptr<GeomAPI_Pnt2d>& theLastPoint) const
761 {
762   if (!theFirstPoint.get() || !theLastPoint.get())
763     return;
764
765   // if first point is closer to last point, swap first and last values
766   if (theStartPointAttr->pnt()->distance(theFirstPoint) >
767       theStartPointAttr->pnt()->distance(theLastPoint)) {
768     std::shared_ptr<GeomAPI_Pnt2d> aTmpPoint = theFirstPoint;
769     theFirstPoint = theLastPoint;
770     theLastPoint = aTmpPoint;
771   }
772 }
773
774 void SketchPlugin_Trim::arrangePointsOnArc(const FeaturePtr& theArc,
775                                   const AttributePoint2DPtr& theStartPointAttr,
776                                   const AttributePoint2DPtr& theEndPointAttr,
777                                   std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
778                                   std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint) const
779 {
780   if (!theFirstPoint.get() || !theSecondPoint.get())
781     return;
782
783   static const double anAngleTol = 1.e-12;
784
785   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
786       theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
787   bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
788
789   // collect directions to each point
790   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
791       new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
792   std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
793       new GeomAPI_Dir2d(theFirstPoint->xy()->decreased(aCenter->xy())));
794   std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
795       new GeomAPI_Dir2d(theSecondPoint->xy()->decreased(aCenter->xy())));
796
797   // sort points by their angular values
798   double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
799   double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
800   double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
801   if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
802     aFirstPtAngle += aPeriod;
803   if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
804     aSecondPtAngle += aPeriod;
805
806   if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
807     std::shared_ptr<GeomAPI_Pnt2d> aTmpPoint = theFirstPoint;
808     theFirstPoint = theSecondPoint;
809     theSecondPoint = aTmpPoint;
810   }
811 }
812
813 void SketchPlugin_Trim::fillPointAttribute(const AttributePtr& theModifiedAttribute,
814                                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
815 {
816   std::string anAttributeType = theModifiedAttribute->attributeType();
817   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
818     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
819                                               theModifiedAttribute);
820     aModifiedAttribute->setValue(thePoint);
821
822 #ifdef DEBUG_TRIM
823     std::cout << "<fillPointAttribute> => Pnt2d - [" << thePoint->x() << ", "
824               << thePoint->y() << "]" << std::endl;
825 #endif
826   }
827 }
828
829
830 void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute,
831                                       const AttributePtr& theSourceAttribute)
832 {
833   std::string anAttributeType = theModifiedAttribute->attributeType();
834   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
835     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
836                                               theModifiedAttribute);
837     AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
838                                               theSourceAttribute);
839
840     if (aModifiedAttribute.get() && aSourceAttribute.get())
841       aModifiedAttribute->setValue(aSourceAttribute->pnt());
842   }
843   else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
844     AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
845                                               theModifiedAttribute);
846     AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
847                                               theSourceAttribute);
848
849     if (aModifiedAttribute.get() && aSourceAttribute.get())
850       aModifiedAttribute->setValue(aSourceAttribute->value());
851   }
852   else if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
853     AttributeRefAttrPtr aRefAttributeToFill = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
854                                                                              theModifiedAttribute);
855     AttributeRefAttrPtr aSourceRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
856                                          theSourceAttribute);
857     if (!aSourceRefAttr.get())
858       aRefAttributeToFill->setAttr(theSourceAttribute);
859     else {
860       if (aSourceRefAttr->isObject())
861         aRefAttributeToFill->setObject(aSourceRefAttr->object());
862       else
863         aRefAttributeToFill->setAttr(aSourceRefAttr->attr());
864     }
865   }
866 }
867
868 FeaturePtr SketchPlugin_Trim::createLineFeature(const FeaturePtr& theBaseFeature,
869                                         const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
870                                         const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
871 {
872   FeaturePtr aFeature;
873   SketchPlugin_Sketch* aSketch = sketch();
874   if (!aSketch || !theBaseFeature.get())
875     return aFeature;
876
877   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
878
879   fillPointAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPoint);
880   fillPointAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPoint);
881
882   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
883                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
884
885   aFeature->execute(); // to obtain result
886
887   return aFeature;
888 }
889
890
891 FeaturePtr SketchPlugin_Trim::createArcFeature(const FeaturePtr& theBaseFeature,
892                                                const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
893                                                const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
894 {
895   FeaturePtr aFeature;
896   SketchPlugin_Sketch* aSketch = sketch();
897   if (!aSketch || !theBaseFeature.get())
898     return aFeature;
899
900   std::string aCenterAttributeId;
901   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
902     aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
903   else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
904     aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
905
906   if (aCenterAttributeId.empty())
907     return aFeature;
908
909   aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
910   // update fillet arc: make the arc correct for sure, so, it is not needed to process
911   // the "attribute updated"
912   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
913   bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
914
915   aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
916                 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
917
918   fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
919                 theBaseFeature->attribute(aCenterAttributeId));
920   fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPoint);
921   fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPoint);
922
923   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
924                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
925
926   /// fill referersed state of created arc as it is on the base arc
927   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
928     bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
929     aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
930   }
931   aFeature->execute(); // to obtain result
932   aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
933
934   return aFeature;
935 }
936
937 FeaturePtr SketchPlugin_Trim::createConstraint(const std::string& theConstraintId,
938                                                const AttributePtr& theFirstAttribute,
939                                                const AttributePtr& theSecondAttribute)
940 {
941   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
942   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
943                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
944   aRefAttr->setAttr(theFirstAttribute);
945
946   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
947                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
948   aRefAttr->setAttr(theSecondAttribute);
949
950 #ifdef DEBUG_TRIM
951   std::cout << "<createConstraint to attribute> :"
952             << "first attribute - " << theFirstAttribute->id()
953             << "second attribute - " << theSecondAttribute->id()
954             << std::endl;
955 #endif
956
957   return aConstraint;
958 }
959
960 FeaturePtr SketchPlugin_Trim::createConstraintToObject(const std::string& theConstraintId,
961                                                const AttributePtr& theFirstAttribute,
962                                                const ObjectPtr& theSecondObject)
963 {
964   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
965   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
966                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
967   aRefAttr->setAttr(theFirstAttribute);
968
969   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
970                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
971   aRefAttr->setObject(theSecondObject);
972
973 #ifdef DEBUG_TRIM
974   std::cout << "<createConstraint to attribute> :"
975             << "first attribute - " << theFirstAttribute->id()
976             << "second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
977             << std::endl;
978 #endif
979
980   return aConstraint;
981 }
982
983 FeaturePtr SketchPlugin_Trim::createConstraintForObjects(
984                                                     const std::string& theConstraintId,
985                                                     const ObjectPtr& theFirstObject,
986                                                     const ObjectPtr& theSecondObject)
987 {
988   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
989   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
990                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
991   aRefAttr->setObject(theFirstObject);
992
993   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
994                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
995   aRefAttr->setObject(theSecondObject);
996
997   return aConstraint;
998 }
999
1000 std::shared_ptr<ModelAPI_Result> SketchPlugin_Trim::getFeatureResult(
1001                                     const std::shared_ptr<ModelAPI_Feature>& theFeature)
1002 {
1003   std::shared_ptr<ModelAPI_Result> aResult;
1004
1005   std::string aFeatureKind = theFeature->getKind();
1006   if (aFeatureKind == SketchPlugin_Line::ID())
1007     aResult = theFeature->firstResult();
1008   else if (aFeatureKind == SketchPlugin_Arc::ID())
1009     aResult = theFeature->lastResult();
1010   else if (aFeatureKind == SketchPlugin_Circle::ID())
1011     aResult = theFeature->lastResult();
1012
1013   return aResult;
1014 }
1015
1016 //********************************************************************
1017 bool SketchPlugin_Trim::useGraphicIntersection() const
1018 {
1019   return true;
1020 }
1021
1022 //********************************************************************
1023 void SketchPlugin_Trim::fillObjectShapes(const ObjectPtr& theObject)
1024 {
1025   PointToRefsMap aPointsInfo;
1026
1027   std::set<std::shared_ptr<GeomAPI_Shape> > aShapes;
1028   std::map<std::shared_ptr<GeomAPI_Pnt>,
1029                            std::list< AttributePoint2DPtr > > aPointToAttributes;
1030   std::map<std::shared_ptr<GeomAPI_Pnt>,
1031                            std::list< ObjectPtr > > aPointToObjects;
1032
1033   std::set<AttributePoint2DPtr > aRefAttributes;
1034   // current feature
1035   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1036   std::set<ResultPtr> anEdgeShapes;
1037   // edges on feature
1038   ModelAPI_Tools::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
1039   if (!anEdgeShapes.empty()) {
1040     GeomShapePtr aFeatureShape = (*anEdgeShapes.begin())->shape();
1041
1042     // coincidences to the feature
1043     ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
1044                          aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
1045     // layed on feature coincidences to divide it on several shapes
1046     SketchPlugin_Sketch* aSketch = sketch();
1047     std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
1048     std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1049         aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
1050     std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1051         aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
1052     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1053         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
1054     std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
1055
1056     ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
1057                                                 aX->dir(), aY, aPointsInfo);
1058
1059     // intersection points
1060     if (useGraphicIntersection()) {
1061       std::list<FeaturePtr> aFeatures;
1062       for (int i = 0; i < aSketch->numberOfSubs(); i++) {
1063         FeaturePtr aFeature = aSketch->subFeature(i);
1064         if (aFeature.get())
1065           aFeatures.push_back(aFeature);
1066       }
1067       ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPointsInfo);
1068     }
1069     GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPointsInfo, aShapes);
1070   }
1071   myObjectToPoints[theObject] = aPointsInfo;
1072   myCashedShapes[theObject] = aShapes;
1073 }
1074
1075 //********************************************************************
1076 void SketchPlugin_Trim::attributeChanged(const std::string& theID)
1077 {
1078   //data()->addAttribute(SketchPlugin_Trim::BASE_OBJECT(), ModelAPI_AttributeReference::typeId());
1079   if (theID == SketchPlugin_Trim::BASE_OBJECT()) {
1080     bool isValidAttribute = false;
1081     // feature for trim
1082     AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1083                                              data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
1084     ObjectPtr aBaseObject = aBaseObjectAttr->value();
1085     if (aBaseObject.get()) {
1086       FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1087       // point on feature
1088       AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1089                                                data()->attribute(ENTITY_POINT()));
1090       std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
1091       std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
1092                                                                    anAttributePnt2d->y());
1093
1094       if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
1095         fillObjectShapes(aBaseObject);
1096
1097       const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
1098       isValidAttribute = !aShapes.empty();
1099
1100       if (!isValidAttribute) {
1101         bool aWasBlocked = data()->blockSendAttributeUpdated(true);
1102         aBaseObjectAttr->setValue(ObjectPtr());
1103         data()->blockSendAttributeUpdated(aWasBlocked);
1104       }
1105     }
1106   }
1107 }