Salome HOME
0d8da03a687404cb8058b3819ffeabdbe9f6edcc
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
1 // Copyright (C) 2014-2022  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_CompositeBoolean.h"
27 #include "FeaturesPlugin_Extrusion.h"
28 #include "FeaturesPlugin_Pipe.h"
29 #include "FeaturesPlugin_Union.h"
30
31 #include <Events_InfoMessage.h>
32
33 #include <ModelAPI_Attribute.h>
34 #include <ModelAPI_AttributeDouble.h>
35 #include <ModelAPI_AttributeInteger.h>
36 #include <ModelAPI_AttributeSelectionList.h>
37 #include <ModelAPI_AttributeString.h>
38 #include <ModelAPI_AttributeReference.h>
39 #include <ModelAPI_AttributeRefList.h>
40 #include <ModelAPI_Feature.h>
41 #include <ModelAPI_ResultBody.h>
42 #include <ModelAPI_ResultConstruction.h>
43 #include <ModelAPI_Tools.h>
44
45 #include <GeomValidators_BodyShapes.h>
46 #include <GeomValidators_Face.h>
47 #include <GeomValidators_FeatureKind.h>
48 #include <GeomValidators_ShapeType.h>
49
50 #include <GeomAPI_DataMapOfShapeShape.h>
51 #include <GeomAPI_Lin.h>
52 #include <GeomAPI_PlanarEdges.h>
53 #include <GeomAPI_Pln.h>
54 #include <GeomAPI_ShapeExplorer.h>
55 #include <GeomAPI_ShapeIterator.h>
56
57 #include <GeomAlgoAPI_CompoundBuilder.h>
58 #include <GeomAlgoAPI_MapShapesAndAncestors.h>
59 #include <GeomAlgoAPI_Prism.h>
60 #include <GeomAlgoAPI_ShapeBuilder.h>
61 #include <GeomAlgoAPI_ShapeTools.h>
62 #include <GeomAlgoAPI_WireBuilder.h>
63
64 #include <algorithm>
65
66 #define _USE_MATH_DEFINES
67 #include <math.h>
68
69 #ifdef _MSC_VER
70 #pragma warning(disable: 4100)
71 #endif
72
73 //==================================================================================================
74 bool FeaturesPlugin_ValidatorPipePath::isValid(const AttributePtr& theAttribute,
75                                                const std::list<std::string>& theArguments,
76                                                Events_InfoMessage& theError) const
77 {
78   AttributeSelectionPtr aPathAttrSelection =
79     std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
80   if(!aPathAttrSelection.get()) {
81 // LCOV_EXCL_START
82     theError = "Error: This validator can only work with path selector in \"Pipe\" feature.";
83     return false;
84 // LCOV_EXCL_STOP
85   }
86
87   GeomShapePtr aPathShape = aPathAttrSelection->value();
88   ResultPtr aContext = aPathAttrSelection->context();
89   if(!aContext.get()) {
90     theError = "Error: Empty context.";
91     return false;
92   }
93   GeomShapePtr aContextShape = aContext->shape();
94   if(aPathShape.get() && aPathShape->shapeType() == GeomAPI_Shape::WIRE &&
95       !aPathShape->isEqual(aContextShape)) {
96     theError = "Error: Local selection of wires not allowed.";
97     return false;
98   }
99
100   return true;
101 }
102
103 //==================================================================================================
104 bool FeaturesPlugin_ValidatorPipeLocations::isValid(const AttributePtr& theAttribute,
105                                                     const std::list<std::string>& theArguments,
106                                                     Events_InfoMessage& theError) const
107 {
108   AttributeSelectionListPtr anAttrSelectionList =
109     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
110   if(!anAttrSelectionList.get()) {
111 // LCOV_EXCL_START
112     theError =
113       "Error: This validator can only work with selection list attributes in \"Pipe\" feature.";
114     return false;
115 // LCOV_EXCL_STOP
116   }
117   std::shared_ptr<FeaturesPlugin_Pipe> aFeature =
118     std::dynamic_pointer_cast<FeaturesPlugin_Pipe>(theAttribute->owner());
119
120   AttributeSelectionPtr aPathSelection = aFeature->selection(FeaturesPlugin_Pipe::PATH_OBJECT_ID());
121   if (!aPathSelection.get()) {
122 // LCOV_EXCL_START
123     theError = "Error: Path not selected.";
124     return false;
125 // LCOV_EXCL_STOP
126   }
127
128   GeomShapePtr aPathShape = aPathSelection->value();
129   if (!aPathShape.get()) {
130     ResultPtr aContext = aPathSelection->context();
131     if (!aContext.get()) {
132       FeaturePtr aContFeat = aPathSelection->contextFeature();
133       if (!aContFeat.get() || !aContFeat->results().size()) {
134         theError = "Error: Empty selection context.";
135         return false;
136       }
137     }
138     aPathShape = aContext->shape();
139   }
140
141   if (!aPathShape.get()) {
142     theError = "Error: Empty path shape.";
143     return false;
144   }
145
146   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
147     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
148     if (!anAttrSelection.get()) {
149       theError = "Error: Empty attribute selection.";
150       return false;
151     }
152     ResultPtr aContext = anAttrSelection->context();
153     if (!aContext.get()) {
154       FeaturePtr aContFeat = anAttrSelection->contextFeature();
155       if (!aContFeat.get() || !aContFeat->results().size()) {
156         theError = "Error: Empty selection context.";
157         return false;
158       }
159     }
160     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
161     if (!aShape.get() && aContext.get()) {
162       GeomShapePtr aContextShape = aContext->shape();
163       aShape = aContextShape;
164     }
165     if (!aShape.get()) {
166       theError = "Error: Empty shape.";
167       return false;
168     }
169
170     if (!aPathShape->isSubShape(aShape)) {
171       theError = "Error: Location should be a vertex subshape from path shape.";
172       return false;
173     }
174   }
175
176   return true;
177 }
178
179 //==================================================================================================
180 // LCOV_EXCL_START
181 bool FeaturesPlugin_ValidatorPipeLocationsNumber::isValid(
182   const std::shared_ptr<ModelAPI_Feature>& theFeature,
183   const std::list<std::string>& theArguments,
184   Events_InfoMessage& theError) const
185 {
186   static const std::string aCreationMethodID = "creation_method";
187   static const std::string aBaseObjectsID = "base_objects";
188   static const std::string aLocationsID = "locations_objects";
189
190   if(theFeature->getKind() != "Pipe") {
191     theError = "Error: Feature \"%1\" does not supported by this validator.";
192     theError.arg(theFeature->getKind());
193     return false;
194   }
195
196   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
197   if(!aCreationMethodAttr.get()) {
198     theError = "Error: Could not get \"%1\" attribute.";
199     theError.arg(aCreationMethodID);
200     return false;
201   }
202
203   if(aCreationMethodAttr->value() != "locations") {
204     return true;
205   }
206
207   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
208   if(!aBaseObjectsSelectionList.get()) {
209     theError = "Error: Could not get \"%1\" attribute.";
210     theError.arg(aBaseObjectsID);
211     return false;
212   }
213
214   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
215   if(!aLocationsSelectionList.get()) {
216     theError = "Error: Could not get \"%1\" attribute.";
217     theError.arg(aBaseObjectsID);
218     return false;
219   }
220
221   if(aLocationsSelectionList->size() > 0 &&
222      aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
223     theError = "Error: Number of locations should be the same as base objects.";
224     return false;
225   }
226
227   return true;
228 }
229 // LCOV_EXCL_STOP
230
231 //==================================================================================================
232 bool FeaturesPlugin_ValidatorLoftSameTypeShape::isValid(
233                                                 const std::shared_ptr<ModelAPI_Feature>& theFeature,
234                                                 const std::list<std::string>& theArguments,
235                                                 Events_InfoMessage& theError) const
236 {
237   static const std::string aFirstObjetcID = "first_object";
238   static const std::string aSecondObjetcID = "second_object";
239
240   if (theFeature->getKind() != "Loft") {
241     theError = "Error: Feature \"%1\" does not supported by this validator.";
242     theError.arg(theFeature->getKind());
243     return false;
244   }
245
246   AttributeSelectionPtr aFirstObjectsSelection = theFeature->selection(aFirstObjetcID);
247   if ( !aFirstObjectsSelection->isInitialized()) {
248     theError = "Error: Could not get \"%1\" attribute.";
249     theError.arg(aFirstObjetcID);
250     return false;
251   }
252
253   AttributeSelectionPtr aSecondObjectsSelection = theFeature->selection(aSecondObjetcID);
254   if (!aSecondObjectsSelection->isInitialized()) {
255     theError = "Error: Could not get \"%1\" attribute.";
256     theError.arg(aSecondObjetcID);
257     return false;
258   }
259
260   GeomShapePtr aFirstShape  = aFirstObjectsSelection->value();
261   if (!aFirstShape.get()) {
262     aFirstShape = aFirstObjectsSelection->context()->shape();
263   }
264   GeomShapePtr aSecondShape  = aSecondObjectsSelection->value();
265   if (!aSecondShape.get()) {
266     aSecondShape = aSecondObjectsSelection->context()->shape();
267   }
268
269   if (aFirstShape->isEqual(aSecondShape)) {
270     theError = "Error: the shapes are equal";
271     return false;
272   }
273
274   if (aFirstShape->shapeType()!=aSecondShape->shapeType()) {
275     theError = "Error: the shapes have different type";
276     return false;
277   }
278
279   return true;
280 }
281
282 //==================================================================================================
283 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
284                                                         const std::list<std::string>& theArguments,
285                                                         Events_InfoMessage& theError) const
286 {
287 // LCOV_EXCL_START
288   if(theArguments.empty()) {
289     theError = "Error: Validator parameters is empty.";
290     return false;
291   }
292 // LCOV_EXCL_STOP
293
294   // Checking attribute.
295   if(!isValidAttribute(theAttribute, theArguments, theError)) {
296     if(theError.empty()) {
297       theError = "Error: Attribute contains unacceptable shape.";
298     }
299     return false;
300   }
301
302   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
303   std::string anAttributeType = theAttribute->attributeType();
304   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
305     AttributeSelectionListPtr aListAttr =
306       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
307     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
308       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
309       ResultPtr aContext = aSelectionAttr->context();
310       if(!aContext.get() && !aSelectionAttr->contextFeature().get()) {
311         theError = "Error: Empty context.";
312         return false;
313       }
314
315       ResultConstructionPtr aResultConstruction =
316         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
317       if(!aResultConstruction.get()) {
318         // It is not a result construction.
319         // If shape is compound check that it contains only faces, edges or vertices.
320         GeomShapePtr aShape = aSelectionAttr->value();
321         if(!aShape.get()) {
322           if (aContext.get()) {
323             aShape = aContext->shape();
324           } else {
325             theError = "Error: Empty context.";
326             return false;
327           }
328         }
329
330         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
331           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
332             GeomShapePtr aSubShape = anIt.current();
333             if (aSubShape->shapeType() > GeomAPI_Shape::VERTEX ||
334                 aSubShape->shapeType() < GeomAPI_Shape::FACE) {
335               theError = "Error: Compound should contain only faces, edges or vertices.";
336               return false;
337             }
338           }
339         }
340
341         continue;
342       }
343
344       GeomShapePtr aShape = aSelectionAttr->value();
345       GeomShapePtr aContextShape = aResultConstruction->shape();
346       if(!aShape.get()) {
347         // Whole sketch selected.
348         continue;
349       } else {
350         // Object from sketch selected.
351         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
352           GeomShapePtr aWire = anExp.current();
353           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
354             theError = "Error: Wire with wrong orientation selected.";
355             return false;
356           }
357
358           if(aSelectedWiresFromObjects.isBound(aWire)) {
359             theError =
360               "Error: Objects with this wire already selected. Don't allow to select this object.";
361             return false;
362           }
363
364           aSelectedWiresFromObjects.bind(aWire, aWire);
365         }
366       }
367     }
368   }
369
370   return true;
371 }
372
373 //==================================================================================================
374 bool FeaturesPlugin_ValidatorBaseForGenerationSketchOrSketchObjects::isValid(
375   const std::shared_ptr<ModelAPI_Feature>& theFeature,
376   const std::list<std::string>& theArguments,
377   Events_InfoMessage& theError) const
378 {
379   const std::string aBaseObjectsID = theArguments.front();
380
381   AttributeSelectionListPtr aListAttr = theFeature->selectionList(aBaseObjectsID);
382   if(!aListAttr.get()) {
383 // LCOV_EXCL_START
384     theError = "Error: Could not get \"%1\" attribute.";
385     theError.arg(aBaseObjectsID);
386     return false;
387 // LCOV_EXCL_STOP
388   }
389
390   std::set<ResultConstructionPtr> aSelectedSketches;
391   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
392
393   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
394     AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
395     ResultPtr aContext = aSelectionAttr->context();
396     if(!aContext.get()) {
397       FeaturePtr aFeature = aSelectionAttr->contextFeature();
398       if (!aFeature.get() || aFeature->results().empty()) {
399         theError = "Error: Empty context.";
400         return false;
401       } else {
402         aContext = aFeature->firstResult();
403       }
404     }
405
406     ResultConstructionPtr aResultConstruction =
407       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
408     if(!aResultConstruction.get()) {
409       // It is not a result construction.
410       continue;
411     }
412
413     GeomShapePtr aShape = aSelectionAttr->value();
414     GeomShapePtr aContextShape = aResultConstruction->shape();
415     if(!aShape.get()) {
416       // Whole sketch selected.
417       aSelectedSketches.insert(aResultConstruction);
418     } else {
419       // Object from sketch selected.
420       aSelectedSketchesFromObjects.insert(aResultConstruction);
421     }
422   }
423
424
425   for(std::set<ResultConstructionPtr>::const_iterator anIt = aSelectedSketches.cbegin();
426       anIt != aSelectedSketches.cend();
427       ++anIt) {
428     ResultConstructionPtr aResultConstruction = *anIt;
429     if(aSelectedSketchesFromObjects.find(aResultConstruction) !=
430         aSelectedSketchesFromObjects.cend()) {
431       theError = "Sketch and objects from it can not be selected at the same time.";
432       return false;
433     }
434   }
435
436   return true;
437 }
438
439 //==================================================================================================
440 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
441                                                         const std::list<std::string>& theArguments,
442                                                         Events_InfoMessage& theError) const
443 {
444   if(!theAttribute.get()) {
445 // LCOV_EXCL_START
446     theError = "Error: Empty attribute.";
447     return false;
448 // LCOV_EXCL_STOP
449   }
450
451   std::string anAttributeType = theAttribute->attributeType();
452   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
453     AttributeSelectionListPtr aListAttr =
454       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
455
456     const std::string& aVersion = theAttribute->owner()->data()->version();
457     std::string aSelType;
458     if (!aVersion.empty())
459       aSelType = aListAttr->selectionType();
460
461     std::list<std::string> anApplicableTypes;
462     switch (GeomValidators_ShapeType::shapeType(aSelType)) {
463     case GeomValidators_ShapeType::Vertex:
464       anApplicableTypes.push_back("vertex");
465       break;
466     case GeomValidators_ShapeType::Edge:
467       anApplicableTypes.push_back("edge");
468       anApplicableTypes.push_back("wire");
469       break;
470     case GeomValidators_ShapeType::Face:
471       anApplicableTypes.push_back("face");
472       anApplicableTypes.push_back("shell");
473       // wire should not be the first in this list to be able to check
474       // the type of selection when evaluating shape by shape
475       anApplicableTypes.push_back("wire");
476       break;
477     default:
478       anApplicableTypes = theArguments;
479       break;
480     }
481
482     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
483       // If at least one attribute is invalid, the result is false.
484       if(!isValidAttribute(aListAttr->value(anIndex), anApplicableTypes, theError)) {
485         return false;
486       }
487     }
488   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
489     // Getting context.
490     AttributeSelectionPtr anAttr =
491       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
492     ResultPtr aContext = anAttr->context();
493     if(!aContext.get() && !anAttr->contextFeature().get()) {
494       theError = "Error: Attribute have empty context.";
495       return false;
496     }
497
498     GeomShapePtr aShape = anAttr->value();
499     GeomShapePtr aContextShape;
500     if(!aShape.get() && aContext.get()) {
501       aContextShape = aContext->shape();
502       aShape = aContextShape;
503     }
504     if(!aShape.get()) {
505       theError = "Error: Empty shape selected";
506       return false;
507     }
508
509     ResultConstructionPtr aConstruction;
510     if (!aContext.get() && anAttr->contextFeature()->results().size() == 1) {
511       aContext = anAttr->contextFeature()->firstResult();
512     }
513     if (aContext.get())
514       aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
515     if(aConstruction.get()) {
516       // Construction selected. Check that it is not infinite.
517       if(aConstruction->isInfinite() && !aConstruction->shape()->isVertex()) {
518         theError = "Error: Infinite constructions is not allowed as base.";
519         return false;
520       }
521
522       aContextShape = aContext->shape();
523       if(aShape->isEqual(aContextShape)) {
524         // Whole construction selected. Check that it has faces.
525         if((theArguments.front() == "face" && aConstruction->facesNum() > 0) ||
526             theArguments.front() == "edge") {
527           return true;
528         }
529       } else {
530         // CUT operation supports only FACE or WIRE as a tool base
531         std::shared_ptr<FeaturesPlugin_CompositeBoolean> aComposite =
532             std::dynamic_pointer_cast<FeaturesPlugin_CompositeBoolean>(
533             ModelAPI_Feature::feature(theAttribute->owner()));
534         if (aComposite &&
535             aComposite->operationType() == FeaturesPlugin_CompositeBoolean::BOOL_CUT) {
536           return aShape->shapeType() == GeomAPI_Shape::WIRE ||
537                  aShape->shapeType() == GeomAPI_Shape::FACE;
538         }
539       }
540     }
541
542     if(!aConstruction && aContextShape.get() && !aShape->isEqual(aContextShape)) {
543       // Local selection on body does not allowed.
544       theError =
545         "Error: Selected shape is in the local selection. Only global selection is allowed.";
546       return false;
547     }
548
549     // Check that object is a shape with allowed type.
550     GeomValidators_ShapeType aShapeTypeValidator;
551     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
552       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
553                  "wires on sketch, whole sketch (if it has at least one face), "
554                  "and whole objects with shape types: %1";
555       std::string anArgumentString;
556       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
557         if (!anArgumentString.empty())
558           anArgumentString += ", ";
559         anArgumentString += *anIt;
560       }
561       theError.arg(anArgumentString);
562       return false;
563     }
564
565   } else {
566 // LCOV_EXCL_START
567     theError = "Error: Attribute \"%1\" does not supported by this validator.";
568     theError.arg(anAttributeType);
569     return false;
570 // LCOV_EXCL_STOP
571   }
572
573   return true;
574 }
575
576 //==================================================================================================
577 // LCOV_EXCL_START
578 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
579                                                         const std::list<std::string>& theArguments,
580                                                         Events_InfoMessage& theError) const
581 {
582   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
583     theError = "Error: The attribute with the %1 type is not processed";
584     theError.arg(theAttribute->attributeType());
585     return false;
586   }
587   if (theArguments.size() != 2) {
588     theError = "Error: Wrong parameters in XML definition for %1 type";
589     theError.arg(theAttribute->attributeType());
590     return false;
591   }
592   // first argument is for the base attribute, second - for skipping feature kind
593   std::list<std::string>::const_iterator anIt = theArguments.begin();
594   std::string aBaseAttributeId = *anIt;
595   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
596   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
597   if (!aBaseAttribute.get()) {
598     theError = "Wrong parameters in XML definition for %1 type";
599     theError.arg(theAttribute->attributeType());
600     return false;
601   }
602   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
603     // this validator is not necessary anymore
604     return true;
605
606   anIt++;
607   std::string aFeatureAttributeKind = *anIt;
608   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
609   // check whether the selection is on the sketch
610   std::list<std::string> anArguments;
611   anArguments.push_back(aFeatureAttributeKind);
612
613   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
614   bool aPlanarFace = false;
615   // check if selection has Face selected
616   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
617   anArguments.clear();
618   anArguments.push_back("face");
619   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
620
621   bool aValid = !aFeatureKind && aPlanarFace;
622   return aValid;
623 }
624 // LCOV_EXCL_STOP
625
626 //==================================================================================================
627 bool FeaturesPlugin_ValidatorExtrusionDir::isValid(
628                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
629                                                const std::list<std::string>& theArguments,
630                                                Events_InfoMessage& theError) const
631 {
632   if(theArguments.size() != 2) {
633 // LCOV_EXCL_START
634     theError = "Error: Validator should be used with 2 parameters for extrusion.";
635     return false;
636 // LCOV_EXCL_STOP
637   }
638
639   std::list<std::string>::const_iterator anArgsIt = theArguments.begin();
640
641   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
642   ++anArgsIt;
643
644   GeomShapePtr aDirShape;
645   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
646   if(aSelAttr.get()) {
647     aDirShape = aSelAttr->value();
648     if(!aDirShape.get()) {
649       ResultPtr aContext = aSelAttr->context();
650       if(!aContext.get()) {
651         FeaturePtr aFeature = aSelAttr->contextFeature();
652         if (aFeature.get() && !aFeature->results().empty()) {
653           aContext = aFeature->firstResult();
654         }
655       }
656
657       if(aContext.get()) {
658         aDirShape = aContext->shape();
659       }
660
661       if (aDirShape.get() && aDirShape->isCompound()) {
662         GeomAPI_ShapeIterator anIt(aDirShape);
663         aDirShape = anIt.current();
664       }
665     }
666   }
667
668   if(!aDirShape.get() || aDirShape->isNull() ||
669      aDirShape->shapeType() != GeomAPI_Shape::EDGE) {
670     // Check that dir can be empty.
671     if(!isShapesCanBeEmpty(aCheckAttribute, theError)) {
672       theError = "Error: Base objects list contains vertex or edge, so attribute \"%1\" "
673                  "can not be used with default value. Select direction for extrusion.";
674       theError.arg(*anArgsIt);
675       return false;
676     } else {
677       return true;
678     }
679   }
680
681   std::shared_ptr<GeomAPI_Edge> aDirEdge(new GeomAPI_Edge(aDirShape));
682
683   // If faces selected check that direction not parallel with them.
684   AttributeSelectionListPtr aListAttr =
685     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aCheckAttribute);
686   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
687     AttributeSelectionPtr anAttr = aListAttr->value(anIndex);
688     GeomShapePtr aShapeInList = anAttr->value();
689     if(!aShapeInList.get()) {
690       aShapeInList = anAttr->context()->shape();
691     }
692     bool isParallel = true;
693     if(aShapeInList->shapeType() == GeomAPI_Shape::FACE ||
694        aShapeInList->shapeType() == GeomAPI_Shape::SHELL) {
695       for(GeomAPI_ShapeExplorer
696           anExp(aShapeInList, GeomAPI_Shape::FACE); anExp.more(); anExp.next()) {
697         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(anExp.current()));
698         isParallel = GeomAlgoAPI_ShapeTools::isParallel(aDirEdge, aFace);
699         if(isParallel) {
700           break;
701         }
702       }
703     } else if(aShapeInList->shapeType() == GeomAPI_Shape::COMPOUND) {
704       std::shared_ptr<GeomAPI_PlanarEdges> aPlanarEdges =
705         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aShapeInList);
706       if(aPlanarEdges.get()) {
707         std::shared_ptr<GeomAPI_Dir> aSketchDir = aPlanarEdges->norm();
708         if(aDirEdge->isLine()) {
709           std::shared_ptr<GeomAPI_Dir> aDir = aDirEdge->line()->direction();
710           isParallel = fabs(aSketchDir->angle(aDir) - M_PI / 2.0) < 10e-7;
711         } else {
712           isParallel = false;
713         }
714       } else {
715         isParallel = false;
716       }
717     } else {
718       isParallel = false;
719     }
720     if(isParallel) {
721       theError =
722         "Error: Direction is parallel to one of the selected face or face on selected shell.";
723       return false;
724     }
725   }
726
727   return true;
728 }
729
730 //==================================================================================================
731 bool FeaturesPlugin_ValidatorExtrusionDir::isShapesCanBeEmpty(const AttributePtr& theAttribute,
732                                                               Events_InfoMessage& theError) const
733 {
734 // LCOV_EXCL_START
735   if(!theAttribute.get()) {
736     return true;
737   }
738 // LCOV_EXCL_STOP
739
740   std::string anAttributeType = theAttribute->attributeType();
741   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
742     AttributeSelectionListPtr aListAttr =
743       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
744     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
745       // If at least one attribute is invalid, the result is false.
746       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
747         return false;
748       }
749     }
750   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
751     // Getting context.
752     AttributeSelectionPtr anAttr =
753       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
754     ResultPtr aContext = anAttr->context();
755     if(!aContext.get() && !anAttr->contextFeature().get()) {
756       return false;
757     }
758
759     GeomShapePtr aShape = anAttr->value();
760     if(!aShape.get() && aContext.get()) {
761       GeomShapePtr aContextShape = aContext->shape();
762       aShape = aContextShape;
763     }
764     if(!aShape.get()) {
765       return false;
766     }
767
768     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
769        aShape->shapeType() == GeomAPI_Shape::EDGE ||
770        !aShape->isPlanar()) {
771       return false;
772     }
773   } else {
774     return false;
775   }
776
777   return true;
778 }
779
780 //==================================================================================================
781 bool FeaturesPlugin_ValidatorExtrusionBoundaryFace::isValid(
782     const AttributePtr& theAttribute,
783     const std::list<std::string>& theArguments,
784     Events_InfoMessage& theError) const
785 {
786   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
787
788   // Collect all necessary attributes and try to build prism
789
790   // base face
791   AttributeSelectionListPtr aBaseShapeAttr =
792       aFeature->selectionList(FeaturesPlugin_Extrusion::BASE_OBJECTS_ID());
793   ListOfShape aBaseShapeList;
794   std::string anError;
795   if (!FeaturesPlugin_Tools::getShape(aBaseShapeAttr, true, aBaseShapeList, anError)) {
796     theError = anError;
797     return false;
798   }
799
800   // direction
801   AttributeSelectionPtr aSelection =
802       aFeature->selection(FeaturesPlugin_Extrusion::DIRECTION_OBJECT_ID());
803   GeomShapePtr aShape = aSelection->value();
804   if (!aShape.get() && aSelection->context().get())
805     aShape = aSelection->context()->shape();
806
807   GeomEdgePtr anEdge;
808   if (aShape.get()) {
809     if (aShape->isEdge())
810       anEdge = aShape->edge();
811     else if (aShape->isCompound()) {
812       GeomAPI_ShapeIterator anIt(aShape);
813       anEdge = anIt.current()->edge();
814     }
815   }
816
817   std::shared_ptr<GeomAPI_Dir> aDir;
818   if (anEdge.get() && anEdge->isLine())
819     aDir = anEdge->line()->direction();
820
821   // from/to shapes
822   GeomShapePtr aFromShape, aToShape;
823   aSelection = aFeature->selection(FeaturesPlugin_Extrusion::TO_OBJECT_ID());
824   if (aSelection.get()) {
825     aToShape = aSelection->value();
826     if (!aToShape.get() && aSelection->context().get())
827       aToShape = aSelection->context()->shape();
828     if (aToShape.get() && aToShape->isCompound()) {
829       GeomAPI_ShapeIterator anIt(aToShape);
830       aToShape = anIt.current();
831     }
832     if (aToShape.get() && !aToShape->isFace()) {
833       theError = "\"To\" shape is not a face";
834       return false;
835     }
836   }
837   aSelection = aFeature->selection(FeaturesPlugin_Extrusion::FROM_OBJECT_ID());
838   if (aSelection.get()) {
839     aFromShape = aSelection->value();
840     if (!aFromShape.get() && aSelection->context().get())
841       aFromShape = aSelection->context()->shape();
842     if (aFromShape.get() && aFromShape->isCompound()) {
843       GeomAPI_ShapeIterator anIt(aFromShape);
844       aFromShape = anIt.current();
845     }
846     if (aFromShape.get() && !aFromShape->isFace()) {
847       theError = "\"From\" shape is not a face";
848       return false;
849     }
850   }
851
852   double aToSize = aFeature->real(FeaturesPlugin_Extrusion::TO_OFFSET_ID())->value();
853   double aFromSize = aFeature->real(FeaturesPlugin_Extrusion::FROM_OFFSET_ID())->value();
854
855   // check extrusion
856   for (ListOfShape::iterator anIt = aBaseShapeList.begin(); anIt != aBaseShapeList.end(); anIt++) {
857     std::shared_ptr<GeomAPI_Shape> aBaseShape = *anIt;
858
859     std::shared_ptr<GeomAlgoAPI_Prism> aPrismAlgo(
860         new GeomAlgoAPI_Prism(aBaseShape, aDir, aToShape, aToSize, aFromShape, aFromSize));
861     bool isFailed = GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPrismAlgo,
862                                                                     FeaturesPlugin_Extrusion::ID(),
863                                                                     anError);
864     if (isFailed) {
865       theError = anError;
866       return false;
867     }
868   }
869
870   return true;
871 }
872
873 //==================================================================================================
874 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
875                                                        const std::list<std::string>& theArguments,
876                                                        Events_InfoMessage& theError) const
877 {
878   AttributeSelectionListPtr anAttrSelectionList =
879     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
880   if(!anAttrSelectionList.get()) {
881 // LCOV_EXCL_START
882     theError =
883       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
884     return false;
885 // LCOV_EXCL_STOP
886   }
887   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
888     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theAttribute->owner());
889   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
890
891   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
892     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
893     if(!anAttrSelection.get()) {
894       theError = "Error: Empty attribute selection.";
895       return false;
896     }
897     ResultPtr aContext = anAttrSelection->context();
898     if(!aContext.get()) {
899       FeaturePtr aContFeat = anAttrSelection->contextFeature();
900       if (!aContFeat.get() || !aContFeat->results().size()) {
901         theError = "Error: Empty selection context.";
902         return false;
903       }
904     }
905     ResultConstructionPtr aResultConstruction =
906       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
907     if(aResultConstruction.get()) {
908       if (anOperationType != FeaturesPlugin_Boolean::BOOL_FILL
909           || theAttribute->id() != FeaturesPlugin_Boolean::TOOL_LIST_ID()) {
910         theError = "Error: Result construction not allowed for selection.";
911         return false;
912       }
913     }
914     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
915     if(!aShape.get() && aContext.get()) {
916       GeomShapePtr aContextShape = aContext->shape();
917       aShape = aContextShape;
918     }
919     if(!aShape.get()) {
920       theError = "Error: Empty shape.";
921       return false;
922     }
923     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
924       theError = "Error: Local selection not allowed.";
925       return false;
926     }
927
928     GeomAPI_Shape::ShapeType aShapeType = aShape->shapeType();
929     std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
930     if(anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE) {
931       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
932       anAllowedTypes.insert(GeomAPI_Shape::FACE);
933       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
934       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
935       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
936     } else if (anOperationType == FeaturesPlugin_Boolean::BOOL_FILL
937                || anOperationType == FeaturesPlugin_Boolean::BOOL_CUT)
938     {
939       anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
940       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
941       anAllowedTypes.insert(GeomAPI_Shape::WIRE);
942       anAllowedTypes.insert(GeomAPI_Shape::FACE);
943       anAllowedTypes.insert(GeomAPI_Shape::SHELL);
944       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
945       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
946       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
947     } else {
948       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
949       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
950       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
951     }
952
953     if(anAllowedTypes.find(aShapeType) == anAllowedTypes.end()
954       || (aResultConstruction.get() && aShapeType != GeomAPI_Shape::FACE)) {
955       theError = "Error: Selected shape has the wrong type.";
956       return false;
957     }
958
959   }
960
961   return true;
962 }
963
964 //==================================================================================================
965 bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAttribute,
966                                                       const std::list<std::string>& theArguments,
967                                                       Events_InfoMessage& theError) const
968 {
969   AttributeSelectionListPtr anAttrSelectionList =
970     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
971   if(!anAttrSelectionList.get()) {
972 // LCOV_EXCL_START
973     theError =
974       "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
975     return false;
976 // LCOV_EXCL_STOP
977   }
978
979   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
980   // Check all selected entities are sub-shapes of single solid
981   GeomShapePtr aBaseSolid;
982   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
983     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
984     if(!anAttrSelection.get()) {
985       theError = "Error: Empty attribute selection.";
986       return false;
987     }
988     ResultPtr aContext = anAttrSelection->context();
989     if(!aContext.get()) {
990       FeaturePtr aContFeat = anAttrSelection->contextFeature();
991       if (!aContFeat.get() || !aContFeat->results().size() ||
992           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
993         theError = "Error: Empty selection context.";
994         return false;
995       }
996       if (aContFeat->results().size() == 1)
997         aContext = aContFeat->firstResult();
998       else {
999         theError = "Error: Too many shapes selected.";
1000         return false;
1001       }
1002     }
1003
1004     ResultBodyPtr aContextOwner = ModelAPI_Tools::bodyOwner(aContext, true);
1005     GeomShapePtr anOwner = aContext->shape();
1006     GeomShapePtr aTopLevelOwner = aContextOwner.get() ? aContextOwner->shape() : anOwner;
1007
1008     if (!anOwner) {
1009       theError = "Error: wrong feature is selected.";
1010       return false;
1011     }
1012
1013     if (anOwner->shapeType() != GeomAPI_Shape::SOLID &&
1014         anOwner->shapeType() != GeomAPI_Shape::COMPSOLID) {
1015       theError = "Error: Not all selected shapes are sub-shapes of solids.";
1016       return false;
1017     }
1018
1019     if (!aBaseSolid)
1020       aBaseSolid = aTopLevelOwner;
1021     else if (!aBaseSolid->isEqual(aTopLevelOwner)) {
1022       theError = "Error: Sub-shapes of different solids have been selected.";
1023       return false;
1024     }
1025   }
1026
1027   return true;
1028 }
1029
1030
1031 //==================================================================================================
1032 bool FeaturesPlugin_ValidatorFillet1DSelection::isValid(const AttributePtr& theAttribute,
1033                                                         const std::list<std::string>& theArguments,
1034                                                         Events_InfoMessage& theError) const
1035 {
1036   AttributeSelectionListPtr anAttrSelectionList =
1037     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1038   if (!anAttrSelectionList.get()) {
1039     // LCOV_EXCL_START
1040     theError =
1041       "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
1042     return false;
1043     // LCOV_EXCL_STOP
1044   }
1045
1046   // Validate wires selection
1047   if (!theArguments.empty() &&
1048       theArguments.front() == "wire") {
1049     for (int ind = 0; ind < anAttrSelectionList->size(); ++ind) {
1050       AttributeSelectionPtr aCurSel = anAttrSelectionList->value(ind);
1051       //GeomShapePtr aContext = aCurSel->context()->shape();
1052       GeomShapePtr aWire = aCurSel->value();
1053       if (aWire->shapeType() != GeomAPI_Shape::WIRE) {
1054         theError = "Selected shape is not a wire";
1055         return false;
1056       }
1057     }
1058     return true;
1059   }
1060
1061   // check each selected vertex is a sharp corner between adjacent edges,
1062   // and these edges are in the same plane
1063   std::map<GeomShapePtr, MapShapeToShapes> aWireSubshapes;
1064   int aNbSel = anAttrSelectionList->size();
1065   for (int ind = 0; ind < aNbSel; ++ind) {
1066     AttributeSelectionPtr aCurSel = anAttrSelectionList->value(ind);
1067     GeomShapePtr aContext = aCurSel->context()->shape();
1068     GeomShapePtr aVertex = aCurSel->value();
1069     // check wire already processed, if not, store all vertices and edges, sharing them
1070     std::map<GeomShapePtr, MapShapeToShapes>::iterator aProcessed = aWireSubshapes.find(aContext);
1071     if (aProcessed == aWireSubshapes.end()) {
1072       if (aContext->shapeType() != GeomAPI_Shape::WIRE) {
1073         theError = "Selected vertex is not a wire corner";
1074         return false;
1075       }
1076       if (aVertex->shapeType() != GeomAPI_Shape::VERTEX) {
1077         theError = "Selected shape is not a vertex";
1078         return false;
1079       }
1080
1081       GeomAlgoAPI_MapShapesAndAncestors aMapVE(aContext, GeomAPI_Shape::VERTEX,
1082                                                          GeomAPI_Shape::EDGE);
1083       aWireSubshapes[aContext] = aMapVE.map();
1084       aProcessed = aWireSubshapes.find(aContext);
1085     }
1086
1087     // check the vertex
1088     MapShapeToShapes::iterator aFound = aProcessed->second.find(aVertex);
1089     if (aFound == aProcessed->second.end()) {
1090       theError = "Selected vertex does not exist in the wire";
1091       return true;
1092     }
1093     else if (aFound->second.size() != 2) {
1094       theError = "Vertex should be shared between 2 edges exactly";
1095       return false;
1096     }
1097
1098     ListOfShape anEdges;
1099     anEdges.insert(anEdges.end(), aFound->second.begin(), aFound->second.end());
1100     GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
1101     if (!aPlane) {
1102       theError = "Error: Edges are not planar";
1103       return false;
1104     }
1105
1106     GeomEdgePtr anEdge1(new GeomAPI_Edge(anEdges.front()));
1107     GeomEdgePtr anEdge2(new GeomAPI_Edge(anEdges.back()));
1108     GeomVertexPtr aSharedVertex(new GeomAPI_Vertex(aVertex));
1109     if (GeomAlgoAPI_ShapeTools::isTangent(anEdge1, anEdge2, aSharedVertex)) {
1110       theError = "Error: Edges are tangent";
1111       return false;
1112     }
1113   }
1114
1115   return true;
1116 }
1117
1118 //==================================================================================================
1119 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
1120                                                        const std::list<std::string>& theArguments,
1121                                                        Events_InfoMessage& theError) const
1122 {
1123   AttributeSelectionListPtr anAttrSelectionList =
1124     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1125   if(!anAttrSelectionList.get()) {
1126 // LCOV_EXCL_START
1127     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
1128     return false;
1129 // LCOV_EXCL_STOP
1130   }
1131
1132   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1133     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
1134
1135     //GeomValidators_BodyShapes aBodyValidator;
1136     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
1137     //  continue;
1138     //}
1139
1140     GeomValidators_FeatureKind aFeatureKindValidator;
1141     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
1142       continue;
1143     }
1144
1145     ResultPtr aContext = aSelectAttr->context();
1146     ResultConstructionPtr aResultConstruction =
1147       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1148     if(aResultConstruction.get()) {
1149       theError = "Error: Only body shapes and construction planes are allowed for selection.";
1150       return false;
1151     }
1152
1153     ResultBodyPtr aResultBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
1154     if(aResultBody.get()) {
1155       continue;
1156     }
1157     FeaturePtr aResultFeature = aSelectAttr->contextFeature();
1158     if(aResultFeature.get()) {
1159       bool aOkRes = false;
1160       std::list<ResultPtr>::const_iterator aFRes = aResultFeature->results().cbegin();
1161       for(; aFRes != aResultFeature->results().cend() && !aOkRes; aFRes++) {
1162         ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aFRes);
1163         if (aBody.get() && !aBody->isDisabled())
1164           aOkRes = true;
1165       }
1166       if (aOkRes)
1167         continue;
1168     }
1169
1170     theError = "Error: Only body shapes and construction planes are allowed for selection.";
1171     return false;
1172   }
1173
1174   theError = "";
1175   return true;
1176 }
1177
1178 //==================================================================================================
1179 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
1180                                                      const std::list<std::string>& theArguments,
1181                                                      Events_InfoMessage& theError) const
1182 {
1183   AttributeSelectionListPtr aSubShapesAttrList =
1184     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1185   if(!aSubShapesAttrList.get()) {
1186 // LCOV_EXCL_START
1187     theError =
1188       "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
1189     return false;
1190 // LCOV_EXCL_STOP
1191   }
1192
1193   static const std::string aBaseShapeID = "base_shape";
1194   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1195   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
1196
1197   if(!aShapeAttrSelection.get()) {
1198 // LCOV_EXCL_START
1199     theError = "Error: Could not get \"%1\" attribute.";
1200     theError.arg(aBaseShapeID);
1201     return false;
1202 // LCOV_EXCL_STOP
1203   }
1204
1205   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
1206   ResultPtr aContext = aShapeAttrSelection->context();
1207   if(!aContext.get()) {
1208     theError = "Error: Empty context.";
1209     return false;
1210   }
1211   if(!aBaseShape.get()) {
1212     aBaseShape = aContext->shape();
1213   }
1214   if(!aBaseShape.get()) {
1215     theError = "Error: Empty base shape.";
1216     return false;
1217   }
1218
1219   std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
1220   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
1221     bool isSameFound = false;
1222     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
1223     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
1224     for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt)
1225     {
1226       if ((*anIt)->isEqual(aShapeToAdd)) {
1227         isSameFound = true;
1228         break;
1229       }
1230     }
1231     if (!isSameFound) {
1232       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
1233       return false;
1234     }
1235   }
1236
1237   return true;
1238 }
1239
1240 //==================================================================================================
1241 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
1242   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1243   const std::list<std::string>& theArguments,
1244   Events_InfoMessage& theError) const
1245 {
1246   static const std::string aBaseShapeID = "base_shape";
1247   static const std::string aSubShapesID = "subshapes_to_keep";
1248
1249 // LCOV_EXCL_START
1250   if(theFeature->getKind() != "Remove_SubShapes") {
1251     theError = "Error: Feature \"%1\" does not supported by this validator.";
1252     theError.arg(theFeature->getKind());
1253     return false;
1254   }
1255
1256   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
1257   if(!aShapeAttrSelection.get()) {
1258     theError = "Error: Could not get \"%1\" attribute.";
1259     theError.arg(aBaseShapeID);
1260     return false;
1261   }
1262
1263   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
1264   if(!aSubShapesAttrList.get()) {
1265     theError = "Error: Could not get \"%1\" attribute.";
1266     theError.arg(aSubShapesID);
1267     return false;
1268   }
1269 // LCOV_EXCL_STOP
1270
1271   // Copy base shape.
1272   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
1273   if(!aBaseShape.get()) {
1274     theError = "Error: Base shape is empty.";
1275     return false;
1276   }
1277   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
1278
1279   if (aSubShapesAttrList->size() == 0) {
1280     theError = "Error: Resulting shape is not valid.";
1281     return false;
1282   }
1283
1284   // Copy sub-shapes from list to new shape.
1285   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
1286     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
1287     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
1288     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
1289   }
1290
1291   // Check new shape.
1292   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
1293     theError = "Error: Resulting shape is not valid.";
1294     return false;
1295   }
1296
1297   return true;
1298 }
1299
1300 //==================================================================================================
1301 // LCOV_EXCL_START
1302 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
1303                                                      const std::list<std::string>& theArguments,
1304                                                      Events_InfoMessage& theError) const
1305 {
1306   AttributeSelectionListPtr aBaseObjectsAttrList =
1307     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1308   if(!aBaseObjectsAttrList.get()) {
1309     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
1310     theError.arg(FeaturesPlugin_Union::ID());
1311     return false;
1312   }
1313
1314   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
1315     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
1316     ResultPtr aContext = anAttrSelectionInList->context();
1317     if (!aContext.get()) {
1318       theError = "Error: selection is invalid.";
1319       return false;
1320     }
1321
1322     ResultConstructionPtr aConstruction =
1323       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1324     if(aConstruction.get()) {
1325       theError = "Error: Result construction not allowed for selection.";
1326       return false;
1327     }
1328
1329     GeomShapePtr aShape = anAttrSelectionInList->value();
1330     GeomShapePtr aContextShape = aContext->shape();
1331     if (aShape.get() && aContextShape.get() && !aContextShape->isEqual(aShape)) {
1332       theError = "Error: Local selection not allowed.";
1333       return false;
1334     }
1335
1336     ResultBodyPtr aResult =
1337       std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
1338     if(!aResult.get()) {
1339       continue;
1340     }
1341
1342     if(aResult->numberOfSubs() > 0) {
1343       theError = "Error: Whole compsolids not allowed for selection.";
1344       return false;
1345     }
1346   }
1347
1348   return true;
1349 }
1350 // LCOV_EXCL_STOP
1351
1352 //==================================================================================================
1353 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
1354   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1355   const std::list<std::string>& theArguments,
1356   Events_InfoMessage& theError) const
1357 {
1358 // LCOV_EXCL_START
1359   // Check feature kind.
1360   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
1361     theError = "Error: This validator supports only \"%1\" feature.";
1362     theError.arg(FeaturesPlugin_Union::ID());
1363     return false;
1364   }
1365
1366   // Get base objects attribute list.
1367   AttributeSelectionListPtr aBaseObejctsAttrList =
1368     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
1369   if(!aBaseObejctsAttrList.get()) {
1370     theError = "Error: Could not get \"%1\" attribute.";
1371     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
1372     return false;
1373   }
1374 // LCOV_EXCL_STOP
1375
1376   // Get all shapes.
1377   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::COMPSOLID;
1378   ListOfShape aBaseShapesList;
1379   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
1380     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
1381     GeomShapePtr aShape = anAttrSelectionInList->value();
1382     if (!aShape.get()) {
1383       continue;
1384     }
1385     aBaseShapesList.push_back(aShape);
1386     aType = aShape->shapeType() == GeomAPI_Shape::FACE ? GeomAPI_Shape::SHELL :
1387                                                          GeomAPI_Shape::COMPSOLID;
1388   }
1389
1390   // Make compound and find connected.
1391   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
1392   ListOfShape aResults;
1393   GeomAlgoAPI_ShapeTools::combineShapes(aCompound, aType, aResults);
1394
1395   if(aResults.size() > 1 || (aResults.size() == 1 && aResults.front()->shapeType() > aType)) {
1396     theError = "Error: Not all shapes have shared topology.";
1397     return false;
1398   }
1399
1400   return true;
1401 }
1402
1403 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
1404                                             const std::list<std::string>& theArguments,
1405                                             Events_InfoMessage& theError) const
1406 {
1407   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
1408 // LCOV_EXCL_START
1409     theError = "Error: The attribute with the %1 type is not processed";
1410     theError.arg(theAttribute->attributeType());
1411     return false;
1412 // LCOV_EXCL_STOP
1413   }
1414
1415   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
1416                                                                                (theAttribute);
1417   ObjectPtr aRefObject = aRefAttribute->value();
1418   if (!aRefObject.get()) {
1419     theError = "Error: Empty feature.";
1420     return false;
1421   }
1422
1423   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
1424   if (!aRefFeature.get()) {
1425     theError = "Error: Empty feature.";
1426     return false;
1427   }
1428   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
1429   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
1430
1431   size_t aConcealedResults = aResults.size();
1432   if (!aConcealedResults && !theArguments.empty()) {
1433     // find if these results are touched by the feature in another attribute
1434     std::list<std::string>::const_iterator anIt = theArguments.begin();
1435     std::string aRecoveredList = *anIt;
1436     if (!aRecoveredList.empty()) {
1437       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
1438                                  theAttribute->owner()->data()->reflist(aRecoveredList);
1439       if (aParameterList.get())
1440         aConcealedResults = aParameterList->size();
1441     }
1442   }
1443
1444   if (aConcealedResults == 0)
1445     theError = "Error: No concealed results.";
1446
1447   return theError.empty();
1448 }
1449
1450 bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
1451                                                const std::list<std::string>& theArguments,
1452                                                Events_InfoMessage& theError) const
1453 {
1454   static std::list<std::string> aEdgeArg(1, "circle");
1455   static std::list<std::string> aFaceArg(1, "cylinder");
1456
1457   Events_InfoMessage aError;
1458   bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
1459   if (!isValid) {
1460     isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
1461     if (!isValid)
1462       theError = "The shape neither circle nor cylinder";
1463   }
1464   return isValid;
1465 }
1466
1467 //=================================================================================================
1468 bool FeaturesPlugin_ValidatorBooleanArguments::isValid(
1469   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1470   const std::list<std::string>& theArguments,
1471   Events_InfoMessage& theError) const
1472 {
1473 // LCOV_EXCL_START
1474   if (theArguments.size() != 2)
1475   {
1476     theError = "Wrong number of arguments (expected 2).";
1477     return false;
1478   }
1479 // LCOV_EXCL_STOP
1480
1481   int anObjectsToolsNb[2] = { 0,  0 };
1482
1483   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1484
1485   bool isAllInSameCompSolid = true;
1486   ResultBodyPtr aCompSolid;
1487
1488   for (int* anArgNbIt = anObjectsToolsNb; anIt != aLast; ++anIt, ++anArgNbIt) {
1489     AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1490     if (anAttrSelList)
1491     {
1492       *anArgNbIt = anAttrSelList->size();
1493       if (isAllInSameCompSolid) {
1494         for (int anIndex = 0; anIndex < *anArgNbIt; ++anIndex)
1495         {
1496           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1497           ResultPtr aContext = anAttr->context();
1498           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1499           if (aResCompSolidPtr.get())
1500           {
1501             if (aCompSolid.get())
1502             {
1503               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1504             }
1505             else
1506             {
1507               aCompSolid = aResCompSolidPtr;
1508             }
1509           }
1510           else
1511           {
1512             isAllInSameCompSolid = false;
1513             break;
1514           }
1515         }
1516       }
1517     }
1518   }
1519
1520   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1521     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1522   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1523
1524   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1525   {
1526     // Fuse operation
1527     if (anObjectsToolsNb[0] + anObjectsToolsNb[1] < 2)
1528     {
1529       theError = "Not enough arguments for Fuse operation.";
1530       return false;
1531     }
1532     else if (isAllInSameCompSolid)
1533     {
1534       theError = "Operations only between sub-shapes of the same shape not allowed.";
1535       return false;
1536     }
1537   }
1538   else
1539   {
1540     if (anObjectsToolsNb[0] < 1) // check number of objects
1541     {
1542       theError = "Objects not selected.";
1543       return false;
1544     }
1545     if (anObjectsToolsNb[1] < 1) // check number of tools
1546     {
1547       theError = "Tools not selected.";
1548       return false;
1549     }
1550     if (isAllInSameCompSolid)
1551     {
1552       theError = "Operations only between sub-shapes of the same shape not allowed.";
1553       return false;
1554     }
1555   }
1556
1557   return true;
1558 }
1559
1560 //=================================================================================================
1561 // LCOV_EXCL_START
1562 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1563                                                                std::string theAttribute)
1564 {
1565   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1566   {
1567     return true;
1568   }
1569
1570   return false;
1571 }
1572 // LCOV_EXCL_STOP
1573
1574 //==================================================================================================
1575 bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
1576   const AttributePtr& theAttribute,
1577   const std::list<std::string>& theArguments,
1578   Events_InfoMessage& theError) const
1579 {
1580   std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
1581     std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
1582
1583   AttributeSelectionListPtr anAttrSelectionList =
1584     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1585   if (!aFeature.get() || !anAttrSelectionList.get()) {
1586 // LCOV_EXCL_START
1587     theError =
1588       "Error: Validator used in wrong feature or attribute";
1589     return false;
1590 // LCOV_EXCL_STOP
1591   }
1592
1593   AttributeSelectionListPtr anOtherAttrSelectionList;
1594   if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
1595     anOtherAttrSelectionList =
1596       aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
1597   } else {
1598     anOtherAttrSelectionList =
1599       aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
1600   }
1601
1602   GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
1603   GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
1604   GeomPlanePtr aFacesPln;
1605
1606   for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
1607     AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
1608
1609     if (anAttrSelection->contextFeature().get()) {
1610       theError = "Error: Features not allowed for selection.";
1611       return false;
1612     }
1613
1614     ResultPtr aContext = anAttrSelection->context();
1615     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1616     if (!aShape.get()) {
1617       if (!aContext.get()) {
1618         theError = "Error: Empty selection.";
1619         return false;
1620       }
1621       aShape = aContext->shape();
1622     }
1623
1624     if (aShape->isSolid() || aShape->isCompSolid()) {
1625       aSelectedShapesType = GeomAPI_Shape::SOLID;
1626       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1627       if (aResCompSolidPtr.get()) {
1628         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1629         aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
1630       }
1631     } else {
1632       aSelectedShapesType = GeomAPI_Shape::FACE;
1633       GeomAPI_Face aFace(aShape);
1634       aFacesPln = aFace.getPlane();
1635       break;
1636     }
1637   }
1638
1639   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1640     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1641     if (!anAttrSelection.get()) {
1642       theError = "Error: Empty attribute selection.";
1643       return false;
1644     }
1645
1646     if (anAttrSelection->contextFeature().get()) {
1647       theError = "Error: Features not allowed for selection.";
1648       return false;
1649     }
1650
1651     ResultPtr aContext = anAttrSelection->context();
1652     if(!aContext.get()) {
1653       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1654       if (!aContFeat.get() || !aContFeat->results().size() ||
1655           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1656         theError = "Error: Empty selection context.";
1657         return false;
1658       }
1659     }
1660     ResultConstructionPtr aResultConstruction =
1661       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1662     if (aResultConstruction.get()) {
1663       theError = "Error: Result construction not allowed for selection.";
1664       return false;
1665     }
1666     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1667     GeomShapePtr aContextShape = aContext->shape();
1668     if (!aShape.get()) {
1669       aShape = aContextShape;
1670     }
1671     if (!aShape.get()) {
1672       theError = "Error: Empty shape.";
1673       return false;
1674     }
1675     if (!aShape->isEqual(aContextShape)) {
1676       theError = "Error: Local selection not allowed.";
1677       return false;
1678     }
1679
1680     if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
1681       // Other list is empty.
1682       if (aShape->isSolid() || aShape->isCompSolid()) {
1683         aSelectedShapesType = GeomAPI_Shape::SOLID;
1684       } else {
1685         aSelectedShapesType = GeomAPI_Shape::FACE;
1686         GeomAPI_Face aFace(aShape);
1687         aFacesPln = aFace.getPlane();
1688
1689         if (!aFacesPln.get()) {
1690           theError = "Error: Only planar faces allowed.";
1691           return false;
1692         }
1693       }
1694
1695       continue;
1696     } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
1697       if (!aShape->isSolid() && !aShape->isCompSolid()) {
1698         theError = "Error: Selected shapes should have the same type.";
1699         return false;
1700       }
1701     } else {
1702       GeomAPI_Face aFace(aShape);
1703       GeomPlanePtr aPln = aFace.getPlane();
1704
1705       if (!aPln.get()) {
1706         theError = "Error: Only planar faces allowed.";
1707         return false;
1708       }
1709
1710       if (!aFacesPln->isCoincident(aPln)) {
1711         theError = "Error: Only coincident faces allowed.";
1712         return false;
1713       }
1714     }
1715   }
1716
1717   return true;
1718 }
1719
1720 //==================================================================================================
1721 // LCOV_EXCL_START
1722 bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttribute,
1723                                                    const std::list<std::string>& theArguments,
1724                                                    Events_InfoMessage& theError) const
1725 {
1726   if (!theAttribute.get()) {
1727     theError = "Error: empty selection.";
1728     return false;
1729   }
1730   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1731   AttributeSelectionListPtr anAttrSelectionList =
1732     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1733   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1734     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1735     if (!anAttrSelection.get()) {
1736       theError = "Error: empty attribute selection.";
1737       return false;
1738     }
1739     ResultPtr aContext = anAttrSelection->context();
1740     if (aContext.get()) {
1741       aFeature = ModelAPI_Feature::feature(aContext);
1742     } else {
1743       aFeature = anAttrSelection->contextFeature();
1744       if (!aFeature.get() || !aFeature->results().size() ||
1745           aFeature->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1746         theError = "Error: Empty selection context.";
1747         return false;
1748       }
1749     }
1750     if (!aFeature.get()) {
1751       theError = "Error: empty feature.";
1752       return false;
1753     }
1754     std::string aFeatureKind = aFeature->getKind();
1755     if (aFeatureKind == "Sketch" ||
1756         aFeatureKind == "Plane" ||
1757         aFeatureKind == "Axis") {
1758       theError = "Error: %1 shape is not allowed for selection.";
1759       theError.arg(aFeatureKind);
1760       return false;
1761     }
1762     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1763     if (!aShape.get()) {
1764       GeomShapePtr aContextShape = aContext->shape();
1765       aShape = aContextShape;
1766     }
1767     if (!aShape.get()) {
1768       theError = "Error: empty shape.";
1769       return false;
1770     }
1771     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1772       theError = "Error: Local selection not allowed.";
1773       return false;
1774     }
1775
1776     int aShapeType = aShape->shapeType();
1777     // Allow to select edges, faces and solids.
1778     if (aShapeType != GeomAPI_Shape::EDGE &&
1779         aShapeType != GeomAPI_Shape::FACE &&
1780         aShapeType != GeomAPI_Shape::SOLID &&
1781         aShapeType != GeomAPI_Shape::COMPSOLID &&
1782         aShapeType != GeomAPI_Shape::COMPOUND) {
1783       theError = "Error: selected shape has the wrong type.";
1784       return false;
1785     }
1786   }
1787
1788   return true;
1789 }
1790 // LCOV_EXCL_STOP
1791
1792 //==================================================================================================
1793 // LCOV_EXCL_START
1794 bool FeaturesPlugin_ValidatorBooleanFuseSelection::isValid(
1795   const AttributePtr& theAttribute,
1796   const std::list<std::string>& theArguments,
1797   Events_InfoMessage& theError) const
1798 {
1799   AttributeSelectionListPtr anAttrSelectionList =
1800     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1801   if (!anAttrSelectionList.get()) {
1802     theError =
1803       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1804     return false;
1805   }
1806
1807   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1808     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1809     if (!anAttrSelection.get()) {
1810       theError = "Error: Empty attribute selection.";
1811       return false;
1812     }
1813     ResultPtr aContext = anAttrSelection->context();
1814     if(!aContext.get()) {
1815       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1816       if (!aContFeat.get() || !aContFeat->results().size() ||
1817           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1818         theError = "Error: Empty selection context.";
1819         return false;
1820       }
1821     }
1822     ResultConstructionPtr aResultConstruction =
1823       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1824     if (aResultConstruction.get()) {
1825       theError = "Error: Result construction not allowed for selection.";
1826       return false;
1827     }
1828     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1829     if (!aShape.get()) {
1830       GeomShapePtr aContextShape = aContext->shape();
1831       aShape = aContextShape;
1832     }
1833     if (!aShape.get()) {
1834       theError = "Error: Empty shape.";
1835       return false;
1836     }
1837     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1838       theError = "Error: Local selection not allowed.";
1839       return false;
1840     }
1841   }
1842
1843   return true;
1844 }
1845 // LCOV_EXCL_STOP
1846
1847 //=================================================================================================
1848 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
1849   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1850   const std::list<std::string>& theArguments,
1851   Events_InfoMessage& theError) const
1852 {
1853 // LCOV_EXCL_START
1854   if (theArguments.size() != 2) {
1855     theError = "Wrong number of arguments (expected 2).";
1856     return false;
1857   }
1858 // LCOV_EXCL_STOP
1859
1860   std::shared_ptr<FeaturesPlugin_BooleanFuse> aFeature =
1861     std::dynamic_pointer_cast<FeaturesPlugin_BooleanFuse>(theFeature);
1862
1863   int anObjectsNb = 0, aToolsNb = 0;
1864
1865   std::list<std::string>::const_iterator anIt = theArguments.begin();
1866
1867   bool isAllInSameCompSolid = true;
1868   ResultBodyPtr aCompSolid;
1869
1870   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1871   if (anAttrSelList) {
1872     anObjectsNb = anAttrSelList->size();
1873     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex) {
1874       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1875       ResultPtr aContext = anAttr->context();
1876       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1877       if (aResCompSolidPtr.get()) {
1878         if (aCompSolid.get()) {
1879           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1880         } else {
1881           aCompSolid = aResCompSolidPtr;
1882         }
1883       } else {
1884         isAllInSameCompSolid = false;
1885         break;
1886       }
1887     }
1888   }
1889   anIt++;
1890
1891   if (aFeature->string(FeaturesPlugin_BooleanFuse::CREATION_METHOD())->value()
1892       == FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED()) {
1893     anAttrSelList = theFeature->selectionList(*anIt);
1894     if (anAttrSelList) {
1895       aToolsNb = anAttrSelList->size();
1896       if (isAllInSameCompSolid) {
1897         for (int anIndex = 0; anIndex < aToolsNb; ++anIndex) {
1898           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1899           ResultPtr aContext = anAttr->context();
1900           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1901           if (aResCompSolidPtr.get()) {
1902             if (aCompSolid.get()) {
1903               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1904             } else {
1905               aCompSolid = aResCompSolidPtr;
1906             }
1907           } else {
1908             isAllInSameCompSolid = false;
1909             break;
1910           }
1911         }
1912       }
1913     }
1914   }
1915
1916   if (anObjectsNb + aToolsNb < 2) {
1917     theError = "Not enough arguments for Fuse operation.";
1918     return false;
1919   }
1920
1921   return true;
1922 }
1923
1924 //=================================================================================================
1925 // LCOV_EXCL_START
1926 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isNotObligatory(
1927   std::string theFeature,
1928   std::string theAttribute)
1929 {
1930   if (theAttribute == "main_objects" || theAttribute == "tool_objects") {
1931     return true;
1932   }
1933
1934   return false;
1935 }
1936 // LCOV_EXCL_STOP
1937
1938 //==================================================================================================
1939 // LCOV_EXCL_START
1940 bool FeaturesPlugin_ValidatorBooleanCommonSelection::isValid(
1941   const AttributePtr& theAttribute,
1942   const std::list<std::string>& theArguments,
1943   Events_InfoMessage& theError) const
1944 {
1945   AttributeSelectionListPtr anAttrSelectionList =
1946     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1947   if (!anAttrSelectionList.get()) {
1948     theError =
1949       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1950     return false;
1951   }
1952
1953   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1954     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1955     if (!anAttrSelection.get()) {
1956       theError = "Error: Empty attribute selection.";
1957       return false;
1958     }
1959     ResultPtr aContext = anAttrSelection->context();
1960     if (!aContext.get() && !anAttrSelection->contextFeature().get()) {
1961       theError = "Error: Empty selection context.";
1962       return false;
1963     }
1964     ResultConstructionPtr aResultConstruction =
1965       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1966     if (aResultConstruction.get()) {
1967       if (theAttribute->id() != FeaturesPlugin_BooleanCommon::TOOL_LIST_ID()) {
1968         theError = "Error: Result construction not allowed for selection.";
1969         return false;
1970       }
1971     }
1972     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1973     GeomShapePtr aContextShape;
1974     if (aContext.get()) {
1975       aContextShape = aContext->shape();
1976     }
1977     if (!aShape.get()) {
1978       aShape = aContextShape;
1979     }
1980     if (!aShape.get()) {
1981       theError = "Error: Empty shape.";
1982       return false;
1983     }
1984     if (aContextShape.get() && !aShape->isEqual(aContextShape)) {
1985       theError = "Error: Local selection not allowed.";
1986       return false;
1987     }
1988
1989     if (aResultConstruction.get() && aShape->shapeType() != GeomAPI_Shape::FACE) {
1990       theError = "Error: Result construction should be plane.";
1991       return false;
1992     }
1993   }
1994
1995   return true;
1996 }
1997 // LCOV_EXCL_STOP
1998
1999 //=================================================================================================
2000 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
2001   const std::shared_ptr<ModelAPI_Feature>& theFeature,
2002   const std::list<std::string>& theArguments,
2003   Events_InfoMessage& theError) const
2004 {
2005   if (theArguments.size() != 2) {
2006 // LCOV_EXCL_START
2007     theError = "Wrong number of arguments (expected 2).";
2008     return false;
2009 // LCOV_EXCL_STOP
2010   }
2011
2012   std::shared_ptr<FeaturesPlugin_BooleanCommon> aFeature =
2013     std::dynamic_pointer_cast<FeaturesPlugin_BooleanCommon>(theFeature);
2014
2015   int anObjectsNb = 0, aToolsNb = 0;
2016
2017   std::list<std::string>::const_iterator anIt = theArguments.begin();
2018
2019   ResultBodyPtr aCompSolid;
2020
2021   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
2022   if (anAttrSelList) {
2023     anObjectsNb = anAttrSelList->size();
2024   }
2025
2026   bool isSimpleMode = aFeature->string(FeaturesPlugin_BooleanCommon::CREATION_METHOD())->value()
2027                       == FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE();
2028
2029   if (!isSimpleMode) {
2030     anAttrSelList = theFeature->selectionList(*anIt);
2031     if (anAttrSelList) {
2032       aToolsNb = anAttrSelList->size();
2033     }
2034   }
2035
2036   if ((isSimpleMode && anObjectsNb < 2)
2037       || (!isSimpleMode && (anObjectsNb == 0 || aToolsNb == 0))) {
2038     theError = "Not enough arguments for Common operation.";
2039     return false;
2040   }
2041   return true;
2042 }
2043
2044 //=================================================================================================
2045 // LCOV_EXCL_START
2046 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
2047   std::string theFeature,
2048   std::string theAttribute)
2049 {
2050   return false;
2051 }
2052 // LCOV_EXCL_STOP
2053
2054 //==================================================================================================
2055 bool FeaturesPlugin_ValidatorDefeaturingSelection::isValid(
2056     const AttributePtr& theAttribute,
2057     const std::list<std::string>& theArguments,
2058     Events_InfoMessage& theError) const
2059 {
2060   AttributeSelectionListPtr anAttrSelectionList =
2061       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
2062   if (!anAttrSelectionList.get()) {
2063     // LCOV_EXCL_START
2064     theError = "Error: This validator can only work with selection list attributes.";
2065     return false;
2066     // LCOV_EXCL_STOP
2067   }
2068
2069   // Check selected entities are sub-shapes of solid or compsolid
2070   GeomShapePtr aBaseSolid;
2071   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
2072     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
2073     if (!anAttrSelection.get()) {
2074       theError = "Error: Empty attribute selection.";
2075       return false;
2076     }
2077     ResultPtr aContext = anAttrSelection->context();
2078     if (!aContext.get()) {
2079       theError = "Error: Empty selection context.";
2080       return false;
2081     }
2082
2083     GeomShapePtr aContextShape = aContext->shape();
2084     if (aContextShape->shapeType() != GeomAPI_Shape::SOLID) {
2085       theError = "Error: Not all selected shapes are sub-shapes of solids.";
2086       return false;
2087     }
2088
2089     ResultBodyPtr aResRootPtr = ModelAPI_Tools::bodyOwner(aContext, true);
2090     if (aResRootPtr.get() && aResRootPtr->shape().get()) {
2091       if (!aResRootPtr->shape()->isCollectionOfSolids()) {
2092         theError = "Error: The main shape should be a collection of solids";
2093         return false;
2094       }
2095     }
2096   }
2097
2098   return true;
2099 }
2100
2101 //==================================================================================================
2102 bool FeaturesPlugin_ValidatorSewingSelection::isValid(const AttributePtr& theAttribute,
2103                                                       const std::list<std::string>& theArguments,
2104                                                       Events_InfoMessage& theError) const
2105 {
2106   AttributeSelectionListPtr anAttrSelectionList =
2107       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
2108   if (!anAttrSelectionList.get()) {
2109     theError = "Error: This validator can only work with selection list attributes.";
2110     return false;
2111   }
2112
2113   // Check selected entities are of valid types
2114   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
2115     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
2116     if (!anAttrSelection.get()) {
2117       theError = "Error: Empty attribute selection.";
2118       return false;
2119     }
2120     ResultPtr aContext = anAttrSelection->context();
2121     if (!aContext.get()) {
2122       theError = "Error: Empty selection context.";
2123       return false;
2124     }
2125     if (aContext->groupName() != ModelAPI_ResultBody::group()) {
2126       theError = "Error: Not a result body.";
2127       return false;
2128     }
2129
2130     GeomShapePtr aContextShape = aContext->shape();
2131     if (!aContextShape.get()) {
2132       theError = "Error: Empty shape.";
2133       return false;
2134     }
2135
2136     GeomAPI_Shape::ShapeType aShapeType = aContextShape->shapeType();
2137     std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
2138     anAllowedTypes.insert(GeomAPI_Shape::FACE);
2139     anAllowedTypes.insert(GeomAPI_Shape::SHELL);
2140     anAllowedTypes.insert(GeomAPI_Shape::SOLID);
2141     anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
2142     anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
2143     if (anAllowedTypes.find(aShapeType) == anAllowedTypes.end()) {
2144       theError = "Error: Selected shape has the wrong type.";
2145       return false;
2146     }
2147
2148   }
2149
2150   return true;
2151 }
2152
2153 //==================================================================================================
2154 bool FeaturesPlugin_ValidatorGlueFacesSelection::isValid(const AttributePtr& theAttribute,
2155                                                          const std::list<std::string>& theArguments,
2156                                                          Events_InfoMessage& theError) const
2157 {
2158   AttributeSelectionListPtr anAttrSelectionList =
2159       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
2160   if (!anAttrSelectionList.get()) {
2161     theError = "Error: This validator can only work with selection list attributes.";
2162     return false;
2163   }
2164
2165   // Check selected entities are of valid types
2166   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
2167     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
2168     if (!anAttrSelection.get()) {
2169       theError = "Error: Empty attribute selection.";
2170       return false;
2171     }
2172     ResultPtr aContext = anAttrSelection->context();
2173     if (!aContext.get()) {
2174       theError = "Error: Empty selection context.";
2175       return false;
2176     }
2177     if (aContext->groupName() != ModelAPI_ResultBody::group()) {
2178       theError = "Error: Not a result body.";
2179       return false;
2180     }
2181
2182     GeomShapePtr aContextShape = aContext->shape();
2183     if (!aContextShape.get()) {
2184       theError = "Error: Empty shape.";
2185       return false;
2186     }
2187
2188     GeomAPI_Shape::ShapeType aShapeType = aContextShape->shapeType();
2189     std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
2190     anAllowedTypes.insert(GeomAPI_Shape::FACE);
2191     anAllowedTypes.insert(GeomAPI_Shape::SHELL);
2192     anAllowedTypes.insert(GeomAPI_Shape::SOLID);
2193     anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
2194     anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
2195     if (anAllowedTypes.find(aShapeType) == anAllowedTypes.end()) {
2196       theError = "Error: Selected shape has the wrong type.";
2197       return false;
2198     }
2199
2200   }
2201
2202   return true;
2203 }