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