]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_Validators.cpp
Salome HOME
#1371 Using auxilliary Sketch elements in any Feature: code improvement to separate...
[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_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
43   ModuleBase_ISelection::filterSelectionOnEqualPoints(aList);
44
45   int aCount = 0;
46   foreach (ModuleBase_ViewerPrs 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_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
59   int aCount = 0;
60   foreach(ModuleBase_ViewerPrs 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_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
160     ModuleBase_ViewerPrs aPrs;
161     int aCount = 0;
162     foreach (ModuleBase_ViewerPrs aPrs, aList) {
163       const GeomShapePtr& aShape = aPrs.shape();
164       if (aShape.get() && !aShape->isNull()) {
165         if (aShape->shapeType() == GeomAPI_Shape::EDGE) {
166           const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
167           TopoDS_Edge aEdge = TopoDS::Edge(aTDShape);
168           Standard_Real aStart, aEnd;
169           Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
170           GeomAdaptor_Curve aAdaptor(aCurve);
171           if (aAdaptor.GetType() == GeomAbs_Circle)
172             aCount++;
173         }
174       }
175     }
176     return (aCount == 1);
177   }
178 }
179
180 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
181 {
182   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
183     return isEmptySelectionValid(theOperation);
184   } else {
185     QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
186     return (aList.count() == 1);
187   }
188 }
189
190
191 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
192 {
193   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
194     return isEmptySelectionValid(theOperation);
195   } else {
196     // Coincident can be applied to points and to lines
197     int aCount = shapesNbPoints(theSelection);
198     aCount += shapesNbLines(theSelection);
199     return (aCount > 0) && (aCount < 3);
200   }
201 }
202
203 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
204 {
205   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
206     return isEmptySelectionValid(theOperation);
207   } else {
208     int aCount = shapesNbLines(theSelection);
209     return (aCount == 1);
210   }
211 }
212
213 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
214 {
215   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
216     return isEmptySelectionValid(theOperation);
217   } else {
218     int aCount = shapesNbPoints(theSelection);
219     return aCount == 1;
220   }
221 }
222
223 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
224 {
225   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
226     return isEmptySelectionValid(theOperation);
227   } else {
228     QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
229     if ((aList.size() == 0) || (aList.size() > 2))
230       return false;
231
232     ModuleBase_ViewerPrs aPrs = aList.first();
233     const GeomShapePtr& aShape = aPrs.shape();
234     if (!aShape.get() || aShape->isNull() || aShape->shapeType() != GeomAPI_Shape::EDGE)
235       return false;
236     GeomAPI_Edge aEdge1(aShape);
237
238     if (aEdge1.isLine() || aEdge1.isArc()) {
239       if (aList.size() == 2) {
240         // Check second selection
241         aPrs = aList.last();
242         const GeomShapePtr& aShape2 = aPrs.shape();
243         if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
244           return false;
245         GeomAPI_Edge aEdge2(aShape2);
246
247         if (aEdge1.isLine() && aEdge2.isArc())
248           return true;
249         else if (aEdge1.isArc() && aEdge2.isLine())
250           return true;
251         else
252           return false;
253       } else
254         return true;
255     }
256     return false;
257   }
258 }
259
260 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
261 {
262   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
263     return isEmptySelectionValid(theOperation);
264   } else {
265     int aCount = shapesNbLines(theSelection);
266     return (aCount > 0) && (aCount < 3);
267   }
268 }
269
270 bool PartSet_EqualSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
271 {
272   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
273     return isEmptySelectionValid(theOperation);
274   } else {
275     QList<ModuleBase_ViewerPrs> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
276     ModuleBase_ViewerPrs aPrs;
277     int aCount = 0;
278     int aType = 0;
279     foreach (ModuleBase_ViewerPrs aPrs, aList) {
280       GeomShapePtr aShape = aPrs.shape();
281       if (aShape.get() && aShape->isEdge()) {
282         aCount++;
283         GeomAPI_Edge aEdge(aShape);
284         if (aEdge.isLine()) {
285           if (aCount == 1)
286             aType = 1;
287           else if (aType != 1)
288             return false;
289         } else if (aEdge.isCircle()) {
290           if (aCount == 1)
291             aType = 2;
292           else if (aType != 2)
293             return false;
294         } else if (aEdge.isArc()) {
295           if (aCount == 1)
296             aType = 3;
297           else if (aType != 3)
298             return false;
299         }
300       } else
301         return false;
302     }
303     return (aCount > 0) && (aCount < 3);
304   }
305 }
306
307 bool PartSet_CollinearSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
308 {
309   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
310     return isEmptySelectionValid(theOperation);
311   } else {
312     int aCount = shapesNbLines(theSelection);
313     return (aCount > 0) && (aCount < 3);
314   }
315 }
316
317 bool PartSet_MiddlePointSelection::isValid(const ModuleBase_ISelection* theSelection, ModuleBase_Operation* theOperation) const
318 {
319   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0)
320     return isEmptySelectionValid(theOperation);
321   else
322     return shapesNbLines(theSelection) == 1 && shapesNbPoints(theSelection) == 1;
323 }
324
325
326 std::string PartSet_DifferentObjectsValidator::errorMessage(
327                          const PartSet_DifferentObjectsValidator::ErrorType& theType,
328                          const std::string& thEqualObject, const std::string& theFirstAttribute,
329                          const std::string& theSecondAttribute) const
330 {
331   std::string anError;
332   switch (theType) {
333     case EqualObjects:
334       anError = "The feature uses one " + thEqualObject + " object in " +
335                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
336       break;
337     case EqualAttributes:
338       anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
339                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
340       break;
341     case EqualShapes:
342       anError = "The feature uses one shape in " +
343                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
344       break;
345     case EmptyShapes:
346       anError = "The feature uses empty shapes in " +
347                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
348       break;
349       break;
350     default:
351       break;
352   }
353   return anError;
354 }
355
356 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute, 
357                                                 const std::list<std::string>& theArguments,
358                                                 std::string& theError) const
359 {
360   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
361
362   // the type of validated attributes should be equal, attributes with different types are not validated
363   // Check RefAttr attributes
364   std::string anAttrType = theAttribute->attributeType();
365   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
366
367   if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
368     AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
369     bool isObject = anAttr->isObject();
370     ObjectPtr anObject = anAttr->object();
371     AttributePtr anAttributeAttr = anAttr->attr();
372
373     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
374     if (anAttrs.size() > 0) {
375       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
376       for(; anAttr != anAttrs.end(); anAttr++) {
377       if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
378           std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
379                                       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
380           if (aRef->isObject() != isObject)
381             continue;
382           if (isObject) {
383             if (aRef->object() == anObject) {
384               theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
385                                       theAttribute->id(), aRef->id());
386               return false;
387             }
388           }
389           else { // the attribute reference
390             if (aRef->attr() == anAttributeAttr) {
391               theError = errorMessage(EqualAttributes,
392                                       anAttributeAttr.get() ? anAttributeAttr->id() : "",
393                                       theAttribute->id(), aRef->id());
394               return false;
395             }
396           }
397         }
398       }
399     }
400   }
401   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
402     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
403     ResultPtr aContext = anAttr->context();
404     GeomShapePtr aShape = anAttr->value();
405
406     // Check selection attributes
407     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
408     if (anAttrs.size() > 0) {
409       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
410       for(; anAttr != anAttrs.end(); anAttr++) {
411         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
412           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
413                                         std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
414           // check the object is already presented
415           if (aRef->context() == aContext) {
416             bool aHasShape = aShape.get() != NULL;
417             if (!aHasShape || aRef->value()->isEqual(aShape)) {
418               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
419               return false;
420             }
421           }
422         }
423       }
424     }
425   }
426   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
427     AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
428     ObjectPtr anObject = anAttr->value();
429     // Check selection attributes
430     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
431     if (anAttrs.size() > 0) {
432       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
433       for(; anAttr != anAttrs.end(); anAttr++) {
434         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
435           std::shared_ptr<ModelAPI_AttributeReference> aRef =
436             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
437           // check the object is already presented
438           if (aRef->value() == anObject) {
439             theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
440                                     theAttribute->id(), aRef->id());
441             return false;
442           }
443         }
444         return true;
445       }
446     }
447   }
448   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
449     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList = 
450             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
451     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
452     if(anAttrs.size() > 0) {
453       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
454       for(; anAttrItr != anAttrs.end(); anAttrItr++){
455         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
456           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList = 
457             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
458           for(int i = 0; i < aCurSelList->size(); i++) {
459             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
460             ResultPtr aCurSelContext = aCurSel->context();
461             ResultCompSolidPtr aCurSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aCurSelContext);
462             std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
463             if(aCurSelCompSolidPtr.get()) {
464               aCurSelCompSolid = aCurSelCompSolidPtr->shape();
465             }
466             for(int j = 0; j < aRefSelList->size(); j++) {
467               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
468               ResultPtr aRefSelContext = aRefSel->context();
469               ResultCompSolidPtr aRefSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aRefSelContext);
470               std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
471               if(aRefSelCompSolidPtr.get()) {
472                 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
473               }
474               if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
475                 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
476                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
477                                           aRefSel->id());
478                   return false;
479               }
480               if(aCurSelContext == aRefSelContext) {
481                 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
482                   theError = errorMessage(EmptyShapes, "", theAttribute->id(),
483                                           aRefSel->id());
484                   return false;
485                 }
486                 if (aCurSel->value()->isEqual(aRefSel->value())) {
487                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
488                                           aRefSel->id());
489                   return false;
490                 }
491               }
492             }
493           }
494         }
495       }
496     }
497   }
498   else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
499     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
500       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
501     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
502     if (anAttrs.size() > 0) {
503       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
504       for (; anAttrItr != anAttrs.end(); anAttrItr++){
505         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
506           std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
507             std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
508           for (int i = 0; i < aCurSelList->size(); i++) {
509             ObjectPtr aCurSelObject = aCurSelList->object(i);
510             for (int j = 0; j < aRefSelList->size(); j++) {
511               if (aCurSelObject == aRefSelList->object(j)) {
512                 theError = errorMessage(EqualObjects,
513                               aCurSelObject.get() ? aCurSelObject->data()->name() : "",
514                               theAttribute->id(), aCurSelList->id());
515                 return false;
516               }
517             }
518           }
519         }
520       }
521     }
522   }
523   return true;
524 }
525
526 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute, 
527                                      const std::list<std::string>& theArguments,
528                                      std::string& theError) const
529 {
530   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
531     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
532     return false;
533   }
534
535   // there is a check whether the feature contains a point and a linear edge or two point values
536   std::string aParamA = theArguments.front();
537   SessionPtr aMgr = ModelAPI_Session::get();
538   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
539
540   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
541   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
542   QList<FeaturePtr> aCoinsideLines;
543   QList<FeaturePtr> aCoins;
544
545   bool isObject = aRefAttr->isObject();
546   ObjectPtr anObject = aRefAttr->object();
547   if (isObject && anObject) {
548     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
549     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
550     ObjectPtr aOtherObject = aOtherAttr->object();
551     // if the other attribute is not filled still, the result is true
552     if (!aOtherObject.get())
553       return true;
554     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
555
556     // check that both have coincidence
557     FeaturePtr aConstrFeature;
558     std::set<FeaturePtr> aCoinList;
559     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
560     std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
561     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
562       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
563       aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
564       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
565         AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
566         AttributePtr aAR = aRAttr->attr();
567         if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
568           aCoinList.insert(aConstrFeature);
569           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
570                                           SketchPlugin_ConstraintCoincidence::ENTITY_A());
571           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
572                                           SketchPlugin_ConstraintCoincidence::ENTITY_B());
573       }
574     }
575     // if there is no coincidence then it is not valid
576     if (aCoinList.size() > 0) {
577       QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
578       bool aValid = false;
579       for (; anIt != aLast && !aValid; anIt++) {
580         aValid = *anIt == aOtherFea;
581       }
582       if (aValid)
583         return true;
584     }
585   }
586   theError = "There is no a common coincident point.";
587   return false;
588 }
589