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