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