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