Salome HOME
Meet the coding style (line length <= 100)
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        FeaturesPlugin_Validators.cpp
4 // Created:     22 March 2016
5 // Author:      Dmitry Bobylev
6
7 #include "FeaturesPlugin_Validators.h"
8
9 #include "FeaturesPlugin_Union.h"
10
11 #include <Events_InfoMessage.h>
12
13 #include <ModelAPI_Attribute.h>
14 #include <ModelAPI_AttributeInteger.h>
15 #include <ModelAPI_AttributeSelectionList.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_AttributeReference.h>
18 #include <ModelAPI_AttributeRefList.h>
19 #include <ModelAPI_Feature.h>
20 #include <ModelAPI_ResultCompSolid.h>
21 #include <ModelAPI_ResultConstruction.h>
22 #include <ModelAPI_Tools.h>
23
24 #include <GeomValidators_BodyShapes.h>
25 #include <GeomValidators_FeatureKind.h>
26 #include <GeomValidators_ShapeType.h>
27
28 #include <GeomAPI_DataMapOfShapeShape.h>
29 #include <GeomAPI_Lin.h>
30 #include <GeomAPI_PlanarEdges.h>
31 #include <GeomAPI_ShapeExplorer.h>
32 #include <GeomAPI_ShapeIterator.h>
33
34 #include <GeomAlgoAPI_CompoundBuilder.h>
35 #include <GeomAlgoAPI_ShapeBuilder.h>
36 #include <GeomAlgoAPI_ShapeTools.h>
37 #include <GeomAlgoAPI_WireBuilder.h>
38
39 #define _USE_MATH_DEFINES
40 #include <math.h>
41
42 //==================================================================================================
43 bool FeaturesPlugin_ValidatorPipePath::isValid(const AttributePtr& theAttribute,
44                                                const std::list<std::string>& theArguments,
45                                                Events_InfoMessage& theError) const
46 {
47   AttributeSelectionPtr aPathAttrSelection =
48     std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
49   if(!aPathAttrSelection.get()) {
50     theError = "Error: This validator can only work with path selector in \"Pipe\" feature.";
51     return false;
52   }
53
54   GeomShapePtr aPathShape = aPathAttrSelection->value();
55   ResultPtr aContext = aPathAttrSelection->context();
56   if(!aContext.get()) {
57     theError = "Error: Empty context.";
58     return false;
59   }
60   GeomShapePtr aContextShape = aContext->shape();
61   if(aPathShape.get() && aPathShape->shapeType() == GeomAPI_Shape::WIRE &&
62       !aPathShape->isEqual(aContextShape)) {
63     theError = "Error: Local selection of wires not allowed.";
64     return false;
65   }
66
67   return true;
68 }
69
70 //==================================================================================================
71 bool FeaturesPlugin_ValidatorPipeLocations::isValid(
72   const std::shared_ptr<ModelAPI_Feature>& theFeature,
73   const std::list<std::string>& theArguments,
74   Events_InfoMessage& theError) const
75 {
76   static const std::string aCreationMethodID = "creation_method";
77   static const std::string aBaseObjectsID = "base_objects";
78   static const std::string aLocationsID = "locations_objects";
79
80   if(theFeature->getKind() != "Pipe") {
81     theError = "Error: Feature \"%1\" does not supported by this validator.";
82     theError.arg(theFeature->getKind());
83     return false;
84   }
85
86   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
87   if(!aCreationMethodAttr.get()) {
88     theError = "Error: Could not get \"%1\" attribute.";
89     theError.arg(aCreationMethodID);
90     return false;
91   }
92
93   if(aCreationMethodAttr->value() != "locations") {
94     return true;
95   }
96
97   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
98   if(!aBaseObjectsSelectionList.get()) {
99     theError = "Error: Could not get \"%1\" attribute.";
100     theError.arg(aBaseObjectsID);
101     return false;
102   }
103
104   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
105   if(!aLocationsSelectionList.get()) {
106     theError = "Error: Could not get \"%1\" attribute.";
107     theError.arg(aBaseObjectsID);
108     return false;
109   }
110
111   if(aLocationsSelectionList->size() > 0 &&
112      aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
113     theError = "Error: Number of locations should be the same as base objects.";
114     return false;
115   }
116
117   return true;
118 }
119
120 //==================================================================================================
121 bool FeaturesPlugin_ValidatorPipeLocations::isNotObligatory(std::string theFeature,
122                                                             std::string theAttribute)
123 {
124   return false;
125 }
126
127 //==================================================================================================
128 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
129                                                         const std::list<std::string>& theArguments,
130                                                         Events_InfoMessage& theError) const
131 {
132   if(theArguments.empty()) {
133     theError = "Error: Validator parameters is empty.";
134     return false;
135   }
136
137   // Checking attribute.
138   if(!isValidAttribute(theAttribute, theArguments, theError)) {
139     if(theError.empty()) {
140       theError = "Error: Attribute contains unacceptable shape.";
141     }
142     return false;
143   }
144
145   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
146   std::string anAttributeType = theAttribute->attributeType();
147   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
148     AttributeSelectionListPtr aListAttr =
149       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
150     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
151       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
152       ResultPtr aContext = aSelectionAttr->context();
153       if(!aContext.get()) {
154         theError = "Error: Empty context.";
155         return false;
156       }
157
158       ResultConstructionPtr aResultConstruction =
159         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
160       if(!aResultConstruction.get()) {
161         // It is not a result construction.
162         // If shape is compound check that it contains only faces and edges.
163         GeomShapePtr aShape = aSelectionAttr->value();
164         if(!aShape.get()) {
165           aShape = aContext->shape();
166         }
167
168         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
169           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
170             GeomShapePtr aSubShape = anIt.current();
171             if(aSubShape->shapeType() != GeomAPI_Shape::EDGE
172                 && aSubShape->shapeType() != GeomAPI_Shape::FACE) {
173               theError = "Error: Compound should contain only faces and edges.";
174               return false;
175             }
176           }
177         }
178
179         continue;
180       }
181
182       GeomShapePtr aShape = aSelectionAttr->value();
183       GeomShapePtr aContextShape = aResultConstruction->shape();
184       if(!aShape.get()) {
185         // Whole sketch selected.
186         continue;
187       } else {
188         // Object from sketch selected.
189         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
190           GeomShapePtr aWire = anExp.current();
191           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
192             theError = "Error: Wire with wrong orientation selected.";
193             return false;
194           }
195
196           if(aSelectedWiresFromObjects.isBound(aWire)) {
197             theError =
198               "Error: Objects with such wire already selected. Don't allow to select this object.";
199             return false;
200           }
201
202           aSelectedWiresFromObjects.bind(aWire, aWire);
203         }
204       }
205     }
206   }
207
208   return true;
209 }
210
211 //==================================================================================================
212 bool FeaturesPlugin_ValidatorBaseForGenerationSketchOrSketchObjects::isValid(
213   const std::shared_ptr<ModelAPI_Feature>& theFeature,
214   const std::list<std::string>& theArguments,
215   Events_InfoMessage& theError) const
216 {
217   const std::string aBaseObjectsID = theArguments.front();
218
219   AttributeSelectionListPtr aListAttr = theFeature->selectionList(aBaseObjectsID);
220   if(!aListAttr.get()) {
221     theError = "Error: Could not get \"%1\" attribute.";
222     theError.arg(aBaseObjectsID);
223     return false;
224   }
225
226   std::set<ResultConstructionPtr> aSelectedSketches;
227   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
228
229   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
230     AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
231     ResultPtr aContext = aSelectionAttr->context();
232     if(!aContext.get()) {
233       theError = "Error: Empty context.";
234       return false;
235     }
236
237     ResultConstructionPtr aResultConstruction =
238       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
239     if(!aResultConstruction.get()) {
240       // It is not a result construction.
241       continue;
242     }
243
244     GeomShapePtr aShape = aSelectionAttr->value();
245     GeomShapePtr aContextShape = aResultConstruction->shape();
246     if(!aShape.get()) {
247       // Whole sketch selected.
248       aSelectedSketches.insert(aResultConstruction);
249     } else {
250       // Object from sketch selected.
251       aSelectedSketchesFromObjects.insert(aResultConstruction);
252     }
253   }
254
255
256   for(std::set<ResultConstructionPtr>::const_iterator anIt = aSelectedSketches.cbegin();
257       anIt != aSelectedSketches.cend();
258       ++anIt) {
259     ResultConstructionPtr aResultConstruction = *anIt;
260     if(aSelectedSketchesFromObjects.find(aResultConstruction) !=
261         aSelectedSketchesFromObjects.cend()) {
262       theError = "Sketch and objects from it can not be selected at the same time.";
263       return false;
264     }
265   }
266
267   return true;
268 }
269
270 //==================================================================================================
271 bool FeaturesPlugin_ValidatorBaseForGenerationSketchOrSketchObjects::isNotObligatory(
272     std::string theFeature,
273     std::string theAttribute)
274 {
275   return false;
276 }
277
278 //==================================================================================================
279 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
280                                                         const std::list<std::string>& theArguments,
281                                                         Events_InfoMessage& theError) const
282 {
283   if(!theAttribute.get()) {
284     theError = "Error: Empty attribute.";
285     return false;
286   }
287
288   std::string anAttributeType = theAttribute->attributeType();
289   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
290     AttributeSelectionListPtr aListAttr =
291       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
292     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
293       // If at least one attribute is invalid, the result is false.
294       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
295         return false;
296       }
297     }
298   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
299     // Getting context.
300     AttributeSelectionPtr anAttr =
301       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
302     ResultPtr aContext = anAttr->context();
303     if(!aContext.get()) {
304       theError = "Error: Attribute have empty context.";
305       return false;
306     }
307
308     GeomShapePtr aShape = anAttr->value();
309     GeomShapePtr aContextShape = aContext->shape();
310     if(!aShape.get()) {
311       aShape = aContextShape;
312     }
313     if(!aShape.get()) {
314       theError = "Error: Empty shape selected";
315       return false;
316     }
317
318     ResultConstructionPtr aConstruction =
319       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
320     if(aConstruction.get()) {
321       // Construciotn selected. Check that is is not infinite.
322       if(aConstruction->isInfinite()) {
323         theError = "Error: Infinite constructions is not allowed as base.";
324         return false;
325       }
326
327       if(aShape->isEqual(aContextShape)) {
328         // Whole construction selected. Check that it have faces.
329         if(aConstruction->facesNum() > 0) {
330           return true;
331         }
332       } else {
333         // Shape on construction selected. Check that it is a face or wire.
334         if(aShape->shapeType() == GeomAPI_Shape::WIRE ||
335            aShape->shapeType() == GeomAPI_Shape::FACE) {
336           return true;
337         }
338       }
339
340       return false;
341     }
342
343     if(!aShape->isEqual(aContextShape)) {
344       // Local selection on body does not allowed.
345       theError =
346         "Error: Selected shape is in the local selection. Only global selection is allowed.";
347       return false;
348     }
349
350     // Check that object is a shape with allowed type.
351     GeomValidators_ShapeType aShapeTypeValidator;
352     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
353       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
354                  "wires on sketch, whole sketch(if it has at least one face), "
355                  "and whole objects with shape types: %1";
356       std::string anArgumentString;
357       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
358         if (!anArgumentString.empty())
359           anArgumentString += ", ";
360         anArgumentString += *anIt;
361       }
362       theError.arg(anArgumentString);
363       return false;
364     }
365
366   } else {
367     theError = "Error: Attribute \"%1\" does not supported by this validator.";
368     theError.arg(anAttributeType);
369     return false;
370   }
371
372   return true;
373 }
374
375 //==================================================================================================
376 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
377                                                         const std::list<std::string>& theArguments,
378                                                         Events_InfoMessage& theError) const
379 {
380   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
381     theError = "Error: The attribute with the %1 type is not processed";
382     theError.arg(theAttribute->attributeType());
383     return false;
384   }
385   if (theArguments.size() != 2) {
386     theError = "Error: Wrong parameters in XML definition for %1 type";
387     theError.arg(theAttribute->attributeType());
388     return false;
389   }
390   // first argument is for the base attribute, second - for skipping feature kind
391   std::list<std::string>::const_iterator anIt = theArguments.begin();
392   std::string aBaseAttributeId = *anIt;
393   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
394   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
395   if (!aBaseAttribute.get()) {
396     theError = "Wrong parameters in XML definition for %1 type";
397     theError.arg(theAttribute->attributeType());
398     return false;
399   }
400   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
401     // this validator is not necessary anymore
402     return true;
403
404   anIt++;
405   std::string aFeatureAttributeKind = *anIt;
406   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
407   // check whether the selection is on the sketch
408   std::list<std::string> anArguments;
409   anArguments.push_back(aFeatureAttributeKind);
410
411   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
412   bool aPlanarFace = false;
413   // check if selection has Face selected
414   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
415   anArguments.clear();
416   anArguments.push_back("face");
417   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
418
419   bool aValid = !aFeatureKind && aPlanarFace;
420   return aValid;
421 }
422
423 //==================================================================================================
424 bool FeaturesPlugin_ValidatorExtrusionDir::isValid(
425                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
426                                                const std::list<std::string>& theArguments,
427                                                Events_InfoMessage& theError) const
428 {
429   if(theArguments.size() != 2) {
430     theError = "Error: Validator should be used with 2 parameters for extrusion.";
431     return false;
432   }
433
434   std::list<std::string>::const_iterator
435     anArgsIt = theArguments.begin(), aLast = theArguments.end();
436
437   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
438   ++anArgsIt;
439
440   GeomShapePtr aDirShape;
441   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
442   if(aSelAttr.get()) {
443     aDirShape = aSelAttr->value();
444     if(!aDirShape.get()) {
445       ResultPtr aContext = aSelAttr->context();
446       if(aContext.get()) {
447         aDirShape = aContext->shape();
448       }
449     }
450   }
451
452   if(!aDirShape.get()) {
453     // Check that dir can be empty.
454     if(!isShapesCanBeEmpty(aCheckAttribute, theError)) {
455       theError = "Error: Base objects list contains vertex or edge, so attribute \"%1\" "
456                  "can not be used with default value. Select direction for extrusion.";
457       theError.arg(*anArgsIt);
458       return false;
459     } else {
460       return true;
461     }
462   }
463
464   std::shared_ptr<GeomAPI_Edge> aDirEdge(new GeomAPI_Edge(aDirShape));
465
466   // If faces selected check that direction not parallel with them.
467   AttributeSelectionListPtr aListAttr =
468     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aCheckAttribute);
469   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
470     AttributeSelectionPtr anAttr = aListAttr->value(anIndex);
471     GeomShapePtr aShapeInList = anAttr->value();
472     if(!aShapeInList.get()) {
473       aShapeInList = anAttr->context()->shape();
474     }
475     bool isParallel = true;
476     if(aShapeInList->shapeType() == GeomAPI_Shape::FACE ||
477        aShapeInList->shapeType() == GeomAPI_Shape::SHELL) {
478       for(GeomAPI_ShapeExplorer
479           anExp(aShapeInList, GeomAPI_Shape::FACE); anExp.more(); anExp.next()) {
480         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(anExp.current()));
481         isParallel = GeomAlgoAPI_ShapeTools::isParallel(aDirEdge, aFace);
482         if(isParallel) {
483           break;
484         }
485       }
486     } else if(aShapeInList->shapeType() == GeomAPI_Shape::COMPOUND) {
487       std::shared_ptr<GeomAPI_PlanarEdges> aPlanarEdges =
488         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aShapeInList);
489       if(aPlanarEdges.get()) {
490         std::shared_ptr<GeomAPI_Dir> aSketchDir = aPlanarEdges->norm();
491         if(aDirEdge->isLine()) {
492           std::shared_ptr<GeomAPI_Dir> aDir = aDirEdge->line()->direction();
493           isParallel = fabs(aSketchDir->angle(aDir) - M_PI / 2.0) < 10e-7;
494         } else {
495           isParallel = false;
496         }
497       } else {
498         isParallel = false;
499       }
500     } else {
501       isParallel = false;
502     }
503     if(isParallel) {
504       theError =
505         "Error: Direction is parallel to one of the selected face or face on selected shell.";
506       return false;
507     }
508   }
509
510   return true;
511 }
512
513 //==================================================================================================
514 bool FeaturesPlugin_ValidatorExtrusionDir::isNotObligatory(std::string theFeature,
515                                                            std::string theAttribute)
516 {
517   return false;
518 }
519
520 //==================================================================================================
521 bool FeaturesPlugin_ValidatorExtrusionDir::isShapesCanBeEmpty(const AttributePtr& theAttribute,
522                                                               Events_InfoMessage& theError) const
523 {
524   if(!theAttribute.get()) {
525     return true;
526   }
527
528   std::string anAttributeType = theAttribute->attributeType();
529   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
530     AttributeSelectionListPtr aListAttr =
531       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
532     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
533       // If at least one attribute is invalid, the result is false.
534       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
535         return false;
536       }
537     }
538   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
539     // Getting context.
540     AttributeSelectionPtr anAttr =
541       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
542     ResultPtr aContext = anAttr->context();
543     if(!aContext.get()) {
544       return false;
545     }
546
547     GeomShapePtr aShape = anAttr->value();
548     GeomShapePtr aContextShape = aContext->shape();
549     if(!aShape.get()) {
550       aShape = aContextShape;
551     }
552     if(!aShape.get()) {
553       return false;
554     }
555
556     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
557        aShape->shapeType() == GeomAPI_Shape::EDGE ||
558        !aShape->isPlanar()) {
559       return false;
560     }
561   } else {
562     return false;
563   }
564
565   return true;
566 }
567
568 //==================================================================================================
569 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
570                                                        const std::list<std::string>& theArguments,
571                                                        Events_InfoMessage& theError) const
572 {
573   AttributeSelectionListPtr anAttrSelectionList =
574     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
575   if(!anAttrSelectionList.get()) {
576     theError =
577       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
578     return false;
579   }
580   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
581   int anOperationType = aFeature->integer("bool_type")->value();
582
583   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
584     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
585     if(!anAttrSelection.get()) {
586       theError = "Error: Empty attribute selection.";
587       return false;
588     }
589     ResultPtr aContext = anAttrSelection->context();
590     if(!aContext.get()) {
591       theError = "Error: Empty selection context.";
592       return false;
593     }
594     ResultConstructionPtr aResultConstruction =
595       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
596     if(aResultConstruction.get()) {
597       theError = "Error: Result construction not allowed for selection.";
598       return false;
599     }
600     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
601     GeomShapePtr aContextShape = aContext->shape();
602     if(!aShape.get()) {
603       aShape = aContextShape;
604     }
605     if(!aShape.get()) {
606       theError = "Error: Empty shape.";
607       return false;
608     }
609     if(!aShape->isEqual(aContextShape)) {
610       theError = "Error: Local selection not allowed.";
611       return false;
612     }
613
614     int aShapeType = aShape->shapeType();
615     if(anOperationType == 1) {
616       // Fuse operation. Allow to select edges, faces and solids.
617       if(aShapeType != GeomAPI_Shape::EDGE &&
618          aShapeType != GeomAPI_Shape::FACE &&
619          aShapeType != GeomAPI_Shape::SOLID &&
620          aShapeType != GeomAPI_Shape::COMPSOLID &&
621          aShapeType != GeomAPI_Shape::COMPOUND) {
622         theError = "Error: Selected shape has the wrong type.";
623         return false;
624       }
625     } else {
626       if(aShapeType != GeomAPI_Shape::SOLID &&
627          aShapeType != GeomAPI_Shape::COMPSOLID &&
628          aShapeType != GeomAPI_Shape::COMPOUND) {
629         theError = "Error: Selected shape has the wrong type.";
630         return false;
631       }
632     }
633   }
634
635   return true;
636 }
637
638 //==================================================================================================
639 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
640                                                        const std::list<std::string>& theArguments,
641                                                        Events_InfoMessage& theError) const
642 {
643   AttributeSelectionListPtr anAttrSelectionList =
644     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
645   if(!anAttrSelectionList.get()) {
646     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
647     return false;
648   }
649
650   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
651     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
652
653     //GeomValidators_BodyShapes aBodyValidator;
654     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
655     //  continue;
656     //}
657
658     GeomValidators_FeatureKind aFeatureKindValidator;
659     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
660       continue;
661     }
662
663     ResultPtr aContext = aSelectAttr->context();
664     ResultConstructionPtr aResultConstruction =
665       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
666     if(aResultConstruction.get()) {
667       theError = "Error: Only body shapes and construction planes are allowed for selection.";
668       return false;
669     }
670
671     ResultCompSolidPtr aResultCompsolid =
672       std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aContext);
673     if(aResultCompsolid.get()) {
674       continue;
675     }
676
677     theError = "Error: Only body shapes and construction planes are allowed for selection.";
678     return false;
679   }
680
681   theError = "";
682   return true;
683 }
684
685 //==================================================================================================
686 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
687                                                      const std::list<std::string>& theArguments,
688                                                      Events_InfoMessage& theError) const
689 {
690   AttributeSelectionListPtr aSubShapesAttrList =
691     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
692   if(!aSubShapesAttrList.get()) {
693     theError =
694       "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
695     return false;
696   }
697
698   static const std::string aBaseShapeID = "base_shape";
699   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
700   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
701
702   if(!aShapeAttrSelection.get()) {
703     theError = "Error: Could not get \"%1\" attribute.";
704     theError.arg(aBaseShapeID);
705     return false;
706   }
707
708   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
709   ResultPtr aContext = aShapeAttrSelection->context();
710   if(!aContext.get()) {
711     theError = "Error: Empty context.";
712     return false;
713   }
714   if(!aBaseShape.get()) {
715     aBaseShape = aContext->shape();
716   }
717   if(!aBaseShape.get()) {
718     theError = "Error: Empty base shape.";
719     return false;
720   }
721
722   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
723     bool isSameFound = false;
724     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
725     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
726     for(GeomAPI_ShapeIterator anIt(aBaseShape); anIt.more(); anIt.next()) {
727       if(anIt.current()->isEqual(aShapeToAdd)) {
728         isSameFound = true;
729         break;
730       }
731     }
732     if(!isSameFound) {
733       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
734       return false;
735     }
736   }
737
738   return true;
739 }
740
741 //==================================================================================================
742 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
743   const std::shared_ptr<ModelAPI_Feature>& theFeature,
744   const std::list<std::string>& theArguments,
745   Events_InfoMessage& theError) const
746 {
747   static const std::string aBaseShapeID = "base_shape";
748   static const std::string aSubShapesID = "subshapes";
749
750   if(theFeature->getKind() != "Remove_SubShapes") {
751     theError = "Error: Feature \"%1\" does not supported by this validator.";
752     theError.arg(theFeature->getKind());
753     return false;
754   }
755
756   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
757   if(!aShapeAttrSelection.get()) {
758     theError = "Error: Could not get \"%1\" attribute.";
759     theError.arg(aBaseShapeID);
760     return false;
761   }
762
763   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
764   if(!aSubShapesAttrList.get()) {
765     theError = "Error: Could not get \"%1\" attribute.";
766     theError.arg(aSubShapesID);
767     return false;
768   }
769
770   // Copy base shape.
771   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
772   if(!aBaseShape.get()) {
773     theError = "Error: Base shape is empty.";
774     return false;
775   }
776   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
777
778   // Copy sub-shapes from list to new shape.
779   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
780     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
781     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
782     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
783   }
784
785   // Check new shape.
786   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
787     theError = "Error: Resulting shape is not valid.";
788     return false;
789   }
790
791   return true;
792 }
793
794 //==================================================================================================
795 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isNotObligatory(std::string theFeature,
796                                                                     std::string theAttribute)
797 {
798   return false;
799 }
800
801 //==================================================================================================
802 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
803                                                      const std::list<std::string>& theArguments,
804                                                      Events_InfoMessage& theError) const
805 {
806   AttributeSelectionListPtr aBaseObjectsAttrList =
807     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
808   if(!aBaseObjectsAttrList.get()) {
809     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
810     theError.arg(FeaturesPlugin_Union::ID());
811     return false;
812   }
813
814   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
815     bool isSameFound = false;
816     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
817     ResultCompSolidPtr aResult =
818       std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(anAttrSelectionInList->context());
819     if(!aResult.get()) {
820       continue;
821     }
822     if(aResult->numberOfSubs() > 0) {
823       theError = "Error: Whole compsolids not allowed for selection.";
824       return false;
825     }
826   }
827
828   return true;
829 }
830
831 //==================================================================================================
832 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
833   const std::shared_ptr<ModelAPI_Feature>& theFeature,
834   const std::list<std::string>& theArguments,
835   Events_InfoMessage& theError) const
836 {
837   // Check feature kind.
838   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
839     theError = "Error: This validator supports only \"%1\" feature.";
840     theError.arg(FeaturesPlugin_Union::ID());
841     return false;
842   }
843
844   // Get base objects attribute list.
845   AttributeSelectionListPtr aBaseObejctsAttrList =
846     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
847   if(!aBaseObejctsAttrList.get()) {
848     theError = "Error: Could not get \"%1\" attribute.";
849     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
850     return false;
851   }
852
853   // Get all shapes.
854   ListOfShape aBaseShapesList;
855   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
856     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
857     GeomShapePtr aShape = anAttrSelectionInList->value();
858     aBaseShapesList.push_back(aShape);
859   }
860
861   // Make componud and find connected.
862   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
863   ListOfShape aCombined, aFree;
864   GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCombined, aFree);
865
866   if(aFree.size() > 0 || aCombined.size() > 1) {
867     theError = "Error: Not all shapes have shared topology.";
868     return false;
869   }
870
871   return true;
872 }
873
874 //==================================================================================================
875 bool FeaturesPlugin_ValidatorUnionArguments::isNotObligatory(std::string theFeature,
876                                                              std::string theAttribute)
877 {
878   return false;
879 }
880
881 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
882                                             const std::list<std::string>& theArguments,
883                                             Events_InfoMessage& theError) const
884 {
885   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
886     theError = "Error: The attribute with the %1 type is not processed";
887     theError.arg(theAttribute->attributeType());
888     return false;
889   }
890
891   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
892                                                                                (theAttribute);
893   ObjectPtr aRefObject = aRefAttribute->value();
894   if (!aRefObject.get()) {
895     theError = "Error: Empty feature.";
896     return false;
897   }
898
899   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
900   if (!aRefFeature.get()) {
901     theError = "Error: Empty feature.";
902     return false;
903   }
904   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
905   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
906
907   size_t aConcealedResults = aResults.size();
908   if (!aConcealedResults && !theArguments.empty()) {
909     // find if these results are touched by the feature in another attribute
910     std::list<std::string>::const_iterator anIt = theArguments.begin();
911     std::string aRecoveredList = *anIt;
912     if (!aRecoveredList.empty()) {
913       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
914                                  theAttribute->owner()->data()->reflist(aRecoveredList);
915       if (aParameterList.get())
916         aConcealedResults = aParameterList->size();
917     }
918   }
919
920   if (aConcealedResults == 0)
921     theError = "Error: No concealed results.";
922
923   return theError.empty();
924 }