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