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