Salome HOME
Initial implementation of support of any level of hierarchy in Result Bodies.
[modules/shaper.git] / src / PartSet / PartSet_Validators.cpp
1 // Copyright (C) 2014-2017  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "PartSet_Validators.h"
22
23 #include "PartSet_Tools.h"
24 #include "PartSet_SketcherMgr.h"
25
26 #include <TopoDS.hxx>
27 #include <TopoDS_Edge.hxx>
28 #include <BRep_Tool.hxx>
29 #include <GeomAdaptor_Curve.hxx>
30 #include <GeomAbs_CurveType.hxx>
31 #include <ModuleBase_ISelection.h>
32 #include <ModuleBase_WidgetShapeSelector.h>
33 #include <ModuleBase_OperationFeature.h>
34 #include <ModuleBase_ViewerPrs.h>
35
36 #include <GeomDataAPI_Point2D.h>
37 #include <GeomAPI_Pnt2d.h>
38
39 #include <Events_InfoMessage.h>
40
41 #include <ModelAPI_AttributeRefAttr.h>
42 #include <ModelAPI_AttributeSelection.h>
43 #include <ModelAPI_AttributeReference.h>
44 #include <ModelAPI_AttributeSelectionList.h>
45 #include <ModelAPI_AttributeRefList.h>
46 #include <ModelAPI_Object.h>
47 #include <ModelAPI_ResultBody.h>
48 #include <ModelAPI_Session.h>
49 #include <ModelAPI_Tools.h>
50
51 #include <SketchPlugin_Sketch.h>
52 #include <SketchPlugin_ConstraintCoincidence.h>
53 #include <SketchPlugin_Arc.h>
54 #include <SketchPlugin_Point.h>
55 #include <GeomAPI_Edge.h>
56
57 #include <list>
58 #ifdef _DEBUG
59 #include <iostream>
60 #endif
61
62 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
63 {
64   QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
65   ModuleBase_ISelection::filterSelectionOnEqualPoints(aList);
66
67   int aCount = 0;
68   foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
69     const GeomShapePtr& aShape = aPrs->shape();
70     if (aShape.get() && !aShape->isNull()) {
71       if (aShape->shapeType() == GeomAPI_Shape::VERTEX)
72         aCount++;
73     }
74   }
75   return aCount;
76 }
77
78 int shapesNbLines(const ModuleBase_ISelection* theSelection)
79 {
80   QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
81   int aCount = 0;
82   foreach(ModuleBase_ViewerPrsPtr aPrs, aList) {
83     const GeomShapePtr& aShape = aPrs->shape();
84     if (aShape.get() && !aShape->isNull()) {
85       if (aShape->shapeType() == GeomAPI_Shape::EDGE) {
86         const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
87         TopoDS_Edge aEdge = TopoDS::Edge(aTDShape);
88         Standard_Real aStart, aEnd;
89         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
90         GeomAdaptor_Curve aAdaptor(aCurve);
91         if (aAdaptor.GetType() == GeomAbs_Line)
92           aCount++;
93       }
94     }
95   }
96   return aCount;
97 }
98
99
100 std::shared_ptr<GeomAPI_Pln> sketcherPlane(ModuleBase_Operation* theOperation)
101 {
102   std::shared_ptr<GeomAPI_Pln> aEmptyPln;
103   if (theOperation) {
104     ModuleBase_OperationFeature* aFeatureOp =
105       dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
106     if (aFeatureOp) {
107       CompositeFeaturePtr aFeature =
108         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeatureOp->feature());
109       if (aFeature && (aFeature->getKind() == SketchPlugin_Sketch::ID()))
110         return PartSet_Tools::sketchPlane(aFeature);
111     }
112   }
113   return aEmptyPln;
114 }
115
116
117 bool isEmptySelectionValid(ModuleBase_Operation* theOperation)
118 {
119   ModuleBase_OperationFeature* aFeatureOp =
120     dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
121   // during the create operation empty selection is always valid
122   if (!aFeatureOp->isEditOperation()) {
123     return true;
124   }
125   else {
126     if (PartSet_SketcherMgr::isSketchOperation(aFeatureOp)) {
127       std::shared_ptr<GeomAPI_Pln> aPlane = sketcherPlane(theOperation);
128       if (aPlane.get())
129         return true;
130       else
131         return false;
132     }
133     else
134       // in edit operation an empty selection is always valid, performed for re-entrant operrations
135       return true;
136   }
137 }
138
139 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection,
140                                         ModuleBase_Operation* theOperation) const
141 {
142   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
143     return isEmptySelectionValid(theOperation);
144   } else {
145     int aCount = shapesNbPoints(theSelection) + shapesNbLines(theSelection);
146     return (aCount > 0) && (aCount < 3);
147   }
148 }
149
150 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection,
151                                       ModuleBase_Operation* theOperation) const
152 {
153   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
154     return isEmptySelectionValid(theOperation);
155   } else {
156     int aCount = shapesNbLines(theSelection);
157     return (aCount == 1);
158   }
159 }
160
161 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection,
162                                              ModuleBase_Operation* theOperation) const
163 {
164   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
165     return isEmptySelectionValid(theOperation);
166   } else {
167     int aCount = shapesNbLines(theSelection);
168     return (aCount > 0) && (aCount < 3);
169   }
170 }
171
172 bool PartSet_ParallelSelection::isValid(const ModuleBase_ISelection* theSelection,
173                                         ModuleBase_Operation* theOperation) const
174 {
175   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
176     return isEmptySelectionValid(theOperation);
177   } else {
178     int aCount = shapesNbLines(theSelection);
179     return (aCount > 0) && (aCount < 3);
180   }
181 }
182
183 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection,
184                                       ModuleBase_Operation* theOperation) const
185 {
186   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
187     return isEmptySelectionValid(theOperation);
188   } else {
189     QList<ModuleBase_ViewerPrsPtr> aList =
190       theSelection->getSelected(ModuleBase_ISelection::Viewer);
191     int aCount = 0;
192     foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
193       const GeomShapePtr& aShape = aPrs->shape();
194       if (aShape.get() && !aShape->isNull()) {
195         if (aShape->shapeType() == GeomAPI_Shape::EDGE) {
196           const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
197           TopoDS_Edge aEdge = TopoDS::Edge(aTDShape);
198           Standard_Real aStart, aEnd;
199           Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
200           GeomAdaptor_Curve aAdaptor(aCurve);
201           if (aAdaptor.GetType() == GeomAbs_Circle)
202             aCount++;
203         }
204       }
205     }
206     return (aCount == 1);
207   }
208 }
209
210 bool PartSet_RigidSelection::isValid(const ModuleBase_ISelection* theSelection,
211                                      ModuleBase_Operation* theOperation) const
212 {
213   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
214     return isEmptySelectionValid(theOperation);
215   } else {
216     QList<ModuleBase_ViewerPrsPtr> aList =
217       theSelection->getSelected(ModuleBase_ISelection::Viewer);
218     int aCount = 0;
219     foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
220       ObjectPtr aObj = aPrs->object();
221       if (aObj.get()) {
222         FeaturePtr aFeature = ModelAPI_Feature::feature(aObj);
223         if (aFeature.get()) {
224           CompositeFeaturePtr aComp = ModelAPI_Tools::compositeOwner(aFeature);
225           if (aComp.get() && (aComp->getKind() == SketchPlugin_Sketch::ID()))
226             aCount++;
227         }
228       }
229     }
230     return (aCount == 1);
231   }
232 }
233
234
235 bool PartSet_CoincidentSelection::isValid(const ModuleBase_ISelection* theSelection,
236                                           ModuleBase_Operation* theOperation) const
237 {
238   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
239     return isEmptySelectionValid(theOperation);
240   } else {
241     // Coincident can be applied to points and to lines
242     int aCount = shapesNbPoints(theSelection);
243     aCount += shapesNbLines(theSelection);
244     return (aCount > 0) && (aCount < 3);
245   }
246 }
247
248 bool PartSet_HVDirSelection::isValid(const ModuleBase_ISelection* theSelection,
249                                      ModuleBase_Operation* theOperation) const
250 {
251   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
252     return isEmptySelectionValid(theOperation);
253   } else {
254     int aCount = shapesNbLines(theSelection);
255     return (aCount == 1);
256   }
257 }
258
259 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection,
260                                       ModuleBase_Operation* theOperation) const
261 {
262   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
263     return isEmptySelectionValid(theOperation);
264   } else {
265     int aCount = shapesNbPoints(theSelection);
266     return aCount > 1;
267   }
268 }
269
270 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection,
271                                        ModuleBase_Operation* theOperation) const
272 {
273   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
274     return isEmptySelectionValid(theOperation);
275   } else {
276     QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
277     if ((aList.size() == 0) || (aList.size() > 2))
278       return false;
279
280     ModuleBase_ViewerPrsPtr aPrs = aList.first();
281     const GeomShapePtr& aShape = aPrs->shape();
282     if (!aShape.get() || aShape->isNull() || aShape->shapeType() != GeomAPI_Shape::EDGE)
283       return false;
284     GeomAPI_Edge aEdge1(aShape);
285
286     if (aEdge1.isLine() || aEdge1.isArc()) {
287       if (aList.size() == 2) {
288         // Check second selection
289         aPrs = aList.last();
290         const GeomShapePtr& aShape2 = aPrs->shape();
291         if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
292           return false;
293         GeomAPI_Edge aEdge2(aShape2);
294
295         if (aEdge1.isLine() && aEdge2.isArc())
296           return true;
297         else if (aEdge1.isArc() && aEdge2.isLine())
298           return true;
299         else
300           return false;
301       } else
302         return true;
303     }
304     return false;
305   }
306 }
307
308 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection,
309                                      ModuleBase_Operation* theOperation) const
310 {
311   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
312     return isEmptySelectionValid(theOperation);
313   } else {
314     int aCount = shapesNbLines(theSelection);
315     return (aCount > 0) && (aCount < 3);
316   }
317 }
318
319 bool PartSet_EqualSelection::isValid(const ModuleBase_ISelection* theSelection,
320                                      ModuleBase_Operation* theOperation) const
321 {
322   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
323     return isEmptySelectionValid(theOperation);
324   } else {
325     QList<ModuleBase_ViewerPrsPtr> aList =
326       theSelection->getSelected(ModuleBase_ISelection::Viewer);
327     int aCount = 0;
328     int aType = 0;
329     foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
330       GeomShapePtr aShape = aPrs->shape();
331       if (aShape.get() && aShape->isEdge()) {
332         aCount++;
333         GeomAPI_Edge aEdge(aShape);
334         if (aEdge.isLine()) {
335           if (aCount == 1)
336             aType = 1;
337           else if (aType != 1)
338             return false;
339         } else if (aEdge.isCircle()) {
340           if (aCount == 1)
341             aType = 2;
342           else if (aType != 2)
343             return false;
344         } else if (aEdge.isArc()) {
345           if (aCount == 1)
346             aType = 3;
347           else if (aType != 3)
348             return false;
349         }
350       } else
351         return false;
352     }
353     return (aCount > 0) && (aCount < 3);
354   }
355 }
356
357 bool PartSet_CollinearSelection::isValid(const ModuleBase_ISelection* theSelection,
358                                          ModuleBase_Operation* theOperation) const
359 {
360   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
361     return isEmptySelectionValid(theOperation);
362   } else {
363     int aCount = shapesNbLines(theSelection);
364     return (aCount > 0) && (aCount < 3);
365   }
366 }
367
368 bool PartSet_MiddlePointSelection::isValid(const ModuleBase_ISelection* theSelection,
369                                            ModuleBase_Operation* theOperation) const
370 {
371   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0)
372     return isEmptySelectionValid(theOperation);
373   else
374     return shapesNbLines(theSelection) == 1 || shapesNbPoints(theSelection) == 1;
375 }
376
377 bool PartSet_MultyTranslationSelection::isValid(const ModuleBase_ISelection* theSelection,
378                                      ModuleBase_Operation* theOperation) const
379 {
380   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
381     return isEmptySelectionValid(theOperation);
382   } else {
383     int aCount = shapesNbLines(theSelection);
384     return aCount > 0;
385   }
386 }
387
388 bool PartSet_SplitSelection::isValid(const ModuleBase_ISelection* theSelection,
389                                      ModuleBase_Operation* theOperation) const
390 {
391   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
392     return isEmptySelectionValid(theOperation);
393   } else {
394     int aCount = shapesNbLines(theSelection);
395     return aCount > 0;
396   }
397 }
398
399 bool PartSet_ProjectionSelection::isValid(const ModuleBase_ISelection* theSelection,
400                                      ModuleBase_Operation* theOperation) const
401 {
402   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
403     return isEmptySelectionValid(theOperation);
404   } else {
405     int aCount = shapesNbLines(theSelection);
406     return aCount > 0;
407   }
408 }
409
410 bool PartSet_IntersectionSelection::isValid(const ModuleBase_ISelection* theSelection,
411                                      ModuleBase_Operation* theOperation) const
412 {
413   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
414     return isEmptySelectionValid(theOperation);
415   } else {
416     int aCount = shapesNbLines(theSelection);
417     return aCount == 0;
418   }
419 }
420
421
422 std::string PartSet_DifferentObjectsValidator::errorMessage(
423                          const PartSet_DifferentObjectsValidator::ErrorType& theType,
424                          const std::string& thEqualObject, const std::string& theFirstAttribute,
425                          const std::string& theSecondAttribute) const
426 {
427   std::string anError;
428   switch (theType) {
429     case EqualObjects:
430       anError = "The feature uses one " + thEqualObject + " object in " +
431                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
432       break;
433     case EqualAttributes:
434       anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
435                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
436       break;
437     case EqualShapes:
438       anError = "The feature uses one shape in " +
439                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
440       break;
441     case EmptyShapes:
442       anError = "The feature uses empty shapes in " +
443                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
444       break;
445       break;
446     default:
447       break;
448   }
449   return anError;
450 }
451
452 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute,
453                                                 const std::list<std::string>& theArguments,
454                                                 Events_InfoMessage& theError) const
455 {
456   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
457
458   // the type of validated attributes should be equal, attributes with
459   // different types are not validated
460   // Check RefAttr attributes
461   std::string anAttrType = theAttribute->attributeType();
462   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
463
464   if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
465     AttributeRefAttrPtr anAttr =
466       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
467     bool isObject = anAttr->isObject();
468     ObjectPtr anObject = anAttr->object();
469
470     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
471     if (anAttrs.size() > 0) {
472       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttrs.begin();
473       for(; anAttrIter != anAttrs.end(); anAttrIter++) {
474       if ((*anAttrIter).get() && (*anAttrIter)->id() != theAttribute->id()) {
475           std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
476                               std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
477           if (aRef->isObject() != isObject)
478             continue;
479           if (isObject) {
480             if (aRef->object() == anObject) {
481               theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
482                                       theAttribute->id(), aRef->id());
483               return false;
484             }
485           }
486           else { // the attribute reference
487             AttributePtr anAttributeAttr = anAttr->attr();
488             if (aRef->attr() == anAttributeAttr) {
489               theError = errorMessage(EqualAttributes,
490                                       anAttributeAttr.get() ? anAttributeAttr->id() : "",
491                                       theAttribute->id(), aRef->id());
492               return false;
493             }
494           }
495         }
496       }
497     }
498   }
499   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
500     AttributeSelectionPtr anAttr =
501       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
502     ResultPtr aContext = anAttr->context();
503     GeomShapePtr aShape = anAttr->value();
504
505     // Check selection attributes
506     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
507     if (anAttrs.size() > 0) {
508       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
509       for(; anAttr != anAttrs.end(); anAttr++) {
510         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
511           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
512                               std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
513           // check the object is already presented
514           if (aRef->context() == aContext) {
515             bool aHasShape = aShape.get() != NULL;
516             if (!aHasShape || aRef->value()->isEqual(aShape)) {
517               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
518               return false;
519             }
520           }
521         }
522       }
523     }
524   }
525   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
526     AttributeReferencePtr anAttr =
527       std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
528     ObjectPtr anObject = anAttr->value();
529     // Check selection attributes
530     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
531     if (anAttrs.size() > 0) {
532       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
533       for(; anAttr != anAttrs.end(); anAttr++) {
534         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
535           std::shared_ptr<ModelAPI_AttributeReference> aRef =
536             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
537           // check the object is already presented
538           if (aRef->value() == anObject) {
539             theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
540                                     theAttribute->id(), aRef->id());
541             return false;
542           }
543         }
544         return true;
545       }
546     }
547   }
548   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
549     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList =
550             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
551     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
552     if(anAttrs.size() > 0) {
553       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
554       for(; anAttrItr != anAttrs.end(); anAttrItr++){
555         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
556           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList =
557             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
558           for(int i = 0; i < aCurSelList->size(); i++) {
559             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
560             ResultPtr aCurSelContext = aCurSel->context();
561             ResultBodyPtr aCurSelCompSolidPtr = ModelAPI_Tools::bodyOwner(aCurSelContext);
562             std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
563             if(aCurSelCompSolidPtr.get()) {
564               aCurSelCompSolid = aCurSelCompSolidPtr->shape();
565             }
566             for(int j = 0; j < aRefSelList->size(); j++) {
567               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
568               ResultPtr aRefSelContext = aRefSel->context();
569               ResultBodyPtr aRefSelCompSolidPtr =
570                 ModelAPI_Tools::bodyOwner(aRefSelContext);
571               std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
572               if(aRefSelCompSolidPtr.get()) {
573                 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
574               }
575               if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
576                 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
577                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
578                                           aRefSel->id());
579                   return false;
580               }
581               if(aCurSelContext == aRefSelContext) {
582                 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
583                   theError = errorMessage(EmptyShapes, "", theAttribute->id(),
584                                           aRefSel->id());
585                   return false;
586                 }
587                 if (aCurSel->value()->isEqual(aRefSel->value())) {
588                   theError = errorMessage(EqualShapes, "", theAttribute->id(),
589                                           aRefSel->id());
590                   return false;
591                 }
592               }
593             }
594           }
595         }
596       }
597     }
598   }
599   else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
600     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
601       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
602     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
603     if (anAttrs.size() > 0) {
604       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
605       for (; anAttrItr != anAttrs.end(); anAttrItr++){
606         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
607           std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
608             std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
609           for (int i = 0; i < aCurSelList->size(); i++) {
610             ObjectPtr aCurSelObject = aCurSelList->object(i);
611             for (int j = 0; j < aRefSelList->size(); j++) {
612               if (aCurSelObject == aRefSelList->object(j)) {
613                 theError = errorMessage(EqualObjects,
614                               aCurSelObject.get() ? aCurSelObject->data()->name() : "",
615                               theAttribute->id(), aCurSelList->id());
616                 return false;
617               }
618             }
619           }
620         }
621       }
622     }
623   }
624   return true;
625 }
626
627 bool PartSet_DifferentPointsValidator::isValid(const AttributePtr& theAttribute,
628                                                const std::list<std::string>& theArguments,
629                                                Events_InfoMessage& theError) const
630 {
631   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
632
633   // the type of validated attributes should be equal, attributes with
634   // different types are not validated
635   // Check RefAttr attributes
636   std::string anAttrType = theAttribute->attributeType();
637   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
638   if (anAttrType != ModelAPI_AttributeRefAttr::typeId())
639     return true;
640
641   // obtain point of the given attribute
642   AttributePoint2DPtr anAttributePoint = getRefPointAttribute(theAttribute);
643   if (!anAttributePoint.get() || !anAttributePoint->isInitialized())
644     return true;
645
646   // obtain point of the parameter attribute
647   AttributePoint2DPtr anArgumentPoint = getRefPointAttribute
648                                               (aFeature->attribute(theArguments.front()));
649
650   if (!anArgumentPoint.get() || !anArgumentPoint->isInitialized())
651     return true;
652
653   return !anAttributePoint->pnt()->isEqual(anArgumentPoint->pnt());
654 }
655
656 AttributePoint2DPtr PartSet_DifferentPointsValidator::getRefPointAttribute
657                                                      (const AttributePtr& theAttribute) const
658 {
659   AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
660
661   AttributePoint2DPtr aPointAttribute;
662   if (anAttr->isObject()) {
663     ObjectPtr anObject  = anAttr->object();
664     if (anObject.get()) {
665       FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
666       if (aFeature->getKind() == SketchPlugin_Point::ID())
667         aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>
668                                           (aFeature->attribute(SketchPlugin_Point::COORD_ID()));
669     }
670   }
671   else {
672     aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
673   }
674   return aPointAttribute;
675 }
676
677 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute,
678                                      const std::list<std::string>& theArguments,
679                                      Events_InfoMessage& theError) const
680 {
681   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
682     theError = "The attribute with the %1 type is not processed";
683     theError.arg(theAttribute->attributeType());
684     return false;
685   }
686
687   // there is a check whether the feature contains a point and a linear edge or two point values
688   std::string aParamA = theArguments.front();
689   SessionPtr aMgr = ModelAPI_Session::get();
690   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
691
692   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
693   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
694   QList<FeaturePtr> aCoinsideLines;
695   QList<FeaturePtr> aCoins;
696
697   bool isObject = aRefAttr->isObject();
698   ObjectPtr anObject = aRefAttr->object();
699   if (isObject && anObject) {
700     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
701     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
702     ObjectPtr aOtherObject = aOtherAttr->object();
703     // if the other attribute is not filled still, the result is true
704     if (!aOtherObject.get())
705       return true;
706     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
707
708     // check that both have coincidence
709     FeaturePtr aConstrFeature;
710     std::set<FeaturePtr> aCoinList;
711     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
712     std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
713     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
714       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
715       aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
716       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
717         AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
718         AttributePtr aAR = aRAttr->attr();
719         if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
720           aCoinList.insert(aConstrFeature);
721           QList<bool> anIsAttributes;
722           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
723                                           SketchPlugin_ConstraintCoincidence::ENTITY_A(),
724                                           anIsAttributes);
725           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
726                                           SketchPlugin_ConstraintCoincidence::ENTITY_B(),
727                                           anIsAttributes);
728       }
729     }
730     // if there is no coincidence then it is not valid
731     if (aCoinList.size() > 0) {
732       QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
733       bool aValid = false;
734       for (; anIt != aLast && !aValid; anIt++) {
735         aValid = *anIt == aOtherFea;
736       }
737       if (aValid)
738         return true;
739     }
740   }
741   theError = "There is no a common coincident point.";
742   return false;
743 }