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