]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
Salome HOME
Make tests working on new results structure and selection of feature as argument
[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_Union.h"
25
26 #include <Events_InfoMessage.h>
27
28 #include <ModelAPI_Attribute.h>
29 #include <ModelAPI_AttributeInteger.h>
30 #include <ModelAPI_AttributeSelectionList.h>
31 #include <ModelAPI_AttributeString.h>
32 #include <ModelAPI_AttributeReference.h>
33 #include <ModelAPI_AttributeRefList.h>
34 #include <ModelAPI_Feature.h>
35 #include <ModelAPI_ResultBody.h>
36 #include <ModelAPI_ResultConstruction.h>
37 #include <ModelAPI_Tools.h>
38
39 #include <GeomValidators_BodyShapes.h>
40 #include <GeomValidators_Face.h>
41 #include <GeomValidators_FeatureKind.h>
42 #include <GeomValidators_ShapeType.h>
43
44 #include <GeomAPI_DataMapOfShapeShape.h>
45 #include <GeomAPI_Lin.h>
46 #include <GeomAPI_PlanarEdges.h>
47 #include <GeomAPI_ShapeExplorer.h>
48 #include <GeomAPI_ShapeIterator.h>
49
50 #include <GeomAlgoAPI_CompoundBuilder.h>
51 #include <GeomAlgoAPI_ShapeBuilder.h>
52 #include <GeomAlgoAPI_ShapeTools.h>
53 #include <GeomAlgoAPI_WireBuilder.h>
54
55 #define _USE_MATH_DEFINES
56 #include <math.h>
57
58 //==================================================================================================
59 bool FeaturesPlugin_ValidatorPipePath::isValid(const AttributePtr& theAttribute,
60                                                const std::list<std::string>& theArguments,
61                                                Events_InfoMessage& theError) const
62 {
63   AttributeSelectionPtr aPathAttrSelection =
64     std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
65   if(!aPathAttrSelection.get()) {
66     theError = "Error: This validator can only work with path selector in \"Pipe\" feature.";
67     return false;
68   }
69
70   GeomShapePtr aPathShape = aPathAttrSelection->value();
71   ResultPtr aContext = aPathAttrSelection->context();
72   if(!aContext.get()) {
73     theError = "Error: Empty context.";
74     return false;
75   }
76   GeomShapePtr aContextShape = aContext->shape();
77   if(aPathShape.get() && aPathShape->shapeType() == GeomAPI_Shape::WIRE &&
78       !aPathShape->isEqual(aContextShape)) {
79     theError = "Error: Local selection of wires not allowed.";
80     return false;
81   }
82
83   return true;
84 }
85
86 //==================================================================================================
87 bool FeaturesPlugin_ValidatorPipeLocations::isValid(
88   const std::shared_ptr<ModelAPI_Feature>& theFeature,
89   const std::list<std::string>& theArguments,
90   Events_InfoMessage& theError) const
91 {
92   static const std::string aCreationMethodID = "creation_method";
93   static const std::string aBaseObjectsID = "base_objects";
94   static const std::string aLocationsID = "locations_objects";
95
96   if(theFeature->getKind() != "Pipe") {
97     theError = "Error: Feature \"%1\" does not supported by this validator.";
98     theError.arg(theFeature->getKind());
99     return false;
100   }
101
102   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
103   if(!aCreationMethodAttr.get()) {
104     theError = "Error: Could not get \"%1\" attribute.";
105     theError.arg(aCreationMethodID);
106     return false;
107   }
108
109   if(aCreationMethodAttr->value() != "locations") {
110     return true;
111   }
112
113   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
114   if(!aBaseObjectsSelectionList.get()) {
115     theError = "Error: Could not get \"%1\" attribute.";
116     theError.arg(aBaseObjectsID);
117     return false;
118   }
119
120   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
121   if(!aLocationsSelectionList.get()) {
122     theError = "Error: Could not get \"%1\" attribute.";
123     theError.arg(aBaseObjectsID);
124     return false;
125   }
126
127   if(aLocationsSelectionList->size() > 0 &&
128      aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
129     theError = "Error: Number of locations should be the same as base objects.";
130     return false;
131   }
132
133   return true;
134 }
135
136 //==================================================================================================
137 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
138                                                         const std::list<std::string>& theArguments,
139                                                         Events_InfoMessage& theError) const
140 {
141   if(theArguments.empty()) {
142     theError = "Error: Validator parameters is empty.";
143     return false;
144   }
145
146   // Checking attribute.
147   if(!isValidAttribute(theAttribute, theArguments, theError)) {
148     if(theError.empty()) {
149       theError = "Error: Attribute contains unacceptable shape.";
150     }
151     return false;
152   }
153
154   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
155   std::string anAttributeType = theAttribute->attributeType();
156   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
157     AttributeSelectionListPtr aListAttr =
158       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
159     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
160       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
161       ResultPtr aContext = aSelectionAttr->context();
162       if(!aContext.get()) {
163         theError = "Error: Empty context.";
164         return false;
165       }
166
167       ResultConstructionPtr aResultConstruction =
168         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
169       if(!aResultConstruction.get()) {
170         // It is not a result construction.
171         // If shape is compound check that it contains only faces and edges.
172         GeomShapePtr aShape = aSelectionAttr->value();
173         if(!aShape.get()) {
174           aShape = aContext->shape();
175         }
176
177         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
178           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
179             GeomShapePtr aSubShape = anIt.current();
180             if(aSubShape->shapeType() != GeomAPI_Shape::EDGE
181                 && aSubShape->shapeType() != GeomAPI_Shape::FACE) {
182               theError = "Error: Compound should contain only faces and edges.";
183               return false;
184             }
185           }
186         }
187
188         continue;
189       }
190
191       GeomShapePtr aShape = aSelectionAttr->value();
192       GeomShapePtr aContextShape = aResultConstruction->shape();
193       if(!aShape.get()) {
194         // Whole sketch selected.
195         continue;
196       } else {
197         // Object from sketch selected.
198         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
199           GeomShapePtr aWire = anExp.current();
200           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
201             theError = "Error: Wire with wrong orientation selected.";
202             return false;
203           }
204
205           if(aSelectedWiresFromObjects.isBound(aWire)) {
206             theError =
207               "Error: Objects with such wire already selected. Don't allow to select this object.";
208             return false;
209           }
210
211           aSelectedWiresFromObjects.bind(aWire, aWire);
212         }
213       }
214     }
215   }
216
217   return true;
218 }
219
220 //==================================================================================================
221 bool FeaturesPlugin_ValidatorBaseForGenerationSketchOrSketchObjects::isValid(
222   const std::shared_ptr<ModelAPI_Feature>& theFeature,
223   const std::list<std::string>& theArguments,
224   Events_InfoMessage& theError) const
225 {
226   const std::string aBaseObjectsID = theArguments.front();
227
228   AttributeSelectionListPtr aListAttr = theFeature->selectionList(aBaseObjectsID);
229   if(!aListAttr.get()) {
230     theError = "Error: Could not get \"%1\" attribute.";
231     theError.arg(aBaseObjectsID);
232     return false;
233   }
234
235   std::set<ResultConstructionPtr> aSelectedSketches;
236   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
237
238   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
239     AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
240     ResultPtr aContext = aSelectionAttr->context();
241     if(!aContext.get()) {
242       theError = "Error: Empty context.";
243       return false;
244     }
245
246     ResultConstructionPtr aResultConstruction =
247       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
248     if(!aResultConstruction.get()) {
249       // It is not a result construction.
250       continue;
251     }
252
253     GeomShapePtr aShape = aSelectionAttr->value();
254     GeomShapePtr aContextShape = aResultConstruction->shape();
255     if(!aShape.get()) {
256       // Whole sketch selected.
257       aSelectedSketches.insert(aResultConstruction);
258     } else {
259       // Object from sketch selected.
260       aSelectedSketchesFromObjects.insert(aResultConstruction);
261     }
262   }
263
264
265   for(std::set<ResultConstructionPtr>::const_iterator anIt = aSelectedSketches.cbegin();
266       anIt != aSelectedSketches.cend();
267       ++anIt) {
268     ResultConstructionPtr aResultConstruction = *anIt;
269     if(aSelectedSketchesFromObjects.find(aResultConstruction) !=
270         aSelectedSketchesFromObjects.cend()) {
271       theError = "Sketch and objects from it can not be selected at the same time.";
272       return false;
273     }
274   }
275
276   return true;
277 }
278
279 //==================================================================================================
280 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
281                                                         const std::list<std::string>& theArguments,
282                                                         Events_InfoMessage& theError) const
283 {
284   if(!theAttribute.get()) {
285     theError = "Error: Empty attribute.";
286     return false;
287   }
288
289   std::string anAttributeType = theAttribute->attributeType();
290   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
291     AttributeSelectionListPtr aListAttr =
292       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
293     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
294       // If at least one attribute is invalid, the result is false.
295       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
296         return false;
297       }
298     }
299   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
300     // Getting context.
301     AttributeSelectionPtr anAttr =
302       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
303     ResultPtr aContext = anAttr->context();
304     if(!aContext.get()) {
305       theError = "Error: Attribute have empty context.";
306       return false;
307     }
308
309     GeomShapePtr aShape = anAttr->value();
310     GeomShapePtr aContextShape = aContext->shape();
311     if(!aShape.get()) {
312       aShape = aContextShape;
313     }
314     if(!aShape.get()) {
315       theError = "Error: Empty shape selected";
316       return false;
317     }
318
319     ResultConstructionPtr aConstruction =
320       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
321     if(aConstruction.get()) {
322       // Construciotn selected. Check that is is not infinite.
323       if(aConstruction->isInfinite()) {
324         theError = "Error: Infinite constructions is not allowed as base.";
325         return false;
326       }
327
328       if(aShape->isEqual(aContextShape)) {
329         // Whole construction selected. Check that it have faces.
330         if(aConstruction->facesNum() > 0) {
331           return true;
332         }
333       } else {
334         // Shape on construction selected. Check that it is a face or wire.
335         if(aShape->shapeType() == GeomAPI_Shape::WIRE ||
336            aShape->shapeType() == GeomAPI_Shape::FACE) {
337           return true;
338         }
339       }
340
341       return false;
342     }
343
344     if(!aShape->isEqual(aContextShape)) {
345       // Local selection on body does not allowed.
346       theError =
347         "Error: Selected shape is in the local selection. Only global selection is allowed.";
348       return false;
349     }
350
351     // Check that object is a shape with allowed type.
352     GeomValidators_ShapeType aShapeTypeValidator;
353     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
354       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
355                  "wires on sketch, whole sketch(if it has at least one face), "
356                  "and whole objects with shape types: %1";
357       std::string anArgumentString;
358       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
359         if (!anArgumentString.empty())
360           anArgumentString += ", ";
361         anArgumentString += *anIt;
362       }
363       theError.arg(anArgumentString);
364       return false;
365     }
366
367   } else {
368     theError = "Error: Attribute \"%1\" does not supported by this validator.";
369     theError.arg(anAttributeType);
370     return false;
371   }
372
373   return true;
374 }
375
376 //==================================================================================================
377 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
378                                                         const std::list<std::string>& theArguments,
379                                                         Events_InfoMessage& theError) const
380 {
381   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
382     theError = "Error: The attribute with the %1 type is not processed";
383     theError.arg(theAttribute->attributeType());
384     return false;
385   }
386   if (theArguments.size() != 2) {
387     theError = "Error: Wrong parameters in XML definition for %1 type";
388     theError.arg(theAttribute->attributeType());
389     return false;
390   }
391   // first argument is for the base attribute, second - for skipping feature kind
392   std::list<std::string>::const_iterator anIt = theArguments.begin();
393   std::string aBaseAttributeId = *anIt;
394   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
395   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
396   if (!aBaseAttribute.get()) {
397     theError = "Wrong parameters in XML definition for %1 type";
398     theError.arg(theAttribute->attributeType());
399     return false;
400   }
401   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
402     // this validator is not necessary anymore
403     return true;
404
405   anIt++;
406   std::string aFeatureAttributeKind = *anIt;
407   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
408   // check whether the selection is on the sketch
409   std::list<std::string> anArguments;
410   anArguments.push_back(aFeatureAttributeKind);
411
412   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
413   bool aPlanarFace = false;
414   // check if selection has Face selected
415   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
416   anArguments.clear();
417   anArguments.push_back("face");
418   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
419
420   bool aValid = !aFeatureKind && aPlanarFace;
421   return aValid;
422 }
423
424 //==================================================================================================
425 bool FeaturesPlugin_ValidatorExtrusionDir::isValid(
426                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
427                                                const std::list<std::string>& theArguments,
428                                                Events_InfoMessage& theError) const
429 {
430   if(theArguments.size() != 2) {
431     theError = "Error: Validator should be used with 2 parameters for extrusion.";
432     return false;
433   }
434
435   std::list<std::string>::const_iterator
436     anArgsIt = theArguments.begin(), aLast = theArguments.end();
437
438   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
439   ++anArgsIt;
440
441   GeomShapePtr aDirShape;
442   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
443   if(aSelAttr.get()) {
444     aDirShape = aSelAttr->value();
445     if(!aDirShape.get()) {
446       ResultPtr aContext = aSelAttr->context();
447       if(aContext.get()) {
448         aDirShape = aContext->shape();
449       }
450     }
451   }
452
453   if(!aDirShape.get()) {
454     // Check that dir can be empty.
455     if(!isShapesCanBeEmpty(aCheckAttribute, theError)) {
456       theError = "Error: Base objects list contains vertex or edge, so attribute \"%1\" "
457                  "can not be used with default value. Select direction for extrusion.";
458       theError.arg(*anArgsIt);
459       return false;
460     } else {
461       return true;
462     }
463   }
464
465   std::shared_ptr<GeomAPI_Edge> aDirEdge(new GeomAPI_Edge(aDirShape));
466
467   // If faces selected check that direction not parallel with them.
468   AttributeSelectionListPtr aListAttr =
469     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aCheckAttribute);
470   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
471     AttributeSelectionPtr anAttr = aListAttr->value(anIndex);
472     GeomShapePtr aShapeInList = anAttr->value();
473     if(!aShapeInList.get()) {
474       aShapeInList = anAttr->context()->shape();
475     }
476     bool isParallel = true;
477     if(aShapeInList->shapeType() == GeomAPI_Shape::FACE ||
478        aShapeInList->shapeType() == GeomAPI_Shape::SHELL) {
479       for(GeomAPI_ShapeExplorer
480           anExp(aShapeInList, GeomAPI_Shape::FACE); anExp.more(); anExp.next()) {
481         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(anExp.current()));
482         isParallel = GeomAlgoAPI_ShapeTools::isParallel(aDirEdge, aFace);
483         if(isParallel) {
484           break;
485         }
486       }
487     } else if(aShapeInList->shapeType() == GeomAPI_Shape::COMPOUND) {
488       std::shared_ptr<GeomAPI_PlanarEdges> aPlanarEdges =
489         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aShapeInList);
490       if(aPlanarEdges.get()) {
491         std::shared_ptr<GeomAPI_Dir> aSketchDir = aPlanarEdges->norm();
492         if(aDirEdge->isLine()) {
493           std::shared_ptr<GeomAPI_Dir> aDir = aDirEdge->line()->direction();
494           isParallel = fabs(aSketchDir->angle(aDir) - M_PI / 2.0) < 10e-7;
495         } else {
496           isParallel = false;
497         }
498       } else {
499         isParallel = false;
500       }
501     } else {
502       isParallel = false;
503     }
504     if(isParallel) {
505       theError =
506         "Error: Direction is parallel to one of the selected face or face on selected shell.";
507       return false;
508     }
509   }
510
511   return true;
512 }
513
514 //==================================================================================================
515 bool FeaturesPlugin_ValidatorExtrusionDir::isShapesCanBeEmpty(const AttributePtr& theAttribute,
516                                                               Events_InfoMessage& theError) const
517 {
518   if(!theAttribute.get()) {
519     return true;
520   }
521
522   std::string anAttributeType = theAttribute->attributeType();
523   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
524     AttributeSelectionListPtr aListAttr =
525       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
526     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
527       // If at least one attribute is invalid, the result is false.
528       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
529         return false;
530       }
531     }
532   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
533     // Getting context.
534     AttributeSelectionPtr anAttr =
535       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
536     ResultPtr aContext = anAttr->context();
537     if(!aContext.get()) {
538       return false;
539     }
540
541     GeomShapePtr aShape = anAttr->value();
542     GeomShapePtr aContextShape = aContext->shape();
543     if(!aShape.get()) {
544       aShape = aContextShape;
545     }
546     if(!aShape.get()) {
547       return false;
548     }
549
550     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
551        aShape->shapeType() == GeomAPI_Shape::EDGE ||
552        !aShape->isPlanar()) {
553       return false;
554     }
555   } else {
556     return false;
557   }
558
559   return true;
560 }
561
562 //==================================================================================================
563 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
564                                                        const std::list<std::string>& theArguments,
565                                                        Events_InfoMessage& theError) const
566 {
567   AttributeSelectionListPtr anAttrSelectionList =
568     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
569   if(!anAttrSelectionList.get()) {
570     theError =
571       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
572     return false;
573   }
574   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
575     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theAttribute->owner());
576   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
577
578   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
579     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
580     if(!anAttrSelection.get()) {
581       theError = "Error: Empty attribute selection.";
582       return false;
583     }
584     ResultPtr aContext = anAttrSelection->context();
585     if(!aContext.get()) {
586       FeaturePtr aContFeat = anAttrSelection->contextFeature();
587       if (!aContFeat.get()) {
588         theError = "Error: Empty selection context.";
589         return false;
590       }
591     }
592     ResultConstructionPtr aResultConstruction =
593       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
594     if(aResultConstruction.get()) {
595       if (anOperationType != FeaturesPlugin_Boolean::BOOL_FILL
596           || theAttribute->id() != FeaturesPlugin_Boolean::TOOL_LIST_ID()) {
597         theError = "Error: Result construction not allowed for selection.";
598         return false;
599       }
600     }
601     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
602     if(!aShape.get()) {
603       GeomShapePtr aContextShape = aContext->shape();
604       aShape = aContextShape;
605     }
606     if(!aShape.get()) {
607       theError = "Error: Empty shape.";
608       return false;
609     }
610     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
611       theError = "Error: Local selection not allowed.";
612       return false;
613     }
614
615     GeomAPI_Shape::ShapeType aShapeType = aShape->shapeType();
616     std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
617     if(anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE) {
618       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
619       anAllowedTypes.insert(GeomAPI_Shape::FACE);
620       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
621       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
622       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
623     } else if (anOperationType == FeaturesPlugin_Boolean::BOOL_FILL
624                || anOperationType == FeaturesPlugin_Boolean::BOOL_CUT)
625     {
626       anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
627       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
628       anAllowedTypes.insert(GeomAPI_Shape::WIRE);
629       anAllowedTypes.insert(GeomAPI_Shape::FACE);
630       anAllowedTypes.insert(GeomAPI_Shape::SHELL);
631       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
632       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
633       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
634     } else {
635       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
636       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
637       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
638     }
639
640     if(anAllowedTypes.find(aShapeType) == anAllowedTypes.end()
641       || (aResultConstruction.get() && aShapeType != GeomAPI_Shape::FACE)) {
642       theError = "Error: Selected shape has the wrong type.";
643       return false;
644     }
645
646   }
647
648   return true;
649 }
650
651 //==================================================================================================
652 bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAttribute,
653                                                       const std::list<std::string>& theArguments,
654                                                       Events_InfoMessage& theError) const
655 {
656   AttributeSelectionListPtr anAttrSelectionList =
657     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
658   if(!anAttrSelectionList.get()) {
659     theError =
660       "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
661     return false;
662   }
663
664   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
665   // Check all selected entities are sub-shapes of single solid
666   GeomShapePtr aBaseSolid;
667   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
668     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
669     if(!anAttrSelection.get()) {
670       theError = "Error: Empty attribute selection.";
671       return false;
672     }
673     ResultPtr aContext = anAttrSelection->context();
674     if(!aContext.get()) {
675       theError = "Error: Empty selection context.";
676       return false;
677     }
678
679     ResultBodyPtr aContextOwner = ModelAPI_Tools::bodyOwner(aContext);
680     GeomShapePtr anOwner = aContextOwner.get() ? aContextOwner->shape() : aContext->shape();
681
682     if (anOwner->shapeType() != GeomAPI_Shape::SOLID &&
683         anOwner->shapeType() != GeomAPI_Shape::COMPSOLID) {
684       theError = "Error: Not all selected shapes are sub-shapes of solids";
685       return false;
686     }
687
688     if (!aBaseSolid)
689       aBaseSolid = anOwner;
690     else if (!aBaseSolid->isEqual(anOwner)) {
691       theError = "Error: Sub-shapes of different solids have been selected.";
692       return false;
693     }
694   }
695
696   return true;
697 }
698
699 //==================================================================================================
700 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
701                                                        const std::list<std::string>& theArguments,
702                                                        Events_InfoMessage& theError) const
703 {
704   AttributeSelectionListPtr anAttrSelectionList =
705     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
706   if(!anAttrSelectionList.get()) {
707     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
708     return false;
709   }
710
711   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
712     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
713
714     //GeomValidators_BodyShapes aBodyValidator;
715     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
716     //  continue;
717     //}
718
719     GeomValidators_FeatureKind aFeatureKindValidator;
720     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
721       continue;
722     }
723
724     ResultPtr aContext = aSelectAttr->context();
725     ResultConstructionPtr aResultConstruction =
726       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
727     if(aResultConstruction.get()) {
728       theError = "Error: Only body shapes and construction planes are allowed for selection.";
729       return false;
730     }
731
732     ResultBodyPtr aResultBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
733     if(aResultBody.get()) {
734       continue;
735     }
736     FeaturePtr aResultFeature = aSelectAttr->contextFeature();
737     if(aResultFeature.get()) {
738       bool aOkRes = false;
739       std::list<ResultPtr>::const_iterator aFRes = aResultFeature->results().cbegin();
740       for(; aFRes != aResultFeature->results().cend() && !aOkRes; aFRes++) {
741         ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aFRes);
742         if (aBody.get() && !aBody->isDisabled())
743           aOkRes = true;
744       }
745       if (aOkRes)
746         continue;
747     }
748
749     theError = "Error: Only body shapes and construction planes are allowed for selection.";
750     return false;
751   }
752
753   theError = "";
754   return true;
755 }
756
757 //==================================================================================================
758 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
759                                                      const std::list<std::string>& theArguments,
760                                                      Events_InfoMessage& theError) const
761 {
762   AttributeSelectionListPtr aSubShapesAttrList =
763     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
764   if(!aSubShapesAttrList.get()) {
765     theError =
766       "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
767     return false;
768   }
769
770   static const std::string aBaseShapeID = "base_shape";
771   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
772   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
773
774   if(!aShapeAttrSelection.get()) {
775     theError = "Error: Could not get \"%1\" attribute.";
776     theError.arg(aBaseShapeID);
777     return false;
778   }
779
780   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
781   ResultPtr aContext = aShapeAttrSelection->context();
782   if(!aContext.get()) {
783     theError = "Error: Empty context.";
784     return false;
785   }
786   if(!aBaseShape.get()) {
787     aBaseShape = aContext->shape();
788   }
789   if(!aBaseShape.get()) {
790     theError = "Error: Empty base shape.";
791     return false;
792   }
793
794   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
795     bool isSameFound = false;
796     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
797     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
798     for(GeomAPI_ShapeIterator anIt(aBaseShape); anIt.more(); anIt.next()) {
799       if(anIt.current()->isEqual(aShapeToAdd)) {
800         isSameFound = true;
801         break;
802       }
803     }
804     if(!isSameFound) {
805       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
806       return false;
807     }
808   }
809
810   return true;
811 }
812
813 //==================================================================================================
814 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
815   const std::shared_ptr<ModelAPI_Feature>& theFeature,
816   const std::list<std::string>& theArguments,
817   Events_InfoMessage& theError) const
818 {
819   static const std::string aBaseShapeID = "base_shape";
820   static const std::string aSubShapesID = "subshapes_to_keep";
821
822   if(theFeature->getKind() != "Remove_SubShapes") {
823     theError = "Error: Feature \"%1\" does not supported by this validator.";
824     theError.arg(theFeature->getKind());
825     return false;
826   }
827
828   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
829   if(!aShapeAttrSelection.get()) {
830     theError = "Error: Could not get \"%1\" attribute.";
831     theError.arg(aBaseShapeID);
832     return false;
833   }
834
835   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
836   if(!aSubShapesAttrList.get()) {
837     theError = "Error: Could not get \"%1\" attribute.";
838     theError.arg(aSubShapesID);
839     return false;
840   }
841
842   // Copy base shape.
843   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
844   if(!aBaseShape.get()) {
845     theError = "Error: Base shape is empty.";
846     return false;
847   }
848   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
849
850   if (aSubShapesAttrList->size() == 0) {
851     theError = "Error: Resulting shape is not valid.";
852     return false;
853   }
854
855   // Copy sub-shapes from list to new shape.
856   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
857     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
858     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
859     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
860   }
861
862   // Check new shape.
863   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
864     theError = "Error: Resulting shape is not valid.";
865     return false;
866   }
867
868   return true;
869 }
870
871 //==================================================================================================
872 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
873                                                      const std::list<std::string>& theArguments,
874                                                      Events_InfoMessage& theError) const
875 {
876   AttributeSelectionListPtr aBaseObjectsAttrList =
877     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
878   if(!aBaseObjectsAttrList.get()) {
879     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
880     theError.arg(FeaturesPlugin_Union::ID());
881     return false;
882   }
883
884   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
885     bool isSameFound = false;
886     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
887     ResultPtr aContext = anAttrSelectionInList->context();
888     if (!aContext.get()) {
889       theError = "Error: selection is invalid.";
890       return false;
891     }
892
893     ResultConstructionPtr aConstruction =
894       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
895     if(aConstruction.get()) {
896       theError = "Error: Result construction not allowed for selection.";
897       return false;
898     }
899
900     GeomShapePtr aShape = anAttrSelectionInList->value();
901     GeomShapePtr aContextShape = aContext->shape();
902     if (aShape.get() && aContextShape.get() && !aContextShape->isEqual(aShape)) {
903       theError = "Error: Local selection not allowed.";
904       return false;
905     }
906
907     ResultBodyPtr aResult =
908       std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
909     if(!aResult.get()) {
910       continue;
911     }
912
913     if(aResult->numberOfSubs() > 0) {
914       theError = "Error: Whole compsolids not allowed for selection.";
915       return false;
916     }
917   }
918
919   return true;
920 }
921
922 //==================================================================================================
923 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
924   const std::shared_ptr<ModelAPI_Feature>& theFeature,
925   const std::list<std::string>& theArguments,
926   Events_InfoMessage& theError) const
927 {
928   // Check feature kind.
929   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
930     theError = "Error: This validator supports only \"%1\" feature.";
931     theError.arg(FeaturesPlugin_Union::ID());
932     return false;
933   }
934
935   // Get base objects attribute list.
936   AttributeSelectionListPtr aBaseObejctsAttrList =
937     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
938   if(!aBaseObejctsAttrList.get()) {
939     theError = "Error: Could not get \"%1\" attribute.";
940     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
941     return false;
942   }
943
944   // Get all shapes.
945   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::COMPSOLID;
946   ListOfShape aBaseShapesList;
947   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
948     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
949     GeomShapePtr aShape = anAttrSelectionInList->value();
950     if (!aShape.get()) {
951       continue;
952     }
953     aBaseShapesList.push_back(aShape);
954     aType = aShape->shapeType() == GeomAPI_Shape::FACE ? GeomAPI_Shape::SHELL :
955                                                          GeomAPI_Shape::COMPSOLID;
956   }
957
958   // Make compound and find connected.
959   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
960   ListOfShape aCombined, aFree;
961   GeomAlgoAPI_ShapeTools::combineShapes(
962     aCompound,
963     aType,
964     aCombined,
965     aFree);
966
967   if(aFree.size() > 0 || aCombined.size() > 1) {
968     theError = "Error: Not all shapes have shared topology.";
969     return false;
970   }
971
972   return true;
973 }
974
975 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
976                                             const std::list<std::string>& theArguments,
977                                             Events_InfoMessage& theError) const
978 {
979   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
980     theError = "Error: The attribute with the %1 type is not processed";
981     theError.arg(theAttribute->attributeType());
982     return false;
983   }
984
985   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
986                                                                                (theAttribute);
987   ObjectPtr aRefObject = aRefAttribute->value();
988   if (!aRefObject.get()) {
989     theError = "Error: Empty feature.";
990     return false;
991   }
992
993   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
994   if (!aRefFeature.get()) {
995     theError = "Error: Empty feature.";
996     return false;
997   }
998   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
999   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
1000
1001   size_t aConcealedResults = aResults.size();
1002   if (!aConcealedResults && !theArguments.empty()) {
1003     // find if these results are touched by the feature in another attribute
1004     std::list<std::string>::const_iterator anIt = theArguments.begin();
1005     std::string aRecoveredList = *anIt;
1006     if (!aRecoveredList.empty()) {
1007       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
1008                                  theAttribute->owner()->data()->reflist(aRecoveredList);
1009       if (aParameterList.get())
1010         aConcealedResults = aParameterList->size();
1011     }
1012   }
1013
1014   if (aConcealedResults == 0)
1015     theError = "Error: No concealed results.";
1016
1017   return theError.empty();
1018 }
1019
1020 bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
1021                                                const std::list<std::string>& theArguments,
1022                                                Events_InfoMessage& theError) const
1023 {
1024   static std::list<std::string> aEdgeArg(1, "circle");
1025   static std::list<std::string> aFaceArg(1, "cylinder");
1026
1027   Events_InfoMessage aError;
1028   bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
1029   if (!isValid) {
1030     isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
1031     if (!isValid)
1032       theError = "The shape neither circle nor cylinder";
1033   }
1034   return isValid;
1035 }
1036
1037 //=================================================================================================
1038 bool FeaturesPlugin_ValidatorBooleanArguments::isValid(
1039   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1040   const std::list<std::string>& theArguments,
1041   Events_InfoMessage& theError) const
1042 {
1043   if (theArguments.size() != 2)
1044   {
1045     theError = "Wrong number of arguments (expected 2).";
1046     return false;
1047   }
1048
1049   int anObjectsNb = 0, aToolsNb = 0;
1050   //int anOperationType = 0;
1051
1052   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1053
1054   bool isAllInSameCompSolid = true;
1055   ResultBodyPtr aCompSolid;
1056
1057   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1058   if (anAttrSelList)
1059   {
1060     anObjectsNb = anAttrSelList->size();
1061     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex)
1062     {
1063       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1064       ResultPtr aContext = anAttr->context();
1065       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1066       if (aResCompSolidPtr.get())
1067       {
1068         if (aCompSolid.get())
1069         {
1070           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1071         }
1072         else
1073         {
1074           aCompSolid = aResCompSolidPtr;
1075         }
1076       }
1077       else
1078       {
1079         isAllInSameCompSolid = false;
1080         break;
1081       }
1082     }
1083   }
1084   anIt++;
1085
1086
1087   anAttrSelList = theFeature->selectionList(*anIt);
1088   if (anAttrSelList)
1089   {
1090     aToolsNb = anAttrSelList->size();
1091     if (isAllInSameCompSolid)
1092     {
1093       for (int anIndex = 0; anIndex < aToolsNb; ++anIndex)
1094       {
1095         AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1096         ResultPtr aContext = anAttr->context();
1097         ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1098         if (aResCompSolidPtr.get())
1099         {
1100           if (aCompSolid.get())
1101           {
1102             isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1103           }
1104           else
1105           {
1106             aCompSolid = aResCompSolidPtr;
1107           }
1108         }
1109         else
1110         {
1111           isAllInSameCompSolid = false;
1112           break;
1113         }
1114       }
1115     }
1116   }
1117   anIt++;
1118
1119   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1120     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1121   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1122
1123   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1124   {
1125     // Fuse operation
1126     if (anObjectsNb + aToolsNb < 2)
1127     {
1128       theError = "Not enough arguments for Fuse operation.";
1129       return false;
1130     }
1131     else if (isAllInSameCompSolid)
1132     {
1133       theError = "Operations only between sub-shapes of the same shape not allowed.";
1134       return false;
1135     }
1136   }
1137   else
1138   {
1139     if (anObjectsNb < 1)
1140     {
1141       theError = "Objects not selected.";
1142       return false;
1143     }
1144     if (aToolsNb < 1)
1145     {
1146       theError = "Tools not selected.";
1147       return false;
1148     }
1149     if (isAllInSameCompSolid)
1150     {
1151       theError = "Operations only between sub-shapes of the same shape not allowed.";
1152       return false;
1153     }
1154   }
1155
1156   return true;
1157 }
1158
1159 //=================================================================================================
1160 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1161                                                                std::string theAttribute)
1162 {
1163   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1164   {
1165     return true;
1166   }
1167
1168   return false;
1169 }