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