]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
Salome HOME
ff7d8cb391a1963bea496a14eba4ca6c7134ce00
[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     GeomShapePtr aContextShape = aContext->shape();
510     if(!aShape.get()) {
511       aShape = aContextShape;
512     }
513     if(!aShape.get()) {
514       theError = "Error: Empty shape.";
515       return false;
516     }
517     if(!aShape->isEqual(aContextShape)) {
518       theError = "Error: Local selection not allowed.";
519       return false;
520     }
521
522     int aShapeType = aShape->shapeType();
523     if(anOperationType == 1) {
524       // Fuse operation. Allow to select edges, faces and solids.
525       if(aShapeType != GeomAPI_Shape::EDGE &&
526          aShapeType != GeomAPI_Shape::FACE &&
527          aShapeType != GeomAPI_Shape::SOLID &&
528          aShapeType != GeomAPI_Shape::COMPSOLID &&
529          aShapeType != GeomAPI_Shape::COMPOUND) {
530         theError = "Error: Selected shape has the wrong type.";
531         return false;
532       }
533     } else {
534       if(aShapeType != GeomAPI_Shape::SOLID &&
535          aShapeType != GeomAPI_Shape::COMPSOLID &&
536          aShapeType != GeomAPI_Shape::COMPOUND) {
537         theError = "Error: Selected shape has the wrong type.";
538         return false;
539       }
540     }
541   }
542
543   return true;
544 }
545
546 //==================================================================================================
547 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
548                                                          const std::list<std::string>& theArguments,
549                                                          Events_InfoMessage& theError) const
550 {
551   AttributeSelectionListPtr anAttrSelectionList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
552   if(!anAttrSelectionList.get()) {
553     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
554     return false;
555   }
556
557   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
558     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
559
560     //GeomValidators_BodyShapes aBodyValidator;
561     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
562     //  continue;
563     //}
564
565     GeomValidators_FeatureKind aFeatureKindValidator;
566     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
567       continue;
568     }
569
570     ResultPtr aContext = aSelectAttr->context();
571     ResultConstructionPtr aResultConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
572     if(aResultConstruction.get()) {
573       theError = "Error: Only body shapes and construction planes are allowed for selection.";
574       return false;
575     }
576
577     ResultCompSolidPtr aResultCompsolid = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aContext);
578     if(aResultCompsolid.get()) {
579       continue;
580     }
581
582     theError = "Error: Only body shapes and construction planes are allowed for selection.";
583     return false;
584   }
585
586   theError = "";
587   return true;
588 }
589
590 //==================================================================================================
591 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
592                                                                const std::list<std::string>& theArguments,
593                                                                Events_InfoMessage& theError) const
594 {
595   AttributeSelectionListPtr aSubShapesAttrList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
596   if(!aSubShapesAttrList.get()) {
597     theError = "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
598     return false;
599   }
600
601   static const std::string aBaseShapeID = "base_shape";
602   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
603   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
604
605   if(!aShapeAttrSelection.get()) {
606     theError = "Error: Could not get \"" + aBaseShapeID + "\" attribute.";
607     return false;
608   }
609
610   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
611   ResultPtr aContext = aShapeAttrSelection->context();
612   if(!aContext.get()) {
613     theError = "Error: Empty context.";
614     return false;
615   }
616   if(!aBaseShape.get()) {
617     aBaseShape = aContext->shape();
618   }
619   if(!aBaseShape.get()) {
620     theError = "Error: Empty base shape.";
621     return false;
622   }
623
624   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
625     bool isSameFound = false;
626     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
627     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
628     for(GeomAPI_ShapeIterator anIt(aBaseShape); anIt.more(); anIt.next()) {
629       if(anIt.current()->isEqual(aShapeToAdd)) {
630         isSameFound = true;
631         break;
632       }
633     }
634     if(!isSameFound) {
635       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
636       return false;
637     }
638   }
639
640   return true;
641 }
642
643 //==================================================================================================
644 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
645                                                             const std::list<std::string>& theArguments,
646                                                             Events_InfoMessage& theError) const
647 {
648   static const std::string aBaseShapeID = "base_shape";
649   static const std::string aSubShapesID = "subshapes";
650
651   if(theFeature->getKind() != "Remove_SubShapes") {
652     theError = "Error: Feature \"" + theFeature->getKind() + "\" does not supported by this validator.";
653     return false;
654   }
655
656   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
657   if(!aShapeAttrSelection.get()) {
658     theError = "Error: Could not get \"" + aBaseShapeID + "\" attribute.";
659     return false;
660   }
661
662   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
663   if(!aSubShapesAttrList.get()) {
664     theError = "Error: Could not get \"" + aSubShapesID + "\" attribute.";
665     return false;
666   }
667
668   // Copy base shape.
669   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
670   if(!aBaseShape.get()) {
671     theError = "Error: Base shape is empty.";
672     return false;
673   }
674   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
675
676   // Copy sub-shapes from list to new shape.
677   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
678     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
679     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
680     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
681   }
682
683   // Check new shape.
684   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
685     theError = "Error: Resulting shape is not valid.";
686     return false;
687   }
688
689   return true;
690 }
691
692 //==================================================================================================
693 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isNotObligatory(std::string theFeature,
694                                                                     std::string theAttribute)
695 {
696   return false;
697 }
698
699 //==================================================================================================
700 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
701                                                      const std::list<std::string>& theArguments,
702                                                      Events_InfoMessage& theError) const
703 {
704   AttributeSelectionListPtr aBaseObjectsAttrList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
705   if(!aBaseObjectsAttrList.get()) {
706     theError = "Error: This validator can only work with selection list in \"" + FeaturesPlugin_Union::ID() + "\" feature.";
707     return false;
708   }
709
710   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
711     bool isSameFound = false;
712     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
713     ResultCompSolidPtr aResult = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(anAttrSelectionInList->context());
714     if(!aResult.get()) {
715       continue;
716     }
717     if(aResult->numberOfSubs() > 0) {
718       theError = "Error: Whole compsolids not allowed for selection.";
719       return false;
720     }
721   }
722
723   return true;
724 }
725
726 //==================================================================================================
727 bool FeaturesPlugin_ValidatorUnionArguments::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
728                                                      const std::list<std::string>& theArguments,
729                                                      Events_InfoMessage& theError) const
730 {
731   // Check feature kind.
732   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
733     theError = "Error: This validator supports only \"" + FeaturesPlugin_Union::ID() + "\" feature.";
734     return false;
735   }
736
737   // Get base objects attribute list.
738   AttributeSelectionListPtr aBaseObejctsAttrList = theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
739   if(!aBaseObejctsAttrList.get()) {
740     theError = "Error: Could not get \"" + FeaturesPlugin_Union::BASE_OBJECTS_ID() + "\" attribute.";
741     return false;
742   }
743
744   // Get all shapes.
745   ListOfShape aBaseShapesList;
746   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
747     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
748     GeomShapePtr aShape = anAttrSelectionInList->value();
749     aBaseShapesList.push_back(aShape);
750   }
751
752   // Make componud and find connected.
753   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
754   ListOfShape aCombined, aFree;
755   GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCombined, aFree);
756
757   if(aFree.size() > 0 || aCombined.size() > 1) {
758     theError = "Error: Not all shapes have shared topology.";
759     return false;
760   }
761
762   return true;
763 }
764
765 //==================================================================================================
766 bool FeaturesPlugin_ValidatorUnionArguments::isNotObligatory(std::string theFeature,
767                                                              std::string theAttribute)
768 {
769   return false;
770 }