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