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