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