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