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