Salome HOME
Fix coding style (line length <= 100)
[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 =
338           std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
339       if (aRefAttr.get())
340         aRefAttr->setObject(aReplacingResult);
341       else {
342         AttributeReferencePtr aReferenceAttr =
343                              std::dynamic_pointer_cast<ModelAPI_AttributeReference>(anAttribute);
344         if (aReferenceAttr.get())
345           aReferenceAttr->setObject(aReplacingResult);
346       }
347     }
348   }
349
350   // Wait all constraints being created, then send update events
351   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
352   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
353   if (isUpdateFlushed)
354     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
355
356   updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes, aFeaturesToDelete);
357
358   // delete constraints
359 #ifdef DEBUG_TRIM
360   std::cout << "remove features and references:" << std::endl;
361   std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
362                                        aDLast = aFeaturesToDelete.end();
363   for (; aDIt != aDLast; aDIt++) {
364     //std::cout << getFeatureInfo(*aDIt, false) << std::endl;
365     //std::cout << std::endl;
366   }
367 #endif
368   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
369   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
370
371   // Send events to update the sub-features by the solver.
372   if(isUpdateFlushed) {
373     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
374   }
375
376 #ifdef DEBUG_TRIM
377   std::cout << "SketchPlugin_Trim::done" << std::endl;
378 #endif
379 }
380
381 bool SketchPlugin_Trim::setCoincidenceToAttribute(const AttributePtr& theAttribute,
382                                 const std::set<AttributePoint2DPtr>& theFurtherCoincidences)
383 {
384   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
385   if (aFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
386     return false;
387
388   AttributePoint2DPtr aRefPointAttr = SketchPlugin_ConstraintCoincidence::getPoint(aFeature);
389   if (!aRefPointAttr.get())
390     return false;
391   std::shared_ptr<GeomAPI_Pnt2d> aRefPnt2d = aRefPointAttr->pnt();
392
393   std::set<AttributePoint2DPtr>::const_iterator anIt = theFurtherCoincidences.begin(),
394                                                 aLast = theFurtherCoincidences.end();
395   bool aFoundPoint = false;
396   for (; anIt != aLast && !aFoundPoint; anIt++) {
397     AttributePoint2DPtr aPointAttribute = (*anIt);
398     std::shared_ptr<GeomAPI_Pnt2d> aPoint2d = aPointAttribute->pnt();
399     if (aPoint2d->isEqual(aRefPnt2d)) {
400       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
401                                                                            theAttribute);
402       /*if (theAttribute->id() == SketchPlugin_ConstraintCoincidence::ENTITY_A())
403         aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
404                   aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_B()));
405       else if (theAttribute->id() == SketchPlugin_ConstraintCoincidence::ENTITY_B())
406         aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
407                   aFeature->attribute(SketchPlugin_ConstraintCoincidence::ENTITY_A()));*/
408       if (aRefAttr.get()) {
409         aRefAttr->setAttr(aPointAttribute);
410         aFoundPoint = true;
411       }
412     }
413   }
414   /*AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
415   if (!aRefAttr.get())
416     return false;
417
418   if (aRefAttr.get())
419     aRefAttr->setObject(aReplacingResult);//continue;
420   else {
421   //AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
422     AttributeReferencePtr aReferenceAttr =
423                           std::dynamic_pointer_cast<ModelAPI_AttributeReference>(anAttribute);
424   }*/
425
426   return aFoundPoint;
427 }
428
429 bool SketchPlugin_Trim::isMacro() const
430 {
431   return true;
432 }
433
434 AISObjectPtr SketchPlugin_Trim::getAISObject(AISObjectPtr thePrevious)
435 {
436   AISObjectPtr anAIS = thePrevious;
437
438   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
439   GeomShapePtr aPreviewShape = getSubShape(PREVIEW_OBJECT(), PREVIEW_POINT());
440   if (aPreviewShape.get())
441     aShapes.push_back(aPreviewShape);
442   GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
443   if (aSelectedShape.get())
444     aShapes.push_back(aSelectedShape);
445
446   if (aShapes.empty())
447     return AISObjectPtr();
448
449   GeomShapePtr aBaseShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
450   if (!aBaseShape.get())
451     return AISObjectPtr();
452
453   if (aBaseShape.get()) {
454     if (!anAIS)
455       anAIS = AISObjectPtr(new GeomAPI_AISObject);
456     anAIS->createShape(aBaseShape);
457
458     std::vector<int> aColor;
459     aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color");
460     double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
461     int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
462     anAIS->setColor(aColor[0], aColor[1], aColor[2]);
463     // width when there is not base object should be extened in several points
464     // in order to see this preview over highlight
465     anAIS->setWidth(aWidth+4);
466     anAIS->setLineStyle(aLineStyle);
467   }
468   else
469     anAIS = AISObjectPtr();
470
471   return anAIS;
472 }
473
474 GeomShapePtr SketchPlugin_Trim::getSubShape(const std::string& theObjectAttributeId,
475                                             const std::string& thePointAttributeId)
476 {
477   GeomShapePtr aBaseShape;
478
479   AttributeReferencePtr anObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
480                                                        data()->attribute(theObjectAttributeId));
481   ObjectPtr aBaseObject = anObjectAttr->value();
482   if (!aBaseObject.get())
483     return aBaseShape;
484
485   // point on feature
486   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
487                                            data()->attribute(thePointAttributeId));
488   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
489   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
490                                                                anAttributePnt2d->y());
491
492   if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
493     fillObjectShapes(aBaseObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
494
495   const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
496   if (!aShapes.empty()) {
497     std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
498     for (; anIt != aLast; anIt++) {
499       GeomShapePtr aShape = *anIt;
500       std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
501       if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, anAttributePnt, aProjectedPoint))
502         aBaseShape = aShape;
503     }
504   }
505   return aBaseShape;
506 }
507
508 void SketchPlugin_Trim::getFeaturePoints(const FeaturePtr& theFeature,
509                                          AttributePoint2DPtr& theStartPointAttr,
510                                          AttributePoint2DPtr& theEndPointAttr)
511 {
512   std::string aFeatureKind = theFeature->getKind();
513   std::string aStartAttributeName, anEndAttributeName;
514   if (aFeatureKind == SketchPlugin_Line::ID()) {
515     aStartAttributeName = SketchPlugin_Line::START_ID();
516     anEndAttributeName = SketchPlugin_Line::END_ID();
517   }
518   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
519     aStartAttributeName = SketchPlugin_Arc::START_ID();
520     anEndAttributeName = SketchPlugin_Arc::END_ID();
521   }
522   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
523     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
524                                          theFeature->attribute(aStartAttributeName));
525     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
526                                          theFeature->attribute(anEndAttributeName));
527   }
528 }
529
530 void SketchPlugin_Trim::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete)
531 {
532   std::shared_ptr<ModelAPI_Data> aData = data();
533
534   // Check the base objects are initialized.
535   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
536                                          aData->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
537   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
538   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
539
540   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
541   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
542   aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
543
544   std::set<AttributePtr>::const_iterator aIt;
545   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
546     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
547     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
548     std::string aRefFeatureKind = aRefFeature->getKind();
549     if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
550         aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
551         aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
552         aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
553       theFeaturesToDelete.insert(aRefFeature);
554   }
555 }
556
557 void SketchPlugin_Trim::getRefAttributes(const FeaturePtr& theFeature,
558                                     std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
559                                     std::list<AttributePtr>& theRefsToFeature)
560 {
561   theRefs.clear();
562
563   std::list<AttributePtr> aPointAttributes =
564     theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
565   std::set<AttributePtr> aPointAttributesSet;
566
567   std::list<AttributePtr>::const_iterator aPIt =
568     aPointAttributes.begin(), aPLast = aPointAttributes.end();
569   for (; aPIt != aPLast; aPIt++)
570     aPointAttributesSet.insert(*aPIt);
571
572   std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
573   std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
574   aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
575
576   std::set<AttributePtr>::const_iterator aIt;
577   for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
578     AttributePtr anAttr = (*aIt);
579     FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
580     if (anAttrFeature.get() != this &&
581         anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
582       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
583       if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
584         AttributePtr anAttrInRef = aRefAttr->attr();
585         if (anAttrInRef.get() &&
586             aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
587           if (theRefs.find(anAttrInRef) != theRefs.end())
588             theRefs[anAttrInRef].push_back(aRefAttr);
589           else {
590             std::list<AttributePtr> anAttrList;
591             anAttrList.push_back(aRefAttr);
592             theRefs[anAttrInRef] = anAttrList;
593           }
594         }
595       }
596       else { /// find attributes referenced to feature itself
597         theRefsToFeature.push_back(anAttr);
598       }
599     }
600   }
601 }
602
603 void SketchPlugin_Trim::getCoincidencesToObject(const ObjectPtr& theObject,
604                    std::map<AttributePtr, FeaturePtr>& theCoincidencesToBaseFeature)
605 {
606   const std::set<AttributePtr>& aRefsList = theObject->data()->refsToMe();
607   std::set<AttributePtr>::const_iterator aIt;
608   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
609     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
610     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
611     if (aRefFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
612       continue;
613     AttributePtr anAttribute;
614     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
615                                   (aRefFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
616     if (aRefAttr->isObject() && aRefAttr->object() == theObject)
617     {
618       anAttribute = aRefFeature->attribute(SketchPlugin_Constraint::ENTITY_B());
619     }
620     else {
621       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>
622                                     (aRefFeature->attribute(SketchPlugin_Constraint::ENTITY_B()));
623       if (aRefAttr->isObject() && aRefAttr->object() == theObject)
624         anAttribute = aRefFeature->attribute(SketchPlugin_Constraint::ENTITY_A());
625     }
626     if (!anAttribute.get())
627       continue;
628
629     aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
630     if (aRefAttr->isObject())
631       continue; // one of attributes of coincidence contains link to an attribute
632
633     anAttribute = aRefAttr->attr();
634     if (anAttribute.get())
635     {
636       theCoincidencesToBaseFeature[anAttribute] = aRefFeature;
637     }
638   }
639 }
640
641 void SketchPlugin_Trim::updateRefAttConstraints(
642                     const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
643                     const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes,
644                     std::set<FeaturePtr>& theFeaturesToDelete)
645 {
646 #ifdef DEBUG_TRIM
647   std::cout << "SketchPlugin_Trim::updateRefAttConstraints" << std::endl;
648 #endif
649
650   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
651     anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
652   for (; anIt != aLast; anIt++) {
653     AttributePtr anAttribute = anIt->first;
654
655     /// not found in references
656     if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
657       continue;
658     std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
659     std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
660                                             aRLast = aRefAttributes.end();
661
662     AttributePtr aNewAttribute = anIt->second;
663     for (; aRefIt != aRLast; aRefIt++) {
664       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
665       if (aRefAttr.get()) {
666         if (aNewAttribute.get())
667           aRefAttr->setAttr(aNewAttribute);
668         else
669           theFeaturesToDelete.insert(ModelAPI_Feature::feature(aRefAttr->owner()));
670 #ifdef DEBUG_TRIM
671         //FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
672         //std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
673 #endif
674       }
675     }
676   }
677 }
678
679 void SketchPlugin_Trim::trimLine(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
680                                  const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
681                                  std::set<AttributePoint2DPtr>& thePoints,
682                   std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
683 {
684   // Check the base objects are initialized.
685   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
686                                         data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
687   ObjectPtr aBaseObject = aBaseObjectAttr->value();
688   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
689
690   /// points of trim
691   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
692   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
693
694   std::shared_ptr<GeomAPI_Pnt2d> aStartFeaturePoint = aStartPointAttrOfBase->pnt();
695   std::shared_ptr<GeomAPI_Pnt2d> aLastFeaturePoint = anEndPointAttrOfBase->pnt();
696
697   std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
698   std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
699   arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
700                       aStartShapePoint, aLastShapePoint);
701 #ifdef DEBUG_TRIM
702   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
703   if (aStartShapePoint.get())
704     std::cout << "Start point: [" << aStartShapePoint->x() << ", " <<
705                                        aStartShapePoint->y() << "]" << std::endl;
706   std::cout << "1st point:   [" << aStartFeaturePoint->x() << ", " <<
707                                    aStartFeaturePoint->y() << "]" << std::endl;
708   if (aLastShapePoint.get())
709     std::cout << "2st point:   [" << aLastShapePoint->x() << ", " <<
710                                      aLastShapePoint->y() << "]" << std::endl;
711   std::cout << "End point:   [" << aLastFeaturePoint->x() << ", " <<
712                                    aLastFeaturePoint->y() << "]" << std::endl;
713 #endif
714
715   bool isStartPoint = !aStartShapePoint.get() || aStartFeaturePoint->isEqual(aStartShapePoint);
716   bool isLastPoint = !aLastShapePoint.get() || aLastFeaturePoint->isEqual(aLastShapePoint);
717   if (isStartPoint || isLastPoint) {
718     // result is one line: changed existing line
719     std::string aModifiedAttribute = isStartPoint ? SketchPlugin_Line::START_ID()
720                                                   : SketchPlugin_Line::END_ID();
721     std::shared_ptr<GeomAPI_Pnt2d> aPoint;
722     if (aStartShapePoint.get() && aLastShapePoint.get())
723       aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
724     else
725       aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
726
727     fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
728     theModifiedAttributes.insert(
729       std::make_pair(aBaseFeature->attribute(aModifiedAttribute), AttributePtr()));
730
731     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
732                                (aBaseFeature->attribute(aModifiedAttribute)));
733   }
734   else {
735     // result is two lines: start line point - start shape point,
736     // last shape point - last line point
737     // create second line
738     FeaturePtr anNewFeature = createLineFeature(aBaseFeature, aLastShapePoint, aLastFeaturePoint);
739     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
740                                (anNewFeature->attribute(SketchPlugin_Line::START_ID())));
741
742     std::string aModifiedAttribute = SketchPlugin_Line::END_ID();
743     theModifiedAttributes.insert(
744       std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
745                                    anNewFeature->attribute(SketchPlugin_Line::END_ID())));
746
747     // modify base arc
748     fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
749
750     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
751                                (aBaseFeature->attribute(aModifiedAttribute)));
752
753     // Collinear constraint for lines
754     createConstraintForObjects(SketchPlugin_ConstraintCollinear::ID(),
755                                getFeatureResult(aBaseFeature),
756                                getFeatureResult(anNewFeature));
757
758   }
759 }
760
761 void SketchPlugin_Trim::trimArc(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
762                                 const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
763                                 std::set<AttributePoint2DPtr>& thePoints,
764                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
765 {
766   // Check the base objects are initialized.
767   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
768                                         data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
769   ObjectPtr aBaseObject = aBaseObjectAttr->value();
770   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
771
772   /// points of trim
773   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
774   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
775
776   std::shared_ptr<GeomAPI_Pnt2d> aStartArcPoint = aStartPointAttrOfBase->pnt();
777   std::shared_ptr<GeomAPI_Pnt2d> aLastArcPoint = anEndPointAttrOfBase->pnt();
778
779   std::shared_ptr<GeomAPI_Pnt2d> aStartShapePoint = theStartShapePoint;
780   std::shared_ptr<GeomAPI_Pnt2d> aLastShapePoint = theLastShapePoint;
781   arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
782                      aStartShapePoint, aLastShapePoint);
783 #ifdef DEBUG_TRIM
784   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
785   if (aStartShapePoint.get())
786     std::cout << "Start point: [" << aStartShapePoint->x() << ", " <<
787                                        aStartShapePoint->y() << "]" << std::endl;
788   std::cout << "1st point:   [" << aStartArcPoint->x() << ", " <<
789                                    aStartArcPoint->y() << "]" << std::endl;
790   if (aLastShapePoint.get())
791     std::cout << "2st point:   [" << aLastShapePoint->x() << ", " <<
792                                      aLastShapePoint->y() << "]" << std::endl;
793   std::cout << "End point:   [" << aLastArcPoint->x() << ", " <<
794                                    aLastArcPoint->y() << "]" << std::endl;
795 #endif
796
797   bool isStartPoint = !aStartShapePoint.get() || aStartArcPoint->isEqual(aStartShapePoint);
798   bool isLastPoint = !aLastShapePoint.get() || aLastArcPoint->isEqual(aLastShapePoint);
799   if (isStartPoint || isLastPoint) {
800     // result is one arc: changed existing arc
801     std::string aModifiedAttribute = isStartPoint ? SketchPlugin_Arc::START_ID()
802                                                   : SketchPlugin_Arc::END_ID();
803     std::shared_ptr<GeomAPI_Pnt2d> aPoint;
804     if (aStartShapePoint.get() && aLastShapePoint.get())
805       aPoint = isStartPoint ? aLastShapePoint : aStartShapePoint;
806     else
807       aPoint = aStartShapePoint.get() ? aStartShapePoint : aLastShapePoint;
808
809     fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aPoint);
810     theModifiedAttributes.insert(
811       std::make_pair(aBaseFeature->attribute(aModifiedAttribute), AttributePtr()));
812
813     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
814                                (aBaseFeature->attribute(aModifiedAttribute)));
815   }
816   else {
817     // result is two arcs: start arc point - start shape point, last shape point - last arc point
818     // create second arc
819     FeaturePtr anArcFeature = createArcFeature(aBaseFeature, aLastShapePoint, aLastArcPoint);
820     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
821                                (anArcFeature->attribute(SketchPlugin_Arc::START_ID())));
822
823     std::string aModifiedAttribute = SketchPlugin_Arc::END_ID();
824     theModifiedAttributes.insert(
825       std::make_pair(aBaseFeature->attribute(aModifiedAttribute),
826                                    anArcFeature->attribute(SketchPlugin_Arc::END_ID())));
827
828     // modify base arc
829     fillPointAttribute(aBaseFeature->attribute(aModifiedAttribute), aStartShapePoint);
830
831     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
832                                (aBaseFeature->attribute(aModifiedAttribute)));
833
834     // equal Radius constraint for arcs
835     anArcFeature->execute(); // we need the created arc result to set equal constraint
836     createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
837                                getFeatureResult(aBaseFeature),
838                                getFeatureResult(anArcFeature));
839     // coincident centers constraint
840     createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
841                      aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
842                      anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
843   }
844 }
845
846 FeaturePtr SketchPlugin_Trim::trimCircle(const std::shared_ptr<GeomAPI_Pnt2d>& theStartShapePoint,
847                                    const std::shared_ptr<GeomAPI_Pnt2d>& theLastShapePoint,
848                                    std::set<AttributePoint2DPtr>& thePoints,
849                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
850 {
851   // Check the base objects are initialized.
852   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
853                                         data()->attribute(SketchPlugin_Trim::SELECTED_OBJECT()));
854   ObjectPtr aBaseObject = aBaseObjectAttr->value();
855   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
856
857   /// points of trim
858   //AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
859   //getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
860
861   /// trim feature
862   FeaturePtr anArcFeature = createArcFeature(aBaseFeature, theStartShapePoint, theLastShapePoint);
863   // arc created by trim of circle is always correct, that means that it is not inversed
864   anArcFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(false);
865
866   theModifiedAttributes.insert(
867     std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
868                    anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID())));
869
870   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
871                              (anArcFeature->attribute(SketchPlugin_Arc::START_ID())));
872   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
873                              (anArcFeature->attribute(SketchPlugin_Arc::END_ID())));
874
875   return anArcFeature;
876 }
877
878 void SketchPlugin_Trim::arrangePointsOnLine(const AttributePoint2DPtr& theStartPointAttr,
879                                             const AttributePoint2DPtr& theEndPointAttr,
880                                             std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
881                                             std::shared_ptr<GeomAPI_Pnt2d>& theLastPoint) const
882 {
883   if (!theFirstPoint.get() || !theLastPoint.get())
884     return;
885
886   // if first point is closer to last point, swap first and last values
887   if (theStartPointAttr->pnt()->distance(theFirstPoint) >
888       theStartPointAttr->pnt()->distance(theLastPoint)) {
889     std::shared_ptr<GeomAPI_Pnt2d> aTmpPoint = theFirstPoint;
890     theFirstPoint = theLastPoint;
891     theLastPoint = aTmpPoint;
892   }
893 }
894
895 void SketchPlugin_Trim::arrangePointsOnArc(const FeaturePtr& theArc,
896                                   const AttributePoint2DPtr& theStartPointAttr,
897                                   const AttributePoint2DPtr& theEndPointAttr,
898                                   std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
899                                   std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint) const
900 {
901   if (!theFirstPoint.get() || !theSecondPoint.get())
902     return;
903
904   static const double anAngleTol = 1.e-12;
905
906   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
907       theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
908   bool isReversed = theArc->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
909
910   // collect directions to each point
911   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
912       new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
913   std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
914       new GeomAPI_Dir2d(theFirstPoint->xy()->decreased(aCenter->xy())));
915   std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
916       new GeomAPI_Dir2d(theSecondPoint->xy()->decreased(aCenter->xy())));
917
918   // sort points by their angular values
919   double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
920   double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
921   double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
922   if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
923     aFirstPtAngle += aPeriod;
924   if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
925     aSecondPtAngle += aPeriod;
926
927   if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
928     std::shared_ptr<GeomAPI_Pnt2d> aTmpPoint = theFirstPoint;
929     theFirstPoint = theSecondPoint;
930     theSecondPoint = aTmpPoint;
931   }
932 }
933
934 void SketchPlugin_Trim::fillPointAttribute(const AttributePtr& theModifiedAttribute,
935                                            const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
936 {
937   std::string anAttributeType = theModifiedAttribute->attributeType();
938   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
939     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
940                                               theModifiedAttribute);
941     aModifiedAttribute->setValue(thePoint);
942
943 #ifdef DEBUG_TRIM
944     std::cout << "<fillPointAttribute> => Pnt2d - [" << thePoint->x() << ", "
945               << thePoint->y() << "]" << std::endl;
946 #endif
947   }
948 }
949
950
951 void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute,
952                                       const AttributePtr& theSourceAttribute)
953 {
954   std::string anAttributeType = theModifiedAttribute->attributeType();
955   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
956     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
957                                               theModifiedAttribute);
958     AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
959                                               theSourceAttribute);
960
961     if (aModifiedAttribute.get() && aSourceAttribute.get())
962       aModifiedAttribute->setValue(aSourceAttribute->pnt());
963   }
964   else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
965     AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
966                                               theModifiedAttribute);
967     AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
968                                               theSourceAttribute);
969
970     if (aModifiedAttribute.get() && aSourceAttribute.get())
971       aModifiedAttribute->setValue(aSourceAttribute->value());
972   }
973   else if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
974     AttributeRefAttrPtr aRefAttributeToFill = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
975                                                                              theModifiedAttribute);
976     AttributeRefAttrPtr aSourceRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
977                                          theSourceAttribute);
978     if (!aSourceRefAttr.get())
979       aRefAttributeToFill->setAttr(theSourceAttribute);
980     else {
981       if (aSourceRefAttr->isObject())
982         aRefAttributeToFill->setObject(aSourceRefAttr->object());
983       else
984         aRefAttributeToFill->setAttr(aSourceRefAttr->attr());
985     }
986   }
987 }
988
989 FeaturePtr SketchPlugin_Trim::createLineFeature(const FeaturePtr& theBaseFeature,
990                                         const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
991                                         const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
992 {
993   FeaturePtr aFeature;
994   SketchPlugin_Sketch* aSketch = sketch();
995   if (!aSketch || !theBaseFeature.get())
996     return aFeature;
997
998   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
999
1000   fillPointAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPoint);
1001   fillPointAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPoint);
1002
1003   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1004                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1005
1006   aFeature->execute(); // to obtain result
1007
1008   return aFeature;
1009 }
1010
1011 FeaturePtr SketchPlugin_Trim::createArcFeature(const FeaturePtr& theBaseFeature,
1012                                                const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
1013                                                const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
1014 {
1015   FeaturePtr aFeature;
1016   SketchPlugin_Sketch* aSketch = sketch();
1017   if (!aSketch || !theBaseFeature.get())
1018     return aFeature;
1019
1020   std::string aCenterAttributeId;
1021   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1022     aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1023   else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1024     aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1025
1026   if (aCenterAttributeId.empty())
1027     return aFeature;
1028
1029   aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1030   // update fillet arc: make the arc correct for sure, so, it is not needed to process
1031   // the "attribute updated"
1032   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1033   bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
1034
1035   fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1036                 theBaseFeature->attribute(aCenterAttributeId));
1037   fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPoint);
1038   fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPoint);
1039
1040   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1041                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1042
1043   /// fill referersed state of created arc as it is on the base arc
1044   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1045     bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
1046     aFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(aReversed);
1047   }
1048   //aFeature->execute(); // to obtain result
1049   aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
1050
1051   return aFeature;
1052 }
1053
1054 FeaturePtr SketchPlugin_Trim::createConstraint(const std::string& theConstraintId,
1055                                                const AttributePtr& theFirstAttribute,
1056                                                const AttributePtr& theSecondAttribute)
1057 {
1058   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1059   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1060                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1061   aRefAttr->setAttr(theFirstAttribute);
1062
1063   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1064                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1065   aRefAttr->setAttr(theSecondAttribute);
1066
1067 #ifdef DEBUG_TRIM
1068   std::cout << "<createConstraint to attribute> :"
1069             << "first attribute - " << theFirstAttribute->id()
1070             << "second attribute - " << theSecondAttribute->id()
1071             << std::endl;
1072 #endif
1073
1074   return aConstraint;
1075 }
1076
1077 FeaturePtr SketchPlugin_Trim::createConstraintToObject(const std::string& theConstraintId,
1078                                                const AttributePtr& theFirstAttribute,
1079                                                const ObjectPtr& theSecondObject)
1080 {
1081   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1082   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1083                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1084   aRefAttr->setAttr(theFirstAttribute);
1085
1086   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1087                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1088   aRefAttr->setObject(theSecondObject);
1089
1090 #ifdef DEBUG_TRIM
1091   std::cout << "<createConstraint to attribute> :"
1092             << "first attribute - " << theFirstAttribute->id()
1093             << "second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
1094             << std::endl;
1095 #endif
1096
1097   return aConstraint;
1098 }
1099
1100 FeaturePtr SketchPlugin_Trim::createConstraintForObjects(
1101                                                     const std::string& theConstraintId,
1102                                                     const ObjectPtr& theFirstObject,
1103                                                     const ObjectPtr& theSecondObject)
1104 {
1105   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1106   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1107                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1108   aRefAttr->setObject(theFirstObject);
1109
1110   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1111                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1112   aRefAttr->setObject(theSecondObject);
1113
1114   return aConstraint;
1115 }
1116
1117 std::shared_ptr<ModelAPI_Result> SketchPlugin_Trim::getFeatureResult(
1118                                     const std::shared_ptr<ModelAPI_Feature>& theFeature)
1119 {
1120   std::shared_ptr<ModelAPI_Result> aResult;
1121
1122   std::string aFeatureKind = theFeature->getKind();
1123   if (aFeatureKind == SketchPlugin_Line::ID())
1124     aResult = theFeature->firstResult();
1125   else if (aFeatureKind == SketchPlugin_Arc::ID())
1126     aResult = theFeature->lastResult();
1127   else if (aFeatureKind == SketchPlugin_Circle::ID())
1128     aResult = theFeature->lastResult();
1129
1130   return aResult;
1131 }
1132
1133 //********************************************************************
1134 void SketchPlugin_Trim::fillObjectShapes(const ObjectPtr& theObject,
1135                 const ObjectPtr& theSketch,
1136                 std::map<ObjectPtr, std::set<GeomShapePtr> >& theCashedShapes,
1137                 std::map<ObjectPtr, PointToRefsMap>& theObjectToPoints)
1138 {
1139   PointToRefsMap aPointsInfo;
1140
1141   std::set<std::shared_ptr<GeomAPI_Shape> > aShapes;
1142   std::map<std::shared_ptr<GeomAPI_Pnt>,
1143                            std::list< AttributePoint2DPtr > > aPointToAttributes;
1144   std::map<std::shared_ptr<GeomAPI_Pnt>,
1145                            std::list< ObjectPtr > > aPointToObjects;
1146
1147   std::set<AttributePoint2DPtr > aRefAttributes;
1148   // current feature
1149   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1150   std::set<ResultPtr> anEdgeShapes;
1151   // edges on feature
1152   ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
1153   if (!anEdgeShapes.empty()) {
1154     GeomShapePtr aFeatureShape = (*anEdgeShapes.begin())->shape();
1155
1156     // coincidences to the feature
1157     ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
1158                          aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
1159     // layed on feature coincidences to divide it on several shapes
1160     //SketchPlugin_Sketch* aSketch = sketch();
1161     std::shared_ptr<ModelAPI_Data> aData = theSketch->data();
1162     std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1163         aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
1164     std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1165         aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
1166     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1167         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
1168     std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
1169
1170     ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
1171                                                 aX->dir(), aY, aPointsInfo);
1172
1173     std::list<FeaturePtr> aFeatures;
1174     CompositeFeaturePtr aSketchComposite =
1175                          std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theSketch);
1176     for (int i = 0; i < aSketchComposite->numberOfSubs(); i++) {
1177       FeaturePtr aFeature = aSketchComposite->subFeature(i);
1178       if (aFeature.get())
1179         aFeatures.push_back(aFeature);
1180     }
1181     ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPointsInfo);
1182
1183     GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPointsInfo, aShapes);
1184   }
1185   theObjectToPoints[theObject] = aPointsInfo;
1186   theCashedShapes[theObject] = aShapes;
1187 }