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