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