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