]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
Salome HOME
Apply the coding rules standards
[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     {
843       if ((*anIt)->isEqual(aShapeToAdd)) {
844         isSameFound = true;
845         break;
846       }
847     }
848     if (!isSameFound) {
849       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
850       return false;
851     }
852   }
853
854   return true;
855 }
856
857 //==================================================================================================
858 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
859   const std::shared_ptr<ModelAPI_Feature>& theFeature,
860   const std::list<std::string>& theArguments,
861   Events_InfoMessage& theError) const
862 {
863   static const std::string aBaseShapeID = "base_shape";
864   static const std::string aSubShapesID = "subshapes_to_keep";
865
866   if(theFeature->getKind() != "Remove_SubShapes") {
867     theError = "Error: Feature \"%1\" does not supported by this validator.";
868     theError.arg(theFeature->getKind());
869     return false;
870   }
871
872   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
873   if(!aShapeAttrSelection.get()) {
874     theError = "Error: Could not get \"%1\" attribute.";
875     theError.arg(aBaseShapeID);
876     return false;
877   }
878
879   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
880   if(!aSubShapesAttrList.get()) {
881     theError = "Error: Could not get \"%1\" attribute.";
882     theError.arg(aSubShapesID);
883     return false;
884   }
885
886   // Copy base shape.
887   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
888   if(!aBaseShape.get()) {
889     theError = "Error: Base shape is empty.";
890     return false;
891   }
892   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
893
894   if (aSubShapesAttrList->size() == 0) {
895     theError = "Error: Resulting shape is not valid.";
896     return false;
897   }
898
899   // Copy sub-shapes from list to new shape.
900   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
901     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
902     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
903     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
904   }
905
906   // Check new shape.
907   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
908     theError = "Error: Resulting shape is not valid.";
909     return false;
910   }
911
912   return true;
913 }
914
915 //==================================================================================================
916 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
917                                                      const std::list<std::string>& theArguments,
918                                                      Events_InfoMessage& theError) const
919 {
920   AttributeSelectionListPtr aBaseObjectsAttrList =
921     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
922   if(!aBaseObjectsAttrList.get()) {
923     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
924     theError.arg(FeaturesPlugin_Union::ID());
925     return false;
926   }
927
928   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
929     bool isSameFound = false;
930     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
931     ResultPtr aContext = anAttrSelectionInList->context();
932     if (!aContext.get()) {
933       theError = "Error: selection is invalid.";
934       return false;
935     }
936
937     ResultConstructionPtr aConstruction =
938       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
939     if(aConstruction.get()) {
940       theError = "Error: Result construction not allowed for selection.";
941       return false;
942     }
943
944     GeomShapePtr aShape = anAttrSelectionInList->value();
945     GeomShapePtr aContextShape = aContext->shape();
946     if (aShape.get() && aContextShape.get() && !aContextShape->isEqual(aShape)) {
947       theError = "Error: Local selection not allowed.";
948       return false;
949     }
950
951     ResultBodyPtr aResult =
952       std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
953     if(!aResult.get()) {
954       continue;
955     }
956
957     if(aResult->numberOfSubs() > 0) {
958       theError = "Error: Whole compsolids not allowed for selection.";
959       return false;
960     }
961   }
962
963   return true;
964 }
965
966 //==================================================================================================
967 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
968   const std::shared_ptr<ModelAPI_Feature>& theFeature,
969   const std::list<std::string>& theArguments,
970   Events_InfoMessage& theError) const
971 {
972   // Check feature kind.
973   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
974     theError = "Error: This validator supports only \"%1\" feature.";
975     theError.arg(FeaturesPlugin_Union::ID());
976     return false;
977   }
978
979   // Get base objects attribute list.
980   AttributeSelectionListPtr aBaseObejctsAttrList =
981     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
982   if(!aBaseObejctsAttrList.get()) {
983     theError = "Error: Could not get \"%1\" attribute.";
984     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
985     return false;
986   }
987
988   // Get all shapes.
989   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::COMPSOLID;
990   ListOfShape aBaseShapesList;
991   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
992     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
993     GeomShapePtr aShape = anAttrSelectionInList->value();
994     if (!aShape.get()) {
995       continue;
996     }
997     aBaseShapesList.push_back(aShape);
998     aType = aShape->shapeType() == GeomAPI_Shape::FACE ? GeomAPI_Shape::SHELL :
999                                                          GeomAPI_Shape::COMPSOLID;
1000   }
1001
1002   // Make compound and find connected.
1003   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
1004   ListOfShape aCombined, aFree;
1005   GeomAlgoAPI_ShapeTools::combineShapes(
1006     aCompound,
1007     aType,
1008     aCombined,
1009     aFree);
1010
1011   if(aFree.size() > 0 || aCombined.size() > 1) {
1012     theError = "Error: Not all shapes have shared topology.";
1013     return false;
1014   }
1015
1016   return true;
1017 }
1018
1019 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
1020                                             const std::list<std::string>& theArguments,
1021                                             Events_InfoMessage& theError) const
1022 {
1023   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1024     theError = "Error: The attribute with the %1 type is not processed";
1025     theError.arg(theAttribute->attributeType());
1026     return false;
1027   }
1028
1029   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
1030                                                                                (theAttribute);
1031   ObjectPtr aRefObject = aRefAttribute->value();
1032   if (!aRefObject.get()) {
1033     theError = "Error: Empty feature.";
1034     return false;
1035   }
1036
1037   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
1038   if (!aRefFeature.get()) {
1039     theError = "Error: Empty feature.";
1040     return false;
1041   }
1042   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
1043   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
1044
1045   size_t aConcealedResults = aResults.size();
1046   if (!aConcealedResults && !theArguments.empty()) {
1047     // find if these results are touched by the feature in another attribute
1048     std::list<std::string>::const_iterator anIt = theArguments.begin();
1049     std::string aRecoveredList = *anIt;
1050     if (!aRecoveredList.empty()) {
1051       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
1052                                  theAttribute->owner()->data()->reflist(aRecoveredList);
1053       if (aParameterList.get())
1054         aConcealedResults = aParameterList->size();
1055     }
1056   }
1057
1058   if (aConcealedResults == 0)
1059     theError = "Error: No concealed results.";
1060
1061   return theError.empty();
1062 }
1063
1064 bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
1065                                                const std::list<std::string>& theArguments,
1066                                                Events_InfoMessage& theError) const
1067 {
1068   static std::list<std::string> aEdgeArg(1, "circle");
1069   static std::list<std::string> aFaceArg(1, "cylinder");
1070
1071   Events_InfoMessage aError;
1072   bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
1073   if (!isValid) {
1074     isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
1075     if (!isValid)
1076       theError = "The shape neither circle nor cylinder";
1077   }
1078   return isValid;
1079 }
1080
1081 //=================================================================================================
1082 bool FeaturesPlugin_ValidatorBooleanArguments::isValid(
1083   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1084   const std::list<std::string>& theArguments,
1085   Events_InfoMessage& theError) const
1086 {
1087   if (theArguments.size() != 2)
1088   {
1089     theError = "Wrong number of arguments (expected 2).";
1090     return false;
1091   }
1092
1093   int anObjectsNb = 0, aToolsNb = 0;
1094   //int anOperationType = 0;
1095
1096   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1097
1098   bool isAllInSameCompSolid = true;
1099   ResultBodyPtr aCompSolid;
1100
1101   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1102   if (anAttrSelList)
1103   {
1104     anObjectsNb = anAttrSelList->size();
1105     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex)
1106     {
1107       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1108       ResultPtr aContext = anAttr->context();
1109       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1110       if (aResCompSolidPtr.get())
1111       {
1112         if (aCompSolid.get())
1113         {
1114           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1115         }
1116         else
1117         {
1118           aCompSolid = aResCompSolidPtr;
1119         }
1120       }
1121       else
1122       {
1123         isAllInSameCompSolid = false;
1124         break;
1125       }
1126     }
1127   }
1128   anIt++;
1129
1130
1131   anAttrSelList = theFeature->selectionList(*anIt);
1132   if (anAttrSelList)
1133   {
1134     aToolsNb = anAttrSelList->size();
1135     if (isAllInSameCompSolid)
1136     {
1137       for (int anIndex = 0; anIndex < aToolsNb; ++anIndex)
1138       {
1139         AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1140         ResultPtr aContext = anAttr->context();
1141         ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1142         if (aResCompSolidPtr.get())
1143         {
1144           if (aCompSolid.get())
1145           {
1146             isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1147           }
1148           else
1149           {
1150             aCompSolid = aResCompSolidPtr;
1151           }
1152         }
1153         else
1154         {
1155           isAllInSameCompSolid = false;
1156           break;
1157         }
1158       }
1159     }
1160   }
1161   anIt++;
1162
1163   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1164     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1165   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1166
1167   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1168   {
1169     // Fuse operation
1170     if (anObjectsNb + aToolsNb < 2)
1171     {
1172       theError = "Not enough arguments for Fuse operation.";
1173       return false;
1174     }
1175     else if (isAllInSameCompSolid)
1176     {
1177       theError = "Operations only between sub-shapes of the same shape not allowed.";
1178       return false;
1179     }
1180   }
1181   else
1182   {
1183     if (anObjectsNb < 1)
1184     {
1185       theError = "Objects not selected.";
1186       return false;
1187     }
1188     if (aToolsNb < 1)
1189     {
1190       theError = "Tools not selected.";
1191       return false;
1192     }
1193     if (isAllInSameCompSolid)
1194     {
1195       theError = "Operations only between sub-shapes of the same shape not allowed.";
1196       return false;
1197     }
1198   }
1199
1200   return true;
1201 }
1202
1203 //=================================================================================================
1204 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1205                                                                std::string theAttribute)
1206 {
1207   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1208   {
1209     return true;
1210   }
1211
1212   return false;
1213 }
1214
1215 //==================================================================================================
1216 bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
1217   const AttributePtr& theAttribute,
1218   const std::list<std::string>& theArguments,
1219   Events_InfoMessage& theError) const
1220 {
1221   std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
1222     std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
1223
1224   AttributeSelectionListPtr anAttrSelectionList =
1225     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1226   if (!aFeature.get() || !anAttrSelectionList.get()) {
1227     theError =
1228       "Error: Validator used in wrong feature or attribute";
1229     return false;
1230   }
1231
1232   AttributeSelectionListPtr anOtherAttrSelectionList;
1233   if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
1234     anOtherAttrSelectionList =
1235       aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
1236   } else {
1237     anOtherAttrSelectionList =
1238       aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
1239   }
1240
1241   GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
1242   GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
1243   GeomPlanePtr aFacesPln;
1244
1245   for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
1246     AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
1247
1248     if (anAttrSelection->contextFeature().get()) {
1249       theError = "Error: Features not allowed for selection.";
1250       return false;
1251     }
1252
1253     ResultPtr aContext = anAttrSelection->context();
1254     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1255     GeomShapePtr aContextShape = aContext->shape();
1256     if (!aShape.get()) {
1257       aShape = aContextShape;
1258     }
1259
1260     if (aShape->isSolid() || aShape->isCompSolid()) {
1261       aSelectedShapesType = GeomAPI_Shape::SOLID;
1262       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1263       if (aResCompSolidPtr.get()) {
1264         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1265         aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
1266       }
1267     } else {
1268       aSelectedShapesType = GeomAPI_Shape::FACE;
1269       GeomAPI_Face aFace(aShape);
1270       aFacesPln = aFace.getPlane();
1271       break;
1272     }
1273   }
1274
1275   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1276     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1277     if (!anAttrSelection.get()) {
1278       theError = "Error: Empty attribute selection.";
1279       return false;
1280     }
1281
1282     if (anAttrSelection->contextFeature().get()) {
1283       theError = "Error: Features not allowed for selection.";
1284       return false;
1285     }
1286
1287     ResultPtr aContext = anAttrSelection->context();
1288     if(!aContext.get()) {
1289       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1290       if (!aContFeat.get() || !aContFeat->results().size() ||
1291           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1292         theError = "Error: Empty selection context.";
1293         return false;
1294       }
1295     }
1296     ResultConstructionPtr aResultConstruction =
1297       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1298     if (aResultConstruction.get()) {
1299       theError = "Error: Result construction not allowed for selection.";
1300       return false;
1301     }
1302     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1303     GeomShapePtr aContextShape = aContext->shape();
1304     if (!aShape.get()) {
1305       aShape = aContextShape;
1306     }
1307     if (!aShape.get()) {
1308       theError = "Error: Empty shape.";
1309       return false;
1310     }
1311     if (!aShape->isEqual(aContextShape)) {
1312       theError = "Error: Local selection not allowed.";
1313       return false;
1314     }
1315
1316     if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
1317       // Other list is empty.
1318       if (aShape->isSolid() || aShape->isCompSolid()) {
1319         aSelectedShapesType = GeomAPI_Shape::SOLID;
1320       } else {
1321         aSelectedShapesType = GeomAPI_Shape::FACE;
1322         GeomAPI_Face aFace(aShape);
1323         aFacesPln = aFace.getPlane();
1324
1325         if (!aFacesPln.get()) {
1326           theError = "Error: Only planar faces allowed.";
1327           return false;
1328         }
1329       }
1330
1331       continue;
1332     } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
1333       if (!aShape->isSolid() && !aShape->isCompSolid()) {
1334         theError = "Error: Selected shapes should have the same type.";
1335         return false;
1336       }
1337
1338       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1339       if (aResCompSolidPtr.get()) {
1340         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1341         if (aSelectedCompSolidsInOtherList.isBound(aCompSolidShape)) {
1342           theError = "Error: Solids from compsolid in other list not allowed.";
1343           return false;
1344         }
1345       }
1346     } else {
1347       GeomAPI_Face aFace(aShape);
1348       GeomPlanePtr aPln = aFace.getPlane();
1349
1350       if (!aPln.get()) {
1351         theError = "Error: Only planar faces allowed.";
1352         return false;
1353       }
1354
1355       if (!aFacesPln->isCoincident(aPln)) {
1356         theError = "Error: Only coincident faces allowed.";
1357         return false;
1358       }
1359     }
1360   }
1361
1362   return true;
1363 }
1364
1365 //==================================================================================================
1366 bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttribute,
1367                                                    const std::list<std::string>& theArguments,
1368                                                    Events_InfoMessage& theError) const
1369 {
1370   if (!theAttribute.get()) {
1371     theError = "Error: empty selection.";
1372     return false;
1373   }
1374   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1375   AttributeSelectionListPtr anAttrSelectionList =
1376     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1377   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1378     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1379     if (!anAttrSelection.get()) {
1380       theError = "Error: empty attribute selection.";
1381       return false;
1382     }
1383     ResultPtr aContext = anAttrSelection->context();
1384     if(!aContext.get()) {
1385       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1386       if (!aContFeat.get() || !aContFeat->results().size() ||
1387           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1388         theError = "Error: Empty selection context.";
1389         return false;
1390       }
1391     }
1392     FeaturePtr aFeature = anAttrSelection->contextFeature().get() ?
1393       anAttrSelection->contextFeature() : ModelAPI_Feature::feature(aContext);
1394     if (!aFeature.get()) {
1395       theError = "Error: empty feature.";
1396       return false;
1397     }
1398     std::string aFeatureKind = aFeature->getKind();
1399     if (aFeatureKind == "Sketch" ||
1400         aFeatureKind == "Plane" ||
1401         aFeatureKind == "Axis") {
1402       theError = "Error: %1 shape is not allowed for selection.";
1403       theError.arg(aFeatureKind);
1404       return false;
1405     }
1406     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1407     if (!aShape.get()) {
1408       GeomShapePtr aContextShape = aContext->shape();
1409       aShape = aContextShape;
1410     }
1411     if (!aShape.get()) {
1412       theError = "Error: empty shape.";
1413       return false;
1414     }
1415     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1416       theError = "Error: Local selection not allowed.";
1417       return false;
1418     }
1419
1420     int aShapeType = aShape->shapeType();
1421     // Allow to select edges, faces and solids.
1422     if (aShapeType != GeomAPI_Shape::EDGE &&
1423         aShapeType != GeomAPI_Shape::FACE &&
1424         aShapeType != GeomAPI_Shape::SOLID &&
1425         aShapeType != GeomAPI_Shape::COMPSOLID &&
1426         aShapeType != GeomAPI_Shape::COMPOUND) {
1427       theError = "Error: selected shape has the wrong type.";
1428       return false;
1429     }
1430   }
1431
1432   return true;
1433 }
1434
1435 //==================================================================================================
1436 bool FeaturesPlugin_ValidatorBooleanFuseSelection::isValid(
1437   const AttributePtr& theAttribute,
1438   const std::list<std::string>& theArguments,
1439   Events_InfoMessage& theError) const
1440 {
1441   AttributeSelectionListPtr anAttrSelectionList =
1442     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1443   if (!anAttrSelectionList.get()) {
1444     theError =
1445       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1446     return false;
1447   }
1448
1449   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1450     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1451     if (!anAttrSelection.get()) {
1452       theError = "Error: Empty attribute selection.";
1453       return false;
1454     }
1455     ResultPtr aContext = anAttrSelection->context();
1456     if(!aContext.get()) {
1457       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1458       if (!aContFeat.get() || !aContFeat->results().size() ||
1459           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1460         theError = "Error: Empty selection context.";
1461         return false;
1462       }
1463     }
1464     ResultConstructionPtr aResultConstruction =
1465       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1466     if (aResultConstruction.get()) {
1467       theError = "Error: Result construction not allowed for selection.";
1468       return false;
1469     }
1470     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1471     if (!aShape.get()) {
1472       GeomShapePtr aContextShape = aContext->shape();
1473       aShape = aContextShape;
1474     }
1475     if (!aShape.get()) {
1476       theError = "Error: Empty shape.";
1477       return false;
1478     }
1479     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1480       theError = "Error: Local selection not allowed.";
1481       return false;
1482     }
1483   }
1484
1485   return true;
1486 }
1487
1488 //=================================================================================================
1489 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
1490   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1491   const std::list<std::string>& theArguments,
1492   Events_InfoMessage& theError) const
1493 {
1494   if (theArguments.size() != 2) {
1495     theError = "Wrong number of arguments (expected 2).";
1496     return false;
1497   }
1498
1499   std::shared_ptr<FeaturesPlugin_BooleanFuse> aFeature =
1500     std::dynamic_pointer_cast<FeaturesPlugin_BooleanFuse>(theFeature);
1501
1502   int anObjectsNb = 0, aToolsNb = 0;
1503
1504   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1505
1506   bool isAllInSameCompSolid = true;
1507   ResultBodyPtr aCompSolid;
1508
1509   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1510   if (anAttrSelList) {
1511     anObjectsNb = anAttrSelList->size();
1512     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex) {
1513       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1514       ResultPtr aContext = anAttr->context();
1515       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1516       if (aResCompSolidPtr.get()) {
1517         if (aCompSolid.get()) {
1518           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1519         } else {
1520           aCompSolid = aResCompSolidPtr;
1521         }
1522       } else {
1523         isAllInSameCompSolid = false;
1524         break;
1525       }
1526     }
1527   }
1528   anIt++;
1529
1530   if (aFeature->string(FeaturesPlugin_BooleanFuse::CREATION_METHOD())->value()
1531       == FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED()) {
1532     anAttrSelList = theFeature->selectionList(*anIt);
1533     if (anAttrSelList) {
1534       aToolsNb = anAttrSelList->size();
1535       if (isAllInSameCompSolid) {
1536         for (int anIndex = 0; anIndex < aToolsNb; ++anIndex) {
1537           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1538           ResultPtr aContext = anAttr->context();
1539           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1540           if (aResCompSolidPtr.get()) {
1541             if (aCompSolid.get()) {
1542               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1543             } else {
1544               aCompSolid = aResCompSolidPtr;
1545             }
1546           } else {
1547             isAllInSameCompSolid = false;
1548             break;
1549           }
1550         }
1551       }
1552     }
1553   }
1554
1555   anIt++;
1556
1557   if (anObjectsNb + aToolsNb < 2) {
1558     theError = "Not enough arguments for Fuse operation.";
1559     return false;
1560   } else if (isAllInSameCompSolid) {
1561     theError = "Operations only between sub-shapes of the same shape not allowed.";
1562     return false;
1563   }
1564
1565   return true;
1566 }
1567
1568 //=================================================================================================
1569 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isNotObligatory(
1570   std::string theFeature,
1571   std::string theAttribute)
1572 {
1573   if (theAttribute == "main_objects" || theAttribute == "tool_objects") {
1574     return true;
1575   }
1576
1577   return false;
1578 }
1579
1580 //==================================================================================================
1581 bool FeaturesPlugin_ValidatorBooleanCommonSelection::isValid(
1582   const AttributePtr& theAttribute,
1583   const std::list<std::string>& theArguments,
1584   Events_InfoMessage& theError) const
1585 {
1586   AttributeSelectionListPtr anAttrSelectionList =
1587     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1588   if (!anAttrSelectionList.get()) {
1589     theError =
1590       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1591     return false;
1592   }
1593
1594   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1595     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1596     if (!anAttrSelection.get()) {
1597       theError = "Error: Empty attribute selection.";
1598       return false;
1599     }
1600     ResultPtr aContext = anAttrSelection->context();
1601     if (!aContext.get() && !anAttrSelection->contextFeature().get()) {
1602       theError = "Error: Empty selection context.";
1603       return false;
1604     }
1605     ResultConstructionPtr aResultConstruction =
1606       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1607     if (aResultConstruction.get()) {
1608       if (theAttribute->id() != FeaturesPlugin_BooleanCommon::TOOL_LIST_ID()) {
1609         theError = "Error: Result construction not allowed for selection.";
1610         return false;
1611       }
1612     }
1613     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1614     GeomShapePtr aContextShape;
1615     if (!aShape.get() && aContext.get()) {
1616       aContextShape = aContext->shape();
1617       aShape = aContextShape;
1618     }
1619     if (!aShape.get()) {
1620       theError = "Error: Empty shape.";
1621       return false;
1622     }
1623     if (aContextShape.get() && !aShape->isEqual(aContextShape)) {
1624       theError = "Error: Local selection not allowed.";
1625       return false;
1626     }
1627
1628     if (aResultConstruction.get() && aShape->shapeType() != GeomAPI_Shape::FACE) {
1629       theError = "Error: Result construction should be plane.";
1630       return false;
1631     }
1632   }
1633
1634   return true;
1635 }
1636
1637 //=================================================================================================
1638 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
1639   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1640   const std::list<std::string>& theArguments,
1641   Events_InfoMessage& theError) const
1642 {
1643   if (theArguments.size() != 2) {
1644     theError = "Wrong number of arguments (expected 2).";
1645     return false;
1646   }
1647
1648   std::shared_ptr<FeaturesPlugin_BooleanCommon> aFeature =
1649     std::dynamic_pointer_cast<FeaturesPlugin_BooleanCommon>(theFeature);
1650
1651   int anObjectsNb = 0, aToolsNb = 0;
1652
1653   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1654
1655   bool isAllInSameCompSolid = true;
1656   ResultBodyPtr aCompSolid;
1657
1658   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1659   if (anAttrSelList) {
1660     anObjectsNb = anAttrSelList->size();
1661   }
1662
1663   bool isSimpleMode = aFeature->string(FeaturesPlugin_BooleanCommon::CREATION_METHOD())->value()
1664                       == FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE();
1665
1666   if (!isSimpleMode) {
1667     anAttrSelList = theFeature->selectionList(*anIt);
1668     if (anAttrSelList) {
1669       aToolsNb = anAttrSelList->size();
1670     }
1671   }
1672
1673   if ((isSimpleMode && anObjectsNb < 2)
1674       || (!isSimpleMode && (anObjectsNb == 0 || aToolsNb == 0))) {
1675     theError = "Not enough arguments for Fuse operation.";
1676     return false;
1677   }
1678   return true;
1679 }
1680
1681 //=================================================================================================
1682 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
1683   std::string theFeature,
1684   std::string theAttribute)
1685 {
1686   return false;
1687 }