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