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