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