]> SALOME platform Git repositories - modules/shaper.git/blob - src/PartSet/PartSet_Validators.cpp
Salome HOME
76c8e61566cd287be78bc273012f5560eaae313a
[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,
439                 anObject.get() ? ModelAPI_Tools::toString(anObject->data()->name()) : "",
440                 theAttribute->id(), aRef->id());
441               return false;
442             }
443           }
444           else { // the attribute reference
445             AttributePtr anAttributeAttr = anAttr->attr();
446             if (aRef->attr() == anAttributeAttr) {
447               theError = errorMessage(EqualAttributes,
448                                       anAttributeAttr.get() ? anAttributeAttr->id() : "",
449                                       theAttribute->id(), aRef->id());
450               return false;
451             }
452           }
453         }
454       }
455     }
456   }
457   else if (anAttrType == ModelAPI_AttributeSelection::typeId()) {
458     AttributeSelectionPtr anAttr =
459       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
460     ResultPtr aContext = anAttr->context();
461     FeaturePtr aContextFeature = anAttr->contextFeature();
462     GeomShapePtr aShape = anAttr->value();
463
464     // Check selection attributes
465     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelection::typeId());
466     if (anAttrs.size() > 0) {
467       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
468       for(; anAttr != anAttrs.end(); anAttr++) {
469         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
470           std::shared_ptr<ModelAPI_AttributeSelection> aRef =
471                               std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(*anAttr);
472           // check the object is already presented
473           if (aRef->context() == aContext) {
474             bool aHasShape = aShape.get() != NULL;
475             if (!aHasShape || aRef->value()->isEqual(aShape)) {
476               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
477               return false;
478             }
479           }
480           // check the whole selected feature contains the result
481           if (aContextFeature.get()) {
482             if (aRef->contextFeature().get()) {
483               if (aContextFeature == aRef->contextFeature()) {
484                 theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
485                 return false;
486               }
487             } else if (aRef->context().get() &&
488                 aRef->context()->document()->feature(aRef->context()) == aContextFeature) {
489               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
490               return false;
491             }
492           } else if (aRef->contextFeature().get() && aContext.get()) {
493             if (aContext->document()->feature(aContext) == aRef->contextFeature()) {
494               theError = errorMessage(EqualShapes, "", theAttribute->id(), aRef->id());
495               return false;
496             }
497           }
498         }
499       }
500     }
501   }
502   else if (anAttrType == ModelAPI_AttributeReference::typeId()) {
503     AttributeReferencePtr anAttr =
504       std::dynamic_pointer_cast<ModelAPI_AttributeReference>(theAttribute);
505     ObjectPtr anObject = anAttr->value();
506     // Check selection attributes
507     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeReference::typeId());
508     if (anAttrs.size() > 0) {
509       std::list<std::shared_ptr<ModelAPI_Attribute> >::iterator anAttr = anAttrs.begin();
510       for(; anAttr != anAttrs.end(); anAttr++) {
511         if ((*anAttr).get() && (*anAttr)->id() != theAttribute->id()) {
512           std::shared_ptr<ModelAPI_AttributeReference> aRef =
513             std::dynamic_pointer_cast<ModelAPI_AttributeReference>(*anAttr);
514           // check the object is already presented
515           if (aRef->value() == anObject) {
516             theError = errorMessage(EqualObjects,
517               anObject.get() ? ModelAPI_Tools::toString(anObject->data()->name()) : "",
518               theAttribute->id(), aRef->id());
519             return false;
520           }
521         }
522         return true;
523       }
524     }
525   }
526   else if(anAttrType == ModelAPI_AttributeSelectionList::typeId()) {
527     std::shared_ptr<ModelAPI_AttributeSelectionList> aCurSelList =
528             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
529     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
530     if(anAttrs.size() > 0) {
531       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
532       for(; anAttrItr != anAttrs.end(); anAttrItr++){
533         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
534           std::shared_ptr<ModelAPI_AttributeSelectionList> aRefSelList =
535             std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(*anAttrItr);
536           for(int i = 0; i < aCurSelList->size(); i++) {
537             std::shared_ptr<ModelAPI_AttributeSelection> aCurSel = aCurSelList->value(i);
538             ResultPtr aCurSelContext = aCurSel->context();
539             FeaturePtr aCurSelFeature = aCurSel->contextFeature();
540             ResultBodyPtr aCurSelCompSolidPtr = ModelAPI_Tools::bodyOwner(aCurSelContext);
541             std::shared_ptr<GeomAPI_Shape> aCurSelCompSolid;
542             if(aCurSelCompSolidPtr.get()) {
543               aCurSelCompSolid = aCurSelCompSolidPtr->shape();
544             }
545             for(int j = 0; j < aRefSelList->size(); j++) {
546               std::shared_ptr<ModelAPI_AttributeSelection> aRefSel = aRefSelList->value(j);
547               ResultPtr aRefSelContext = aRefSel->context();
548               FeaturePtr aRefSelFeature = aRefSel->contextFeature();
549               ResultBodyPtr aRefSelCompSolidPtr =
550                 ModelAPI_Tools::bodyOwner(aRefSelContext);
551               std::shared_ptr<GeomAPI_Shape> aRefSelCompSolid;
552               if (aRefSelCompSolidPtr.get()) {
553                 aRefSelCompSolid = aRefSelCompSolidPtr->shape();
554               }
555               if ((aCurSelCompSolid.get() && aCurSelCompSolid->isEqual(aRefSel->value()))
556                 || (aRefSelCompSolid.get() && aRefSelCompSolid->isEqual(aCurSel->value()))) {
557                 theError = errorMessage(EqualShapes, "", theAttribute->id(),
558                   aRefSel->id());
559                 return false;
560               }
561               if (aCurSelContext == aRefSelContext) {
562                 if (aCurSel->value().get() == NULL || aRefSel->value().get() == NULL) {
563                   theError = errorMessage(EmptyShapes, "", theAttribute->id(), aRefSel->id());
564                   return false;
565                 }
566                 if (aCurSel->value()->isEqual(aRefSel->value())) {
567                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
568                   return false;
569                 }
570               }
571
572               // check the whole selected feature contains the result
573               if (aCurSelFeature.get()) {
574                 if (aRefSelFeature.get()) {
575                   if (aCurSelFeature == aRefSelFeature) {
576                     theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
577                     return false;
578                   }
579                 }
580                 else if (aRefSelContext.get() &&
581                   aRefSelContext->document()->feature(aRefSelContext) == aCurSelFeature) {
582                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
583                   return false;
584                 }
585               }
586               else if (aRefSelFeature.get() && aCurSelContext.get()) {
587                 if (aCurSelContext->document()->feature(aCurSelContext) == aRefSelFeature) {
588                   theError = errorMessage(EqualShapes, "", theAttribute->id(), aRefSel->id());
589                   return false;
590                 }
591               }
592             }
593           }
594         }
595       }
596     }
597   }
598   else if (anAttrType == ModelAPI_AttributeRefList::typeId()) {
599     std::shared_ptr<ModelAPI_AttributeRefList> aCurSelList =
600       std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(theAttribute);
601     anAttrs = aFeature->data()->attributes(ModelAPI_AttributeRefList::typeId());
602     if (anAttrs.size() > 0) {
603       std::list<std::shared_ptr<ModelAPI_Attribute>>::iterator anAttrItr = anAttrs.begin();
604       for (; anAttrItr != anAttrs.end(); anAttrItr++){
605         if ((*anAttrItr).get() && (*anAttrItr)->id() != theAttribute->id()){
606           std::shared_ptr<ModelAPI_AttributeRefList> aRefSelList =
607             std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrItr);
608           for (int i = 0; i < aCurSelList->size(); i++) {
609             ObjectPtr aCurSelObject = aCurSelList->object(i);
610             for (int j = 0; j < aRefSelList->size(); j++) {
611               if (aCurSelObject == aRefSelList->object(j)) {
612                 theError = errorMessage(EqualObjects,
613                   aCurSelObject.get()?
614                   ModelAPI_Tools::toString(aCurSelObject->data()->name()) : "",
615                   theAttribute->id(), aCurSelList->id());
616                 return false;
617               }
618             }
619           }
620         }
621       }
622     }
623   }
624   return true;
625 }
626
627 bool PartSet_DifferentPointsValidator::isValid(const AttributePtr& theAttribute,
628                                                const std::list<std::string>& theArguments,
629                                                Events_InfoMessage& theError) const
630 {
631   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
632
633   // the type of validated attributes should be equal, attributes with
634   // different types are not validated
635   // Check RefAttr attributes
636   std::string anAttrType = theAttribute->attributeType();
637   std::list<std::shared_ptr<ModelAPI_Attribute> > anAttrs;
638   if (anAttrType != ModelAPI_AttributeRefAttr::typeId())
639     return true;
640
641   // obtain point of the given attribute
642   AttributePoint2DPtr anAttributePoint = getRefPointAttribute(theAttribute);
643   if (!anAttributePoint.get() || !anAttributePoint->isInitialized())
644     return true;
645
646   // obtain point of the parameter attribute
647   AttributePoint2DPtr anArgumentPoint = getRefPointAttribute
648                                               (aFeature->attribute(theArguments.front()));
649
650   if (!anArgumentPoint.get() || !anArgumentPoint->isInitialized())
651     return true;
652
653   return !anAttributePoint->pnt()->isEqual(anArgumentPoint->pnt());
654 }
655
656 AttributePoint2DPtr PartSet_DifferentPointsValidator::getRefPointAttribute
657                                                      (const AttributePtr& theAttribute) const
658 {
659   AttributeRefAttrPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
660
661   AttributePoint2DPtr aPointAttribute;
662   if (anAttr->isObject()) {
663     ObjectPtr anObject  = anAttr->object();
664     if (anObject.get()) {
665       FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
666       if (aFeature->getKind() == SketchPlugin_Point::ID())
667         aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>
668                                           (aFeature->attribute(SketchPlugin_Point::COORD_ID()));
669     }
670   }
671   else {
672     aPointAttribute = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
673   }
674   return aPointAttribute;
675 }
676
677 bool PartSet_CoincidentAttr::isValid(const AttributePtr& theAttribute,
678                                      const std::list<std::string>& theArguments,
679                                      Events_InfoMessage& theError) const
680 {
681   if (theAttribute->attributeType() != ModelAPI_AttributeRefAttr::typeId()) {
682     theError = "The attribute with the %1 type is not processed";
683     theError.arg(theAttribute->attributeType());
684     return false;
685   }
686
687   // there is a check whether the feature contains a point and a linear edge or two point values
688   std::string aParamA = theArguments.front();
689   SessionPtr aMgr = ModelAPI_Session::get();
690   ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
691
692   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
693   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
694   QList<FeaturePtr> aCoinsideLines;
695   QList<FeaturePtr> aCoins;
696
697   bool isObject = aRefAttr->isObject();
698   ObjectPtr anObject = aRefAttr->object();
699   if (isObject && anObject) {
700     FeaturePtr aRefFea = ModelAPI_Feature::feature(anObject);
701     AttributeRefAttrPtr aOtherAttr = aFeature->data()->refattr(aParamA);
702     ObjectPtr aOtherObject = aOtherAttr->object();
703     // if the other attribute is not filled still, the result is true
704     if (!aOtherObject.get())
705       return true;
706     FeaturePtr aOtherFea = ModelAPI_Feature::feature(aOtherObject);
707
708     // check that both have coincidence
709     FeaturePtr aConstrFeature;
710     std::set<FeaturePtr> aCoinList;
711     const std::set<std::shared_ptr<ModelAPI_Attribute>>& aRefsList = aRefFea->data()->refsToMe();
712     std::set<std::shared_ptr<ModelAPI_Attribute>>::const_iterator aIt;
713     for (aIt = aRefsList.cbegin(); aIt != aRefsList.cend(); ++aIt) {
714       std::shared_ptr<ModelAPI_Attribute> aAttr = (*aIt);
715       aConstrFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aAttr->owner());
716       if (aConstrFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
717         AttributeRefAttrPtr aRAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aAttr);
718         AttributePtr aAR = aRAttr->attr();
719         if (aAR->id() != SketchPlugin_Arc::CENTER_ID()) // ignore constraint to center of arc
720           aCoinList.insert(aConstrFeature);
721           QList<bool> anIsAttributes;
722           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
723                                           SketchPlugin_ConstraintCoincidence::ENTITY_A(),
724                                           anIsAttributes);
725           PartSet_Tools::findCoincidences(aConstrFeature, aCoinsideLines, aCoins,
726                                           SketchPlugin_ConstraintCoincidence::ENTITY_B(),
727                                           anIsAttributes);
728       }
729     }
730     // if there is no coincidence then it is not valid
731     if (aCoinList.size() > 0) {
732       QList<FeaturePtr>::const_iterator anIt = aCoinsideLines.begin(), aLast = aCoinsideLines.end();
733       bool aValid = false;
734       for (; anIt != aLast && !aValid; anIt++) {
735         aValid = *anIt == aOtherFea;
736       }
737       if (aValid)
738         return true;
739     }
740   }
741   theError = "There is no a common coincident point.";
742   return false;
743 }