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