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