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