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