Salome HOME
4740ca2b8c9dc95e70f64e579459240e322b5c02
[modules/shaper.git] / src / PartSet / PartSet_WidgetPoint2d.cpp
1 // Copyright (C) 2014-2021  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 "PartSet_WidgetPoint2d.h"
21 #include <PartSet_Tools.h>
22 #include <PartSet_Module.h>
23 #include <PartSet_SketcherReentrantMgr.h>
24 #include <PartSet_ExternalObjectsMgr.h>
25 #include <PartSet_CenterPrs.h>
26
27 #include <XGUI_Tools.h>
28 #include <XGUI_Workshop.h>
29 #include <XGUI_Displayer.h>
30
31 #include <ModuleBase_ParamSpinBox.h>
32 #include <ModuleBase_Tools.h>
33 #include <ModuleBase_IViewer.h>
34 #include <ModuleBase_IViewWindow.h>
35 #include <ModuleBase_ISelection.h>
36 #include <ModuleBase_ViewerPrs.h>
37 #include <ModuleBase_WidgetValidator.h>
38 #include <ModuleBase_WidgetValidated.h>
39 #include <ModuleBase_LabelValue.h>
40
41 #include <Config_Keywords.h>
42 #include <Config_WidgetAPI.h>
43
44 #include <Events_Loop.h>
45 #include <Events_InfoMessage.h>
46 #include <ModelAPI_Events.h>
47 #include <ModelAPI_AttributeBoolean.h>
48 #include <ModelAPI_AttributeRefAttr.h>
49 #include <ModelAPI_AttributeRefList.h>
50 #include <ModelAPI_Validator.h>
51 #include <ModelAPI_Session.h>
52
53 #include <ModelAPI_Feature.h>
54 #include <ModelAPI_Data.h>
55 #include <ModelAPI_Object.h>
56 #include <GeomDataAPI_Point2D.h>
57 #include <GeomAPI_Pnt2d.h>
58
59 #include <GeomAPI_ShapeExplorer.h>
60 #include <GeomAPI_Vertex.h>
61
62 #include <SketchPlugin_Feature.h>
63 #include <SketchPlugin_ConstraintCoincidence.h>
64 #include <SketchPlugin_Line.h>
65 #include <SketchPlugin_Arc.h>
66 #include <SketchPlugin_Circle.h>
67 #include <SketchPlugin_Point.h>
68
69 #include <QGroupBox>
70 #include <QGridLayout>
71 #include <QLabel>
72 #include <QEvent>
73 #include <QMouseEvent>
74 #include <QApplication>
75
76 #include <TopoDS.hxx>
77 #include <TopoDS_Vertex.hxx>
78 #include <BRep_Tool.hxx>
79 #include <Geom_Point.hxx>
80
81 #include <cfloat>
82 #include <climits>
83
84 const double MaxCoordinate = 1e12;
85
86 static QStringList MyFeaturesForCoincedence;
87
88 PartSet_WidgetPoint2D::PartSet_WidgetPoint2D(QWidget* theParent,
89                                              ModuleBase_IWorkshop* theWorkshop,
90                                              const Config_WidgetAPI* theData)
91 : ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop),
92   myValueIsCashed(false), myIsFeatureVisibleInCash(true),
93   myXValueInCash(0), myYValueInCash(0)
94 {
95   myRefAttribute = theData->getProperty("reference_attribute");
96   if (MyFeaturesForCoincedence.isEmpty()) {
97     MyFeaturesForCoincedence << SketchPlugin_Line::ID().c_str()
98       << SketchPlugin_Arc::ID().c_str()
99       << SketchPlugin_Point::ID().c_str()
100       << SketchPlugin_Circle::ID().c_str();
101   }
102
103   // the control should accept the focus, so the boolean flag is corrected to be true
104   myIsObligatory = true;
105   QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
106   myGroupBox = new QGroupBox(aPageName, theParent);
107   myGroupBox->setFlat(false);
108
109 #ifdef _DEBUG
110   bool aAcceptVariables =
111 #endif
112     theData->getBooleanAttribute(DOUBLE_WDG_ACCEPT_EXPRESSIONS, true);
113
114   QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
115   ModuleBase_Tools::adjustMargins(aGroupLay);
116   aGroupLay->setSpacing(2);
117   aGroupLay->setColumnStretch(1, 1);
118
119   myXSpin = new ModuleBase_LabelValue(myGroupBox, tr("X"));
120   aGroupLay->addWidget(myXSpin, 0, 1);
121   myYSpin = new ModuleBase_LabelValue(myGroupBox, tr("Y"));
122   aGroupLay->addWidget(myYSpin, 1, 1);
123
124   QVBoxLayout* aLayout = new QVBoxLayout(this);
125   ModuleBase_Tools::zeroMargins(aLayout);
126   aLayout->addWidget(myGroupBox);
127   setLayout(aLayout);
128
129   myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
130   myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
131                                          theData->getProperty("can_create_external"), true);
132 }
133
134 bool PartSet_WidgetPoint2D::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
135 {
136   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
137   if (aModule->sketchReentranceMgr()->isInternalEditActive())
138     return true; /// when internal edit is started a new feature is created. I has not results, AIS
139
140   /// the selection is not possible if the current feature has no presentation for the current
141   /// attribute not in AIS not in results. If so, no object in current feature where make
142   /// coincidence, so selection is not necessary
143   GeomShapePtr anAISShape;
144   GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(myFeature);
145   if (aPrs.get()) {
146     AISObjectPtr anAIS;
147     anAIS = aPrs->getAISObject(anAIS);
148     if (anAIS.get()) {
149       anAISShape = anAIS->getShape();
150     }
151   }
152   const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = myFeature->results();
153   if (!anAISShape.get() && aResults.empty())
154     return true;
155
156   AttributeRefAttrPtr aRefAttr = attributeRefAttr();
157   if (aRefAttr.get())
158     return isValidSelectionForAttribute_(theValue, myFeature->attribute(attributeID()));
159   else {
160     bool aFoundPoint = false;
161     /// Avoid coincidence build to passed point. Coincidence is build later only if there are no
162     /// reference attribute.
163     /// The condition is that the selected feature has shape that has after explore a point
164     /// equal to clicked one.
165     std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
166     AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
167         aData->attribute(attributeID()));
168     std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
169     if (anAISShape.get())
170       aFoundPoint = shapeExploreHasVertex(anAISShape, aPoint, mySketch);
171
172     /// analysis of results
173     std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.cbegin();
174     for (; aRIter != aResults.cend() && !aFoundPoint; aRIter++) {
175       ResultPtr aResult = *aRIter;
176       if (aResult.get() && aResult->shape().get()) {
177         GeomShapePtr aShape = aResult->shape();
178         aFoundPoint = shapeExploreHasVertex(aShape, aPoint, mySketch);
179       }
180     }
181     return aFoundPoint;
182   }
183   return true;
184 }
185
186 //********************************************************************
187 bool PartSet_WidgetPoint2D::isValidSelectionForAttribute_(
188                                             const ModuleBase_ViewerPrsPtr& theValue,
189                                             const AttributePtr& theAttribute)
190 {
191   bool aValid = false;
192
193   // stores the current values of the widget attribute
194   bool isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked;
195
196   AttributeRefAttrPtr aRefAttr = attributeRefAttr();
197   ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttr, myFeature, true,
198       isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
199   myWidgetValidator->storeAttributeValue(aRefAttr);
200
201   // saves the owner value to the widget attribute
202   aValid = setSelectionCustom(theValue);
203   if (aValid)
204     // checks the attribute validity
205     aValid = myWidgetValidator->isValidAttribute(theAttribute);
206
207   // restores the current values of the widget attribute
208   myWidgetValidator->restoreAttributeValue(aRefAttr, aValid);
209   myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
210
211   ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttr, myFeature, false, isFlushesActived,
212                                 isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
213   return aValid;
214 }
215
216 bool PartSet_WidgetPoint2D::setSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
217 {
218   bool isDone = false;
219   GeomShapePtr aShape = theValue->shape();
220   if (aShape.get() && !aShape->isNull()) {
221     Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
222     const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
223     GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
224     if (aPnt) {
225       fillRefAttribute(aPnt->x(), aPnt->y(), theValue);
226       isDone = true;
227     }
228     else if (aTDShape.ShapeType() == TopAbs_EDGE) {
229       fillRefAttribute(theValue);
230       isDone = true;
231     }
232   }
233   return isDone;
234 }
235
236 bool PartSet_WidgetPoint2D::resetCustom()
237 {
238   bool aDone = false;
239   if (!isUseReset() || isComputedDefault()
240       /*|| myXSpin->hasVariable() || myYSpin->hasVariable()*/) {
241     aDone = false;
242   }
243   else {
244     if (myValueIsCashed) {
245       // if the restored value should be hidden, aDone = true to set
246       // reset state for the widget in the parent
247       aDone = restoreCurentValue();
248       emit objectUpdated();
249     }
250     else {
251       bool isOk;
252       double aDefValue = QString::fromStdString(getDefaultValue()).toDouble(&isOk);
253       // it is important to block the spin box control in order to do not through out the
254       // locking of the validating state.
255       myXSpin->setValue(isOk ? aDefValue : 0.0);
256       myYSpin->setValue(isOk ? aDefValue : 0.0);
257
258       //ModuleBase_Tools::setSpinValue(myXSpin, isOk ? aDefValue : 0.0);
259       //ModuleBase_Tools::setSpinValue(myYSpin, isOk ? aDefValue : 0.0);
260       storeValueCustom();
261       aDone = true;
262     }
263   }
264   return aDone;
265 }
266
267 PartSet_WidgetPoint2D::~PartSet_WidgetPoint2D()
268 {
269   delete myExternalObjectMgr;
270 }
271
272 bool PartSet_WidgetPoint2D::setSelection(QList<ModuleBase_ViewerPrsPtr>& theValues,
273                                          const bool theToValidate)
274 {
275   bool isDone = false;
276   if (theValues.empty())
277     return isDone;
278
279   ModuleBase_ViewerPrsPtr aValue = theValues.takeFirst();
280
281   if (!theToValidate || myWidgetValidator->isValidSelection(aValue)) {
282     GeomShapePtr aShape = aValue->shape();
283     if (aShape.get() && !aShape->isNull()) {
284       Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
285       const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
286       GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
287
288       if (aPnt) {
289         //isDone = setPoint(aPnt->x(), aPnt->y());
290         //setConstraintToPoint(aPnt->x(), aPnt->y(), aValue);
291         processSelection(aValue, aPnt->x(), aPnt->y());
292         isDone = true;
293       }
294     }
295   }
296   return isDone;
297 }
298
299 //void PartSet_WidgetPoint2D::selectContent()
300 //{
301 // // myXSpin->selectAll();
302 //}
303
304 bool PartSet_WidgetPoint2D::setPoint(double theX, double theY)
305 {
306   if (fabs(theX) >= MaxCoordinate)
307     return false;
308   if (fabs(theY) >= MaxCoordinate)
309     return false;
310
311   myXSpin->setValue(theX);
312   myYSpin->setValue(theY);
313
314   //ModuleBase_Tools::setSpinValue(myXSpin, theX);
315   //ModuleBase_Tools::setSpinValue(myYSpin, theY);
316
317   storeValue();
318   return true;
319 }
320
321 bool PartSet_WidgetPoint2D::storeValueCustom()
322 {
323   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
324   if (!aData || !aData->isValid()) // can be on abort of sketcher element
325     return false;
326   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
327       aData->attribute(attributeID()));
328
329   PartSet_WidgetPoint2D* that = (PartSet_WidgetPoint2D*) this;
330   bool isBlocked = that->blockSignals(true);
331   bool isImmutable = aPoint->setImmutable(true);
332
333   // if text is not empty then setValue will be ignored
334   // so we should set the text at first
335   //aPoint->setText(myXSpin->hasVariable() ? myXSpin->text().toStdString() : "",
336   //                myYSpin->hasVariable() ? myYSpin->text().toStdString() : "");
337   //aPoint->setValue(!myXSpin->hasVariable() ? myXSpin->value() : aPoint->x(),
338   //                 !myYSpin->hasVariable() ? myYSpin->value() : aPoint->y());
339
340   if (myFeature->isMacro()) {
341     // Moving points of macro-features has been processed directly (without solver)
342     aPoint->setValue(myXSpin->value(), myYSpin->value());
343     updateObject(myFeature);
344
345   } else {
346     if (!aPoint->isInitialized())
347       aPoint->setValue(0., 0.);
348
349     std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
350         new ModelAPI_ObjectMovedMessage(this));
351     aMessage->setMovedAttribute(aPoint);
352     aMessage->setOriginalPosition(aPoint->pnt());
353     aMessage->setCurrentPosition(myXSpin->value(), myYSpin->value());
354     Events_Loop::loop()->send(aMessage);
355   }
356
357   aPoint->setImmutable(isImmutable);
358   that->blockSignals(isBlocked);
359
360   return true;
361 }
362
363 bool PartSet_WidgetPoint2D::restoreValueCustom()
364 {
365   std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
366   AttributePoint2DPtr aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
367       aData->attribute(attributeID()));
368   double aValueX = aPoint->isInitialized() ? aPoint->x() : 0.;
369   double aValueY = aPoint->isInitialized() ? aPoint->y() : 0.;
370   myXSpin->setValue(aValueX);
371   myYSpin->setValue(aValueY);
372
373   return true;
374 }
375
376 void PartSet_WidgetPoint2D::storeCurentValue()
377 {
378   // do not use cash if a variable is used
379   //if (myXSpin->hasVariable() || myYSpin->hasVariable())
380   //  return;
381
382   myValueIsCashed = true;
383   myIsFeatureVisibleInCash = XGUI_Displayer::isVisible(
384                        XGUI_Tools::workshop(myWorkshop)->displayer(), myFeature);
385   myXValueInCash = myXSpin->value();
386   myYValueInCash = myYSpin->value();
387 }
388
389 bool PartSet_WidgetPoint2D::restoreCurentValue()
390 {
391   bool aRestoredAndHidden = true;
392
393   bool isVisible = myIsFeatureVisibleInCash;
394   // fill the control widgets by the cashed value
395
396   myValueIsCashed = false;
397   myIsFeatureVisibleInCash = true;
398   myXSpin->setValue(myXValueInCash);
399   myYSpin->setValue(myYValueInCash);
400   //ModuleBase_Tools::setSpinValue(myXSpin, myXValueInCash);
401   //ModuleBase_Tools::setSpinValue(myYSpin, myYValueInCash);
402
403   // store value to the model
404   storeValueCustom();
405   if (isVisible) {
406     setValueState(Stored);
407     aRestoredAndHidden = false;
408   }
409   else
410     aRestoredAndHidden = true;
411
412   return aRestoredAndHidden;
413 }
414
415 QList<QWidget*> PartSet_WidgetPoint2D::getControls() const
416 {
417   QList<QWidget*> aControls;
418   aControls.append(myXSpin);
419   aControls.append(myYSpin);
420   return aControls;
421 }
422
423 //********************************************************************
424 void PartSet_WidgetPoint2D::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
425 {
426   theModuleSelectionModes = -1;
427   theModes << TopAbs_VERTEX;
428   theModes << TopAbs_EDGE;
429 }
430
431 //********************************************************************
432 void PartSet_WidgetPoint2D::activateCustom()
433 {
434   if (!isEditingMode()) {
435     FeaturePtr aFeature = feature();
436     if (aFeature.get() && aFeature->getKind() == SketchPlugin_Point::ID())
437       storeValue();
438   }
439 }
440
441 void PartSet_WidgetPoint2D::setHighlighted(bool isHighlighted)
442 {
443 }
444
445 void PartSet_WidgetPoint2D::deactivate()
446 {
447   // the value of the control should be stored to model if it was not
448   // initialized yet. It is important when we leave this control by Tab key.
449   // It should not be performed by the widget activation as the preview
450   // is visualized with default value. Line point is moved to origin.
451   AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
452   if (anAttribute && !anAttribute->isInitialized())
453     storeValue();
454
455   ModuleBase_ModelWidget::deactivate();
456 }
457
458 bool PartSet_WidgetPoint2D::setConstraintToPoint(double theClickedX, double theClickedY,
459                                   const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
460 {
461   AttributeRefAttrPtr aRefAttr = attributeRefAttr();
462   if (aRefAttr.get())
463     fillRefAttribute(theClickedX, theClickedY, theValue);
464   else {
465     FeaturePtr aFeature = feature();
466     std::string anAttribute = attributeID();
467
468     if (!aFeature.get())
469       return false;
470
471     std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = std::shared_ptr<GeomAPI_Pnt2d>(
472                                      new GeomAPI_Pnt2d(theClickedX, theClickedY));
473     AttributePoint2DPtr aClickedFeaturePoint = findFirstEqualPointInSketch(mySketch,
474                                                            aFeature, aClickedPoint);
475     if (!aClickedFeaturePoint.get())
476       return false;
477
478   //  aRefAttr->setAttr(aClickedFeaturePoint);
479   //else {
480     // find a feature point by the selection mode
481     AttributePoint2DPtr aFeaturePoint;
482     if (aFeature->isMacro()) {
483       // the macro feature will be removed after the operation is stopped, so we need to build
484       // coincidence to possible sub-features
485       aFeaturePoint = findFirstEqualPointInArgumentFeatures(aFeature, aClickedPoint);
486     }
487     else {
488       aFeaturePoint = std::dynamic_pointer_cast<
489                                      GeomDataAPI_Point2D>(aFeature->data()->attribute(anAttribute));
490     }
491     if (!aFeaturePoint.get())
492       return false;
493
494     PartSet_Tools::createConstraint(mySketch, aClickedFeaturePoint, aFeaturePoint);
495   }
496   return true;
497 }
498
499 bool PartSet_WidgetPoint2D::setConstraintToObject(const ObjectPtr& theObject)
500 {
501   AttributeRefAttrPtr aRefAttr = attributeRefAttr();
502   if (aRefAttr.get()) {
503     fillRefAttribute(theObject);
504   }
505   else {
506     AttributePoint2DPtr aFeaturePoint;
507
508     if (feature()->isMacro()) {
509       AttributePtr aThisAttr = feature()->data()->attribute(attributeID());
510       AttributePoint2DPtr anAttrPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aThisAttr);
511       if (anAttrPoint.get()) {
512         // the macro feature will be removed after the operation is stopped, so we need to build
513         // coincidence to possible sub-features
514         aFeaturePoint = findFirstEqualPointInArgumentFeatures(feature(),
515                                                                    anAttrPoint->pnt());
516       }
517     }
518     else {
519       AttributePtr aThisAttr = feature()->data()->attribute(attributeID());
520       aFeaturePoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aThisAttr);
521     }
522     if (!aFeaturePoint.get())
523       return false;
524
525     // Create point-edge coincedence
526     FeaturePtr aFeature = mySketch->addFeature(SketchPlugin_ConstraintCoincidence::ID());
527     std::shared_ptr<ModelAPI_Data> aData = aFeature->data();
528
529     std::shared_ptr<ModelAPI_AttributeRefAttr> aRef1 = std::dynamic_pointer_cast<
530         ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
531
532     aRef1->setAttr(aFeaturePoint);
533
534     std::shared_ptr<ModelAPI_AttributeRefAttr> aRef2 = std::dynamic_pointer_cast<
535         ModelAPI_AttributeRefAttr>(aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
536     aRef2->setObject(theObject);
537
538     // we need to flush created signal in order to coincidence is processed by solver
539     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
540   }
541   return true;
542 }
543
544 void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent)
545 {
546   // the contex menu release by the right button should not be processed by this widget
547   if (theEvent->button() != Qt::LeftButton)
548     return;
549
550   ModuleBase_ISelection* aSelection = myWorkshop->selection();
551   Handle(V3d_View) aView = theWindow->v3dView();
552
553   QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
554   ModuleBase_ViewerPrsPtr aFirstValue =
555     aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
556   if (!aFirstValue.get() && myPreSelected.get()) {
557     aFirstValue = myPreSelected;
558   }
559
560   double aX=0, aY=0;
561   bool aHasPoint = false;
562   if (aFirstValue.get()) {
563     GeomShapePtr aShape = aFirstValue->shape();
564     if (aShape.get() && aShape->shapeType() == GeomAPI_Shape::VERTEX) {
565       const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
566       GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
567       aX = aPnt->x();
568       aY = aPnt->y();
569       aHasPoint = true;
570     }
571   }
572   if (!aHasPoint) {
573     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
574     PartSet_Tools::convertTo2D(aPoint, mySketch, aView, aX, aY);
575   }
576   processSelection(aFirstValue, aX, aY);
577 }
578
579 void PartSet_WidgetPoint2D::processSelection(const ModuleBase_ViewerPrsPtr& theValue,
580   double theX, double theY)
581 {
582   if (!setPoint(theX, theY))
583     return;
584   // if we have selection and use it
585   if (theValue.get() && isValidSelectionCustom(theValue) && theValue->shape().get()) {
586     /// Trihedron Axis may be selected, but shape is empty
587     GeomShapePtr aGeomShape = theValue->shape();
588     TopoDS_Shape aShape = aGeomShape->impl<TopoDS_Shape>();
589     ObjectPtr aObject = theValue->object();
590
591     FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aObject);
592     bool anExternal = false;
593     std::shared_ptr<SketchPlugin_Feature> aSPFeature;
594     if (aSelectedFeature.get() != NULL)
595       aSPFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
596
597     ResultPtr aFixedObject;
598     bool aSketchExternalFeature = aSPFeature.get() && aSPFeature->isExternal();
599     if ((!aSPFeature && !aShape.IsNull()) || aSketchExternalFeature) {
600       aFixedObject = PartSet_Tools::findFixedObjectByExternal(aShape, aObject, mySketch);
601       if (aSketchExternalFeature && !aFixedObject.get()) {/// local selection on external feature
602         anExternal = false;
603       }
604       else {
605         anExternal = true;
606         if (!aFixedObject.get())
607         {
608           FeaturePtr aCreatedFeature;
609           aFixedObject = PartSet_Tools::createFixedObjectByExternal(aGeomShape, aObject, mySketch,
610             false, aCreatedFeature);
611         }
612       }
613     }
614     if (anExternal) {
615       if (!isFeatureContainsPoint(myFeature, theX, theY)) {
616         if (aShape.ShapeType() == TopAbs_EDGE) {
617           setValueState(Stored); // in case of edge selection, Apply state should also be updated
618         }
619         bool anOrphanPoint = aShape.ShapeType() == TopAbs_VERTEX ||
620                               isOrphanPoint(aSelectedFeature, mySketch, theX, theY);
621         if (anExternal) {
622           // we should not stop reentrant operation on external objects because
623           anOrphanPoint = true;
624           // they are not participate in the contour creation excepting external vertices
625           if (aShape.ShapeType() == TopAbs_VERTEX) {
626             FeaturePtr aFixedFeature = ModelAPI_Feature::feature(aFixedObject);
627             if (aFixedFeature.get() && aFixedFeature->getKind() == SketchPlugin_Point::ID()) {
628               anOrphanPoint = isOrphanPoint(aFixedFeature, mySketch, theX, theY);
629             }
630           }
631         }
632         if (aFixedObject.get())
633           setConstraintToObject(aFixedObject);
634         // fignal updated should be flushed in order to visualize possible created
635         // external objects e.g. selection of trihedron axis when input end arc point
636         updateObject(feature());
637
638         if (!anOrphanPoint)
639           emit vertexSelected(); // it stops the reentrant operation
640
641         myPreSelected.reset();
642         emit focusOutWidget(this);
643       }
644     }
645     else {
646       if (!isFeatureContainsPoint(myFeature, theX, theY)) {
647         double aX = 0, aY = 0;
648         bool anOrphanPoint = isOrphanPoint(aSelectedFeature, mySketch, aX, aY);
649         // do not set a coincidence constraint in the attribute if the feature contains a point
650         // with the same coordinates. It is important for line creation in order to do not set
651         // the same constraints for the same points, oterwise the result line has zero length.
652         bool isAuxiliaryFeature = false;
653         if (aShape.ShapeType() == TopAbs_VERTEX) {
654           setConstraintToPoint(theX, theY, theValue);
655         }
656         else if (aShape.ShapeType() == TopAbs_EDGE) {
657           // point is taken from mouse event and set in attribute. It should be done before setting
658           // coinident constraint to the external line. If a point is created, it should be in
659           // the mouse clicked point
660           setConstraintToObject(aObject);
661           setValueState(Stored); // in case of edge selection, Apply state should also be updated
662           isAuxiliaryFeature = PartSet_Tools::isAuxiliarySketchEntity(aObject);
663         }
664         // it is important to perform updateObject() in order to the current value is
665         // processed by Sketch Solver. Test case: line is created from a previous point
666         // to some distance, but in the area of the highlighting of the point. Constraint
667         // coincidence is created, after the solver is performed, the distance between the
668         // points of the line becomes less than the tolerance. Validator of the line returns
669         // false, the line will be aborted, but sketch stays valid.
670         updateObject(feature());
671         if (!anOrphanPoint && !anExternal && !isAuxiliaryFeature)
672           emit vertexSelected();
673         myPreSelected.reset();
674         emit focusOutWidget(this);
675       }
676     }
677   }
678   // The selection could be a center of an external circular object
679   else if (theValue.get() && (!theValue->interactive().IsNull())) {
680     Handle(PartSet_CenterPrs) aAIS =
681         Handle(PartSet_CenterPrs)::DownCast(theValue->interactive());
682     if (!aAIS.IsNull()) {
683       gp_Pnt aPntComp = aAIS->Component()->Pnt();
684       GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
685       TopoDS_Shape aShape = aVertPtr->impl<TopoDS_Shape>();
686
687       ResultPtr aFixedObject =
688           PartSet_Tools::findFixedObjectByExternal(aShape, aAIS->object(), mySketch);
689       if (!aFixedObject.get())
690       {
691         FeaturePtr aCreatedFeature;
692         aFixedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
693           aAIS->centerType(), mySketch, false, aCreatedFeature);
694       }
695       if (aFixedObject.get())
696         setConstraintToObject(aFixedObject);
697       // fignal updated should be flushed in order to visualize possible created
698       // external objects e.g. selection of trihedron axis when input end arc point
699       updateObject(feature());
700
701       emit vertexSelected(); // it stops the reentrant operation
702       myPreSelected.reset();
703       emit focusOutWidget(this);
704     }
705   }
706   else {
707     // A case when point is taken from mouse event
708
709     // if the feature contains the point, focus is not switched
710     if (isFeatureContainsPoint(myFeature, theX, theY))
711       return;
712
713     myPreSelected.reset();
714     emit focusOutWidget(this);
715   }
716 }
717
718 void PartSet_WidgetPoint2D::setPreSelection(
719                                const std::shared_ptr<ModuleBase_ViewerPrs>& thePreSelected,
720                                ModuleBase_IViewWindow* theWnd,
721                                QMouseEvent* theEvent)
722 {
723   myPreSelected = thePreSelected;
724   mouseReleased(theWnd, theEvent);
725 }
726
727 void PartSet_WidgetPoint2D::getGeomSelection_(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue,
728                                               ObjectPtr& theObject,
729                                               GeomShapePtr& theShape)
730 {
731   myExternalObjectMgr->getGeomSelection(theValue, theObject, theShape, myWorkshop, sketch(), true);
732 }
733
734 void PartSet_WidgetPoint2D::mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent)
735 {
736   PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
737
738   if (isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditActive())
739     return;
740
741   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
742
743   double aX = 0, aY = 0;
744   PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, aY);
745   if (myState != ModifiedInViewer)
746     storeCurentValue();
747   // we need to block the value state change
748   bool isBlocked = blockValueState(true);
749   setPoint(aX, aY);
750   blockValueState(isBlocked);
751   setValueState(ModifiedInViewer);
752 }
753
754 double PartSet_WidgetPoint2D::x() const
755 {
756   return myXSpin->value();
757 }
758
759 double PartSet_WidgetPoint2D::y() const
760 {
761   return myYSpin->value();
762 }
763
764
765 bool PartSet_WidgetPoint2D::isFeatureContainsPoint(const FeaturePtr& theFeature,
766                                                    double theX, double theY)
767 {
768   bool aPointIsFound = false;
769
770   if (feature()->getKind() != SketchPlugin_Line::ID())
771     return aPointIsFound;
772
773   AttributePtr aWidgetAttribute = myFeature->attribute(attributeID());
774
775   std::shared_ptr<GeomAPI_Pnt2d> aPnt2d =
776                                     std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(theX, theY));
777   std::list<AttributePtr> anAttributes =
778                                 myFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
779   std::list<AttributePtr>::iterator anIter = anAttributes.begin();
780   for(; anIter != anAttributes.end() && !aPointIsFound; anIter++) {
781     AttributePoint2DPtr aPoint2DAttribute =
782       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIter);
783     if (aPoint2DAttribute == aWidgetAttribute)
784       continue;
785     if (aPoint2DAttribute.get() && aPoint2DAttribute->isInitialized()) {
786       aPointIsFound = aPoint2DAttribute->pnt()->isEqual(aPnt2d);
787     }
788   }
789   return aPointIsFound;
790 }
791
792 void PartSet_WidgetPoint2D::initializeValueByActivate()
793 {
794 }
795
796 /*void PartSet_WidgetPoint2D::onValuesChanged()
797 {
798   emit valuesChanged();
799 }*/
800
801 bool PartSet_WidgetPoint2D::processEnter()
802 {
803   return false;
804   /*bool isModified = getValueState() == ModifiedInPP;
805   if (isModified) {
806     bool isXModified = myXSpin->hasFocus();
807     emit valuesChanged();
808     if (isXModified)
809       myXSpin->selectAll();
810     else
811       myYSpin->selectAll();
812   }
813   return isModified;*/
814 }
815
816 bool PartSet_WidgetPoint2D::useSelectedShapes() const
817 {
818   return true;
819 }
820
821 bool PartSet_WidgetPoint2D::isOrphanPoint(const FeaturePtr& theFeature,
822                                           const CompositeFeaturePtr& theSketch,
823                                           double theX, double theY)
824 {
825   bool anOrphanPoint = false;
826   if (theFeature.get()) {
827     AttributePoint2DPtr aPointAttr;
828     std::string aFeatureKind = theFeature->getKind();
829     if (aFeatureKind == SketchPlugin_Point::ID())
830       aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
831                                        theFeature->attribute(SketchPlugin_Point::COORD_ID()));
832     else if (aFeatureKind == SketchPlugin_Circle::ID())
833       aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
834                                        theFeature->attribute(SketchPlugin_Circle::CENTER_ID()));
835
836     else if (aFeatureKind == SketchPlugin_Arc::ID())
837       aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
838                                        theFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
839
840     /// check that the geometry point with the given coordinates is the checked point
841     /// e.g. in arc the (x,y) point can not coicide to the center point and it automatically
842     /// means that this point is not an orphant one.
843     if (aPointAttr.get()) {
844       std::shared_ptr<GeomAPI_Pnt2d> aCheckedPoint = std::shared_ptr<GeomAPI_Pnt2d>(
845                                                     new GeomAPI_Pnt2d(theX, theY));
846       if (!aCheckedPoint->isEqual(aPointAttr->pnt()))
847         return anOrphanPoint;
848     }
849
850     if (aPointAttr.get()) {
851       std::shared_ptr<GeomAPI_Pnt2d> aPoint = aPointAttr->pnt();
852       // we need to find coincidence features in results also, because external object(point)
853       // uses refs to me in another feature.
854       FeaturePtr aCoincidence = PartSet_Tools::findFirstCoincidence(theFeature, aPoint);
855       anOrphanPoint = true;
856       // if there is at least one concident line to the point, the point is not an orphant
857       if (aCoincidence.get()) {
858         QList<FeaturePtr> aCoinsideLines;
859         QList<FeaturePtr> aCoins;
860         QList<bool> anIsAttributes;
861         PartSet_Tools::findCoincidences(aCoincidence, aCoinsideLines, aCoins,
862                                         SketchPlugin_ConstraintCoincidence::ENTITY_A(),
863                                         anIsAttributes);
864         PartSet_Tools::findCoincidences(aCoincidence, aCoinsideLines, aCoins,
865                                         SketchPlugin_ConstraintCoincidence::ENTITY_B(),
866                                         anIsAttributes);
867         QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(),
868                                           aLast = aCoinsideLines.end();
869         for (; anIt != aLast && anOrphanPoint; anIt++) {
870           anOrphanPoint = (*anIt)->getKind() != SketchPlugin_Line::ID();
871         }
872       }
873     }
874   }
875   return anOrphanPoint;
876 }
877
878 bool PartSet_WidgetPoint2D::shapeExploreHasVertex(const GeomShapePtr& theShape,
879                                                   const std::shared_ptr<GeomAPI_Pnt2d>& thePoint,
880                                                   const CompositeFeaturePtr& theSketch)
881 {
882   std::shared_ptr<GeomAPI_Pnt> aPoint = PartSet_Tools::point3D(thePoint, theSketch);
883
884   bool aContainPoint = false;
885   GeomAPI_ShapeExplorer anExp(theShape, GeomAPI_Shape::VERTEX);
886   for(; anExp.more() && !aContainPoint; anExp.next()) {
887     std::shared_ptr<GeomAPI_Shape> aVertexInCompSolid = anExp.current();
888     std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex(aVertexInCompSolid));
889     if (aVertex.get())
890       aContainPoint = aPoint->isEqual(aVertex->point());
891   }
892   return aContainPoint;
893 }
894
895 AttributeRefAttrPtr PartSet_WidgetPoint2D::attributeRefAttr() const
896 {
897   AttributeRefAttrPtr anAttribute;
898   if (myRefAttribute.empty())
899     return anAttribute;
900
901   AttributePtr anAttributeRef = feature()->attribute(myRefAttribute);
902   if (!anAttributeRef.get())
903     return anAttribute;
904
905   return std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttributeRef);
906 }
907
908 void PartSet_WidgetPoint2D::fillRefAttribute(double theClickedX, double theClickedY,
909                               const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
910 {
911   AttributeRefAttrPtr aRefAttr = attributeRefAttr();
912   if (!aRefAttr.get())
913     return;
914
915   FeaturePtr aFeature = feature();
916   std::string anAttribute = attributeID();
917
918   if (aFeature.get()) {
919     std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = std::shared_ptr<GeomAPI_Pnt2d>(
920                                       new GeomAPI_Pnt2d(theClickedX, theClickedY));
921     AttributePoint2DPtr aClickedFeaturePoint = findFirstEqualPointInSketch(mySketch,
922                                                             aFeature, aClickedPoint);
923     if (aClickedFeaturePoint.get())
924       aRefAttr->setAttr(aClickedFeaturePoint);
925     else {
926       ObjectPtr anObject = getGeomSelection(theValue);
927       if (anObject.get())
928         aRefAttr->setObject(anObject);
929     }
930   }
931 }
932
933 void PartSet_WidgetPoint2D::fillRefAttribute(const ModuleBase_ViewerPrsPtr& theValue)
934 {
935   fillRefAttribute(getGeomSelection(theValue));
936 }
937
938 void PartSet_WidgetPoint2D::fillRefAttribute(const ObjectPtr& theObject)
939 {
940   AttributeRefAttrPtr aRefAttr = attributeRefAttr();
941   if (aRefAttr.get())
942     aRefAttr->setObject(theObject);
943 }
944
945 std::shared_ptr<GeomDataAPI_Point2D> PartSet_WidgetPoint2D::findFirstEqualPointInArgumentFeatures(
946                   const FeaturePtr& theFeature, const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
947 {
948   std::shared_ptr<GeomDataAPI_Point2D> aFeaturePoint;
949
950   // may be feature is not updated yet, execute is not performed and references features
951   // are not created. Case: rectangle macro feature
952   ModuleBase_Tools::flushUpdated(theFeature);
953
954   std::list<AttributePtr> anAttributes = theFeature->data()->attributes(
955                                           ModelAPI_AttributeRefList::typeId());
956   std::list<AttributePtr>::const_iterator anIt = anAttributes.begin(), aLast = anAttributes.end();
957   for (; anIt != aLast && !aFeaturePoint.get(); anIt++) {
958     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
959                                       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIt);
960     for (int i = 0, aNb = aCurSelList->size(); i < aNb && !aFeaturePoint.get(); i++) {
961       ObjectPtr anObject = aCurSelList->object(i);
962       FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(anObject);
963       if (aFeature.get())
964         aFeaturePoint = findFirstEqualPoint(aFeature, thePoint);
965     }
966   }
967   return aFeaturePoint;
968 }
969
970 std::shared_ptr<GeomDataAPI_Point2D> PartSet_WidgetPoint2D::findFirstEqualPoint(
971                                               const FeaturePtr& theFeature,
972                                               const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
973 {
974   std::shared_ptr<GeomDataAPI_Point2D> aFPoint;
975
976   // find the given point in the feature attributes
977   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttiributes =
978                                     theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
979   std::list<std::shared_ptr<ModelAPI_Attribute> >::const_iterator anIt = anAttiributes.begin(),
980       aLast = anAttiributes.end();
981   ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
982
983   for (; anIt != aLast && !aFPoint; anIt++) {
984     std::shared_ptr<GeomDataAPI_Point2D> aCurPoint =
985                                              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
986     if (aCurPoint && aCurPoint->isInitialized() &&
987         aValidators->isCase(theFeature, aCurPoint->id()) &&
988         (aCurPoint->pnt()->distance(thePoint) < Precision::Confusion())) {
989       aFPoint = aCurPoint;
990       break;
991     }
992   }
993   return aFPoint;
994 }
995
996 std::shared_ptr<GeomDataAPI_Point2D> PartSet_WidgetPoint2D::findFirstEqualPointInSketch(
997                                     const CompositeFeaturePtr& theSketch,
998                                     const FeaturePtr& theSkipFeature,
999                                     const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
1000 {
1001   // get all sketch features. If the point with the given coordinates belong to any sketch feature,
1002   // the constraint is created between the feature point and the found sketch point
1003   std::shared_ptr<ModelAPI_Data> aData = theSketch->data();
1004   std::shared_ptr<ModelAPI_AttributeRefList> aRefList = std::dynamic_pointer_cast<
1005       ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
1006
1007   std::list<ObjectPtr> aFeatures = aRefList->list();
1008   std::list<ObjectPtr>::const_iterator anIt = aFeatures.begin(), aLast = aFeatures.end();
1009   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttiributes;
1010
1011   std::shared_ptr<GeomDataAPI_Point2D> aFPoint;
1012   for (; anIt != aLast; anIt++) {
1013     FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
1014     if (!aFeature.get() || (theSkipFeature.get() && theSkipFeature == aFeature))
1015       continue;
1016     aFPoint = PartSet_WidgetPoint2D::findFirstEqualPoint(aFeature, thePoint);
1017     if (aFPoint.get())
1018       break;
1019   }
1020   return aFPoint;
1021 }
1022
1023 ObjectPtr PartSet_WidgetPoint2D::getGeomSelection(const ModuleBase_ViewerPrsPtr& theValue)
1024 {
1025   ObjectPtr anObject;
1026   GeomShapePtr aShape;
1027   ModuleBase_ISelection* aSelection = myWorkshop->selection();
1028   anObject = aSelection->getResult(theValue);
1029   aShape = aSelection->getShape(theValue);
1030   myExternalObjectMgr->getGeomSelection(theValue, anObject, aShape, myWorkshop, sketch(), true);
1031
1032   return anObject;
1033 }