Salome HOME
ac0630cfd2d0cb4289340ed521df752cba5d8390
[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       createConstraint(SketchPlugin_ConstraintCoincidence::ID(), aPointAttribute, *anObjectIt);
244     }
245   }
246
247   // Wait all constraints being created, then send update events
248   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
249   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
250   if (isUpdateFlushed)
251     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
252
253   updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes, aFeaturesToDelete);
254
255   // delete constraints
256 #ifdef DEBUG_TRIM
257   std::cout << "remove features and references:" << std::endl;
258   std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
259                                        aDLast = aFeaturesToDelete.end();
260   for (; aDIt != aDLast; aDIt++) {
261     //std::cout << getFeatureInfo(*aDIt, false) << std::endl;
262     //std::cout << std::endl;
263   }
264 #endif
265   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
266   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
267
268   // Send events to update the sub-features by the solver.
269   if(isUpdateFlushed) {
270     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
271   }
272
273 #ifdef DEBUG_TRIM
274   std::cout << "SketchPlugin_Trim::done" << std::endl;
275 #endif
276 }
277
278 bool SketchPlugin_Trim::isMacro() const
279 {
280   return true;
281 }
282
283 AISObjectPtr SketchPlugin_Trim::getAISObject(AISObjectPtr thePrevious)
284 {
285   AISObjectPtr anAIS = thePrevious;
286   // feature for trim
287   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
288                                            data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
289   ObjectPtr aBaseObject = aBaseObjectAttr->value();
290   if (!aBaseObject.get())
291     return anAIS;
292   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
293
294   // point on feature
295   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
296                                            data()->attribute(ENTITY_POINT()));
297   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
298   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(), anAttributePnt2d->y());
299
300   if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
301     fillObjectShapes(aBaseObject);
302
303   const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
304   if (!aShapes.empty()) {
305     std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
306     for (; anIt != aLast; anIt++) {
307       GeomShapePtr aBaseShape = *anIt;
308       std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
309       if (ModelGeomAlgo_Point2D::isPointOnEdge(aBaseShape, anAttributePnt, aProjectedPoint)) {
310         if (aBaseShape) {
311           if (!anAIS)
312             anAIS = AISObjectPtr(new GeomAPI_AISObject);
313           anAIS->createShape(aBaseShape);
314
315           std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
316                  aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
317
318           bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
319
320           std::vector<int> aColor;
321           aColor = Config_PropManager::color("Visualization", "operation_highlight_color",
322                                              OPERATION_HIGHLIGHT_COLOR());
323           double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
324           int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
325           if (isConstruction) {
326             aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
327             aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY();
328           }
329           anAIS->setColor(aColor[0], aColor[1], aColor[2]);
330            // modification of width should be replaced to value 1 after highlight problem is fixed
331           anAIS->setWidth(aWidth + 2);//1);
332           anAIS->setLineStyle(aLineStyle);
333           break;
334         }
335       }
336     }
337   }
338
339   return anAIS;
340 }
341
342 void SketchPlugin_Trim::getFeaturePoints(const FeaturePtr& theFeature,
343                                          AttributePoint2DPtr& theStartPointAttr,
344                                          AttributePoint2DPtr& theEndPointAttr)
345 {
346   std::string aFeatureKind = theFeature->getKind();
347   std::string aStartAttributeName, anEndAttributeName;
348   if (aFeatureKind == SketchPlugin_Line::ID()) {
349     aStartAttributeName = SketchPlugin_Line::START_ID();
350     anEndAttributeName = SketchPlugin_Line::END_ID();
351   }
352   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
353     aStartAttributeName = SketchPlugin_Arc::START_ID();
354     anEndAttributeName = SketchPlugin_Arc::END_ID();
355   }
356   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
357     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
358                                          theFeature->attribute(aStartAttributeName));
359     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
360                                          theFeature->attribute(anEndAttributeName));
361   }
362 }
363
364 void SketchPlugin_Trim::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
365                                       std::set<FeaturePtr>& theFeaturesToUpdate)
366 {
367   std::shared_ptr<ModelAPI_Data> aData = data();
368
369   // Check the base objects are initialized.
370   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
371                                             aData->attribute(SketchPlugin_Trim::BASE_OBJECT()));
372   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
373   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
374
375   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
376   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
377   aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
378
379   std::set<AttributePtr>::const_iterator aIt;
380   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
381     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
382     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
383     std::string aRefFeatureKind = aRefFeature->getKind();
384     if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
385         aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
386         aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
387         aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
388       theFeaturesToDelete.insert(aRefFeature);
389     else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
390       theFeaturesToUpdate.insert(aRefFeature);
391     else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
392       if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
393         /// until tangency between arc and line is implemented
394         theFeaturesToDelete.insert(aRefFeature);
395       else {
396         std::string anAttributeToBeModified;
397         AttributePoint2DPtr aTangentPoint;
398         ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
399         ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
400         if (aResult1.get() && aResult2.get()) {
401           FeaturePtr aCoincidenceFeature =
402             SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
403                                                        (ModelAPI_Feature::feature(aResult1),
404                                                         ModelAPI_Feature::feature(aResult2));
405           // get the point not lying on the splitting feature
406           for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
407             AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(SketchPlugin_Trim::BASE_OBJECT());
408             if (!aRefAttr || aRefAttr->isObject())
409               continue;
410             AttributePoint2DPtr aPoint =
411                 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
412             if (!aPoint)
413               continue;
414             if (aPoint->owner() != aBaseFeature) {
415               aTangentPoint = aPoint;
416               break;
417             }
418           }
419         }
420         if (aTangentPoint.get()) {
421           //FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
422           //std::string anAttributeToBeModified = aFeature1 == aBaseFeature
423           //             ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
424           //theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
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() << ", " << thePoint->y() << "]" << std::endl;
793 #endif
794   }
795 }
796
797
798 void SketchPlugin_Trim::fillAttribute(const AttributePtr& theModifiedAttribute,
799                                       const AttributePtr& theSourceAttribute)
800 {
801   std::string anAttributeType = theModifiedAttribute->attributeType();
802   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
803     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
804                                               theModifiedAttribute);
805     AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
806                                               theSourceAttribute);
807
808     if (aModifiedAttribute.get() && aSourceAttribute.get())
809       aModifiedAttribute->setValue(aSourceAttribute->pnt());
810   }
811   else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
812     AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
813                                               theModifiedAttribute);
814     AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
815                                               theSourceAttribute);
816
817     if (aModifiedAttribute.get() && aSourceAttribute.get())
818       aModifiedAttribute->setValue(aSourceAttribute->value());
819   }
820   else if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
821     AttributeRefAttrPtr aRefAttributeToFill = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
822                                                                                theModifiedAttribute);
823     AttributeRefAttrPtr aSourceRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
824                                          theSourceAttribute);
825     if (!aSourceRefAttr.get())
826       aRefAttributeToFill->setAttr(theSourceAttribute);
827     else {
828       if (aSourceRefAttr->isObject())
829         aRefAttributeToFill->setObject(aSourceRefAttr->object());
830       else
831         aRefAttributeToFill->setAttr(aSourceRefAttr->attr());
832     }
833   }
834 }
835
836 FeaturePtr SketchPlugin_Trim::createLineFeature(const FeaturePtr& theBaseFeature,
837                                         const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
838                                         const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
839 {
840   FeaturePtr aFeature;
841   SketchPlugin_Sketch* aSketch = sketch();
842   if (!aSketch || !theBaseFeature.get())
843     return aFeature;
844
845   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
846
847   fillPointAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPoint);
848   fillPointAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPoint);
849
850   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
851                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
852
853   aFeature->execute(); // to obtain result
854
855   return aFeature;
856 }
857
858
859 FeaturePtr SketchPlugin_Trim::createArcFeature(const FeaturePtr& theBaseFeature,
860                                                const std::shared_ptr<GeomAPI_Pnt2d>& theFirstPoint,
861                                                const std::shared_ptr<GeomAPI_Pnt2d>& theSecondPoint)
862 {
863   FeaturePtr aFeature;
864   SketchPlugin_Sketch* aSketch = sketch();
865   if (!aSketch || !theBaseFeature.get())
866     return aFeature;
867
868   std::string aCenterAttributeId;
869   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
870     aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
871   else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
872     aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
873
874   if (aCenterAttributeId.empty())
875     return aFeature;
876
877   aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
878   // update fillet arc: make the arc correct for sure, so, it is not needed to process
879   // the "attribute updated"
880   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
881   bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
882
883   aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
884                 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
885
886   fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
887                 theBaseFeature->attribute(aCenterAttributeId));
888   fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPoint);
889   fillPointAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPoint);
890
891   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
892                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
893
894   /// fill referersed state of created arc as it is on the base arc
895   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
896     bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
897     aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
898   }
899   aFeature->execute(); // to obtain result
900   aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
901
902   return aFeature;
903 }
904
905 FeaturePtr SketchPlugin_Trim::createConstraint(const std::string& theConstraintId,
906                                                const AttributePtr& theFirstAttribute,
907                                                const AttributePtr& theSecondAttribute)
908 {
909   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
910   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
911                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
912   aRefAttr->setAttr(theFirstAttribute);
913
914   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
915                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
916   aRefAttr->setAttr(theSecondAttribute);
917
918 #ifdef DEBUG_TRIM
919   std::cout << "<createConstraint to attribute> :"
920             << "first attribute - " << theFirstAttribute->id()
921             << "second attribute - " << theSecondAttribute->id()
922             << std::endl;
923 #endif
924
925   return aConstraint;
926 }
927
928 FeaturePtr SketchPlugin_Trim::createConstraint(const std::string& theConstraintId,
929                                                const AttributePtr& theFirstAttribute,
930                                                const ObjectPtr& theSecondObject)
931 {
932   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
933   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
934                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
935   aRefAttr->setAttr(theFirstAttribute);
936
937   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
938                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
939   aRefAttr->setObject(theSecondObject);
940
941 #ifdef DEBUG_TRIM
942   std::cout << "<createConstraint to attribute> :"
943             << "first attribute - " << theFirstAttribute->id()
944             << "second object - " << ModelAPI_Feature::feature(theSecondObject)->getKind()
945             << std::endl;
946 #endif
947
948   return aConstraint;
949 }
950
951 FeaturePtr SketchPlugin_Trim::createConstraintForObjects(
952                                                     const std::string& theConstraintId,
953                                                     const ObjectPtr& theFirstObject,
954                                                     const ObjectPtr& theSecondObject)
955 {
956   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
957   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
958                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
959   aRefAttr->setObject(theFirstObject);
960
961   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
962                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
963   aRefAttr->setObject(theSecondObject);
964
965   return aConstraint;
966 }
967
968 std::shared_ptr<ModelAPI_Result> SketchPlugin_Trim::getFeatureResult(
969                                     const std::shared_ptr<ModelAPI_Feature>& theFeature)
970 {
971   std::shared_ptr<ModelAPI_Result> aResult;
972
973   std::string aFeatureKind = theFeature->getKind();
974   if (aFeatureKind == SketchPlugin_Line::ID())
975     aResult = theFeature->firstResult();
976   else if (aFeatureKind == SketchPlugin_Arc::ID())
977     aResult = theFeature->lastResult();
978   else if (aFeatureKind == SketchPlugin_Circle::ID())
979     aResult = theFeature->lastResult();
980
981   return aResult;
982 }
983
984 //********************************************************************
985 bool SketchPlugin_Trim::useGraphicIntersection() const
986 {
987   return true;
988 }
989
990 //********************************************************************
991 void SketchPlugin_Trim::fillObjectShapes(const ObjectPtr& theObject)
992 {
993   PointToRefsMap aPointsInfo;
994
995   std::set<std::shared_ptr<GeomAPI_Shape> > aShapes;
996   std::map<std::shared_ptr<GeomAPI_Pnt>,
997                            std::list< AttributePoint2DPtr > > aPointToAttributes;
998   std::map<std::shared_ptr<GeomAPI_Pnt>,
999                            std::list< ObjectPtr > > aPointToObjects;
1000
1001   std::set<AttributePoint2DPtr > aRefAttributes;
1002   // current feature
1003   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
1004   std::set<ResultPtr> anEdgeShapes;
1005   // edges on feature
1006   ModelAPI_Tools::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeShapes);
1007   if (!anEdgeShapes.empty()) {
1008     GeomShapePtr aFeatureShape = (*anEdgeShapes.begin())->shape();
1009
1010     // coincidences to the feature
1011     ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
1012                          aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
1013     // layed on feature coincidences to divide it on several shapes
1014     SketchPlugin_Sketch* aSketch = sketch();
1015     std::shared_ptr<ModelAPI_Data> aData = aSketch->data();
1016     std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
1017         aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
1018     std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1019         aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
1020     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
1021         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
1022     std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
1023
1024     ModelGeomAlgo_Point2D::getPointsInsideShape(aFeatureShape, aRefAttributes, aC->pnt(),
1025                                                 aX->dir(), aY, aPointsInfo);
1026
1027     // intersection points
1028     if (useGraphicIntersection()) {
1029       std::list<FeaturePtr> aFeatures;
1030       for (int i = 0; i < aSketch->numberOfSubs(); i++) {
1031         FeaturePtr aFeature = aSketch->subFeature(i);
1032         if (aFeature.get())
1033           aFeatures.push_back(aFeature);
1034       }
1035       ModelGeomAlgo_Point2D::getPointsIntersectedShape(aFeature, aFeatures, aPointsInfo);
1036     }
1037     GeomAlgoAPI_ShapeTools::splitShape(aFeatureShape, aPointsInfo, aShapes);
1038   }
1039   myObjectToPoints[theObject] = aPointsInfo;
1040   myCashedShapes[theObject] = aShapes;
1041 }
1042
1043 //********************************************************************
1044 void SketchPlugin_Trim::attributeChanged(const std::string& theID)
1045 {
1046   //data()->addAttribute(SketchPlugin_Trim::BASE_OBJECT(), ModelAPI_AttributeReference::typeId());
1047   if (theID == SketchPlugin_Trim::BASE_OBJECT()) {
1048     bool isValidAttribute = false;
1049     // feature for trim
1050     AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1051                                              data()->attribute(SketchPlugin_Trim::BASE_OBJECT()));
1052     ObjectPtr aBaseObject = aBaseObjectAttr->value();
1053     if (aBaseObject.get()) {
1054       FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1055       // point on feature
1056       AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1057                                                data()->attribute(ENTITY_POINT()));
1058       std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPoint->pnt();
1059       std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(), anAttributePnt2d->y());
1060
1061       if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
1062         fillObjectShapes(aBaseObject);
1063
1064       const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
1065       isValidAttribute = !aShapes.empty();
1066
1067       if (!isValidAttribute) {
1068         bool aWasBlocked = data()->blockSendAttributeUpdated(true);
1069         aBaseObjectAttr->setValue(ObjectPtr());
1070         data()->blockSendAttributeUpdated(aWasBlocked);
1071       }
1072     }
1073   }
1074 }