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