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