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