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