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