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