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