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