]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
Salome HOME
Task 3.2. To keep compounds’ sub-shapes for all operations (issue #3139)
[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, true);
917     GeomShapePtr anOwner = aContext->shape();
918     GeomShapePtr aTopLevelOwner = aContextOwner.get() ? aContextOwner->shape() : anOwner;
919
920     if (!anOwner) {
921       theError = "Error: wrong feature is selected.";
922       return false;
923     }
924
925     if (anOwner->shapeType() != GeomAPI_Shape::SOLID &&
926         anOwner->shapeType() != GeomAPI_Shape::COMPSOLID) {
927       theError = "Error: Not all selected shapes are sub-shapes of solids.";
928       return false;
929     }
930
931     if (!aBaseSolid)
932       aBaseSolid = aTopLevelOwner;
933     else if (!aBaseSolid->isEqual(aTopLevelOwner)) {
934       theError = "Error: Sub-shapes of different solids have been selected.";
935       return false;
936     }
937   }
938
939   return true;
940 }
941
942 //==================================================================================================
943 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
944                                                        const std::list<std::string>& theArguments,
945                                                        Events_InfoMessage& theError) const
946 {
947   AttributeSelectionListPtr anAttrSelectionList =
948     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
949   if(!anAttrSelectionList.get()) {
950 // LCOV_EXCL_START
951     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
952     return false;
953 // LCOV_EXCL_STOP
954   }
955
956   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
957     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
958
959     //GeomValidators_BodyShapes aBodyValidator;
960     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
961     //  continue;
962     //}
963
964     GeomValidators_FeatureKind aFeatureKindValidator;
965     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
966       continue;
967     }
968
969     ResultPtr aContext = aSelectAttr->context();
970     ResultConstructionPtr aResultConstruction =
971       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
972     if(aResultConstruction.get()) {
973       theError = "Error: Only body shapes and construction planes are allowed for selection.";
974       return false;
975     }
976
977     ResultBodyPtr aResultBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
978     if(aResultBody.get()) {
979       continue;
980     }
981     FeaturePtr aResultFeature = aSelectAttr->contextFeature();
982     if(aResultFeature.get()) {
983       bool aOkRes = false;
984       std::list<ResultPtr>::const_iterator aFRes = aResultFeature->results().cbegin();
985       for(; aFRes != aResultFeature->results().cend() && !aOkRes; aFRes++) {
986         ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aFRes);
987         if (aBody.get() && !aBody->isDisabled())
988           aOkRes = true;
989       }
990       if (aOkRes)
991         continue;
992     }
993
994     theError = "Error: Only body shapes and construction planes are allowed for selection.";
995     return false;
996   }
997
998   theError = "";
999   return true;
1000 }
1001
1002 //==================================================================================================
1003 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
1004                                                      const std::list<std::string>& theArguments,
1005                                                      Events_InfoMessage& theError) const
1006 {
1007   AttributeSelectionListPtr aSubShapesAttrList =
1008     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1009   if(!aSubShapesAttrList.get()) {
1010 // LCOV_EXCL_START
1011     theError =
1012       "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
1013     return false;
1014 // LCOV_EXCL_STOP
1015   }
1016
1017   static const std::string aBaseShapeID = "base_shape";
1018   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1019   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
1020
1021   if(!aShapeAttrSelection.get()) {
1022 // LCOV_EXCL_START
1023     theError = "Error: Could not get \"%1\" attribute.";
1024     theError.arg(aBaseShapeID);
1025     return false;
1026 // LCOV_EXCL_STOP
1027   }
1028
1029   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
1030   ResultPtr aContext = aShapeAttrSelection->context();
1031   if(!aContext.get()) {
1032     theError = "Error: Empty context.";
1033     return false;
1034   }
1035   if(!aBaseShape.get()) {
1036     aBaseShape = aContext->shape();
1037   }
1038   if(!aBaseShape.get()) {
1039     theError = "Error: Empty base shape.";
1040     return false;
1041   }
1042
1043   std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
1044   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
1045     bool isSameFound = false;
1046     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
1047     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
1048     for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt)
1049     {
1050       if ((*anIt)->isEqual(aShapeToAdd)) {
1051         isSameFound = true;
1052         break;
1053       }
1054     }
1055     if (!isSameFound) {
1056       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
1057       return false;
1058     }
1059   }
1060
1061   return true;
1062 }
1063
1064 //==================================================================================================
1065 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
1066   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1067   const std::list<std::string>& theArguments,
1068   Events_InfoMessage& theError) const
1069 {
1070   static const std::string aBaseShapeID = "base_shape";
1071   static const std::string aSubShapesID = "subshapes_to_keep";
1072
1073 // LCOV_EXCL_START
1074   if(theFeature->getKind() != "Remove_SubShapes") {
1075     theError = "Error: Feature \"%1\" does not supported by this validator.";
1076     theError.arg(theFeature->getKind());
1077     return false;
1078   }
1079
1080   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
1081   if(!aShapeAttrSelection.get()) {
1082     theError = "Error: Could not get \"%1\" attribute.";
1083     theError.arg(aBaseShapeID);
1084     return false;
1085   }
1086
1087   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
1088   if(!aSubShapesAttrList.get()) {
1089     theError = "Error: Could not get \"%1\" attribute.";
1090     theError.arg(aSubShapesID);
1091     return false;
1092   }
1093 // LCOV_EXCL_STOP
1094
1095   // Copy base shape.
1096   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
1097   if(!aBaseShape.get()) {
1098     theError = "Error: Base shape is empty.";
1099     return false;
1100   }
1101   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
1102
1103   if (aSubShapesAttrList->size() == 0) {
1104     theError = "Error: Resulting shape is not valid.";
1105     return false;
1106   }
1107
1108   // Copy sub-shapes from list to new shape.
1109   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
1110     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
1111     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
1112     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
1113   }
1114
1115   // Check new shape.
1116   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
1117     theError = "Error: Resulting shape is not valid.";
1118     return false;
1119   }
1120
1121   return true;
1122 }
1123
1124 //==================================================================================================
1125 // LCOV_EXCL_START
1126 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
1127                                                      const std::list<std::string>& theArguments,
1128                                                      Events_InfoMessage& theError) const
1129 {
1130   AttributeSelectionListPtr aBaseObjectsAttrList =
1131     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1132   if(!aBaseObjectsAttrList.get()) {
1133     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
1134     theError.arg(FeaturesPlugin_Union::ID());
1135     return false;
1136   }
1137
1138   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
1139     bool isSameFound = false;
1140     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
1141     ResultPtr aContext = anAttrSelectionInList->context();
1142     if (!aContext.get()) {
1143       theError = "Error: selection is invalid.";
1144       return false;
1145     }
1146
1147     ResultConstructionPtr aConstruction =
1148       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1149     if(aConstruction.get()) {
1150       theError = "Error: Result construction not allowed for selection.";
1151       return false;
1152     }
1153
1154     GeomShapePtr aShape = anAttrSelectionInList->value();
1155     GeomShapePtr aContextShape = aContext->shape();
1156     if (aShape.get() && aContextShape.get() && !aContextShape->isEqual(aShape)) {
1157       theError = "Error: Local selection not allowed.";
1158       return false;
1159     }
1160
1161     ResultBodyPtr aResult =
1162       std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
1163     if(!aResult.get()) {
1164       continue;
1165     }
1166
1167     if(aResult->numberOfSubs() > 0) {
1168       theError = "Error: Whole compsolids not allowed for selection.";
1169       return false;
1170     }
1171   }
1172
1173   return true;
1174 }
1175 // LCOV_EXCL_STOP
1176
1177 //==================================================================================================
1178 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
1179   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1180   const std::list<std::string>& theArguments,
1181   Events_InfoMessage& theError) const
1182 {
1183 // LCOV_EXCL_START
1184   // Check feature kind.
1185   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
1186     theError = "Error: This validator supports only \"%1\" feature.";
1187     theError.arg(FeaturesPlugin_Union::ID());
1188     return false;
1189   }
1190
1191   // Get base objects attribute list.
1192   AttributeSelectionListPtr aBaseObejctsAttrList =
1193     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
1194   if(!aBaseObejctsAttrList.get()) {
1195     theError = "Error: Could not get \"%1\" attribute.";
1196     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
1197     return false;
1198   }
1199 // LCOV_EXCL_STOP
1200
1201   // Get all shapes.
1202   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::COMPSOLID;
1203   ListOfShape aBaseShapesList;
1204   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
1205     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
1206     GeomShapePtr aShape = anAttrSelectionInList->value();
1207     if (!aShape.get()) {
1208       continue;
1209     }
1210     aBaseShapesList.push_back(aShape);
1211     aType = aShape->shapeType() == GeomAPI_Shape::FACE ? GeomAPI_Shape::SHELL :
1212                                                          GeomAPI_Shape::COMPSOLID;
1213   }
1214
1215   // Make compound and find connected.
1216   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
1217   ListOfShape aResults;
1218   GeomAlgoAPI_ShapeTools::combineShapes(aCompound, aType, aResults);
1219
1220   if(aResults.size() > 1 || (aResults.size() == 1 && aResults.front()->shapeType() > aType)) {
1221     theError = "Error: Not all shapes have shared topology.";
1222     return false;
1223   }
1224
1225   return true;
1226 }
1227
1228 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
1229                                             const std::list<std::string>& theArguments,
1230                                             Events_InfoMessage& theError) const
1231 {
1232   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1233 // LCOV_EXCL_START
1234     theError = "Error: The attribute with the %1 type is not processed";
1235     theError.arg(theAttribute->attributeType());
1236     return false;
1237 // LCOV_EXCL_STOP
1238   }
1239
1240   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
1241                                                                                (theAttribute);
1242   ObjectPtr aRefObject = aRefAttribute->value();
1243   if (!aRefObject.get()) {
1244     theError = "Error: Empty feature.";
1245     return false;
1246   }
1247
1248   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
1249   if (!aRefFeature.get()) {
1250     theError = "Error: Empty feature.";
1251     return false;
1252   }
1253   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
1254   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
1255
1256   size_t aConcealedResults = aResults.size();
1257   if (!aConcealedResults && !theArguments.empty()) {
1258     // find if these results are touched by the feature in another attribute
1259     std::list<std::string>::const_iterator anIt = theArguments.begin();
1260     std::string aRecoveredList = *anIt;
1261     if (!aRecoveredList.empty()) {
1262       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
1263                                  theAttribute->owner()->data()->reflist(aRecoveredList);
1264       if (aParameterList.get())
1265         aConcealedResults = aParameterList->size();
1266     }
1267   }
1268
1269   if (aConcealedResults == 0)
1270     theError = "Error: No concealed results.";
1271
1272   return theError.empty();
1273 }
1274
1275 bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
1276                                                const std::list<std::string>& theArguments,
1277                                                Events_InfoMessage& theError) const
1278 {
1279   static std::list<std::string> aEdgeArg(1, "circle");
1280   static std::list<std::string> aFaceArg(1, "cylinder");
1281
1282   Events_InfoMessage aError;
1283   bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
1284   if (!isValid) {
1285     isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
1286     if (!isValid)
1287       theError = "The shape neither circle nor cylinder";
1288   }
1289   return isValid;
1290 }
1291
1292 //=================================================================================================
1293 bool FeaturesPlugin_ValidatorBooleanArguments::isValid(
1294   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1295   const std::list<std::string>& theArguments,
1296   Events_InfoMessage& theError) const
1297 {
1298 // LCOV_EXCL_START
1299   if (theArguments.size() != 2)
1300   {
1301     theError = "Wrong number of arguments (expected 2).";
1302     return false;
1303   }
1304 // LCOV_EXCL_STOP
1305
1306   int anObjectsToolsNb[2] = { 0,  0 };
1307
1308   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1309
1310   bool isAllInSameCompSolid = true;
1311   ResultBodyPtr aCompSolid;
1312
1313   for (int* anArgNbIt = anObjectsToolsNb; anIt != aLast; ++anIt, ++anArgNbIt) {
1314     AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1315     if (anAttrSelList)
1316     {
1317       *anArgNbIt = anAttrSelList->size();
1318       if (isAllInSameCompSolid) {
1319         for (int anIndex = 0; anIndex < *anArgNbIt; ++anIndex)
1320         {
1321           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1322           ResultPtr aContext = anAttr->context();
1323           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1324           if (aResCompSolidPtr.get())
1325           {
1326             if (aCompSolid.get())
1327             {
1328               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1329             }
1330             else
1331             {
1332               aCompSolid = aResCompSolidPtr;
1333             }
1334           }
1335           else
1336           {
1337             isAllInSameCompSolid = false;
1338             break;
1339           }
1340         }
1341       }
1342     }
1343   }
1344
1345   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1346     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1347   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1348
1349   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1350   {
1351     // Fuse operation
1352     if (anObjectsToolsNb[0] + anObjectsToolsNb[1] < 2)
1353     {
1354       theError = "Not enough arguments for Fuse operation.";
1355       return false;
1356     }
1357     else if (isAllInSameCompSolid)
1358     {
1359       theError = "Operations only between sub-shapes of the same shape not allowed.";
1360       return false;
1361     }
1362   }
1363   else
1364   {
1365     if (anObjectsToolsNb[0] < 1) // check number of objects
1366     {
1367       theError = "Objects not selected.";
1368       return false;
1369     }
1370     if (anObjectsToolsNb[1] < 1) // check number of tools
1371     {
1372       theError = "Tools not selected.";
1373       return false;
1374     }
1375     if (isAllInSameCompSolid)
1376     {
1377       theError = "Operations only between sub-shapes of the same shape not allowed.";
1378       return false;
1379     }
1380   }
1381
1382   return true;
1383 }
1384
1385 //=================================================================================================
1386 // LCOV_EXCL_START
1387 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1388                                                                std::string theAttribute)
1389 {
1390   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1391   {
1392     return true;
1393   }
1394
1395   return false;
1396 }
1397 // LCOV_EXCL_STOP
1398
1399 //==================================================================================================
1400 bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
1401   const AttributePtr& theAttribute,
1402   const std::list<std::string>& theArguments,
1403   Events_InfoMessage& theError) const
1404 {
1405   std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
1406     std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
1407
1408   AttributeSelectionListPtr anAttrSelectionList =
1409     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1410   if (!aFeature.get() || !anAttrSelectionList.get()) {
1411 // LCOV_EXCL_START
1412     theError =
1413       "Error: Validator used in wrong feature or attribute";
1414     return false;
1415 // LCOV_EXCL_STOP
1416   }
1417
1418   AttributeSelectionListPtr anOtherAttrSelectionList;
1419   if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
1420     anOtherAttrSelectionList =
1421       aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
1422   } else {
1423     anOtherAttrSelectionList =
1424       aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
1425   }
1426
1427   GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
1428   GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
1429   GeomPlanePtr aFacesPln;
1430
1431   for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
1432     AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
1433
1434     if (anAttrSelection->contextFeature().get()) {
1435       theError = "Error: Features not allowed for selection.";
1436       return false;
1437     }
1438
1439     ResultPtr aContext = anAttrSelection->context();
1440     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1441     if (!aShape.get()) {
1442       if (!aContext.get()) {
1443         theError = "Error: Empty selection.";
1444         return false;
1445       }
1446       aShape = aContext->shape();
1447     }
1448
1449     if (aShape->isSolid() || aShape->isCompSolid()) {
1450       aSelectedShapesType = GeomAPI_Shape::SOLID;
1451       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1452       if (aResCompSolidPtr.get()) {
1453         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1454         aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
1455       }
1456     } else {
1457       aSelectedShapesType = GeomAPI_Shape::FACE;
1458       GeomAPI_Face aFace(aShape);
1459       aFacesPln = aFace.getPlane();
1460       break;
1461     }
1462   }
1463
1464   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1465     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1466     if (!anAttrSelection.get()) {
1467       theError = "Error: Empty attribute selection.";
1468       return false;
1469     }
1470
1471     if (anAttrSelection->contextFeature().get()) {
1472       theError = "Error: Features not allowed for selection.";
1473       return false;
1474     }
1475
1476     ResultPtr aContext = anAttrSelection->context();
1477     if(!aContext.get()) {
1478       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1479       if (!aContFeat.get() || !aContFeat->results().size() ||
1480           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1481         theError = "Error: Empty selection context.";
1482         return false;
1483       }
1484     }
1485     ResultConstructionPtr aResultConstruction =
1486       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1487     if (aResultConstruction.get()) {
1488       theError = "Error: Result construction not allowed for selection.";
1489       return false;
1490     }
1491     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1492     GeomShapePtr aContextShape = aContext->shape();
1493     if (!aShape.get()) {
1494       aShape = aContextShape;
1495     }
1496     if (!aShape.get()) {
1497       theError = "Error: Empty shape.";
1498       return false;
1499     }
1500     if (!aShape->isEqual(aContextShape)) {
1501       theError = "Error: Local selection not allowed.";
1502       return false;
1503     }
1504
1505     if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
1506       // Other list is empty.
1507       if (aShape->isSolid() || aShape->isCompSolid()) {
1508         aSelectedShapesType = GeomAPI_Shape::SOLID;
1509       } else {
1510         aSelectedShapesType = GeomAPI_Shape::FACE;
1511         GeomAPI_Face aFace(aShape);
1512         aFacesPln = aFace.getPlane();
1513
1514         if (!aFacesPln.get()) {
1515           theError = "Error: Only planar faces allowed.";
1516           return false;
1517         }
1518       }
1519
1520       continue;
1521     } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
1522       if (!aShape->isSolid() && !aShape->isCompSolid()) {
1523         theError = "Error: Selected shapes should have the same type.";
1524         return false;
1525       }
1526     } else {
1527       GeomAPI_Face aFace(aShape);
1528       GeomPlanePtr aPln = aFace.getPlane();
1529
1530       if (!aPln.get()) {
1531         theError = "Error: Only planar faces allowed.";
1532         return false;
1533       }
1534
1535       if (!aFacesPln->isCoincident(aPln)) {
1536         theError = "Error: Only coincident faces allowed.";
1537         return false;
1538       }
1539     }
1540   }
1541
1542   return true;
1543 }
1544
1545 //==================================================================================================
1546 // LCOV_EXCL_START
1547 bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttribute,
1548                                                    const std::list<std::string>& theArguments,
1549                                                    Events_InfoMessage& theError) const
1550 {
1551   if (!theAttribute.get()) {
1552     theError = "Error: empty selection.";
1553     return false;
1554   }
1555   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1556   AttributeSelectionListPtr anAttrSelectionList =
1557     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1558   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1559     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1560     if (!anAttrSelection.get()) {
1561       theError = "Error: empty attribute selection.";
1562       return false;
1563     }
1564     ResultPtr aContext = anAttrSelection->context();
1565     if(!aContext.get()) {
1566       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1567       if (!aContFeat.get() || !aContFeat->results().size() ||
1568           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1569         theError = "Error: Empty selection context.";
1570         return false;
1571       }
1572     }
1573     FeaturePtr aFeature = anAttrSelection->contextFeature().get() ?
1574       anAttrSelection->contextFeature() : ModelAPI_Feature::feature(aContext);
1575     if (!aFeature.get()) {
1576       theError = "Error: empty feature.";
1577       return false;
1578     }
1579     std::string aFeatureKind = aFeature->getKind();
1580     if (aFeatureKind == "Sketch" ||
1581         aFeatureKind == "Plane" ||
1582         aFeatureKind == "Axis") {
1583       theError = "Error: %1 shape is not allowed for selection.";
1584       theError.arg(aFeatureKind);
1585       return false;
1586     }
1587     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1588     if (!aShape.get()) {
1589       GeomShapePtr aContextShape = aContext->shape();
1590       aShape = aContextShape;
1591     }
1592     if (!aShape.get()) {
1593       theError = "Error: empty shape.";
1594       return false;
1595     }
1596     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1597       theError = "Error: Local selection not allowed.";
1598       return false;
1599     }
1600
1601     int aShapeType = aShape->shapeType();
1602     // Allow to select edges, faces and solids.
1603     if (aShapeType != GeomAPI_Shape::EDGE &&
1604         aShapeType != GeomAPI_Shape::FACE &&
1605         aShapeType != GeomAPI_Shape::SOLID &&
1606         aShapeType != GeomAPI_Shape::COMPSOLID &&
1607         aShapeType != GeomAPI_Shape::COMPOUND) {
1608       theError = "Error: selected shape has the wrong type.";
1609       return false;
1610     }
1611   }
1612
1613   return true;
1614 }
1615 // LCOV_EXCL_STOP
1616
1617 //==================================================================================================
1618 // LCOV_EXCL_START
1619 bool FeaturesPlugin_ValidatorBooleanFuseSelection::isValid(
1620   const AttributePtr& theAttribute,
1621   const std::list<std::string>& theArguments,
1622   Events_InfoMessage& theError) const
1623 {
1624   AttributeSelectionListPtr anAttrSelectionList =
1625     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1626   if (!anAttrSelectionList.get()) {
1627     theError =
1628       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1629     return false;
1630   }
1631
1632   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1633     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1634     if (!anAttrSelection.get()) {
1635       theError = "Error: Empty attribute selection.";
1636       return false;
1637     }
1638     ResultPtr aContext = anAttrSelection->context();
1639     if(!aContext.get()) {
1640       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1641       if (!aContFeat.get() || !aContFeat->results().size() ||
1642           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1643         theError = "Error: Empty selection context.";
1644         return false;
1645       }
1646     }
1647     ResultConstructionPtr aResultConstruction =
1648       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1649     if (aResultConstruction.get()) {
1650       theError = "Error: Result construction not allowed for selection.";
1651       return false;
1652     }
1653     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1654     if (!aShape.get()) {
1655       GeomShapePtr aContextShape = aContext->shape();
1656       aShape = aContextShape;
1657     }
1658     if (!aShape.get()) {
1659       theError = "Error: Empty shape.";
1660       return false;
1661     }
1662     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1663       theError = "Error: Local selection not allowed.";
1664       return false;
1665     }
1666   }
1667
1668   return true;
1669 }
1670 // LCOV_EXCL_STOP
1671
1672 //=================================================================================================
1673 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
1674   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1675   const std::list<std::string>& theArguments,
1676   Events_InfoMessage& theError) const
1677 {
1678 // LCOV_EXCL_START
1679   if (theArguments.size() != 2) {
1680     theError = "Wrong number of arguments (expected 2).";
1681     return false;
1682   }
1683 // LCOV_EXCL_STOP
1684
1685   std::shared_ptr<FeaturesPlugin_BooleanFuse> aFeature =
1686     std::dynamic_pointer_cast<FeaturesPlugin_BooleanFuse>(theFeature);
1687
1688   int anObjectsNb = 0, aToolsNb = 0;
1689
1690   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1691
1692   bool isAllInSameCompSolid = true;
1693   ResultBodyPtr aCompSolid;
1694
1695   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1696   if (anAttrSelList) {
1697     anObjectsNb = anAttrSelList->size();
1698     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex) {
1699       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1700       ResultPtr aContext = anAttr->context();
1701       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1702       if (aResCompSolidPtr.get()) {
1703         if (aCompSolid.get()) {
1704           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1705         } else {
1706           aCompSolid = aResCompSolidPtr;
1707         }
1708       } else {
1709         isAllInSameCompSolid = false;
1710         break;
1711       }
1712     }
1713   }
1714   anIt++;
1715
1716   if (aFeature->string(FeaturesPlugin_BooleanFuse::CREATION_METHOD())->value()
1717       == FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED()) {
1718     anAttrSelList = theFeature->selectionList(*anIt);
1719     if (anAttrSelList) {
1720       aToolsNb = anAttrSelList->size();
1721       if (isAllInSameCompSolid) {
1722         for (int anIndex = 0; anIndex < aToolsNb; ++anIndex) {
1723           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1724           ResultPtr aContext = anAttr->context();
1725           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1726           if (aResCompSolidPtr.get()) {
1727             if (aCompSolid.get()) {
1728               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1729             } else {
1730               aCompSolid = aResCompSolidPtr;
1731             }
1732           } else {
1733             isAllInSameCompSolid = false;
1734             break;
1735           }
1736         }
1737       }
1738     }
1739   }
1740
1741   anIt++;
1742
1743   if (anObjectsNb + aToolsNb < 2) {
1744     theError = "Not enough arguments for Fuse operation.";
1745     return false;
1746   }
1747
1748   return true;
1749 }
1750
1751 //=================================================================================================
1752 // LCOV_EXCL_START
1753 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isNotObligatory(
1754   std::string theFeature,
1755   std::string theAttribute)
1756 {
1757   if (theAttribute == "main_objects" || theAttribute == "tool_objects") {
1758     return true;
1759   }
1760
1761   return false;
1762 }
1763 // LCOV_EXCL_STOP
1764
1765 //==================================================================================================
1766 // LCOV_EXCL_START
1767 bool FeaturesPlugin_ValidatorBooleanCommonSelection::isValid(
1768   const AttributePtr& theAttribute,
1769   const std::list<std::string>& theArguments,
1770   Events_InfoMessage& theError) const
1771 {
1772   AttributeSelectionListPtr anAttrSelectionList =
1773     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1774   if (!anAttrSelectionList.get()) {
1775     theError =
1776       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1777     return false;
1778   }
1779
1780   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1781     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1782     if (!anAttrSelection.get()) {
1783       theError = "Error: Empty attribute selection.";
1784       return false;
1785     }
1786     ResultPtr aContext = anAttrSelection->context();
1787     if (!aContext.get() && !anAttrSelection->contextFeature().get()) {
1788       theError = "Error: Empty selection context.";
1789       return false;
1790     }
1791     ResultConstructionPtr aResultConstruction =
1792       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1793     if (aResultConstruction.get()) {
1794       if (theAttribute->id() != FeaturesPlugin_BooleanCommon::TOOL_LIST_ID()) {
1795         theError = "Error: Result construction not allowed for selection.";
1796         return false;
1797       }
1798     }
1799     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1800     GeomShapePtr aContextShape;
1801     if (aContext.get()) {
1802       aContextShape = aContext->shape();
1803     }
1804     if (!aShape.get()) {
1805       aShape = aContextShape;
1806     }
1807     if (!aShape.get()) {
1808       theError = "Error: Empty shape.";
1809       return false;
1810     }
1811     if (aContextShape.get() && !aShape->isEqual(aContextShape)) {
1812       theError = "Error: Local selection not allowed.";
1813       return false;
1814     }
1815
1816     if (aResultConstruction.get() && aShape->shapeType() != GeomAPI_Shape::FACE) {
1817       theError = "Error: Result construction should be plane.";
1818       return false;
1819     }
1820   }
1821
1822   return true;
1823 }
1824 // LCOV_EXCL_STOP
1825
1826 //=================================================================================================
1827 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
1828   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1829   const std::list<std::string>& theArguments,
1830   Events_InfoMessage& theError) const
1831 {
1832   if (theArguments.size() != 2) {
1833 // LCOV_EXCL_START
1834     theError = "Wrong number of arguments (expected 2).";
1835     return false;
1836 // LCOV_EXCL_STOP
1837   }
1838
1839   std::shared_ptr<FeaturesPlugin_BooleanCommon> aFeature =
1840     std::dynamic_pointer_cast<FeaturesPlugin_BooleanCommon>(theFeature);
1841
1842   int anObjectsNb = 0, aToolsNb = 0;
1843
1844   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1845
1846   bool isAllInSameCompSolid = true;
1847   ResultBodyPtr aCompSolid;
1848
1849   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1850   if (anAttrSelList) {
1851     anObjectsNb = anAttrSelList->size();
1852   }
1853
1854   bool isSimpleMode = aFeature->string(FeaturesPlugin_BooleanCommon::CREATION_METHOD())->value()
1855                       == FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE();
1856
1857   if (!isSimpleMode) {
1858     anAttrSelList = theFeature->selectionList(*anIt);
1859     if (anAttrSelList) {
1860       aToolsNb = anAttrSelList->size();
1861     }
1862   }
1863
1864   if ((isSimpleMode && anObjectsNb < 2)
1865       || (!isSimpleMode && (anObjectsNb == 0 || aToolsNb == 0))) {
1866     theError = "Not enough arguments for Fuse operation.";
1867     return false;
1868   }
1869   return true;
1870 }
1871
1872 //=================================================================================================
1873 // LCOV_EXCL_START
1874 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
1875   std::string theFeature,
1876   std::string theAttribute)
1877 {
1878   return false;
1879 }
1880 // LCOV_EXCL_STOP
1881
1882 //==================================================================================================
1883 bool FeaturesPlugin_ValidatorDefeaturingSelection::isValid(
1884     const AttributePtr& theAttribute,
1885     const std::list<std::string>& theArguments,
1886     Events_InfoMessage& theError) const
1887 {
1888   AttributeSelectionListPtr anAttrSelectionList =
1889       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1890   if (!anAttrSelectionList.get()) {
1891     // LCOV_EXCL_START
1892     theError = "Error: This validator can only work with selection list attributes.";
1893     return false;
1894     // LCOV_EXCL_STOP
1895   }
1896
1897   // Check selected entities are sub-shapes of solid or compsolid
1898   GeomShapePtr aBaseSolid;
1899   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1900     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1901     if (!anAttrSelection.get()) {
1902       theError = "Error: Empty attribute selection.";
1903       return false;
1904     }
1905     ResultPtr aContext = anAttrSelection->context();
1906     if (!aContext.get()) {
1907       theError = "Error: Empty selection context.";
1908       return false;
1909     }
1910
1911     GeomShapePtr aContextShape = aContext->shape();
1912     if (aContextShape->shapeType() != GeomAPI_Shape::SOLID) {
1913       theError = "Error: Not all selected shapes are sub-shapes of solids.";
1914       return false;
1915     }
1916   }
1917
1918   return true;
1919 }