Salome HOME
62dad8c5fd74ef09b9ba09aaec9dd06b41c06229
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Split.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "SketchPlugin_Split.h"
21
22 #include <Events_Message.h>
23
24 #include <GeomAPI_Dir2d.h>
25 #include <GeomAPI_Edge.h>
26 #include <GeomAPI_Pnt2d.h>
27 #include <GeomAPI_XY.h>
28 #include <GeomDataAPI_Point2D.h>
29 #include <GeomAlgoAPI_ShapeTools.h>
30
31 #include <ModelAPI_AttributeBoolean.h>
32 #include <ModelAPI_AttributeDouble.h>
33 #include <ModelAPI_AttributeRefAttr.h>
34 #include <ModelAPI_AttributeReference.h>
35 #include <ModelAPI_AttributeString.h>
36 #include <ModelAPI_Events.h>
37 #include <ModelAPI_Validator.h>
38 #include <ModelAPI_Session.h>
39 #include <ModelAPI_Tools.h>
40
41 #include <ModelGeomAlgo_Shape.h>
42
43 #include <SketchPlugin_Arc.h>
44 #include <SketchPlugin_Circle.h>
45 #include <SketchPlugin_ConstraintCoincidence.h>
46 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
47 #include <SketchPlugin_ConstraintEqual.h>
48 #include <SketchPlugin_ConstraintLength.h>
49 #include <SketchPlugin_ConstraintMiddle.h>
50 #include <SketchPlugin_ConstraintMirror.h>
51 #include <SketchPlugin_ConstraintParallel.h>
52 #include <SketchPlugin_ConstraintTangent.h>
53 #include <SketchPlugin_Ellipse.h>
54 #include <SketchPlugin_EllipticArc.h>
55 #include <SketchPlugin_Line.h>
56 #include <SketchPlugin_MultiRotation.h>
57 #include <SketchPlugin_MultiTranslation.h>
58 #include <SketchPlugin_Point.h>
59
60 #include <ModelGeomAlgo_Point2D.h>
61 #include <ModelAPI_EventReentrantMessage.h>
62 #include <Events_Loop.h>
63
64 #include <cmath>
65
66 //#define CREATE_CONSTRAINTS
67
68 #ifdef DEBUG_SPLIT
69 #include <iostream>
70 #endif
71
72 static const double PI = 3.141592653589793238463;
73
74 SketchPlugin_Split::SketchPlugin_Split()
75 {
76 }
77
78 void SketchPlugin_Split::initAttributes()
79 {
80   data()->addAttribute(SELECTED_OBJECT(), ModelAPI_AttributeReference::typeId());
81   data()->addAttribute(SELECTED_POINT(), GeomDataAPI_Point2D::typeId());
82
83   data()->addAttribute(PREVIEW_POINT(), GeomDataAPI_Point2D::typeId());
84   data()->addAttribute(PREVIEW_OBJECT(), ModelAPI_AttributeReference::typeId());
85
86   data()->attribute(PREVIEW_POINT())->setIsArgument(false);
87   data()->attribute(SELECTED_POINT())->setIsArgument(false);
88   data()->attribute(PREVIEW_OBJECT())->setIsArgument(false);
89
90   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PREVIEW_POINT());
91   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), PREVIEW_OBJECT());
92 }
93
94 void SketchPlugin_Split::execute()
95 {
96   std::shared_ptr<ModelAPI_Data> aData = data();
97
98   // Check the base objects are initialized.
99   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
100                                                            data()->attribute(SELECTED_OBJECT()));
101   if(!aBaseObjectAttr->isInitialized()) {
102     setError("Error: Base object is not initialized.");
103     return;
104   }
105   ObjectPtr aBaseObject = aBaseObjectAttr->value();
106   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
107   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
108   if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
109       !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
110     setError("Error: Sub-shape is not initialized.");
111     return;
112   }
113
114   // Remove reference of this feature to feature used in preview, it is not necessary anymore
115   // as trim will be removed after execute
116   AttributeReferencePtr aPreviewObjectAttr =
117                      std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
118                      data()->attribute(PREVIEW_OBJECT()));
119
120   ObjectPtr aPreviewObject = aPreviewObjectAttr->value();
121   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
122                                            data()->attribute(PREVIEW_POINT()));
123   std::shared_ptr<GeomAPI_Pnt2d> aPreviewPnt2d = aPoint->pnt();
124   // nullify pointer of preview attribute
125   aPreviewObjectAttr->setValue(ResultPtr());
126   bool anIsEqualPreviewAndSelected = aPreviewObject == aBaseObject;
127
128   // Wait all constraints being created, then send update events
129   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
130   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
131   if (isUpdateFlushed)
132     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
133
134   // Find feature constraints
135   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
136   ResultPtr aBaseFeatureResult = aBaseFeature->lastResult();
137   std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
138
139   //std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
140   std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
141   getConstraints(aFeaturesToDelete, aFeaturesToUpdate, aCoincidenceToFeature);
142
143   std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
144   std::list<AttributePtr> aRefsToFeature;
145   SketchPlugin_SegmentationTools::getRefAttributes(
146       aBaseFeature, aBaseRefAttributes, aRefsToFeature);
147
148   std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
149
150 #ifdef DEBUG_SPLIT
151   std::cout << std::endl;
152   std::cout << "SketchPlugin_Split::execute()" << std::endl;
153   std::cout << std::endl;
154
155   SketchPlugin_Sketch* aSketch = sketch();
156   std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
157   for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
158     std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
159   }
160
161   std::cout << std::endl;
162   std::cout << "---- IN PARAMETERS ----" << std::endl;
163   std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
164   std::cout << std::endl;
165
166   if (!aCoincidenceToFeature.empty()) {
167     std::cout << "Coincidences to base feature[" <<
168       aCoincidenceToFeature.size() << "]: " << std::endl;
169     std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
170                                                         aLast = aCoincidenceToFeature.end();
171     for (int i = 1; anIt != aLast; anIt++, i++) {
172       FeaturePtr aFeature = (*anIt).first;
173       std::string anAttributeId = (*anIt).second.first;
174       std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
175
176       std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
177       std::cout <<     " -Attribute to correct:" << anAttributeId << std::endl;
178       std::cout <<     " -Point attribute:" <<
179         ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
180     }
181   }
182
183   std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
184     aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
185   std::cout << std::endl << "References to attributes of base feature [" <<
186     aBaseRefAttributes.size() << "]" << std::endl;
187   for (; aRefIt != aRefLast; aRefIt++) {
188     AttributePtr aBaseAttr = aRefIt->first;
189     std::list<AttributePtr> aRefAttributes = aRefIt->second;
190     std::string aRefsInfo;
191     std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
192                                             aRefAttrLast = aRefAttributes.end();
193     for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
194       if (!aRefsInfo.empty())
195         aRefsInfo.append(",");
196       AttributePtr aRAttr = *aRefAttrIt;
197       aRefsInfo.append(aRAttr->id());
198       FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
199       aRefsInfo.append("(" + aRFeature->name() + ") ");
200     }
201     std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
202       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
203     std::cout << aPointAttr->id().c_str() <<
204       ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
205   }
206   std::cout << std::endl;
207   std::cout << std::endl << "References to base feature [" <<
208     aRefsToFeature.size() << "]" << std::endl;
209   std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
210                                           aRefAttrLast = aRefsToFeature.end();
211   std::string aRefsInfo;
212   for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
213     if (!aRefsInfo.empty())
214       aRefsInfo.append(",");
215     AttributePtr aRAttr = *aRefAttrIt;
216     aRefsInfo.append(aRAttr->id());
217     FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
218     aRefsInfo.append("(" + aRFeature->name() + ") ");
219   }
220   std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
221
222
223   std::cout << std::endl;
224   std::cout << "---- SPLIT ----" << std::endl;
225   std::cout << std::endl;
226 #endif
227
228   keepCurrentFeature();
229
230   std::string aFeatureKind = aBaseFeature->getKind();
231   FeaturePtr aSplitFeature, anAfterFeature;
232   std::set<AttributePoint2DPtr> aFurtherCoincidences;
233   std::set<FeaturePtr> aCreatedFeatures;
234   std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
235   FeaturePtr aReplacingFeature, aNewFeature;
236   if (aFeatureKind == SketchPlugin_Line::ID())
237     aNewFeature = splitLine(aSplitFeature, aBaseFeature, anAfterFeature,
238                             aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
239   else if (aFeatureKind == SketchPlugin_Arc::ID())
240     aNewFeature = splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
241                            aCreatedFeatures, aModifiedAttributes);
242   else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
243     aNewFeature = splitEllipticArc(aSplitFeature, aBaseFeature, anAfterFeature,
244         aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
245
246   restoreCurrentFeature();
247
248   if (aFeatureKind == SketchPlugin_Circle::ID() || aFeatureKind == SketchPlugin_Ellipse::ID()) {
249     aFeaturesToDelete.insert(aBaseFeature);
250     aReplacingFeature = splitClosed(aSplitFeature, aBaseFeature, anAfterFeature,
251                                     aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
252
253     updateRefFeatureConstraints(aBaseFeature->lastResult(), aRefsToFeature);
254
255     // as circle is removed, temporary fill this attribute*/
256     aBaseObjectAttr->setObject(ResultPtr());
257   }
258
259 #ifdef DEBUG_SPLIT
260   std::cout << "---- OUT PARAMETERS ----" << std::endl;
261   std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
262   std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
263   std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
264   std::cout << std::endl;
265
266   std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
267   std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
268                                        aFLast = aCreatedFeatures.end();
269   for (; aFIt != aFLast; aFIt++) {
270     std::cout << getFeatureInfo(*aFIt) << std::endl;
271   }
272   std::cout << std::endl;
273
274   std::cout << "Attributes for further Coincidences:" << std::endl;
275   std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
276                                                 aLast = aFurtherCoincidences.end();
277   for (; anIt != aLast; anIt++) {
278     AttributePtr anAttribute = *anIt;
279     FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
280     std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
281               << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
282   }
283
284   std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
285   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
286     aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
287   std::string aResInfo;
288   for (; aPIt != aPLast; aPIt++) {
289     if (!aResInfo.empty())
290       aResInfo += "\n";
291
292     std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
293
294     AttributePtr anAttr = aPair.first;
295     aResInfo.append(anAttr->id());
296     FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
297     aResInfo.append("(" + aFeature->name() + ") ");
298
299     aResInfo.append("  - is modified to -  ");
300
301     anAttr = aPair.second;
302     aResInfo.append(anAttr->id());
303     aFeature = ModelAPI_Feature::feature(anAttr->owner());
304     aResInfo.append("(" + aFeature->name() + ") ");
305   }
306   std::cout << aResInfo << std::endl;
307 #endif
308
309   std::set<ResultPtr> aFeatureResults;
310   aFeatureResults.insert(aBaseFeature->lastResult());
311   if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
312     aFeatureResults.insert(anAfterFeature->lastResult());
313
314   // coincidence to feature
315   updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
316                                         aFeatureResults, aSplitFeature, aFeaturesToDelete);
317
318   SketchPlugin_SegmentationTools::updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
319
320   // delete constraints
321 #ifdef DEBUG_SPLIT
322   std::cout << "remove features and references:" << std::endl;
323   std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
324                                        aDLast = aFeaturesToDelete.end();
325   for (; aDIt != aDLast; aDIt++) {
326     std::cout << getFeatureInfo(*aDIt, false) << std::endl;
327     std::cout << std::endl;
328   }
329 #endif
330   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
331   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
332
333 #ifdef DEBUG_SPLIT
334   std::cout << "update features after split:" << std::endl;
335   std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
336                                        anULast = aFeaturesToUpdate.end();
337   for (; anUIt != anULast; anUIt++) {
338     std::cout << getFeatureInfo(*anUIt, false) << std::endl;
339     std::cout << std::endl;
340   }
341 #endif
342   SketchPlugin_SegmentationTools::updateFeaturesAfterOperation(aFeaturesToUpdate);
343
344   // Send events to update the sub-features by the solver.
345   if(isUpdateFlushed) {
346     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
347   }
348
349     if (anIsEqualPreviewAndSelected) {
350     // equal preview and selected objects
351     // nothing to do if the preview and selected objects are different
352     ResultPtr aReplacingResult;
353     if (aReplacingFeature.get()) {
354       aReplacingFeature->execute(); // need it to obtain result
355       aReplacingResult = aReplacingFeature->lastResult();
356     }
357     if (aReplacingResult.get()) { // base object was removed
358       aPreviewObject = aReplacingResult;
359       //aMessage->setSelectedObject(aReplacingResult);
360
361       //GeomShapePtr aSelectedShape = aReplacingResult->shape();
362       //std::shared_ptr<GeomAPI_Pnt> aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(),
363       //                                                          aPreviewPnt2d->y());
364       //std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
365       //if (ModelGeomAlgo_Point2D::isPointOnEdge(aSelectedShape, aPreviewPnt, aProjectedPoint)) {
366         //bool aValue = true;
367       //}
368       //aBaseShape = aShape;
369
370 #ifdef DEBUG_SPLIT
371       if (!aSelectedShape.get())
372         std::cout << "Set empty selected object" << std::endl;
373       else
374         std::cout << "Set shape with ShapeType: " << aSelectedShape->shapeTypeStr() << std::endl;
375 #endif
376       //bool aValue = true;
377     }
378     else {
379       aPreviewObject = ObjectPtr();
380
381       aBaseFeature->execute(); // should recompute shapes of result to do not check obsolete one
382       aBaseObject = aBaseFeature->lastResult();
383       std::shared_ptr<GeomAPI_Pnt> aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(),
384                                                                 aPreviewPnt2d->y());
385       ResultPtr aBaseResult = std::dynamic_pointer_cast<ModelAPI_Result>(aBaseObject);
386       if (aBaseResult) {
387         GeomShapePtr aShape = aBaseResult->shape();
388         std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
389         if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPreviewPnt, aProjectedPoint))
390           aPreviewObject = aBaseResult;
391       }
392       if (!aPreviewObject.get() && aNewFeature.get()) {
393         ResultPtr aNewFeatureResult = aNewFeature->lastResult();
394         if (aNewFeatureResult.get()) {
395           GeomShapePtr aShape = aNewFeatureResult->shape();
396           std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
397           if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPreviewPnt, aProjectedPoint))
398             aPreviewObject = aNewFeatureResult;
399         }
400       }
401     }
402   }
403   if (aPreviewObject.get()) {
404     std::shared_ptr<ModelAPI_EventReentrantMessage> aMessage = std::shared_ptr
405       <ModelAPI_EventReentrantMessage>(new ModelAPI_EventReentrantMessage(
406                                            ModelAPI_EventReentrantMessage::eventId(), this));
407     aMessage->setSelectedObject(aPreviewObject);
408     Events_Loop::loop()->send(aMessage);
409   }
410
411
412 #ifdef DEBUG_SPLIT
413   std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
414   for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
415     std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
416   }
417 #endif
418 }
419
420 // LCOV_EXCL_START
421 std::string SketchPlugin_Split::processEvent(const std::shared_ptr<Events_Message>& theMessage)
422 {
423 #ifdef DEBUG_SPLIT
424   std::cout << "SketchPlugin_Split::processEvent:" << data()->name() << std::endl;
425 #endif
426   std::string aFilledAttributeName;
427
428   std::shared_ptr<ModelAPI_EventReentrantMessage> aMessage =
429         std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
430   if (aMessage.get()) {
431     ObjectPtr anObject = aMessage->selectedObject();
432     std::shared_ptr<GeomAPI_Pnt2d> aPoint = aMessage->clickedPoint();
433
434     if (anObject.get() && aPoint.get()) {
435       if (myCashedShapes.find(anObject) == myCashedShapes.end()) {
436         SketchPlugin_SegmentationTools::fillObjectShapes(
437             this, anObject, myCashedShapes, myCashedReferences);
438       }
439       const std::set<GeomShapePtr>& aShapes = myCashedShapes[anObject];
440       if (aShapes.size() > 1) {
441         std::shared_ptr<ModelAPI_AttributeReference> aRefSelectedAttr =
442                               std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
443                               data()->attribute(SELECTED_OBJECT()));
444         std::shared_ptr<ModelAPI_AttributeReference> aRefPreviewAttr =
445                               std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
446                               data()->attribute(PREVIEW_OBJECT()));
447         aRefSelectedAttr->setValue(anObject);
448         aRefPreviewAttr->setValue(anObject);
449
450         std::shared_ptr<GeomDataAPI_Point2D> aPointSelectedAttr =
451                               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
452                               data()->attribute(SELECTED_POINT()));
453         std::shared_ptr<GeomDataAPI_Point2D> aPointPreviewAttr =
454                               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
455                               data()->attribute(PREVIEW_POINT()));
456         aPointSelectedAttr->setValue(aPoint);
457         aPointPreviewAttr->setValue(aPoint);
458
459         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
460
461         GeomShapePtr aSelectedShape = SketchPlugin_SegmentationTools::getSubShape(this,
462             SELECTED_OBJECT(), SELECTED_POINT(), myCashedShapes, myCashedReferences);
463         if (aSelectedShape.get()) {
464           aFilledAttributeName = SELECTED_OBJECT();
465         }
466         else {
467           // #2480 - sub shape is not initialized when split sketch
468           // If restarted operation use some selection on the shape that is split and
469           // result selectiona can not participate in new split(checked shape above is null),
470           // reset filled values of selection set in this method above
471           aRefSelectedAttr->setValue(ResultPtr());
472           aRefPreviewAttr->setValue(ResultPtr());
473         }
474   #ifdef DEBUG_SPLIT
475         if (!aSelectedShape.get())
476           std::cout << "Set empty selected object" << std::endl;
477         else
478           std::cout << "Set shape with ShapeType: " << aSelectedShape->shapeTypeStr() << std::endl;
479   #endif
480       }
481     }
482   }
483   return aFilledAttributeName;
484 }
485 // LCOV_EXCL_STOP
486
487 AISObjectPtr SketchPlugin_Split::getAISObject(AISObjectPtr thePrevious)
488 {
489   return SketchPlugin_SegmentationTools::getAISObject(thePrevious,
490       this, PREVIEW_OBJECT(), PREVIEW_POINT(), SELECTED_OBJECT(), SELECTED_POINT());
491 }
492
493 //********************************************************************
494 void SketchPlugin_Split::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
495                                     std::set<FeaturePtr>& theFeaturesToUpdate,
496                                     std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
497 {
498   std::shared_ptr<ModelAPI_Data> aData = data();
499
500   // Check the base objects are initialized.
501   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
502                                                            data()->attribute(SELECTED_OBJECT()));
503   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
504   ResultPtr aBaseFeatureResult = aBaseFeature->lastResult();
505
506   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
507   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
508   aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
509
510   std::set<AttributePtr>::const_iterator aIt;
511   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
512     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
513     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
514     std::string aRefFeatureKind = aRefFeature->getKind();
515     if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
516         aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
517         aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
518         aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
519       theFeaturesToDelete.insert(aRefFeature);
520     else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
521       theFeaturesToUpdate.insert(aRefFeature);
522     else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID() ||
523              aRefFeatureKind == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
524       std::string anAttributeToBeModified;
525       AttributePoint2DPtr aCoincidentPoint;
526       AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
527       AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
528       bool isToFeature = false;
529       if (anAttrA->isObject() || anAttrB->isObject()) { // coincidence to base feature
530         FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
531                                                   : FeaturePtr();
532         isToFeature = aFeature.get() && aFeature == aBaseFeature;
533         anAttributeToBeModified = anAttrA->id();
534         if (!isToFeature) {
535           aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
536                                          : FeaturePtr();
537           isToFeature = aFeature.get() && aFeature == aBaseFeature;
538           anAttributeToBeModified = anAttrB->id();
539         }
540         if (isToFeature)
541           aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
542       }
543       if (!isToFeature) { // coincidence to point on base feature
544         AttributePtr anAttribute;
545
546         if (!anAttrA->isObject()) {
547           AttributePtr aCurAttribute = anAttrA->attr();
548           if (aCurAttribute.get()) {
549             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
550             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
551               anAttribute = anAttrB->attr();
552               anAttributeToBeModified = anAttrA->id();
553             }
554           }
555         }
556         if (!anAttribute.get() && !anAttrB->isObject()) {
557           AttributePtr aCurAttribute = anAttrB->attr();
558           if (aCurAttribute.get()) {
559             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
560             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
561               anAttribute = anAttrA->attr();
562               anAttributeToBeModified = anAttrB->id();
563             }
564           }
565         }
566         if (anAttribute.get())
567           aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
568       }
569       if (aCoincidentPoint.get() && isToFeature)
570         theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
571                                                               aCoincidentPoint);
572     }
573   }
574 }
575
576 void SketchPlugin_Split::updateCoincidenceConstraintsToFeature(
577       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
578       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
579       const std::set<ResultPtr>& theFeatureResults,
580       const FeaturePtr& theSplitFeature,
581       std::set<FeaturePtr>& theFeaturesToDelete)
582 {
583   if (theCoincidenceToFeature.empty())
584     return;
585
586   // we should build coincidence constraints to end of the split feature
587   std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
588   AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
589   SketchPlugin_SegmentationTools::getFeaturePoints(
590       theSplitFeature, aStartPointAttr, anEndPointAttr);
591   if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
592     aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
593   if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
594     aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
595
596   std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
597                                                       aCLast = theCoincidenceToFeature.end();
598 #ifdef DEBUG_SPLIT
599   std::cout << std::endl;
600   std::cout << "Coincidences to feature(modified):"<< std::endl;
601 #endif
602   for (; aCIt != aCLast; aCIt++) {
603     FeaturePtr aCoincFeature = aCIt->first;
604     std::string anAttributeId = aCIt->second.first;
605     std::string aSecondAttribute = anAttributeId == SketchPlugin_Constraint::ENTITY_A() ?
606         SketchPlugin_Constraint::ENTITY_B() : SketchPlugin_Constraint::ENTITY_A();
607
608     AttributePoint2DPtr aCoincPoint = aCIt->second.second;
609     std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
610                                                   aFCLast = theFurtherCoincidences.end();
611     std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
612     AttributePoint2DPtr aFeaturePointAttribute;
613     for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
614       AttributePoint2DPtr aFCAttribute = *aFCIt;
615       if (aCoincPnt->isEqual(aFCAttribute->pnt()))
616         aFeaturePointAttribute = aFCAttribute;
617     }
618     if (aFeaturePointAttribute.get()) {
619       // create new constraint and remove the current
620       aCoincFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
621           SketchPlugin_ConstraintCoincidence::ID(),
622           aFeaturePointAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
623       theFeaturesToDelete.insert(aCIt->first);
624       // create new coincidences to split feature points
625       std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
626                                                     aSFLast = aNewCoincidencesToSplitFeature.end();
627       for (; aSFIt != aSFLast; aSFIt++) {
628         AttributePoint2DPtr aSFAttribute = *aSFIt;
629         if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
630           SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
631                            SketchPlugin_ConstraintCoincidence::ID(),
632                            aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
633         }
634       }
635     }
636     else {
637       // find feature by shape intersected the point
638       ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
639
640       if (theFeatureResults.size() > 1) { // try to find point on additional feature
641         ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
642         GeomShapePtr aShape = anAddtionalResult->shape();
643
644         std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
645         std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
646
647         std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
648         if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
649           aResultForCoincidence = anAddtionalResult;
650       }
651       aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
652     }
653 #ifdef DEBUG_SPLIT
654   std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
655 #endif
656   }
657 }
658
659 void SketchPlugin_Split::updateRefFeatureConstraints(
660                                                   const ResultPtr& theFeatureBaseResult,
661                                                   const std::list<AttributePtr>& theRefsToFeature)
662 {
663   std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
664                                           aLast = theRefsToFeature.end();
665   for (; anIt != aLast; anIt++) {
666     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
667     if (aRefAttr.get())
668       aRefAttr->setObject(theFeatureBaseResult);
669   }
670 }
671
672 FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
673                                          FeaturePtr& theBaseFeatureModified,
674                                          FeaturePtr& theAfterFeature,
675                                          std::set<AttributePoint2DPtr>& thePoints,
676                                          std::set<FeaturePtr>& theCreatedFeatures,
677                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
678 {
679   FeaturePtr anNewFeature;
680
681   std::set<FeaturePtr> aCreatedFeatures;
682   FeaturePtr aConstraintFeature;
683   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
684
685   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
686                                                            data()->attribute(SELECTED_OBJECT()));
687   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
688
689   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
690   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
691   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
692
693   SketchPlugin_SegmentationTools::getFeaturePoints(
694       aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
695   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
696     setError("Error: Feature has no start and end points.");
697     return anNewFeature;
698   }
699
700   arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
701                       aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
702
703 #ifdef DEBUG_SPLIT
704   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
705   std::cout << "Start point: " <<
706     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
707   std::cout << "1st point:   " <<
708     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
709   std::cout << "2nd point:   " <<
710     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
711   std::cout << "End point:   " <<
712     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
713 #endif
714
715   // create a split feature
716   theSplitFeature = SketchPlugin_SegmentationTools::createLineFeature(
717       aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
718   theCreatedFeatures.insert(theSplitFeature);
719
720   // before split feature
721   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
722     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
723                                         theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
724   }
725   else {
726     theBaseFeatureModified = aBaseFeature; // use base feature to store all constraints here
727     // move end arc point to start of split
728   }
729
730   // after split feature
731   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
732     FeaturePtr aFeature;
733     if (!theBaseFeatureModified.get()) {
734       aFeature = aBaseFeature; // use base feature to store all constraints here
735       fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
736       aFeature->execute(); // to update result
737     }
738     else {
739       aFeature = SketchPlugin_SegmentationTools::createLineFeature(
740           aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
741       theCreatedFeatures.insert(aFeature);
742       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
743                                              aFeature->attribute(SketchPlugin_Line::END_ID())));
744       anNewFeature = aFeature;
745     }
746     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
747                      SketchPlugin_ConstraintCoincidence::ID(),
748                      theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
749                      aFeature->attribute(SketchPlugin_Line::START_ID()));
750     theCreatedFeatures.insert(aConstraintFeature);
751
752     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
753                                 (aFeature->attribute(SketchPlugin_Line::START_ID())));
754     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
755                                 (aFeature->attribute(SketchPlugin_Line::END_ID())));
756
757     if (!theBaseFeatureModified.get())
758       theBaseFeatureModified = aFeature;
759     else
760       theAfterFeature = aFeature;
761   }
762   else {
763     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
764                                   (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
765     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
766                                    theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
767   }
768   // base split, that is defined before split feature should be changed at end
769   // (after the after feature creation). Otherwise modified value will be used in after feature
770   // before split feature
771   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
772     // move end arc point to start of split
773     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
774                                                     aFirstPointAttrOfSplit);
775     theBaseFeatureModified->execute(); // to update result
776     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
777                      SketchPlugin_ConstraintCoincidence::ID(),
778                      theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
779                      theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
780     theCreatedFeatures.insert(aConstraintFeature);
781
782     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
783                              (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
784     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
785                                (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
786   }
787   else
788     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
789                                        (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
790
791 #ifdef CREATE_CONSTRAINTS
792   // additional constraints between split and base features
793   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
794           SketchPlugin_ConstraintParallel::ID(),
795           aBaseFeature->lastResult(),
796           theSplitFeature->lastResult());
797   theCreatedFeatures.insert(aConstraintFeature);
798   if (theAfterFeature.get()) {
799     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
800           SketchPlugin_ConstraintParallel::ID(),
801           aBaseFeature->lastResult(),
802           theAfterFeature->lastResult());
803     theCreatedFeatures.insert(aConstraintFeature);
804   }
805 #endif
806   return anNewFeature;
807 }
808
809 FeaturePtr SketchPlugin_Split::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   FeaturePtr anNewFeature;
817
818   std::set<FeaturePtr> aCreatedFeatures;
819   FeaturePtr aConstraintFeature;
820   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
821
822   AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
823   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
824
825   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
826   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
827   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
828   SketchPlugin_SegmentationTools::getFeaturePoints(
829       aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
830   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
831     setError("Error: Feature has no start and end points.");
832     return anNewFeature;
833   }
834
835   arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
836                      aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
837 #ifdef DEBUG_SPLIT
838   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
839   std::cout << "Start point: " <<
840     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
841   std::cout << "1st point:   " <<
842     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
843   std::cout << "2nd point:   " <<
844     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
845   std::cout << "End point:   " <<
846     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
847 #endif
848
849   // split feature
850   theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
851       aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
852   theCreatedFeatures.insert(theSplitFeature);
853
854   // before split feature
855   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
856     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
857                                   theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
858   }
859   else {
860     theBaseFeatureModified = aBaseFeature; // use base feature to store all constraints here
861     // move end arc point to start of split
862   }
863
864   // after split feature
865   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
866     FeaturePtr aFeature;
867     if (!theBaseFeatureModified.get()) {
868       aFeature = aBaseFeature; // use base feature to store all constraints here
869       fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
870       aFeature->execute(); // to update result
871     }
872     else {
873       aFeature = SketchPlugin_SegmentationTools::createArcFeature(
874           aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
875       theCreatedFeatures.insert(aFeature);
876       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
877                                                   aFeature->attribute(SketchPlugin_Arc::END_ID())));
878       anNewFeature = aFeature;
879     }
880     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
881                      SketchPlugin_ConstraintCoincidence::ID(),
882                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
883                      aFeature->attribute(SketchPlugin_Arc::START_ID()));
884     theCreatedFeatures.insert(aConstraintFeature);
885
886     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
887                                 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
888     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
889                                 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
890
891     if (!theBaseFeatureModified.get())
892       theBaseFeatureModified = aFeature;
893     else
894       theAfterFeature = aFeature;
895   }
896   else {
897     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
898                                   (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
899     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
900                                    theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
901   }
902   // base split, that is defined before split feature should be changed at end
903   // (after the after feature creation). Otherwise modified value will be used in after feature
904   // before split feature
905   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
906     // move end arc point to start of split
907     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
908                                                     aFirstPointAttrOfSplit);
909     theBaseFeatureModified->execute(); // to update result
910     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
911                      SketchPlugin_ConstraintCoincidence::ID(),
912                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
913                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
914     theCreatedFeatures.insert(aConstraintFeature);
915
916     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
917                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
918     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
919                                (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
920   }
921   else
922     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
923                                        (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
924
925   // additional constraints between split and base features
926 #ifdef CREATE_CONSTRAINTS
927   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
928           SketchPlugin_ConstraintEqual::ID(),
929           aBaseFeature->lastResult(),
930           theSplitFeature->lastResult());
931   theCreatedFeatures.insert(aConstraintFeature);
932   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
933           SketchPlugin_ConstraintTangent::ID(),
934           theSplitFeature->lastResult(),
935           aBaseFeature->lastResult());
936   theCreatedFeatures.insert(aConstraintFeature);
937   if (theAfterFeature.get()) {
938     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
939                 SketchPlugin_ConstraintEqual::ID(),
940                 aBaseFeature->lastResult(),
941                 theAfterFeature->lastResult());
942     theCreatedFeatures.insert(aConstraintFeature);
943     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
944                 SketchPlugin_ConstraintTangent::ID(),
945                 theSplitFeature->lastResult(),
946                 theAfterFeature->lastResult());
947     theCreatedFeatures.insert(aConstraintFeature);
948   }
949 #endif
950   return anNewFeature;
951 }
952
953 FeaturePtr SketchPlugin_Split::splitEllipticArc(FeaturePtr& theSplitFeature,
954                                                 FeaturePtr& theBaseFeatureModified,
955                                                 FeaturePtr& theAfterFeature,
956                                                 std::set<AttributePoint2DPtr>& thePoints,
957                                                 std::set<FeaturePtr>& theCreatedFeatures,
958                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
959 {
960   FeaturePtr anNewFeature;
961
962   std::set<FeaturePtr> aCreatedFeatures;
963   FeaturePtr aConstraintFeature;
964   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
965
966   AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
967   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
968
969   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
970   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
971   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
972   SketchPlugin_SegmentationTools::getFeaturePoints(
973       aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
974   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
975     setError("Error: Feature has no start and end points.");
976     return anNewFeature;
977   }
978
979   arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
980                      aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
981 #ifdef DEBUG_SPLIT
982   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
983   std::cout << "Start point: " <<
984     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
985   std::cout << "1st point:   " <<
986     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
987   std::cout << "2nd point:   " <<
988     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
989   std::cout << "End point:   " <<
990     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
991 #endif
992
993   // split feature
994   theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
995       aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
996   theCreatedFeatures.insert(theSplitFeature);
997
998   // before split feature
999   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1000     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
1001         theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
1002   }
1003   else {
1004     theBaseFeatureModified = aBaseFeature; // use base feature to store all constraints here
1005     // move end arc point to start of split
1006   }
1007
1008   // after split feature
1009   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
1010     FeaturePtr aFeature;
1011     if (!theBaseFeatureModified.get()) {
1012       aFeature = aBaseFeature; // use base feature to store all constraints here
1013       fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
1014       aFeature->execute(); // to update result
1015     }
1016     else {
1017       aFeature = SketchPlugin_SegmentationTools::createArcFeature(
1018           aBaseFeature, aSecondPointAttrOfSplit->pnt(), anEndPointAttrOfBase->pnt());
1019       theCreatedFeatures.insert(aFeature);
1020       theModifiedAttributes.insert(std::make_pair(
1021           anEndPointAttrOfBase, aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
1022       anNewFeature = aFeature;
1023     }
1024     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1025                      SketchPlugin_ConstraintCoincidence::ID(),
1026                      theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
1027                      aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
1028     theCreatedFeatures.insert(aConstraintFeature);
1029
1030     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1031                                 (aFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
1032     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1033                                 (aFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
1034
1035     if (!theBaseFeatureModified.get())
1036       theBaseFeatureModified = aFeature;
1037     else
1038       theAfterFeature = aFeature;
1039   }
1040   else {
1041     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1042         theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
1043     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
1044         theSplitFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
1045   }
1046   // base split, that is defined before split feature should be changed at end
1047   // (after the after feature creation). Otherwise modified value will be used in after feature
1048   // before split feature
1049   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1050     // move end arc point to start of split
1051     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
1052                   aFirstPointAttrOfSplit);
1053     theBaseFeatureModified->execute(); // to update result
1054     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1055                      SketchPlugin_ConstraintCoincidence::ID(),
1056                      theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID()),
1057                      theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
1058     theCreatedFeatures.insert(aConstraintFeature);
1059
1060     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1061         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
1062     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1063         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::END_POINT_ID())));
1064   }
1065   else
1066     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1067                      theSplitFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID())));
1068
1069   // additional constraints between split and base features
1070 #ifdef CREATE_CONSTRAINTS
1071   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1072           SketchPlugin_ConstraintEqual::ID(),
1073           aBaseFeature->lastResult(),
1074           theSplitFeature->lastResult());
1075   theCreatedFeatures.insert(aConstraintFeature);
1076   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1077           SketchPlugin_ConstraintTangent::ID(),
1078           theSplitFeature->lastResult(),
1079           aBaseFeature->lastResult());
1080   theCreatedFeatures.insert(aConstraintFeature);
1081   if (theAfterFeature.get()) {
1082     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1083                 SketchPlugin_ConstraintEqual::ID(),
1084                 aBaseFeature->lastResult(),
1085                 theAfterFeature->lastResult());
1086     theCreatedFeatures.insert(aConstraintFeature);
1087     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1088                 SketchPlugin_ConstraintTangent::ID(),
1089                 theSplitFeature->lastResult(),
1090                 theAfterFeature->lastResult());
1091     theCreatedFeatures.insert(aConstraintFeature);
1092   }
1093 #endif
1094   return anNewFeature;
1095 }
1096
1097 FeaturePtr SketchPlugin_Split::splitClosed(FeaturePtr& theSplitFeature,
1098                                                FeaturePtr& theBaseFeatureModified,
1099                                                FeaturePtr& theAfterFeature,
1100                                                std::set<AttributePoint2DPtr>& thePoints,
1101                                                std::set<FeaturePtr>& theCreatedFeatures,
1102                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1103 {
1104   FeaturePtr anNewFeature;
1105
1106   std::set<FeaturePtr> aCreatedFeatures;
1107   FeaturePtr aConstraintFeature;
1108   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1109
1110   AttributeReferencePtr aBaseObjectAttr = reference(SELECTED_OBJECT());
1111   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1112
1113   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
1114   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
1115
1116   // split feature
1117   theSplitFeature = SketchPlugin_SegmentationTools::createArcFeature(
1118       aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
1119   const std::string& aReversedAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
1120       SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
1121   bool aSplitReversed = theSplitFeature->boolean(aReversedAttrName)->value();
1122   theCreatedFeatures.insert(theSplitFeature);
1123
1124   // base feature is a left part of the circle
1125   theBaseFeatureModified = SketchPlugin_SegmentationTools::createArcFeature(
1126       aBaseFeature, aFirstPointAttrOfSplit->pnt(), aSecondPointAttrOfSplit->pnt());
1127   anNewFeature = theBaseFeatureModified;
1128   theBaseFeatureModified->boolean(aReversedAttrName)->setValue(!aSplitReversed);
1129   theBaseFeatureModified->execute();
1130
1131   if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
1132     theModifiedAttributes.insert(std::make_pair(
1133         aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1134         theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1135   }
1136   else if (aBaseFeature->getKind() == SketchPlugin_Ellipse::ID()) {
1137     theModifiedAttributes.insert(std::make_pair(
1138         aBaseFeature->attribute(SketchPlugin_Ellipse::CENTER_ID()),
1139         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::CENTER_ID())));
1140     theModifiedAttributes.insert(std::make_pair(
1141         aBaseFeature->attribute(SketchPlugin_Ellipse::FIRST_FOCUS_ID()),
1142         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::FIRST_FOCUS_ID())));
1143     theModifiedAttributes.insert(std::make_pair(
1144         aBaseFeature->attribute(SketchPlugin_Ellipse::SECOND_FOCUS_ID()),
1145         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::SECOND_FOCUS_ID())));
1146     theModifiedAttributes.insert(std::make_pair(
1147         aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()),
1148         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_START_ID())));
1149     theModifiedAttributes.insert(std::make_pair(
1150         aBaseFeature->attribute(SketchPlugin_Ellipse::MAJOR_AXIS_END_ID()),
1151         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MAJOR_AXIS_END_ID())));
1152     theModifiedAttributes.insert(std::make_pair(
1153         aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_START_ID()),
1154         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_START_ID())));
1155     theModifiedAttributes.insert(std::make_pair(
1156         aBaseFeature->attribute(SketchPlugin_Ellipse::MINOR_AXIS_END_ID()),
1157         theBaseFeatureModified->attribute(SketchPlugin_EllipticArc::MINOR_AXIS_END_ID())));
1158
1159     // update the PARENT_ID reference for all the features created by the ellipse
1160     const std::set<AttributePtr>& aRefs = aBaseFeature->data()->refsToMe();
1161     std::list<AttributePtr> aRefsToParent;
1162     for (std::set<AttributePtr>::const_iterator aRef = aRefs.begin(); aRef != aRefs.end(); ++aRef) {
1163       if ((*aRef)->id() == SketchPlugin_SketchEntity::PARENT_ID())
1164         aRefsToParent.push_back(*aRef);
1165     }
1166     for (std::list<AttributePtr>::iterator aRef = aRefsToParent.begin();
1167          aRef != aRefsToParent.end(); ++aRef) {
1168       std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*aRef)->setValue(
1169           theBaseFeatureModified);
1170
1171       FeaturePtr anOwner = ModelAPI_Feature::feature((*aRef)->owner());
1172       SketchPlugin_Tools::replaceInName(anOwner,
1173           aBaseFeature->name(), theBaseFeatureModified->name());
1174       SketchPlugin_Tools::replaceInName(anOwner->lastResult(),
1175           aBaseFeature->name(), theBaseFeatureModified->name());
1176     }
1177   }
1178
1179   theCreatedFeatures.insert(theBaseFeatureModified);
1180
1181   const std::string& aStartAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
1182       SketchPlugin_Arc::START_ID() : SketchPlugin_EllipticArc::START_POINT_ID();
1183   const std::string& aEndAttrName = theSplitFeature->getKind() == SketchPlugin_Arc::ID() ?
1184       SketchPlugin_Arc::END_ID() : SketchPlugin_EllipticArc::END_POINT_ID();
1185
1186   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1187                              (theBaseFeatureModified->attribute(aStartAttrName)));
1188   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1189                              (theBaseFeatureModified->attribute(aEndAttrName)));
1190
1191   // additional constraints between split and base features
1192   aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1193                      SketchPlugin_ConstraintCoincidence::ID(),
1194                      theBaseFeatureModified->attribute(aEndAttrName),
1195                      theSplitFeature->attribute(aEndAttrName));
1196   theCreatedFeatures.insert(aConstraintFeature);
1197   aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1198                      SketchPlugin_ConstraintCoincidence::ID(),
1199                      theBaseFeatureModified->attribute(aStartAttrName),
1200                      theSplitFeature->attribute(aStartAttrName));
1201   theCreatedFeatures.insert(aConstraintFeature);
1202
1203 #ifdef CREATE_CONSTRAINTS
1204   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1205                      SketchPlugin_ConstraintTangent::ID(),
1206                      theSplitFeature->lastResult(),
1207                      theBaseFeatureModified->lastResult());
1208   theCreatedFeatures.insert(aConstraintFeature);
1209 #endif
1210   return anNewFeature;
1211 }
1212
1213 void SketchPlugin_Split::arrangePointsOnLine(
1214     const AttributePoint2DPtr& theStartPointAttr,
1215     const AttributePoint2DPtr& theEndPointAttr,
1216     AttributePoint2DPtr& theFirstPointAttr,
1217     AttributePoint2DPtr& theLastPointAttr) const
1218 {
1219   // if first point is closer to last point, swap first and last values
1220   if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1221       theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1222     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1223     theFirstPointAttr = theLastPointAttr;
1224     theLastPointAttr = aTmpPoint;
1225   }
1226 }
1227
1228 void SketchPlugin_Split::arrangePointsOnArc(
1229     const FeaturePtr& theArc,
1230     const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1231     const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1232     std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1233     std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1234 {
1235   static const double anAngleTol = 1.e-12;
1236
1237   const std::string& aCenterAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
1238       SketchPlugin_Arc::CENTER_ID() : SketchPlugin_EllipticArc::CENTER_ID();
1239   const std::string& aReversedAttrName = theArc->getKind() == SketchPlugin_Arc::ID() ?
1240       SketchPlugin_Arc::REVERSED_ID() : SketchPlugin_EllipticArc::REVERSED_ID();
1241
1242   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1243       theArc->attribute(aCenterAttrName))->pnt();
1244   bool isReversed = theArc->boolean(aReversedAttrName)->value();
1245
1246   // collect directions to each point
1247   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1248       new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1249   std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1250       new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1251   std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1252       new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1253
1254   // sort points by their angular values
1255   double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1256   double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1257   double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1258   if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1259     aFirstPtAngle += aPeriod;
1260   if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1261     aSecondPtAngle += aPeriod;
1262
1263   if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1264     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1265     theFirstPointAttr = theSecondPointAttr;
1266     theSecondPointAttr = aTmpPoint;
1267   }
1268 }
1269
1270 void SketchPlugin_Split::fillAttribute(const AttributePtr& theModifiedAttribute,
1271                                                  const AttributePtr& theSourceAttribute)
1272 {
1273   std::string anAttributeType = theModifiedAttribute->attributeType();
1274   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1275     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1276                                               theModifiedAttribute);
1277     AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1278                                               theSourceAttribute);
1279
1280     if (aModifiedAttribute.get() && aSourceAttribute.get())
1281       aModifiedAttribute->setValue(aSourceAttribute->pnt());
1282   }
1283   else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1284     AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1285                                               theModifiedAttribute);
1286     AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1287                                               theSourceAttribute);
1288
1289     if (aModifiedAttribute.get() && aSourceAttribute.get())
1290       aModifiedAttribute->setValue(aSourceAttribute->value());
1291   }
1292 }
1293
1294 #ifdef _DEBUG
1295 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_Split::getEdgeAttributes(
1296                                            const std::shared_ptr<ModelAPI_Feature>& theFeature)
1297 {
1298   std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1299
1300   std::string aFeatureKind = theFeature->getKind();
1301   if (aFeatureKind == SketchPlugin_Line::ID()) {
1302     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1303     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1304   }
1305   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1306     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1307     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1308   }
1309   else if (aFeatureKind == SketchPlugin_EllipticArc::ID()) {
1310     anAttributes.insert(theFeature->attribute(SketchPlugin_EllipticArc::START_POINT_ID()));
1311     anAttributes.insert(theFeature->attribute(SketchPlugin_EllipticArc::END_POINT_ID()));
1312   }
1313   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1314   }
1315
1316   return anAttributes;
1317 }
1318 #endif
1319
1320 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_Split::getPointAttribute
1321                                                               (const bool isFirstAttribute)
1322 {
1323   std::shared_ptr<GeomDataAPI_Point2D> anAttribute;
1324
1325   GeomShapePtr aSelectedShape = SketchPlugin_SegmentationTools::getSubShape(this,
1326       SELECTED_OBJECT(), SELECTED_POINT(), myCashedShapes, myCashedReferences);
1327   if (!aSelectedShape.get())
1328     return anAttribute;
1329
1330   if (aSelectedShape->shapeType() != GeomAPI_Shape::EDGE)
1331     return anAttribute;
1332
1333   AttributeReferencePtr anObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1334                                                        data()->attribute(SELECTED_OBJECT()));
1335   ObjectPtr aBaseObject = anObjectAttr->value();
1336   if (!aBaseObject.get())
1337     return anAttribute;
1338
1339   std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelectedShape));
1340
1341   std::shared_ptr<GeomAPI_Pnt> aFirstPnt = anEdge->firstPoint();
1342   std::shared_ptr<GeomAPI_Pnt> aLastPnt = anEdge->lastPoint();
1343
1344   std::shared_ptr<GeomDataAPI_Point2D> aFirstPointAttr, aLastPointAttr;
1345   // find the points in feature attributes
1346   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
1347   std::list<AttributePtr> a2DPointAttributes = aBaseFeature->data()->attributes(
1348                                                     GeomDataAPI_Point2D::typeId());
1349   std::list<AttributePtr>::const_iterator anIt = a2DPointAttributes.begin(),
1350                                           aLast = a2DPointAttributes.end();
1351   for (; anIt != aLast; anIt++) {
1352     std::shared_ptr<GeomDataAPI_Point2D> anAttributePoint =
1353                                   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
1354     std::shared_ptr<GeomAPI_Pnt2d> aPoint2D = anAttributePoint->pnt();
1355     std::shared_ptr<GeomAPI_Pnt> aPoint3D = sketch()->to3D(aPoint2D->x(), aPoint2D->y());
1356     if (aFirstPnt->isEqual(aPoint3D))
1357       aFirstPointAttr = anAttributePoint;
1358     else if (aLastPnt->isEqual(aPoint3D))
1359       aLastPointAttr = anAttributePoint;
1360   }
1361
1362   // find the points in coincident features
1363   const GeomAlgoAPI_ShapeTools::PointToRefsMap& aRefAttributes = myCashedReferences.at(aBaseObject);
1364   GeomAlgoAPI_ShapeTools::PointToRefsMap::const_iterator
1365     aRIt = aRefAttributes.begin(), aRLast = aRefAttributes.end();
1366   for (; aRIt != aRLast; aRIt++) {
1367     const std::list<AttributePoint2DPtr>& anAttributes = aRIt->second.first;
1368     GeomPointPtr aPoint = aRIt->first;
1369     if (!aFirstPointAttr.get() && aFirstPnt->isEqual(aPoint))
1370       aFirstPointAttr = anAttributes.front();
1371     if (!aLastPointAttr.get() && aLastPnt->isEqual(aPoint))
1372       aLastPointAttr = anAttributes.front();
1373     if (aFirstPointAttr.get() && aLastPointAttr.get())
1374       break;
1375   }
1376   if (!aFirstPointAttr.get() || !aLastPointAttr)
1377     return anAttribute;
1378
1379   return isFirstAttribute ? aFirstPointAttr : aLastPointAttr;
1380 }
1381
1382 #ifdef _DEBUG
1383 std::string SketchPlugin_Split::getFeatureInfo(const std::shared_ptr<ModelAPI_Feature>& theFeature,
1384                                                const bool isUseAttributesInfo)
1385 {
1386   std::string anInfo;
1387   if (!theFeature.get()) {
1388     return "none";
1389   }
1390
1391   if (theFeature->data()->isValid())
1392     anInfo.append(theFeature->data()->name().c_str());
1393
1394   if (isUseAttributesInfo) {
1395     std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1396                                                              getEdgeAttributes(theFeature));
1397     // processing of feature with point 2d attributes, like line, arc, circle
1398     if (!aPointsInfo.empty()) {
1399       anInfo += ": ";
1400       anInfo += "\n";
1401       anInfo += aPointsInfo;
1402     }
1403     else { // process constraint coincidence, find points in ref attr attributes
1404       std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1405                                                        ModelAPI_AttributeRefAttr::typeId());
1406       std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1407       std::string anAttributesInfo;
1408       for(; anIt != aLast; anIt++) {
1409         if (!anAttributesInfo.empty()) {
1410           anAttributesInfo.append(", ");
1411           anAttributesInfo += "\n";
1412         }
1413         AttributePtr anAttr = *anIt;
1414         std::string aValue = "not defined";
1415         std::string aType = anAttr->attributeType();
1416         if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1417           std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1418                              std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1419           if (aRefAttr.get()) {
1420             if (aRefAttr->isObject()) {
1421               FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1422               aValue = "<object:>" + getFeatureInfo(aFeature, false);
1423             }
1424             else {
1425               AttributePtr anAttribute = aRefAttr->attr();
1426               if (anAttribute.get()) {
1427                 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1428                 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1429                          " [" + getFeatureInfo(aFeature, false) + "]";
1430               }
1431             }
1432           }
1433         }
1434         anAttributesInfo.append("    " + anAttr->id() + ": " + aValue);
1435       }
1436       if (!anAttributesInfo.empty())
1437         anInfo = anInfo + "\n" + anAttributesInfo;
1438     }
1439   }
1440   return anInfo;
1441 }
1442 #endif