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