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