Salome HOME
ModuleBase_ViewerPrs is wrapped into shared_ptr.
[modules/shaper.git] / src / PartSet / PartSet_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        PartSet_Validators.cpp
4 // Created:     09 July 2014
5 // Author:      Vitaly SMETANNIKOV
6
7 #include "PartSet_Validators.h"
8
9 #include "PartSet_Tools.h"
10 #include "PartSet_SketcherMgr.h"
11
12 #include <TopoDS.hxx>
13 #include <TopoDS_Edge.hxx>
14 #include <BRep_Tool.hxx>
15 #include <GeomAdaptor_Curve.hxx>
16 #include <GeomAbs_CurveType.hxx>
17 #include <ModuleBase_ISelection.h>
18 #include <ModuleBase_WidgetShapeSelector.h>
19 #include <ModuleBase_OperationFeature.h>
20
21 #include <ModelAPI_AttributeRefAttr.h>
22 #include <ModelAPI_AttributeSelection.h>
23 #include <ModelAPI_AttributeReference.h>
24 #include <ModelAPI_AttributeSelectionList.h>
25 #include <ModelAPI_AttributeRefList.h>
26 #include <ModelAPI_Object.h>
27 #include <ModelAPI_Session.h>
28 #include <ModelAPI_Tools.h>
29
30 #include <SketchPlugin_Sketch.h>
31 #include <SketchPlugin_ConstraintCoincidence.h>
32 #include <SketchPlugin_Arc.h>
33 #include <GeomAPI_Edge.h>
34
35 #include <list>
36 #ifdef _DEBUG
37 #include <iostream>
38 #endif
39
40 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
41 {
42   QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
43   ModuleBase_ISelection::filterSelectionOnEqualPoints(aList);
44
45   int aCount = 0;
46   foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
47     const GeomShapePtr& aShape = aPrs->shape();
48     if (aShape.get() && !aShape->isNull()) {
49       if (aShape->shapeType() == GeomAPI_Shape::VERTEX)
50         aCount++;
51     }
52   }
53   return aCount;
54 }
55
56 int shapesNbLines(const ModuleBase_ISelection* theSelection)
57 {
58   QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
59   int aCount = 0;
60   foreach(ModuleBase_ViewerPrsPtr aPrs, aList) {
61     const GeomShapePtr& aShape = aPrs->shape();
62     if (aShape.get() && !aShape->isNull()) {
63       if (aShape->shapeType() == GeomAPI_Shape::EDGE) {
64         const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
65         TopoDS_Edge aEdge = TopoDS::Edge(aTDShape);
66         Standard_Real aStart, aEnd;
67         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
68         GeomAdaptor_Curve aAdaptor(aCurve);
69         if (aAdaptor.GetType() == GeomAbs_Line)
70           aCount++;
71       }
72     }
73   }
74   return aCount;
75 }
76
77
78 std::shared_ptr<GeomAPI_Pln> sketcherPlane(ModuleBase_Operation* theOperation)
79 {
80   std::shared_ptr<GeomAPI_Pln> aEmptyPln;
81   if (theOperation) {
82     ModuleBase_OperationFeature* aFeatureOp = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
83     if (aFeatureOp) {
84       CompositeFeaturePtr aFeature = 
85         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeatureOp->feature());
86       if (aFeature && (aFeature->getKind() == SketchPlugin_Sketch::ID()))
87         return PartSet_Tools::sketchPlane(aFeature);
88     }
89   }
90   return aEmptyPln; 
91 }
92
93
94 bool isEmptySelectionValid(ModuleBase_Operation* theOperation)
95 {
96   ModuleBase_OperationFeature* aFeatureOp = dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
97   // during the create operation empty selection is always valid
98   if (!aFeatureOp->isEditOperation()) {
99     return true;
100   }
101   else {
102     if (PartSet_SketcherMgr::isSketchOperation(aFeatureOp)) {
103       std::shared_ptr<GeomAPI_Pln> aPlane = sketcherPlane(theOperation);
104       if (aPlane.get())
105         return true;
106       else 
107         return false;
108     }
109     else// in edit operation an empty selection is always valid, performed for re-entrant operrations
110       return true;
111   }
112 }
113
114 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
115 {
116   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
117     return isEmptySelectionValid(theOperation);
118   } else {
119     int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
120     return (aCount > 0) && (aCount < 3);
121   }
122 }
123
124 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
125 {
126   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
127     return isEmptySelectionValid(theOperation);
128   } else {
129     int aCount = shapesNbLines(theSelection);
130     return (aCount == 1);
131   }
132 }
133
134 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
135 {
136   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
137     return isEmptySelectionValid(theOperation);
138   } else {
139     int aCount = shapesNbLines(theSelection);
140     return (aCount > 0) && (aCount < 3);
141   }
142 }
143
144 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
145 {
146   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
147     return isEmptySelectionValid(theOperation);
148   } else {
149     int aCount = shapesNbLines(theSelection);
150     return (aCount > 0) && (aCount < 3);
151   }
152 }
153
154 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
155 {
156   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
157     return isEmptySelectionValid(theOperation);
158   } else {
159     QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
160     int aCount = 0;
161     foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
162       const GeomShapePtr& aShape = aPrs->shape();
163       if (aShape.get() && !aShape->isNull()) {
164         if (aShape->shapeType() == GeomAPI_Shape::EDGE) {
165           const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
166           TopoDS_Edge aEdge = TopoDS::Edge(aTDShape);
167           Standard_Real aStart, aEnd;
168           Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
169           GeomAdaptor_Curve aAdaptor(aCurve);
170           if (aAdaptor.GetType() == GeomAbs_Circle)
171             aCount++;
172         }
173       }
174     }
175     return (aCount == 1);
176   }
177 }
178
179 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
180 {
181   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
182     return isEmptySelectionValid(theOperation);
183   } else {
184     QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
185     return (aList.count() == 1);
186   }
187 }
188
189
190 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
191 {
192   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
193     return isEmptySelectionValid(theOperation);
194   } else {
195     // Coincident can be applied to points and to lines
196     int aCount = shapesNbPoints(theSelection);
197     aCount += shapesNbLines(theSelection);
198     return (aCount > 0) && (aCount < 3);
199   }
200 }
201
202 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
203 {
204   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
205     return isEmptySelectionValid(theOperation);
206   } else {
207     int aCount = shapesNbLines(theSelection);
208     return (aCount == 1);
209   }
210 }
211
212 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
213 {
214   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
215     return isEmptySelectionValid(theOperation);
216   } else {
217     int aCount = shapesNbPoints(theSelection);
218     return aCount == 1;
219   }
220 }
221
222 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
223 {
224   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
225     return isEmptySelectionValid(theOperation);
226   } else {
227     QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
228     if ((aList.size() == 0) || (aList.size() > 2))
229       return false;
230
231     ModuleBase_ViewerPrsPtr aPrs = aList.first();
232     const GeomShapePtr& aShape = aPrs->shape();
233     if (!aShape.get() || aShape->isNull() || aShape->shapeType() != GeomAPI_Shape::EDGE)
234       return false;
235     GeomAPI_Edge aEdge1(aShape);
236
237     if (aEdge1.isLine() || aEdge1.isArc()) {
238       if (aList.size() == 2) {
239         // Check second selection
240         aPrs = aList.last();
241         const GeomShapePtr& aShape2 = aPrs->shape();
242         if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
243           return false;
244         GeomAPI_Edge aEdge2(aShape2);
245
246         if (aEdge1.isLine() && aEdge2.isArc())
247           return true;
248         else if (aEdge1.isArc() && aEdge2.isLine())
249           return true;
250         else
251           return false;
252       } else
253         return true;
254     }
255     return false;
256   }
257 }
258
259 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
260 {
261   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
262     return isEmptySelectionValid(theOperation);
263   } else {
264     int aCount = shapesNbLines(theSelection);
265     return (aCount > 0) && (aCount < 3);
266   }
267 }
268
269 bool PartSet_EqualSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
270 {
271   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
272     return isEmptySelectionValid(theOperation);
273   } else {
274     QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
275     int aCount = 0;
276     int aType = 0;
277     foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
278       GeomShapePtr aShape = aPrs->shape();
279       if (aShape.get() && aShape->isEdge()) {
280         aCount++;
281         GeomAPI_Edge aEdge(aShape);
282         if (aEdge.isLine()) {
283           if (aCount == 1)
284             aType = 1;
285           else if (aType != 1)
286             return false;
287         } else if (aEdge.isCircle()) {
288           if (aCount == 1)
289             aType = 2;
290           else if (aType != 2)
291             return false;
292         } else if (aEdge.isArc()) {
293           if (aCount == 1)
294             aType = 3;
295           else if (aType != 3)
296             return false;
297         }
298       } else
299         return false;
300     }
301     return (aCount > 0) && (aCount < 3);
302   }
303 }
304
305 bool PartSet_CollinearSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
306 {
307   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
308     return isEmptySelectionValid(theOperation);
309   } else {
310     int aCount = shapesNbLines(theSelection);
311     return (aCount > 0) && (aCount < 3);
312   }
313 }
314
315 bool PartSet_MiddlePointSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
316 {
317   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0)
318     return isEmptySelectionValid(theOperation);
319   else
320     return shapesNbLines(theSelection) == 1 && shapesNbPoints(theSelection) == 1;
321 }
322
323
324 std::string PartSet_DifferentObjectsValidator::errorMessage(
325                          const PartSet_DifferentObjectsValidator::ErrorType& theType,
326                          const std::string& thEqualObject, const std::string& theFirstAttribute,
327                          const std::string& theSecondAttribute) const
328 {
329   std::string anError;
330   switch (theType) {
331     case EqualObjects:
332       anError = "The feature uses one " + thEqualObject + " object in " +
333                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
334       break;
335     case EqualAttributes:
336       anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
337                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
338       break;
339     case EqualShapes:
340       anError = "The feature uses one shape in " +
341                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
342       break;
343     case EmptyShapes:
344       anError = "The feature uses empty shapes in " +
345                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
346       break;
347       break;
348     default:
349       break;
350   }
351   return anError;
352 }
353
354 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute, 
355                                                 const std::list<std::string>& theArguments,
356                                                 std::string& theError) const
357 {
358   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
359
360   // the type of validated attributes should be equal, attributes with different types are not validated
361   // Check RefAttr attributes
362   std::string anAttrType = theAttribute->attributeType();
363   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
364
365   if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
366     AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
367     bool isObject = anAttr->isObject();
368     ObjectPtr anObject = anAttr->object();
369     AttributePtr anAttributeAttr = anAttr->attr();
370
371     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
372     if (anAttrs.size() > 0) {
373       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
374       for(; anAttr != anAttrs.end(); anAttr++) {
375       if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
376           std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
377                                       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
378           if (aRef->isObject() != isObject)
379             continue;
380           if (isObject) {
381             if (aRef->object() == anObject) {
382               theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
383                                       theAttribute->id(), aRef->id());
384               return false;
385             }
386           }
387           else { // the attribute reference
388             if (aRef->attr() == anAttributeAttr) {
389               theError = errorMessage(EqualAttributes,
390                                       anAttributeAttr.get() ? anAttributeAttr->id() : "",
391                                       theAttribute->id(), aRef->id());
392               return false;
393             }
394           }
395         }
396       }
397     }
398   }
399   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
400     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
401     ResultPtr aContext = anAttr->context();
402     GeomShapePtr aShape = anAttr->value();
403
404     // Check selection attributes
405     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
406     if (anAttrs.size() > 0) {
407       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
408       for(; anAttr != anAttrs.end(); anAttr++) {
409         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
410           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
411                                         std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
412           // check the object is already presented
413           if (aRef->context() == aContext) {
414             bool aHasShape = aShape.get() != NULL;
415             if (!aHasShape || aRef->value()->isEqual(aShape)) {
416               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
417               return false;
418             }
419           }
420         }
421       }
422     }
423   }
424   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
425     AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
426     ObjectPtr anObject = anAttr->value();
427     // Check selection attributes
428     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
429     if (anAttrs.size() > 0) {
430       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
431       for(; anAttr != anAttrs.end(); anAttr++) {
432         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
433           std::shared_ptr<ModelAPI_AttributeReference> aRef =
434             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
435           // check the object is already presented
436           if (aRef->value() == anObject) {
437             theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
438                                     theAttribute->id(), aRef->id());
439             return false;
440           }
441         }
442         return true;
443       }
444     }
445   }
446   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
447     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList = 
448             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
449     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
450     if(anAttrs.size() > 0) {
451       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
452       for(; anAttrItr != anAttrs.end(); anAttrItr++){
453         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
454           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList = 
455             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
456           for(int i = 0; i < aCurSelList->size(); i++) {
457             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
458             ResultPtr aCurSelContext = aCurSel->context();
459             ResultCompSolidPtr aCurSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aCurSelContext);
460             std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
461             if(aCurSelCompSolidPtr.get()) {
462               aCurSelCompSolid = aCurSelCompSolidPtr->shape();
463             }
464             for(int j = 0; j < aRefSelList->size(); j++) {
465               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
466               ResultPtr aRefSelContext = aRefSel->context();
467               ResultCompSolidPtr aRefSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aRefSelContext);
468               std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
469               if(aRefSelCompSolidPtr.get()) {
470                 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
471               }
472               if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
473                 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
474                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
475                                           aRefSel->id());
476                   return false;
477               }
478               if(aCurSelContext == aRefSelContext) {
479                 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
480                   theError = errorMessage(EmptyShapes, "", theAttribute->id(),
481                                           aRefSel->id());
482                   return false;
483                 }
484                 if (aCurSel->value()->isEqual(aRefSel->value())) {
485                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
486                                           aRefSel->id());
487                   return false;
488                 }
489               }
490             }
491           }
492         }
493       }
494     }
495   }
496   else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
497     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
498       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
499     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
500     if (anAttrs.size() > 0) {
501       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
502       for (; anAttrItr != anAttrs.end(); anAttrItr++){
503         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
504           std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
505             std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
506           for (int i = 0; i < aCurSelList->size(); i++) {
507             ObjectPtr aCurSelObject = aCurSelList->object(i);
508             for (int j = 0; j < aRefSelList->size(); j++) {
509               if (aCurSelObject == aRefSelList->object(j)) {
510                 theError = errorMessage(EqualObjects,
511                               aCurSelObject.get() ? aCurSelObject->data()->name() : "",
512                               theAttribute->id(), aCurSelList->id());
513                 return false;
514               }
515             }
516           }
517         }
518       }
519     }
520   }
521   return true;
522 }
523
524 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute, 
525                                      const std::list<std::string>& theArguments,
526                                      std::string& theError) const
527 {
528   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
529     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
530     return false;
531   }
532
533   // there is a check whether the feature contains a point and a linear edge or two point values
534   std::string aParamA = theArguments.front();
535   SessionPtr aMgr = ModelAPI_Session::get();
536   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
537
538   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
539   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
540   QList<FeaturePtr> aCoinsideLines;
541   QList<FeaturePtr> aCoins;
542
543   bool isObject = aRefAttr->isObject();
544   ObjectPtr anObject = aRefAttr->object();
545   if (isObject && anObject) {
546     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
547     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
548     ObjectPtr aOtherObject = aOtherAttr->object();
549     // if the other attribute is not filled still, the result is true
550     if (!aOtherObject.get())
551       return true;
552     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
553
554     // check that both have coincidence
555     FeaturePtr aConstrFeature;
556     std::set<FeaturePtr> aCoinList;
557     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
558     std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
559     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
560       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
561       aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
562       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
563         AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
564         AttributePtr aAR = aRAttr->attr();
565         if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
566           aCoinList.insert(aConstrFeature);
567           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
568                                           SketchPlugin_ConstraintCoincidence::ENTITY_A());
569           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
570                                           SketchPlugin_ConstraintCoincidence::ENTITY_B());
571       }
572     }
573     // if there is no coincidence then it is not valid
574     if (aCoinList.size() > 0) {
575       QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
576       bool aValid = false;
577       for (; anIt != aLast && !aValid; anIt++) {
578         aValid = *anIt == aOtherFea;
579       }
580       if (aValid)
581         return true;
582     }
583   }
584   theError = "There is no a common coincident point.";
585   return false;
586 }
587