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