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