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