]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
Salome HOME
Issue #2650: Crash when create pipe
[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     ResultConstructionPtr aResultConstruction =
145       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
146     if (aResultConstruction.get()) {
147       theError = "Error: Result construction not allowed for selection.";
148       return false;
149     }
150     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
151     if (!aShape.get() && aContext.get()) {
152       GeomShapePtr aContextShape = aContext->shape();
153       aShape = aContextShape;
154     }
155     if (!aShape.get()) {
156       theError = "Error: Empty shape.";
157       return false;
158     }
159
160     if (!aPathShape->isSubShape(aShape)) {
161       theError = "Error: Location should be a vertex subshape from path shape.";
162       return false;
163     }
164   }
165
166   return true;
167 }
168
169 //==================================================================================================
170 bool FeaturesPlugin_ValidatorPipeLocationsNumber::isValid(
171   const std::shared_ptr<ModelAPI_Feature>& theFeature,
172   const std::list<std::string>& theArguments,
173   Events_InfoMessage& theError) const
174 {
175   static const std::string aCreationMethodID = "creation_method";
176   static const std::string aBaseObjectsID = "base_objects";
177   static const std::string aLocationsID = "locations_objects";
178
179   if(theFeature->getKind() != "Pipe") {
180     theError = "Error: Feature \"%1\" does not supported by this validator.";
181     theError.arg(theFeature->getKind());
182     return false;
183   }
184
185   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
186   if(!aCreationMethodAttr.get()) {
187     theError = "Error: Could not get \"%1\" attribute.";
188     theError.arg(aCreationMethodID);
189     return false;
190   }
191
192   if(aCreationMethodAttr->value() != "locations") {
193     return true;
194   }
195
196   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
197   if(!aBaseObjectsSelectionList.get()) {
198     theError = "Error: Could not get \"%1\" attribute.";
199     theError.arg(aBaseObjectsID);
200     return false;
201   }
202
203   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
204   if(!aLocationsSelectionList.get()) {
205     theError = "Error: Could not get \"%1\" attribute.";
206     theError.arg(aBaseObjectsID);
207     return false;
208   }
209
210   if(aLocationsSelectionList->size() > 0 &&
211      aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
212     theError = "Error: Number of locations should be the same as base objects.";
213     return false;
214   }
215
216   return true;
217 }
218
219 //==================================================================================================
220 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
221                                                         const std::list<std::string>& theArguments,
222                                                         Events_InfoMessage& theError) const
223 {
224   if(theArguments.empty()) {
225     theError = "Error: Validator parameters is empty.";
226     return false;
227   }
228
229   // Checking attribute.
230   if(!isValidAttribute(theAttribute, theArguments, theError)) {
231     if(theError.empty()) {
232       theError = "Error: Attribute contains unacceptable shape.";
233     }
234     return false;
235   }
236
237   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
238   std::string anAttributeType = theAttribute->attributeType();
239   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
240     AttributeSelectionListPtr aListAttr =
241       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
242     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
243       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
244       ResultPtr aContext = aSelectionAttr->context();
245       if(!aContext.get() && !aSelectionAttr->contextFeature().get()) {
246         theError = "Error: Empty context.";
247         return false;
248       }
249
250       ResultConstructionPtr aResultConstruction =
251         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
252       if(!aResultConstruction.get()) {
253         // It is not a result construction.
254         // If shape is compound check that it contains only faces and edges.
255         GeomShapePtr aShape = aSelectionAttr->value();
256         if(!aShape.get()) {
257           if (aContext.get()) {
258             aShape = aContext->shape();
259           } else {
260             theError = "Error: Empty context.";
261             return false;
262           }
263         }
264
265         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
266           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
267             GeomShapePtr aSubShape = anIt.current();
268             if(aSubShape->shapeType() != GeomAPI_Shape::EDGE
269                 && aSubShape->shapeType() != GeomAPI_Shape::FACE) {
270               theError = "Error: Compound should contain only faces and edges.";
271               return false;
272             }
273           }
274         }
275
276         continue;
277       }
278
279       GeomShapePtr aShape = aSelectionAttr->value();
280       GeomShapePtr aContextShape = aResultConstruction->shape();
281       if(!aShape.get()) {
282         // Whole sketch selected.
283         continue;
284       } else {
285         // Object from sketch selected.
286         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
287           GeomShapePtr aWire = anExp.current();
288           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
289             theError = "Error: Wire with wrong orientation selected.";
290             return false;
291           }
292
293           if(aSelectedWiresFromObjects.isBound(aWire)) {
294             theError =
295               "Error: Objects with such wire already selected. Don't allow to select this object.";
296             return false;
297           }
298
299           aSelectedWiresFromObjects.bind(aWire, aWire);
300         }
301       }
302     }
303   }
304
305   return true;
306 }
307
308 //==================================================================================================
309 bool FeaturesPlugin_ValidatorBaseForGenerationSketchOrSketchObjects::isValid(
310   const std::shared_ptr<ModelAPI_Feature>& theFeature,
311   const std::list<std::string>& theArguments,
312   Events_InfoMessage& theError) const
313 {
314   const std::string aBaseObjectsID = theArguments.front();
315
316   AttributeSelectionListPtr aListAttr = theFeature->selectionList(aBaseObjectsID);
317   if(!aListAttr.get()) {
318     theError = "Error: Could not get \"%1\" attribute.";
319     theError.arg(aBaseObjectsID);
320     return false;
321   }
322
323   std::set<ResultConstructionPtr> aSelectedSketches;
324   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
325
326   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
327     AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
328     ResultPtr aContext = aSelectionAttr->context();
329     if(!aContext.get()) {
330       FeaturePtr aFeature = aSelectionAttr->contextFeature();
331       if (!aFeature.get() || aFeature->results().empty()) {
332         theError = "Error: Empty context.";
333         return false;
334       } else {
335         aContext = aFeature->firstResult();
336       }
337     }
338
339     ResultConstructionPtr aResultConstruction =
340       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
341     if(!aResultConstruction.get()) {
342       // It is not a result construction.
343       continue;
344     }
345
346     GeomShapePtr aShape = aSelectionAttr->value();
347     GeomShapePtr aContextShape = aResultConstruction->shape();
348     if(!aShape.get()) {
349       // Whole sketch selected.
350       aSelectedSketches.insert(aResultConstruction);
351     } else {
352       // Object from sketch selected.
353       aSelectedSketchesFromObjects.insert(aResultConstruction);
354     }
355   }
356
357
358   for(std::set<ResultConstructionPtr>::const_iterator anIt = aSelectedSketches.cbegin();
359       anIt != aSelectedSketches.cend();
360       ++anIt) {
361     ResultConstructionPtr aResultConstruction = *anIt;
362     if(aSelectedSketchesFromObjects.find(aResultConstruction) !=
363         aSelectedSketchesFromObjects.cend()) {
364       theError = "Sketch and objects from it can not be selected at the same time.";
365       return false;
366     }
367   }
368
369   return true;
370 }
371
372 //==================================================================================================
373 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
374                                                         const std::list<std::string>& theArguments,
375                                                         Events_InfoMessage& theError) const
376 {
377   if(!theAttribute.get()) {
378     theError = "Error: Empty attribute.";
379     return false;
380   }
381
382   std::string anAttributeType = theAttribute->attributeType();
383   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
384     AttributeSelectionListPtr aListAttr =
385       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
386     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
387       // If at least one attribute is invalid, the result is false.
388       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
389         return false;
390       }
391     }
392   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
393     // Getting context.
394     AttributeSelectionPtr anAttr =
395       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
396     ResultPtr aContext = anAttr->context();
397     if(!aContext.get() && !anAttr->contextFeature().get()) {
398       theError = "Error: Attribute have empty context.";
399       return false;
400     }
401
402     GeomShapePtr aShape = anAttr->value();
403     GeomShapePtr aContextShape;
404     if(!aShape.get() && aContext.get()) {
405       aContextShape = aContext->shape();
406       aShape = aContextShape;
407     }
408     if(!aShape.get()) {
409       theError = "Error: Empty shape selected";
410       return false;
411     }
412
413     ResultConstructionPtr aConstruction;
414     if (!aContext.get() && anAttr->contextFeature()->results().size() == 1) {
415       aContext = anAttr->contextFeature()->firstResult();
416     }
417     if (aContext.get())
418       aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
419     if(aConstruction.get()) {
420       // Construciotn selected. Check that is is not infinite.
421       if(aConstruction->isInfinite()) {
422         theError = "Error: Infinite constructions is not allowed as base.";
423         return false;
424       }
425
426       GeomShapePtr aContextShape = aContext->shape();
427       if(aShape->isEqual(aContextShape)) {
428         // Whole construction selected. Check that it have faces.
429         if(aConstruction->facesNum() > 0) {
430           return true;
431         }
432       } else {
433         // Shape on construction selected. Check that it is a face or wire.
434         if(aShape->shapeType() == GeomAPI_Shape::WIRE ||
435            aShape->shapeType() == GeomAPI_Shape::FACE) {
436           return true;
437         }
438       }
439
440       return false;
441     }
442
443     if(aContextShape.get() && !aShape->isEqual(aContextShape)) {
444       // Local selection on body does not allowed.
445       theError =
446         "Error: Selected shape is in the local selection. Only global selection is allowed.";
447       return false;
448     }
449
450     // Check that object is a shape with allowed type.
451     GeomValidators_ShapeType aShapeTypeValidator;
452     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
453       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
454                  "wires on sketch, whole sketch(if it has at least one face), "
455                  "and whole objects with shape types: %1";
456       std::string anArgumentString;
457       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
458         if (!anArgumentString.empty())
459           anArgumentString += ", ";
460         anArgumentString += *anIt;
461       }
462       theError.arg(anArgumentString);
463       return false;
464     }
465
466   } else {
467     theError = "Error: Attribute \"%1\" does not supported by this validator.";
468     theError.arg(anAttributeType);
469     return false;
470   }
471
472   return true;
473 }
474
475 //==================================================================================================
476 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
477                                                         const std::list<std::string>& theArguments,
478                                                         Events_InfoMessage& theError) const
479 {
480   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
481     theError = "Error: The attribute with the %1 type is not processed";
482     theError.arg(theAttribute->attributeType());
483     return false;
484   }
485   if (theArguments.size() != 2) {
486     theError = "Error: Wrong parameters in XML definition for %1 type";
487     theError.arg(theAttribute->attributeType());
488     return false;
489   }
490   // first argument is for the base attribute, second - for skipping feature kind
491   std::list<std::string>::const_iterator anIt = theArguments.begin();
492   std::string aBaseAttributeId = *anIt;
493   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
494   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
495   if (!aBaseAttribute.get()) {
496     theError = "Wrong parameters in XML definition for %1 type";
497     theError.arg(theAttribute->attributeType());
498     return false;
499   }
500   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
501     // this validator is not necessary anymore
502     return true;
503
504   anIt++;
505   std::string aFeatureAttributeKind = *anIt;
506   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
507   // check whether the selection is on the sketch
508   std::list<std::string> anArguments;
509   anArguments.push_back(aFeatureAttributeKind);
510
511   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
512   bool aPlanarFace = false;
513   // check if selection has Face selected
514   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
515   anArguments.clear();
516   anArguments.push_back("face");
517   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
518
519   bool aValid = !aFeatureKind && aPlanarFace;
520   return aValid;
521 }
522
523 //==================================================================================================
524 bool FeaturesPlugin_ValidatorExtrusionDir::isValid(
525                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
526                                                const std::list<std::string>& theArguments,
527                                                Events_InfoMessage& theError) const
528 {
529   if(theArguments.size() != 2) {
530     theError = "Error: Validator should be used with 2 parameters for extrusion.";
531     return false;
532   }
533
534   std::list<std::string>::const_iterator
535     anArgsIt = theArguments.begin(), aLast = theArguments.end();
536
537   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
538   ++anArgsIt;
539
540   GeomShapePtr aDirShape;
541   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
542   if(aSelAttr.get()) {
543     aDirShape = aSelAttr->value();
544     if(!aDirShape.get()) {
545       ResultPtr aContext = aSelAttr->context();
546       if(!aContext.get()) {
547         FeaturePtr aFeature = aSelAttr->contextFeature();
548         if (aFeature.get() && !aFeature->results().empty()) {
549           aContext = aFeature->firstResult();
550         }
551       }
552
553       if(aContext.get()) {
554         aDirShape = aContext->shape();
555       }
556     }
557   }
558
559   if(!aDirShape.get()) {
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 (!aShape.get() && aContext.get()) {
1695       aContextShape = aContext->shape();
1696       aShape = aContextShape;
1697     }
1698     if (!aShape.get()) {
1699       theError = "Error: Empty shape.";
1700       return false;
1701     }
1702     if (aContextShape.get() && !aShape->isEqual(aContextShape)) {
1703       theError = "Error: Local selection not allowed.";
1704       return false;
1705     }
1706
1707     if (aResultConstruction.get() && aShape->shapeType() != GeomAPI_Shape::FACE) {
1708       theError = "Error: Result construction should be plane.";
1709       return false;
1710     }
1711   }
1712
1713   return true;
1714 }
1715
1716 //=================================================================================================
1717 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
1718   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1719   const std::list<std::string>& theArguments,
1720   Events_InfoMessage& theError) const
1721 {
1722   if (theArguments.size() != 2) {
1723     theError = "Wrong number of arguments (expected 2).";
1724     return false;
1725   }
1726
1727   std::shared_ptr<FeaturesPlugin_BooleanCommon> aFeature =
1728     std::dynamic_pointer_cast<FeaturesPlugin_BooleanCommon>(theFeature);
1729
1730   int anObjectsNb = 0, aToolsNb = 0;
1731
1732   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1733
1734   bool isAllInSameCompSolid = true;
1735   ResultBodyPtr aCompSolid;
1736
1737   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1738   if (anAttrSelList) {
1739     anObjectsNb = anAttrSelList->size();
1740   }
1741
1742   bool isSimpleMode = aFeature->string(FeaturesPlugin_BooleanCommon::CREATION_METHOD())->value()
1743                       == FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE();
1744
1745   if (!isSimpleMode) {
1746     anAttrSelList = theFeature->selectionList(*anIt);
1747     if (anAttrSelList) {
1748       aToolsNb = anAttrSelList->size();
1749     }
1750   }
1751
1752   if ((isSimpleMode && anObjectsNb < 2)
1753       || (!isSimpleMode && (anObjectsNb == 0 || aToolsNb == 0))) {
1754     theError = "Not enough arguments for Fuse operation.";
1755     return false;
1756   }
1757   return true;
1758 }
1759
1760 //=================================================================================================
1761 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
1762   std::string theFeature,
1763   std::string theAttribute)
1764 {
1765   return false;
1766 }