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