]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
Salome HOME
e28008720d77cdd77dfd50a16a017ec601163cda
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
1 // Copyright (C) 2014-2017  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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "FeaturesPlugin_Validators.h"
22
23 #include "FeaturesPlugin_Boolean.h"
24 #include "FeaturesPlugin_BooleanFuse.h"
25 #include "FeaturesPlugin_BooleanCommon.h"
26 #include "FeaturesPlugin_BooleanSmash.h"
27 #include "FeaturesPlugin_Union.h"
28
29 #include <Events_InfoMessage.h>
30
31 #include <ModelAPI_Attribute.h>
32 #include <ModelAPI_AttributeInteger.h>
33 #include <ModelAPI_AttributeSelectionList.h>
34 #include <ModelAPI_AttributeString.h>
35 #include <ModelAPI_AttributeReference.h>
36 #include <ModelAPI_AttributeRefList.h>
37 #include <ModelAPI_Feature.h>
38 #include <ModelAPI_ResultBody.h>
39 #include <ModelAPI_ResultConstruction.h>
40 #include <ModelAPI_Tools.h>
41
42 #include <GeomValidators_BodyShapes.h>
43 #include <GeomValidators_Face.h>
44 #include <GeomValidators_FeatureKind.h>
45 #include <GeomValidators_ShapeType.h>
46
47 #include <GeomAPI_DataMapOfShapeShape.h>
48 #include <GeomAPI_Lin.h>
49 #include <GeomAPI_PlanarEdges.h>
50 #include <GeomAPI_Pln.h>
51 #include <GeomAPI_ShapeExplorer.h>
52 #include <GeomAPI_ShapeIterator.h>
53
54 #include <GeomAlgoAPI_CompoundBuilder.h>
55 #include <GeomAlgoAPI_ShapeBuilder.h>
56 #include <GeomAlgoAPI_ShapeTools.h>
57 #include <GeomAlgoAPI_WireBuilder.h>
58
59 #define _USE_MATH_DEFINES
60 #include <math.h>
61
62 //==================================================================================================
63 bool FeaturesPlugin_ValidatorPipePath::isValid(const AttributePtr& theAttribute,
64                                                const std::list<std::string>& theArguments,
65                                                Events_InfoMessage& theError) const
66 {
67   AttributeSelectionPtr aPathAttrSelection =
68     std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
69   if(!aPathAttrSelection.get()) {
70     theError = "Error: This validator can only work with path selector in \"Pipe\" feature.";
71     return false;
72   }
73
74   GeomShapePtr aPathShape = aPathAttrSelection->value();
75   ResultPtr aContext = aPathAttrSelection->context();
76   if(!aContext.get()) {
77     theError = "Error: Empty context.";
78     return false;
79   }
80   GeomShapePtr aContextShape = aContext->shape();
81   if(aPathShape.get() && aPathShape->shapeType() == GeomAPI_Shape::WIRE &&
82       !aPathShape->isEqual(aContextShape)) {
83     theError = "Error: Local selection of wires not allowed.";
84     return false;
85   }
86
87   return true;
88 }
89
90 //==================================================================================================
91 bool FeaturesPlugin_ValidatorPipeLocations::isValid(
92   const std::shared_ptr<ModelAPI_Feature>& theFeature,
93   const std::list<std::string>& theArguments,
94   Events_InfoMessage& theError) const
95 {
96   static const std::string aCreationMethodID = "creation_method";
97   static const std::string aBaseObjectsID = "base_objects";
98   static const std::string aLocationsID = "locations_objects";
99
100   if(theFeature->getKind() != "Pipe") {
101     theError = "Error: Feature \"%1\" does not supported by this validator.";
102     theError.arg(theFeature->getKind());
103     return false;
104   }
105
106   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
107   if(!aCreationMethodAttr.get()) {
108     theError = "Error: Could not get \"%1\" attribute.";
109     theError.arg(aCreationMethodID);
110     return false;
111   }
112
113   if(aCreationMethodAttr->value() != "locations") {
114     return true;
115   }
116
117   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
118   if(!aBaseObjectsSelectionList.get()) {
119     theError = "Error: Could not get \"%1\" attribute.";
120     theError.arg(aBaseObjectsID);
121     return false;
122   }
123
124   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
125   if(!aLocationsSelectionList.get()) {
126     theError = "Error: Could not get \"%1\" attribute.";
127     theError.arg(aBaseObjectsID);
128     return false;
129   }
130
131   if(aLocationsSelectionList->size() > 0 &&
132      aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
133     theError = "Error: Number of locations should be the same as base objects.";
134     return false;
135   }
136
137   return true;
138 }
139
140 //==================================================================================================
141 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
142                                                         const std::list<std::string>& theArguments,
143                                                         Events_InfoMessage& theError) const
144 {
145   if(theArguments.empty()) {
146     theError = "Error: Validator parameters is empty.";
147     return false;
148   }
149
150   // Checking attribute.
151   if(!isValidAttribute(theAttribute, theArguments, theError)) {
152     if(theError.empty()) {
153       theError = "Error: Attribute contains unacceptable shape.";
154     }
155     return false;
156   }
157
158   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
159   std::string anAttributeType = theAttribute->attributeType();
160   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
161     AttributeSelectionListPtr aListAttr =
162       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
163     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
164       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
165       ResultPtr aContext = aSelectionAttr->context();
166       if(!aContext.get() && !aSelectionAttr->contextFeature().get()) {
167         theError = "Error: Empty context.";
168         return false;
169       }
170
171       ResultConstructionPtr aResultConstruction =
172         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
173       if(!aResultConstruction.get()) {
174         // It is not a result construction.
175         // If shape is compound check that it contains only faces and edges.
176         GeomShapePtr aShape = aSelectionAttr->value();
177         if(!aShape.get()) {
178           if (aContext.get()) {
179             aShape = aContext->shape();
180           } else {
181             theError = "Error: Empty context.";
182             return false;
183           }
184         }
185
186         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
187           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
188             GeomShapePtr aSubShape = anIt.current();
189             if(aSubShape->shapeType() != GeomAPI_Shape::EDGE
190                 && aSubShape->shapeType() != GeomAPI_Shape::FACE) {
191               theError = "Error: Compound should contain only faces and edges.";
192               return false;
193             }
194           }
195         }
196
197         continue;
198       }
199
200       GeomShapePtr aShape = aSelectionAttr->value();
201       GeomShapePtr aContextShape = aResultConstruction->shape();
202       if(!aShape.get()) {
203         // Whole sketch selected.
204         continue;
205       } else {
206         // Object from sketch selected.
207         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
208           GeomShapePtr aWire = anExp.current();
209           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
210             theError = "Error: Wire with wrong orientation selected.";
211             return false;
212           }
213
214           if(aSelectedWiresFromObjects.isBound(aWire)) {
215             theError =
216               "Error: Objects with such wire already selected. Don't allow to select this object.";
217             return false;
218           }
219
220           aSelectedWiresFromObjects.bind(aWire, aWire);
221         }
222       }
223     }
224   }
225
226   return true;
227 }
228
229 //==================================================================================================
230 bool FeaturesPlugin_ValidatorBaseForGenerationSketchOrSketchObjects::isValid(
231   const std::shared_ptr<ModelAPI_Feature>& theFeature,
232   const std::list<std::string>& theArguments,
233   Events_InfoMessage& theError) const
234 {
235   const std::string aBaseObjectsID = theArguments.front();
236
237   AttributeSelectionListPtr aListAttr = theFeature->selectionList(aBaseObjectsID);
238   if(!aListAttr.get()) {
239     theError = "Error: Could not get \"%1\" attribute.";
240     theError.arg(aBaseObjectsID);
241     return false;
242   }
243
244   std::set<ResultConstructionPtr> aSelectedSketches;
245   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
246
247   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
248     AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
249     ResultPtr aContext = aSelectionAttr->context();
250     if(!aContext.get()) {
251       FeaturePtr aFeature = aSelectionAttr->contextFeature();
252       if (!aFeature.get() || aFeature->results().empty()) {
253         theError = "Error: Empty context.";
254         return false;
255       } else {
256         aContext = aFeature->firstResult();
257       }
258     }
259
260     ResultConstructionPtr aResultConstruction =
261       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
262     if(!aResultConstruction.get()) {
263       // It is not a result construction.
264       continue;
265     }
266
267     GeomShapePtr aShape = aSelectionAttr->value();
268     GeomShapePtr aContextShape = aResultConstruction->shape();
269     if(!aShape.get()) {
270       // Whole sketch selected.
271       aSelectedSketches.insert(aResultConstruction);
272     } else {
273       // Object from sketch selected.
274       aSelectedSketchesFromObjects.insert(aResultConstruction);
275     }
276   }
277
278
279   for(std::set<ResultConstructionPtr>::const_iterator anIt = aSelectedSketches.cbegin();
280       anIt != aSelectedSketches.cend();
281       ++anIt) {
282     ResultConstructionPtr aResultConstruction = *anIt;
283     if(aSelectedSketchesFromObjects.find(aResultConstruction) !=
284         aSelectedSketchesFromObjects.cend()) {
285       theError = "Sketch and objects from it can not be selected at the same time.";
286       return false;
287     }
288   }
289
290   return true;
291 }
292
293 //==================================================================================================
294 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
295                                                         const std::list<std::string>& theArguments,
296                                                         Events_InfoMessage& theError) const
297 {
298   if(!theAttribute.get()) {
299     theError = "Error: Empty attribute.";
300     return false;
301   }
302
303   std::string anAttributeType = theAttribute->attributeType();
304   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
305     AttributeSelectionListPtr aListAttr =
306       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
307     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
308       // If at least one attribute is invalid, the result is false.
309       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
310         return false;
311       }
312     }
313   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
314     // Getting context.
315     AttributeSelectionPtr anAttr =
316       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
317     ResultPtr aContext = anAttr->context();
318     if(!aContext.get() && !anAttr->contextFeature().get()) {
319       theError = "Error: Attribute have empty context.";
320       return false;
321     }
322
323     GeomShapePtr aShape = anAttr->value();
324     GeomShapePtr aContextShape;
325     if(!aShape.get() && aContext.get()) {
326       aContextShape = aContext->shape();
327       aShape = aContextShape;
328     }
329     if(!aShape.get()) {
330       theError = "Error: Empty shape selected";
331       return false;
332     }
333
334     ResultConstructionPtr aConstruction;
335     if (!aContext.get() && anAttr->contextFeature()->results().size() == 1) {
336       aContext = anAttr->contextFeature()->firstResult();
337     }
338     if (aContext.get())
339       aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
340     if(aConstruction.get()) {
341       // Construciotn selected. Check that is is not infinite.
342       if(aConstruction->isInfinite()) {
343         theError = "Error: Infinite constructions is not allowed as base.";
344         return false;
345       }
346
347       GeomShapePtr aContextShape = aContext->shape();
348       if(aShape->isEqual(aContextShape)) {
349         // Whole construction selected. Check that it have faces.
350         if(aConstruction->facesNum() > 0) {
351           return true;
352         }
353       } else {
354         // Shape on construction selected. Check that it is a face or wire.
355         if(aShape->shapeType() == GeomAPI_Shape::WIRE ||
356            aShape->shapeType() == GeomAPI_Shape::FACE) {
357           return true;
358         }
359       }
360
361       return false;
362     }
363
364     if(aContextShape.get() && !aShape->isEqual(aContextShape)) {
365       // Local selection on body does not allowed.
366       theError =
367         "Error: Selected shape is in the local selection. Only global selection is allowed.";
368       return false;
369     }
370
371     // Check that object is a shape with allowed type.
372     GeomValidators_ShapeType aShapeTypeValidator;
373     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
374       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
375                  "wires on sketch, whole sketch(if it has at least one face), "
376                  "and whole objects with shape types: %1";
377       std::string anArgumentString;
378       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
379         if (!anArgumentString.empty())
380           anArgumentString += ", ";
381         anArgumentString += *anIt;
382       }
383       theError.arg(anArgumentString);
384       return false;
385     }
386
387   } else {
388     theError = "Error: Attribute \"%1\" does not supported by this validator.";
389     theError.arg(anAttributeType);
390     return false;
391   }
392
393   return true;
394 }
395
396 //==================================================================================================
397 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
398                                                         const std::list<std::string>& theArguments,
399                                                         Events_InfoMessage& theError) const
400 {
401   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
402     theError = "Error: The attribute with the %1 type is not processed";
403     theError.arg(theAttribute->attributeType());
404     return false;
405   }
406   if (theArguments.size() != 2) {
407     theError = "Error: Wrong parameters in XML definition for %1 type";
408     theError.arg(theAttribute->attributeType());
409     return false;
410   }
411   // first argument is for the base attribute, second - for skipping feature kind
412   std::list<std::string>::const_iterator anIt = theArguments.begin();
413   std::string aBaseAttributeId = *anIt;
414   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
415   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
416   if (!aBaseAttribute.get()) {
417     theError = "Wrong parameters in XML definition for %1 type";
418     theError.arg(theAttribute->attributeType());
419     return false;
420   }
421   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
422     // this validator is not necessary anymore
423     return true;
424
425   anIt++;
426   std::string aFeatureAttributeKind = *anIt;
427   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
428   // check whether the selection is on the sketch
429   std::list<std::string> anArguments;
430   anArguments.push_back(aFeatureAttributeKind);
431
432   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
433   bool aPlanarFace = false;
434   // check if selection has Face selected
435   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
436   anArguments.clear();
437   anArguments.push_back("face");
438   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
439
440   bool aValid = !aFeatureKind && aPlanarFace;
441   return aValid;
442 }
443
444 //==================================================================================================
445 bool FeaturesPlugin_ValidatorExtrusionDir::isValid(
446                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
447                                                const std::list<std::string>& theArguments,
448                                                Events_InfoMessage& theError) const
449 {
450   if(theArguments.size() != 2) {
451     theError = "Error: Validator should be used with 2 parameters for extrusion.";
452     return false;
453   }
454
455   std::list<std::string>::const_iterator
456     anArgsIt = theArguments.begin(), aLast = theArguments.end();
457
458   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
459   ++anArgsIt;
460
461   GeomShapePtr aDirShape;
462   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
463   if(aSelAttr.get()) {
464     aDirShape = aSelAttr->value();
465     if(!aDirShape.get()) {
466       ResultPtr aContext = aSelAttr->context();
467       if(!aContext.get()) {
468         FeaturePtr aFeature = aSelAttr->contextFeature();
469         if (aFeature.get() && !aFeature->results().empty()) {
470           aContext = aFeature->firstResult();
471         }
472       }
473
474       if(aContext.get()) {
475         aDirShape = aContext->shape();
476       }
477     }
478   }
479
480   if(!aDirShape.get()) {
481     // Check that dir can be empty.
482     if(!isShapesCanBeEmpty(aCheckAttribute, theError)) {
483       theError = "Error: Base objects list contains vertex or edge, so attribute \"%1\" "
484                  "can not be used with default value. Select direction for extrusion.";
485       theError.arg(*anArgsIt);
486       return false;
487     } else {
488       return true;
489     }
490   }
491
492   std::shared_ptr<GeomAPI_Edge> aDirEdge(new GeomAPI_Edge(aDirShape));
493
494   // If faces selected check that direction not parallel with them.
495   AttributeSelectionListPtr aListAttr =
496     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aCheckAttribute);
497   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
498     AttributeSelectionPtr anAttr = aListAttr->value(anIndex);
499     GeomShapePtr aShapeInList = anAttr->value();
500     if(!aShapeInList.get()) {
501       aShapeInList = anAttr->context()->shape();
502     }
503     bool isParallel = true;
504     if(aShapeInList->shapeType() == GeomAPI_Shape::FACE ||
505        aShapeInList->shapeType() == GeomAPI_Shape::SHELL) {
506       for(GeomAPI_ShapeExplorer
507           anExp(aShapeInList, GeomAPI_Shape::FACE); anExp.more(); anExp.next()) {
508         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(anExp.current()));
509         isParallel = GeomAlgoAPI_ShapeTools::isParallel(aDirEdge, aFace);
510         if(isParallel) {
511           break;
512         }
513       }
514     } else if(aShapeInList->shapeType() == GeomAPI_Shape::COMPOUND) {
515       std::shared_ptr<GeomAPI_PlanarEdges> aPlanarEdges =
516         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aShapeInList);
517       if(aPlanarEdges.get()) {
518         std::shared_ptr<GeomAPI_Dir> aSketchDir = aPlanarEdges->norm();
519         if(aDirEdge->isLine()) {
520           std::shared_ptr<GeomAPI_Dir> aDir = aDirEdge->line()->direction();
521           isParallel = fabs(aSketchDir->angle(aDir) - M_PI / 2.0) < 10e-7;
522         } else {
523           isParallel = false;
524         }
525       } else {
526         isParallel = false;
527       }
528     } else {
529       isParallel = false;
530     }
531     if(isParallel) {
532       theError =
533         "Error: Direction is parallel to one of the selected face or face on selected shell.";
534       return false;
535     }
536   }
537
538   return true;
539 }
540
541 //==================================================================================================
542 bool FeaturesPlugin_ValidatorExtrusionDir::isShapesCanBeEmpty(const AttributePtr& theAttribute,
543                                                               Events_InfoMessage& theError) const
544 {
545   if(!theAttribute.get()) {
546     return true;
547   }
548
549   std::string anAttributeType = theAttribute->attributeType();
550   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
551     AttributeSelectionListPtr aListAttr =
552       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
553     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
554       // If at least one attribute is invalid, the result is false.
555       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
556         return false;
557       }
558     }
559   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
560     // Getting context.
561     AttributeSelectionPtr anAttr =
562       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
563     ResultPtr aContext = anAttr->context();
564     if(!aContext.get() && !anAttr->contextFeature().get()) {
565       return false;
566     }
567
568     GeomShapePtr aShape = anAttr->value();
569     if(!aShape.get() && aContext.get()) {
570       GeomShapePtr aContextShape = aContext->shape();
571       aShape = aContextShape;
572     }
573     if(!aShape.get()) {
574       return false;
575     }
576
577     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
578        aShape->shapeType() == GeomAPI_Shape::EDGE ||
579        !aShape->isPlanar()) {
580       return false;
581     }
582   } else {
583     return false;
584   }
585
586   return true;
587 }
588
589 //==================================================================================================
590 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
591                                                        const std::list<std::string>& theArguments,
592                                                        Events_InfoMessage& theError) const
593 {
594   AttributeSelectionListPtr anAttrSelectionList =
595     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
596   if(!anAttrSelectionList.get()) {
597     theError =
598       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
599     return false;
600   }
601   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
602     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theAttribute->owner());
603   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
604
605   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
606     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
607     if(!anAttrSelection.get()) {
608       theError = "Error: Empty attribute selection.";
609       return false;
610     }
611     ResultPtr aContext = anAttrSelection->context();
612     if(!aContext.get()) {
613       FeaturePtr aContFeat = anAttrSelection->contextFeature();
614       if (!aContFeat.get() || !aContFeat->results().size()) {
615         theError = "Error: Empty selection context.";
616         return false;
617       }
618     }
619     ResultConstructionPtr aResultConstruction =
620       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
621     if(aResultConstruction.get()) {
622       if (anOperationType != FeaturesPlugin_Boolean::BOOL_FILL
623           || theAttribute->id() != FeaturesPlugin_Boolean::TOOL_LIST_ID()) {
624         theError = "Error: Result construction not allowed for selection.";
625         return false;
626       }
627     }
628     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
629     if(!aShape.get() && aContext.get()) {
630       GeomShapePtr aContextShape = aContext->shape();
631       aShape = aContextShape;
632     }
633     if(!aShape.get()) {
634       theError = "Error: Empty shape.";
635       return false;
636     }
637     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
638       theError = "Error: Local selection not allowed.";
639       return false;
640     }
641
642     GeomAPI_Shape::ShapeType aShapeType = aShape->shapeType();
643     std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
644     if(anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE) {
645       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
646       anAllowedTypes.insert(GeomAPI_Shape::FACE);
647       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
648       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
649       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
650     } else if (anOperationType == FeaturesPlugin_Boolean::BOOL_FILL
651                || anOperationType == FeaturesPlugin_Boolean::BOOL_CUT)
652     {
653       anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
654       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
655       anAllowedTypes.insert(GeomAPI_Shape::WIRE);
656       anAllowedTypes.insert(GeomAPI_Shape::FACE);
657       anAllowedTypes.insert(GeomAPI_Shape::SHELL);
658       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
659       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
660       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
661     } else {
662       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
663       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
664       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
665     }
666
667     if(anAllowedTypes.find(aShapeType) == anAllowedTypes.end()
668       || (aResultConstruction.get() && aShapeType != GeomAPI_Shape::FACE)) {
669       theError = "Error: Selected shape has the wrong type.";
670       return false;
671     }
672
673   }
674
675   return true;
676 }
677
678 //==================================================================================================
679 bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAttribute,
680                                                       const std::list<std::string>& theArguments,
681                                                       Events_InfoMessage& theError) const
682 {
683   AttributeSelectionListPtr anAttrSelectionList =
684     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
685   if(!anAttrSelectionList.get()) {
686     theError =
687       "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
688     return false;
689   }
690
691   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
692   // Check all selected entities are sub-shapes of single solid
693   GeomShapePtr aBaseSolid;
694   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
695     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
696     if(!anAttrSelection.get()) {
697       theError = "Error: Empty attribute selection.";
698       return false;
699     }
700     ResultPtr aContext = anAttrSelection->context();
701     if(!aContext.get()) {
702       FeaturePtr aContFeat = anAttrSelection->contextFeature();
703       if (!aContFeat.get() || !aContFeat->results().size() ||
704           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
705         theError = "Error: Empty selection context.";
706         return false;
707       }
708       if (aContFeat->results().size() == 1)
709         aContext = aContFeat->firstResult();
710       else {
711         theError = "Error: Too many shapes selected.";
712         return false;
713       }
714     }
715
716     ResultBodyPtr aContextOwner = ModelAPI_Tools::bodyOwner(aContext);
717     GeomShapePtr anOwner = aContextOwner.get() ? aContextOwner->shape() : aContext->shape();
718
719     if (anOwner->shapeType() != GeomAPI_Shape::SOLID &&
720         anOwner->shapeType() != GeomAPI_Shape::COMPSOLID) {
721       theError = "Error: Not all selected shapes are sub-shapes of solids.";
722       return false;
723     }
724
725     if (!aBaseSolid)
726       aBaseSolid = anOwner;
727     else if (!aBaseSolid->isEqual(anOwner)) {
728       theError = "Error: Sub-shapes of different solids have been selected.";
729       return false;
730     }
731   }
732
733   return true;
734 }
735
736 //==================================================================================================
737 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
738                                                        const std::list<std::string>& theArguments,
739                                                        Events_InfoMessage& theError) const
740 {
741   AttributeSelectionListPtr anAttrSelectionList =
742     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
743   if(!anAttrSelectionList.get()) {
744     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
745     return false;
746   }
747
748   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
749     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
750
751     //GeomValidators_BodyShapes aBodyValidator;
752     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
753     //  continue;
754     //}
755
756     GeomValidators_FeatureKind aFeatureKindValidator;
757     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
758       continue;
759     }
760
761     ResultPtr aContext = aSelectAttr->context();
762     ResultConstructionPtr aResultConstruction =
763       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
764     if(aResultConstruction.get()) {
765       theError = "Error: Only body shapes and construction planes are allowed for selection.";
766       return false;
767     }
768
769     ResultBodyPtr aResultBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
770     if(aResultBody.get()) {
771       continue;
772     }
773     FeaturePtr aResultFeature = aSelectAttr->contextFeature();
774     if(aResultFeature.get()) {
775       bool aOkRes = false;
776       std::list<ResultPtr>::const_iterator aFRes = aResultFeature->results().cbegin();
777       for(; aFRes != aResultFeature->results().cend() && !aOkRes; aFRes++) {
778         ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aFRes);
779         if (aBody.get() && !aBody->isDisabled())
780           aOkRes = true;
781       }
782       if (aOkRes)
783         continue;
784     }
785
786     theError = "Error: Only body shapes and construction planes are allowed for selection.";
787     return false;
788   }
789
790   theError = "";
791   return true;
792 }
793
794 //==================================================================================================
795 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
796                                                      const std::list<std::string>& theArguments,
797                                                      Events_InfoMessage& theError) const
798 {
799   AttributeSelectionListPtr aSubShapesAttrList =
800     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
801   if(!aSubShapesAttrList.get()) {
802     theError =
803       "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
804     return false;
805   }
806
807   static const std::string aBaseShapeID = "base_shape";
808   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
809   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
810
811   if(!aShapeAttrSelection.get()) {
812     theError = "Error: Could not get \"%1\" attribute.";
813     theError.arg(aBaseShapeID);
814     return false;
815   }
816
817   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
818   ResultPtr aContext = aShapeAttrSelection->context();
819   if(!aContext.get()) {
820     theError = "Error: Empty context.";
821     return false;
822   }
823   if(!aBaseShape.get()) {
824     aBaseShape = aContext->shape();
825   }
826   if(!aBaseShape.get()) {
827     theError = "Error: Empty base shape.";
828     return false;
829   }
830
831   std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
832   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
833     bool isSameFound = false;
834     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
835     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
836     for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt) {
837       if ((*anIt)->isEqual(aShapeToAdd)) {
838         isSameFound = true;
839         break;
840       }
841     }
842     if (!isSameFound) {
843       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
844       return false;
845     }
846   }
847
848   return true;
849 }
850
851 //==================================================================================================
852 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
853   const std::shared_ptr<ModelAPI_Feature>& theFeature,
854   const std::list<std::string>& theArguments,
855   Events_InfoMessage& theError) const
856 {
857   static const std::string aBaseShapeID = "base_shape";
858   static const std::string aSubShapesID = "subshapes_to_keep";
859
860   if(theFeature->getKind() != "Remove_SubShapes") {
861     theError = "Error: Feature \"%1\" does not supported by this validator.";
862     theError.arg(theFeature->getKind());
863     return false;
864   }
865
866   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
867   if(!aShapeAttrSelection.get()) {
868     theError = "Error: Could not get \"%1\" attribute.";
869     theError.arg(aBaseShapeID);
870     return false;
871   }
872
873   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
874   if(!aSubShapesAttrList.get()) {
875     theError = "Error: Could not get \"%1\" attribute.";
876     theError.arg(aSubShapesID);
877     return false;
878   }
879
880   // Copy base shape.
881   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
882   if(!aBaseShape.get()) {
883     theError = "Error: Base shape is empty.";
884     return false;
885   }
886   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
887
888   if (aSubShapesAttrList->size() == 0) {
889     theError = "Error: Resulting shape is not valid.";
890     return false;
891   }
892
893   // Copy sub-shapes from list to new shape.
894   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
895     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
896     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
897     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
898   }
899
900   // Check new shape.
901   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
902     theError = "Error: Resulting shape is not valid.";
903     return false;
904   }
905
906   return true;
907 }
908
909 //==================================================================================================
910 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
911                                                      const std::list<std::string>& theArguments,
912                                                      Events_InfoMessage& theError) const
913 {
914   AttributeSelectionListPtr aBaseObjectsAttrList =
915     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
916   if(!aBaseObjectsAttrList.get()) {
917     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
918     theError.arg(FeaturesPlugin_Union::ID());
919     return false;
920   }
921
922   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
923     bool isSameFound = false;
924     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
925     ResultPtr aContext = anAttrSelectionInList->context();
926     if (!aContext.get()) {
927       theError = "Error: selection is invalid.";
928       return false;
929     }
930
931     ResultConstructionPtr aConstruction =
932       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
933     if(aConstruction.get()) {
934       theError = "Error: Result construction not allowed for selection.";
935       return false;
936     }
937
938     GeomShapePtr aShape = anAttrSelectionInList->value();
939     GeomShapePtr aContextShape = aContext->shape();
940     if (aShape.get() && aContextShape.get() && !aContextShape->isEqual(aShape)) {
941       theError = "Error: Local selection not allowed.";
942       return false;
943     }
944
945     ResultBodyPtr aResult =
946       std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
947     if(!aResult.get()) {
948       continue;
949     }
950
951     if(aResult->numberOfSubs() > 0) {
952       theError = "Error: Whole compsolids not allowed for selection.";
953       return false;
954     }
955   }
956
957   return true;
958 }
959
960 //==================================================================================================
961 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
962   const std::shared_ptr<ModelAPI_Feature>& theFeature,
963   const std::list<std::string>& theArguments,
964   Events_InfoMessage& theError) const
965 {
966   // Check feature kind.
967   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
968     theError = "Error: This validator supports only \"%1\" feature.";
969     theError.arg(FeaturesPlugin_Union::ID());
970     return false;
971   }
972
973   // Get base objects attribute list.
974   AttributeSelectionListPtr aBaseObejctsAttrList =
975     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
976   if(!aBaseObejctsAttrList.get()) {
977     theError = "Error: Could not get \"%1\" attribute.";
978     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
979     return false;
980   }
981
982   // Get all shapes.
983   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::COMPSOLID;
984   ListOfShape aBaseShapesList;
985   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
986     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
987     GeomShapePtr aShape = anAttrSelectionInList->value();
988     if (!aShape.get()) {
989       continue;
990     }
991     aBaseShapesList.push_back(aShape);
992     aType = aShape->shapeType() == GeomAPI_Shape::FACE ? GeomAPI_Shape::SHELL :
993                                                          GeomAPI_Shape::COMPSOLID;
994   }
995
996   // Make compound and find connected.
997   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
998   ListOfShape aCombined, aFree;
999   GeomAlgoAPI_ShapeTools::combineShapes(
1000     aCompound,
1001     aType,
1002     aCombined,
1003     aFree);
1004
1005   if(aFree.size() > 0 || aCombined.size() > 1) {
1006     theError = "Error: Not all shapes have shared topology.";
1007     return false;
1008   }
1009
1010   return true;
1011 }
1012
1013 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
1014                                             const std::list<std::string>& theArguments,
1015                                             Events_InfoMessage& theError) const
1016 {
1017   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1018     theError = "Error: The attribute with the %1 type is not processed";
1019     theError.arg(theAttribute->attributeType());
1020     return false;
1021   }
1022
1023   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
1024                                                                                (theAttribute);
1025   ObjectPtr aRefObject = aRefAttribute->value();
1026   if (!aRefObject.get()) {
1027     theError = "Error: Empty feature.";
1028     return false;
1029   }
1030
1031   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
1032   if (!aRefFeature.get()) {
1033     theError = "Error: Empty feature.";
1034     return false;
1035   }
1036   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
1037   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
1038
1039   size_t aConcealedResults = aResults.size();
1040   if (!aConcealedResults && !theArguments.empty()) {
1041     // find if these results are touched by the feature in another attribute
1042     std::list<std::string>::const_iterator anIt = theArguments.begin();
1043     std::string aRecoveredList = *anIt;
1044     if (!aRecoveredList.empty()) {
1045       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
1046                                  theAttribute->owner()->data()->reflist(aRecoveredList);
1047       if (aParameterList.get())
1048         aConcealedResults = aParameterList->size();
1049     }
1050   }
1051
1052   if (aConcealedResults == 0)
1053     theError = "Error: No concealed results.";
1054
1055   return theError.empty();
1056 }
1057
1058 bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
1059                                                const std::list<std::string>& theArguments,
1060                                                Events_InfoMessage& theError) const
1061 {
1062   static std::list<std::string> aEdgeArg(1, "circle");
1063   static std::list<std::string> aFaceArg(1, "cylinder");
1064
1065   Events_InfoMessage aError;
1066   bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
1067   if (!isValid) {
1068     isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
1069     if (!isValid)
1070       theError = "The shape neither circle nor cylinder";
1071   }
1072   return isValid;
1073 }
1074
1075 //=================================================================================================
1076 bool FeaturesPlugin_ValidatorBooleanArguments::isValid(
1077   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1078   const std::list<std::string>& theArguments,
1079   Events_InfoMessage& theError) const
1080 {
1081   if (theArguments.size() != 2)
1082   {
1083     theError = "Wrong number of arguments (expected 2).";
1084     return false;
1085   }
1086
1087   int anObjectsNb = 0, aToolsNb = 0;
1088   //int anOperationType = 0;
1089
1090   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1091
1092   bool isAllInSameCompSolid = true;
1093   ResultBodyPtr aCompSolid;
1094
1095   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1096   if (anAttrSelList)
1097   {
1098     anObjectsNb = anAttrSelList->size();
1099     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex)
1100     {
1101       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1102       ResultPtr aContext = anAttr->context();
1103       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1104       if (aResCompSolidPtr.get())
1105       {
1106         if (aCompSolid.get())
1107         {
1108           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1109         }
1110         else
1111         {
1112           aCompSolid = aResCompSolidPtr;
1113         }
1114       }
1115       else
1116       {
1117         isAllInSameCompSolid = false;
1118         break;
1119       }
1120     }
1121   }
1122   anIt++;
1123
1124
1125   anAttrSelList = theFeature->selectionList(*anIt);
1126   if (anAttrSelList)
1127   {
1128     aToolsNb = anAttrSelList->size();
1129     if (isAllInSameCompSolid)
1130     {
1131       for (int anIndex = 0; anIndex < aToolsNb; ++anIndex)
1132       {
1133         AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1134         ResultPtr aContext = anAttr->context();
1135         ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1136         if (aResCompSolidPtr.get())
1137         {
1138           if (aCompSolid.get())
1139           {
1140             isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1141           }
1142           else
1143           {
1144             aCompSolid = aResCompSolidPtr;
1145           }
1146         }
1147         else
1148         {
1149           isAllInSameCompSolid = false;
1150           break;
1151         }
1152       }
1153     }
1154   }
1155   anIt++;
1156
1157   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1158     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1159   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1160
1161   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1162   {
1163     // Fuse operation
1164     if (anObjectsNb + aToolsNb < 2)
1165     {
1166       theError = "Not enough arguments for Fuse operation.";
1167       return false;
1168     }
1169     else if (isAllInSameCompSolid)
1170     {
1171       theError = "Operations only between sub-shapes of the same shape not allowed.";
1172       return false;
1173     }
1174   }
1175   else
1176   {
1177     if (anObjectsNb < 1)
1178     {
1179       theError = "Objects not selected.";
1180       return false;
1181     }
1182     if (aToolsNb < 1)
1183     {
1184       theError = "Tools not selected.";
1185       return false;
1186     }
1187     if (isAllInSameCompSolid)
1188     {
1189       theError = "Operations only between sub-shapes of the same shape not allowed.";
1190       return false;
1191     }
1192   }
1193
1194   return true;
1195 }
1196
1197 //=================================================================================================
1198 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1199                                                                std::string theAttribute)
1200 {
1201   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1202   {
1203     return true;
1204   }
1205
1206   return false;
1207 }
1208
1209 //==================================================================================================
1210 bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
1211   const AttributePtr& theAttribute,
1212   const std::list<std::string>& theArguments,
1213   Events_InfoMessage& theError) const
1214 {
1215   std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
1216     std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
1217
1218   AttributeSelectionListPtr anAttrSelectionList =
1219     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1220   if (!aFeature.get() || !anAttrSelectionList.get()) {
1221     theError =
1222       "Error: Validator used in wrong feature or attribute";
1223     return false;
1224   }
1225
1226   AttributeSelectionListPtr anOtherAttrSelectionList;
1227   if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
1228     anOtherAttrSelectionList =
1229       aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
1230   } else {
1231     anOtherAttrSelectionList =
1232       aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
1233   }
1234
1235   GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
1236   GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
1237   GeomPlanePtr aFacesPln;
1238
1239   for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
1240     AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
1241
1242     if (anAttrSelection->contextFeature().get()) {
1243       theError = "Error: Features not allowed for selection.";
1244       return false;
1245     }
1246
1247     ResultPtr aContext = anAttrSelection->context();
1248     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1249     GeomShapePtr aContextShape = aContext->shape();
1250     if (!aShape.get()) {
1251       aShape = aContextShape;
1252     }
1253
1254     if (aShape->isSolid() || aShape->isCompSolid()) {
1255       aSelectedShapesType = GeomAPI_Shape::SOLID;
1256       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1257       if (aResCompSolidPtr.get()) {
1258         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1259         aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
1260       }
1261     } else {
1262       aSelectedShapesType = GeomAPI_Shape::FACE;
1263       GeomAPI_Face aFace(aShape);
1264       aFacesPln = aFace.getPlane();
1265       break;
1266     }
1267   }
1268
1269   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1270     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1271     if (!anAttrSelection.get()) {
1272       theError = "Error: Empty attribute selection.";
1273       return false;
1274     }
1275
1276     if (anAttrSelection->contextFeature().get()) {
1277       theError = "Error: Features not allowed for selection.";
1278       return false;
1279     }
1280
1281     ResultPtr aContext = anAttrSelection->context();
1282     if(!aContext.get()) {
1283       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1284       if (!aContFeat.get() || !aContFeat->results().size() ||
1285           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1286         theError = "Error: Empty selection context.";
1287         return false;
1288       }
1289     }
1290     ResultConstructionPtr aResultConstruction =
1291       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1292     if (aResultConstruction.get()) {
1293       theError = "Error: Result construction not allowed for selection.";
1294       return false;
1295     }
1296     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1297     GeomShapePtr aContextShape = aContext->shape();
1298     if (!aShape.get()) {
1299       aShape = aContextShape;
1300     }
1301     if (!aShape.get()) {
1302       theError = "Error: Empty shape.";
1303       return false;
1304     }
1305     if (!aShape->isEqual(aContextShape)) {
1306       theError = "Error: Local selection not allowed.";
1307       return false;
1308     }
1309
1310     if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
1311       // Other list is empty.
1312       if (aShape->isSolid() || aShape->isCompSolid()) {
1313         aSelectedShapesType = GeomAPI_Shape::SOLID;
1314       } else {
1315         aSelectedShapesType = GeomAPI_Shape::FACE;
1316         GeomAPI_Face aFace(aShape);
1317         aFacesPln = aFace.getPlane();
1318
1319         if (!aFacesPln.get()) {
1320           theError = "Error: Only planar faces allowed.";
1321           return false;
1322         }
1323       }
1324
1325       continue;
1326     } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
1327       if (!aShape->isSolid() && !aShape->isCompSolid()) {
1328         theError = "Error: Selected shapes should have the same type.";
1329         return false;
1330       }
1331
1332       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1333       if (aResCompSolidPtr.get()) {
1334         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1335         if (aSelectedCompSolidsInOtherList.isBound(aCompSolidShape)) {
1336           theError = "Error: Solids from compsolid in other list not allowed.";
1337           return false;
1338         }
1339       }
1340     } else {
1341       GeomAPI_Face aFace(aShape);
1342       GeomPlanePtr aPln = aFace.getPlane();
1343
1344       if (!aPln.get()) {
1345         theError = "Error: Only planar faces allowed.";
1346         return false;
1347       }
1348
1349       if (!aFacesPln->isCoincident(aPln)) {
1350         theError = "Error: Only coincident faces allowed.";
1351         return false;
1352       }
1353     }
1354   }
1355
1356   return true;
1357 }
1358
1359 //==================================================================================================
1360 bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttribute,
1361                                                    const std::list<std::string>& theArguments,
1362                                                    Events_InfoMessage& theError) const
1363 {
1364   if (!theAttribute.get()) {
1365     theError = "Error: empty selection.";
1366     return false;
1367   }
1368   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1369   AttributeSelectionListPtr anAttrSelectionList =
1370     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1371   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1372     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1373     if (!anAttrSelection.get()) {
1374       theError = "Error: empty attribute selection.";
1375       return false;
1376     }
1377     ResultPtr aContext = anAttrSelection->context();
1378     if(!aContext.get()) {
1379       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1380       if (!aContFeat.get() || !aContFeat->results().size() ||
1381           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1382         theError = "Error: Empty selection context.";
1383         return false;
1384       }
1385     }
1386     FeaturePtr aFeature = anAttrSelection->contextFeature().get() ?
1387       anAttrSelection->contextFeature() : ModelAPI_Feature::feature(aContext);
1388     if (!aFeature.get()) {
1389       theError = "Error: empty feature.";
1390       return false;
1391     }
1392     std::string aFeatureKind = aFeature->getKind();
1393     if (aFeatureKind == "Sketch" ||
1394         aFeatureKind == "Plane" ||
1395         aFeatureKind == "Axis") {
1396       theError = "Error: %1 shape is not allowed for selection.";
1397       theError.arg(aFeatureKind);
1398       return false;
1399     }
1400     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1401     if (!aShape.get()) {
1402       GeomShapePtr aContextShape = aContext->shape();
1403       aShape = aContextShape;
1404     }
1405     if (!aShape.get()) {
1406       theError = "Error: empty shape.";
1407       return false;
1408     }
1409     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1410       theError = "Error: Local selection not allowed.";
1411       return false;
1412     }
1413
1414     int aShapeType = aShape->shapeType();
1415     // Allow to select edges, faces and solids.
1416     if (aShapeType != GeomAPI_Shape::EDGE &&
1417         aShapeType != GeomAPI_Shape::FACE &&
1418         aShapeType != GeomAPI_Shape::SOLID &&
1419         aShapeType != GeomAPI_Shape::COMPSOLID &&
1420         aShapeType != GeomAPI_Shape::COMPOUND) {
1421       theError = "Error: selected shape has the wrong type.";
1422       return false;
1423     }
1424   }
1425
1426   return true;
1427 }
1428
1429 //==================================================================================================
1430 bool FeaturesPlugin_ValidatorBooleanFuseSelection::isValid(
1431   const AttributePtr& theAttribute,
1432   const std::list<std::string>& theArguments,
1433   Events_InfoMessage& theError) const
1434 {
1435   AttributeSelectionListPtr anAttrSelectionList =
1436     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1437   if (!anAttrSelectionList.get()) {
1438     theError =
1439       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1440     return false;
1441   }
1442
1443   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1444     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1445     if (!anAttrSelection.get()) {
1446       theError = "Error: Empty attribute selection.";
1447       return false;
1448     }
1449     ResultPtr aContext = anAttrSelection->context();
1450     if(!aContext.get()) {
1451       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1452       if (!aContFeat.get() || !aContFeat->results().size() ||
1453           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1454         theError = "Error: Empty selection context.";
1455         return false;
1456       }
1457     }
1458     ResultConstructionPtr aResultConstruction =
1459       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1460     if (aResultConstruction.get()) {
1461       theError = "Error: Result construction not allowed for selection.";
1462       return false;
1463     }
1464     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1465     if (!aShape.get()) {
1466       GeomShapePtr aContextShape = aContext->shape();
1467       aShape = aContextShape;
1468     }
1469     if (!aShape.get()) {
1470       theError = "Error: Empty shape.";
1471       return false;
1472     }
1473     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1474       theError = "Error: Local selection not allowed.";
1475       return false;
1476     }
1477   }
1478
1479   return true;
1480 }
1481
1482 //=================================================================================================
1483 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
1484   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1485   const std::list<std::string>& theArguments,
1486   Events_InfoMessage& theError) const
1487 {
1488   if (theArguments.size() != 2) {
1489     theError = "Wrong number of arguments (expected 2).";
1490     return false;
1491   }
1492
1493   std::shared_ptr<FeaturesPlugin_BooleanFuse> aFeature =
1494     std::dynamic_pointer_cast<FeaturesPlugin_BooleanFuse>(theFeature);
1495
1496   int anObjectsNb = 0, aToolsNb = 0;
1497
1498   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1499
1500   bool isAllInSameCompSolid = true;
1501   ResultBodyPtr aCompSolid;
1502
1503   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1504   if (anAttrSelList) {
1505     anObjectsNb = anAttrSelList->size();
1506     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex) {
1507       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1508       ResultPtr aContext = anAttr->context();
1509       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1510       if (aResCompSolidPtr.get()) {
1511         if (aCompSolid.get()) {
1512           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1513         } else {
1514           aCompSolid = aResCompSolidPtr;
1515         }
1516       } else {
1517         isAllInSameCompSolid = false;
1518         break;
1519       }
1520     }
1521   }
1522   anIt++;
1523
1524   if (aFeature->string(FeaturesPlugin_BooleanFuse::CREATION_METHOD())->value()
1525       == FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED()) {
1526     anAttrSelList = theFeature->selectionList(*anIt);
1527     if (anAttrSelList) {
1528       aToolsNb = anAttrSelList->size();
1529       if (isAllInSameCompSolid) {
1530         for (int anIndex = 0; anIndex < aToolsNb; ++anIndex) {
1531           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1532           ResultPtr aContext = anAttr->context();
1533           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1534           if (aResCompSolidPtr.get()) {
1535             if (aCompSolid.get()) {
1536               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1537             } else {
1538               aCompSolid = aResCompSolidPtr;
1539             }
1540           } else {
1541             isAllInSameCompSolid = false;
1542             break;
1543           }
1544         }
1545       }
1546     }
1547   }
1548
1549   anIt++;
1550
1551   if (anObjectsNb + aToolsNb < 2) {
1552     theError = "Not enough arguments for Fuse operation.";
1553     return false;
1554   } else if (isAllInSameCompSolid) {
1555     theError = "Operations only between sub-shapes of the same shape not allowed.";
1556     return false;
1557   }
1558
1559   return true;
1560 }
1561
1562 //=================================================================================================
1563 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isNotObligatory(
1564   std::string theFeature,
1565   std::string theAttribute)
1566 {
1567   if (theAttribute == "main_objects" || theAttribute == "tool_objects") {
1568     return true;
1569   }
1570
1571   return false;
1572 }
1573
1574 //==================================================================================================
1575 bool FeaturesPlugin_ValidatorBooleanCommonSelection::isValid(
1576   const AttributePtr& theAttribute,
1577   const std::list<std::string>& theArguments,
1578   Events_InfoMessage& theError) const
1579 {
1580   AttributeSelectionListPtr anAttrSelectionList =
1581     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1582   if (!anAttrSelectionList.get()) {
1583     theError =
1584       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1585     return false;
1586   }
1587
1588   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1589     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1590     if (!anAttrSelection.get()) {
1591       theError = "Error: Empty attribute selection.";
1592       return false;
1593     }
1594     ResultPtr aContext = anAttrSelection->context();
1595     if (!aContext.get() && !anAttrSelection->contextFeature().get()) {
1596       theError = "Error: Empty selection context.";
1597       return false;
1598     }
1599     ResultConstructionPtr aResultConstruction =
1600       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1601     if (aResultConstruction.get()) {
1602       if (theAttribute->id() != FeaturesPlugin_BooleanCommon::TOOL_LIST_ID()) {
1603         theError = "Error: Result construction not allowed for selection.";
1604         return false;
1605       }
1606     }
1607     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1608     GeomShapePtr aContextShape;
1609     if (!aShape.get() && aContext.get()) {
1610       aContextShape = aContext->shape();
1611       aShape = aContextShape;
1612     }
1613     if (!aShape.get()) {
1614       theError = "Error: Empty shape.";
1615       return false;
1616     }
1617     if (aContextShape.get() && !aShape->isEqual(aContextShape)) {
1618       theError = "Error: Local selection not allowed.";
1619       return false;
1620     }
1621
1622     if (aResultConstruction.get() && aShape->shapeType() != GeomAPI_Shape::FACE) {
1623       theError = "Error: Result construction should be plane.";
1624       return false;
1625     }
1626   }
1627
1628   return true;
1629 }
1630
1631 //=================================================================================================
1632 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
1633   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1634   const std::list<std::string>& theArguments,
1635   Events_InfoMessage& theError) const
1636 {
1637   if (theArguments.size() != 2) {
1638     theError = "Wrong number of arguments (expected 2).";
1639     return false;
1640   }
1641
1642   std::shared_ptr<FeaturesPlugin_BooleanCommon> aFeature =
1643     std::dynamic_pointer_cast<FeaturesPlugin_BooleanCommon>(theFeature);
1644
1645   int anObjectsNb = 0, aToolsNb = 0;
1646
1647   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1648
1649   bool isAllInSameCompSolid = true;
1650   ResultBodyPtr aCompSolid;
1651
1652   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1653   if (anAttrSelList) {
1654     anObjectsNb = anAttrSelList->size();
1655   }
1656
1657   bool isSimpleMode = aFeature->string(FeaturesPlugin_BooleanCommon::CREATION_METHOD())->value()
1658                       == FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE();
1659
1660   if (!isSimpleMode) {
1661     anAttrSelList = theFeature->selectionList(*anIt);
1662     if (anAttrSelList) {
1663       aToolsNb = anAttrSelList->size();
1664     }
1665   }
1666
1667   if ((isSimpleMode && anObjectsNb < 2)
1668       || (!isSimpleMode && (anObjectsNb == 0 || aToolsNb == 0))) {
1669     theError = "Not enough arguments for Fuse operation.";
1670     return false;
1671   }
1672   return true;
1673 }
1674
1675 //=================================================================================================
1676 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
1677   std::string theFeature,
1678   std::string theAttribute)
1679 {
1680   return false;
1681 }