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