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