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