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