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