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