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