Salome HOME
Disable sketch input fields unconditionally.
[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)->setObject(ResultPtr());
534       aCoincFeature->refattr(anAttributeId)->setAttr(aFeaturePointAttribute);
535     }
536     else {
537       /// find feature by shape intersected the point
538       ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
539
540       if (theFeatureResults.size() > 1) { // try to find point on additional feature
541         ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
542         GeomShapePtr aShape = anAddtionalResult->shape();
543
544         std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
545         std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
546
547         std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
548         if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
549           aResultForCoincidence = anAddtionalResult;
550       }
551       aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
552     }
553 #ifdef DEBUG_SPLIT
554   std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
555 #endif
556   }
557 }
558
559 void SketchPlugin_ConstraintSplit::updateTangentConstraintsToFeature(
560       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theTangentFeatures,
561       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences)
562 {
563   if (theTangentFeatures.empty())
564     return;
565
566   std::map<FeaturePtr, IdToPointPair>::const_iterator aTIt = theTangentFeatures.begin(),
567                                                       aTLast = theTangentFeatures.end();
568 #ifdef DEBUG_SPLIT
569   std::cout << std::endl;
570   std::cout << "Tangencies to feature(modified):"<< std::endl;
571 #endif
572   for (; aTIt != aTLast; aTIt++) {
573     FeaturePtr aTangentFeature = aTIt->first;
574     std::string anAttributeId = aTIt->second.first;
575     AttributePoint2DPtr aTangentPoint = aTIt->second.second;
576     std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
577                                                   aFCLast = theFurtherCoincidences.end();
578     std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aTangentPoint->pnt();
579     AttributePoint2DPtr aFeaturePointAttribute;
580     /// here we rely on created coincidence between further coincidence point and tangent result
581     for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
582       AttributePoint2DPtr aFCAttribute = *aFCIt;
583       if (aCoincPnt->isEqual(aFCAttribute->pnt()))
584         aFeaturePointAttribute = aFCAttribute;
585     }
586     if (aFeaturePointAttribute.get()) {
587       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aFeaturePointAttribute->owner());
588       aTangentFeature->refattr(anAttributeId)->setObject(getFeatureResult(aFeature));
589     }
590 #ifdef DEBUG_SPLIT
591   std::cout << " -" << getFeatureInfo(aTangentFeature) << std::endl;
592 #endif
593   }
594 }
595
596 void SketchPlugin_ConstraintSplit::updateRefAttConstraints(
597                       const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
598                       const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
599 {
600 #ifdef DEBUG_SPLIT
601   std::cout << "SketchPlugin_ConstraintSplit::updateRefAttConstraints" << std::endl;
602 #endif
603
604   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator anIt = theModifiedAttributes.begin(),
605                                                                    aLast = theModifiedAttributes.end();
606   for (; anIt != aLast; anIt++) {
607     AttributePtr anAttribute = anIt->first;
608
609     if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end()) /// not found in references
610       continue;
611     std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
612     std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
613                                             aRLast = aRefAttributes.end();
614
615     AttributePtr aNewAttribute = anIt->second;
616     for (; aRefIt != aRLast; aRefIt++) {
617       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
618       if (aRefAttr.get()) {
619         aRefAttr->setAttr(aNewAttribute);
620 #ifdef DEBUG_SPLIT
621         FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
622         std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
623 #endif
624       }
625     }
626   }
627 }
628
629 void SketchPlugin_ConstraintSplit::splitLine(FeaturePtr& theSplitFeature,
630                                              FeaturePtr& theBaseFeatureModified,
631                                              FeaturePtr& theAfterFeature,
632                                              std::set<AttributePoint2DPtr>& thePoints,
633                                              std::set<FeaturePtr>& theCreatedFeatures,
634                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
635 {
636   std::set<FeaturePtr> aCreatedFeatures;
637   FeaturePtr aConstraintFeature;
638   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
639
640   SketchPlugin_Sketch* aSketch = sketch();
641   if (!aSketch)
642     return;
643
644   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
645                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
646   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
647   std::string aFeatureKind = aBaseFeature->getKind();
648   if (aFeatureKind != SketchPlugin_Line::ID())
649     return;
650
651   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
652   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
653   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
654   getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase);
655   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
656     setError("Error: Feature has no start and end points.");
657     return;
658   }
659
660   arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
661
662 #ifdef DEBUG_SPLIT
663   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
664   std::cout << "Start point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
665   std::cout << "1st point:   " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
666   std::cout << "2nd point:   " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
667   std::cout << "End point:   " << ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
668 #endif
669
670   /// create a split feature
671   theSplitFeature = createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
672   theCreatedFeatures.insert(theSplitFeature);
673
674   // before split feature
675   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
676     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
677                                                 theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
678   }
679   else {
680     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
681     /// move end arc point to start of split
682   }
683
684   // after split feature
685   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
686     FeaturePtr aFeature;
687     if (!theBaseFeatureModified.get()) {
688       aFeature = aBaseFeature; ///< use base feature to store all constraints here
689       fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
690       aFeature->execute(); // to update result
691     }
692     else {
693       aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
694       theCreatedFeatures.insert(aFeature);
695       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
696                                                   aFeature->attribute(SketchPlugin_Line::END_ID())));
697     }
698     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
699                      theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
700                      aFeature->attribute(SketchPlugin_Line::START_ID()));
701     theCreatedFeatures.insert(aConstraintFeature);
702
703     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
704                                 (aFeature->attribute(SketchPlugin_Line::START_ID())));
705     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
706                                 (aFeature->attribute(SketchPlugin_Line::END_ID())));
707
708     if (!theBaseFeatureModified.get())
709       theBaseFeatureModified = aFeature;
710     else
711       theAfterFeature = aFeature;
712   }
713   else {
714     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
715                                   (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
716     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
717                                                 theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
718   }
719   // base split, that is defined before split feature should be changed at end
720   // (after the after feature creation). Otherwise modified value will be used in after feature
721   // before split feature
722   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
723     /// move end arc point to start of split
724     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()), aFirstPointAttrOfSplit);
725     theBaseFeatureModified->execute(); // to update result
726     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
727                      theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
728                      theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
729     theCreatedFeatures.insert(aConstraintFeature);
730
731     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
732                              (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
733     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
734                                (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
735   }
736   else
737     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
738                                        (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
739
740   // additional constraints between split and base features
741   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
742                                                        getFeatureResult(aBaseFeature),
743                                                        getFeatureResult(theSplitFeature));
744   theCreatedFeatures.insert(aConstraintFeature);
745   if (theAfterFeature.get()) {
746     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintParallel::ID(),
747                                                     getFeatureResult(aBaseFeature),
748                                                     getFeatureResult(theAfterFeature));
749     theCreatedFeatures.insert(aConstraintFeature);
750   }
751 }
752
753 void SketchPlugin_ConstraintSplit::splitArc(FeaturePtr& theSplitFeature,
754                                             FeaturePtr& theBaseFeatureModified,
755                                             FeaturePtr& theAfterFeature,
756                                             std::set<AttributePoint2DPtr>& thePoints,
757                                             std::set<FeaturePtr>& theCreatedFeatures,
758                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
759 {
760   std::set<FeaturePtr> aCreatedFeatures;
761   FeaturePtr aConstraintFeature;
762   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
763
764   SketchPlugin_Sketch* aSketch = sketch();
765   if (!aSketch)
766     return;
767
768   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
769                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
770   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
771   std::string aFeatureKind = aBaseFeature->getKind();
772   if (aFeatureKind != SketchPlugin_Arc::ID())
773     return;
774
775   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
776   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
777   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
778   getFeaturePoints(aStartPointAttrOfBase, anEndPointAttrOfBase);
779   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
780     setError("Error: Feature has no start and end points.");
781     return;
782   }
783
784   // manually change type of arc to avoid incorrect self-constrainting of the tangent arc
785   aBaseFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
786       SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
787
788   arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
789                      aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
790 #ifdef DEBUG_SPLIT
791   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
792   std::cout << "Start point: " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
793   std::cout << "1st point:   " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
794   std::cout << "2nd point:   " << ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
795   std::cout << "End point:   " << ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
796 #endif
797
798   /// split feature
799   theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
800   theCreatedFeatures.insert(theSplitFeature);
801
802   // before split feature
803   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
804     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
805                                                 theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
806   }
807   else {
808     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
809     /// move end arc point to start of split
810   }
811
812   // after split feature
813   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
814     FeaturePtr aFeature;
815     if (!theBaseFeatureModified.get()) {
816       aFeature = aBaseFeature; ///< use base feature to store all constraints here
817       fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
818       aFeature->execute(); // to update result
819     }
820     else {
821       aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
822       theCreatedFeatures.insert(aFeature);
823       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
824                                                   aFeature->attribute(SketchPlugin_Arc::END_ID())));
825     }
826     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
827                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
828                      aFeature->attribute(SketchPlugin_Arc::START_ID()));
829     theCreatedFeatures.insert(aConstraintFeature);
830
831     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
832                                 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
833     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
834                                 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
835
836     if (!theBaseFeatureModified.get())
837       theBaseFeatureModified = aFeature;
838     else
839       theAfterFeature = aFeature;
840   }
841   else {
842     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
843                                   (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
844     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
845                                    theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
846   }
847   // base split, that is defined before split feature should be changed at end
848   // (after the after feature creation). Otherwise modified value will be used in after feature
849   // before split feature
850   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
851     /// move end arc point to start of split
852     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()), aFirstPointAttrOfSplit);
853     theBaseFeatureModified->execute(); // to update result
854     aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
855                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
856                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
857     theCreatedFeatures.insert(aConstraintFeature);
858
859     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
860                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
861     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
862                                (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
863   }
864   else
865     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
866                                        (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
867
868   // additional constraints between split and base features
869   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
870                                                        getFeatureResult(aBaseFeature),
871                                                        getFeatureResult(theSplitFeature));
872   theCreatedFeatures.insert(aConstraintFeature);
873   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
874                                                        getFeatureResult(theSplitFeature),
875                                                        getFeatureResult(aBaseFeature));
876   theCreatedFeatures.insert(aConstraintFeature);
877   if (theAfterFeature.get()) {
878     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintEqual::ID(),
879                                                     getFeatureResult(aBaseFeature),
880                                                     getFeatureResult(theAfterFeature));
881     theCreatedFeatures.insert(aConstraintFeature);
882     aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
883                                                     getFeatureResult(theSplitFeature),
884                                                     getFeatureResult(theAfterFeature));
885     theCreatedFeatures.insert(aConstraintFeature);
886   }
887 }
888
889 void SketchPlugin_ConstraintSplit::splitCircle(FeaturePtr& theSplitFeature,
890                                                FeaturePtr& theBaseFeatureModified,
891                                                FeaturePtr& theAfterFeature,
892                                                std::set<AttributePoint2DPtr>& thePoints,
893                                                std::set<FeaturePtr>& theCreatedFeatures,
894                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
895 {
896   std::set<FeaturePtr> aCreatedFeatures;
897   FeaturePtr aConstraintFeature;
898   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
899
900   SketchPlugin_Sketch* aSketch = sketch();
901   if (!aSketch)
902     return;
903
904   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
905                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
906   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
907   std::string aFeatureKind = aBaseFeature->getKind();
908   if (aFeatureKind != SketchPlugin_Circle::ID())
909     return;
910
911   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
912   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
913
914   /// split feature
915   theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
916   bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
917   theCreatedFeatures.insert(theSplitFeature);
918
919   /// base feature is a left part of the circle
920   theBaseFeatureModified = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
921   std::dynamic_pointer_cast<SketchPlugin_Arc>(theBaseFeatureModified)->setReversed(!aSplitReversed);
922   theBaseFeatureModified->execute();
923
924   theModifiedAttributes.insert(std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
925                                               theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
926
927   theCreatedFeatures.insert(theBaseFeatureModified);
928
929   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
930                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
931   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
932                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
933
934   // additional constraints between split and base features
935   aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
936                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
937                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
938   theCreatedFeatures.insert(aConstraintFeature);
939   aConstraintFeature = createConstraint(SketchPlugin_ConstraintCoincidence::ID(),
940                      theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
941                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
942   theCreatedFeatures.insert(aConstraintFeature);
943
944   aConstraintFeature = createConstraintForObjects(SketchPlugin_ConstraintTangent::ID(),
945                                                        getFeatureResult(theSplitFeature),
946                                                        getFeatureResult(theBaseFeatureModified));
947   theCreatedFeatures.insert(aConstraintFeature);
948 }
949
950 void SketchPlugin_ConstraintSplit::arrangePointsOnLine(
951     const AttributePoint2DPtr& theStartPointAttr,
952     const AttributePoint2DPtr& theEndPointAttr,
953     AttributePoint2DPtr& theFirstPointAttr,
954     AttributePoint2DPtr& theLastPointAttr) const
955 {
956   // if first point is closer to last point, swap first and last values
957   if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
958       theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
959     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
960     theFirstPointAttr = theLastPointAttr;
961     theLastPointAttr = aTmpPoint;
962   }
963 }
964
965 void SketchPlugin_ConstraintSplit::arrangePointsOnArc(
966     const FeaturePtr& theArc,
967     const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
968     const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
969     std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
970     std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
971 {
972   static const double anAngleTol = 1.e-12;
973
974   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
975       theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
976   bool isReversed = theArc->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
977
978   // collect directions to each point
979   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
980       new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
981   std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
982       new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
983   std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
984       new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
985
986   // sort points by their angular values
987   double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
988   double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
989   double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
990   if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
991     aFirstPtAngle += aPeriod;
992   if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
993     aSecondPtAngle += aPeriod;
994
995   if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
996     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
997     theFirstPointAttr = theSecondPointAttr;
998     theSecondPointAttr = aTmpPoint;
999   }
1000 }
1001
1002 void SketchPlugin_ConstraintSplit::fillAttribute(const AttributePtr& theModifiedAttribute,
1003                                                  const AttributePtr& theSourceAttribute)
1004 {
1005   AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1006                                             theModifiedAttribute);
1007   AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1008                                             theSourceAttribute);
1009
1010   if (aModifiedAttribute.get() && aSourceAttribute.get())
1011     aModifiedAttribute->setValue(aSourceAttribute->pnt());
1012 }
1013
1014 FeaturePtr SketchPlugin_ConstraintSplit::createLineFeature(const FeaturePtr& theBaseFeature,
1015                                                            const AttributePtr& theFirstPointAttr,
1016                                                            const AttributePtr& theSecondPointAttr)
1017 {
1018   FeaturePtr aFeature;
1019   SketchPlugin_Sketch* aSketch = sketch();
1020   if (!aSketch || !theBaseFeature.get())
1021     return aFeature;
1022
1023   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1024
1025   fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1026   fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1027   aFeature->execute(); // to obtain result
1028
1029   return aFeature;
1030 }
1031
1032 FeaturePtr SketchPlugin_ConstraintSplit::createArcFeature(const FeaturePtr& theBaseFeature,
1033                                                           const AttributePtr& theFirstPointAttr,
1034                                                           const AttributePtr& theSecondPointAttr)
1035 {
1036   FeaturePtr aFeature;
1037   SketchPlugin_Sketch* aSketch = sketch();
1038   if (!aSketch || !theBaseFeature.get())
1039     return aFeature;
1040
1041   std::string aCenterAttributeId;
1042   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1043     aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1044   else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1045     aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1046
1047   if (aCenterAttributeId.empty())
1048     return aFeature;
1049
1050   aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1051   // update fillet arc: make the arc correct for sure, so, it is not needed to process the "attribute updated"
1052   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1053   aFeature->data()->blockSendAttributeUpdated(true);
1054
1055   aFeature->string(SketchPlugin_Arc::ARC_TYPE())->setValue(
1056                 SketchPlugin_Arc::ARC_TYPE_CENTER_START_END());
1057
1058   fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1059                 theBaseFeature->attribute(aCenterAttributeId));
1060   fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1061   fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1062
1063   /// fill referersed state of created arc as it is on the base arc
1064   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1065     bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->value();
1066     aFeature->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue(aReversed);
1067   }
1068   aFeature->data()->blockSendAttributeUpdated(false);
1069   aFeature->execute(); // to obtain result
1070
1071   return aFeature;
1072 }
1073
1074 FeaturePtr SketchPlugin_ConstraintSplit::createConstraint(const std::string& theConstraintId,
1075                                                     const AttributePtr& theFirstAttribute,
1076                                                     const AttributePtr& theSecondAttribute)
1077 {
1078   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1079   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1080                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1081   aRefAttr->setAttr(theFirstAttribute);
1082
1083   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1084                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1085   aRefAttr->setAttr(theSecondAttribute);
1086
1087   return aConstraint;
1088 }
1089
1090 FeaturePtr SketchPlugin_ConstraintSplit::createConstraintForObjects(const std::string& theConstraintId,
1091                                                     const ObjectPtr& theFirstObject,
1092                                                     const ObjectPtr& theSecondObject)
1093 {
1094   FeaturePtr aConstraint = sketch()->addFeature(theConstraintId);
1095   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1096                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
1097   aRefAttr->setObject(theFirstObject);
1098
1099   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
1100                                  aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
1101   aRefAttr->setObject(theSecondObject);
1102
1103   return aConstraint;
1104 }
1105
1106 std::shared_ptr<ModelAPI_Result> SketchPlugin_ConstraintSplit::getFeatureResult(
1107                                     const std::shared_ptr<ModelAPI_Feature>& theFeature)
1108 {
1109   std::shared_ptr<ModelAPI_Result> aResult;
1110
1111   std::string aFeatureKind = theFeature->getKind();
1112   if (aFeatureKind == SketchPlugin_Line::ID())
1113     aResult = theFeature->firstResult();
1114   else if (aFeatureKind == SketchPlugin_Arc::ID())
1115     aResult = theFeature->lastResult();
1116   else if (aFeatureKind == SketchPlugin_Circle::ID())
1117     aResult = theFeature->lastResult();
1118
1119   return aResult;
1120 }
1121
1122 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_ConstraintSplit::getEdgeAttributes(
1123                                            const std::shared_ptr<ModelAPI_Feature>& theFeature)
1124 {
1125   std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1126
1127   std::string aFeatureKind = theFeature->getKind();
1128   if (aFeatureKind == SketchPlugin_Line::ID()) {
1129     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1130     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1131   }
1132   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1133     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1134     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1135   }
1136   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1137   }
1138
1139   return anAttributes;
1140 }
1141
1142
1143 std::string SketchPlugin_ConstraintSplit::getFeatureInfo(
1144                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
1145                                                const bool isUseAttributesInfo)
1146 {
1147   std::string anInfo;
1148   if (!theFeature.get()) {
1149     return "none";
1150   }
1151
1152   if (theFeature->data()->isValid())
1153     anInfo.append(theFeature->data()->name().c_str());
1154
1155   if (isUseAttributesInfo) {
1156     std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1157                                                              getEdgeAttributes(theFeature));
1158     if (!aPointsInfo.empty()) { /// processing of feature with point 2d attributes, like line, arc, circle
1159       anInfo += ": ";
1160       anInfo += "\n";
1161       anInfo += aPointsInfo;
1162     }
1163     else { /// process constraint coincidence, find points in ref attr attributes
1164       std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1165                                                                 ModelAPI_AttributeRefAttr::typeId());
1166       std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1167       std::string anAttributesInfo;
1168       for(; anIt != aLast; anIt++) {
1169         if (!anAttributesInfo.empty()) {
1170           anAttributesInfo.append(", ");
1171           anAttributesInfo += "\n";
1172         }
1173         AttributePtr anAttr = *anIt;
1174         std::string aValue = "not defined";
1175         std::string aType = anAttr->attributeType();
1176         if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1177           std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1178                                         std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1179           if (aRefAttr.get()) {
1180             if (aRefAttr->isObject()) {
1181               FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1182               aValue = "<object:>" + getFeatureInfo(aFeature, false);
1183             }
1184             else {
1185               AttributePtr anAttribute = aRefAttr->attr();
1186               if (anAttribute.get()) {
1187                 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1188                 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1189                          " [" + getFeatureInfo(aFeature, false) + "]";
1190               }
1191             }
1192           }
1193         }
1194         anAttributesInfo.append("    " + anAttr->id() + ": " + aValue);
1195       }
1196       if (!anAttributesInfo.empty())
1197         anInfo = anInfo + "\n" + anAttributesInfo;
1198     }
1199   }
1200   return anInfo;
1201 }
1202