Salome HOME
Merge branch 'Dev_0.6.1' of newgeom:newgeom into Dev_0.6.1
[modules/shaper.git] / src / PartSet / PartSet_SketcherMgr.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        PartSet_SketcherMgr.cpp
4 // Created:     19 Dec 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "PartSet_SketcherMgr.h"
8 #include "PartSet_Module.h"
9 #include "PartSet_WidgetPoint2D.h"
10 #include "PartSet_Tools.h"
11
12 #include <XGUI_ModuleConnector.h>
13 #include <XGUI_Displayer.h>
14 #include <XGUI_Workshop.h>
15 #include <XGUI_Selection.h>
16 #include <XGUI_SelectionMgr.h>
17
18 #include <ModuleBase_IViewer.h>
19 #include <ModuleBase_IWorkshop.h>
20 #include <ModuleBase_IViewWindow.h>
21 #include <ModuleBase_Operation.h>
22 #include <ModuleBase_ISelection.h>
23 #include <ModuleBase_IPropertyPanel.h>
24 #include <ModuleBase_Operation.h>
25
26 #include <Events_Loop.h>
27
28 #include <SketchPlugin_Line.h>
29 #include <SketchPlugin_Sketch.h>
30 #include <SketchPlugin_Point.h>
31 #include <SketchPlugin_Arc.h>
32 #include <SketchPlugin_Circle.h>
33 #include <SketchPlugin_ConstraintLength.h>
34 #include <SketchPlugin_ConstraintDistance.h>
35 #include <SketchPlugin_ConstraintParallel.h>
36 #include <SketchPlugin_ConstraintPerpendicular.h>
37 #include <SketchPlugin_ConstraintRadius.h>
38 #include <SketchPlugin_ConstraintRigid.h>
39
40 #include <SelectMgr_IndexedMapOfOwner.hxx>
41 #include <StdSelect_BRepOwner.hxx>
42
43 #include <ModelAPI_Events.h>
44
45 #include <QMouseEvent>
46 #include <QApplication>
47
48
49
50
51 /// Returns list of unique objects by sum of objects from List1 and List2
52 QList<ObjectPtr> getSumList(const QList<ModuleBase_ViewerPrs>& theList1,
53                                        const QList<ModuleBase_ViewerPrs>& theList2)
54 {
55   QList<ObjectPtr> aRes;
56   foreach (ModuleBase_ViewerPrs aPrs, theList1) {
57     if (!aRes.contains(aPrs.object()))
58       aRes.append(aPrs.object());
59   }
60   foreach (ModuleBase_ViewerPrs aPrs, theList2) {
61     if (!aRes.contains(aPrs.object()))
62       aRes.append(aPrs.object());
63   }
64   return aRes;
65 }
66
67
68
69
70 PartSet_SketcherMgr::PartSet_SketcherMgr(PartSet_Module* theModule)
71   : QObject(theModule), myModule(theModule), myIsDragging(false), myDragDone(false)
72 {
73   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
74   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
75
76   connect(aViewer, SIGNAL(mousePress(ModuleBase_IViewWindow*, QMouseEvent*)),
77           this, SLOT(onMousePressed(ModuleBase_IViewWindow*, QMouseEvent*)));
78
79   connect(aViewer, SIGNAL(mouseRelease(ModuleBase_IViewWindow*, QMouseEvent*)),
80           this, SLOT(onMouseReleased(ModuleBase_IViewWindow*, QMouseEvent*)));
81
82   connect(aViewer, SIGNAL(mouseMove(ModuleBase_IViewWindow*, QMouseEvent*)),
83           this, SLOT(onMouseMoved(ModuleBase_IViewWindow*, QMouseEvent*)));
84
85   connect(aViewer, SIGNAL(mouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)),
86           this, SLOT(onMouseDoubleClick(ModuleBase_IViewWindow*, QMouseEvent*)));
87 }
88
89 PartSet_SketcherMgr::~PartSet_SketcherMgr()
90 {
91   if (!myPlaneFilter.IsNull())
92     myPlaneFilter.Nullify();
93 }
94
95 void PartSet_SketcherMgr::onMousePressed(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
96 {
97   // 
98   if (!(theEvent->buttons() & Qt::LeftButton))
99     return;
100
101   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
102   ModuleBase_Operation* aOperation = aWorkshop->currentOperation();
103   // Use only for sketch operations
104   if (aOperation && myCurrentSketch) {
105     if (!PartSet_Tools::sketchPlane(myCurrentSketch))
106       return;
107
108     bool isSketcher = (aOperation->id().toStdString() == SketchPlugin_Sketch::ID());
109     bool isSketchOpe = sketchOperationIdList().contains(aOperation->id());
110
111     // Avoid non-sketch operations
112     if ((!isSketchOpe) && (!isSketcher))
113       return;
114
115     bool isEditing = aOperation->isEditOperation();
116
117     // Ignore creation sketch operation
118     if ((!isSketcher) && (!isEditing))
119       return;
120
121     if (theEvent->modifiers()) {
122       // If user performs multiselection
123       if (isSketchOpe /* && (!isSketcher)*/)
124         if (!aOperation->commit())
125           aOperation->abort();
126       return;
127     }
128     // Remember highlighted objects for editing
129     ModuleBase_ISelection* aSelect = aWorkshop->selection();
130     QList<ModuleBase_ViewerPrs> aHighlighted = aSelect->getHighlighted();
131     QList<ModuleBase_ViewerPrs> aSelected = aSelect->getSelected();
132     myEditingFeatures.clear();
133     myEditingAttr.clear();
134
135     bool aHasShift = (theEvent->modifiers() & Qt::ShiftModifier);
136     QObjectPtrList aSelObjects;
137     if (aHasShift)
138       aSelObjects = getSumList(aHighlighted, aSelected);
139     else {
140       foreach (ModuleBase_ViewerPrs aPrs, aHighlighted) {
141         aSelObjects.append(aPrs.object());
142       }
143     }
144     if ((aSelObjects.size() == 0)) {
145       if (isSketchOpe && (!isSketcher))
146         // commit previous operation
147         if (!aOperation->commit())
148           aOperation->abort();
149       return;
150     }
151     if ((aHighlighted.size() == 1) && (aSelected.size() == 0)) {
152       // Move by selected shape (vertex). Can be used only for single selection
153       foreach(ModuleBase_ViewerPrs aPrs, aHighlighted) {
154         FeaturePtr aFeature = ModelAPI_Feature::feature(aHighlighted.first().object());
155         if (aFeature) {
156           myEditingFeatures.append(aFeature);
157           TopoDS_Shape aShape = aPrs.shape();
158           if (!aShape.IsNull()) {
159             if (aShape.ShapeType() == TopAbs_VERTEX) {
160               AttributePtr aAttr = PartSet_Tools::findAttributeBy2dPoint(myEditingFeatures.first(), 
161                                                                          aShape, myCurrentSketch);
162               if (aAttr)
163                 myEditingAttr.append(aAttr);
164             }
165           }
166         }
167       }
168     } else {
169       // Provide multi-selection. Can be used only for features
170       foreach (ObjectPtr aObj, aSelObjects) {
171         FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
172         if (aFeature && (!myEditingFeatures.contains(aFeature)))
173           myEditingFeatures.append(aFeature);
174       }
175
176     }
177     // If nothing highlighted - return
178     if (myEditingFeatures.size() == 0)
179       return;
180
181     if (isSketcher) {
182       myIsDragging = true;
183       get2dPoint(theWnd, theEvent, myCurX, myCurY);
184       myDragDone = false;
185       aWorkshop->viewer()->enableMultiselection(false);
186       launchEditing();
187
188     } else if (isSketchOpe && isEditing) {
189       // If selected another object
190       aOperation->abort();
191
192       myIsDragging = true;
193       get2dPoint(theWnd, theEvent, myCurX, myCurY);
194       myDragDone = false;
195       aWorkshop->viewer()->enableMultiselection(false);
196
197       // This is necessary in order to finalize previous operation
198       QApplication::processEvents();
199       launchEditing();
200     }
201   }
202 }
203
204 void PartSet_SketcherMgr::onMouseReleased(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
205 {
206   ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
207   ModuleBase_Operation* aOp = aWorkshop->currentOperation();
208   if (!aOp)
209     return;
210   if (!sketchOperationIdList().contains(aOp->id()))
211     return;
212
213   // Only for sketcher operations
214   ModuleBase_IViewer* aViewer = aWorkshop->viewer();
215   if (myIsDragging) {
216     myIsDragging = false;
217     if (myDragDone) {
218       aViewer->enableMultiselection(true);
219       aOp->commit();
220       myEditingFeatures.clear();
221       myEditingAttr.clear();
222       return;
223     }
224   }
225   if (!aViewer->isMultiSelectionEnabled()) {
226     aViewer->enableMultiselection(true);
227   }
228   //aViewer->AISContext()->MoveTo(theEvent->x(), theEvent->y(), theWnd->v3dView());
229   //if (theEvent->modifiers() & Qt::ShiftModifier)
230   //  aViewer->AISContext()->ShiftSelect();
231   //else
232   //  aViewer->AISContext()->Select();
233 }
234
235 void PartSet_SketcherMgr::onMouseMoved(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
236 {
237   if (myIsDragging) {
238     ModuleBase_Operation* aOperation = myModule->workshop()->currentOperation();
239     if (aOperation->id().toStdString() == SketchPlugin_Sketch::ID())
240       return; // No edit operation activated
241
242     static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_MOVED);
243     Handle(V3d_View) aView = theWnd->v3dView();
244     gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
245     double aX, aY;
246     PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, aX, aY);
247     double dX =  aX - myCurX;
248     double dY =  aY - myCurY;
249
250     if ((aOperation->id().toStdString() == SketchPlugin_Line::ID()) &&
251         (myEditingAttr.size() == 1) && 
252         myEditingAttr.first()) {
253       // probably we have prehighlighted point
254       AttributePtr aAttr = myEditingAttr.first();
255       std::string aAttrId = aAttr->id();
256       ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
257       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
258       // Find corresponded widget to provide dragging
259       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
260         if (aWgt->attributeID() == aAttrId) {
261           PartSet_WidgetPoint2D* aWgt2d = dynamic_cast<PartSet_WidgetPoint2D*>(aWgt);
262           if (aWgt2d) {
263             aWgt2d->setPoint(aWgt2d->x() + dX, aWgt2d->y() + dY);
264             break;
265           }
266         }
267       }
268     } else {
269       foreach(FeaturePtr aFeature, myEditingFeatures) {
270         std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
271           std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
272         if (aSketchFeature) { 
273           // save the previous selection
274           /*ModuleBase_IWorkshop* aWorkshop = myModule->workshop();
275           XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(aWorkshop);
276           XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
277           QIntList anActivatedModes;
278
279           ResultPtr aResult = aSketchFeature->firstResult();
280
281           aDisplayer->getModesOfActivation(aResult, anActivatedModes);
282
283           std::list<AttributePtr> aSelectedAttributes;
284           getCurrentSelection(aSketchFeature, myCurrentSketch, aWorkshop, aSelectedAttributes);*/
285           // save the previous selection: end
286
287
288           aSketchFeature->move(dX, dY);
289           ModelAPI_EventCreator::get()->sendUpdated(aSketchFeature, anEvent);
290           /*
291           // TODO: the selection restore should be after the AIS presentation is rebuilt
292           Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_MOVED));
293           Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
294
295           // restore the previous selection
296           aResult = aSketchFeature->firstResult();
297             aDisplayer->activate(aResult, anActivatedModes);
298
299           SelectMgr_IndexedMapOfOwner anOwnersToSelect;
300           getSelectionOwners(aSketchFeature, myCurrentSketch, aWorkshop, aSelectedAttributes,
301                              anOwnersToSelect);
302           
303           ModuleBase_IViewer* aViewer = aWorkshop->viewer();
304           Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
305           for (Standard_Integer i = 1, n = anOwnersToSelect.Extent(); i <= n; i++)
306             aContext->AddOrRemoveSelected(anOwnersToSelect(i), false); // SetSelected()
307
308           aContext->UpdateCurrentViewer();
309           // restore the previous selection*/
310         }
311       }
312       // TODO: set here
313       Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_MOVED));
314       Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
315     }
316     myDragDone = true;
317     myCurX = aX;
318     myCurY = aY;
319   }
320 }
321
322 void PartSet_SketcherMgr::onMouseDoubleClick(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent)
323 {
324   ModuleBase_Operation* aOperation = myModule->workshop()->currentOperation();
325   if (aOperation && aOperation->isEditOperation()) {
326     std::string aId = aOperation->id().toStdString();
327     if ((aId == SketchPlugin_ConstraintLength::ID()) ||
328       (aId == SketchPlugin_ConstraintDistance::ID()) ||
329       (aId == SketchPlugin_ConstraintRadius::ID())) 
330     {
331       // Activate dimension value editing on double click
332       ModuleBase_IPropertyPanel* aPanel = aOperation->propertyPanel();
333       QList<ModuleBase_ModelWidget*> aWidgets = aPanel->modelWidgets();
334       // Find corresponded widget to activate value editing
335       foreach (ModuleBase_ModelWidget* aWgt, aWidgets) {
336         if (aWgt->attributeID() == "ConstraintValue") {
337           aWgt->focusTo();
338           return;
339         }
340       }
341     }
342   }
343 }
344
345 void PartSet_SketcherMgr::get2dPoint(ModuleBase_IViewWindow* theWnd, QMouseEvent* theEvent, 
346                                 double& theX, double& theY)
347 {
348   Handle(V3d_View) aView = theWnd->v3dView();
349   gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), aView);
350   PartSet_Tools::convertTo2D(aPoint, myCurrentSketch, aView, theX, theY);
351 }
352
353 void PartSet_SketcherMgr::launchEditing()
354 {
355   if (myEditingFeatures.size() > 0) {
356     FeaturePtr aFeature = myEditingFeatures.first();
357     std::shared_ptr<SketchPlugin_Feature> aSPFeature = 
358               std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
359     if (aSPFeature) {
360       myModule->editFeature(aSPFeature);
361     }
362   }
363 }
364
365
366 QStringList PartSet_SketcherMgr::sketchOperationIdList()
367 {
368   static QStringList aIds;
369   if (aIds.size() == 0) {
370     aIds << SketchPlugin_Line::ID().c_str();
371     aIds << SketchPlugin_Point::ID().c_str();
372     aIds << SketchPlugin_Arc::ID().c_str();
373     aIds << SketchPlugin_Circle::ID().c_str();
374     aIds << SketchPlugin_ConstraintLength::ID().c_str();
375     aIds << SketchPlugin_ConstraintDistance::ID().c_str();
376     aIds << SketchPlugin_ConstraintRigid::ID().c_str();
377     aIds << SketchPlugin_ConstraintRadius::ID().c_str();
378     aIds << SketchPlugin_ConstraintPerpendicular::ID().c_str();
379     aIds << SketchPlugin_ConstraintParallel::ID().c_str();
380   }
381   return aIds;
382 }
383
384 void PartSet_SketcherMgr::startSketch(ModuleBase_Operation* theOperation)
385 {
386   // Display all sketcher sub-Objects
387   myCurrentSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theOperation->feature());
388   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
389   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
390
391   // Hide sketcher result
392   std::list<ResultPtr> aResults = myCurrentSketch->results();
393   std::list<ResultPtr>::const_iterator aIt;
394   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
395     aDisplayer->erase((*aIt), false);
396   }
397   aDisplayer->erase(myCurrentSketch, false);
398
399   // Display sketcher objects
400   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
401     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
402     std::list<ResultPtr> aResults = aFeature->results();
403     std::list<ResultPtr>::const_iterator aIt;
404     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
405       aDisplayer->display((*aIt), false);
406     }
407     aDisplayer->display(aFeature, false);
408   }
409
410   if (myPlaneFilter.IsNull()) 
411     myPlaneFilter = new ModuleBase_ShapeInPlaneFilter();
412
413   myModule->workshop()->viewer()->addSelectionFilter(myPlaneFilter);
414   if (theOperation->isEditOperation()) {
415     // If it is editing of sketch then it means that plane is already defined
416     std::shared_ptr<GeomAPI_Pln> aPln = PartSet_Tools::sketchPlane(myCurrentSketch);
417     myPlaneFilter->setPlane(aPln->impl<gp_Pln>());
418   }
419   aDisplayer->updateViewer();
420 }
421
422 void PartSet_SketcherMgr::stopSketch(ModuleBase_Operation* theOperation)
423 {
424   DataPtr aData = myCurrentSketch->data();
425   if ((!aData) || (!aData->isValid())) {
426     // The sketch was aborted
427     myCurrentSketch = CompositeFeaturePtr();
428     myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
429     return; 
430   }
431   // Hide all sketcher sub-Objects
432   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
433   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
434   for (int i = 0; i < myCurrentSketch->numberOfSubs(); i++) {
435     FeaturePtr aFeature = myCurrentSketch->subFeature(i);
436     std::list<ResultPtr> aResults = aFeature->results();
437     std::list<ResultPtr>::const_iterator aIt;
438     for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
439       aDisplayer->erase((*aIt), false);
440     }
441     aDisplayer->erase(aFeature, false);
442   }
443   // Display sketcher result
444   std::list<ResultPtr> aResults = myCurrentSketch->results();
445   std::list<ResultPtr>::const_iterator aIt;
446   for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
447     aDisplayer->display((*aIt), false);
448   }
449   aDisplayer->display(myCurrentSketch);
450     
451   myCurrentSketch = CompositeFeaturePtr();
452   myModule->workshop()->viewer()->removeSelectionFilter(myPlaneFilter);
453   aDisplayer->updateViewer();
454 }
455
456
457 void PartSet_SketcherMgr::onPlaneSelected(const std::shared_ptr<GeomAPI_Pln>& thePln)
458 {
459   myPlaneFilter->setPlane(thePln->impl<gp_Pln>());
460 }
461
462 void PartSet_SketcherMgr::getCurrentSelection(const ObjectPtr& theObject,
463                                               const FeaturePtr& theSketch,
464                                               ModuleBase_IWorkshop* theWorkshop,
465                                               std::list<AttributePtr>& theSelectedAttributes)
466 {
467   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
468   if (aFeature.get() == NULL)
469     return;
470
471   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
472   Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
473   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
474   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
475
476   // TODO: check all results and IPresentable feature
477   ResultPtr aResult = aFeature->firstResult();
478
479   bool isVisibleSketch = aDisplayer->isVisible(aResult);
480   AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
481
482   if (aAISObj.get() != NULL) {
483     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
484     for (aContext->InitSelected(); aContext->MoreSelected(); aContext->NextSelected())
485     {
486       Handle(StdSelect_BRepOwner) aBRepOwner = Handle(StdSelect_BRepOwner)::DownCast(
487                                                                       aContext->SelectedOwner());
488       if (aBRepOwner.IsNull()) continue;
489
490       Handle(AIS_InteractiveObject) anIO = Handle(AIS_InteractiveObject)::DownCast(
491                                                                        aBRepOwner->Selectable());
492       if (anIO != anAISIO) continue;
493
494       if (aBRepOwner->HasShape()) {
495         const TopoDS_Shape& aShape = aBRepOwner->Shape();
496         TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
497         if (aShapeType == TopAbs_VERTEX) {
498           AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theObject,
499                                                                         aShape, theSketch);
500           if (aPntAttr.get() != NULL)
501             theSelectedAttributes.push_back(aPntAttr);
502         }
503       }
504     }
505   }
506 }
507
508 void PartSet_SketcherMgr::getSelectionOwners(const ObjectPtr& theObject,
509                                              const FeaturePtr& theSketch,
510                                              ModuleBase_IWorkshop* theWorkshop,
511                                              const std::list<AttributePtr>& theSelectedAttributes,
512                                              SelectMgr_IndexedMapOfOwner& anOwnersToSelect)
513 {
514   FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
515   if (aFeature.get() == NULL)
516     return;
517
518   ModuleBase_IViewer* aViewer = theWorkshop->viewer();
519   Handle(AIS_InteractiveContext) aContext = aViewer->AISContext();
520   XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(theWorkshop);
521   XGUI_Displayer* aDisplayer = aConnector->workshop()->displayer();
522
523   // TODO: check all results and IPresentable feature
524   ResultPtr aResult = aFeature->firstResult();
525
526   bool isVisibleSketch = aDisplayer->isVisible(aResult);
527   AISObjectPtr aAISObj = aDisplayer->getAISObject(aResult);
528
529   if (aAISObj.get() != NULL) {
530     Handle(AIS_InteractiveObject) anAISIO = aAISObj->impl<Handle(AIS_InteractiveObject)>();
531
532     SelectMgr_IndexedMapOfOwner aSelectedOwners;
533
534     aConnector->workshop()->selector()->selection()->entityOwners(anAISIO, aSelectedOwners);
535     for  ( Standard_Integer i = 1, n = aSelectedOwners.Extent(); i <= n; i++ ) {
536       Handle(StdSelect_BRepOwner) anOwner = Handle(StdSelect_BRepOwner)::DownCast(aSelectedOwners(i));
537       if ( anOwner.IsNull() || !anOwner->HasShape() )
538         continue;
539       const TopoDS_Shape& aShape = anOwner->Shape();
540       TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
541       if (aShapeType == TopAbs_VERTEX) {
542         AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(aFeature, aShape, theSketch);
543         if (aPntAttr.get() != NULL) {
544           std::list<AttributePtr>::const_iterator anIt = theSelectedAttributes.begin(),
545                                                   aLast = theSelectedAttributes.end();
546           for (; anIt != aLast; anIt++) {
547             AttributePtr anAttrIt = *anIt;
548             if (anAttrIt.get() == aPntAttr.get()) {
549               anOwnersToSelect.Add(anOwner);
550             }
551           }
552         }
553       }
554     }
555   }
556 }