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