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