]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
Salome HOME
Issue #2305: 1.1.2.2 To complete the operator FILL
[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     GeomAPI_Shape::ShapeType aShapeType = aShape->shapeType();
633     std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
634     if(anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE) {
635       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
636       anAllowedTypes.insert(GeomAPI_Shape::FACE);
637       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
638       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
639       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
640     } else if (anOperationType == FeaturesPlugin_Boolean::BOOL_FILL) {
641       anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
642       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
643       anAllowedTypes.insert(GeomAPI_Shape::WIRE);
644       anAllowedTypes.insert(GeomAPI_Shape::FACE);
645       anAllowedTypes.insert(GeomAPI_Shape::SHELL);
646       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
647       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
648       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
649     } else {
650       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
651       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
652       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
653     }
654
655     if(anAllowedTypes.find(aShapeType) == anAllowedTypes.end()
656       || (aResultConstruction.get() && aShapeType != GeomAPI_Shape::FACE)) {
657       theError = "Error: Selected shape has the wrong type.";
658       return false;
659     }
660
661   }
662
663   return true;
664 }
665
666 //==================================================================================================
667 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
668                                                        const std::list<std::string>& theArguments,
669                                                        Events_InfoMessage& theError) const
670 {
671   AttributeSelectionListPtr anAttrSelectionList =
672     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
673   if(!anAttrSelectionList.get()) {
674     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
675     return false;
676   }
677
678   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
679     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
680
681     //GeomValidators_BodyShapes aBodyValidator;
682     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
683     //  continue;
684     //}
685
686     GeomValidators_FeatureKind aFeatureKindValidator;
687     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
688       continue;
689     }
690
691     ResultPtr aContext = aSelectAttr->context();
692     ResultConstructionPtr aResultConstruction =
693       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
694     if(aResultConstruction.get()) {
695       theError = "Error: Only body shapes and construction planes are allowed for selection.";
696       return false;
697     }
698
699     ResultCompSolidPtr aResultCompsolid =
700       std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aContext);
701     if(aResultCompsolid.get()) {
702       continue;
703     }
704
705     theError = "Error: Only body shapes and construction planes are allowed for selection.";
706     return false;
707   }
708
709   theError = "";
710   return true;
711 }
712
713 //==================================================================================================
714 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
715                                                      const std::list<std::string>& theArguments,
716                                                      Events_InfoMessage& theError) const
717 {
718   AttributeSelectionListPtr aSubShapesAttrList =
719     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
720   if(!aSubShapesAttrList.get()) {
721     theError =
722       "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
723     return false;
724   }
725
726   static const std::string aBaseShapeID = "base_shape";
727   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
728   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
729
730   if(!aShapeAttrSelection.get()) {
731     theError = "Error: Could not get \"%1\" attribute.";
732     theError.arg(aBaseShapeID);
733     return false;
734   }
735
736   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
737   ResultPtr aContext = aShapeAttrSelection->context();
738   if(!aContext.get()) {
739     theError = "Error: Empty context.";
740     return false;
741   }
742   if(!aBaseShape.get()) {
743     aBaseShape = aContext->shape();
744   }
745   if(!aBaseShape.get()) {
746     theError = "Error: Empty base shape.";
747     return false;
748   }
749
750   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
751     bool isSameFound = false;
752     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
753     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
754     for(GeomAPI_ShapeIterator anIt(aBaseShape); anIt.more(); anIt.next()) {
755       if(anIt.current()->isEqual(aShapeToAdd)) {
756         isSameFound = true;
757         break;
758       }
759     }
760     if(!isSameFound) {
761       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
762       return false;
763     }
764   }
765
766   return true;
767 }
768
769 //==================================================================================================
770 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
771   const std::shared_ptr<ModelAPI_Feature>& theFeature,
772   const std::list<std::string>& theArguments,
773   Events_InfoMessage& theError) const
774 {
775   static const std::string aBaseShapeID = "base_shape";
776   static const std::string aSubShapesID = "subshapes_to_keep";
777
778   if(theFeature->getKind() != "Remove_SubShapes") {
779     theError = "Error: Feature \"%1\" does not supported by this validator.";
780     theError.arg(theFeature->getKind());
781     return false;
782   }
783
784   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
785   if(!aShapeAttrSelection.get()) {
786     theError = "Error: Could not get \"%1\" attribute.";
787     theError.arg(aBaseShapeID);
788     return false;
789   }
790
791   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
792   if(!aSubShapesAttrList.get()) {
793     theError = "Error: Could not get \"%1\" attribute.";
794     theError.arg(aSubShapesID);
795     return false;
796   }
797
798   // Copy base shape.
799   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
800   if(!aBaseShape.get()) {
801     theError = "Error: Base shape is empty.";
802     return false;
803   }
804   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
805
806   if (aSubShapesAttrList->size() == 0) {
807     theError = "Error: Resulting shape is not valid.";
808     return false;
809   }
810
811   // Copy sub-shapes from list to new shape.
812   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
813     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
814     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
815     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
816   }
817
818   // Check new shape.
819   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
820     theError = "Error: Resulting shape is not valid.";
821     return false;
822   }
823
824   return true;
825 }
826
827 //==================================================================================================
828 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isNotObligatory(std::string theFeature,
829                                                                     std::string theAttribute)
830 {
831   return false;
832 }
833
834 //==================================================================================================
835 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
836                                                      const std::list<std::string>& theArguments,
837                                                      Events_InfoMessage& theError) const
838 {
839   AttributeSelectionListPtr aBaseObjectsAttrList =
840     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
841   if(!aBaseObjectsAttrList.get()) {
842     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
843     theError.arg(FeaturesPlugin_Union::ID());
844     return false;
845   }
846
847   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
848     bool isSameFound = false;
849     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
850     ResultPtr aContext = anAttrSelectionInList->context();
851
852     ResultConstructionPtr aConstruction =
853       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
854     if(aConstruction.get()) {
855       theError = "Error: Result construction not allowed for selection.";
856       return false;
857     }
858
859     GeomShapePtr aShape = anAttrSelectionInList->value();
860     GeomShapePtr aContextShape = aContext->shape();
861     if (aShape.get() && aContextShape.get() && !aContextShape->isEqual(aShape)) {
862       theError = "Error: Local selection not allowed.";
863       return false;
864     }
865
866     ResultCompSolidPtr aResult =
867       std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aContext);
868     if(!aResult.get()) {
869       continue;
870     }
871
872     if(aResult->numberOfSubs() > 0) {
873       theError = "Error: Whole compsolids not allowed for selection.";
874       return false;
875     }
876   }
877
878   return true;
879 }
880
881 //==================================================================================================
882 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
883   const std::shared_ptr<ModelAPI_Feature>& theFeature,
884   const std::list<std::string>& theArguments,
885   Events_InfoMessage& theError) const
886 {
887   // Check feature kind.
888   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
889     theError = "Error: This validator supports only \"%1\" feature.";
890     theError.arg(FeaturesPlugin_Union::ID());
891     return false;
892   }
893
894   // Get base objects attribute list.
895   AttributeSelectionListPtr aBaseObejctsAttrList =
896     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
897   if(!aBaseObejctsAttrList.get()) {
898     theError = "Error: Could not get \"%1\" attribute.";
899     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
900     return false;
901   }
902
903   // Get all shapes.
904   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::COMPSOLID;
905   ListOfShape aBaseShapesList;
906   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
907     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
908     GeomShapePtr aShape = anAttrSelectionInList->value();
909     if (!aShape.get()) {
910       continue;
911     }
912     aBaseShapesList.push_back(aShape);
913     aType = aShape->shapeType() == GeomAPI_Shape::FACE ? GeomAPI_Shape::SHELL :
914                                                          GeomAPI_Shape::COMPSOLID;
915   }
916
917   // Make compound and find connected.
918   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
919   ListOfShape aCombined, aFree;
920   GeomAlgoAPI_ShapeTools::combineShapes(
921     aCompound,
922     aType,
923     aCombined,
924     aFree);
925
926   if(aFree.size() > 0 || aCombined.size() > 1) {
927     theError = "Error: Not all shapes have shared topology.";
928     return false;
929   }
930
931   return true;
932 }
933
934 //==================================================================================================
935 bool FeaturesPlugin_ValidatorUnionArguments::isNotObligatory(std::string theFeature,
936                                                              std::string theAttribute)
937 {
938   return false;
939 }
940
941 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
942                                             const std::list<std::string>& theArguments,
943                                             Events_InfoMessage& theError) const
944 {
945   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
946     theError = "Error: The attribute with the %1 type is not processed";
947     theError.arg(theAttribute->attributeType());
948     return false;
949   }
950
951   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
952                                                                                (theAttribute);
953   ObjectPtr aRefObject = aRefAttribute->value();
954   if (!aRefObject.get()) {
955     theError = "Error: Empty feature.";
956     return false;
957   }
958
959   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
960   if (!aRefFeature.get()) {
961     theError = "Error: Empty feature.";
962     return false;
963   }
964   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
965   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
966
967   size_t aConcealedResults = aResults.size();
968   if (!aConcealedResults && !theArguments.empty()) {
969     // find if these results are touched by the feature in another attribute
970     std::list<std::string>::const_iterator anIt = theArguments.begin();
971     std::string aRecoveredList = *anIt;
972     if (!aRecoveredList.empty()) {
973       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
974                                  theAttribute->owner()->data()->reflist(aRecoveredList);
975       if (aParameterList.get())
976         aConcealedResults = aParameterList->size();
977     }
978   }
979
980   if (aConcealedResults == 0)
981     theError = "Error: No concealed results.";
982
983   return theError.empty();
984 }