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