]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_ConstraintSplit.cpp
Salome HOME
fccbf1df4b9e105d23bfed6460790af4a415b058
[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: 17 Jul 2016
5 // Author:  Natalia ERMOLAEVA
6
7 #include "SketchPlugin_ConstraintSplit.h"
8
9 #include <GeomAPI_Pnt2d.h>
10 #include <GeomDataAPI_Point2D.h>
11 #include <ModelAPI_AttributeReference.h>
12 #include <ModelAPI_AttributeString.h>
13 #include <ModelAPI_AttributeRefAttr.h>
14 #include <ModelAPI_Tools.h>
15
16 #include <ModelAPI_Validator.h>
17 #include <ModelAPI_Session.h>
18
19 #include <SketchPlugin_Line.h>
20 #include <SketchPlugin_Arc.h>
21 #include <SketchPlugin_Circle.h>
22 #include <SketchPlugin_ConstraintCoincidence.h>
23 #include <SketchPlugin_ConstraintEqual.h>
24 #include <SketchPlugin_ConstraintParallel.h>
25 #include <SketchPlugin_ConstraintTangent.h>
26 #include <SketchPlugin_ConstraintMirror.h>
27 #include <SketchPlugin_MultiRotation.h>
28 #include <SketchPlugin_MultiTranslation.h>
29
30 #include <ModelAPI_Events.h>
31 #include <SketchPlugin_Line.h>
32 #include <SketchPlugin_Arc.h>
33 #include <SketchPlugin_Circle.h>
34
35 #include <ModelGeomAlgo_Point2D.h>
36 #include <Events_Loop.h>
37
38 #define DEBUG_SPLIT
39 #ifdef DEBUG_SPLIT
40 #include <iostream>
41 #endif
42
43 SketchPlugin_ConstraintSplit::SketchPlugin_ConstraintSplit()
44 {
45 }
46
47 void SketchPlugin_ConstraintSplit::initAttributes()
48 {
49   data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
50   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
51   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
52 }
53
54 void SketchPlugin_ConstraintSplit::execute()
55 {
56   std::shared_ptr<ModelAPI_Data> aData = data();
57
58   // Check the base objects are initialized.
59   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
60                                             aData->attribute(SketchPlugin_Constraint::VALUE()));
61   if(!aBaseObjectAttr->isInitialized()) {
62     setError("Error: Base object is not initialized.");
63     return;
64   }
65   AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
66   AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
67   if (!aFirstPointAttr.get() || !aFirstPointAttr->isInitialized() ||
68       !aSecondPointAttr.get() || !aSecondPointAttr->isInitialized()) {
69     setError("Error: Sub-shape is not initialized.");
70     return;
71   }
72
73   // Wait all constraints being created, then send update events
74   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
75   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
76   if (isUpdateFlushed)
77     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
78
79
80   // Find feature constraints
81   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
82   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
83
84   std::set<FeaturePtr> aFeaturesToDelete;
85   std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
86   std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
87   std::map<FeaturePtr, IdToPointPair> aCoincidenceToPoint;
88   getConstraints(aFeaturesToDelete, aTangentFeatures, aCoincidenceToFeature, aCoincidenceToPoint);
89
90 #ifdef DEBUG_SPLIT
91   std::cout << std::endl;
92   std::cout << "SketchPlugin_ConstraintSplit::execute()" << std::endl;
93   std::cout << std::endl;
94
95   std::cout << "SKETCH FEATURES (before split):" << std::endl;
96   SketchPlugin_Sketch* aSketch = sketch();
97   for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
98     std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
99     std::cout << std::endl;
100   }
101
102   std::cout << std::endl;
103   std::cout << "IN PARAMETERS" << std::endl;
104   std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
105   std::cout << std::endl;
106
107   if (!aCoincidenceToFeature.empty()) {
108     std::cout << "Coincidences to base feature[" << aCoincidenceToFeature.size() << "]: " << std::endl;
109     std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
110                                                         aLast = aCoincidenceToFeature.end();
111     for (int i = 1; anIt != aLast; anIt++, i++) {
112       FeaturePtr aFeature = (*anIt).first;
113       std::string anAttributeId = (*anIt).second.first;
114       std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
115
116       std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
117       std::cout <<     " -Attribute to correct:" << anAttributeId << std::endl;
118       std::cout <<     " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
119     }
120   }
121
122   if (!aCoincidenceToPoint.empty()) {
123     std::cout << "Coincidences to points on base feature[" << aCoincidenceToPoint.size() << "]: " << std::endl;
124     std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToPoint.begin(),
125                                                         aLast = aCoincidenceToPoint.end();
126     for (int i = 1; anIt != aLast; anIt++, i++) {
127       FeaturePtr aFeature = (*anIt).first;
128       std::string anAttributeId = (*anIt).second.first;
129       std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
130
131       std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
132       std::cout <<     " -Attribute to correct:" << anAttributeId << std::endl;
133       std::cout <<     " -Point attribute:" << ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
134     }
135   }
136 #endif
137
138 #ifdef DEBUG_SPLIT
139   std::cout << std::endl;
140   std::cout << "---- SPLIT ----" << std::endl;
141   std::cout << std::endl;
142 #endif
143
144   std::string aFeatureKind = aBaseFeature->getKind();
145   FeaturePtr aSplitFeature, anAfterFeature;
146   std::set<AttributePoint2DPtr> aFurtherCoincidences;
147   std::set<FeaturePtr> aCreatedFeatures;
148   if (aFeatureKind == SketchPlugin_Line::ID())
149     splitLine(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
150   else if (aFeatureKind == SketchPlugin_Arc::ID())
151     splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
152   if (aFeatureKind == SketchPlugin_Circle::ID()) {
153     FeaturePtr aCircleFeature = aBaseFeature;
154     splitCircle(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences, aCreatedFeatures);
155     aFeaturesToDelete.insert(aCircleFeature);
156     aBaseObjectAttr->setObject(ResultPtr()); // as circle is removed, temporary fill this attribute
157   }
158
159 #ifdef DEBUG_SPLIT
160   std::cout << "OUT PARAMETERS" << std::endl;
161   std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
162   std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
163   std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
164   std::cout << std::endl;
165
166   std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
167   std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
168                                        aFLast = aCreatedFeatures.end();
169   for (; aFIt != aFLast; aFIt++) {
170     std::cout << getFeatureInfo(*aFIt) << std::endl;
171   }
172   std::cout << std::endl;
173
174   std::cout << "Attributes for further Coincidences:" << std::endl;
175   std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
176                                                 aLast = aFurtherCoincidences.end();
177   for (; anIt != aLast; anIt++) {
178     AttributePtr anAttribute = *anIt;
179     FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
180     std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
181               << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
182   }
183 #endif
184
185   std::set<ResultPtr> aFeatureResults;
186   aFeatureResults.insert(getFeatureResult(aBaseFeature));
187   if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
188     aFeatureResults.insert(getFeatureResult(anAfterFeature));
189
190   // coincidence to feature
191   updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
192                                         aFeatureResults);
193   // coincidence to points
194   updateCoincidenceConstraintsToFeature(aCoincidenceToPoint, aFurtherCoincidences,
195                                         std::set<ResultPtr>());
196   // TODO
197   // tangency
198   // TODO
199
200   // delete constraints
201 #ifdef DEBUG_SPLIT
202   std::cout << "remove features and references:" << std::endl;
203   std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
204                                        aDLast = aFeaturesToDelete.end();
205   for (; aDIt != aDLast; aDIt++) {
206     std::cout << getFeatureInfo(*aDIt, false) << std::endl;
207     std::cout << std::endl;
208   }
209 #endif
210   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
211
212   // Send events to update the sub-features by the solver.
213   if(isUpdateFlushed) {
214     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
215   }
216
217 #ifdef DEBUG_SPLIT
218   std::cout << "SKETCH FEATURES (after split):" << std::endl;
219   for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
220     std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
221     std::cout << std::endl;
222   }
223 #endif
224 }
225
226 bool SketchPlugin_ConstraintSplit::isMacro() const
227 {
228   return true;
229 }
230
231 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_ConstraintSplit::getPointOfRefAttr(
232                                                                   const AttributePtr& theAttribute)
233 {
234   AttributePoint2DPtr aPointAttribute;
235
236   if (theAttribute->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
237     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
238     if (aRefAttr.get() && aRefAttr->isInitialized()) {
239       AttributePtr anAttribute = aRefAttr->attr();
240       if (anAttribute.get() && anAttribute->attributeType() == GeomDataAPI_Point2D::typeId())
241         aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
242     }
243   }
244   return aPointAttribute;
245 }
246
247 void SketchPlugin_ConstraintSplit::getFeaturePoints(AttributePoint2DPtr& theStartPointAttr,
248                                                     AttributePoint2DPtr& theEndPointAttr)
249 {
250   AttributePoint2DPtr aPointAttribute;
251
252   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
253                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
254   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
255
256   std::string aFeatureKind = aBaseFeature->getKind();
257   std::string aStartAttributeName, anEndAttributeName;
258   if (aFeatureKind == SketchPlugin_Line::ID()) {
259     aStartAttributeName = SketchPlugin_Line::START_ID();
260     anEndAttributeName = SketchPlugin_Line::END_ID();
261   }
262   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
263     aStartAttributeName = SketchPlugin_Arc::START_ID();
264     anEndAttributeName = SketchPlugin_Arc::END_ID();
265   }
266   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
267     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
268                                                          aBaseFeature->attribute(aStartAttributeName));
269     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
270                                                          aBaseFeature->attribute(anEndAttributeName));
271   }
272 }
273
274 void SketchPlugin_ConstraintSplit::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
275                                       std::map<FeaturePtr, IdToPointPair>& theTangentFeatures,
276                                       std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature,
277                                       std::map<FeaturePtr, IdToPointPair>& theCoincidenceToPoint)
278 {
279   std::shared_ptr<ModelAPI_Data> aData = data();
280
281   // Check the base objects are initialized.
282   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
283                                             aData->attribute(SketchPlugin_Constraint::VALUE()));
284   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
285   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
286
287   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
288   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
289   aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
290
291   std::set<AttributePtr>::const_iterator aIt;
292   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
293     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
294     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
295     std::string aRefFeatureKind = aRefFeature->getKind();
296     if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
297         aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
298         aRefFeatureKind == SketchPlugin_MultiTranslation::ID())
299       theFeaturesToDelete.insert(aRefFeature);
300     else if (aRefFeatureKind == SketchPlugin_ConstraintTangent::ID()) {
301       if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) /// TEMPORARY limitaion
302         theFeaturesToDelete.insert(aRefFeature); /// until tangency between arc and line is implemented
303       else {
304         std::string anAttributeToBeModified;
305         AttributePoint2DPtr aTangentPoint;
306         ObjectPtr aResult1 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A())->object();
307         ObjectPtr aResult2 = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B())->object();
308         if (aResult1.get() && aResult2.get()) {
309           FeaturePtr aCoincidenceFeature = SketchPlugin_ConstraintCoincidence::findCoincidenceFeature
310                                                                     (ModelAPI_Feature::feature(aResult1),
311                                                                      ModelAPI_Feature::feature(aResult2));
312           aTangentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aCoincidenceFeature);
313         }
314         if (aTangentPoint.get()) {
315           FeaturePtr aFeature1 = ModelAPI_Feature::feature(aResult1);
316           std::string anAttributeToBeModified = aFeature1 == aBaseFeature
317                        ? SketchPlugin_Constraint::ENTITY_B() : SketchPlugin_Constraint::ENTITY_A();
318           theTangentFeatures[aRefFeature] = std::make_pair(anAttributeToBeModified, aTangentPoint);
319         }
320         else
321           theFeaturesToDelete.insert(aRefFeature); /// there is not coincident point between tangent constraint
322       }
323     }
324     else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
325       std::string anAttributeToBeModified;
326       AttributePoint2DPtr aCoincidentPoint;
327       AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
328       AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
329       bool isToFeature = false;
330       if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
331         FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
332                                                   : FeaturePtr();
333         isToFeature = aFeature.get() && aFeature == aBaseFeature;
334         anAttributeToBeModified = anAttrA->id();
335         if (!isToFeature) {
336           aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
337                                          : FeaturePtr();
338           isToFeature = aFeature.get() && aFeature == aBaseFeature;
339           anAttributeToBeModified = anAttrB->id();
340         }
341         if (isToFeature)
342           aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
343       }
344       if (!isToFeature) { /// coincidence to point on base feature
345         AttributePtr anAttribute;
346
347         if (!anAttrA->isObject()) {
348           AttributePtr aCurAttribute = anAttrA->attr();
349           if (aCurAttribute.get()) {
350             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
351             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
352               anAttribute = anAttrA->attr();
353               anAttributeToBeModified = anAttrA->id();
354             }
355           }
356         }
357         if (!anAttribute.get() && !anAttrB->isObject()) {
358           AttributePtr aCurAttribute = anAttrB->attr();
359           if (aCurAttribute.get()) {
360             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
361             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
362               anAttribute = anAttrB->attr();
363               anAttributeToBeModified = anAttrB->id();
364             }
365           }
366         }
367         if (anAttribute.get())
368           aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
369       }
370       if (aCoincidentPoint.get()) {
371         if (isToFeature)
372           theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
373                                                                 aCoincidentPoint);
374         else
375           theCoincidenceToPoint[aRefFeature] = std::make_pair(anAttributeToBeModified,
376                                                               aCoincidentPoint);
377       }
378       else
379         theFeaturesToDelete.insert(aRefFeature); /// this case should not happen
380     }
381   }
382 }
383
384 void SketchPlugin_ConstraintSplit::updateCoincidenceConstraintsToFeature(
385       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
386       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
387       const std::set<ResultPtr>& theFeatureResults)
388 {
389   if (theCoincidenceToFeature.empty())
390     return;
391
392   std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
393                                                             aCLast = theCoincidenceToFeature.end();
394 #ifdef DEBUG_SPLIT
395   std::cout << std::endl;
396   std::cout << "Coincidences to feature(modified):"<< std::endl;
397 #endif
398   for (; aCIt != aCLast; aCIt++) {
399     FeaturePtr aCoincFeature = aCIt->first;
400     std::string anAttributeId = aCIt->second.first;
401     AttributePoint2DPtr aCoincPoint = aCIt->second.second;
402     std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
403                                                   aFCLast = theFurtherCoincidences.end();
404     std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
405     AttributePoint2DPtr aFeaturePointAttribute;
406     for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
407       AttributePoint2DPtr aFCAttribute = *aFCIt;
408       if (aCoincPnt->isEqual(aFCAttribute->pnt()))
409         aFeaturePointAttribute = aFCAttribute;
410     }
411     if (aFeaturePointAttribute.get()) {
412       aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
413     }
414     else {
415       /// find feature by shape intersected the point
416       ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
417
418       if (theFeatureResults.size() > 1) { // try to find point on additional feature
419         ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
420         GeomShapePtr aShape = anAddtionalResult->shape();
421
422         std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
423         std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
424
425         std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
426         if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
427           aResultForCoincidence = anAddtionalResult;
428       }
429       aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
430     }
431 #ifdef DEBUG_SPLIT
432   std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
433 #endif
434   }
435 }
436
437 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
438                                              FeaturePtr& theBaseFeatureModified,
439                                              FeaturePtr& theAfterFeature,
440                                              std::set<AttributePoint2DPtr>& thePoints,
441                                              std::set<FeaturePtr>& theCreatedFeatures)
442 {
443   std::set<FeaturePtr> aCreatedFeatures;
444   FeaturePtr aConstraintFeature;
445   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
446
447   SketchPlugin_Sketch* aSketch = sketch();
448   if (!aSketch)
449     return;
450
451   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
452                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
453   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
454   std::string aFeatureKind = aBaseFeature->getKind();
455   if (aFeatureKind != SketchPlugin_Line::ID())
456     return;
457
458   AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
459   AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
460   AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
461   getFeaturePoints(aStartPointAttr, anEndPointAttr);
462   if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
463     setError("Error: Feature has no start and end points.");
464     return;
465   }
466
467   arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
468
469   /// split feature
470   theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
471   theCreatedFeatures.insert(theSplitFeature);
472
473   // before split feature
474   if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
475     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
476     /// move end arc point to start of split
477   }
478
479   // after split feature
480   if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
481     FeaturePtr aFeature;
482     if (!theBaseFeatureModified.get()) {
483       aFeature = aBaseFeature; ///< use base feature to store all constraints here
484       fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttr);
485       aFeature->execute(); // to update result
486     }
487     else {
488       aFeature = createLineFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
489       theCreatedFeatures.insert(aFeature);
490     }
491     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
492                      theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
493                      aFeature->attribute(SketchPlugin_Line::START_ID()));
494     theCreatedFeatures.insert(aConstraintFeature);
495
496     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
497                                 (aFeature->attribute(SketchPlugin_Line::START_ID())));
498     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
499                                 (aFeature->attribute(SketchPlugin_Line::END_ID())));
500
501     if (!theBaseFeatureModified.get())
502       theBaseFeatureModified = aFeature;
503     else
504       theAfterFeature = aFeature;
505   }
506   else
507     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
508                                   (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
509
510   // base split, that is defined before split feature should be changed at end
511   // (after the after feature creation). Otherwise modified value will be used in after feature
512   // before split feature
513   if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
514     /// move end arc point to start of split
515     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttr);
516     theBaseFeatureModified->execute(); // to update result
517     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
518                      theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
519                      theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
520     theCreatedFeatures.insert(aConstraintFeature);
521
522     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
523                              (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
524     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
525                                (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
526   }
527   else
528     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
529                                        (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
530
531   // additional constraints between split and base features
532   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
533                                                        getFeatureResult(aBaseFeature),
534                                                        getFeatureResult(theSplitFeature));
535   theCreatedFeatures.insert(aConstraintFeature);
536   if (theAfterFeature.get()) {
537     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
538                                                     getFeatureResult(aBaseFeature),
539                                                     getFeatureResult(theAfterFeature));
540     theCreatedFeatures.insert(aConstraintFeature);
541   }
542 }
543
544 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
545                                             FeaturePtr& theBaseFeatureModified,
546                                             FeaturePtr& theAfterFeature,
547                                             std::set<AttributePoint2DPtr>& thePoints,
548                                             std::set<FeaturePtr>& theCreatedFeatures)
549 {
550   std::set<FeaturePtr> aCreatedFeatures;
551   FeaturePtr aConstraintFeature;
552   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
553
554   SketchPlugin_Sketch* aSketch = sketch();
555   if (!aSketch)
556     return;
557
558   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
559                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
560   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
561   std::string aFeatureKind = aBaseFeature->getKind();
562   if (aFeatureKind != SketchPlugin_Arc::ID())
563     return;
564
565   AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
566   AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
567   AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
568   getFeaturePoints(aStartPointAttr, anEndPointAttr);
569   if (!aStartPointAttr.get() && !anEndPointAttr.get()) {
570     setError("Error: Feature has no start and end points.");
571     return;
572   }
573
574   arrangePoints(aStartPointAttr, anEndPointAttr, aFirstPointAttr, aSecondPointAttr);
575
576   /// split feature
577   theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
578   theCreatedFeatures.insert(theSplitFeature);
579
580   // before split feature
581   if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
582     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
583     /// move end arc point to start of split
584   }
585
586   // after split feature
587   if (!aSecondPointAttr->pnt()->isEqual(anEndPointAttr->pnt())) {
588     FeaturePtr aFeature;
589     if (!theBaseFeatureModified.get()) {
590       aFeature = aBaseFeature; ///< use base feature to store all constraints here
591       fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttr);
592       aFeature->execute(); // to update result
593     }
594     else {
595       aFeature = createArcFeature(aBaseFeature, aSecondPointAttr, anEndPointAttr);
596       theCreatedFeatures.insert(aFeature);
597     }
598     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
599                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
600                      aFeature->attribute(SketchPlugin_Arc::START_ID()));
601     theCreatedFeatures.insert(aConstraintFeature);
602
603     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
604                                 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
605     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
606                                 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
607
608     if (!theBaseFeatureModified.get())
609       theBaseFeatureModified = aFeature;
610     else
611       theAfterFeature = aFeature;
612   }
613   else
614     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
615                                   (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
616
617   // base split, that is defined before split feature should be changed at end
618   // (after the after feature creation). Otherwise modified value will be used in after feature
619   // before split feature
620   if (!aStartPointAttr->pnt()->isEqual(aFirstPointAttr->pnt())) {
621     /// move end arc point to start of split
622     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttr);
623     theBaseFeatureModified->execute(); // to update result
624     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
625                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
626                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
627     theCreatedFeatures.insert(aConstraintFeature);
628
629     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
630                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
631     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
632                                (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
633   }
634   else
635     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
636                                        (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
637
638   // additional constraints between split and base features
639   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
640                                                        getFeatureResult(aBaseFeature),
641                                                        getFeatureResult(theSplitFeature));
642   theCreatedFeatures.insert(aConstraintFeature);
643   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
644                                                        getFeatureResult(theSplitFeature),
645                                                        getFeatureResult(aBaseFeature));
646   theCreatedFeatures.insert(aConstraintFeature);
647   if (theAfterFeature.get()) {
648     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
649                                                     getFeatureResult(aBaseFeature),
650                                                     getFeatureResult(theAfterFeature));
651     theCreatedFeatures.insert(aConstraintFeature);
652     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
653                                                     getFeatureResult(theSplitFeature),
654                                                     getFeatureResult(theAfterFeature));
655     theCreatedFeatures.insert(aConstraintFeature);
656   }
657 }
658
659 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
660                                                FeaturePtr& theBaseFeatureModified,
661                                                FeaturePtr& theAfterFeature,
662                                                std::set<AttributePoint2DPtr>& thePoints,
663                                                std::set<FeaturePtr>& theCreatedFeatures)
664 {
665   std::set<FeaturePtr> aCreatedFeatures;
666   FeaturePtr aConstraintFeature;
667   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
668
669   SketchPlugin_Sketch* aSketch = sketch();
670   if (!aSketch)
671     return;
672
673   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
674                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
675   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
676   std::string aFeatureKind = aBaseFeature->getKind();
677   if (aFeatureKind != SketchPlugin_Circle::ID())
678     return;
679
680   AttributePoint2DPtr aFirstPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
681   AttributePoint2DPtr aSecondPointAttr = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
682
683   /// split feature
684   theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
685   bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
686   theCreatedFeatures.insert(theSplitFeature);
687
688   /// base feature is a left part of the circle
689   theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttr, aSecondPointAttr);
690   std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
691   theBaseFeatureModified->execute();
692   theCreatedFeatures.insert(theBaseFeatureModified);
693
694   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
695                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
696   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
697                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
698
699   // additional constraints between split and base features
700   aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
701                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
702                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
703   theCreatedFeatures.insert(aConstraintFeature);
704   aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
705                      theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
706                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
707   theCreatedFeatures.insert(aConstraintFeature);
708
709   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
710                                                        getFeatureResult(theSplitFeature),
711                                                        getFeatureResult(theBaseFeatureModified));
712   theCreatedFeatures.insert(aConstraintFeature);
713 }
714
715 void SketchPlugin_ConstraintSplit::arrangePoints(const AttributePoint2DPtr& theStartPointAttr,
716                                                  const AttributePoint2DPtr& theEndPointAttr,
717                                                  AttributePoint2DPtr& theFirstPointAttr,
718                                                  AttributePoint2DPtr& theLastPointAttr)
719 {
720   /// if first point is closer to last point, wrap first and last values
721   if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
722       theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
723     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
724     theFirstPointAttr = theLastPointAttr;
725     theLastPointAttr = aTmpPoint;
726   }
727 }
728
729 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
730                                                  const AttributePtr& theSourceAttribute)
731 {
732   AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
733                                             theModifiedAttribute);
734   AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
735                                             theSourceAttribute);
736
737   if (aModifiedAttribute.get() && aSourceAttribute.get())
738     aModifiedAttribute->setValue(aSourceAttribute->pnt());
739 }
740
741 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
742                                                            const AttributePtr& theFirstPointAttr,
743                                                            const AttributePtr& theSecondPointAttr)
744 {
745   FeaturePtr aFeature;
746   SketchPlugin_Sketch* aSketch = sketch();
747   if (!aSketch || !theBaseFeature.get())
748     return aFeature;
749
750   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
751   // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
752   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
753   aFeature->data()->blockSendAttributeUpdated(true);
754
755   fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
756   fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
757   aFeature->data()->blockSendAttributeUpdated(false);
758   aFeature->execute(); // to obtain result
759
760   return aFeature;
761 }
762
763 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
764                                                           const AttributePtr& theFirstPointAttr,
765                                                           const AttributePtr& theSecondPointAttr)
766 {
767   FeaturePtr aFeature;
768   SketchPlugin_Sketch* aSketch = sketch();
769   if (!aSketch || !theBaseFeature.get())
770     return aFeature;
771
772   std::string aCenterAttributeId;
773   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
774     aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
775   else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
776     aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
777
778   if (aCenterAttributeId.empty())
779     return aFeature;
780
781   aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
782   // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
783   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
784   aFeature->data()->blockSendAttributeUpdated(true);
785
786   aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
787                 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
788
789   fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
790                 theBaseFeature->attribute(aCenterAttributeId));
791   fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
792   fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
793   aFeature->data()->blockSendAttributeUpdated(false);
794   aFeature->execute(); // to obtain result
795
796   return aFeature;
797 }
798
799 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
800                                                     const AttributePtr& theFirstAttribute,
801                                                     const AttributePtr& theSecondAttribute)
802 {
803   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
804   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
805                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
806   aRefAttr->setAttr(theFirstAttribute);
807
808   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
809                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
810   aRefAttr->setAttr(theSecondAttribute);
811
812   return aConstraint;
813 }
814
815 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
816                                                     const ObjectPtr& theFirstObject,
817                                                     const ObjectPtr& theSecondObject)
818 {
819   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
820   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
821                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
822   aRefAttr->setObject(theFirstObject);
823
824   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
825                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
826   aRefAttr->setObject(theSecondObject);
827
828   return aConstraint;
829 }
830
831 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
832                                     const std::shared_ptr<ModelAPI_Feature>& theFeature)
833 {
834   std::shared_ptr<ModelAPI_Result> aResult;
835
836   std::string aFeatureKind = theFeature->getKind();
837   if (aFeatureKind == SketchPlugin_Line::ID())
838     aResult = theFeature->firstResult();
839   else if (aFeatureKind == SketchPlugin_Arc::ID())
840     aResult = theFeature->lastResult();
841   else if (aFeatureKind == SketchPlugin_Circle::ID())
842     aResult = theFeature->lastResult();
843
844   return aResult;
845 }
846
847 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
848                                            const std::shared_ptr<ModelAPI_Feature>& theFeature)
849 {
850   std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
851
852   std::string aFeatureKind = theFeature->getKind();
853   if (aFeatureKind == SketchPlugin_Line::ID()) {
854     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
855     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
856   }
857   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
858     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
859     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
860   }
861   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
862   }
863
864   return anAttributes;
865 }
866
867
868 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
869                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
870                                                const bool isUseAttributesInfo)
871 {
872   std::string anInfo;
873   if (!theFeature.get()) {
874     return "none";
875   }
876
877   //anInfo.append(theFeature->getKind().c_str());
878   if (theFeature->data()->isValid()) {
879     //anInfo.append(", name=");
880     anInfo.append(theFeature->data()->name().c_str());
881   }
882   if (isUseAttributesInfo) {
883     std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
884                                                              getEdgeAttributes(theFeature));
885     if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
886       anInfo += ": ";
887       anInfo += "\n";
888       anInfo += aPointsInfo;
889     }
890     else { /// process constraint coincidence, find points in ref attr attributes
891       std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
892                                                                 ModelAPI_AttributeRefAttr::typeId());
893       std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
894       std::string anAttributesInfo;
895       for(; anIt != aLast; anIt++) {
896         if (!anAttributesInfo.empty()) {
897           anAttributesInfo.append(", ");
898           anAttributesInfo += "\n";
899         }
900         AttributePtr anAttr = *anIt;
901         std::string aValue = "not defined";
902         std::string aType = anAttr->attributeType();
903         if (aType == ModelAPI_AttributeRefAttr::typeId()) {
904           std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
905                                         std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
906           if (aRefAttr.get()) {
907             if (aRefAttr->isObject()) {
908               FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
909               aValue = "<object:>" + getFeatureInfo(aFeature, false);
910             }
911             else {
912               AttributePtr anAttribute = aRefAttr->attr();
913               if (anAttribute.get()) {
914                 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
915                 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
916                          " [" + getFeatureInfo(aFeature, false) + "]";
917               }
918             }
919           }
920         }
921         anAttributesInfo.append("    " + anAttr->id() + ": " + aValue);
922       }
923       if (!anAttributesInfo.empty())
924         anInfo = anInfo + "\n" + anAttributesInfo;
925     }
926   }
927   return anInfo;
928 }
929