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