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