Salome HOME
32199abce256870049b612d95c94b8459bef9566
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_ConstraintSplit.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:    SketchPlugin_ConstraintSplit.cpp
4 // Created: 25 Aug 2016
5 // Author:  Natalia ERMOLAEVA
6
7 #include "SketchPlugin_ConstraintSplit.h"
8
9 #include <GeomAPI_Dir2d.h>
10 #include <GeomAPI_Pnt2d.h>
11 #include <GeomAPI_XY.h>
12 #include <GeomDataAPI_Point2D.h>
13 #include <GeomAlgoAPI_ShapeTools.h>
14
15 #include <ModelAPI_AttributeReference.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_AttributeRefAttr.h>
18 #include <ModelAPI_Tools.h>
19 #include <ModelAPI_AttributeBoolean.h>
20
21 #include <ModelAPI_Validator.h>
22 #include <ModelAPI_Session.h>
23 #include <ModelAPI_AttributeDouble.h>
24
25 #include <SketchPlugin_Line.h>
26 #include <SketchPlugin_Arc.h>
27 #include <SketchPlugin_Circle.h>
28 #include <SketchPlugin_ConstraintCoincidence.h>
29 #include <SketchPlugin_ConstraintEqual.h>
30 #include <SketchPlugin_ConstraintParallel.h>
31 #include <SketchPlugin_ConstraintTangent.h>
32 #include <SketchPlugin_ConstraintLength.h>
33 #include <SketchPlugin_ConstraintMirror.h>
34 #include <SketchPlugin_MultiRotation.h>
35 #include <SketchPlugin_MultiTranslation.h>
36 #include <SketchPlugin_ConstraintMiddle.h>
37
38 #include <ModelAPI_Events.h>
39 #include <SketchPlugin_Line.h>
40 #include <SketchPlugin_Arc.h>
41 #include <SketchPlugin_Circle.h>
42
43 #include <ModelGeomAlgo_Point2D.h>
44 #include <Events_Loop.h>
45
46 #include <cmath>
47
48 //#define DEBUG_SPLIT
49 #ifdef DEBUG_SPLIT
50 #include <iostream>
51 #endif
52
53 static const double PI = 3.141592653589793238463;
54
55 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
56 {
57 }
58
59 void SketchPlugin_ConstraintSplit::initAttributes()
60 {
61   data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
62   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
63   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
64 }
65
66 void SketchPlugin_ConstraintSplit::execute()
67 {
68   std::shared_ptr<ModelAPI_Data> aData = data();
69
70   // Check the base objects are initialized.
71   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
72                                             aData->attribute(SketchPlugin_Constraint::VALUE()));
73   if(!aBaseObjectAttr->isInitialized()) {
74     setError("Error: Base object is not initialized.");
75     return;
76   }
77   AttributePoint2DPtr aFirstPointAttrOfSplit =
78     getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
79   AttributePoint2DPtr aSecondPointAttrOfSplit =
80     getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
81   if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
82       !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
83     setError("Error: Sub-shape is not initialized.");
84     return;
85   }
86
87   // Wait all constraints being created, then send update events
88   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
89   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
90   if (isUpdateFlushed)
91     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
92
93
94   // Find feature constraints
95   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
96   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
97   std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
98
99   std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
100   std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
101   getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aTangentFeatures, aCoincidenceToFeature);
102
103   std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
104   std::list<AttributePtr> aRefsToFeature;
105   getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
106
107   std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
108
109 #ifdef DEBUG_SPLIT
110   std::cout << std::endl;
111   std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
112   std::cout << std::endl;
113
114   SketchPlugin_Sketch* aSketch = sketch();
115   std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
116   for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
117     std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
118   }
119
120   std::cout << std::endl;
121   std::cout << "---- IN PARAMETERS ----" << std::endl;
122   std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
123   std::cout << std::endl;
124
125   if (!aCoincidenceToFeature.empty()) {
126     std::cout << "Coincidences to base feature[" <<
127       aCoincidenceToFeature.size() << "]: " << std::endl;
128     std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
129                                                         aLast = aCoincidenceToFeature.end();
130     for (int i = 1; anIt != aLast; anIt++, i++) {
131       FeaturePtr aFeature = (*anIt).first;
132       std::string anAttributeId = (*anIt).second.first;
133       std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
134
135       std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
136       std::cout <<     " -Attribute to correct:" << anAttributeId << std::endl;
137       std::cout <<     " -Point attribute:" <<
138         ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
139     }
140   }
141
142   if (!aTangentFeatures.empty()) {
143     std::cout << std::endl;
144     std::cout << "Tangencies to base feature[" << aTangentFeatures.size() << "]: " << std::endl;
145     std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aTangentFeatures.begin(),
146                                                         aLast = aTangentFeatures.end();
147     for (int i = 1; anIt != aLast; anIt++, i++) {
148       FeaturePtr aFeature = (*anIt).first;
149       std::string anAttributeId = (*anIt).second.first;
150       std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
151
152       std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
153       std::cout <<     " -Attribute to correct:" << anAttributeId << std::endl;
154       std::cout <<     " -Point attribute:" <<
155         ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
156     }
157   }
158
159   std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
160     aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
161   std::cout << std::endl << "References to attributes of base feature [" <<
162     aBaseRefAttributes.size() << "]" << std::endl;
163   for (; aRefIt != aRefLast; aRefIt++) {
164     AttributePtr aBaseAttr = aRefIt->first;
165     std::list<AttributePtr> aRefAttributes = aRefIt->second;
166     std::string aRefsInfo;
167     std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
168                                             aRefAttrLast = aRefAttributes.end();
169     for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
170       if (!aRefsInfo.empty())
171         aRefsInfo.append(",");
172       AttributePtr aRAttr = *aRefAttrIt;
173       aRefsInfo.append(aRAttr->id());
174       FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
175       aRefsInfo.append("(" + aRFeature->name() + ") ");
176     }
177     std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
178       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
179     std::cout << aPointAttr->id().c_str() <<
180       ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
181   }
182   std::cout << std::endl;
183   std::cout << std::endl << "References to base feature [" <<
184     aRefsToFeature.size() << "]" << std::endl;
185   std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
186                                           aRefAttrLast = aRefsToFeature.end();
187   std::string aRefsInfo;
188   for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
189     if (!aRefsInfo.empty())
190       aRefsInfo.append(",");
191     AttributePtr aRAttr = *aRefAttrIt;
192     aRefsInfo.append(aRAttr->id());
193     FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
194     aRefsInfo.append("(" + aRFeature->name() + ") ");
195   }
196   std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
197
198
199   std::cout << std::endl;
200   std::cout << "---- SPLIT ----" << std::endl;
201   std::cout << std::endl;
202 #endif
203
204   std::string aFeatureKind = aBaseFeature->getKind();
205   FeaturePtr aSplitFeature, anAfterFeature;
206   std::set<AttributePoint2DPtr> aFurtherCoincidences;
207   std::set<FeaturePtr> aCreatedFeatures;
208   std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
209   if (aFeatureKind == SketchPlugin_Line::ID())
210     splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
211               aModifiedAttributes);
212   else if (aFeatureKind == SketchPlugin_Arc::ID())
213     splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures,
214              aModifiedAttributes);
215   if (aFeatureKind == SketchPlugin_Circle::ID()) {
216     FeaturePtr aCircleFeature = aBaseFeature;
217     splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
218       aCreatedFeatures, aModifiedAttributes);
219
220     updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
221
222     AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
223     aFeaturesToDelete.insert(aCircleFeature);
224     // as circle is removed, temporary fill this attribute*/
225     aBaseObjectAttr->setObject(ResultPtr());
226   }
227
228 #ifdef DEBUG_SPLIT
229   std::cout << "---- OUT PARAMETERS ----" << std::endl;
230   std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
231   std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
232   std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
233   std::cout << std::endl;
234
235   std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
236   std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
237                                        aFLast = aCreatedFeatures.end();
238   for (; aFIt != aFLast; aFIt++) {
239     std::cout << getFeatureInfo(*aFIt) << std::endl;
240   }
241   std::cout << std::endl;
242
243   std::cout << "Attributes for further Coincidences:" << std::endl;
244   std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
245                                                 aLast = aFurtherCoincidences.end();
246   for (; anIt != aLast; anIt++) {
247     AttributePtr anAttribute = *anIt;
248     FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
249     std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
250               << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
251   }
252
253   std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
254   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
255     aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
256   std::string aResInfo;
257   for (; aPIt != aPLast; aPIt++) {
258     if (!aResInfo.empty())
259       aResInfo += "\n";
260
261     std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
262
263     AttributePtr anAttr = aPair.first;
264     aResInfo.append(anAttr->id());
265     FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
266     aResInfo.append("(" + aFeature->name() + ") ");
267
268     aResInfo.append("  - is modified to -  ");
269
270     anAttr = aPair.second;
271     aResInfo.append(anAttr->id());
272     aFeature = ModelAPI_Feature::feature(anAttr->owner());
273     aResInfo.append("(" + aFeature->name() + ") ");
274   }
275   std::cout << aResInfo << std::endl;
276 #endif
277
278   std::set<ResultPtr> aFeatureResults;
279   aFeatureResults.insert(getFeatureResult(aBaseFeature));
280   if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
281     aFeatureResults.insert(getFeatureResult(anAfterFeature));
282
283   // coincidence to feature
284   updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
285                                         aFeatureResults, aSplitFeature);
286   // tangency
287   updateTangentConstraintsToFeature(aTangentFeatures, aFurtherCoincidences);
288
289   updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
290
291   // delete constraints
292 #ifdef DEBUG_SPLIT
293   std::cout << "remove features and references:" << std::endl;
294   std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
295                                        aDLast = aFeaturesToDelete.end();
296   for (; aDIt != aDLast; aDIt++) {
297     std::cout << getFeatureInfo(*aDIt, false) << std::endl;
298     std::cout << std::endl;
299   }
300 #endif
301   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
302   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
303
304 #ifdef DEBUG_SPLIT
305   std::cout << "update features after split:" << std::endl;
306   std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
307                                        anULast = aFeaturesToUpdate.end();
308   for (; anUIt != anULast; anUIt++) {
309     std::cout << getFeatureInfo(*anUIt, false) << std::endl;
310     std::cout << std::endl;
311   }
312 #endif
313   updateFeaturesAfterSplit(aFeaturesToUpdate);
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_SPLIT
321   std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
322   for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
323     std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
324   }
325 #endif
326 }
327
328 bool SketchPlugin_ConstraintSplit::isMacro() const
329 {
330   return true;
331 }
332
333 AISObjectPtr SketchPlugin_ConstraintSplit::getAISObject(AISObjectPtr thePrevious)
334 {
335   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
336                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
337   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
338
339   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
340                                         data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
341   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
342                                         data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
343
344   if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
345       aFirstPointAttrOfSplit->isInitialized() &&
346       aSecondPointAttrOfSplit->isInitialized()) {
347
348     ResultPtr aResult = getFeatureResult(aBaseFeature);
349     GeomShapePtr aBaseShape = aResult->shape();
350     std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
351
352     std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
353     std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
354     aPoints.push_back(aStartPoint);
355
356     std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
357     std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
358       sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
359     aPoints.push_back(aSecondPoint);
360
361     std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
362
363     GeomAlgoAPI_ShapeTools::splitShape(aBaseShape, aPoints, aSplitShapes);
364     std::shared_ptr<GeomAPI_Shape> aShape =
365       GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
366
367     AISObjectPtr anAIS = thePrevious;
368     if (aShape) {
369       if (!anAIS)
370         anAIS = AISObjectPtr(new GeomAPI_AISObject);
371       anAIS->createShape(aShape);
372       std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
373              aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
374
375       bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
376
377       std::vector<int> aColor;
378       double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
379       int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
380       if (isConstruction) {
381         aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color",
382                                            SKETCH_AUXILIARY_COLOR);
383         aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
384         aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY();
385       }
386       else {
387         aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
388                                             SKETCH_ENTITY_COLOR);
389       }
390       anAIS->setColor(aColor[0], aColor[1], aColor[2]);
391       anAIS->setWidth(aWidth + 1);
392       anAIS->setLineStyle(aLineStyle);
393     }
394     return anAIS;
395   }
396   return AISObjectPtr();
397 }
398
399 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
400                                                       const AttributePtr& theAttribute)
401 {
402   AttributePoint2DPtr aPointAttribute;
403
404   if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
405     AttributeRefAttrPtr aRefAttr =
406       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
407     if (aRefAttr.get() && aRefAttr->isInitialized()) {
408       AttributePtr anAttribute = aRefAttr->attr();
409       if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
410         aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
411     }
412   }
413   return aPointAttribute;
414 }
415
416 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
417                                                     AttributePoint2DPtr& theStartPointAttr,
418                                                     AttributePoint2DPtr& theEndPointAttr)
419 {
420   std::string aFeatureKind = theFeature->getKind();
421   std::string aStartAttributeName, anEndAttributeName;
422   if (aFeatureKind == SketchPlugin_Line::ID()) {
423     aStartAttributeName = SketchPlugin_Line::START_ID();
424     anEndAttributeName = SketchPlugin_Line::END_ID();
425   }
426   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
427     aStartAttributeName = SketchPlugin_Arc::START_ID();
428     anEndAttributeName = SketchPlugin_Arc::END_ID();
429   }
430   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
431     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
432                                          theFeature->attribute(aStartAttributeName));
433     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
434                                          theFeature->attribute(anEndAttributeName));
435   }
436 }
437
438 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
439                                       std::set<FeaturePtr>& theFeaturesToUpdate,
440                                       std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
441                                       std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
442 {
443   std::shared_ptr<ModelAPI_Data> aData = data();
444
445   // Check the base objects are initialized.
446   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
447                                             aData->attribute(SketchPlugin_Constraint::VALUE()));
448   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
449   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
450
451   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
452   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
453   aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
454
455   std::set<AttributePtr>::const_iterator aIt;
456   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
457     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
458     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
459     std::string aRefFeatureKind = aRefFeature->getKind();
460     if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
461         aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
462         aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
463         aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
464       theFeaturesToDelete.insert(aRefFeature);
465     else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
466       theFeaturesToUpdate.insert(aRefFeature);
467     else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
468       if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
469         /// until tangency between arc and line is implemented
470         theFeaturesToDelete.insert(aRefFeature);
471       else {
472         std::string anAttributeToBeModified;
473         AttributePoint2DPtr aTangentPoint;
474         ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
475         ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
476         if (aResult1.get() && aResult2.get()) {
477           FeaturePtr aCoincidenceFeature =
478             SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
479                                                        (ModelAPI_Feature::feature(aResult1),
480                                                         ModelAPI_Feature::feature(aResult2));
481           // get the point not lying on the splitting feature
482           for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
483             AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
484             if (!aRefAttr || aRefAttr->isObject())
485               continue;
486             AttributePoint2DPtr aPoint =
487                 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
488             if (!aPoint)
489               continue;
490             if (aPoint->owner() != aBaseFeature) {
491               aTangentPoint = aPoint;
492               break;
493             }
494           }
495         }
496         if (aTangentPoint.get()) {
497           FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
498           std::string anAttributeToBeModified = aFeature1 == aBaseFeature
499                        ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
500           theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
501         }
502         else /// there is not coincident point between tangent constraint
503           theFeaturesToDelete.insert(aRefFeature);
504       }
505     }
506     else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
507       std::string anAttributeToBeModified;
508       AttributePoint2DPtr aCoincidentPoint;
509       AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
510       AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
511       bool isToFeature = false;
512       if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
513         FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
514                                                   : FeaturePtr();
515         isToFeature = aFeature.get() && aFeature == aBaseFeature;
516         anAttributeToBeModified = anAttrA->id();
517         if (!isToFeature) {
518           aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
519                                          : FeaturePtr();
520           isToFeature = aFeature.get() && aFeature == aBaseFeature;
521           anAttributeToBeModified = anAttrB->id();
522         }
523         if (isToFeature)
524           aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
525       }
526       if (!isToFeature) { /// coincidence to point on base feature
527         AttributePtr anAttribute;
528
529         if (!anAttrA->isObject()) {
530           AttributePtr aCurAttribute = anAttrA->attr();
531           if (aCurAttribute.get()) {
532             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
533             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
534               anAttribute = anAttrB->attr();
535               anAttributeToBeModified = anAttrA->id();
536             }
537           }
538         }
539         if (!anAttribute.get() && !anAttrB->isObject()) {
540           AttributePtr aCurAttribute = anAttrB->attr();
541           if (aCurAttribute.get()) {
542             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
543             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
544               anAttribute = anAttrA->attr();
545               anAttributeToBeModified = anAttrB->id();
546             }
547           }
548         }
549         if (anAttribute.get())
550           aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
551       }
552       if (aCoincidentPoint.get() && isToFeature)
553         theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
554                                                               aCoincidentPoint);
555     }
556   }
557 }
558
559 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
560                                     std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
561                                     std::list<AttributePtr>& theRefsToFeature)
562 {
563   theRefs.clear();
564
565   std::list<AttributePtr> aPointAttributes =
566     theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
567   std::set<AttributePtr> aPointAttributesSet;
568
569   std::list<AttributePtr>::const_iterator aPIt =
570     aPointAttributes.begin(), aPLast = aPointAttributes.end();
571   for (; aPIt != aPLast; aPIt++)
572     aPointAttributesSet.insert(*aPIt);
573
574   std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
575   std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
576   aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
577
578   std::set<AttributePtr>::const_iterator aIt;
579   for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
580     AttributePtr anAttr = (*aIt);
581     FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
582     if (anAttrFeature.get() != this &&
583         anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
584       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
585       if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
586         AttributePtr anAttrInRef = aRefAttr->attr();
587         if (anAttrInRef.get() &&
588             aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
589           if (theRefs.find(anAttrInRef) != theRefs.end())
590             theRefs[anAttrInRef].push_back(aRefAttr);
591           else {
592             std::list<AttributePtr> anAttrList;
593             anAttrList.push_back(aRefAttr);
594             theRefs[anAttrInRef] = anAttrList;
595           }
596         }
597       }
598       else { /// find attributes referenced to feature itself
599         theRefsToFeature.push_back(anAttr);
600       }
601     }
602   }
603 }
604
605 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
606       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
607       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
608       const std::set<ResultPtr>& theFeatureResults,
609       const FeaturePtr& theSplitFeature)
610 {
611   if (theCoincidenceToFeature.empty())
612     return;
613
614   // we should build coincidence constraints to end of the split feature
615   std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
616   AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
617   getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
618   if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
619     aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
620   if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
621     aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
622
623   std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
624                                                             aCLast = theCoincidenceToFeature.end();
625 #ifdef DEBUG_SPLIT
626   std::cout << std::endl;
627   std::cout << "Coincidences to feature(modified):"<< std::endl;
628 #endif
629   for (; aCIt != aCLast; aCIt++) {
630     FeaturePtr aCoincFeature = aCIt->first;
631     std::string anAttributeId = aCIt->second.first;
632     AttributePoint2DPtr aCoincPoint = aCIt->second.second;
633     std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
634                                                   aFCLast = theFurtherCoincidences.end();
635     std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
636     AttributePoint2DPtr aFeaturePointAttribute;
637     for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
638       AttributePoint2DPtr aFCAttribute = *aFCIt;
639       if (aCoincPnt->isEqual(aFCAttribute->pnt()))
640         aFeaturePointAttribute = aFCAttribute;
641     }
642     if (aFeaturePointAttribute.get()) {
643       aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
644       aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
645       // create new coincidences to split feature points
646       std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
647                                                     aSFLast = aNewCoincidencesToSplitFeature.end();
648       for (; aSFIt != aSFLast; aSFIt++) {
649         AttributePoint2DPtr aSFAttribute = *aSFIt;
650         if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
651           std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
652           if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
653             aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
654           createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
655                            aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
656         }
657       }
658     }
659     else {
660       /// find feature by shape intersected the point
661       ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
662
663       if (theFeatureResults.size() > 1) { // try to find point on additional feature
664         ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
665         GeomShapePtr aShape = anAddtionalResult->shape();
666
667         std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
668         std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
669
670         std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
671         if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
672           aResultForCoincidence = anAddtionalResult;
673       }
674       aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
675     }
676 #ifdef DEBUG_SPLIT
677   std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
678 #endif
679   }
680 }
681
682 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
683       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
684       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
685 {
686   if (theTangentFeatures.empty())
687     return;
688
689   std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
690                                                       aTLast = theTangentFeatures.end();
691 #ifdef DEBUG_SPLIT
692   std::cout << std::endl;
693   std::cout << "Tangencies to feature(modified):"<< std::endl;
694 #endif
695   for (; aTIt != aTLast; aTIt++) {
696     FeaturePtr aTangentFeature = aTIt->first;
697     std::string anAttributeId = aTIt->second.first;
698     AttributePoint2DPtr aTangentPoint = aTIt->second.second;
699     std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
700                                                   aFCLast = theFurtherCoincidences.end();
701     std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
702     AttributePoint2DPtr aFeaturePointAttribute;
703     /// here we rely on created coincidence between further coincidence point and tangent result
704     for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
705       AttributePoint2DPtr aFCAttribute = *aFCIt;
706       if (aCoincPnt->isEqual(aFCAttribute->pnt()))
707         aFeaturePointAttribute = aFCAttribute;
708     }
709     if (aFeaturePointAttribute.get()) {
710       FeaturePtr aFeature =
711         std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
712       aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
713     }
714 #ifdef DEBUG_SPLIT
715   std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
716 #endif
717   }
718 }
719
720 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
721                                                   const ResultPtr& theFeatureBaseResult,
722                                                   const std::list<AttributePtr>& theRefsToFeature)
723 {
724   std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
725                                           aLast = theRefsToFeature.end();
726   for (; anIt != aLast; anIt++) {
727     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
728     if (aRefAttr.get())
729       aRefAttr->setObject(theFeatureBaseResult);
730   }
731 }
732
733 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
734                     const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
735                     const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
736 {
737 #ifdef DEBUG_SPLIT
738   std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
739 #endif
740
741   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
742     anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
743   for (; anIt != aLast; anIt++) {
744     AttributePtr anAttribute = anIt->first;
745
746     /// not found in references
747     if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
748       continue;
749     std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
750     std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
751                                             aRLast = aRefAttributes.end();
752
753     AttributePtr aNewAttribute = anIt->second;
754     for (; aRefIt != aRLast; aRefIt++) {
755       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
756       if (aRefAttr.get()) {
757         aRefAttr->setAttr(aNewAttribute);
758 #ifdef DEBUG_SPLIT
759         FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
760         std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
761 #endif
762       }
763     }
764   }
765 }
766
767 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
768                                              FeaturePtr& theBaseFeatureModified,
769                                              FeaturePtr& theAfterFeature,
770                                              std::set<AttributePoint2DPtr>& thePoints,
771                                              std::set<FeaturePtr>& theCreatedFeatures,
772                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
773 {
774   std::set<FeaturePtr> aCreatedFeatures;
775   FeaturePtr aConstraintFeature;
776   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
777
778   SketchPlugin_Sketch* aSketch = sketch();
779   if (!aSketch)
780     return;
781
782   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
783                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
784   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
785   std::string aFeatureKind = aBaseFeature->getKind();
786   if (aFeatureKind != SketchPlugin_Line::ID())
787     return;
788
789   AttributePoint2DPtr aFirstPointAttrOfSplit =
790     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
791   AttributePoint2DPtr aSecondPointAttrOfSplit =
792     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
793   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
794
795   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
796   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
797     setError("Error: Feature has no start and end points.");
798     return;
799   }
800
801   arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
802                       aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
803
804 #ifdef DEBUG_SPLIT
805   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
806   std::cout << "Start point: " <<
807     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
808   std::cout << "1st point:   " <<
809     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
810   std::cout << "2nd point:   " <<
811     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
812   std::cout << "End point:   " <<
813     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
814 #endif
815
816   /// create a split feature
817   theSplitFeature =
818     createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
819   theCreatedFeatures.insert(theSplitFeature);
820
821   // before split feature
822   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
823     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
824                                         theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
825   }
826   else {
827     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
828     /// move end arc point to start of split
829   }
830
831   // after split feature
832   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
833     FeaturePtr aFeature;
834     if (!theBaseFeatureModified.get()) {
835       aFeature = aBaseFeature; ///< use base feature to store all constraints here
836       fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
837       aFeature->execute(); // to update result
838     }
839     else {
840       aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
841       theCreatedFeatures.insert(aFeature);
842       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
843                                              aFeature->attribute(SketchPlugin_Line::END_ID())));
844     }
845     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
846                      theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
847                      aFeature->attribute(SketchPlugin_Line::START_ID()));
848     theCreatedFeatures.insert(aConstraintFeature);
849
850     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
851                                 (aFeature->attribute(SketchPlugin_Line::START_ID())));
852     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
853                                 (aFeature->attribute(SketchPlugin_Line::END_ID())));
854
855     if (!theBaseFeatureModified.get())
856       theBaseFeatureModified = aFeature;
857     else
858       theAfterFeature = aFeature;
859   }
860   else {
861     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
862                                   (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
863     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
864                                    theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
865   }
866   // base split, that is defined before split feature should be changed at end
867   // (after the after feature creation). Otherwise modified value will be used in after feature
868   // before split feature
869   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
870     /// move end arc point to start of split
871     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
872                                                     aFirstPointAttrOfSplit);
873     theBaseFeatureModified->execute(); // to update result
874     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
875                      theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
876                      theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
877     theCreatedFeatures.insert(aConstraintFeature);
878
879     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
880                              (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
881     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
882                                (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
883   }
884   else
885     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
886                                        (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
887
888   // additional constraints between split and base features
889   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
890                                                        getFeatureResult(aBaseFeature),
891                                                        getFeatureResult(theSplitFeature));
892   theCreatedFeatures.insert(aConstraintFeature);
893   if (theAfterFeature.get()) {
894     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
895                                                     getFeatureResult(aBaseFeature),
896                                                     getFeatureResult(theAfterFeature));
897     theCreatedFeatures.insert(aConstraintFeature);
898   }
899 }
900
901 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
902                                             FeaturePtr& theBaseFeatureModified,
903                                             FeaturePtr& theAfterFeature,
904                                             std::set<AttributePoint2DPtr>& thePoints,
905                                             std::set<FeaturePtr>& theCreatedFeatures,
906                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
907 {
908   std::set<FeaturePtr> aCreatedFeatures;
909   FeaturePtr aConstraintFeature;
910   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
911
912   SketchPlugin_Sketch* aSketch = sketch();
913   if (!aSketch)
914     return;
915
916   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
917                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
918   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
919   std::string aFeatureKind = aBaseFeature->getKind();
920   if (aFeatureKind != SketchPlugin_Arc::ID())
921     return;
922
923   AttributePoint2DPtr aFirstPointAttrOfSplit =
924     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
925   AttributePoint2DPtr aSecondPointAttrOfSplit =
926     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
927   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
928   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
929   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
930     setError("Error: Feature has no start and end points.");
931     return;
932   }
933
934   // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
935   aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
936       SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
937
938   arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
939                      aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
940 #ifdef DEBUG_SPLIT
941   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
942   std::cout << "Start point: " <<
943     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
944   std::cout << "1st point:   " <<
945     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
946   std::cout << "2nd point:   " <<
947     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
948   std::cout << "End point:   " <<
949     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
950 #endif
951
952   /// split feature
953   theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
954   theCreatedFeatures.insert(theSplitFeature);
955
956   // before split feature
957   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
958     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
959                                   theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
960   }
961   else {
962     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
963     /// move end arc point to start of split
964   }
965
966   // after split feature
967   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
968     FeaturePtr aFeature;
969     if (!theBaseFeatureModified.get()) {
970       aFeature = aBaseFeature; ///< use base feature to store all constraints here
971       fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
972       aFeature->execute(); // to update result
973     }
974     else {
975       aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
976       theCreatedFeatures.insert(aFeature);
977       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
978                                                   aFeature->attribute(SketchPlugin_Arc::END_ID())));
979     }
980     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
981                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
982                      aFeature->attribute(SketchPlugin_Arc::START_ID()));
983     theCreatedFeatures.insert(aConstraintFeature);
984
985     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
986                                 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
987     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
988                                 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
989
990     if (!theBaseFeatureModified.get())
991       theBaseFeatureModified = aFeature;
992     else
993       theAfterFeature = aFeature;
994   }
995   else {
996     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
997                                   (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
998     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
999                                    theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
1000   }
1001   // base split, that is defined before split feature should be changed at end
1002   // (after the after feature creation). Otherwise modified value will be used in after feature
1003   // before split feature
1004   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1005     /// move end arc point to start of split
1006     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1007                                                     aFirstPointAttrOfSplit);
1008     theBaseFeatureModified->execute(); // to update result
1009     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1010                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1011                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1012     theCreatedFeatures.insert(aConstraintFeature);
1013
1014     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1015                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1016     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1017                                (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1018   }
1019   else
1020     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1021                                        (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1022
1023   // additional constraints between split and base features
1024   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1025                                                        getFeatureResult(aBaseFeature),
1026                                                        getFeatureResult(theSplitFeature));
1027   theCreatedFeatures.insert(aConstraintFeature);
1028   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1029                                                        getFeatureResult(theSplitFeature),
1030                                                        getFeatureResult(aBaseFeature));
1031   theCreatedFeatures.insert(aConstraintFeature);
1032   if (theAfterFeature.get()) {
1033     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1034                                                     getFeatureResult(aBaseFeature),
1035                                                     getFeatureResult(theAfterFeature));
1036     theCreatedFeatures.insert(aConstraintFeature);
1037     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1038                                                     getFeatureResult(theSplitFeature),
1039                                                     getFeatureResult(theAfterFeature));
1040     theCreatedFeatures.insert(aConstraintFeature);
1041   }
1042 }
1043
1044 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1045                                                FeaturePtr& theBaseFeatureModified,
1046                                                FeaturePtr& theAfterFeature,
1047                                                std::set<AttributePoint2DPtr>& thePoints,
1048                                                std::set<FeaturePtr>& theCreatedFeatures,
1049                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1050 {
1051   std::set<FeaturePtr> aCreatedFeatures;
1052   FeaturePtr aConstraintFeature;
1053   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1054
1055   SketchPlugin_Sketch* aSketch = sketch();
1056   if (!aSketch)
1057     return;
1058
1059   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1060                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
1061   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1062   std::string aFeatureKind = aBaseFeature->getKind();
1063   if (aFeatureKind != SketchPlugin_Circle::ID())
1064     return;
1065
1066   AttributePoint2DPtr aFirstPointAttrOfSplit =
1067     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1068   AttributePoint2DPtr aSecondPointAttrOfSplit =
1069     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1070
1071   /// split feature
1072   theSplitFeature =
1073     createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1074   bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1075   theCreatedFeatures.insert(theSplitFeature);
1076
1077   /// base feature is a left part of the circle
1078   theBaseFeatureModified = createArcFeature(aBaseFeature,
1079     aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1080   std::dynamic_pointer_cast<SketchPlugin_Arc>(
1081     theBaseFeatureModified)->setReversed(!aSplitReversed);
1082   theBaseFeatureModified->execute();
1083
1084   theModifiedAttributes.insert(
1085     std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1086                   theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1087
1088   theCreatedFeatures.insert(theBaseFeatureModified);
1089
1090   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1091                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1092   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1093                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1094
1095   // additional constraints between split and base features
1096   aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1097                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1098                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1099   theCreatedFeatures.insert(aConstraintFeature);
1100   aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1101                      theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1102                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1103   theCreatedFeatures.insert(aConstraintFeature);
1104
1105   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1106                                                        getFeatureResult(theSplitFeature),
1107                                                        getFeatureResult(theBaseFeatureModified));
1108   theCreatedFeatures.insert(aConstraintFeature);
1109 }
1110
1111 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1112     const AttributePoint2DPtr& theStartPointAttr,
1113     const AttributePoint2DPtr& theEndPointAttr,
1114     AttributePoint2DPtr& theFirstPointAttr,
1115     AttributePoint2DPtr& theLastPointAttr) const
1116 {
1117   // if first point is closer to last point, swap first and last values
1118   if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1119       theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1120     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1121     theFirstPointAttr = theLastPointAttr;
1122     theLastPointAttr = aTmpPoint;
1123   }
1124 }
1125
1126 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1127     const FeaturePtr& theArc,
1128     const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1129     const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1130     std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1131     std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1132 {
1133   static const double anAngleTol = 1.e-12;
1134
1135   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1136       theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1137   bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1138
1139   // collect directions to each point
1140   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1141       new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1142   std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1143       new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1144   std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1145       new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1146
1147   // sort points by their angular values
1148   double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1149   double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1150   double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1151   if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1152     aFirstPtAngle += aPeriod;
1153   if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1154     aSecondPtAngle += aPeriod;
1155
1156   if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1157     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1158     theFirstPointAttr = theSecondPointAttr;
1159     theSecondPointAttr = aTmpPoint;
1160   }
1161 }
1162
1163 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1164                                                  const AttributePtr& theSourceAttribute)
1165 {
1166   std::string anAttributeType = theModifiedAttribute->attributeType();
1167   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1168     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1169                                               theModifiedAttribute);
1170     AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1171                                               theSourceAttribute);
1172
1173     if (aModifiedAttribute.get() && aSourceAttribute.get())
1174       aModifiedAttribute->setValue(aSourceAttribute->pnt());
1175   }
1176   else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1177     AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1178                                               theModifiedAttribute);
1179     AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1180                                               theSourceAttribute);
1181
1182     if (aModifiedAttribute.get() && aSourceAttribute.get())
1183       aModifiedAttribute->setValue(aSourceAttribute->value());
1184   }
1185 }
1186
1187 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1188                                                            const AttributePtr& theFirstPointAttr,
1189                                                            const AttributePtr& theSecondPointAttr)
1190 {
1191   FeaturePtr aFeature;
1192   SketchPlugin_Sketch* aSketch = sketch();
1193   if (!aSketch || !theBaseFeature.get())
1194     return aFeature;
1195
1196   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1197
1198   fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1199   fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1200
1201   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1202                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1203
1204   aFeature->execute(); // to obtain result
1205
1206   return aFeature;
1207 }
1208
1209 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1210                                                           const AttributePtr& theFirstPointAttr,
1211                                                           const AttributePtr& theSecondPointAttr)
1212 {
1213   FeaturePtr aFeature;
1214   SketchPlugin_Sketch* aSketch = sketch();
1215   if (!aSketch || !theBaseFeature.get())
1216     return aFeature;
1217
1218   std::string aCenterAttributeId;
1219   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1220     aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1221   else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1222     aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1223
1224   if (aCenterAttributeId.empty())
1225     return aFeature;
1226
1227   aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1228   // update fillet arc: make the arc correct for sure, so, it is not needed to process
1229   // the "attribute updated"
1230   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1231   aFeature->data()->blockSendAttributeUpdated(true);
1232
1233   aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1234                 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1235
1236   fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1237                 theBaseFeature->attribute(aCenterAttributeId));
1238   fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1239   fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1240
1241   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1242                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1243
1244   /// fill referersed state of created arc as it is on the base arc
1245   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1246     bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1247     aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1248   }
1249   aFeature->data()->blockSendAttributeUpdated(false);
1250   aFeature->execute(); // to obtain result
1251
1252   return aFeature;
1253 }
1254
1255 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1256                                                     const AttributePtr& theFirstAttribute,
1257                                                     const AttributePtr& theSecondAttribute)
1258 {
1259   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1260   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1261                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1262   aRefAttr->setAttr(theFirstAttribute);
1263
1264   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1265                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1266   aRefAttr->setAttr(theSecondAttribute);
1267
1268   return aConstraint;
1269 }
1270
1271 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1272                                                     const std::string& theConstraintId,
1273                                                     const ObjectPtr& theFirstObject,
1274                                                     const ObjectPtr& theSecondObject)
1275 {
1276   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1277   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1278                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1279   aRefAttr->setObject(theFirstObject);
1280
1281   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1282                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1283   aRefAttr->setObject(theSecondObject);
1284
1285   return aConstraint;
1286 }
1287
1288 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1289                                                    const std::set<FeaturePtr>& theFeaturesToUpdate)
1290 {
1291   std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1292                                        aLast = theFeaturesToUpdate.end();
1293   for (; anIt != aLast; anIt++) {
1294     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1295     std::string aRefFeatureKind = aRefFeature->getKind();
1296     if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1297       std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1298                               std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1299       if (aLenghtFeature.get()) {
1300         std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1301             ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1302         double aValue;
1303         if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1304           aValueAttr->setValue(aValue);
1305       }
1306     }
1307   }
1308 }
1309
1310 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1311                                     const std::shared_ptr<ModelAPI_Feature>& theFeature)
1312 {
1313   std::shared_ptr<ModelAPI_Result> aResult;
1314
1315   std::string aFeatureKind = theFeature->getKind();
1316   if (aFeatureKind == SketchPlugin_Line::ID())
1317     aResult = theFeature->firstResult();
1318   else if (aFeatureKind == SketchPlugin_Arc::ID())
1319     aResult = theFeature->lastResult();
1320   else if (aFeatureKind == SketchPlugin_Circle::ID())
1321     aResult = theFeature->lastResult();
1322
1323   return aResult;
1324 }
1325
1326 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1327                                            const std::shared_ptr<ModelAPI_Feature>& theFeature)
1328 {
1329   std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1330
1331   std::string aFeatureKind = theFeature->getKind();
1332   if (aFeatureKind == SketchPlugin_Line::ID()) {
1333     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1334     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1335   }
1336   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1337     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1338     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1339   }
1340   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1341   }
1342
1343   return anAttributes;
1344 }
1345
1346 #ifdef _DEBUG
1347 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1348                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
1349                                                const bool isUseAttributesInfo)
1350 {
1351   std::string anInfo;
1352   if (!theFeature.get()) {
1353     return "none";
1354   }
1355
1356   if (theFeature->data()->isValid())
1357     anInfo.append(theFeature->data()->name().c_str());
1358
1359   if (isUseAttributesInfo) {
1360     std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1361                                                              getEdgeAttributes(theFeature));
1362     /// processing of feature with point 2d attributes, like line, arc, circle
1363     if (!aPointsInfo.empty()) {
1364       anInfo += ": ";
1365       anInfo += "\n";
1366       anInfo += aPointsInfo;
1367     }
1368     else { /// process constraint coincidence, find points in ref attr attributes
1369       std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1370                                                        ModelAPI_AttributeRefAttr::typeId());
1371       std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1372       std::string anAttributesInfo;
1373       for(; anIt != aLast; anIt++) {
1374         if (!anAttributesInfo.empty()) {
1375           anAttributesInfo.append(", ");
1376           anAttributesInfo += "\n";
1377         }
1378         AttributePtr anAttr = *anIt;
1379         std::string aValue = "not defined";
1380         std::string aType = anAttr->attributeType();
1381         if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1382           std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1383                              std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1384           if (aRefAttr.get()) {
1385             if (aRefAttr->isObject()) {
1386               FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1387               aValue = "<object:>" + getFeatureInfo(aFeature, false);
1388             }
1389             else {
1390               AttributePtr anAttribute = aRefAttr->attr();
1391               if (anAttribute.get()) {
1392                 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1393                 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1394                          " [" + getFeatureInfo(aFeature, false) + "]";
1395               }
1396             }
1397           }
1398         }
1399         anAttributesInfo.append("    " + anAttr->id() + ": " + aValue);
1400       }
1401       if (!anAttributesInfo.empty())
1402         anInfo = anInfo + "\n" + anAttributesInfo;
1403     }
1404   }
1405   return anInfo;
1406 }
1407 #endif