Salome HOME
Issue #3123: Provide chain of create Angle constraint operations
[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 (aList.size() == 2) {
286       // Check second selection
287       aPrs = aList.last();
288       const GeomShapePtr& aShape2 = aPrs->shape();
289       if (!aShape2.get() || aShape2->isNull() || aShape2->shapeType() != GeomAPI_Shape::EDGE)
290         return false;
291       GeomAPI_Edge aEdge2(aShape2);
292
293       if (aEdge1.isLine() && aEdge2.isLine())
294         return false;
295     }
296   }
297   return true;
298 }
299
300 bool PartSet_AngleSelection::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 aCount = shapesNbLines(theSelection);
307     return (aCount > 0) && (aCount < 3);
308   }
309 }
310
311 bool PartSet_EqualSelection::isValid(const ModuleBase_ISelection* theSelection,
312                                      ModuleBase_Operation* theOperation) const
313 {
314   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
315     return isEmptySelectionValid(theOperation);
316   } else {
317     QList<ModuleBase_ViewerPrsPtr> aList =
318       theSelection->getSelected(ModuleBase_ISelection::Viewer);
319     int aCount = 0;
320     int aType = 0;
321     foreach (ModuleBase_ViewerPrsPtr aPrs, aList) {
322       GeomShapePtr aShape = aPrs->shape();
323       if (aShape.get() && aShape->isEdge()) {
324         aCount++;
325         GeomAPI_Edge aEdge(aShape);
326         if (aEdge.isLine()) {
327           if (aCount == 1)
328             aType = 1;
329           else if (aType != 1)
330             return false;
331         } else if (aEdge.isCircle() || aEdge.isArc()) {
332           if (aCount == 1)
333             aType = 2;
334           else if (aType != 2)
335             return false;
336         } else if (aEdge.isEllipse()) {
337           if (aCount == 1)
338             aType = 3;
339           else if (aType != 3)
340             return false;
341         }
342       } else
343         return false;
344     }
345     return (aCount > 0) && (aCount < 3);
346   }
347 }
348
349 bool PartSet_CollinearSelection::isValid(const ModuleBase_ISelection* theSelection,
350                                          ModuleBase_Operation* theOperation) const
351 {
352   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
353     return isEmptySelectionValid(theOperation);
354   } else {
355     int aCount = shapesNbLines(theSelection);
356     return (aCount > 0) && (aCount < 3);
357   }
358 }
359
360 bool PartSet_MiddlePointSelection::isValid(const ModuleBase_ISelection* theSelection,
361                                            ModuleBase_Operation* theOperation) const
362 {
363   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0)
364     return isEmptySelectionValid(theOperation);
365   else
366     return shapesNbLines(theSelection) == 1 || shapesNbPoints(theSelection) == 1;
367 }
368
369 bool PartSet_MultyTranslationSelection::isValid(const ModuleBase_ISelection* theSelection,
370                                      ModuleBase_Operation* theOperation) const
371 {
372   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
373     return isEmptySelectionValid(theOperation);
374   } else {
375     int aCount = shapesNbLines(theSelection);
376     return aCount > 0;
377   }
378 }
379
380 bool PartSet_SplitSelection::isValid(const ModuleBase_ISelection* theSelection,
381                                      ModuleBase_Operation* theOperation) const
382 {
383   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
384     return isEmptySelectionValid(theOperation);
385   } else {
386     int aCount = shapesNbLines(theSelection);
387     return aCount > 0;
388   }
389 }
390
391 bool PartSet_ProjectionSelection::isValid(const ModuleBase_ISelection* theSelection,
392                                      ModuleBase_Operation* theOperation) const
393 {
394   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
395     return isEmptySelectionValid(theOperation);
396   } else {
397     int aCount = shapesNbLines(theSelection);
398     return aCount > 0;
399   }
400 }
401
402 bool PartSet_IntersectionSelection::isValid(const ModuleBase_ISelection* theSelection,
403                                      ModuleBase_Operation* theOperation) const
404 {
405   if (theSelection->getSelected(ModuleBase_ISelection::Viewer).size() == 0) {
406     return isEmptySelectionValid(theOperation);
407   } else {
408     int aCount = shapesNbLines(theSelection);
409     return aCount == 0;
410   }
411 }
412
413
414 std::string PartSet_DifferentObjectsValidator::errorMessage(
415                          const PartSet_DifferentObjectsValidator::ErrorType& theType,
416                          const std::string& thEqualObject, const std::string& theFirstAttribute,
417                          const std::string& theSecondAttribute) const
418 {
419   std::string anError;
420   switch (theType) {
421     case EqualObjects:
422       anError = "The feature uses one " + thEqualObject + " object in " +
423                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
424       break;
425     case EqualAttributes:
426       anError = "The feature uses reference to one " + thEqualObject + " attribute in " +
427                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
428       break;
429     case EqualShapes:
430       anError = "The feature uses one shape in " +
431                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
432       break;
433     case EmptyShapes:
434       anError = "The feature uses empty shapes in " +
435                 theFirstAttribute + " and " + theSecondAttribute + " attributes.";
436       break;
437       break;
438     default:
439       break;
440   }
441   return anError;
442 }
443
444 bool PartSet_DifferentObjectsValidator::isValid(const AttributePtr& theAttribute,
445                                                 const std::list<std::string>& theArguments,
446                                                 Events_InfoMessage& theError) const
447 {
448   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
449
450   // the type of validated attributes should be equal, attributes with
451   // different types are not validated
452   // Check RefAttr attributes
453   std::string anAttrType = theAttribute->attributeType();
454   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
455
456   if (anAttrType == ModelAPI_AttributeRefAttr::typeId()) {
457     AttributeRefAttrPtr anAttr =
458       std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
459     bool isObject = anAttr->isObject();
460     ObjectPtr anObject = anAttr->object();
461
462     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
463     if (anAttrs.size() > 0) {
464       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttrIter = anAttrs.begin();
465       for(; anAttrIter != anAttrs.end(); anAttrIter++) {
466       if ((*anAttrIter).get() && (*anAttrIter)->id() != theAttribute->id()) {
467           std::shared_ptr<ModelAPI_AttributeRefAttr> aRef =
468                               std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
469           if (aRef->isObject() != isObject)
470             continue;
471           if (isObject) {
472             if (aRef->object() == anObject) {
473               theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
474                                       theAttribute->id(), aRef->id());
475               return false;
476             }
477           }
478           else { // the attribute reference
479             AttributePtr anAttributeAttr = anAttr->attr();
480             if (aRef->attr() == anAttributeAttr) {
481               theError = errorMessage(EqualAttributes,
482                                       anAttributeAttr.get() ? anAttributeAttr->id() : "",
483                                       theAttribute->id(), aRef->id());
484               return false;
485             }
486           }
487         }
488       }
489     }
490   }
491   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
492     AttributeSelectionPtr anAttr =
493       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
494     ResultPtr aContext = anAttr->context();
495     FeaturePtr aContextFeature = anAttr->contextFeature();
496     GeomShapePtr aShape = anAttr->value();
497
498     // Check selection attributes
499     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
500     if (anAttrs.size() > 0) {
501       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
502       for(; anAttr != anAttrs.end(); anAttr++) {
503         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
504           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
505                               std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
506           // check the object is already presented
507           if (aRef->context() == aContext) {
508             bool aHasShape = aShape.get() != NULL;
509             if (!aHasShape || aRef->value()->isEqual(aShape)) {
510               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
511               return false;
512             }
513           }
514           // check the whole selected feature contains the result
515           if (aContextFeature.get()) {
516             if (aRef->contextFeature().get()) {
517               if (aContextFeature == aRef->contextFeature()) {
518                 theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
519                 return false;
520               }
521             } else if (aRef->context().get() &&
522                 aRef->context()->document()->feature(aRef->context()) == aContextFeature) {
523               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
524               return false;
525             }
526           } else if (aRef->contextFeature().get() && aContext.get()) {
527             if (aContext->document()->feature(aContext) == aRef->contextFeature()) {
528               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
529               return false;
530             }
531           }
532         }
533       }
534     }
535   }
536   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
537     AttributeReferencePtr anAttr =
538       std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
539     ObjectPtr anObject = anAttr->value();
540     // Check selection attributes
541     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
542     if (anAttrs.size() > 0) {
543       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
544       for(; anAttr != anAttrs.end(); anAttr++) {
545         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
546           std::shared_ptr<ModelAPI_AttributeReference> aRef =
547             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
548           // check the object is already presented
549           if (aRef->value() == anObject) {
550             theError = errorMessage(EqualObjects, anObject.get() ? anObject->data()->name() : "",
551                                     theAttribute->id(), aRef->id());
552             return false;
553           }
554         }
555         return true;
556       }
557     }
558   }
559   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
560     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList =
561             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
562     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
563     if(anAttrs.size() > 0) {
564       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
565       for(; anAttrItr != anAttrs.end(); anAttrItr++){
566         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
567           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList =
568             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
569           for(int i = 0; i < aCurSelList->size(); i++) {
570             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
571             ResultPtr aCurSelContext = aCurSel->context();
572             FeaturePtr aCurSelFeature = aCurSel->contextFeature();
573             ResultBodyPtr aCurSelCompSolidPtr = ModelAPI_Tools::bodyOwner(aCurSelContext);
574             std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
575             if(aCurSelCompSolidPtr.get()) {
576               aCurSelCompSolid = aCurSelCompSolidPtr->shape();
577             }
578             for(int j = 0; j < aRefSelList->size(); j++) {
579               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
580               ResultPtr aRefSelContext = aRefSel->context();
581               FeaturePtr aRefSelFeature = aRefSel->contextFeature();
582               ResultBodyPtr aRefSelCompSolidPtr =
583                 ModelAPI_Tools::bodyOwner(aRefSelContext);
584               std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
585               if (aRefSelCompSolidPtr.get()) {
586                 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
587               }
588               if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
589                 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
590                 theError = errorMessage(EqualShapes, "", theAttribute->id(),
591                   aRefSel->id());
592                 return false;
593               }
594               if (aCurSelContext == aRefSelContext) {
595                 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
596                   theError = errorMessage(EmptyShapes, "", theAttribute->id(), aRefSel->id());
597                   return false;
598                 }
599                 if (aCurSel->value()->isEqual(aRefSel->value())) {
600                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
601                   return false;
602                 }
603               }
604
605               // check the whole selected feature contains the result
606               if (aCurSelFeature.get()) {
607                 if (aRefSelFeature.get()) {
608                   if (aCurSelFeature == aRefSelFeature) {
609                     theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
610                     return false;
611                   }
612                 }
613                 else if (aRefSelContext.get() &&
614                   aRefSelContext->document()->feature(aRefSelContext) == aCurSelFeature) {
615                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
616                   return false;
617                 }
618               }
619               else if (aRefSelFeature.get() && aCurSelContext.get()) {
620                 if (aCurSelContext->document()->feature(aCurSelContext) == aRefSelFeature) {
621                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
622                   return false;
623                 }
624               }
625             }
626           }
627         }
628       }
629     }
630   }
631   else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
632     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
633       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
634     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
635     if (anAttrs.size() > 0) {
636       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
637       for (; anAttrItr != anAttrs.end(); anAttrItr++){
638         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
639           std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
640             std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
641           for (int i = 0; i < aCurSelList->size(); i++) {
642             ObjectPtr aCurSelObject = aCurSelList->object(i);
643             for (int j = 0; j < aRefSelList->size(); j++) {
644               if (aCurSelObject == aRefSelList->object(j)) {
645                 theError = errorMessage(EqualObjects,
646                               aCurSelObject.get() ? aCurSelObject->data()->name() : "",
647                               theAttribute->id(), aCurSelList->id());
648                 return false;
649               }
650             }
651           }
652         }
653       }
654     }
655   }
656   return true;
657 }
658
659 bool PartSet_DifferentPointsValidator::isValid(const AttributePtr& theAttribute,
660                                                const std::list<std::string>& theArguments,
661                                                Events_InfoMessage& theError) const
662 {
663   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
664
665   // the type of validated attributes should be equal, attributes with
666   // different types are not validated
667   // Check RefAttr attributes
668   std::string anAttrType = theAttribute->attributeType();
669   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
670   if (anAttrType != ModelAPI_AttributeRefAttr::typeId())
671     return true;
672
673   // obtain point of the given attribute
674   AttributePoint2DPtr anAttributePoint = getRefPointAttribute(theAttribute);
675   if (!anAttributePoint.get() || !anAttributePoint->isInitialized())
676     return true;
677
678   // obtain point of the parameter attribute
679   AttributePoint2DPtr anArgumentPoint = getRefPointAttribute
680                                               (aFeature->attribute(theArguments.front()));
681
682   if (!anArgumentPoint.get() || !anArgumentPoint->isInitialized())
683     return true;
684
685   return !anAttributePoint->pnt()->isEqual(anArgumentPoint->pnt());
686 }
687
688 AttributePoint2DPtr PartSet_DifferentPointsValidator::getRefPointAttribute
689                                                      (const AttributePtr& theAttribute) const
690 {
691   AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
692
693   AttributePoint2DPtr aPointAttribute;
694   if (anAttr->isObject()) {
695     ObjectPtr anObject  = anAttr->object();
696     if (anObject.get()) {
697       FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
698       if (aFeature->getKind() == SketchPlugin_Point::ID())
699         aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>
700                                           (aFeature->attribute(SketchPlugin_Point::COORD_ID()));
701     }
702   }
703   else {
704     aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
705   }
706   return aPointAttribute;
707 }
708
709 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute,
710                                      const std::list<std::string>& theArguments,
711                                      Events_InfoMessage& theError) const
712 {
713   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
714     theError = "The attribute with the %1 type is not processed";
715     theError.arg(theAttribute->attributeType());
716     return false;
717   }
718
719   // there is a check whether the feature contains a point and a linear edge or two point values
720   std::string aParamA = theArguments.front();
721   SessionPtr aMgr = ModelAPI_Session::get();
722   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
723
724   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
725   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
726   QList<FeaturePtr> aCoinsideLines;
727   QList<FeaturePtr> aCoins;
728
729   bool isObject = aRefAttr->isObject();
730   ObjectPtr anObject = aRefAttr->object();
731   if (isObject && anObject) {
732     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
733     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
734     ObjectPtr aOtherObject = aOtherAttr->object();
735     // if the other attribute is not filled still, the result is true
736     if (!aOtherObject.get())
737       return true;
738     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
739
740     // check that both have coincidence
741     FeaturePtr aConstrFeature;
742     std::set<FeaturePtr> aCoinList;
743     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
744     std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
745     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
746       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
747       aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
748       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
749         AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
750         AttributePtr aAR = aRAttr->attr();
751         if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
752           aCoinList.insert(aConstrFeature);
753           QList<bool> anIsAttributes;
754           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
755                                           SketchPlugin_ConstraintCoincidence::ENTITY_A(),
756                                           anIsAttributes);
757           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
758                                           SketchPlugin_ConstraintCoincidence::ENTITY_B(),
759                                           anIsAttributes);
760       }
761     }
762     // if there is no coincidence then it is not valid
763     if (aCoinList.size() > 0) {
764       QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
765       bool aValid = false;
766       for (; anIt != aLast && !aValid; anIt++) {
767         aValid = *anIt == aOtherFea;
768       }
769       if (aValid)
770         return true;
771     }
772   }
773   theError = "There is no a common coincident point.";
774   return false;
775 }