Salome HOME
e8e20884ec9899c3a3d7bcc6d17fdf6bd44e6852
[modules/shaper.git] / src / PartSet / PartSet_Validators.cpp
1 // Copyright (C) 2014-2023  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 <Locale_Convert.h>
57
58 #include <list>
59 #include <unordered_map>
60 #ifdef _DEBUG
61 #include <iostream>
62 #endif
63
64 int shapesNbPoints(const ModuleBase_ISelection* theSelection)
65 {
66   QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
67   ModuleBase_ISelection::filterSelectionOnEqualPoints(aList);
68
69   int aCount = 0;
70   foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
71     const GeomShapePtr& aShape = aPrs->shape();
72     if (aShape.get() && !aShape->isNull()) {
73       if (aShape->shapeType() == GeomAPI_Shape::VERTEX)
74         aCount++;
75     }
76   }
77   return aCount;
78 }
79
80 typedef std::unordered_map<int, int> ShapeQuantity;
81
82 int shapesNbEdges(const ModuleBase_ISelection* theSelection, ShapeQuantity& theEdges)
83 {
84   QList<ModuleBase_ViewerPrsPtr> aList = theSelection->getSelected(ModuleBase_ISelection::Viewer);
85   int aCount = 0;
86   foreach(ModuleBase_ViewerPrsPtr aPrs, aList) {
87     const GeomShapePtr& aShape = aPrs->shape();
88     if (aShape.get() && !aShape->isNull()) {
89       if (aShape->shapeType() == GeomAPI_Shape::EDGE) {
90         const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
91         TopoDS_Edge aEdge = TopoDS::Edge(aTDShape);
92         Standard_Real aStart, aEnd;
93         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aEdge, aStart, aEnd);
94         GeomAdaptor_Curve aAdaptor(aCurve);
95         theEdges[(int)aAdaptor.GetType()] += 1;
96         aCount++;
97       }
98     }
99   }
100   return aCount;
101 }
102
103
104 std::shared_ptr<GeomAPI_Pln> sketcherPlane(ModuleBase_Operation* theOperation)
105 {
106   std::shared_ptr<GeomAPI_Pln> aEmptyPln;
107   if (theOperation) {
108     ModuleBase_OperationFeature* aFeatureOp =
109       dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
110     if (aFeatureOp) {
111       CompositeFeaturePtr aFeature =
112         std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeatureOp->feature());
113       if (aFeature && (aFeature->getKind() == SketchPlugin_Sketch::ID()))
114         return PartSet_Tools::sketchPlane(aFeature);
115     }
116   }
117   return aEmptyPln;
118 }
119
120
121 bool isEmptySelectionValid(ModuleBase_Operation* theOperation)
122 {
123   ModuleBase_OperationFeature* aFeatureOp =
124     dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
125   // during the create operation empty selection is always valid
126   if (!aFeatureOp->isEditOperation()) {
127     return true;
128   }
129   else {
130     if (PartSet_SketcherMgr::isSketchOperation(aFeatureOp)) {
131       std::shared_ptr<GeomAPI_Pln> aPlane = sketcherPlane(theOperation);
132       if (aPlane.get())
133         return true;
134       else
135         return false;
136     }
137     else
138       // in edit operation an empty selection is always valid, performed for re-entrant operrations
139       return true;
140   }
141 }
142
143 bool PartSet_DistanceSelection::isValid(const ModuleBase_ISelection* theSelection,
144                                         ModuleBase_Operation* theOperation) const
145 {
146   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
147     return isEmptySelectionValid(theOperation);
148   } else {
149     int aNbPoints = shapesNbPoints(theSelection);
150     ShapeQuantity aShapes;
151     int aNbEdges = shapesNbEdges(theSelection, aShapes);
152     return (aNbPoints >= 0 && aNbPoints < 3) &&
153            (aShapes[GeomAbs_Line] == aNbEdges && aNbEdges >= 0 && aNbEdges < 2);
154   }
155 }
156
157 bool PartSet_LengthSelection::isValid(const ModuleBase_ISelection* theSelection,
158                                       ModuleBase_Operation* theOperation) const
159 {
160   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
161     return isEmptySelectionValid(theOperation);
162   } else {
163     int aNbPoints = shapesNbPoints(theSelection);
164     ShapeQuantity aShapes;
165     int aNbEdges = shapesNbEdges(theSelection, aShapes);
166     return aNbPoints == 0 && (aShapes[GeomAbs_Line] == aNbEdges && aNbEdges == 1);
167   }
168 }
169
170 bool PartSet_PerpendicularSelection::isValid(const ModuleBase_ISelection* theSelection,
171                                              ModuleBase_Operation* theOperation) const
172 {
173   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
174     return isEmptySelectionValid(theOperation);
175   } else {
176     int aNbPoints = shapesNbPoints(theSelection);
177     ShapeQuantity aShapes;
178     int aNbEdges = shapesNbEdges(theSelection, aShapes);
179     return aNbPoints == 0 && aShapes[GeomAbs_Line] == aNbEdges && aNbEdges > 0 && aNbEdges < 3;
180   }
181 }
182
183 bool PartSet_ParallelSelection::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     int aNbPoints = shapesNbPoints(theSelection);
190     ShapeQuantity aShapes;
191     int aNbEdges = shapesNbEdges(theSelection, aShapes);
192     return aNbPoints == 0 && aShapes[GeomAbs_Line] == aNbEdges && aNbEdges > 0 && aNbEdges < 3;
193   }
194 }
195
196 bool PartSet_RadiusSelection::isValid(const ModuleBase_ISelection* theSelection,
197                                       ModuleBase_Operation* theOperation) const
198 {
199   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
200     return isEmptySelectionValid(theOperation);
201   } else {
202     int aNbPoints = shapesNbPoints(theSelection);
203     ShapeQuantity aShapes;
204     int aNbEdges = shapesNbEdges(theSelection, aShapes);
205     return aNbPoints == 0 && (aShapes[GeomAbs_Circle] == aNbEdges && aNbEdges == 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 aNbPoints = shapesNbPoints(theSelection);
242     ShapeQuantity aShapes;
243     int aNbEdges = shapesNbEdges(theSelection, aShapes);
244     return (aNbPoints >= 0 && aNbPoints < 3) && (aNbEdges >= 0 && aNbEdges < 2);
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 aNbPoints = shapesNbPoints(theSelection);
255     ShapeQuantity aShapes;
256     int aNbEdges = shapesNbEdges(theSelection, aShapes);
257     return aNbPoints == 0 && (aShapes[GeomAbs_Line] == aNbEdges && aNbEdges == 1);
258   }
259 }
260
261 bool PartSet_FilletSelection::isValid(const ModuleBase_ISelection* theSelection,
262                                       ModuleBase_Operation* theOperation) const
263 {
264   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
265     return isEmptySelectionValid(theOperation);
266   } else {
267     int aCount = shapesNbPoints(theSelection);
268     ShapeQuantity aShapes;
269     int aNbEdges = shapesNbEdges(theSelection, aShapes);
270     return aCount > 1 && aNbEdges == 0;
271   }
272 }
273
274 bool PartSet_TangentSelection::isValid(const ModuleBase_ISelection* theSelection,
275                                        ModuleBase_Operation* theOperation) const
276 {
277   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
278     return isEmptySelectionValid(theOperation);
279   } else {
280     int aNbPoints = shapesNbPoints(theSelection);
281     ShapeQuantity aShapes;
282     int aNbEdges = shapesNbEdges(theSelection, aShapes);
283     return aNbPoints == 0 && (aNbEdges == 1 || (aNbEdges == 2 && aShapes[GeomAbs_Line] == 1));
284   }
285 }
286
287 bool PartSet_AngleSelection::isValid(const ModuleBase_ISelection* theSelection,
288                                      ModuleBase_Operation* theOperation) const
289 {
290   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
291     return isEmptySelectionValid(theOperation);
292   } else {
293     int aNbPoints = shapesNbPoints(theSelection);
294     ShapeQuantity aShapes;
295     int aNbEdges = shapesNbEdges(theSelection, aShapes);
296     return aNbPoints == 0 && aShapes[GeomAbs_Line] == aNbEdges && aNbEdges > 0 && aNbEdges < 3;
297   }
298 }
299
300 bool PartSet_EqualSelection::isValid(const ModuleBase_ISelection* theSelection,
301                                      ModuleBase_Operation* theOperation) const
302 {
303   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
304     return isEmptySelectionValid(theOperation);
305   } else {
306     int aNbPoints = shapesNbPoints(theSelection);
307     ShapeQuantity aShapes;
308     int aNbEdges = shapesNbEdges(theSelection, aShapes);
309     return aNbPoints == 0 && (aNbEdges > 0 && aNbEdges < 3) &&
310            (aShapes[GeomAbs_Line] == aNbEdges ||
311             aShapes[GeomAbs_Circle] == aNbEdges ||
312             aShapes[GeomAbs_Ellipse] == aNbEdges);
313   }
314 }
315
316 bool PartSet_CollinearSelection::isValid(const ModuleBase_ISelection* theSelection,
317                                          ModuleBase_Operation* theOperation) const
318 {
319   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
320     return isEmptySelectionValid(theOperation);
321   } else {
322     int aNbPoints = shapesNbPoints(theSelection);
323     ShapeQuantity aShapes;
324     int aNbEdges = shapesNbEdges(theSelection, aShapes);
325     return aNbPoints == 0 && aShapes[GeomAbs_Line] == aNbEdges && aNbEdges > 0 && aNbEdges < 3;
326   }
327 }
328
329 bool PartSet_MiddlePointSelection::isValid(const ModuleBase_ISelection* theSelection,
330                                            ModuleBase_Operation* theOperation) const
331 {
332   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0)
333     return isEmptySelectionValid(theOperation);
334   else {
335     int aNbPoints = shapesNbPoints(theSelection);
336     ShapeQuantity aShapes;
337     int aNbEdges = shapesNbEdges(theSelection, aShapes);
338     return (aNbPoints >= 0 && aNbPoints < 3) && (aNbEdges >= 0 && aNbEdges < 2);
339   }
340 }
341
342 bool PartSet_MultyTranslationSelection::isValid(const ModuleBase_ISelection* theSelection,
343                                      ModuleBase_Operation* theOperation) const
344 {
345   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
346     return isEmptySelectionValid(theOperation);
347   } else {
348     ShapeQuantity aShapes;
349     int aNbEdges = shapesNbEdges(theSelection, aShapes);
350     return aNbEdges > 0;
351   }
352 }
353
354 bool PartSet_SplitSelection::isValid(const ModuleBase_ISelection* theSelection,
355                                      ModuleBase_Operation* theOperation) const
356 {
357   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
358     return isEmptySelectionValid(theOperation);
359   } else {
360     ShapeQuantity aShapes;
361     int aNbEdges = shapesNbEdges(theSelection, aShapes);
362     return aNbEdges > 0;
363   }
364 }
365
366 bool PartSet_ProjectionSelection::isValid(const ModuleBase_ISelection* theSelection,
367                                      ModuleBase_Operation* theOperation) const
368 {
369   return theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0 &&
370          isEmptySelectionValid(theOperation);
371 }
372
373 bool PartSet_IntersectionSelection::isValid(const ModuleBase_ISelection* theSelection,
374                                      ModuleBase_Operation* theOperation) const
375 {
376   return theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0 &&
377          isEmptySelectionValid(theOperation);
378 }
379
380
381 std::string PartSet_DifferentObjectsValidator::errorMessage(
382                          const PartSet_DifferentObjectsValidator::ErrorType& theType,
383                          const std::string& thEqualObject, const std::string& theFirstAttribute,
384                          const std::string& theSecondAttribute) const
385 {
386   std::string anError;
387   switch (theType) {
388     case EqualObjects:
389       anError = "The feature uses one " + thEqualObject + " object in " +
390                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
391       break;
392     case EqualAttributes:
393       anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
394                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
395       break;
396     case EqualShapes:
397       anError = "The feature uses one shape in " +
398                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
399       break;
400     case EmptyShapes:
401       anError = "The feature uses empty shapes in " +
402                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
403       break;
404       break;
405     default:
406       break;
407   }
408   return anError;
409 }
410
411 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute,
412                                                 const std::list<std::string>& theArguments,
413                                                 Events_InfoMessage& theError) const
414 {
415   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
416
417   // the type of validated attributes should be equal, attributes with
418   // different types are not validated
419   // Check RefAttr attributes
420   std::string anAttrType = theAttribute->attributeType();
421   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
422
423   if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
424     AttributeRefAttrPtr anAttr =
425       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
426     bool isObject = anAttr->isObject();
427     ObjectPtr anObject = anAttr->object();
428
429     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
430     if (anAttrs.size() > 0) {
431       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttrs.begin();
432       for(; anAttrIter != anAttrs.end(); anAttrIter++) {
433       if ((*anAttrIter).get() && (*anAttrIter)->id() != theAttribute->id()) {
434           std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
435                               std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
436           if (aRef->isObject() != isObject)
437             continue;
438           if (isObject) {
439             if (aRef->object() == anObject) {
440               theError = errorMessage(EqualObjects,
441                 anObject.get() ? Locale::Convert::toString(anObject->data()->name()) : "",
442                 theAttribute->id(), aRef->id());
443               return false;
444             }
445           }
446           else { // the attribute reference
447             AttributePtr anAttributeAttr = anAttr->attr();
448             if (aRef->attr() == anAttributeAttr) {
449               theError = errorMessage(EqualAttributes,
450                                       anAttributeAttr.get() ? anAttributeAttr->id() : "",
451                                       theAttribute->id(), aRef->id());
452               return false;
453             }
454           }
455         }
456       }
457     }
458   }
459   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
460     AttributeSelectionPtr anAttrSel =
461       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
462     ResultPtr aContext = anAttrSel->context();
463     FeaturePtr aContextFeature = anAttrSel->contextFeature();
464     GeomShapePtr aShape = anAttrSel->value();
465
466     // Check selection attributes
467     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
468     if (anAttrs.size() > 0) {
469       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
470       for(; anAttr != anAttrs.end(); anAttr++) {
471         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
472           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
473                               std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
474           // check the object is already presented
475           if (aRef->context() == aContext) {
476             bool aHasShape = aShape.get() != NULL;
477             if (!aHasShape || aRef->value()->isEqual(aShape)) {
478               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
479               return false;
480             }
481           }
482           // check the whole selected feature contains the result
483           if (aContextFeature.get()) {
484             if (aRef->contextFeature().get()) {
485               if (aContextFeature == aRef->contextFeature()) {
486                 theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
487                 return false;
488               }
489             } else if (aRef->context().get() &&
490                 aRef->context()->document()->feature(aRef->context()) == aContextFeature) {
491               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
492               return false;
493             }
494           } else if (aRef->contextFeature().get() && aContext.get()) {
495             if (aContext->document()->feature(aContext) == aRef->contextFeature()) {
496               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
497               return false;
498             }
499           }
500         }
501       }
502     }
503   }
504   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
505     AttributeReferencePtr anAttrRef =
506       std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
507     ObjectPtr anObject = anAttrRef->value();
508     // Check selection attributes
509     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
510     if (anAttrs.size() > 0) {
511       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
512       for(; anAttr != anAttrs.end(); anAttr++) {
513         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
514           std::shared_ptr<ModelAPI_AttributeReference> aRef =
515             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
516           // check the object is already presented
517           if (aRef->value() == anObject) {
518             theError = errorMessage(EqualObjects,
519               anObject.get() ? Locale::Convert::toString(anObject->data()->name()) : "",
520               theAttribute->id(), aRef->id());
521             return false;
522           }
523         }
524       }
525       return true;
526     }
527   }
528   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
529     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList =
530             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
531     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
532     if(anAttrs.size() > 0) {
533       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
534       for(; anAttrItr != anAttrs.end(); anAttrItr++){
535         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
536           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList =
537             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
538           for(int i = 0; i < aCurSelList->size(); i++) {
539             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
540             ResultPtr aCurSelContext = aCurSel->context();
541             FeaturePtr aCurSelFeature = aCurSel->contextFeature();
542             ResultBodyPtr aCurSelCompSolidPtr = ModelAPI_Tools::bodyOwner(aCurSelContext);
543             std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
544             if(aCurSelCompSolidPtr.get()) {
545               aCurSelCompSolid = aCurSelCompSolidPtr->shape();
546             }
547             for(int j = 0; j < aRefSelList->size(); j++) {
548               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
549               ResultPtr aRefSelContext = aRefSel->context();
550               FeaturePtr aRefSelFeature = aRefSel->contextFeature();
551               ResultBodyPtr aRefSelCompSolidPtr =
552                 ModelAPI_Tools::bodyOwner(aRefSelContext);
553               std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
554               if (aRefSelCompSolidPtr.get()) {
555                 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
556               }
557               if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
558                 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
559                 theError = errorMessage(EqualShapes, "", theAttribute->id(),
560                   aRefSel->id());
561                 return false;
562               }
563               if (aCurSelContext == aRefSelContext) {
564                 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
565                   theError = errorMessage(EmptyShapes, "", theAttribute->id(), aRefSel->id());
566                   return false;
567                 }
568                 if (aCurSel->value()->isEqual(aRefSel->value())) {
569                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
570                   return false;
571                 }
572               }
573
574               // check the whole selected feature contains the result
575               if (aCurSelFeature.get()) {
576                 if (aRefSelFeature.get()) {
577                   if (aCurSelFeature == aRefSelFeature) {
578                     theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
579                     return false;
580                   }
581                 }
582                 else if (aRefSelContext.get() &&
583                   aRefSelContext->document()->feature(aRefSelContext) == aCurSelFeature) {
584                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
585                   return false;
586                 }
587               }
588               else if (aRefSelFeature.get() && aCurSelContext.get()) {
589                 if (aCurSelContext->document()->feature(aCurSelContext) == aRefSelFeature) {
590                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
591                   return false;
592                 }
593               }
594             }
595           }
596         }
597       }
598     }
599   }
600   else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
601     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
602       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
603     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
604     if (anAttrs.size() > 0) {
605       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
606       for (; anAttrItr != anAttrs.end(); anAttrItr++){
607         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
608           std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
609             std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
610           for (int i = 0; i < aCurSelList->size(); i++) {
611             ObjectPtr aCurSelObject = aCurSelList->object(i);
612             for (int j = 0; j < aRefSelList->size(); j++) {
613               if (aCurSelObject == aRefSelList->object(j)) {
614                 theError = errorMessage(EqualObjects,
615                   aCurSelObject.get()?
616                   Locale::Convert::toString(aCurSelObject->data()->name()) : "",
617                   theAttribute->id(), aCurSelList->id());
618                 return false;
619               }
620             }
621           }
622         }
623       }
624     }
625   }
626   return true;
627 }
628
629 bool PartSet_DifferentPointsValidator::isValid(const AttributePtr& theAttribute,
630                                                const std::list<std::string>& theArguments,
631                                                Events_InfoMessage& theError) const
632 {
633   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
634
635   // the type of validated attributes should be equal, attributes with
636   // different types are not validated
637   // Check RefAttr attributes
638   std::string anAttrType = theAttribute->attributeType();
639   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
640   if (anAttrType != ModelAPI_AttributeRefAttr::typeId())
641     return true;
642
643   // obtain point of the given attribute
644   AttributePoint2DPtr anAttributePoint = getRefPointAttribute(theAttribute);
645   if (!anAttributePoint.get() || !anAttributePoint->isInitialized())
646     return true;
647
648   // obtain point of the parameter attribute
649   AttributePoint2DPtr anArgumentPoint = getRefPointAttribute
650                                               (aFeature->attribute(theArguments.front()));
651
652   if (!anArgumentPoint.get() || !anArgumentPoint->isInitialized())
653     return true;
654
655   return !anAttributePoint->pnt()->isEqual(anArgumentPoint->pnt());
656 }
657
658 AttributePoint2DPtr PartSet_DifferentPointsValidator::getRefPointAttribute
659                                                      (const AttributePtr& theAttribute) const
660 {
661   AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
662
663   AttributePoint2DPtr aPointAttribute;
664   if (anAttr->isObject()) {
665     ObjectPtr anObject  = anAttr->object();
666     if (anObject.get()) {
667       FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
668       if (aFeature->getKind() == SketchPlugin_Point::ID())
669         aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>
670                                           (aFeature->attribute(SketchPlugin_Point::COORD_ID()));
671     }
672   }
673   else {
674     aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
675   }
676   return aPointAttribute;
677 }
678
679 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute,
680                                      const std::list<std::string>& theArguments,
681                                      Events_InfoMessage& theError) const
682 {
683   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
684     theError = "The attribute with the %1 type is not processed";
685     theError.arg(theAttribute->attributeType());
686     return false;
687   }
688
689   // there is a check whether the feature contains a point and a linear edge or two point values
690   std::string aParamA = theArguments.front();
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 }