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