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