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