Salome HOME
Merge remote-tracking branch 'origin/BR_REENTRANCE_OPERATION' into origin_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 #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 = shapesNbLines(theSelection);
217     return (aCount > 0) && (aCount < 3);
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
318 std::string PartSet_DifferentObjectsValidator::errorMessage(
319                          const PartSet_DifferentObjectsValidator::ErrorType& theType,
320                          const std::string& thEqualObject, const std::string& theFirstAttribute,
321                          const std::string& theSecondAttribute) const
322 {
323   std::string anError;
324   switch (theType) {
325     case EqualObjects:
326       anError = "The feature uses one " + thEqualObject + " object in " +
327                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
328       break;
329     case EqualAttributes:
330       anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
331                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
332       break;
333     case EqualShapes:
334       anError = "The feature uses one shape in " +
335                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
336       break;
337     case EmptyShapes:
338       anError = "The feature uses empty shapes in " +
339                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
340       break;
341       break;
342     default:
343       break;
344   }
345   return anError;
346 }
347
348 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute, 
349                                                 const std::list<std::string>& theArguments,
350                                                 std::string& theError) const
351 {
352   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
353
354   // the type of validated attributes should be equal, attributes with different types are not validated
355   // Check RefAttr attributes
356   std::string anAttrType = theAttribute->attributeType();
357   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
358
359   if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
360     AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
361     bool isObject = anAttr->isObject();
362     ObjectPtr anObject = anAttr->object();
363     AttributePtr anAttributeAttr = anAttr->attr();
364
365     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
366     if (anAttrs.size() > 0) {
367       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
368       for(; anAttr != anAttrs.end(); anAttr++) {
369       if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
370           std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
371                                       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttr);
372           if (aRef->isObject() != isObject)
373             continue;
374           if (isObject) {
375             if (aRef->object() == anObject) {
376               theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
377                                       theAttribute->id(), aRef->id());
378               return false;
379             }
380           }
381           else { // the attribute reference
382             if (aRef->attr() == anAttributeAttr) {
383               theError = errorMessage(EqualAttributes,
384                                       anAttributeAttr.get() ? anAttributeAttr->id() : "",
385                                       theAttribute->id(), aRef->id());
386               return false;
387             }
388           }
389         }
390       }
391     }
392   }
393   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
394     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
395     ResultPtr aContext = anAttr->context();
396     GeomShapePtr aShape = anAttr->value();
397
398     // Check selection attributes
399     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
400     if (anAttrs.size() > 0) {
401       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
402       for(; anAttr != anAttrs.end(); anAttr++) {
403         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
404           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
405                                         std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
406           // check the object is already presented
407           if (aRef->context() == aContext) {
408             bool aHasShape = aShape.get() != NULL;
409             if (!aHasShape || aRef->value()->isEqual(aShape)) {
410               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
411               return false;
412             }
413           }
414         }
415       }
416     }
417   }
418   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
419     AttributeReferencePtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
420     ObjectPtr anObject = anAttr->value();
421     // Check selection attributes
422     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
423     if (anAttrs.size() > 0) {
424       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
425       for(; anAttr != anAttrs.end(); anAttr++) {
426         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
427           std::shared_ptr<ModelAPI_AttributeReference> aRef =
428             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
429           // check the object is already presented
430           if (aRef->value() == anObject) {
431             theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
432                                     theAttribute->id(), aRef->id());
433             return false;
434           }
435         }
436         return true;
437       }
438     }
439   }
440   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
441     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList = 
442             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
443     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
444     if(anAttrs.size() > 0) {
445       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
446       for(; anAttrItr != anAttrs.end(); anAttrItr++){
447         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
448           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList = 
449             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
450           for(int i = 0; i < aCurSelList->size(); i++) {
451             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
452             ResultPtr aCurSelContext = aCurSel->context();
453             ResultCompSolidPtr aCurSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aCurSelContext);
454             std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
455             if(aCurSelCompSolidPtr.get()) {
456               aCurSelCompSolid = aCurSelCompSolidPtr->shape();
457             }
458             for(int j = 0; j < aRefSelList->size(); j++) {
459               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
460               ResultPtr aRefSelContext = aRefSel->context();
461               ResultCompSolidPtr aRefSelCompSolidPtr = ModelAPI_Tools::compSolidOwner(aRefSelContext);
462               std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
463               if(aRefSelCompSolidPtr.get()) {
464                 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
465               }
466               if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
467                 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
468                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
469                                           aRefSel->id());
470                   return false;
471               }
472               if(aCurSelContext == aRefSelContext) {
473                 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
474                   theError = errorMessage(EmptyShapes, "", theAttribute->id(),
475                                           aRefSel->id());
476                   return false;
477                 }
478                 if (aCurSel->value()->isEqual(aRefSel->value())) {
479                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
480                                           aRefSel->id());
481                   return false;
482                 }
483               }
484             }
485           }
486         }
487       }
488     }
489   }
490   else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
491     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
492       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
493     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
494     if (anAttrs.size() > 0) {
495       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
496       for (; anAttrItr != anAttrs.end(); anAttrItr++){
497         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
498           std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
499             std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
500           for (int i = 0; i < aCurSelList->size(); i++) {
501             ObjectPtr aCurSelObject = aCurSelList->object(i);
502             for (int j = 0; j < aRefSelList->size(); j++) {
503               if (aCurSelObject == aRefSelList->object(j)) {
504                 theError = errorMessage(EqualObjects,
505                               aCurSelObject.get() ? aCurSelObject->data()->name() : "",
506                               theAttribute->id(), aCurSelList->id());
507                 return false;
508               }
509             }
510           }
511         }
512       }
513     }
514   }
515   return true;
516 }
517
518 bool PartSet_SketchEntityValidator::isValid(const AttributePtr& theAttribute,
519                                             const std::list<std::string>& theArguments,
520                                             std::string& theError) const
521 {
522   bool isSketchEntities = true;
523   std::set<std::string> anEntityKinds;
524   std::string anEntityKindsStr;
525   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
526   for (; anIt != aLast; anIt++) {
527     anEntityKinds.insert(*anIt);
528     if (!anEntityKindsStr.empty())
529       anEntityKindsStr += ", ";
530     anEntityKindsStr += *anIt;
531   }
532
533   std::string anAttributeType = theAttribute->attributeType();
534   if (anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
535     AttributeSelectionListPtr aSelectionListAttr = 
536                       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
537     // all context objects should be sketch entities
538     for (int i = 0, aSize = aSelectionListAttr->size(); i < aSize && isSketchEntities; i++) {
539       AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(i);
540       ObjectPtr anObject = aSelectAttr->context();
541       // a context of the selection attribute is a feature result. It can be a case when the result
542       // of the feature is null, e.g. the feature is modified and has not been executed yet.
543       // The validator returns an invalid result here. The case is an extrusion built on a sketch
544       // feature. A new sketch element creation leads to an empty result.
545       if (!anObject.get())
546         isSketchEntities = false;
547       else {
548         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
549         isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
550       }
551     }
552   }
553   if (anAttributeType == ModelAPI_AttributeRefList::typeId()) {
554     AttributeRefListPtr aRefListAttr =
555       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
556     // all context objects should be sketch entities
557     for (int i = 0, aSize = aRefListAttr->size(); i < aSize && isSketchEntities; i++) {
558       ObjectPtr anObject = aRefListAttr->object(i);
559       // a context of the selection attribute is a feature result. It can be a case when the result
560       // of the feature is null, e.g. the feature is modified and has not been executed yet.
561       // The validator returns an invalid result here. The case is an extrusion built on a sketch
562       // feature. A new sketch element creation leads to an empty result.
563       if (!anObject.get())
564         isSketchEntities = false;
565       else {
566         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
567         isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
568       }
569     }
570   }
571   if (anAttributeType == ModelAPI_AttributeRefAttr::typeId()) {
572     std::shared_ptr<ModelAPI_AttributeRefAttr> aRef = 
573                      std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
574     isSketchEntities = false;
575     if (aRef->isObject()) {
576       ObjectPtr anObject = aRef->object();
577       if (anObject.get() != NULL) {
578         FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
579         if (aFeature.get() != NULL)
580           isSketchEntities = anEntityKinds.find(aFeature->getKind()) != anEntityKinds.end();
581       }
582     }
583   }
584   if (!isSketchEntities) {
585     theError = "It refers to feature, which kind is not in the list: " + anEntityKindsStr;
586   }
587
588   return isSketchEntities;
589 }
590
591 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute, 
592                                      const std::list<std::string>& theArguments,
593                                      std::string& theError) const
594 {
595   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
596     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
597     return false;
598   }
599
600   // there is a check whether the feature contains a point and a linear edge or two point values
601   std::string aParamA = theArguments.front();
602   SessionPtr aMgr = ModelAPI_Session::get();
603   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
604
605   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
606   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
607   QList<FeaturePtr> aCoinsideLines;
608
609   bool isObject = aRefAttr->isObject();
610   ObjectPtr anObject = aRefAttr->object();
611   if (isObject && anObject) {
612     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
613     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
614     ObjectPtr aOtherObject = aOtherAttr->object();
615     // if the other attribute is not filled still, the result is true
616     if (!aOtherObject.get())
617       return true;
618     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
619
620     // check that both have coincidence
621     FeaturePtr aConstrFeature;
622     std::set<FeaturePtr> aCoinList;
623     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
624     std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
625     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
626       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
627       aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
628       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
629         AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
630         AttributePtr aAR = aRAttr->attr();
631         if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
632           aCoinList.insert(aConstrFeature);
633           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
634                                           SketchPlugin_ConstraintCoincidence::ENTITY_A());
635           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines,
636                                           SketchPlugin_ConstraintCoincidence::ENTITY_B());
637       }
638     }
639     // if there is no coincidence then it is not valid
640     if (aCoinList.size() > 0) {
641       QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
642       bool aValid = false;
643       for (; anIt != aLast && !aValid; anIt++) {
644         aValid = *anIt == aOtherFea;
645       }
646       if (aValid)
647         return true;
648     }
649   }
650   theError = "There is no a common coincident point.";
651   return false;
652 }
653