Salome HOME
ee82a62f5c8c415cd3a897a4818c44d102358822
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
1 // Copyright (C) 2014-2019  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 email : webmaster.salome@opencascade.com
18 //
19
20 #include "FeaturesPlugin_Validators.h"
21
22 #include "FeaturesPlugin_Boolean.h"
23 #include "FeaturesPlugin_BooleanFuse.h"
24 #include "FeaturesPlugin_BooleanCommon.h"
25 #include "FeaturesPlugin_BooleanSmash.h"
26 #include "FeaturesPlugin_Pipe.h"
27 #include "FeaturesPlugin_Union.h"
28
29 #include <Events_InfoMessage.h>
30
31 #include <ModelAPI_Attribute.h>
32 #include <ModelAPI_AttributeInteger.h>
33 #include <ModelAPI_AttributeSelectionList.h>
34 #include <ModelAPI_AttributeString.h>
35 #include <ModelAPI_AttributeReference.h>
36 #include <ModelAPI_AttributeRefList.h>
37 #include <ModelAPI_Feature.h>
38 #include <ModelAPI_ResultBody.h>
39 #include <ModelAPI_ResultConstruction.h>
40 #include <ModelAPI_Tools.h>
41
42 #include <GeomValidators_BodyShapes.h>
43 #include <GeomValidators_Face.h>
44 #include <GeomValidators_FeatureKind.h>
45 #include <GeomValidators_ShapeType.h>
46
47 #include <GeomAPI_DataMapOfShapeShape.h>
48 #include <GeomAPI_Lin.h>
49 #include <GeomAPI_PlanarEdges.h>
50 #include <GeomAPI_Pln.h>
51 #include <GeomAPI_ShapeExplorer.h>
52 #include <GeomAPI_ShapeIterator.h>
53
54 #include <GeomAlgoAPI_CompoundBuilder.h>
55 #include <GeomAlgoAPI_ShapeBuilder.h>
56 #include <GeomAlgoAPI_ShapeTools.h>
57 #include <GeomAlgoAPI_WireBuilder.h>
58
59 #define _USE_MATH_DEFINES
60 #include <math.h>
61
62 //==================================================================================================
63 bool FeaturesPlugin_ValidatorPipePath::isValid(const AttributePtr& theAttribute,
64                                                const std::list<std::string>& theArguments,
65                                                Events_InfoMessage& theError) const
66 {
67   AttributeSelectionPtr aPathAttrSelection =
68     std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
69   if(!aPathAttrSelection.get()) {
70 // LCOV_EXCL_START
71     theError = "Error: This validator can only work with path selector in \"Pipe\" feature.";
72     return false;
73 // LCOV_EXCL_STOP
74   }
75
76   GeomShapePtr aPathShape = aPathAttrSelection->value();
77   ResultPtr aContext = aPathAttrSelection->context();
78   if(!aContext.get()) {
79     theError = "Error: Empty context.";
80     return false;
81   }
82   GeomShapePtr aContextShape = aContext->shape();
83   if(aPathShape.get() && aPathShape->shapeType() == GeomAPI_Shape::WIRE &&
84       !aPathShape->isEqual(aContextShape)) {
85     theError = "Error: Local selection of wires not allowed.";
86     return false;
87   }
88
89   return true;
90 }
91
92 //==================================================================================================
93 bool FeaturesPlugin_ValidatorPipeLocations::isValid(const AttributePtr& theAttribute,
94                                                     const std::list<std::string>& theArguments,
95                                                     Events_InfoMessage& theError) const
96 {
97   AttributeSelectionListPtr anAttrSelectionList =
98     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
99   if(!anAttrSelectionList.get()) {
100 // LCOV_EXCL_START
101     theError =
102       "Error: This validator can only work with selection list attributes in \"Pipe\" feature.";
103     return false;
104 // LCOV_EXCL_STOP
105   }
106   std::shared_ptr<FeaturesPlugin_Pipe> aFeature =
107     std::dynamic_pointer_cast<FeaturesPlugin_Pipe>(theAttribute->owner());
108
109   AttributeSelectionPtr aPathSelection = aFeature->selection(FeaturesPlugin_Pipe::PATH_OBJECT_ID());
110   if (!aPathSelection.get()) {
111 // LCOV_EXCL_START
112     theError = "Error: Path not selected.";
113     return false;
114 // LCOV_EXCL_STOP
115   }
116
117   GeomShapePtr aPathShape = aPathSelection->value();
118   if (!aPathShape.get()) {
119     ResultPtr aContext = aPathSelection->context();
120     if (!aContext.get()) {
121       FeaturePtr aContFeat = aPathSelection->contextFeature();
122       if (!aContFeat.get() || !aContFeat->results().size()) {
123         theError = "Error: Empty selection context.";
124         return false;
125       }
126     }
127     aPathShape = aContext->shape();
128   }
129
130   if (!aPathShape.get()) {
131     theError = "Error: Empty path shape.";
132     return false;
133   }
134
135   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
136     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
137     if (!anAttrSelection.get()) {
138       theError = "Error: Empty attribute selection.";
139       return false;
140     }
141     ResultPtr aContext = anAttrSelection->context();
142     if (!aContext.get()) {
143       FeaturePtr aContFeat = anAttrSelection->contextFeature();
144       if (!aContFeat.get() || !aContFeat->results().size()) {
145         theError = "Error: Empty selection context.";
146         return false;
147       }
148     }
149     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
150     if (!aShape.get() && aContext.get()) {
151       GeomShapePtr aContextShape = aContext->shape();
152       aShape = aContextShape;
153     }
154     if (!aShape.get()) {
155       theError = "Error: Empty shape.";
156       return false;
157     }
158
159     if (!aPathShape->isSubShape(aShape)) {
160       theError = "Error: Location should be a vertex subshape from path shape.";
161       return false;
162     }
163   }
164
165   return true;
166 }
167
168 //==================================================================================================
169 // LCOV_EXCL_START
170 bool FeaturesPlugin_ValidatorPipeLocationsNumber::isValid(
171   const std::shared_ptr<ModelAPI_Feature>& theFeature,
172   const std::list<std::string>& theArguments,
173   Events_InfoMessage& theError) const
174 {
175   static const std::string aCreationMethodID = "creation_method";
176   static const std::string aBaseObjectsID = "base_objects";
177   static const std::string aLocationsID = "locations_objects";
178
179   if(theFeature->getKind() != "Pipe") {
180     theError = "Error: Feature \"%1\" does not supported by this validator.";
181     theError.arg(theFeature->getKind());
182     return false;
183   }
184
185   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
186   if(!aCreationMethodAttr.get()) {
187     theError = "Error: Could not get \"%1\" attribute.";
188     theError.arg(aCreationMethodID);
189     return false;
190   }
191
192   if(aCreationMethodAttr->value() != "locations") {
193     return true;
194   }
195
196   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
197   if(!aBaseObjectsSelectionList.get()) {
198     theError = "Error: Could not get \"%1\" attribute.";
199     theError.arg(aBaseObjectsID);
200     return false;
201   }
202
203   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
204   if(!aLocationsSelectionList.get()) {
205     theError = "Error: Could not get \"%1\" attribute.";
206     theError.arg(aBaseObjectsID);
207     return false;
208   }
209
210   if(aLocationsSelectionList->size() > 0 &&
211      aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
212     theError = "Error: Number of locations should be the same as base objects.";
213     return false;
214   }
215
216   return true;
217 }
218 // LCOV_EXCL_STOP
219
220 //==================================================================================================
221 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
222                                                         const std::list<std::string>& theArguments,
223                                                         Events_InfoMessage& theError) const
224 {
225 // LCOV_EXCL_START
226   if(theArguments.empty()) {
227     theError = "Error: Validator parameters is empty.";
228     return false;
229   }
230 // LCOV_EXCL_STOP
231
232   // Checking attribute.
233   if(!isValidAttribute(theAttribute, theArguments, theError)) {
234     if(theError.empty()) {
235       theError = "Error: Attribute contains unacceptable shape.";
236     }
237     return false;
238   }
239
240   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
241   std::string anAttributeType = theAttribute->attributeType();
242   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
243     AttributeSelectionListPtr aListAttr =
244       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
245     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
246       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
247       ResultPtr aContext = aSelectionAttr->context();
248       if(!aContext.get() && !aSelectionAttr->contextFeature().get()) {
249         theError = "Error: Empty context.";
250         return false;
251       }
252
253       ResultConstructionPtr aResultConstruction =
254         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
255       if(!aResultConstruction.get()) {
256         // It is not a result construction.
257         // If shape is compound check that it contains only faces, edges or vertices.
258         GeomShapePtr aShape = aSelectionAttr->value();
259         if(!aShape.get()) {
260           if (aContext.get()) {
261             aShape = aContext->shape();
262           } else {
263             theError = "Error: Empty context.";
264             return false;
265           }
266         }
267
268         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
269           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
270             GeomShapePtr aSubShape = anIt.current();
271             if(aSubShape->shapeType() != GeomAPI_Shape::VERTEX
272                 && aSubShape->shapeType() != GeomAPI_Shape::EDGE
273                 && aSubShape->shapeType() != GeomAPI_Shape::FACE) {
274               theError = "Error: Compound should contain only faces, edges or vertices.";
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 aResults;
1121   GeomAlgoAPI_ShapeTools::combineShapes(aCompound, aType, aResults);
1122
1123   if(aResults.size() > 1 || (aResults.size() == 1 && aResults.front()->shapeType() > aType)) {
1124     theError = "Error: Not all shapes have shared topology.";
1125     return false;
1126   }
1127
1128   return true;
1129 }
1130
1131 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
1132                                             const std::list<std::string>& theArguments,
1133                                             Events_InfoMessage& theError) const
1134 {
1135   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1136 // LCOV_EXCL_START
1137     theError = "Error: The attribute with the %1 type is not processed";
1138     theError.arg(theAttribute->attributeType());
1139     return false;
1140 // LCOV_EXCL_STOP
1141   }
1142
1143   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
1144                                                                                (theAttribute);
1145   ObjectPtr aRefObject = aRefAttribute->value();
1146   if (!aRefObject.get()) {
1147     theError = "Error: Empty feature.";
1148     return false;
1149   }
1150
1151   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
1152   if (!aRefFeature.get()) {
1153     theError = "Error: Empty feature.";
1154     return false;
1155   }
1156   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
1157   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
1158
1159   size_t aConcealedResults = aResults.size();
1160   if (!aConcealedResults && !theArguments.empty()) {
1161     // find if these results are touched by the feature in another attribute
1162     std::list<std::string>::const_iterator anIt = theArguments.begin();
1163     std::string aRecoveredList = *anIt;
1164     if (!aRecoveredList.empty()) {
1165       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
1166                                  theAttribute->owner()->data()->reflist(aRecoveredList);
1167       if (aParameterList.get())
1168         aConcealedResults = aParameterList->size();
1169     }
1170   }
1171
1172   if (aConcealedResults == 0)
1173     theError = "Error: No concealed results.";
1174
1175   return theError.empty();
1176 }
1177
1178 bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
1179                                                const std::list<std::string>& theArguments,
1180                                                Events_InfoMessage& theError) const
1181 {
1182   static std::list<std::string> aEdgeArg(1, "circle");
1183   static std::list<std::string> aFaceArg(1, "cylinder");
1184
1185   Events_InfoMessage aError;
1186   bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
1187   if (!isValid) {
1188     isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
1189     if (!isValid)
1190       theError = "The shape neither circle nor cylinder";
1191   }
1192   return isValid;
1193 }
1194
1195 //=================================================================================================
1196 bool FeaturesPlugin_ValidatorBooleanArguments::isValid(
1197   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1198   const std::list<std::string>& theArguments,
1199   Events_InfoMessage& theError) const
1200 {
1201 // LCOV_EXCL_START
1202   if (theArguments.size() != 2)
1203   {
1204     theError = "Wrong number of arguments (expected 2).";
1205     return false;
1206   }
1207 // LCOV_EXCL_STOP
1208
1209   int anObjectsToolsNb[2] = { 0,  0 };
1210
1211   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1212
1213   bool isAllInSameCompSolid = true;
1214   ResultBodyPtr aCompSolid;
1215
1216   for (int* anArgNbIt = anObjectsToolsNb; anIt != aLast; ++anIt, ++anArgNbIt) {
1217     AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1218     if (anAttrSelList)
1219     {
1220       *anArgNbIt = anAttrSelList->size();
1221       if (isAllInSameCompSolid) {
1222         for (int anIndex = 0; anIndex < *anArgNbIt; ++anIndex)
1223         {
1224           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1225           ResultPtr aContext = anAttr->context();
1226           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1227           if (aResCompSolidPtr.get())
1228           {
1229             if (aCompSolid.get())
1230             {
1231               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1232             }
1233             else
1234             {
1235               aCompSolid = aResCompSolidPtr;
1236             }
1237           }
1238           else
1239           {
1240             isAllInSameCompSolid = false;
1241             break;
1242           }
1243         }
1244       }
1245     }
1246   }
1247
1248   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1249     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1250   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1251
1252   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1253   {
1254     // Fuse operation
1255     if (anObjectsToolsNb[0] + anObjectsToolsNb[1] < 2)
1256     {
1257       theError = "Not enough arguments for Fuse operation.";
1258       return false;
1259     }
1260     else if (isAllInSameCompSolid)
1261     {
1262       theError = "Operations only between sub-shapes of the same shape not allowed.";
1263       return false;
1264     }
1265   }
1266   else
1267   {
1268     if (anObjectsToolsNb[0] < 1) // check number of objects
1269     {
1270       theError = "Objects not selected.";
1271       return false;
1272     }
1273     if (anObjectsToolsNb[1] < 1) // check number of tools
1274     {
1275       theError = "Tools not selected.";
1276       return false;
1277     }
1278     if (isAllInSameCompSolid)
1279     {
1280       theError = "Operations only between sub-shapes of the same shape not allowed.";
1281       return false;
1282     }
1283   }
1284
1285   return true;
1286 }
1287
1288 //=================================================================================================
1289 // LCOV_EXCL_START
1290 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1291                                                                std::string theAttribute)
1292 {
1293   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1294   {
1295     return true;
1296   }
1297
1298   return false;
1299 }
1300 // LCOV_EXCL_STOP
1301
1302 //==================================================================================================
1303 bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
1304   const AttributePtr& theAttribute,
1305   const std::list<std::string>& theArguments,
1306   Events_InfoMessage& theError) const
1307 {
1308   std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
1309     std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
1310
1311   AttributeSelectionListPtr anAttrSelectionList =
1312     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1313   if (!aFeature.get() || !anAttrSelectionList.get()) {
1314 // LCOV_EXCL_START
1315     theError =
1316       "Error: Validator used in wrong feature or attribute";
1317     return false;
1318 // LCOV_EXCL_STOP
1319   }
1320
1321   AttributeSelectionListPtr anOtherAttrSelectionList;
1322   if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
1323     anOtherAttrSelectionList =
1324       aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
1325   } else {
1326     anOtherAttrSelectionList =
1327       aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
1328   }
1329
1330   GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
1331   GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
1332   GeomPlanePtr aFacesPln;
1333
1334   for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
1335     AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
1336
1337     if (anAttrSelection->contextFeature().get()) {
1338       theError = "Error: Features not allowed for selection.";
1339       return false;
1340     }
1341
1342     ResultPtr aContext = anAttrSelection->context();
1343     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1344     if (!aShape.get()) {
1345       if (!aContext.get()) {
1346         theError = "Error: Empty selection.";
1347         return false;
1348       }
1349       aShape = aContext->shape();
1350     }
1351
1352     if (aShape->isSolid() || aShape->isCompSolid()) {
1353       aSelectedShapesType = GeomAPI_Shape::SOLID;
1354       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1355       if (aResCompSolidPtr.get()) {
1356         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1357         aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
1358       }
1359     } else {
1360       aSelectedShapesType = GeomAPI_Shape::FACE;
1361       GeomAPI_Face aFace(aShape);
1362       aFacesPln = aFace.getPlane();
1363       break;
1364     }
1365   }
1366
1367   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1368     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1369     if (!anAttrSelection.get()) {
1370       theError = "Error: Empty attribute selection.";
1371       return false;
1372     }
1373
1374     if (anAttrSelection->contextFeature().get()) {
1375       theError = "Error: Features not allowed for selection.";
1376       return false;
1377     }
1378
1379     ResultPtr aContext = anAttrSelection->context();
1380     if(!aContext.get()) {
1381       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1382       if (!aContFeat.get() || !aContFeat->results().size() ||
1383           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1384         theError = "Error: Empty selection context.";
1385         return false;
1386       }
1387     }
1388     ResultConstructionPtr aResultConstruction =
1389       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1390     if (aResultConstruction.get()) {
1391       theError = "Error: Result construction not allowed for selection.";
1392       return false;
1393     }
1394     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1395     GeomShapePtr aContextShape = aContext->shape();
1396     if (!aShape.get()) {
1397       aShape = aContextShape;
1398     }
1399     if (!aShape.get()) {
1400       theError = "Error: Empty shape.";
1401       return false;
1402     }
1403     if (!aShape->isEqual(aContextShape)) {
1404       theError = "Error: Local selection not allowed.";
1405       return false;
1406     }
1407
1408     if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
1409       // Other list is empty.
1410       if (aShape->isSolid() || aShape->isCompSolid()) {
1411         aSelectedShapesType = GeomAPI_Shape::SOLID;
1412       } else {
1413         aSelectedShapesType = GeomAPI_Shape::FACE;
1414         GeomAPI_Face aFace(aShape);
1415         aFacesPln = aFace.getPlane();
1416
1417         if (!aFacesPln.get()) {
1418           theError = "Error: Only planar faces allowed.";
1419           return false;
1420         }
1421       }
1422
1423       continue;
1424     } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
1425       if (!aShape->isSolid() && !aShape->isCompSolid()) {
1426         theError = "Error: Selected shapes should have the same type.";
1427         return false;
1428       }
1429     } else {
1430       GeomAPI_Face aFace(aShape);
1431       GeomPlanePtr aPln = aFace.getPlane();
1432
1433       if (!aPln.get()) {
1434         theError = "Error: Only planar faces allowed.";
1435         return false;
1436       }
1437
1438       if (!aFacesPln->isCoincident(aPln)) {
1439         theError = "Error: Only coincident faces allowed.";
1440         return false;
1441       }
1442     }
1443   }
1444
1445   return true;
1446 }
1447
1448 //==================================================================================================
1449 // LCOV_EXCL_START
1450 bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttribute,
1451                                                    const std::list<std::string>& theArguments,
1452                                                    Events_InfoMessage& theError) const
1453 {
1454   if (!theAttribute.get()) {
1455     theError = "Error: empty selection.";
1456     return false;
1457   }
1458   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1459   AttributeSelectionListPtr anAttrSelectionList =
1460     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1461   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1462     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1463     if (!anAttrSelection.get()) {
1464       theError = "Error: empty attribute selection.";
1465       return false;
1466     }
1467     ResultPtr aContext = anAttrSelection->context();
1468     if(!aContext.get()) {
1469       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1470       if (!aContFeat.get() || !aContFeat->results().size() ||
1471           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1472         theError = "Error: Empty selection context.";
1473         return false;
1474       }
1475     }
1476     FeaturePtr aFeature = anAttrSelection->contextFeature().get() ?
1477       anAttrSelection->contextFeature() : ModelAPI_Feature::feature(aContext);
1478     if (!aFeature.get()) {
1479       theError = "Error: empty feature.";
1480       return false;
1481     }
1482     std::string aFeatureKind = aFeature->getKind();
1483     if (aFeatureKind == "Sketch" ||
1484         aFeatureKind == "Plane" ||
1485         aFeatureKind == "Axis") {
1486       theError = "Error: %1 shape is not allowed for selection.";
1487       theError.arg(aFeatureKind);
1488       return false;
1489     }
1490     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1491     if (!aShape.get()) {
1492       GeomShapePtr aContextShape = aContext->shape();
1493       aShape = aContextShape;
1494     }
1495     if (!aShape.get()) {
1496       theError = "Error: empty shape.";
1497       return false;
1498     }
1499     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1500       theError = "Error: Local selection not allowed.";
1501       return false;
1502     }
1503
1504     int aShapeType = aShape->shapeType();
1505     // Allow to select edges, faces and solids.
1506     if (aShapeType != GeomAPI_Shape::EDGE &&
1507         aShapeType != GeomAPI_Shape::FACE &&
1508         aShapeType != GeomAPI_Shape::SOLID &&
1509         aShapeType != GeomAPI_Shape::COMPSOLID &&
1510         aShapeType != GeomAPI_Shape::COMPOUND) {
1511       theError = "Error: selected shape has the wrong type.";
1512       return false;
1513     }
1514   }
1515
1516   return true;
1517 }
1518 // LCOV_EXCL_STOP
1519
1520 //==================================================================================================
1521 // LCOV_EXCL_START
1522 bool FeaturesPlugin_ValidatorBooleanFuseSelection::isValid(
1523   const AttributePtr& theAttribute,
1524   const std::list<std::string>& theArguments,
1525   Events_InfoMessage& theError) const
1526 {
1527   AttributeSelectionListPtr anAttrSelectionList =
1528     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1529   if (!anAttrSelectionList.get()) {
1530     theError =
1531       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1532     return false;
1533   }
1534
1535   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1536     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1537     if (!anAttrSelection.get()) {
1538       theError = "Error: Empty attribute selection.";
1539       return false;
1540     }
1541     ResultPtr aContext = anAttrSelection->context();
1542     if(!aContext.get()) {
1543       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1544       if (!aContFeat.get() || !aContFeat->results().size() ||
1545           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1546         theError = "Error: Empty selection context.";
1547         return false;
1548       }
1549     }
1550     ResultConstructionPtr aResultConstruction =
1551       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1552     if (aResultConstruction.get()) {
1553       theError = "Error: Result construction not allowed for selection.";
1554       return false;
1555     }
1556     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1557     if (!aShape.get()) {
1558       GeomShapePtr aContextShape = aContext->shape();
1559       aShape = aContextShape;
1560     }
1561     if (!aShape.get()) {
1562       theError = "Error: Empty shape.";
1563       return false;
1564     }
1565     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1566       theError = "Error: Local selection not allowed.";
1567       return false;
1568     }
1569   }
1570
1571   return true;
1572 }
1573 // LCOV_EXCL_STOP
1574
1575 //=================================================================================================
1576 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
1577   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1578   const std::list<std::string>& theArguments,
1579   Events_InfoMessage& theError) const
1580 {
1581 // LCOV_EXCL_START
1582   if (theArguments.size() != 2) {
1583     theError = "Wrong number of arguments (expected 2).";
1584     return false;
1585   }
1586 // LCOV_EXCL_STOP
1587
1588   std::shared_ptr<FeaturesPlugin_BooleanFuse> aFeature =
1589     std::dynamic_pointer_cast<FeaturesPlugin_BooleanFuse>(theFeature);
1590
1591   int anObjectsNb = 0, aToolsNb = 0;
1592
1593   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1594
1595   bool isAllInSameCompSolid = true;
1596   ResultBodyPtr aCompSolid;
1597
1598   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1599   if (anAttrSelList) {
1600     anObjectsNb = anAttrSelList->size();
1601     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex) {
1602       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1603       ResultPtr aContext = anAttr->context();
1604       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1605       if (aResCompSolidPtr.get()) {
1606         if (aCompSolid.get()) {
1607           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1608         } else {
1609           aCompSolid = aResCompSolidPtr;
1610         }
1611       } else {
1612         isAllInSameCompSolid = false;
1613         break;
1614       }
1615     }
1616   }
1617   anIt++;
1618
1619   if (aFeature->string(FeaturesPlugin_BooleanFuse::CREATION_METHOD())->value()
1620       == FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED()) {
1621     anAttrSelList = theFeature->selectionList(*anIt);
1622     if (anAttrSelList) {
1623       aToolsNb = anAttrSelList->size();
1624       if (isAllInSameCompSolid) {
1625         for (int anIndex = 0; anIndex < aToolsNb; ++anIndex) {
1626           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1627           ResultPtr aContext = anAttr->context();
1628           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1629           if (aResCompSolidPtr.get()) {
1630             if (aCompSolid.get()) {
1631               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1632             } else {
1633               aCompSolid = aResCompSolidPtr;
1634             }
1635           } else {
1636             isAllInSameCompSolid = false;
1637             break;
1638           }
1639         }
1640       }
1641     }
1642   }
1643
1644   anIt++;
1645
1646   if (anObjectsNb + aToolsNb < 2) {
1647     theError = "Not enough arguments for Fuse operation.";
1648     return false;
1649   } else if (isAllInSameCompSolid) {
1650     theError = "Operations only between sub-shapes of the same shape not allowed.";
1651     return false;
1652   }
1653
1654   return true;
1655 }
1656
1657 //=================================================================================================
1658 // LCOV_EXCL_START
1659 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isNotObligatory(
1660   std::string theFeature,
1661   std::string theAttribute)
1662 {
1663   if (theAttribute == "main_objects" || theAttribute == "tool_objects") {
1664     return true;
1665   }
1666
1667   return false;
1668 }
1669 // LCOV_EXCL_STOP
1670
1671 //==================================================================================================
1672 // LCOV_EXCL_START
1673 bool FeaturesPlugin_ValidatorBooleanCommonSelection::isValid(
1674   const AttributePtr& theAttribute,
1675   const std::list<std::string>& theArguments,
1676   Events_InfoMessage& theError) const
1677 {
1678   AttributeSelectionListPtr anAttrSelectionList =
1679     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1680   if (!anAttrSelectionList.get()) {
1681     theError =
1682       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1683     return false;
1684   }
1685
1686   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1687     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1688     if (!anAttrSelection.get()) {
1689       theError = "Error: Empty attribute selection.";
1690       return false;
1691     }
1692     ResultPtr aContext = anAttrSelection->context();
1693     if (!aContext.get() && !anAttrSelection->contextFeature().get()) {
1694       theError = "Error: Empty selection context.";
1695       return false;
1696     }
1697     ResultConstructionPtr aResultConstruction =
1698       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1699     if (aResultConstruction.get()) {
1700       if (theAttribute->id() != FeaturesPlugin_BooleanCommon::TOOL_LIST_ID()) {
1701         theError = "Error: Result construction not allowed for selection.";
1702         return false;
1703       }
1704     }
1705     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1706     GeomShapePtr aContextShape;
1707     if (aContext.get()) {
1708       aContextShape = aContext->shape();
1709     }
1710     if (!aShape.get()) {
1711       aShape = aContextShape;
1712     }
1713     if (!aShape.get()) {
1714       theError = "Error: Empty shape.";
1715       return false;
1716     }
1717     if (aContextShape.get() && !aShape->isEqual(aContextShape)) {
1718       theError = "Error: Local selection not allowed.";
1719       return false;
1720     }
1721
1722     if (aResultConstruction.get() && aShape->shapeType() != GeomAPI_Shape::FACE) {
1723       theError = "Error: Result construction should be plane.";
1724       return false;
1725     }
1726   }
1727
1728   return true;
1729 }
1730 // LCOV_EXCL_STOP
1731
1732 //=================================================================================================
1733 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
1734   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1735   const std::list<std::string>& theArguments,
1736   Events_InfoMessage& theError) const
1737 {
1738   if (theArguments.size() != 2) {
1739 // LCOV_EXCL_START
1740     theError = "Wrong number of arguments (expected 2).";
1741     return false;
1742 // LCOV_EXCL_STOP
1743   }
1744
1745   std::shared_ptr<FeaturesPlugin_BooleanCommon> aFeature =
1746     std::dynamic_pointer_cast<FeaturesPlugin_BooleanCommon>(theFeature);
1747
1748   int anObjectsNb = 0, aToolsNb = 0;
1749
1750   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1751
1752   bool isAllInSameCompSolid = true;
1753   ResultBodyPtr aCompSolid;
1754
1755   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1756   if (anAttrSelList) {
1757     anObjectsNb = anAttrSelList->size();
1758   }
1759
1760   bool isSimpleMode = aFeature->string(FeaturesPlugin_BooleanCommon::CREATION_METHOD())->value()
1761                       == FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE();
1762
1763   if (!isSimpleMode) {
1764     anAttrSelList = theFeature->selectionList(*anIt);
1765     if (anAttrSelList) {
1766       aToolsNb = anAttrSelList->size();
1767     }
1768   }
1769
1770   if ((isSimpleMode && anObjectsNb < 2)
1771       || (!isSimpleMode && (anObjectsNb == 0 || aToolsNb == 0))) {
1772     theError = "Not enough arguments for Fuse operation.";
1773     return false;
1774   }
1775   return true;
1776 }
1777
1778 //=================================================================================================
1779 // LCOV_EXCL_START
1780 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
1781   std::string theFeature,
1782   std::string theAttribute)
1783 {
1784   return false;
1785 }
1786 // LCOV_EXCL_STOP