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