]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp
Salome HOME
d2f64ddea650659099cfc1af34ecae8c8d9e4e29
[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       anAIS->setWidth(5);
373       std::vector<int> aColor;
374       aColor = Config_PropManager::color("Visualization", "sketch_entity_color",
375                                           SKETCH_ENTITY_COLOR);
376      anAIS->setColor(aColor[0], aColor[1], aColor[2]);
377     }
378     return anAIS;
379   }
380   return AISObjectPtr();
381 }
382
383 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
384                                                       const AttributePtr& theAttribute)
385 {
386   AttributePoint2DPtr aPointAttribute;
387
388   if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
389     AttributeRefAttrPtr aRefAttr =
390       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
391     if (aRefAttr.get() && aRefAttr->isInitialized()) {
392       AttributePtr anAttribute = aRefAttr->attr();
393       if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
394         aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
395     }
396   }
397   return aPointAttribute;
398 }
399
400 void SketchPlugin_ConstraintSplit::getFeaturePoints(const FeaturePtr& theFeature,
401                                                     AttributePoint2DPtr& theStartPointAttr,
402                                                     AttributePoint2DPtr& theEndPointAttr)
403 {
404   std::string aFeatureKind = theFeature->getKind();
405   std::string aStartAttributeName, anEndAttributeName;
406   if (aFeatureKind == SketchPlugin_Line::ID()) {
407     aStartAttributeName = SketchPlugin_Line::START_ID();
408     anEndAttributeName = SketchPlugin_Line::END_ID();
409   }
410   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
411     aStartAttributeName = SketchPlugin_Arc::START_ID();
412     anEndAttributeName = SketchPlugin_Arc::END_ID();
413   }
414   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
415     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
416                                          theFeature->attribute(aStartAttributeName));
417     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
418                                          theFeature->attribute(anEndAttributeName));
419   }
420 }
421
422 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
423                                       std::set<FeaturePtr>& theFeaturesToUpdate,
424                                       std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
425                                       std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
426 {
427   std::shared_ptr<ModelAPI_Data> aData = data();
428
429   // Check the base objects are initialized.
430   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
431                                             aData->attribute(SketchPlugin_Constraint::VALUE()));
432   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
433   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
434
435   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
436   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
437   aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
438
439   std::set<AttributePtr>::const_iterator aIt;
440   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
441     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
442     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
443     std::string aRefFeatureKind = aRefFeature->getKind();
444     if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
445         aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
446         aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
447         aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
448       theFeaturesToDelete.insert(aRefFeature);
449     else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
450       theFeaturesToUpdate.insert(aRefFeature);
451     else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
452       if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
453         /// until tangency between arc and line is implemented
454         theFeaturesToDelete.insert(aRefFeature);
455       else {
456         std::string anAttributeToBeModified;
457         AttributePoint2DPtr aTangentPoint;
458         ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
459         ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
460         if (aResult1.get() && aResult2.get()) {
461           FeaturePtr aCoincidenceFeature =
462             SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
463                                                        (ModelAPI_Feature::feature(aResult1),
464                                                         ModelAPI_Feature::feature(aResult2));
465           // get the point not lying on the splitting feature
466           for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
467             AttributeRefAttrPtr aRefAttr = aCoincidenceFeature->refattr(ATTRIBUTE(i));
468             if (!aRefAttr || aRefAttr->isObject())
469               continue;
470             AttributePoint2DPtr aPoint =
471                 std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
472             if (!aPoint)
473               continue;
474             if (aPoint->owner() != aBaseFeature) {
475               aTangentPoint = aPoint;
476               break;
477             }
478           }
479         }
480         if (aTangentPoint.get()) {
481           FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
482           std::string anAttributeToBeModified = aFeature1 == aBaseFeature
483                        ? SketchPlugin_Constraint::ENTITY_A() : SketchPlugin_Constraint::ENTITY_B();
484           theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
485         }
486         else /// there is not coincident point between tangent constraint
487           theFeaturesToDelete.insert(aRefFeature);
488       }
489     }
490     else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
491       std::string anAttributeToBeModified;
492       AttributePoint2DPtr aCoincidentPoint;
493       AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
494       AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
495       bool isToFeature = false;
496       if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
497         FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
498                                                   : FeaturePtr();
499         isToFeature = aFeature.get() && aFeature == aBaseFeature;
500         anAttributeToBeModified = anAttrA->id();
501         if (!isToFeature) {
502           aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
503                                          : FeaturePtr();
504           isToFeature = aFeature.get() && aFeature == aBaseFeature;
505           anAttributeToBeModified = anAttrB->id();
506         }
507         if (isToFeature)
508           aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
509       }
510       if (!isToFeature) { /// coincidence to point on base feature
511         AttributePtr anAttribute;
512
513         if (!anAttrA->isObject()) {
514           AttributePtr aCurAttribute = anAttrA->attr();
515           if (aCurAttribute.get()) {
516             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
517             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
518               anAttribute = anAttrB->attr();
519               anAttributeToBeModified = anAttrA->id();
520             }
521           }
522         }
523         if (!anAttribute.get() && !anAttrB->isObject()) {
524           AttributePtr aCurAttribute = anAttrB->attr();
525           if (aCurAttribute.get()) {
526             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
527             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
528               anAttribute = anAttrA->attr();
529               anAttributeToBeModified = anAttrB->id();
530             }
531           }
532         }
533         if (anAttribute.get())
534           aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
535       }
536       if (aCoincidentPoint.get() && isToFeature)
537         theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
538                                                               aCoincidentPoint);
539     }
540   }
541 }
542
543 void SketchPlugin_ConstraintSplit::getRefAttributes(const FeaturePtr& theFeature,
544                                     std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
545                                     std::list<AttributePtr>& theRefsToFeature)
546 {
547   theRefs.clear();
548
549   std::list<AttributePtr> aPointAttributes =
550     theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
551   std::set<AttributePtr> aPointAttributesSet;
552
553   std::list<AttributePtr>::const_iterator aPIt =
554     aPointAttributes.begin(), aPLast = aPointAttributes.end();
555   for (; aPIt != aPLast; aPIt++)
556     aPointAttributesSet.insert(*aPIt);
557
558   std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
559   std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
560   aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
561
562   std::set<AttributePtr>::const_iterator aIt;
563   for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
564     AttributePtr anAttr = (*aIt);
565     FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
566     if (anAttrFeature.get() != this &&
567         anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
568       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
569       if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
570         AttributePtr anAttrInRef = aRefAttr->attr();
571         if (anAttrInRef.get() &&
572             aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
573           if (theRefs.find(anAttrInRef) != theRefs.end())
574             theRefs[anAttrInRef].push_back(aRefAttr);
575           else {
576             std::list<AttributePtr> anAttrList;
577             anAttrList.push_back(aRefAttr);
578             theRefs[anAttrInRef] = anAttrList;
579           }
580         }
581       }
582       else { /// find attributes referenced to feature itself
583         theRefsToFeature.push_back(anAttr);
584       }
585     }
586   }
587 }
588
589 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
590       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
591       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
592       const std::set<ResultPtr>& theFeatureResults,
593       const FeaturePtr& theSplitFeature)
594 {
595   if (theCoincidenceToFeature.empty())
596     return;
597
598   // we should build coincidence constraints to end of the split feature
599   std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
600   AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
601   getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
602   if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
603     aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
604   if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
605     aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
606
607   std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
608                                                             aCLast = theCoincidenceToFeature.end();
609 #ifdef DEBUG_SPLIT
610   std::cout << std::endl;
611   std::cout << "Coincidences to feature(modified):"<< std::endl;
612 #endif
613   for (; aCIt != aCLast; aCIt++) {
614     FeaturePtr aCoincFeature = aCIt->first;
615     std::string anAttributeId = aCIt->second.first;
616     AttributePoint2DPtr aCoincPoint = aCIt->second.second;
617     std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
618                                                   aFCLast = theFurtherCoincidences.end();
619     std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
620     AttributePoint2DPtr aFeaturePointAttribute;
621     for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
622       AttributePoint2DPtr aFCAttribute = *aFCIt;
623       if (aCoincPnt->isEqual(aFCAttribute->pnt()))
624         aFeaturePointAttribute = aFCAttribute;
625     }
626     if (aFeaturePointAttribute.get()) {
627       aCoincFeature->refattr(anAttributeId)->setObject(ResultPtr());
628       aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
629       // create new coincidences to split feature points
630       std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
631                                                     aSFLast = aNewCoincidencesToSplitFeature.end();
632       for (; aSFIt != aSFLast; aSFIt++) {
633         AttributePoint2DPtr aSFAttribute = *aSFIt;
634         if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
635           std::string aSecondAttribute = SketchPlugin_Constraint::ENTITY_A();
636           if (anAttributeId == SketchPlugin_Constraint::ENTITY_A())
637             aSecondAttribute = SketchPlugin_Constraint::ENTITY_B();
638           createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
639                            aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
640         }
641       }
642     }
643     else {
644       /// find feature by shape intersected the point
645       ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
646
647       if (theFeatureResults.size() > 1) { // try to find point on additional feature
648         ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
649         GeomShapePtr aShape = anAddtionalResult->shape();
650
651         std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
652         std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
653
654         std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
655         if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
656           aResultForCoincidence = anAddtionalResult;
657       }
658       aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
659     }
660 #ifdef DEBUG_SPLIT
661   std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
662 #endif
663   }
664 }
665
666 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
667       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
668       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
669 {
670   if (theTangentFeatures.empty())
671     return;
672
673   std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
674                                                       aTLast = theTangentFeatures.end();
675 #ifdef DEBUG_SPLIT
676   std::cout << std::endl;
677   std::cout << "Tangencies to feature(modified):"<< std::endl;
678 #endif
679   for (; aTIt != aTLast; aTIt++) {
680     FeaturePtr aTangentFeature = aTIt->first;
681     std::string anAttributeId = aTIt->second.first;
682     AttributePoint2DPtr aTangentPoint = aTIt->second.second;
683     std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
684                                                   aFCLast = theFurtherCoincidences.end();
685     std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
686     AttributePoint2DPtr aFeaturePointAttribute;
687     /// here we rely on created coincidence between further coincidence point and tangent result
688     for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
689       AttributePoint2DPtr aFCAttribute = *aFCIt;
690       if (aCoincPnt->isEqual(aFCAttribute->pnt()))
691         aFeaturePointAttribute = aFCAttribute;
692     }
693     if (aFeaturePointAttribute.get()) {
694       FeaturePtr aFeature =
695         std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
696       aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
697     }
698 #ifdef DEBUG_SPLIT
699   std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
700 #endif
701   }
702 }
703
704 void SketchPlugin_ConstraintSplit::updateRefFeatureConstraints(
705                                                   const ResultPtr& theFeatureBaseResult,
706                                                   const std::list<AttributePtr>& theRefsToFeature)
707 {
708   std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
709                                           aLast = theRefsToFeature.end();
710   for (; anIt != aLast; anIt++) {
711     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
712     if (aRefAttr.get())
713       aRefAttr->setObject(theFeatureBaseResult);
714   }
715 }
716
717 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
718                     const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
719                     const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
720 {
721 #ifdef DEBUG_SPLIT
722   std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
723 #endif
724
725   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
726     anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
727   for (; anIt != aLast; anIt++) {
728     AttributePtr anAttribute = anIt->first;
729
730     /// not found in references
731     if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
732       continue;
733     std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
734     std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
735                                             aRLast = aRefAttributes.end();
736
737     AttributePtr aNewAttribute = anIt->second;
738     for (; aRefIt != aRLast; aRefIt++) {
739       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
740       if (aRefAttr.get()) {
741         aRefAttr->setAttr(aNewAttribute);
742 #ifdef DEBUG_SPLIT
743         FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
744         std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
745 #endif
746       }
747     }
748   }
749 }
750
751 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
752                                              FeaturePtr& theBaseFeatureModified,
753                                              FeaturePtr& theAfterFeature,
754                                              std::set<AttributePoint2DPtr>& thePoints,
755                                              std::set<FeaturePtr>& theCreatedFeatures,
756                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
757 {
758   std::set<FeaturePtr> aCreatedFeatures;
759   FeaturePtr aConstraintFeature;
760   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
761
762   SketchPlugin_Sketch* aSketch = sketch();
763   if (!aSketch)
764     return;
765
766   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
767                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
768   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
769   std::string aFeatureKind = aBaseFeature->getKind();
770   if (aFeatureKind != SketchPlugin_Line::ID())
771     return;
772
773   AttributePoint2DPtr aFirstPointAttrOfSplit =
774     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
775   AttributePoint2DPtr aSecondPointAttrOfSplit =
776     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
777   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
778
779   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
780   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
781     setError("Error: Feature has no start and end points.");
782     return;
783   }
784
785   arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
786                       aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
787
788 #ifdef DEBUG_SPLIT
789   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
790   std::cout << "Start point: " <<
791     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
792   std::cout << "1st point:   " <<
793     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
794   std::cout << "2nd point:   " <<
795     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
796   std::cout << "End point:   " <<
797     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
798 #endif
799
800   /// create a split feature
801   theSplitFeature =
802     createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
803   theCreatedFeatures.insert(theSplitFeature);
804
805   // before split feature
806   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
807     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
808                                         theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
809   }
810   else {
811     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
812     /// move end arc point to start of split
813   }
814
815   // after split feature
816   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
817     FeaturePtr aFeature;
818     if (!theBaseFeatureModified.get()) {
819       aFeature = aBaseFeature; ///< use base feature to store all constraints here
820       fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
821       aFeature->execute(); // to update result
822     }
823     else {
824       aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
825       theCreatedFeatures.insert(aFeature);
826       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
827                                              aFeature->attribute(SketchPlugin_Line::END_ID())));
828     }
829     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
830                      theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
831                      aFeature->attribute(SketchPlugin_Line::START_ID()));
832     theCreatedFeatures.insert(aConstraintFeature);
833
834     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
835                                 (aFeature->attribute(SketchPlugin_Line::START_ID())));
836     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
837                                 (aFeature->attribute(SketchPlugin_Line::END_ID())));
838
839     if (!theBaseFeatureModified.get())
840       theBaseFeatureModified = aFeature;
841     else
842       theAfterFeature = aFeature;
843   }
844   else {
845     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
846                                   (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
847     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
848                                    theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
849   }
850   // base split, that is defined before split feature should be changed at end
851   // (after the after feature creation). Otherwise modified value will be used in after feature
852   // before split feature
853   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
854     /// move end arc point to start of split
855     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
856                                                     aFirstPointAttrOfSplit);
857     theBaseFeatureModified->execute(); // to update result
858     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
859                      theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
860                      theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
861     theCreatedFeatures.insert(aConstraintFeature);
862
863     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
864                              (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
865     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
866                                (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
867   }
868   else
869     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
870                                        (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
871
872   // additional constraints between split and base features
873   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
874                                                        getFeatureResult(aBaseFeature),
875                                                        getFeatureResult(theSplitFeature));
876   theCreatedFeatures.insert(aConstraintFeature);
877   if (theAfterFeature.get()) {
878     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
879                                                     getFeatureResult(aBaseFeature),
880                                                     getFeatureResult(theAfterFeature));
881     theCreatedFeatures.insert(aConstraintFeature);
882   }
883 }
884
885 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
886                                             FeaturePtr& theBaseFeatureModified,
887                                             FeaturePtr& theAfterFeature,
888                                             std::set<AttributePoint2DPtr>& thePoints,
889                                             std::set<FeaturePtr>& theCreatedFeatures,
890                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
891 {
892   std::set<FeaturePtr> aCreatedFeatures;
893   FeaturePtr aConstraintFeature;
894   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
895
896   SketchPlugin_Sketch* aSketch = sketch();
897   if (!aSketch)
898     return;
899
900   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
901                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
902   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
903   std::string aFeatureKind = aBaseFeature->getKind();
904   if (aFeatureKind != SketchPlugin_Arc::ID())
905     return;
906
907   AttributePoint2DPtr aFirstPointAttrOfSplit =
908     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
909   AttributePoint2DPtr aSecondPointAttrOfSplit =
910     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
911   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
912   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
913   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
914     setError("Error: Feature has no start and end points.");
915     return;
916   }
917
918   // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
919   aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
920       SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
921
922   arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
923                      aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
924 #ifdef DEBUG_SPLIT
925   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
926   std::cout << "Start point: " <<
927     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
928   std::cout << "1st point:   " <<
929     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
930   std::cout << "2nd point:   " <<
931     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
932   std::cout << "End point:   " <<
933     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
934 #endif
935
936   /// split feature
937   theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
938   theCreatedFeatures.insert(theSplitFeature);
939
940   // before split feature
941   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
942     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
943                                   theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
944   }
945   else {
946     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
947     /// move end arc point to start of split
948   }
949
950   // after split feature
951   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
952     FeaturePtr aFeature;
953     if (!theBaseFeatureModified.get()) {
954       aFeature = aBaseFeature; ///< use base feature to store all constraints here
955       fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
956       aFeature->execute(); // to update result
957     }
958     else {
959       aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
960       theCreatedFeatures.insert(aFeature);
961       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
962                                                   aFeature->attribute(SketchPlugin_Arc::END_ID())));
963     }
964     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
965                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
966                      aFeature->attribute(SketchPlugin_Arc::START_ID()));
967     theCreatedFeatures.insert(aConstraintFeature);
968
969     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
970                                 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
971     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
972                                 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
973
974     if (!theBaseFeatureModified.get())
975       theBaseFeatureModified = aFeature;
976     else
977       theAfterFeature = aFeature;
978   }
979   else {
980     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
981                                   (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
982     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
983                                    theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
984   }
985   // base split, that is defined before split feature should be changed at end
986   // (after the after feature creation). Otherwise modified value will be used in after feature
987   // before split feature
988   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
989     /// move end arc point to start of split
990     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
991                                                     aFirstPointAttrOfSplit);
992     theBaseFeatureModified->execute(); // to update result
993     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
994                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
995                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
996     theCreatedFeatures.insert(aConstraintFeature);
997
998     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
999                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1000     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1001                                (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1002   }
1003   else
1004     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1005                                        (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1006
1007   // additional constraints between split and base features
1008   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1009                                                        getFeatureResult(aBaseFeature),
1010                                                        getFeatureResult(theSplitFeature));
1011   theCreatedFeatures.insert(aConstraintFeature);
1012   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1013                                                        getFeatureResult(theSplitFeature),
1014                                                        getFeatureResult(aBaseFeature));
1015   theCreatedFeatures.insert(aConstraintFeature);
1016   if (theAfterFeature.get()) {
1017     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
1018                                                     getFeatureResult(aBaseFeature),
1019                                                     getFeatureResult(theAfterFeature));
1020     theCreatedFeatures.insert(aConstraintFeature);
1021     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1022                                                     getFeatureResult(theSplitFeature),
1023                                                     getFeatureResult(theAfterFeature));
1024     theCreatedFeatures.insert(aConstraintFeature);
1025   }
1026 }
1027
1028 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
1029                                                FeaturePtr& theBaseFeatureModified,
1030                                                FeaturePtr& theAfterFeature,
1031                                                std::set<AttributePoint2DPtr>& thePoints,
1032                                                std::set<FeaturePtr>& theCreatedFeatures,
1033                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1034 {
1035   std::set<FeaturePtr> aCreatedFeatures;
1036   FeaturePtr aConstraintFeature;
1037   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1038
1039   SketchPlugin_Sketch* aSketch = sketch();
1040   if (!aSketch)
1041     return;
1042
1043   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1044                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
1045   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1046   std::string aFeatureKind = aBaseFeature->getKind();
1047   if (aFeatureKind != SketchPlugin_Circle::ID())
1048     return;
1049
1050   AttributePoint2DPtr aFirstPointAttrOfSplit =
1051     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1052   AttributePoint2DPtr aSecondPointAttrOfSplit =
1053     getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1054
1055   /// split feature
1056   theSplitFeature =
1057     createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1058   bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1059   theCreatedFeatures.insert(theSplitFeature);
1060
1061   /// base feature is a left part of the circle
1062   theBaseFeatureModified = createArcFeature(aBaseFeature,
1063     aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1064   std::dynamic_pointer_cast<SketchPlugin_Arc>(
1065     theBaseFeatureModified)->setReversed(!aSplitReversed);
1066   theBaseFeatureModified->execute();
1067
1068   theModifiedAttributes.insert(
1069     std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1070                   theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1071
1072   theCreatedFeatures.insert(theBaseFeatureModified);
1073
1074   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1075                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1076   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1077                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1078
1079   // additional constraints between split and base features
1080   aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1081                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1082                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1083   theCreatedFeatures.insert(aConstraintFeature);
1084   aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
1085                      theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1086                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1087   theCreatedFeatures.insert(aConstraintFeature);
1088
1089   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
1090                                                        getFeatureResult(theSplitFeature),
1091                                                        getFeatureResult(theBaseFeatureModified));
1092   theCreatedFeatures.insert(aConstraintFeature);
1093 }
1094
1095 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
1096     const AttributePoint2DPtr& theStartPointAttr,
1097     const AttributePoint2DPtr& theEndPointAttr,
1098     AttributePoint2DPtr& theFirstPointAttr,
1099     AttributePoint2DPtr& theLastPointAttr) const
1100 {
1101   // if first point is closer to last point, swap first and last values
1102   if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1103       theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1104     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1105     theFirstPointAttr = theLastPointAttr;
1106     theLastPointAttr = aTmpPoint;
1107   }
1108 }
1109
1110 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
1111     const FeaturePtr& theArc,
1112     const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1113     const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1114     std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1115     std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1116 {
1117   static const double anAngleTol = 1.e-12;
1118
1119   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1120       theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1121   bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1122
1123   // collect directions to each point
1124   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1125       new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1126   std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1127       new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1128   std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1129       new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1130
1131   // sort points by their angular values
1132   double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1133   double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1134   double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1135   if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1136     aFirstPtAngle += aPeriod;
1137   if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1138     aSecondPtAngle += aPeriod;
1139
1140   if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1141     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1142     theFirstPointAttr = theSecondPointAttr;
1143     theSecondPointAttr = aTmpPoint;
1144   }
1145 }
1146
1147 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1148                                                  const AttributePtr& theSourceAttribute)
1149 {
1150   std::string anAttributeType = theModifiedAttribute->attributeType();
1151   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1152     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1153                                               theModifiedAttribute);
1154     AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1155                                               theSourceAttribute);
1156
1157     if (aModifiedAttribute.get() && aSourceAttribute.get())
1158       aModifiedAttribute->setValue(aSourceAttribute->pnt());
1159   }
1160   else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1161     AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1162                                               theModifiedAttribute);
1163     AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1164                                               theSourceAttribute);
1165
1166     if (aModifiedAttribute.get() && aSourceAttribute.get())
1167       aModifiedAttribute->setValue(aSourceAttribute->value());
1168   }
1169 }
1170
1171 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1172                                                            const AttributePtr& theFirstPointAttr,
1173                                                            const AttributePtr& theSecondPointAttr)
1174 {
1175   FeaturePtr aFeature;
1176   SketchPlugin_Sketch* aSketch = sketch();
1177   if (!aSketch || !theBaseFeature.get())
1178     return aFeature;
1179
1180   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1181
1182   fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1183   fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1184
1185   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1186                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1187
1188   aFeature->execute(); // to obtain result
1189
1190   return aFeature;
1191 }
1192
1193 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1194                                                           const AttributePtr& theFirstPointAttr,
1195                                                           const AttributePtr& theSecondPointAttr)
1196 {
1197   FeaturePtr aFeature;
1198   SketchPlugin_Sketch* aSketch = sketch();
1199   if (!aSketch || !theBaseFeature.get())
1200     return aFeature;
1201
1202   std::string aCenterAttributeId;
1203   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1204     aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1205   else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1206     aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1207
1208   if (aCenterAttributeId.empty())
1209     return aFeature;
1210
1211   aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1212   // update fillet arc: make the arc correct for sure, so, it is not needed to process
1213   // the "attribute updated"
1214   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1215   aFeature->data()->blockSendAttributeUpdated(true);
1216
1217   aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1218                 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1219
1220   fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1221                 theBaseFeature->attribute(aCenterAttributeId));
1222   fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1223   fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1224
1225   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1226                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1227
1228   /// fill referersed state of created arc as it is on the base arc
1229   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1230     bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1231     aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1232   }
1233   aFeature->data()->blockSendAttributeUpdated(false);
1234   aFeature->execute(); // to obtain result
1235
1236   return aFeature;
1237 }
1238
1239 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1240                                                     const AttributePtr& theFirstAttribute,
1241                                                     const AttributePtr& theSecondAttribute)
1242 {
1243   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1244   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1245                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1246   aRefAttr->setAttr(theFirstAttribute);
1247
1248   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1249                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1250   aRefAttr->setAttr(theSecondAttribute);
1251
1252   return aConstraint;
1253 }
1254
1255 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(
1256                                                     const std::string& theConstraintId,
1257                                                     const ObjectPtr& theFirstObject,
1258                                                     const ObjectPtr& theSecondObject)
1259 {
1260   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1261   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1262                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1263   aRefAttr->setObject(theFirstObject);
1264
1265   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1266                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1267   aRefAttr->setObject(theSecondObject);
1268
1269   return aConstraint;
1270 }
1271
1272 void SketchPlugin_ConstraintSplit::updateFeaturesAfterSplit(
1273                                                    const std::set<FeaturePtr>& theFeaturesToUpdate)
1274 {
1275   std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1276                                        aLast = theFeaturesToUpdate.end();
1277   for (; anIt != aLast; anIt++) {
1278     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1279     std::string aRefFeatureKind = aRefFeature->getKind();
1280     if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1281       std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1282                               std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1283       if (aLenghtFeature.get()) {
1284         std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1285             ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1286         double aValue;
1287         if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1288           aValueAttr->setValue(aValue);
1289       }
1290     }
1291   }
1292 }
1293
1294 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1295                                     const std::shared_ptr<ModelAPI_Feature>& theFeature)
1296 {
1297   std::shared_ptr<ModelAPI_Result> aResult;
1298
1299   std::string aFeatureKind = theFeature->getKind();
1300   if (aFeatureKind == SketchPlugin_Line::ID())
1301     aResult = theFeature->firstResult();
1302   else if (aFeatureKind == SketchPlugin_Arc::ID())
1303     aResult = theFeature->lastResult();
1304   else if (aFeatureKind == SketchPlugin_Circle::ID())
1305     aResult = theFeature->lastResult();
1306
1307   return aResult;
1308 }
1309
1310 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1311                                            const std::shared_ptr<ModelAPI_Feature>& theFeature)
1312 {
1313   std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1314
1315   std::string aFeatureKind = theFeature->getKind();
1316   if (aFeatureKind == SketchPlugin_Line::ID()) {
1317     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1318     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1319   }
1320   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1321     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1322     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1323   }
1324   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1325   }
1326
1327   return anAttributes;
1328 }
1329
1330 #ifdef _DEBUG
1331 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1332                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
1333                                                const bool isUseAttributesInfo)
1334 {
1335   std::string anInfo;
1336   if (!theFeature.get()) {
1337     return "none";
1338   }
1339
1340   if (theFeature->data()->isValid())
1341     anInfo.append(theFeature->data()->name().c_str());
1342
1343   if (isUseAttributesInfo) {
1344     std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1345                                                              getEdgeAttributes(theFeature));
1346     /// processing of feature with point 2d attributes, like line, arc, circle
1347     if (!aPointsInfo.empty()) {
1348       anInfo += ": ";
1349       anInfo += "\n";
1350       anInfo += aPointsInfo;
1351     }
1352     else { /// process constraint coincidence, find points in ref attr attributes
1353       std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1354                                                        ModelAPI_AttributeRefAttr::typeId());
1355       std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1356       std::string anAttributesInfo;
1357       for(; anIt != aLast; anIt++) {
1358         if (!anAttributesInfo.empty()) {
1359           anAttributesInfo.append(", ");
1360           anAttributesInfo += "\n";
1361         }
1362         AttributePtr anAttr = *anIt;
1363         std::string aValue = "not defined";
1364         std::string aType = anAttr->attributeType();
1365         if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1366           std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1367                              std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1368           if (aRefAttr.get()) {
1369             if (aRefAttr->isObject()) {
1370               FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1371               aValue = "<object:>" + getFeatureInfo(aFeature, false);
1372             }
1373             else {
1374               AttributePtr anAttribute = aRefAttr->attr();
1375               if (anAttribute.get()) {
1376                 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1377                 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1378                          " [" + getFeatureInfo(aFeature, false) + "]";
1379               }
1380             }
1381           }
1382         }
1383         anAttributesInfo.append("    " + anAttr->id() + ": " + aValue);
1384       }
1385       if (!anAttributesInfo.empty())
1386         anInfo = anInfo + "\n" + anAttributesInfo;
1387     }
1388   }
1389   return anInfo;
1390 }
1391 #endif