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