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