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