]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_Split.cpp
Salome HOME
720da74a6f318af71193fc89b3e690462e5679b6
[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 #include <GeomAlgoAPI_CompoundBuilder.h>
31
32 #include <ModelAPI_AttributeBoolean.h>
33 #include <ModelAPI_AttributeDouble.h>
34 #include <ModelAPI_AttributeRefAttr.h>
35 #include <ModelAPI_AttributeReference.h>
36 #include <ModelAPI_AttributeString.h>
37 #include <ModelAPI_Events.h>
38 #include <ModelAPI_Validator.h>
39 #include <ModelAPI_Session.h>
40 #include <ModelAPI_Tools.h>
41
42 #include <ModelGeomAlgo_Shape.h>
43
44 #include <SketchPlugin_Arc.h>
45 #include <SketchPlugin_Circle.h>
46 #include <SketchPlugin_ConstraintCoincidence.h>
47 #include <SketchPlugin_ConstraintEqual.h>
48 #include <SketchPlugin_ConstraintLength.h>
49 #include <SketchPlugin_ConstraintMiddle.h>
50 #include <SketchPlugin_ConstraintMirror.h>
51 #include <SketchPlugin_ConstraintParallel.h>
52 #include <SketchPlugin_ConstraintTangent.h>
53 #include <SketchPlugin_Line.h>
54 #include <SketchPlugin_MultiRotation.h>
55 #include <SketchPlugin_MultiTranslation.h>
56 #include <SketchPlugin_Point.h>
57 #include <SketchPlugin_Tools.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   // TODO: remove
93   //data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeReference::typeId());
94   //data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
95   //data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
96 }
97
98 void SketchPlugin_Split::execute()
99 {
100   std::shared_ptr<ModelAPI_Data> aData = data();
101
102   // Check the base objects are initialized.
103   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
104                                                            data()->attribute(SELECTED_OBJECT()));
105   //ObjectPtr aBaseObject = anObjectAttr->value();
106   //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
107   //                                          aData->attribute(SketchPlugin_Constraint::VALUE()));
108   if(!aBaseObjectAttr->isInitialized()) {
109     setError("Error: Base object is not initialized.");
110     return;
111   }
112   ObjectPtr aBaseObject = aBaseObjectAttr->value();
113   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
114   //  getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
115   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
116   //  getPointOfRefAttr(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
117   if (!aFirstPointAttrOfSplit.get() || !aFirstPointAttrOfSplit->isInitialized() ||
118       !aSecondPointAttrOfSplit.get() || !aSecondPointAttrOfSplit->isInitialized()) {
119     setError("Error: Sub-shape is not initialized.");
120     return;
121   }
122
123   /// Remove reference of this feature to feature used in preview, it is not necessary anymore
124   /// as trim will be removed after execute
125   AttributeReferencePtr aPreviewObjectAttr =
126                      std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
127                      data()->attribute(PREVIEW_OBJECT()));
128
129   ObjectPtr aPreviewObject = aPreviewObjectAttr->value();
130   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
131                                            data()->attribute(PREVIEW_POINT()));
132   std::shared_ptr<GeomAPI_Pnt2d> aPreviewPnt2d = aPoint->pnt();
133   // nullify pointer of preview attribute
134   aPreviewObjectAttr->setValue(ResultPtr());
135   bool anIsEqualPreviewAndSelected = aPreviewObject == aBaseObject;
136
137   // Wait all constraints being created, then send update events
138   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
139   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
140   if (isUpdateFlushed)
141     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
142
143   // Find feature constraints
144   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
145   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
146   std::set<FeaturePtr> aFeaturesToDelete, aFeaturesToUpdate;
147
148   //std::map<FeaturePtr, IdToPointPair> aTangentFeatures;
149   std::map<FeaturePtr, IdToPointPair> aCoincidenceToFeature;
150   getConstraints(aFeaturesToDelete, aFeaturesToUpdate, /*aTangentFeatures, */
151                  aCoincidenceToFeature);
152
153   std::map<AttributePtr, std::list<AttributePtr> > aBaseRefAttributes;
154   std::list<AttributePtr> aRefsToFeature;
155   getRefAttributes(aBaseFeature, aBaseRefAttributes, aRefsToFeature);
156
157   std::map<AttributePtr, AttributePtr> aBasePointModifiedAttributes;
158
159 #ifdef DEBUG_SPLIT
160   std::cout << std::endl;
161   std::cout << "SketchPlugin_Split::execute()" << std::endl;
162   std::cout << std::endl;
163
164   SketchPlugin_Sketch* aSketch = sketch();
165   std::cout << "SKETCH FEATURES (before split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
166   for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
167     std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
168   }
169
170   std::cout << std::endl;
171   std::cout << "---- IN PARAMETERS ----" << std::endl;
172   std::cout << "Base feature:" << getFeatureInfo(aBaseFeature) << std::endl;
173   std::cout << std::endl;
174
175   if (!aCoincidenceToFeature.empty()) {
176     std::cout << "Coincidences to base feature[" <<
177       aCoincidenceToFeature.size() << "]: " << std::endl;
178     std::map<FeaturePtr, IdToPointPair>::const_iterator anIt = aCoincidenceToFeature.begin(),
179                                                         aLast = aCoincidenceToFeature.end();
180     for (int i = 1; anIt != aLast; anIt++, i++) {
181       FeaturePtr aFeature = (*anIt).first;
182       std::string anAttributeId = (*anIt).second.first;
183       std::shared_ptr<GeomDataAPI_Point2D> aPointAttr = (*anIt).second.second;
184
185       std::cout << i << "-" << getFeatureInfo(aFeature) << std::endl;
186       std::cout <<     " -Attribute to correct:" << anAttributeId << std::endl;
187       std::cout <<     " -Point attribute:" <<
188         ModelGeomAlgo_Point2D::getPointAttributeInfo(aPointAttr) << std::endl;
189     }
190   }
191
192   std::map<AttributePtr, std::list<AttributePtr> >::const_iterator
193     aRefIt = aBaseRefAttributes.begin(), aRefLast = aBaseRefAttributes.end();
194   std::cout << std::endl << "References to attributes of base feature [" <<
195     aBaseRefAttributes.size() << "]" << std::endl;
196   for (; aRefIt != aRefLast; aRefIt++) {
197     AttributePtr aBaseAttr = aRefIt->first;
198     std::list<AttributePtr> aRefAttributes = aRefIt->second;
199     std::string aRefsInfo;
200     std::list<AttributePtr>::const_iterator aRefAttrIt = aRefAttributes.begin(),
201                                             aRefAttrLast = aRefAttributes.end();
202     for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
203       if (!aRefsInfo.empty())
204         aRefsInfo.append(",");
205       AttributePtr aRAttr = *aRefAttrIt;
206       aRefsInfo.append(aRAttr->id());
207       FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
208       aRefsInfo.append("(" + aRFeature->name() + ") ");
209     }
210     std::shared_ptr<GeomDataAPI_Point2D> aPointAttr =
211       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aBaseAttr);
212     std::cout << aPointAttr->id().c_str() <<
213       ": " << "[" << aRefAttributes.size() << "] " << aRefsInfo << std::endl;
214   }
215   std::cout << std::endl;
216   std::cout << std::endl << "References to base feature [" <<
217     aRefsToFeature.size() << "]" << std::endl;
218   std::list<AttributePtr>::const_iterator aRefAttrIt = aRefsToFeature.begin(),
219                                           aRefAttrLast = aRefsToFeature.end();
220   std::string aRefsInfo;
221   for (; aRefAttrIt != aRefAttrLast; aRefAttrIt++) {
222     if (!aRefsInfo.empty())
223       aRefsInfo.append(",");
224     AttributePtr aRAttr = *aRefAttrIt;
225     aRefsInfo.append(aRAttr->id());
226     FeaturePtr aRFeature = ModelAPI_Feature::feature(aRAttr->owner());
227     aRefsInfo.append("(" + aRFeature->name() + ") ");
228   }
229   std::cout << "[" << aRefsToFeature.size() << "] " << aRefsInfo << std::endl;
230
231
232   std::cout << std::endl;
233   std::cout << "---- SPLIT ----" << std::endl;
234   std::cout << std::endl;
235 #endif
236
237   std::string aFeatureKind = aBaseFeature->getKind();
238   FeaturePtr aSplitFeature, anAfterFeature;
239   std::set<AttributePoint2DPtr> aFurtherCoincidences;
240   std::set<FeaturePtr> aCreatedFeatures;
241   std::set<std::pair<AttributePtr, AttributePtr>> aModifiedAttributes;
242   FeaturePtr aReplacingFeature, aNewFeature;
243   if (aFeatureKind == SketchPlugin_Line::ID())
244     aNewFeature = splitLine(aSplitFeature, aBaseFeature, anAfterFeature,
245                             aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
246   else if (aFeatureKind == SketchPlugin_Arc::ID())
247     aNewFeature = splitArc(aSplitFeature, aBaseFeature, anAfterFeature, aFurtherCoincidences,
248                            aCreatedFeatures, aModifiedAttributes);
249   if (aFeatureKind == SketchPlugin_Circle::ID()) {
250     FeaturePtr aCircleFeature = aBaseFeature;
251     aReplacingFeature = splitCircle(aSplitFeature, aBaseFeature, anAfterFeature,
252                                     aFurtherCoincidences, aCreatedFeatures, aModifiedAttributes);
253
254     updateRefFeatureConstraints(getFeatureResult(aBaseFeature), aRefsToFeature);
255
256     AttributePtr aCenterAttr = aCircleFeature->attribute(SketchPlugin_Circle::CENTER_ID());
257     aFeaturesToDelete.insert(aCircleFeature);
258     // as circle is removed, temporary fill this attribute*/
259     aBaseObjectAttr->setObject(ResultPtr());
260   }
261
262 #ifdef DEBUG_SPLIT
263   std::cout << "---- OUT PARAMETERS ----" << std::endl;
264   std::cout << "Base modified feature:" << getFeatureInfo(aBaseFeature) << std::endl;
265   std::cout << "Split feature:" << getFeatureInfo(aSplitFeature) << std::endl;
266   std::cout << "After feature:" << getFeatureInfo(anAfterFeature) << std::endl;
267   std::cout << std::endl;
268
269   std::cout << "Created features by split:[" << aCreatedFeatures.size() << "]" << std::endl;
270   std::set<FeaturePtr>::const_iterator aFIt = aCreatedFeatures.begin(),
271                                        aFLast = aCreatedFeatures.end();
272   for (; aFIt != aFLast; aFIt++) {
273     std::cout << getFeatureInfo(*aFIt) << std::endl;
274   }
275   std::cout << std::endl;
276
277   std::cout << "Attributes for further Coincidences:" << std::endl;
278   std::set<AttributePoint2DPtr>::const_iterator anIt = aFurtherCoincidences.begin(),
279                                                 aLast = aFurtherCoincidences.end();
280   for (; anIt != aLast; anIt++) {
281     AttributePtr anAttribute = *anIt;
282     FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
283     std::cout << ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute)
284               << " [" << getFeatureInfo(aFeature, false) << "]" << std::endl;
285   }
286
287   std::cout << "Modifed attributes (constraints to attributes are moved here):" << std::endl;
288   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
289     aPIt = aModifiedAttributes.begin(), aPLast = aModifiedAttributes.end();
290   std::string aResInfo;
291   for (; aPIt != aPLast; aPIt++) {
292     if (!aResInfo.empty())
293       aResInfo += "\n";
294
295     std::pair<AttributePtr, AttributePtr> aPair = *aPIt;
296
297     AttributePtr anAttr = aPair.first;
298     aResInfo.append(anAttr->id());
299     FeaturePtr aFeature = ModelAPI_Feature::feature(anAttr->owner());
300     aResInfo.append("(" + aFeature->name() + ") ");
301
302     aResInfo.append("  - is modified to -  ");
303
304     anAttr = aPair.second;
305     aResInfo.append(anAttr->id());
306     aFeature = ModelAPI_Feature::feature(anAttr->owner());
307     aResInfo.append("(" + aFeature->name() + ") ");
308   }
309   std::cout << aResInfo << std::endl;
310 #endif
311
312   std::set<ResultPtr> aFeatureResults;
313   aFeatureResults.insert(getFeatureResult(aBaseFeature));
314   if (anAfterFeature.get() && anAfterFeature != aBaseFeature)
315     aFeatureResults.insert(getFeatureResult(anAfterFeature));
316
317   // coincidence to feature
318   updateCoincidenceConstraintsToFeature(aCoincidenceToFeature, aFurtherCoincidences,
319                                         aFeatureResults, aSplitFeature, aFeaturesToDelete);
320
321   updateRefAttConstraints(aBaseRefAttributes, aModifiedAttributes);
322
323   // delete constraints
324 #ifdef DEBUG_SPLIT
325   std::cout << "remove features and references:" << std::endl;
326   std::set<FeaturePtr>::const_iterator aDIt = aFeaturesToDelete.begin(),
327                                        aDLast = aFeaturesToDelete.end();
328   for (; aDIt != aDLast; aDIt++) {
329     std::cout << getFeatureInfo(*aDIt, false) << std::endl;
330     std::cout << std::endl;
331   }
332 #endif
333   ModelAPI_Tools::removeFeaturesAndReferences(aFeaturesToDelete);
334   Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
335
336 #ifdef DEBUG_SPLIT
337   std::cout << "update features after split:" << std::endl;
338   std::set<FeaturePtr>::const_iterator anUIt = aFeaturesToUpdate.begin(),
339                                        anULast = aFeaturesToUpdate.end();
340   for (; anUIt != anULast; anUIt++) {
341     std::cout << getFeatureInfo(*anUIt, false) << std::endl;
342     std::cout << std::endl;
343   }
344 #endif
345   updateFeaturesAfterSplit(aFeaturesToUpdate);
346
347   // Send events to update the sub-features by the solver.
348   if(isUpdateFlushed) {
349     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
350   }
351
352     if (anIsEqualPreviewAndSelected) {
353     // equal preview and selected objects
354     // nothing to do if the preview and selected objects are different
355     ResultPtr aReplacingResult;
356     if (aReplacingFeature.get()) {
357       aReplacingFeature->execute(); // need it to obtain result
358       aReplacingResult = getFeatureResult(aReplacingFeature);
359     }
360     if (aReplacingResult.get()) { // base object was removed
361       aPreviewObject = aReplacingResult;
362       //aMessage->setSelectedObject(aReplacingResult);
363
364       //GeomShapePtr aSelectedShape = aReplacingResult->shape();
365       //std::shared_ptr<GeomAPI_Pnt> aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(),
366       //                                                          aPreviewPnt2d->y());
367       //std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
368       //if (ModelGeomAlgo_Point2D::isPointOnEdge(aSelectedShape, aPreviewPnt, aProjectedPoint)) {
369         //bool aValue = true;
370       //}
371       //aBaseShape = aShape;
372
373 #ifdef DEBUG_SPLIT
374       if (!aSelectedShape.get())
375         std::cout << "Set empty selected object" << std::endl;
376       else
377         std::cout << "Set shape with ShapeType: " << aSelectedShape->shapeTypeStr() << std::endl;
378 #endif
379       //bool aValue = true;
380     }
381     else {
382       aPreviewObject = ObjectPtr();
383
384       aBaseFeature->execute(); // should recompute shapes of result to do not check obsolete one
385       aBaseObject = getFeatureResult(aBaseFeature);
386       std::shared_ptr<GeomAPI_Pnt> aPreviewPnt = sketch()->to3D(aPreviewPnt2d->x(),
387                                                                 aPreviewPnt2d->y());
388       ResultPtr aBaseResult = std::dynamic_pointer_cast<ModelAPI_Result>(aBaseObject);
389       if (aBaseResult) {
390         GeomShapePtr aShape = aBaseResult->shape();
391         std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
392         if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPreviewPnt, aProjectedPoint))
393           aPreviewObject = aBaseResult;
394       }
395       if (!aPreviewObject.get() && aNewFeature.get()) {
396         ResultPtr aNewFeatureResult = getFeatureResult(aNewFeature);
397         if (aNewFeatureResult.get()) {
398           GeomShapePtr aShape = aNewFeatureResult->shape();
399           std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
400           if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPreviewPnt, aProjectedPoint))
401             aPreviewObject = aNewFeatureResult;
402         }
403       }
404     }
405   }
406   if (aPreviewObject.get()) {
407     std::shared_ptr<ModelAPI_EventReentrantMessage> aMessage = std::shared_ptr
408       <ModelAPI_EventReentrantMessage>(new ModelAPI_EventReentrantMessage(
409                                            ModelAPI_EventReentrantMessage::eventId(), this));
410     aMessage->setSelectedObject(aPreviewObject);
411     Events_Loop::loop()->send(aMessage);
412   }
413
414
415 #ifdef DEBUG_SPLIT
416   std::cout << "SKETCH FEATURES (after split) [" << aSketch->numberOfSubs() << "]:" << std::endl;
417   for (int i = 0, aNbSubs = aSketch->numberOfSubs(); i < aNbSubs; i++) {
418     std::cout << getFeatureInfo(aSketch->subFeature(i), false) << std::endl;
419   }
420 #endif
421 }
422
423 // LCOV_EXCL_START
424 std::string SketchPlugin_Split::processEvent(const std::shared_ptr<Events_Message>& theMessage)
425 {
426 #ifdef DEBUG_SPLIT
427   std::cout << "SketchPlugin_Split::processEvent:" << data()->name() << std::endl;
428 #endif
429   std::string aFilledAttributeName;
430
431   std::shared_ptr<ModelAPI_EventReentrantMessage> aMessage =
432         std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
433   if (aMessage.get()) {
434     ObjectPtr anObject = aMessage->selectedObject();
435     std::shared_ptr<GeomAPI_Pnt2d> aPoint = aMessage->clickedPoint();
436
437     if (anObject.get() && aPoint.get()) {
438       //if (myCashedShapes.find(anObject) == myCashedShapes.end())
439       //  fillObjectShapes(anObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
440       if (myCashedShapes.find(anObject) == myCashedShapes.end())
441         fillObjectShapes(anObject, sketch()->data()->owner());
442       const std::set<GeomShapePtr>& aShapes = myCashedShapes[anObject];
443       if (aShapes.size() > 1) {
444         std::shared_ptr<ModelAPI_AttributeReference> aRefSelectedAttr =
445                               std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
446                               data()->attribute(SELECTED_OBJECT()));
447         std::shared_ptr<ModelAPI_AttributeReference> aRefPreviewAttr =
448                               std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
449                               data()->attribute(PREVIEW_OBJECT()));
450         aRefSelectedAttr->setValue(anObject);
451         aRefPreviewAttr->setValue(anObject);
452
453         std::shared_ptr<GeomDataAPI_Point2D> aPointSelectedAttr =
454                               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
455                               data()->attribute(SELECTED_POINT()));
456         std::shared_ptr<GeomDataAPI_Point2D> aPointPreviewAttr =
457                               std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
458                               data()->attribute(PREVIEW_POINT()));
459         aPointSelectedAttr->setValue(aPoint);
460         aPointPreviewAttr->setValue(aPoint);
461
462         Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
463
464         GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
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   /*AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
492                                            data()->attribute(SketchPlugin_Constraint::VALUE()));
493   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
494
495   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
496                                         data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
497   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
498                                         data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
499
500   if (aBaseObjectAttr->isInitialized() && aBaseFeature.get() &&
501       aFirstPointAttrOfSplit->isInitialized() &&
502       aSecondPointAttrOfSplit->isInitialized()) {
503
504     ResultPtr aResult = getFeatureResult(aBaseFeature);
505     GeomShapePtr aBaseShape = aResult->shape();
506     std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
507
508     std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
509     std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
510     aPoints.push_back(aStartPoint);
511
512     std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
513     std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
514       sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
515     aPoints.push_back(aSecondPoint);
516
517     std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
518
519     GeomAlgoAPI_ShapeTools::splitShape_p(aBaseShape, aPoints, aSplitShapes);
520     std::shared_ptr<GeomAPI_Shape> aShape =
521       GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
522
523     AISObjectPtr anAIS = thePrevious;
524     if (aShape) {
525       if (!anAIS)
526         anAIS = AISObjectPtr(new GeomAPI_AISObject);
527       anAIS->createShape(aShape);
528       std::shared_ptr<ModelAPI_AttributeBoolean> anAuxiliaryAttr =
529              aBaseFeature->data()->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID());
530
531       bool isConstruction = anAuxiliaryAttr.get() != NULL && anAuxiliaryAttr->value();
532
533       std::vector<int> aColor;
534       double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
535       int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
536       if (isConstruction) {
537         aColor = Config_PropManager::color("Visualization", "sketch_auxiliary_color");
538         aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH_AUXILIARY();
539         aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY();
540       }
541       else {
542         aColor = Config_PropManager::color("Visualization", "sketch_entity_color");
543       }
544       anAIS->setColor(aColor[0], aColor[1], aColor[2]);
545       anAIS->setWidth(aWidth + 1);
546       anAIS->setLineStyle(aLineStyle);
547     }
548     return anAIS;
549   }
550   return AISObjectPtr();*/
551 #ifdef DEBUG_SPLIT
552   std::cout << "SketchPlugin_Split::getAISObject: " << data()->name() << std::endl;
553 #endif
554
555   AISObjectPtr anAIS = thePrevious;
556
557   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
558   GeomShapePtr aPreviewShape = getSubShape(PREVIEW_OBJECT(), PREVIEW_POINT());
559   if (aPreviewShape.get())
560     aShapes.push_back(aPreviewShape);
561   GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
562   if (aSelectedShape.get())
563     aShapes.push_back(aSelectedShape);
564
565   if (aShapes.empty())
566     return AISObjectPtr();
567
568   GeomShapePtr aBaseShape = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
569   if (!aBaseShape.get())
570     return AISObjectPtr();
571
572   if (aBaseShape.get()) {
573     if (!anAIS)
574       anAIS = AISObjectPtr(new GeomAPI_AISObject);
575     anAIS->createShape(aBaseShape);
576
577     std::vector<int> aColor;
578     aColor = Config_PropManager::color("Visualization", "operation_remove_feature_color");
579     double aWidth = SketchPlugin_SketchEntity::SKETCH_LINE_WIDTH();
580     int aLineStyle = SketchPlugin_SketchEntity::SKETCH_LINE_STYLE();
581     anAIS->setColor(aColor[0], aColor[1], aColor[2]);
582     // width when there is not base object should be extened in several points
583     // in order to see this preview over highlight
584     anAIS->setWidth(aWidth+4);
585     anAIS->setLineStyle(aLineStyle);
586   }
587   else
588     anAIS = AISObjectPtr();
589   return anAIS;
590 }
591
592 //********************************************************************
593 void SketchPlugin_Split::fillObjectShapes(const ObjectPtr& theObject,
594                                           const ObjectPtr& theSketch)
595 {
596   std::set<std::shared_ptr<GeomAPI_Shape> > aShapes;
597   std::map<std::shared_ptr<GeomDataAPI_Point2D>, std::shared_ptr<GeomAPI_Pnt> > aPointToAttributes;
598   std::set<std::shared_ptr<GeomDataAPI_Point2D> > aRefAttributes;
599   // current feature
600   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
601   // edges on feature
602   std::set<ResultPtr> anEdgeResults;
603   ModelGeomAlgo_Shape::shapesOfType(aFeature, GeomAPI_Shape::EDGE, anEdgeResults);
604   if (!anEdgeResults.empty()) {
605     GeomShapePtr aFeatureShape = (*anEdgeResults.begin())->shape();
606
607     // coincidences to the feature
608     ModelGeomAlgo_Point2D::getPointsOfReference(aFeature, SketchPlugin_ConstraintCoincidence::ID(),
609                          aRefAttributes, SketchPlugin_Point::ID(), SketchPlugin_Point::COORD_ID());
610     // layed on feature coincidences to divide it on several shapes
611     std::shared_ptr<ModelAPI_Data> aData = theSketch->data();
612     std::shared_ptr<GeomDataAPI_Point> aC = std::dynamic_pointer_cast<GeomDataAPI_Point>(
613         aData->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
614     std::shared_ptr<GeomDataAPI_Dir> aX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
615         aData->attribute(SketchPlugin_Sketch::DIRX_ID()));
616     std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
617         aData->attribute(SketchPlugin_Sketch::NORM_ID()));
618     std::shared_ptr<GeomAPI_Dir> aY(new GeomAPI_Dir(aNorm->dir()->cross(aX->dir())));
619     std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
620     ModelGeomAlgo_Point2D::getPointsInsideShape_p(aFeatureShape, aRefAttributes, aC->pnt(),
621                                                 aX->dir(), aY, aPoints, aPointToAttributes);
622
623     if (!aPoints.empty())
624       GeomAlgoAPI_ShapeTools::splitShape_p(aFeatureShape, aPoints, aShapes);
625   }
626   myCashedShapes[theObject] = aShapes;
627   myCashedReferences[theObject] = aPointToAttributes;
628 }
629
630 GeomShapePtr SketchPlugin_Split::getSubShape(const std::string& theObjectAttributeId,
631                                              const std::string& thePointAttributeId)
632 {
633   GeomShapePtr aBaseShape;
634
635   AttributeReferencePtr anObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
636                                                        data()->attribute(theObjectAttributeId));
637   ObjectPtr aBaseObject = anObjectAttr->value();
638   if (!aBaseObject.get())
639     return aBaseShape;
640
641   // point on feature
642   AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
643                                            data()->attribute(thePointAttributeId));
644   std::shared_ptr<GeomAPI_Pnt2d> anAttributePnt2d = aPointAttr->pnt();
645   std::shared_ptr<GeomAPI_Pnt> anAttributePnt = sketch()->to3D(anAttributePnt2d->x(),
646                                                                anAttributePnt2d->y());
647
648 #ifdef TRIM_SHAPE
649   if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
650     fillObjectShapes(aBaseObject, sketch()->data()->owner(), myCashedShapes, myObjectToPoints);
651
652   const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
653   if (!aShapes.empty()) {
654     std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
655     for (; anIt != aLast; anIt++) {
656       GeomShapePtr aShape = *anIt;
657       std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
658       if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, anAttributePnt, aProjectedPoint))
659         aBaseShape = aShape;
660     }
661   }
662 #else
663   if (myCashedShapes.find(aBaseObject) == myCashedShapes.end())
664     fillObjectShapes(aBaseObject, sketch()->data()->owner());
665
666   std::shared_ptr<GeomAPI_Pnt> aStartPoint;
667   std::shared_ptr<GeomAPI_Pnt> aSecondPoint;
668   const std::set<GeomShapePtr>& aShapes = myCashedShapes[aBaseObject];
669   std::set<GeomShapePtr>::const_iterator anIt = aShapes.begin(), aLast = aShapes.end();
670   for (; anIt != aLast; anIt++) {
671     GeomShapePtr aCurrentShape = *anIt;
672     std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
673     if (ModelGeomAlgo_Point2D::isPointOnEdge(aCurrentShape, anAttributePnt, aProjectedPoint)) {
674       if (aCurrentShape->shapeType() == GeomAPI_Shape::EDGE) {
675         std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aCurrentShape));
676         aStartPoint = anEdge->firstPoint();
677         aSecondPoint = anEdge->lastPoint();
678       }
679       break;
680     }
681   }
682
683   if (!aStartPoint.get() || !aSecondPoint.get())
684     return aBaseShape;
685
686   //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
687   //                                         data()->attribute(SketchPlugin_Constraint::VALUE()));
688   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject/*aBaseObjectAttr->value()*/);
689
690   //AttributePoint2DPtr aFirstPointAttrOfSplit = getPointOfRefAttr(
691   //                                      data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
692   //AttributePoint2DPtr aSecondPointAttrOfSplit = getPointOfRefAttr(
693   //                                      data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
694   if (anObjectAttr->isInitialized() && aBaseFeature.get() && aPointAttr->isInitialized()) {
695       //aFirstPointAttrOfSplit->isInitialized() &&
696       //aSecondPointAttrOfSplit->isInitialized()) {
697     ResultPtr aResult = getFeatureResult(aBaseFeature);
698     GeomShapePtr aResultShape = aResult->shape();
699     std::list<std::shared_ptr<GeomAPI_Pnt> > aPoints;
700
701     //std::shared_ptr<GeomAPI_Pnt2d> aStartPnt2d = aFirstPointAttrOfSplit->pnt();
702     //std::shared_ptr<GeomAPI_Pnt> aStartPoint = sketch()->to3D(aStartPnt2d->x(), aStartPnt2d->y());
703     aPoints.push_back(aStartPoint);
704
705     //std::shared_ptr<GeomAPI_Pnt2d> aSecondPnt2d = aSecondPointAttrOfSplit->pnt();
706     //std::shared_ptr<GeomAPI_Pnt> aSecondPoint =
707     //  sketch()->to3D(aSecondPnt2d->x(), aSecondPnt2d->y());
708     aPoints.push_back(aSecondPoint);
709
710     std::set<std::shared_ptr<GeomAPI_Shape> > aSplitShapes;
711     GeomAlgoAPI_ShapeTools::splitShape_p(aResultShape, aPoints, aSplitShapes);
712     aBaseShape = GeomAlgoAPI_ShapeTools::findShape(aPoints, aSplitShapes);
713 #endif
714   }
715   return aBaseShape;
716 }
717
718 void SketchPlugin_Split::getFeaturePoints(const FeaturePtr& theFeature,
719                                                     AttributePoint2DPtr& theStartPointAttr,
720                                                     AttributePoint2DPtr& theEndPointAttr)
721 {
722   std::string aFeatureKind = theFeature->getKind();
723   std::string aStartAttributeName, anEndAttributeName;
724   if (aFeatureKind == SketchPlugin_Line::ID()) {
725     aStartAttributeName = SketchPlugin_Line::START_ID();
726     anEndAttributeName = SketchPlugin_Line::END_ID();
727   }
728   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
729     aStartAttributeName = SketchPlugin_Arc::START_ID();
730     anEndAttributeName = SketchPlugin_Arc::END_ID();
731   }
732   if (!aStartAttributeName.empty() && !anEndAttributeName.empty()) {
733     theStartPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
734                                          theFeature->attribute(aStartAttributeName));
735     theEndPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
736                                          theFeature->attribute(anEndAttributeName));
737   }
738 }
739
740 void SketchPlugin_Split::getConstraints(std::set<FeaturePtr>& theFeaturesToDelete,
741                                     std::set<FeaturePtr>& theFeaturesToUpdate,
742                                     std::map<FeaturePtr, IdToPointPair>& theCoincidenceToFeature)
743 {
744   std::shared_ptr<ModelAPI_Data> aData = data();
745
746   // Check the base objects are initialized.
747   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
748                                                            data()->attribute(SELECTED_OBJECT()));
749   //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
750   //                                          aData->attribute(SketchPlugin_Constraint::VALUE()));
751   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
752   ResultPtr aBaseFeatureResult = getFeatureResult(aBaseFeature);
753
754   std::set<AttributePtr> aRefsList = aBaseFeatureResult->data()->refsToMe();
755   std::set<AttributePtr> aFRefsList = aBaseFeature->data()->refsToMe();
756   aRefsList.insert(aFRefsList.begin(), aFRefsList.end());
757
758   std::set<AttributePtr>::const_iterator aIt;
759   for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
760     std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
761     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
762     std::string aRefFeatureKind = aRefFeature->getKind();
763     if (aRefFeatureKind == SketchPlugin_ConstraintMirror::ID() ||
764         aRefFeatureKind == SketchPlugin_MultiRotation::ID() ||
765         aRefFeatureKind == SketchPlugin_MultiTranslation::ID() ||
766         aRefFeatureKind == SketchPlugin_ConstraintMiddle::ID())
767       theFeaturesToDelete.insert(aRefFeature);
768     else if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID())
769       theFeaturesToUpdate.insert(aRefFeature);
770     else if (aRefFeatureKind == SketchPlugin_ConstraintCoincidence::ID()) {
771       std::string anAttributeToBeModified;
772       AttributePoint2DPtr aCoincidentPoint;
773       AttributeRefAttrPtr anAttrA = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_A());
774       AttributeRefAttrPtr anAttrB = aRefFeature->refattr(SketchPlugin_Constraint::ENTITY_B());
775       bool isToFeature = false;
776       if (anAttrA->isObject() || anAttrB->isObject()) { /// coincidence to base feature
777         FeaturePtr aFeature = anAttrA->isObject() ? ModelAPI_Feature::feature(anAttrA->object())
778                                                   : FeaturePtr();
779         isToFeature = aFeature.get() && aFeature == aBaseFeature;
780         anAttributeToBeModified = anAttrA->id();
781         if (!isToFeature) {
782           aFeature = anAttrB->isObject() ? ModelAPI_Feature::feature(anAttrB->object())
783                                          : FeaturePtr();
784           isToFeature = aFeature.get() && aFeature == aBaseFeature;
785           anAttributeToBeModified = anAttrB->id();
786         }
787         if (isToFeature)
788           aCoincidentPoint = SketchPlugin_ConstraintCoincidence::getPoint(aRefFeature);
789       }
790       if (!isToFeature) { /// coincidence to point on base feature
791         AttributePtr anAttribute;
792
793         if (!anAttrA->isObject()) {
794           AttributePtr aCurAttribute = anAttrA->attr();
795           if (aCurAttribute.get()) {
796             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
797             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
798               anAttribute = anAttrB->attr();
799               anAttributeToBeModified = anAttrA->id();
800             }
801           }
802         }
803         if (!anAttribute.get() && !anAttrB->isObject()) {
804           AttributePtr aCurAttribute = anAttrB->attr();
805           if (aCurAttribute.get()) {
806             FeaturePtr aCurFeature = ModelAPI_Feature::feature(aCurAttribute->owner());
807             if (aCurFeature.get() && aCurFeature == aBaseFeature) {
808               anAttribute = anAttrA->attr();
809               anAttributeToBeModified = anAttrB->id();
810             }
811           }
812         }
813         if (anAttribute.get())
814           aCoincidentPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttribute);
815       }
816       if (aCoincidentPoint.get() && isToFeature)
817         theCoincidenceToFeature[aRefFeature] = std::make_pair(anAttributeToBeModified,
818                                                               aCoincidentPoint);
819     }
820   }
821 }
822
823 void SketchPlugin_Split::getRefAttributes(const FeaturePtr& theFeature,
824                                     std::map<AttributePtr, std::list<AttributePtr> >& theRefs,
825                                     std::list<AttributePtr>& theRefsToFeature)
826 {
827   theRefs.clear();
828
829   std::list<AttributePtr> aPointAttributes =
830     theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
831   std::set<AttributePtr> aPointAttributesSet;
832
833   std::list<AttributePtr>::const_iterator aPIt =
834     aPointAttributes.begin(), aPLast = aPointAttributes.end();
835   for (; aPIt != aPLast; aPIt++)
836     aPointAttributesSet.insert(*aPIt);
837
838   std::set<AttributePtr> aRefsAttributes = getFeatureResult(theFeature)->data()->refsToMe();
839   std::set<AttributePtr> aFRefsList = theFeature->data()->refsToMe();
840   aRefsAttributes.insert(aFRefsList.begin(), aFRefsList.end());
841
842   std::set<AttributePtr>::const_iterator aIt;
843   for (aIt = aRefsAttributes.cbegin(); aIt != aRefsAttributes.cend(); ++aIt) {
844     AttributePtr anAttr = (*aIt);
845     FeaturePtr anAttrFeature = ModelAPI_Feature::feature(anAttr->owner());
846     if (anAttrFeature.get() != this &&
847         anAttr.get() && anAttr->attributeType() == ModelAPI_AttributeRefAttr::typeId()) {
848       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
849       if (!aRefAttr->isObject()) { /// find attributes referenced to feature point attributes
850         AttributePtr anAttrInRef = aRefAttr->attr();
851         if (anAttrInRef.get() &&
852             aPointAttributesSet.find(anAttrInRef) != aPointAttributesSet.end()) {
853           if (theRefs.find(anAttrInRef) != theRefs.end())
854             theRefs[anAttrInRef].push_back(aRefAttr);
855           else {
856             std::list<AttributePtr> anAttrList;
857             anAttrList.push_back(aRefAttr);
858             theRefs[anAttrInRef] = anAttrList;
859           }
860         }
861       }
862       else { /// find attributes referenced to feature itself
863         theRefsToFeature.push_back(anAttr);
864       }
865     }
866   }
867 }
868
869 void SketchPlugin_Split::updateCoincidenceConstraintsToFeature(
870       const std::map<std::shared_ptr<ModelAPI_Feature>, IdToPointPair>& theCoincidenceToFeature,
871       const std::set<std::shared_ptr<GeomDataAPI_Point2D> >& theFurtherCoincidences,
872       const std::set<ResultPtr>& theFeatureResults,
873       const FeaturePtr& theSplitFeature,
874       std::set<FeaturePtr>& theFeaturesToDelete)
875 {
876   if (theCoincidenceToFeature.empty())
877     return;
878
879   // we should build coincidence constraints to end of the split feature
880   std::set<std::shared_ptr<GeomDataAPI_Point2D> > aNewCoincidencesToSplitFeature;
881   AttributePoint2DPtr aStartPointAttr, anEndPointAttr;
882   getFeaturePoints(theSplitFeature, aStartPointAttr, anEndPointAttr);
883   if (theFurtherCoincidences.find(aStartPointAttr) == theFurtherCoincidences.end())
884     aNewCoincidencesToSplitFeature.insert(aStartPointAttr);
885   if (theFurtherCoincidences.find(anEndPointAttr) == theFurtherCoincidences.end())
886     aNewCoincidencesToSplitFeature.insert(anEndPointAttr);
887
888   std::map<FeaturePtr, IdToPointPair>::const_iterator aCIt = theCoincidenceToFeature.begin(),
889                                                             aCLast = theCoincidenceToFeature.end();
890 #ifdef DEBUG_SPLIT
891   std::cout << std::endl;
892   std::cout << "Coincidences to feature(modified):"<< std::endl;
893 #endif
894   for (; aCIt != aCLast; aCIt++) {
895     FeaturePtr aCoincFeature = aCIt->first;
896     std::string anAttributeId = aCIt->second.first;
897     std::string aSecondAttribute = anAttributeId == SketchPlugin_Constraint::ENTITY_A() ?
898         SketchPlugin_Constraint::ENTITY_B() : SketchPlugin_Constraint::ENTITY_A();
899
900     AttributePoint2DPtr aCoincPoint = aCIt->second.second;
901     std::set<AttributePoint2DPtr>::const_iterator aFCIt = theFurtherCoincidences.begin(),
902                                                   aFCLast = theFurtherCoincidences.end();
903     std::shared_ptr<GeomAPI_Pnt2d> aCoincPnt = aCoincPoint->pnt();
904     AttributePoint2DPtr aFeaturePointAttribute;
905     for (; aFCIt != aFCLast && !aFeaturePointAttribute.get(); aFCIt++) {
906       AttributePoint2DPtr aFCAttribute = *aFCIt;
907       if (aCoincPnt->isEqual(aFCAttribute->pnt()))
908         aFeaturePointAttribute = aFCAttribute;
909     }
910     if (aFeaturePointAttribute.get()) {
911       // create new constraint and remove the current
912       aCoincFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
913           SketchPlugin_ConstraintCoincidence::ID(),
914           aFeaturePointAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
915       theFeaturesToDelete.insert(aCIt->first);
916       // create new coincidences to split feature points
917       std::set<AttributePoint2DPtr>::const_iterator aSFIt = aNewCoincidencesToSplitFeature.begin(),
918                                                     aSFLast = aNewCoincidencesToSplitFeature.end();
919       for (; aSFIt != aSFLast; aSFIt++) {
920         AttributePoint2DPtr aSFAttribute = *aSFIt;
921         if (aCoincPnt->isEqual(aSFAttribute->pnt())) {
922           SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
923                            SketchPlugin_ConstraintCoincidence::ID(),
924                            aSFAttribute, aCoincFeature->refattr(aSecondAttribute)->attr());
925         }
926       }
927     }
928     else {
929       /// find feature by shape intersected the point
930       ResultPtr aResultForCoincidence = *(theFeatureResults.begin());
931
932       if (theFeatureResults.size() > 1) { // try to find point on additional feature
933         ResultPtr anAddtionalResult = *(theFeatureResults.begin()++);
934         GeomShapePtr aShape = anAddtionalResult->shape();
935
936         std::shared_ptr<GeomAPI_Pnt2d> aPnt2d = aCoincPoint->pnt();
937         std::shared_ptr<GeomAPI_Pnt> aPoint = sketch()->to3D(aPnt2d->x(), aPnt2d->y());
938
939         std::shared_ptr<GeomAPI_Pnt> aProjectedPoint;
940         if (ModelGeomAlgo_Point2D::isPointOnEdge(aShape, aPoint, aProjectedPoint))
941           aResultForCoincidence = anAddtionalResult;
942       }
943       aCoincFeature->refattr(anAttributeId)->setObject(aResultForCoincidence);
944     }
945 #ifdef DEBUG_SPLIT
946   std::cout << " -" << getFeatureInfo(aCoincFeature) << std::endl;
947 #endif
948   }
949 }
950
951 void SketchPlugin_Split::updateRefFeatureConstraints(
952                                                   const ResultPtr& theFeatureBaseResult,
953                                                   const std::list<AttributePtr>& theRefsToFeature)
954 {
955   std::list<AttributePtr>::const_iterator anIt = theRefsToFeature.begin(),
956                                           aLast = theRefsToFeature.end();
957   for (; anIt != aLast; anIt++) {
958     AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
959     if (aRefAttr.get())
960       aRefAttr->setObject(theFeatureBaseResult);
961   }
962 }
963
964 void SketchPlugin_Split::updateRefAttConstraints(
965                     const std::map<AttributePtr, std::list<AttributePtr> >& theBaseRefAttributes,
966                     const std::set<std::pair<AttributePtr, AttributePtr> >& theModifiedAttributes)
967 {
968 #ifdef DEBUG_SPLIT
969   std::cout << "SketchPlugin_Split::updateRefAttConstraints" << std::endl;
970 #endif
971
972   std::set<std::pair<AttributePtr, AttributePtr> >::const_iterator
973     anIt = theModifiedAttributes.begin(),  aLast = theModifiedAttributes.end();
974   for (; anIt != aLast; anIt++) {
975     AttributePtr anAttribute = anIt->first;
976
977     /// not found in references
978     if (theBaseRefAttributes.find(anAttribute) == theBaseRefAttributes.end())
979       continue;
980     std::list<AttributePtr> aRefAttributes = theBaseRefAttributes.at(anAttribute);
981     std::list<AttributePtr>::const_iterator aRefIt = aRefAttributes.begin(),
982                                             aRLast = aRefAttributes.end();
983
984     AttributePtr aNewAttribute = anIt->second;
985     for (; aRefIt != aRLast; aRefIt++) {
986       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*aRefIt);
987       if (aRefAttr.get()) {
988         aRefAttr->setAttr(aNewAttribute);
989 #ifdef DEBUG_SPLIT
990         FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->owner());
991         std::cout << " -" << getFeatureInfo(aFeature) << std::endl;
992 #endif
993       }
994     }
995   }
996 }
997
998 FeaturePtr SketchPlugin_Split::splitLine(FeaturePtr& theSplitFeature,
999                                              FeaturePtr& theBaseFeatureModified,
1000                                              FeaturePtr& theAfterFeature,
1001                                              std::set<AttributePoint2DPtr>& thePoints,
1002                                              std::set<FeaturePtr>& theCreatedFeatures,
1003                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1004 {
1005   FeaturePtr anNewFeature;
1006
1007   std::set<FeaturePtr> aCreatedFeatures;
1008   FeaturePtr aConstraintFeature;
1009   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1010
1011   SketchPlugin_Sketch* aSketch = sketch();
1012   if (!aSketch)
1013     return anNewFeature;
1014
1015   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1016                                                            data()->attribute(SELECTED_OBJECT()));
1017   //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1018   //                                         data()->attribute(SketchPlugin_Constraint::VALUE()));
1019   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1020   std::string aFeatureKind = aBaseFeature->getKind();
1021   if (aFeatureKind != SketchPlugin_Line::ID())
1022     return anNewFeature;
1023
1024   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
1025     //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1026   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
1027     //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1028   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
1029
1030   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
1031   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
1032     setError("Error: Feature has no start and end points.");
1033     return anNewFeature;
1034   }
1035
1036   arrangePointsOnLine(aStartPointAttrOfBase, anEndPointAttrOfBase,
1037                       aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1038
1039 #ifdef DEBUG_SPLIT
1040   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
1041   std::cout << "Start point: " <<
1042     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
1043   std::cout << "1st point:   " <<
1044     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
1045   std::cout << "2nd point:   " <<
1046     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
1047   std::cout << "End point:   " <<
1048     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
1049 #endif
1050
1051   /// create a split feature
1052   theSplitFeature =
1053     createLineFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1054   theCreatedFeatures.insert(theSplitFeature);
1055
1056   // before split feature
1057   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1058     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
1059                                         theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
1060   }
1061   else {
1062     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
1063     /// move end arc point to start of split
1064   }
1065
1066   // after split feature
1067   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
1068     FeaturePtr aFeature;
1069     if (!theBaseFeatureModified.get()) {
1070       aFeature = aBaseFeature; ///< use base feature to store all constraints here
1071       fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), aSecondPointAttrOfSplit);
1072       aFeature->execute(); // to update result
1073     }
1074     else {
1075       aFeature = createLineFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
1076       theCreatedFeatures.insert(aFeature);
1077       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
1078                                              aFeature->attribute(SketchPlugin_Line::END_ID())));
1079       anNewFeature = aFeature;
1080     }
1081     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1082                      SketchPlugin_ConstraintCoincidence::ID(),
1083                      theSplitFeature->attribute(SketchPlugin_Line::END_ID()),
1084                      aFeature->attribute(SketchPlugin_Line::START_ID()));
1085     theCreatedFeatures.insert(aConstraintFeature);
1086
1087     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1088                                 (aFeature->attribute(SketchPlugin_Line::START_ID())));
1089     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1090                                 (aFeature->attribute(SketchPlugin_Line::END_ID())));
1091
1092     if (!theBaseFeatureModified.get())
1093       theBaseFeatureModified = aFeature;
1094     else
1095       theAfterFeature = aFeature;
1096   }
1097   else {
1098     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1099                                   (theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
1100     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
1101                                    theSplitFeature->attribute(SketchPlugin_Line::END_ID())));
1102   }
1103   // base split, that is defined before split feature should be changed at end
1104   // (after the after feature creation). Otherwise modified value will be used in after feature
1105   // before split feature
1106   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1107     /// move end arc point to start of split
1108     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
1109                                                     aFirstPointAttrOfSplit);
1110     theBaseFeatureModified->execute(); // to update result
1111     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1112                      SketchPlugin_ConstraintCoincidence::ID(),
1113                      theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID()),
1114                      theSplitFeature->attribute(SketchPlugin_Line::START_ID()));
1115     theCreatedFeatures.insert(aConstraintFeature);
1116
1117     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1118                              (theBaseFeatureModified->attribute(SketchPlugin_Line::START_ID())));
1119     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1120                                (theBaseFeatureModified->attribute(SketchPlugin_Line::END_ID())));
1121   }
1122   else
1123     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1124                                        (theSplitFeature->attribute(SketchPlugin_Line::START_ID())));
1125
1126 #ifdef CREATE_CONSTRAINTS
1127   // additional constraints between split and base features
1128   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1129           SketchPlugin_ConstraintParallel::ID(),
1130           getFeatureResult(aBaseFeature),
1131           getFeatureResult(theSplitFeature));
1132   theCreatedFeatures.insert(aConstraintFeature);
1133   if (theAfterFeature.get()) {
1134     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1135           SketchPlugin_ConstraintParallel::ID(),
1136           getFeatureResult(aBaseFeature),
1137           getFeatureResult(theAfterFeature));
1138     theCreatedFeatures.insert(aConstraintFeature);
1139   }
1140 #endif
1141   return anNewFeature;
1142 }
1143
1144 FeaturePtr SketchPlugin_Split::splitArc(FeaturePtr& theSplitFeature,
1145                                             FeaturePtr& theBaseFeatureModified,
1146                                             FeaturePtr& theAfterFeature,
1147                                             std::set<AttributePoint2DPtr>& thePoints,
1148                                             std::set<FeaturePtr>& theCreatedFeatures,
1149                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1150 {
1151   FeaturePtr anNewFeature;
1152
1153   std::set<FeaturePtr> aCreatedFeatures;
1154   FeaturePtr aConstraintFeature;
1155   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1156
1157   SketchPlugin_Sketch* aSketch = sketch();
1158   if (!aSketch)
1159     return anNewFeature;
1160
1161   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1162                                                            data()->attribute(SELECTED_OBJECT()));
1163   //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1164   //                                         data()->attribute(SketchPlugin_Constraint::VALUE()));
1165   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1166   std::string aFeatureKind = aBaseFeature->getKind();
1167   if (aFeatureKind != SketchPlugin_Arc::ID())
1168     return anNewFeature;
1169
1170   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
1171     //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1172   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
1173     //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1174   AttributePoint2DPtr aStartPointAttrOfBase, anEndPointAttrOfBase;
1175   getFeaturePoints(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase);
1176   if (!aStartPointAttrOfBase.get() && !anEndPointAttrOfBase.get()) {
1177     setError("Error: Feature has no start and end points.");
1178     return anNewFeature;
1179   }
1180
1181   arrangePointsOnArc(aBaseFeature, aStartPointAttrOfBase, anEndPointAttrOfBase,
1182                      aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1183 #ifdef DEBUG_SPLIT
1184   std::cout << "Arranged points (to build split between 1st and 2nd points:" << std::endl;
1185   std::cout << "Start point: " <<
1186     ModelGeomAlgo_Point2D::getPointAttributeInfo(aStartPointAttrOfBase) << std::endl;
1187   std::cout << "1st point:   " <<
1188     ModelGeomAlgo_Point2D::getPointAttributeInfo(aFirstPointAttrOfSplit) << std::endl;
1189   std::cout << "2nd point:   " <<
1190     ModelGeomAlgo_Point2D::getPointAttributeInfo(aSecondPointAttrOfSplit) << std::endl;
1191   std::cout << "End point:   " <<
1192     ModelGeomAlgo_Point2D::getPointAttributeInfo(anEndPointAttrOfBase) << std::endl;
1193 #endif
1194
1195   /// split feature
1196   theSplitFeature = createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1197   theCreatedFeatures.insert(theSplitFeature);
1198
1199   // before split feature
1200   if (aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1201     theModifiedAttributes.insert(std::make_pair(aStartPointAttrOfBase,
1202                                   theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1203   }
1204   else {
1205     theBaseFeatureModified = aBaseFeature; ///< use base feature to store all constraints here
1206     /// move end arc point to start of split
1207   }
1208
1209   // after split feature
1210   if (!aSecondPointAttrOfSplit->pnt()->isEqual(anEndPointAttrOfBase->pnt())) {
1211     FeaturePtr aFeature;
1212     if (!theBaseFeatureModified.get()) {
1213       aFeature = aBaseFeature; ///< use base feature to store all constraints here
1214       fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), aSecondPointAttrOfSplit);
1215       aFeature->execute(); // to update result
1216     }
1217     else {
1218       aFeature = createArcFeature(aBaseFeature, aSecondPointAttrOfSplit, anEndPointAttrOfBase);
1219       theCreatedFeatures.insert(aFeature);
1220       theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
1221                                                   aFeature->attribute(SketchPlugin_Arc::END_ID())));
1222       anNewFeature = aFeature;
1223     }
1224     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1225                      SketchPlugin_ConstraintCoincidence::ID(),
1226                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()),
1227                      aFeature->attribute(SketchPlugin_Arc::START_ID()));
1228     theCreatedFeatures.insert(aConstraintFeature);
1229
1230     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1231                                 (aFeature->attribute(SketchPlugin_Arc::START_ID())));
1232     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1233                                 (aFeature->attribute(SketchPlugin_Arc::END_ID())));
1234
1235     if (!theBaseFeatureModified.get())
1236       theBaseFeatureModified = aFeature;
1237     else
1238       theAfterFeature = aFeature;
1239   }
1240   else {
1241     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1242                                   (theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
1243     theModifiedAttributes.insert(std::make_pair(anEndPointAttrOfBase,
1244                                    theSplitFeature->attribute(SketchPlugin_Arc::END_ID())));
1245   }
1246   // base split, that is defined before split feature should be changed at end
1247   // (after the after feature creation). Otherwise modified value will be used in after feature
1248   // before split feature
1249   if (!aStartPointAttrOfBase->pnt()->isEqual(aFirstPointAttrOfSplit->pnt())) {
1250     /// move end arc point to start of split
1251     fillAttribute(theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1252                                                     aFirstPointAttrOfSplit);
1253     theBaseFeatureModified->execute(); // to update result
1254     aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1255                      SketchPlugin_ConstraintCoincidence::ID(),
1256                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1257                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1258     theCreatedFeatures.insert(aConstraintFeature);
1259
1260     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1261                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1262     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1263                                (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1264   }
1265   else
1266     thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1267                                        (theSplitFeature->attribute(SketchPlugin_Arc::START_ID())));
1268
1269   // additional constraints between split and base features
1270 #ifdef CREATE_CONSTRAINTS
1271   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1272           SketchPlugin_ConstraintEqual::ID(),
1273           getFeatureResult(aBaseFeature),
1274           getFeatureResult(theSplitFeature));
1275   theCreatedFeatures.insert(aConstraintFeature);
1276   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1277           SketchPlugin_ConstraintTangent::ID(),
1278           getFeatureResult(theSplitFeature),
1279           getFeatureResult(aBaseFeature));
1280   theCreatedFeatures.insert(aConstraintFeature);
1281   if (theAfterFeature.get()) {
1282     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1283                 SketchPlugin_ConstraintEqual::ID(),
1284                 getFeatureResult(aBaseFeature),
1285                 getFeatureResult(theAfterFeature));
1286     theCreatedFeatures.insert(aConstraintFeature);
1287     aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1288                 SketchPlugin_ConstraintTangent::ID(),
1289                 getFeatureResult(theSplitFeature),
1290                 getFeatureResult(theAfterFeature));
1291     theCreatedFeatures.insert(aConstraintFeature);
1292   }
1293 #endif
1294   return anNewFeature;
1295 }
1296
1297 FeaturePtr SketchPlugin_Split::splitCircle(FeaturePtr& theSplitFeature,
1298                                                FeaturePtr& theBaseFeatureModified,
1299                                                FeaturePtr& theAfterFeature,
1300                                                std::set<AttributePoint2DPtr>& thePoints,
1301                                                std::set<FeaturePtr>& theCreatedFeatures,
1302                  std::set<std::pair<AttributePtr, AttributePtr>>& theModifiedAttributes)
1303 {
1304   FeaturePtr anNewFeature;
1305
1306   std::set<FeaturePtr> aCreatedFeatures;
1307   FeaturePtr aConstraintFeature;
1308   theBaseFeatureModified = FeaturePtr(); // it will contain modified base feature
1309
1310   SketchPlugin_Sketch* aSketch = sketch();
1311   if (!aSketch)
1312     return anNewFeature;
1313
1314   AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1315                                                            data()->attribute(SELECTED_OBJECT()));
1316   //AttributeReferencePtr aBaseObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1317   //                                         data()->attribute(SketchPlugin_Constraint::VALUE()));
1318   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObjectAttr->value());
1319   std::string aFeatureKind = aBaseFeature->getKind();
1320   if (aFeatureKind != SketchPlugin_Circle::ID())
1321     return anNewFeature;
1322
1323   AttributePoint2DPtr aFirstPointAttrOfSplit = getPointAttribute(true);
1324     //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_A()));
1325   AttributePoint2DPtr aSecondPointAttrOfSplit = getPointAttribute(false);
1326     //getPointOfRefAttr(data()->attribute(SketchPlugin_Constraint::ENTITY_B()));
1327
1328   /// split feature
1329   theSplitFeature =
1330     createArcFeature(aBaseFeature, aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1331   bool aSplitReversed = std::dynamic_pointer_cast<SketchPlugin_Arc>(theSplitFeature)->isReversed();
1332   theCreatedFeatures.insert(theSplitFeature);
1333
1334   /// base feature is a left part of the circle
1335   theBaseFeatureModified = createArcFeature(aBaseFeature,
1336     aFirstPointAttrOfSplit, aSecondPointAttrOfSplit);
1337   anNewFeature = theBaseFeatureModified;
1338   std::dynamic_pointer_cast<SketchPlugin_Arc>(
1339     theBaseFeatureModified)->setReversed(!aSplitReversed);
1340   theBaseFeatureModified->execute();
1341
1342   theModifiedAttributes.insert(
1343     std::make_pair(aBaseFeature->attribute(SketchPlugin_Circle::CENTER_ID()),
1344                   theBaseFeatureModified->attribute(SketchPlugin_Arc::CENTER_ID())));
1345
1346   theCreatedFeatures.insert(theBaseFeatureModified);
1347
1348   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1349                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID())));
1350   thePoints.insert(std::dynamic_pointer_cast<GeomDataAPI_Point2D>
1351                              (theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID())));
1352
1353   // additional constraints between split and base features
1354   aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1355                      SketchPlugin_ConstraintCoincidence::ID(),
1356                      theBaseFeatureModified->attribute(SketchPlugin_Arc::END_ID()),
1357                      theSplitFeature->attribute(SketchPlugin_Arc::END_ID()));
1358   theCreatedFeatures.insert(aConstraintFeature);
1359   aConstraintFeature = SketchPlugin_Tools::createConstraintAttrAttr(sketch(),
1360                      SketchPlugin_ConstraintCoincidence::ID(),
1361                      theBaseFeatureModified->attribute(SketchPlugin_Arc::START_ID()),
1362                      theSplitFeature->attribute(SketchPlugin_Arc::START_ID()));
1363   theCreatedFeatures.insert(aConstraintFeature);
1364
1365 #ifdef CREATE_CONSTRAINTS
1366   aConstraintFeature = SketchPlugin_Tools::createConstraint(sketch(),
1367                      SketchPlugin_ConstraintTangent::ID(),
1368                      getFeatureResult(theSplitFeature),
1369                      getFeatureResult(theBaseFeatureModified));
1370   theCreatedFeatures.insert(aConstraintFeature);
1371 #endif
1372   return anNewFeature;
1373 }
1374
1375 void SketchPlugin_Split::arrangePointsOnLine(
1376     const AttributePoint2DPtr& theStartPointAttr,
1377     const AttributePoint2DPtr& theEndPointAttr,
1378     AttributePoint2DPtr& theFirstPointAttr,
1379     AttributePoint2DPtr& theLastPointAttr) const
1380 {
1381   // if first point is closer to last point, swap first and last values
1382   if (theStartPointAttr->pnt()->distance(theFirstPointAttr->pnt()) >
1383       theStartPointAttr->pnt()->distance(theLastPointAttr->pnt())) {
1384     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1385     theFirstPointAttr = theLastPointAttr;
1386     theLastPointAttr = aTmpPoint;
1387   }
1388 }
1389
1390 void SketchPlugin_Split::arrangePointsOnArc(
1391     const FeaturePtr& theArc,
1392     const std::shared_ptr<GeomDataAPI_Point2D>& theStartPointAttr,
1393     const std::shared_ptr<GeomDataAPI_Point2D>& theEndPointAttr,
1394     std::shared_ptr<GeomDataAPI_Point2D>& theFirstPointAttr,
1395     std::shared_ptr<GeomDataAPI_Point2D>& theSecondPointAttr) const
1396 {
1397   static const double anAngleTol = 1.e-12;
1398
1399   std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1400       theArc->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
1401   bool isReversed = theArc->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
1402
1403   // collect directions to each point
1404   std::shared_ptr<GeomAPI_Dir2d> aStartDir(
1405       new GeomAPI_Dir2d(theStartPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1406   std::shared_ptr<GeomAPI_Dir2d> aFirstPtDir(
1407       new GeomAPI_Dir2d(theFirstPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1408   std::shared_ptr<GeomAPI_Dir2d> aSecondPtDir(
1409       new GeomAPI_Dir2d(theSecondPointAttr->pnt()->xy()->decreased(aCenter->xy())));
1410
1411   // sort points by their angular values
1412   double aFirstPtAngle = aStartDir->angle(aFirstPtDir);
1413   double aSecondPtAngle = aStartDir->angle(aSecondPtDir);
1414   double aPeriod = isReversed ? -2.0 * PI : 2.0 * PI;
1415   if (fabs(aFirstPtAngle) > anAngleTol && isReversed == (aFirstPtAngle > 0.))
1416     aFirstPtAngle += aPeriod;
1417   if (fabs(aSecondPtAngle) > anAngleTol && isReversed == (aSecondPtAngle > 0.))
1418     aSecondPtAngle += aPeriod;
1419
1420   if (fabs(aFirstPtAngle) > fabs(aSecondPtAngle)) {
1421     AttributePoint2DPtr aTmpPoint = theFirstPointAttr;
1422     theFirstPointAttr = theSecondPointAttr;
1423     theSecondPointAttr = aTmpPoint;
1424   }
1425 }
1426
1427 void SketchPlugin_Split::fillAttribute(const AttributePtr& theModifiedAttribute,
1428                                                  const AttributePtr& theSourceAttribute)
1429 {
1430   std::string anAttributeType = theModifiedAttribute->attributeType();
1431   if (anAttributeType == GeomDataAPI_Point2D::typeId()) {
1432     AttributePoint2DPtr aModifiedAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1433                                               theModifiedAttribute);
1434     AttributePoint2DPtr aSourceAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
1435                                               theSourceAttribute);
1436
1437     if (aModifiedAttribute.get() && aSourceAttribute.get())
1438       aModifiedAttribute->setValue(aSourceAttribute->pnt());
1439   }
1440   else if (anAttributeType == ModelAPI_AttributeBoolean::typeId()) {
1441     AttributeBooleanPtr aModifiedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1442                                               theModifiedAttribute);
1443     AttributeBooleanPtr aSourceAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeBoolean>(
1444                                               theSourceAttribute);
1445
1446     if (aModifiedAttribute.get() && aSourceAttribute.get())
1447       aModifiedAttribute->setValue(aSourceAttribute->value());
1448   }
1449 }
1450
1451 FeaturePtr SketchPlugin_Split::createLineFeature(const FeaturePtr& theBaseFeature,
1452                                                            const AttributePtr& theFirstPointAttr,
1453                                                            const AttributePtr& theSecondPointAttr)
1454 {
1455   FeaturePtr aFeature;
1456   SketchPlugin_Sketch* aSketch = sketch();
1457   if (!aSketch || !theBaseFeature.get())
1458     return aFeature;
1459
1460   aFeature = aSketch->addFeature(SketchPlugin_Line::ID());
1461
1462   fillAttribute(aFeature->attribute(SketchPlugin_Line::START_ID()), theFirstPointAttr);
1463   fillAttribute(aFeature->attribute(SketchPlugin_Line::END_ID()), theSecondPointAttr);
1464
1465   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1466                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1467
1468   aFeature->execute(); // to obtain result
1469
1470   return aFeature;
1471 }
1472
1473 FeaturePtr SketchPlugin_Split::createArcFeature(const FeaturePtr& theBaseFeature,
1474                                                           const AttributePtr& theFirstPointAttr,
1475                                                           const AttributePtr& theSecondPointAttr)
1476 {
1477   FeaturePtr aFeature;
1478   SketchPlugin_Sketch* aSketch = sketch();
1479   if (!aSketch || !theBaseFeature.get())
1480     return aFeature;
1481
1482   std::string aCenterAttributeId;
1483   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID())
1484     aCenterAttributeId = SketchPlugin_Arc::CENTER_ID();
1485   else if (theBaseFeature->getKind() == SketchPlugin_Circle::ID())
1486     aCenterAttributeId = SketchPlugin_Circle::CENTER_ID();
1487
1488   if (aCenterAttributeId.empty())
1489     return aFeature;
1490
1491   aFeature = aSketch->addFeature(SketchPlugin_Arc::ID());
1492   // update fillet arc: make the arc correct for sure, so, it is not needed to process
1493   // the "attribute updated"
1494   // by arc; moreover, it may cause cyclicity in hte mechanism of updater
1495   bool aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true);
1496
1497   fillAttribute(aFeature->attribute(SketchPlugin_Arc::CENTER_ID()),
1498                 theBaseFeature->attribute(aCenterAttributeId));
1499   fillAttribute(aFeature->attribute(SketchPlugin_Arc::START_ID()), theFirstPointAttr);
1500   fillAttribute(aFeature->attribute(SketchPlugin_Arc::END_ID()), theSecondPointAttr);
1501
1502   fillAttribute(aFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()),
1503                 theBaseFeature->attribute(SketchPlugin_SketchEntity::AUXILIARY_ID()));
1504
1505   /// fill referersed state of created arc as it is on the base arc
1506   if (theBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
1507     bool aReversed = theBaseFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->value();
1508     aFeature->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(aReversed);
1509   }
1510   aFeature->data()->blockSendAttributeUpdated(aWasBlocked);
1511   aFeature->execute(); // to obtain result
1512
1513   return aFeature;
1514 }
1515
1516 void SketchPlugin_Split::updateFeaturesAfterSplit(
1517                                                    const std::set<FeaturePtr>& theFeaturesToUpdate)
1518 {
1519   std::set<FeaturePtr>::const_iterator anIt = theFeaturesToUpdate.begin(),
1520                                        aLast = theFeaturesToUpdate.end();
1521   for (; anIt != aLast; anIt++) {
1522     FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1523     std::string aRefFeatureKind = aRefFeature->getKind();
1524     if (aRefFeatureKind == SketchPlugin_ConstraintLength::ID()) {
1525       std::shared_ptr<SketchPlugin_ConstraintLength> aLenghtFeature =
1526                               std::dynamic_pointer_cast<SketchPlugin_ConstraintLength>(*anIt);
1527       if (aLenghtFeature.get()) {
1528         std::shared_ptr<ModelAPI_AttributeDouble> aValueAttr = std::dynamic_pointer_cast<
1529             ModelAPI_AttributeDouble>(aLenghtFeature->attribute(SketchPlugin_Constraint::VALUE()));
1530         double aValue;
1531         if (aLenghtFeature->computeLenghtValue(aValue) && aValueAttr.get())
1532           aValueAttr->setValue(aValue);
1533       }
1534     }
1535   }
1536 }
1537
1538 std::shared_ptr<ModelAPI_Result> SketchPlugin_Split::getFeatureResult(
1539                                     const std::shared_ptr<ModelAPI_Feature>& theFeature)
1540 {
1541   std::shared_ptr<ModelAPI_Result> aResult;
1542
1543   std::string aFeatureKind = theFeature->getKind();
1544   if (aFeatureKind == SketchPlugin_Line::ID())
1545     aResult = theFeature->firstResult();
1546   else if (aFeatureKind == SketchPlugin_Arc::ID())
1547     aResult = theFeature->lastResult();
1548   else if (aFeatureKind == SketchPlugin_Circle::ID())
1549     aResult = theFeature->lastResult();
1550
1551   return aResult;
1552 }
1553
1554 #ifdef _DEBUG
1555 std::set<std::shared_ptr<ModelAPI_Attribute> > SketchPlugin_Split::getEdgeAttributes(
1556                                            const std::shared_ptr<ModelAPI_Feature>& theFeature)
1557 {
1558   std::set<std::shared_ptr<ModelAPI_Attribute> > anAttributes;
1559
1560   std::string aFeatureKind = theFeature->getKind();
1561   if (aFeatureKind == SketchPlugin_Line::ID()) {
1562     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::START_ID()));
1563     anAttributes.insert(theFeature->attribute(SketchPlugin_Line::END_ID()));
1564   }
1565   else if (aFeatureKind == SketchPlugin_Arc::ID()) {
1566     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::START_ID()));
1567     anAttributes.insert(theFeature->attribute(SketchPlugin_Arc::END_ID()));
1568   }
1569   else if (aFeatureKind == SketchPlugin_Circle::ID()) {
1570   }
1571
1572   return anAttributes;
1573 }
1574 #endif
1575
1576 std::shared_ptr<GeomDataAPI_Point2D> SketchPlugin_Split::getPointAttribute
1577                                                               (const bool isFirstAttribute)
1578 {
1579   std::shared_ptr<GeomDataAPI_Point2D> anAttribute;
1580
1581   GeomShapePtr aSelectedShape = getSubShape(SELECTED_OBJECT(), SELECTED_POINT());
1582   if (!aSelectedShape.get())
1583     return anAttribute;
1584
1585   if (aSelectedShape->shapeType() != GeomAPI_Shape::EDGE)
1586     return anAttribute;
1587
1588   AttributeReferencePtr anObjectAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(
1589                                                        data()->attribute(SELECTED_OBJECT()));
1590   ObjectPtr aBaseObject = anObjectAttr->value();
1591   if (!aBaseObject.get())
1592     return anAttribute;
1593
1594   std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelectedShape));
1595
1596   std::shared_ptr<GeomAPI_Pnt> aFirstPnt = anEdge->firstPoint();
1597   std::shared_ptr<GeomAPI_Pnt> aLastPnt = anEdge->lastPoint();
1598
1599   std::shared_ptr<GeomDataAPI_Point2D> aFirstPointAttr, aLastPointAttr;
1600   /// find the points in feature attributes
1601   FeaturePtr aBaseFeature = ModelAPI_Feature::feature(aBaseObject);
1602   std::list<AttributePtr> a2DPointAttributes = aBaseFeature->data()->attributes(
1603                                                     GeomDataAPI_Point2D::typeId());
1604   std::list<AttributePtr>::const_iterator anIt = a2DPointAttributes.begin(),
1605                                           aLast = a2DPointAttributes.end();
1606   for (; anIt != aLast; anIt++) {
1607     std::shared_ptr<GeomDataAPI_Point2D> anAttributePoint =
1608                                   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
1609     std::shared_ptr<GeomAPI_Pnt2d> aPoint2D = anAttributePoint->pnt();
1610     std::shared_ptr<GeomAPI_Pnt> aPoint3D = sketch()->to3D(aPoint2D->x(), aPoint2D->y());
1611     if (aFirstPnt->isEqual(aPoint3D))
1612       aFirstPointAttr = anAttributePoint;
1613     else if (aLastPnt->isEqual(aPoint3D))
1614       aLastPointAttr = anAttributePoint;
1615   }
1616
1617   /// find the points in coincident features
1618   PntToAttributesMap aRefAttributes = myCashedReferences[aBaseObject];
1619   PntToAttributesMap::const_iterator
1620     aRIt = aRefAttributes.begin(), aRLast = aRefAttributes.end();
1621   for (; aRIt != aRLast; aRIt++) {
1622     std::shared_ptr<GeomDataAPI_Point2D> anAttribute = aRIt->first;
1623     std::shared_ptr<GeomAPI_Pnt> aPoint = aRIt->second;
1624     if (!aFirstPointAttr.get() && aFirstPnt->isEqual(aPoint))
1625       aFirstPointAttr = anAttribute;
1626     if (!aLastPointAttr.get() && aLastPnt->isEqual(aPoint))
1627       aLastPointAttr = anAttribute;
1628     if (aFirstPointAttr.get() && aLastPointAttr.get())
1629       break;
1630   }
1631   if (!aFirstPointAttr.get() || !aLastPointAttr)
1632     return anAttribute;
1633
1634   return isFirstAttribute ? aFirstPointAttr : aLastPointAttr;
1635 }
1636
1637 #ifdef _DEBUG
1638 std::string SketchPlugin_Split::getFeatureInfo(const std::shared_ptr<ModelAPI_Feature>& theFeature,
1639                                                const bool isUseAttributesInfo)
1640 {
1641   std::string anInfo;
1642   if (!theFeature.get()) {
1643     return "none";
1644   }
1645
1646   if (theFeature->data()->isValid())
1647     anInfo.append(theFeature->data()->name().c_str());
1648
1649   if (isUseAttributesInfo) {
1650     std::string aPointsInfo = ModelGeomAlgo_Point2D::getPontAttributesInfo(theFeature,
1651                                                              getEdgeAttributes(theFeature));
1652     /// processing of feature with point 2d attributes, like line, arc, circle
1653     if (!aPointsInfo.empty()) {
1654       anInfo += ": ";
1655       anInfo += "\n";
1656       anInfo += aPointsInfo;
1657     }
1658     else { /// process constraint coincidence, find points in ref attr attributes
1659       std::list<AttributePtr> anAttrs = theFeature->data()->attributes(
1660                                                        ModelAPI_AttributeRefAttr::typeId());
1661       std::list<AttributePtr>::const_iterator anIt = anAttrs.begin(), aLast = anAttrs.end();
1662       std::string anAttributesInfo;
1663       for(; anIt != aLast; anIt++) {
1664         if (!anAttributesInfo.empty()) {
1665           anAttributesInfo.append(", ");
1666           anAttributesInfo += "\n";
1667         }
1668         AttributePtr anAttr = *anIt;
1669         std::string aValue = "not defined";
1670         std::string aType = anAttr->attributeType();
1671         if (aType == ModelAPI_AttributeRefAttr::typeId()) {
1672           std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttr =
1673                              std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
1674           if (aRefAttr.get()) {
1675             if (aRefAttr->isObject()) {
1676               FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
1677               aValue = "<object:>" + getFeatureInfo(aFeature, false);
1678             }
1679             else {
1680               AttributePtr anAttribute = aRefAttr->attr();
1681               if (anAttribute.get()) {
1682                 FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
1683                 aValue = "<attr:>" + ModelGeomAlgo_Point2D::getPointAttributeInfo(anAttribute) +
1684                          " [" + getFeatureInfo(aFeature, false) + "]";
1685               }
1686             }
1687           }
1688         }
1689         anAttributesInfo.append("    " + anAttr->id() + ": " + aValue);
1690       }
1691       if (!anAttributesInfo.empty())
1692         anInfo = anInfo + "\n" + anAttributesInfo;
1693     }
1694   }
1695   return anInfo;
1696 }
1697 #endif