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