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