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