Salome HOME
Issue #2565: CEA 2018-1 Intersection
[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_BooleanSmash.h"
25 #include "FeaturesPlugin_Union.h"
26
27 #include <Events_InfoMessage.h>
28
29 #include <ModelAPI_Attribute.h>
30 #include <ModelAPI_AttributeInteger.h>
31 #include <ModelAPI_AttributeSelectionList.h>
32 #include <ModelAPI_AttributeString.h>
33 #include <ModelAPI_AttributeReference.h>
34 #include <ModelAPI_AttributeRefList.h>
35 #include <ModelAPI_Feature.h>
36 #include <ModelAPI_ResultCompSolid.h>
37 #include <ModelAPI_ResultConstruction.h>
38 #include <ModelAPI_Tools.h>
39
40 #include <GeomValidators_BodyShapes.h>
41 #include <GeomValidators_Face.h>
42 #include <GeomValidators_FeatureKind.h>
43 #include <GeomValidators_ShapeType.h>
44
45 #include <GeomAPI_DataMapOfShapeShape.h>
46 #include <GeomAPI_Lin.h>
47 #include <GeomAPI_PlanarEdges.h>
48 #include <GeomAPI_Pln.h>
49 #include <GeomAPI_ShapeExplorer.h>
50 #include <GeomAPI_ShapeIterator.h>
51
52 #include <GeomAlgoAPI_CompoundBuilder.h>
53 #include <GeomAlgoAPI_ShapeBuilder.h>
54 #include <GeomAlgoAPI_ShapeTools.h>
55 #include <GeomAlgoAPI_WireBuilder.h>
56
57 #define _USE_MATH_DEFINES
58 #include <math.h>
59
60 //==================================================================================================
61 bool FeaturesPlugin_ValidatorPipePath::isValid(const AttributePtr& theAttribute,
62                                                const std::list<std::string>& theArguments,
63                                                Events_InfoMessage& theError) const
64 {
65   AttributeSelectionPtr aPathAttrSelection =
66     std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
67   if(!aPathAttrSelection.get()) {
68     theError = "Error: This validator can only work with path selector in \"Pipe\" feature.";
69     return false;
70   }
71
72   GeomShapePtr aPathShape = aPathAttrSelection->value();
73   ResultPtr aContext = aPathAttrSelection->context();
74   if(!aContext.get()) {
75     theError = "Error: Empty context.";
76     return false;
77   }
78   GeomShapePtr aContextShape = aContext->shape();
79   if(aPathShape.get() && aPathShape->shapeType() == GeomAPI_Shape::WIRE &&
80       !aPathShape->isEqual(aContextShape)) {
81     theError = "Error: Local selection of wires not allowed.";
82     return false;
83   }
84
85   return true;
86 }
87
88 //==================================================================================================
89 bool FeaturesPlugin_ValidatorPipeLocations::isValid(
90   const std::shared_ptr<ModelAPI_Feature>& theFeature,
91   const std::list<std::string>& theArguments,
92   Events_InfoMessage& theError) const
93 {
94   static const std::string aCreationMethodID = "creation_method";
95   static const std::string aBaseObjectsID = "base_objects";
96   static const std::string aLocationsID = "locations_objects";
97
98   if(theFeature->getKind() != "Pipe") {
99     theError = "Error: Feature \"%1\" does not supported by this validator.";
100     theError.arg(theFeature->getKind());
101     return false;
102   }
103
104   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
105   if(!aCreationMethodAttr.get()) {
106     theError = "Error: Could not get \"%1\" attribute.";
107     theError.arg(aCreationMethodID);
108     return false;
109   }
110
111   if(aCreationMethodAttr->value() != "locations") {
112     return true;
113   }
114
115   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
116   if(!aBaseObjectsSelectionList.get()) {
117     theError = "Error: Could not get \"%1\" attribute.";
118     theError.arg(aBaseObjectsID);
119     return false;
120   }
121
122   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
123   if(!aLocationsSelectionList.get()) {
124     theError = "Error: Could not get \"%1\" attribute.";
125     theError.arg(aBaseObjectsID);
126     return false;
127   }
128
129   if(aLocationsSelectionList->size() > 0 &&
130      aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
131     theError = "Error: Number of locations should be the same as base objects.";
132     return false;
133   }
134
135   return true;
136 }
137
138 //==================================================================================================
139 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
140                                                         const std::list<std::string>& theArguments,
141                                                         Events_InfoMessage& theError) const
142 {
143   if(theArguments.empty()) {
144     theError = "Error: Validator parameters is empty.";
145     return false;
146   }
147
148   // Checking attribute.
149   if(!isValidAttribute(theAttribute, theArguments, theError)) {
150     if(theError.empty()) {
151       theError = "Error: Attribute contains unacceptable shape.";
152     }
153     return false;
154   }
155
156   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
157   std::string anAttributeType = theAttribute->attributeType();
158   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
159     AttributeSelectionListPtr aListAttr =
160       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
161     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
162       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
163       ResultPtr aContext = aSelectionAttr->context();
164       if(!aContext.get()) {
165         theError = "Error: Empty context.";
166         return false;
167       }
168
169       ResultConstructionPtr aResultConstruction =
170         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
171       if(!aResultConstruction.get()) {
172         // It is not a result construction.
173         // If shape is compound check that it contains only faces and edges.
174         GeomShapePtr aShape = aSelectionAttr->value();
175         if(!aShape.get()) {
176           aShape = aContext->shape();
177         }
178
179         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
180           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
181             GeomShapePtr aSubShape = anIt.current();
182             if(aSubShape->shapeType() != GeomAPI_Shape::EDGE
183                 && aSubShape->shapeType() != GeomAPI_Shape::FACE) {
184               theError = "Error: Compound should contain only faces and edges.";
185               return false;
186             }
187           }
188         }
189
190         continue;
191       }
192
193       GeomShapePtr aShape = aSelectionAttr->value();
194       GeomShapePtr aContextShape = aResultConstruction->shape();
195       if(!aShape.get()) {
196         // Whole sketch selected.
197         continue;
198       } else {
199         // Object from sketch selected.
200         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
201           GeomShapePtr aWire = anExp.current();
202           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
203             theError = "Error: Wire with wrong orientation selected.";
204             return false;
205           }
206
207           if(aSelectedWiresFromObjects.isBound(aWire)) {
208             theError =
209               "Error: Objects with such wire already selected. Don't allow to select this object.";
210             return false;
211           }
212
213           aSelectedWiresFromObjects.bind(aWire, aWire);
214         }
215       }
216     }
217   }
218
219   return true;
220 }
221
222 //==================================================================================================
223 bool FeaturesPlugin_ValidatorBaseForGenerationSketchOrSketchObjects::isValid(
224   const std::shared_ptr<ModelAPI_Feature>& theFeature,
225   const std::list<std::string>& theArguments,
226   Events_InfoMessage& theError) const
227 {
228   const std::string aBaseObjectsID = theArguments.front();
229
230   AttributeSelectionListPtr aListAttr = theFeature->selectionList(aBaseObjectsID);
231   if(!aListAttr.get()) {
232     theError = "Error: Could not get \"%1\" attribute.";
233     theError.arg(aBaseObjectsID);
234     return false;
235   }
236
237   std::set<ResultConstructionPtr> aSelectedSketches;
238   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
239
240   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
241     AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
242     ResultPtr aContext = aSelectionAttr->context();
243     if(!aContext.get()) {
244       theError = "Error: Empty context.";
245       return false;
246     }
247
248     ResultConstructionPtr aResultConstruction =
249       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
250     if(!aResultConstruction.get()) {
251       // It is not a result construction.
252       continue;
253     }
254
255     GeomShapePtr aShape = aSelectionAttr->value();
256     GeomShapePtr aContextShape = aResultConstruction->shape();
257     if(!aShape.get()) {
258       // Whole sketch selected.
259       aSelectedSketches.insert(aResultConstruction);
260     } else {
261       // Object from sketch selected.
262       aSelectedSketchesFromObjects.insert(aResultConstruction);
263     }
264   }
265
266
267   for(std::set<ResultConstructionPtr>::const_iterator anIt = aSelectedSketches.cbegin();
268       anIt != aSelectedSketches.cend();
269       ++anIt) {
270     ResultConstructionPtr aResultConstruction = *anIt;
271     if(aSelectedSketchesFromObjects.find(aResultConstruction) !=
272         aSelectedSketchesFromObjects.cend()) {
273       theError = "Sketch and objects from it can not be selected at the same time.";
274       return false;
275     }
276   }
277
278   return true;
279 }
280
281 //==================================================================================================
282 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
283                                                         const std::list<std::string>& theArguments,
284                                                         Events_InfoMessage& theError) const
285 {
286   if(!theAttribute.get()) {
287     theError = "Error: Empty attribute.";
288     return false;
289   }
290
291   std::string anAttributeType = theAttribute->attributeType();
292   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
293     AttributeSelectionListPtr aListAttr =
294       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
295     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
296       // If at least one attribute is invalid, the result is false.
297       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
298         return false;
299       }
300     }
301   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
302     // Getting context.
303     AttributeSelectionPtr anAttr =
304       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
305     ResultPtr aContext = anAttr->context();
306     if(!aContext.get()) {
307       theError = "Error: Attribute have empty context.";
308       return false;
309     }
310
311     GeomShapePtr aShape = anAttr->value();
312     GeomShapePtr aContextShape = aContext->shape();
313     if(!aShape.get()) {
314       aShape = aContextShape;
315     }
316     if(!aShape.get()) {
317       theError = "Error: Empty shape selected";
318       return false;
319     }
320
321     ResultConstructionPtr aConstruction =
322       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
323     if(aConstruction.get()) {
324       // Construciotn selected. Check that is is not infinite.
325       if(aConstruction->isInfinite()) {
326         theError = "Error: Infinite constructions is not allowed as base.";
327         return false;
328       }
329
330       if(aShape->isEqual(aContextShape)) {
331         // Whole construction selected. Check that it have faces.
332         if(aConstruction->facesNum() > 0) {
333           return true;
334         }
335       } else {
336         // Shape on construction selected. Check that it is a face or wire.
337         if(aShape->shapeType() == GeomAPI_Shape::WIRE ||
338            aShape->shapeType() == GeomAPI_Shape::FACE) {
339           return true;
340         }
341       }
342
343       return false;
344     }
345
346     if(!aShape->isEqual(aContextShape)) {
347       // Local selection on body does not allowed.
348       theError =
349         "Error: Selected shape is in the local selection. Only global selection is allowed.";
350       return false;
351     }
352
353     // Check that object is a shape with allowed type.
354     GeomValidators_ShapeType aShapeTypeValidator;
355     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
356       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
357                  "wires on sketch, whole sketch(if it has at least one face), "
358                  "and whole objects with shape types: %1";
359       std::string anArgumentString;
360       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
361         if (!anArgumentString.empty())
362           anArgumentString += ", ";
363         anArgumentString += *anIt;
364       }
365       theError.arg(anArgumentString);
366       return false;
367     }
368
369   } else {
370     theError = "Error: Attribute \"%1\" does not supported by this validator.";
371     theError.arg(anAttributeType);
372     return false;
373   }
374
375   return true;
376 }
377
378 //==================================================================================================
379 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
380                                                         const std::list<std::string>& theArguments,
381                                                         Events_InfoMessage& theError) const
382 {
383   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
384     theError = "Error: The attribute with the %1 type is not processed";
385     theError.arg(theAttribute->attributeType());
386     return false;
387   }
388   if (theArguments.size() != 2) {
389     theError = "Error: Wrong parameters in XML definition for %1 type";
390     theError.arg(theAttribute->attributeType());
391     return false;
392   }
393   // first argument is for the base attribute, second - for skipping feature kind
394   std::list<std::string>::const_iterator anIt = theArguments.begin();
395   std::string aBaseAttributeId = *anIt;
396   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
397   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
398   if (!aBaseAttribute.get()) {
399     theError = "Wrong parameters in XML definition for %1 type";
400     theError.arg(theAttribute->attributeType());
401     return false;
402   }
403   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
404     // this validator is not necessary anymore
405     return true;
406
407   anIt++;
408   std::string aFeatureAttributeKind = *anIt;
409   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
410   // check whether the selection is on the sketch
411   std::list<std::string> anArguments;
412   anArguments.push_back(aFeatureAttributeKind);
413
414   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
415   bool aPlanarFace = false;
416   // check if selection has Face selected
417   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
418   anArguments.clear();
419   anArguments.push_back("face");
420   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
421
422   bool aValid = !aFeatureKind && aPlanarFace;
423   return aValid;
424 }
425
426 //==================================================================================================
427 bool FeaturesPlugin_ValidatorExtrusionDir::isValid(
428                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
429                                                const std::list<std::string>& theArguments,
430                                                Events_InfoMessage& theError) const
431 {
432   if(theArguments.size() != 2) {
433     theError = "Error: Validator should be used with 2 parameters for extrusion.";
434     return false;
435   }
436
437   std::list<std::string>::const_iterator
438     anArgsIt = theArguments.begin(), aLast = theArguments.end();
439
440   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
441   ++anArgsIt;
442
443   GeomShapePtr aDirShape;
444   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
445   if(aSelAttr.get()) {
446     aDirShape = aSelAttr->value();
447     if(!aDirShape.get()) {
448       ResultPtr aContext = aSelAttr->context();
449       if(aContext.get()) {
450         aDirShape = aContext->shape();
451       }
452     }
453   }
454
455   if(!aDirShape.get()) {
456     // Check that dir can be empty.
457     if(!isShapesCanBeEmpty(aCheckAttribute, theError)) {
458       theError = "Error: Base objects list contains vertex or edge, so attribute \"%1\" "
459                  "can not be used with default value. Select direction for extrusion.";
460       theError.arg(*anArgsIt);
461       return false;
462     } else {
463       return true;
464     }
465   }
466
467   std::shared_ptr<GeomAPI_Edge> aDirEdge(new GeomAPI_Edge(aDirShape));
468
469   // If faces selected check that direction not parallel with them.
470   AttributeSelectionListPtr aListAttr =
471     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aCheckAttribute);
472   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
473     AttributeSelectionPtr anAttr = aListAttr->value(anIndex);
474     GeomShapePtr aShapeInList = anAttr->value();
475     if(!aShapeInList.get()) {
476       aShapeInList = anAttr->context()->shape();
477     }
478     bool isParallel = true;
479     if(aShapeInList->shapeType() == GeomAPI_Shape::FACE ||
480        aShapeInList->shapeType() == GeomAPI_Shape::SHELL) {
481       for(GeomAPI_ShapeExplorer
482           anExp(aShapeInList, GeomAPI_Shape::FACE); anExp.more(); anExp.next()) {
483         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(anExp.current()));
484         isParallel = GeomAlgoAPI_ShapeTools::isParallel(aDirEdge, aFace);
485         if(isParallel) {
486           break;
487         }
488       }
489     } else if(aShapeInList->shapeType() == GeomAPI_Shape::COMPOUND) {
490       std::shared_ptr<GeomAPI_PlanarEdges> aPlanarEdges =
491         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aShapeInList);
492       if(aPlanarEdges.get()) {
493         std::shared_ptr<GeomAPI_Dir> aSketchDir = aPlanarEdges->norm();
494         if(aDirEdge->isLine()) {
495           std::shared_ptr<GeomAPI_Dir> aDir = aDirEdge->line()->direction();
496           isParallel = fabs(aSketchDir->angle(aDir) - M_PI / 2.0) < 10e-7;
497         } else {
498           isParallel = false;
499         }
500       } else {
501         isParallel = false;
502       }
503     } else {
504       isParallel = false;
505     }
506     if(isParallel) {
507       theError =
508         "Error: Direction is parallel to one of the selected face or face on selected shell.";
509       return false;
510     }
511   }
512
513   return true;
514 }
515
516 //==================================================================================================
517 bool FeaturesPlugin_ValidatorExtrusionDir::isShapesCanBeEmpty(const AttributePtr& theAttribute,
518                                                               Events_InfoMessage& theError) const
519 {
520   if(!theAttribute.get()) {
521     return true;
522   }
523
524   std::string anAttributeType = theAttribute->attributeType();
525   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
526     AttributeSelectionListPtr aListAttr =
527       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
528     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
529       // If at least one attribute is invalid, the result is false.
530       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
531         return false;
532       }
533     }
534   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
535     // Getting context.
536     AttributeSelectionPtr anAttr =
537       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
538     ResultPtr aContext = anAttr->context();
539     if(!aContext.get()) {
540       return false;
541     }
542
543     GeomShapePtr aShape = anAttr->value();
544     GeomShapePtr aContextShape = aContext->shape();
545     if(!aShape.get()) {
546       aShape = aContextShape;
547     }
548     if(!aShape.get()) {
549       return false;
550     }
551
552     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
553        aShape->shapeType() == GeomAPI_Shape::EDGE ||
554        !aShape->isPlanar()) {
555       return false;
556     }
557   } else {
558     return false;
559   }
560
561   return true;
562 }
563
564 //==================================================================================================
565 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
566                                                        const std::list<std::string>& theArguments,
567                                                        Events_InfoMessage& theError) const
568 {
569   AttributeSelectionListPtr anAttrSelectionList =
570     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
571   if(!anAttrSelectionList.get()) {
572     theError =
573       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
574     return false;
575   }
576   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
577     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theAttribute->owner());
578   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
579
580   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
581     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
582     if(!anAttrSelection.get()) {
583       theError = "Error: Empty attribute selection.";
584       return false;
585     }
586     ResultPtr aContext = anAttrSelection->context();
587     if(!aContext.get()) {
588       theError = "Error: Empty selection context.";
589       return false;
590     }
591     ResultConstructionPtr aResultConstruction =
592       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
593     if(aResultConstruction.get()) {
594       if (anOperationType != FeaturesPlugin_Boolean::BOOL_FILL
595           || theAttribute->id() != FeaturesPlugin_Boolean::TOOL_LIST_ID()) {
596         theError = "Error: Result construction not allowed for selection.";
597         return false;
598       }
599     }
600     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
601     GeomShapePtr aContextShape = aContext->shape();
602     if(!aShape.get()) {
603       aShape = aContextShape;
604     }
605     if(!aShape.get()) {
606       theError = "Error: Empty shape.";
607       return false;
608     }
609     if(!aShape->isEqual(aContextShape)) {
610       theError = "Error: Local selection not allowed.";
611       return false;
612     }
613
614     GeomAPI_Shape::ShapeType aShapeType = aShape->shapeType();
615     std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
616     if(anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE) {
617       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
618       anAllowedTypes.insert(GeomAPI_Shape::FACE);
619       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
620       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
621       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
622     } else if (anOperationType == FeaturesPlugin_Boolean::BOOL_FILL
623                || anOperationType == FeaturesPlugin_Boolean::BOOL_CUT)
624     {
625       anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
626       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
627       anAllowedTypes.insert(GeomAPI_Shape::WIRE);
628       anAllowedTypes.insert(GeomAPI_Shape::FACE);
629       anAllowedTypes.insert(GeomAPI_Shape::SHELL);
630       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
631       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
632       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
633     } else {
634       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
635       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
636       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
637     }
638
639     if(anAllowedTypes.find(aShapeType) == anAllowedTypes.end()
640       || (aResultConstruction.get() && aShapeType != GeomAPI_Shape::FACE)) {
641       theError = "Error: Selected shape has the wrong type.";
642       return false;
643     }
644
645   }
646
647   return true;
648 }
649
650 //==================================================================================================
651 bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAttribute,
652                                                       const std::list<std::string>& theArguments,
653                                                       Events_InfoMessage& theError) const
654 {
655   AttributeSelectionListPtr anAttrSelectionList =
656     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
657   if(!anAttrSelectionList.get()) {
658     theError =
659       "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
660     return false;
661   }
662
663   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
664   // Check all selected entities are sub-shapes of single solid
665   GeomShapePtr aBaseSolid;
666   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
667     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
668     if(!anAttrSelection.get()) {
669       theError = "Error: Empty attribute selection.";
670       return false;
671     }
672     ResultPtr aContext = anAttrSelection->context();
673     if(!aContext.get()) {
674       theError = "Error: Empty selection context.";
675       return false;
676     }
677
678     ResultCompSolidPtr aContextOwner = ModelAPI_Tools::compSolidOwner(aContext);
679     GeomShapePtr anOwner = aContextOwner.get() ? aContextOwner->shape() : aContext->shape();
680
681     if (anOwner->shapeType() != GeomAPI_Shape::SOLID &&
682         anOwner->shapeType() != GeomAPI_Shape::COMPSOLID) {
683       theError = "Error: Not all selected shapes are sub-shapes of solids";
684       return false;
685     }
686
687     if (!aBaseSolid)
688       aBaseSolid = anOwner;
689     else if (!aBaseSolid->isEqual(anOwner)) {
690       theError = "Error: Sub-shapes of different solids have been selected.";
691       return false;
692     }
693   }
694
695   return true;
696 }
697
698 //==================================================================================================
699 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
700                                                        const std::list<std::string>& theArguments,
701                                                        Events_InfoMessage& theError) const
702 {
703   AttributeSelectionListPtr anAttrSelectionList =
704     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
705   if(!anAttrSelectionList.get()) {
706     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
707     return false;
708   }
709
710   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
711     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
712
713     //GeomValidators_BodyShapes aBodyValidator;
714     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
715     //  continue;
716     //}
717
718     GeomValidators_FeatureKind aFeatureKindValidator;
719     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
720       continue;
721     }
722
723     ResultPtr aContext = aSelectAttr->context();
724     ResultConstructionPtr aResultConstruction =
725       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
726     if(aResultConstruction.get()) {
727       theError = "Error: Only body shapes and construction planes are allowed for selection.";
728       return false;
729     }
730
731     ResultCompSolidPtr aResultCompsolid =
732       std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aContext);
733     if(aResultCompsolid.get()) {
734       continue;
735     }
736
737     theError = "Error: Only body shapes and construction planes are allowed for selection.";
738     return false;
739   }
740
741   theError = "";
742   return true;
743 }
744
745 //==================================================================================================
746 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
747                                                      const std::list<std::string>& theArguments,
748                                                      Events_InfoMessage& theError) const
749 {
750   AttributeSelectionListPtr aSubShapesAttrList =
751     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
752   if(!aSubShapesAttrList.get()) {
753     theError =
754       "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
755     return false;
756   }
757
758   static const std::string aBaseShapeID = "base_shape";
759   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
760   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
761
762   if(!aShapeAttrSelection.get()) {
763     theError = "Error: Could not get \"%1\" attribute.";
764     theError.arg(aBaseShapeID);
765     return false;
766   }
767
768   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
769   ResultPtr aContext = aShapeAttrSelection->context();
770   if(!aContext.get()) {
771     theError = "Error: Empty context.";
772     return false;
773   }
774   if(!aBaseShape.get()) {
775     aBaseShape = aContext->shape();
776   }
777   if(!aBaseShape.get()) {
778     theError = "Error: Empty base shape.";
779     return false;
780   }
781
782   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
783     bool isSameFound = false;
784     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
785     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
786     for(GeomAPI_ShapeIterator anIt(aBaseShape); anIt.more(); anIt.next()) {
787       if(anIt.current()->isEqual(aShapeToAdd)) {
788         isSameFound = true;
789         break;
790       }
791     }
792     if(!isSameFound) {
793       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
794       return false;
795     }
796   }
797
798   return true;
799 }
800
801 //==================================================================================================
802 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
803   const std::shared_ptr<ModelAPI_Feature>& theFeature,
804   const std::list<std::string>& theArguments,
805   Events_InfoMessage& theError) const
806 {
807   static const std::string aBaseShapeID = "base_shape";
808   static const std::string aSubShapesID = "subshapes_to_keep";
809
810   if(theFeature->getKind() != "Remove_SubShapes") {
811     theError = "Error: Feature \"%1\" does not supported by this validator.";
812     theError.arg(theFeature->getKind());
813     return false;
814   }
815
816   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
817   if(!aShapeAttrSelection.get()) {
818     theError = "Error: Could not get \"%1\" attribute.";
819     theError.arg(aBaseShapeID);
820     return false;
821   }
822
823   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
824   if(!aSubShapesAttrList.get()) {
825     theError = "Error: Could not get \"%1\" attribute.";
826     theError.arg(aSubShapesID);
827     return false;
828   }
829
830   // Copy base shape.
831   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
832   if(!aBaseShape.get()) {
833     theError = "Error: Base shape is empty.";
834     return false;
835   }
836   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
837
838   if (aSubShapesAttrList->size() == 0) {
839     theError = "Error: Resulting shape is not valid.";
840     return false;
841   }
842
843   // Copy sub-shapes from list to new shape.
844   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
845     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
846     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
847     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
848   }
849
850   // Check new shape.
851   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
852     theError = "Error: Resulting shape is not valid.";
853     return false;
854   }
855
856   return true;
857 }
858
859 //==================================================================================================
860 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
861                                                      const std::list<std::string>& theArguments,
862                                                      Events_InfoMessage& theError) const
863 {
864   AttributeSelectionListPtr aBaseObjectsAttrList =
865     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
866   if(!aBaseObjectsAttrList.get()) {
867     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
868     theError.arg(FeaturesPlugin_Union::ID());
869     return false;
870   }
871
872   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
873     bool isSameFound = false;
874     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
875     ResultPtr aContext = anAttrSelectionInList->context();
876     if (!aContext.get()) {
877       theError = "Error: selection is invalid.";
878       return false;
879     }
880
881     ResultConstructionPtr aConstruction =
882       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
883     if(aConstruction.get()) {
884       theError = "Error: Result construction not allowed for selection.";
885       return false;
886     }
887
888     GeomShapePtr aShape = anAttrSelectionInList->value();
889     GeomShapePtr aContextShape = aContext->shape();
890     if (aShape.get() && aContextShape.get() && !aContextShape->isEqual(aShape)) {
891       theError = "Error: Local selection not allowed.";
892       return false;
893     }
894
895     ResultCompSolidPtr aResult =
896       std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aContext);
897     if(!aResult.get()) {
898       continue;
899     }
900
901     if(aResult->numberOfSubs() > 0) {
902       theError = "Error: Whole compsolids not allowed for selection.";
903       return false;
904     }
905   }
906
907   return true;
908 }
909
910 //==================================================================================================
911 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
912   const std::shared_ptr<ModelAPI_Feature>& theFeature,
913   const std::list<std::string>& theArguments,
914   Events_InfoMessage& theError) const
915 {
916   // Check feature kind.
917   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
918     theError = "Error: This validator supports only \"%1\" feature.";
919     theError.arg(FeaturesPlugin_Union::ID());
920     return false;
921   }
922
923   // Get base objects attribute list.
924   AttributeSelectionListPtr aBaseObejctsAttrList =
925     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
926   if(!aBaseObejctsAttrList.get()) {
927     theError = "Error: Could not get \"%1\" attribute.";
928     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
929     return false;
930   }
931
932   // Get all shapes.
933   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::COMPSOLID;
934   ListOfShape aBaseShapesList;
935   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
936     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
937     GeomShapePtr aShape = anAttrSelectionInList->value();
938     if (!aShape.get()) {
939       continue;
940     }
941     aBaseShapesList.push_back(aShape);
942     aType = aShape->shapeType() == GeomAPI_Shape::FACE ? GeomAPI_Shape::SHELL :
943                                                          GeomAPI_Shape::COMPSOLID;
944   }
945
946   // Make compound and find connected.
947   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
948   ListOfShape aCombined, aFree;
949   GeomAlgoAPI_ShapeTools::combineShapes(
950     aCompound,
951     aType,
952     aCombined,
953     aFree);
954
955   if(aFree.size() > 0 || aCombined.size() > 1) {
956     theError = "Error: Not all shapes have shared topology.";
957     return false;
958   }
959
960   return true;
961 }
962
963 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
964                                             const std::list<std::string>& theArguments,
965                                             Events_InfoMessage& theError) const
966 {
967   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
968     theError = "Error: The attribute with the %1 type is not processed";
969     theError.arg(theAttribute->attributeType());
970     return false;
971   }
972
973   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
974                                                                                (theAttribute);
975   ObjectPtr aRefObject = aRefAttribute->value();
976   if (!aRefObject.get()) {
977     theError = "Error: Empty feature.";
978     return false;
979   }
980
981   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
982   if (!aRefFeature.get()) {
983     theError = "Error: Empty feature.";
984     return false;
985   }
986   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
987   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
988
989   size_t aConcealedResults = aResults.size();
990   if (!aConcealedResults && !theArguments.empty()) {
991     // find if these results are touched by the feature in another attribute
992     std::list<std::string>::const_iterator anIt = theArguments.begin();
993     std::string aRecoveredList = *anIt;
994     if (!aRecoveredList.empty()) {
995       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
996                                  theAttribute->owner()->data()->reflist(aRecoveredList);
997       if (aParameterList.get())
998         aConcealedResults = aParameterList->size();
999     }
1000   }
1001
1002   if (aConcealedResults == 0)
1003     theError = "Error: No concealed results.";
1004
1005   return theError.empty();
1006 }
1007
1008 bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
1009                                                const std::list<std::string>& theArguments,
1010                                                Events_InfoMessage& theError) const
1011 {
1012   static std::list<std::string> aEdgeArg(1, "circle");
1013   static std::list<std::string> aFaceArg(1, "cylinder");
1014
1015   Events_InfoMessage aError;
1016   bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
1017   if (!isValid) {
1018     isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
1019     if (!isValid)
1020       theError = "The shape neither circle nor cylinder";
1021   }
1022   return isValid;
1023 }
1024
1025 //=================================================================================================
1026 bool FeaturesPlugin_ValidatorBooleanArguments::isValid(
1027   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1028   const std::list<std::string>& theArguments,
1029   Events_InfoMessage& theError) const
1030 {
1031   if (theArguments.size() != 2)
1032   {
1033     theError = "Wrong number of arguments (expected 2).";
1034     return false;
1035   }
1036
1037   int anObjectsNb = 0, aToolsNb = 0;
1038   //int anOperationType = 0;
1039
1040   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1041
1042   bool isAllInSameCompSolid = true;
1043   ResultCompSolidPtr aCompSolid;
1044
1045   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1046   if (anAttrSelList)
1047   {
1048     anObjectsNb = anAttrSelList->size();
1049     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex)
1050     {
1051       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1052       ResultPtr aContext = anAttr->context();
1053       ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
1054       if (aResCompSolidPtr.get())
1055       {
1056         if (aCompSolid.get())
1057         {
1058           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1059         }
1060         else
1061         {
1062           aCompSolid = aResCompSolidPtr;
1063         }
1064       }
1065       else
1066       {
1067         isAllInSameCompSolid = false;
1068         break;
1069       }
1070     }
1071   }
1072   anIt++;
1073
1074
1075   anAttrSelList = theFeature->selectionList(*anIt);
1076   if (anAttrSelList)
1077   {
1078     aToolsNb = anAttrSelList->size();
1079     if (isAllInSameCompSolid)
1080     {
1081       for (int anIndex = 0; anIndex < aToolsNb; ++anIndex)
1082       {
1083         AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1084         ResultPtr aContext = anAttr->context();
1085         ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
1086         if (aResCompSolidPtr.get())
1087         {
1088           if (aCompSolid.get())
1089           {
1090             isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1091           }
1092           else
1093           {
1094             aCompSolid = aResCompSolidPtr;
1095           }
1096         }
1097         else
1098         {
1099           isAllInSameCompSolid = false;
1100           break;
1101         }
1102       }
1103     }
1104   }
1105   anIt++;
1106
1107   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1108     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1109   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1110
1111   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1112   {
1113     // Fuse operation
1114     if (anObjectsNb + aToolsNb < 2)
1115     {
1116       theError = "Not enough arguments for Fuse operation.";
1117       return false;
1118     }
1119     else if (isAllInSameCompSolid)
1120     {
1121       theError = "Operations only between sub-shapes of the same shape not allowed.";
1122       return false;
1123     }
1124   }
1125   else
1126   {
1127     if (anObjectsNb < 1)
1128     {
1129       theError = "Objects not selected.";
1130       return false;
1131     }
1132     if (aToolsNb < 1)
1133     {
1134       theError = "Tools not selected.";
1135       return false;
1136     }
1137     if (isAllInSameCompSolid)
1138     {
1139       theError = "Operations only between sub-shapes of the same shape not allowed.";
1140       return false;
1141     }
1142   }
1143
1144   return true;
1145 }
1146
1147 //=================================================================================================
1148 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1149                                                                std::string theAttribute)
1150 {
1151   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1152   {
1153     return true;
1154   }
1155
1156   return false;
1157 }
1158
1159 //==================================================================================================
1160 bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
1161   const AttributePtr& theAttribute,
1162   const std::list<std::string>& theArguments,
1163   Events_InfoMessage& theError) const
1164 {
1165   std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
1166     std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
1167
1168   AttributeSelectionListPtr anAttrSelectionList =
1169     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1170   if (!aFeature.get() || !anAttrSelectionList.get()) {
1171     theError =
1172       "Error: Validator used in wrong feature or attribute";
1173     return false;
1174   }
1175
1176   AttributeSelectionListPtr anOtherAttrSelectionList;
1177   if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
1178     anOtherAttrSelectionList =
1179       aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
1180   } else {
1181     anOtherAttrSelectionList =
1182       aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
1183   }
1184
1185   GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
1186   GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
1187   GeomPlanePtr aFacesPln;
1188
1189   for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
1190     AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
1191     ResultPtr aContext = anAttrSelection->context();
1192     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1193     GeomShapePtr aContextShape = aContext->shape();
1194     if (!aShape.get()) {
1195       aShape = aContextShape;
1196     }
1197
1198     if (aShape->isSolid() || aShape->isCompSolid()) {
1199       aSelectedShapesType = GeomAPI_Shape::SOLID;
1200       ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
1201       if (aResCompSolidPtr.get()) {
1202         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1203         aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
1204       }
1205     } else {
1206       aSelectedShapesType = GeomAPI_Shape::FACE;
1207       GeomAPI_Face aFace(aShape);
1208       aFacesPln = aFace.getPlane();
1209       break;
1210     }
1211   }
1212
1213   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1214     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1215     if (!anAttrSelection.get()) {
1216       theError = "Error: Empty attribute selection.";
1217       return false;
1218     }
1219     ResultPtr aContext = anAttrSelection->context();
1220     if (!aContext.get()) {
1221       theError = "Error: Empty selection context.";
1222       return false;
1223     }
1224     ResultConstructionPtr aResultConstruction =
1225       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1226     if (aResultConstruction.get()) {
1227       theError = "Error: Result construction not allowed for selection.";
1228       return false;
1229     }
1230     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1231     GeomShapePtr aContextShape = aContext->shape();
1232     if (!aShape.get()) {
1233       aShape = aContextShape;
1234     }
1235     if (!aShape.get()) {
1236       theError = "Error: Empty shape.";
1237       return false;
1238     }
1239     if (!aShape->isEqual(aContextShape)) {
1240       theError = "Error: Local selection not allowed.";
1241       return false;
1242     }
1243
1244     if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
1245       // Other list is empty.
1246       if (aShape->isSolid() || aShape->isCompSolid()) {
1247         aSelectedShapesType = GeomAPI_Shape::SOLID;
1248       } else {
1249         aSelectedShapesType = GeomAPI_Shape::FACE;
1250         GeomAPI_Face aFace(aShape);
1251         aFacesPln = aFace.getPlane();
1252
1253         if (!aFacesPln.get()) {
1254           theError = "Error: Only planar faces allowed.";
1255           return false;
1256         }
1257       }
1258
1259       continue;
1260     } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
1261       if (!aShape->isSolid() && !aShape->isCompSolid()) {
1262         theError = "Error: Selected shapes should have the same type.";
1263         return false;
1264       }
1265
1266       ResultCompSolidPtr aResCompSolidPtr = ModelAPI_Tools::compSolidOwner(aContext);
1267       if (aResCompSolidPtr.get()) {
1268         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1269         if (aSelectedCompSolidsInOtherList.isBound(aCompSolidShape)) {
1270           theError = "Error: Solids from compsolid in other list not allowed.";
1271           return false;
1272         }
1273       }
1274     } else {
1275       GeomAPI_Face aFace(aShape);
1276       GeomPlanePtr aPln = aFace.getPlane();
1277
1278       if (!aPln.get()) {
1279         theError = "Error: Only planar faces allowed.";
1280         return false;
1281       }
1282
1283       if (!aFacesPln->isCoincident(aPln)) {
1284         theError = "Error: Only coincident faces allowed.";
1285         return false;
1286       }
1287     }
1288   }
1289
1290   return true;
1291 }
1292
1293 //==================================================================================================
1294 bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttribute,
1295                                                    const std::list<std::string>& theArguments,
1296                                                    Events_InfoMessage& theError) const
1297 {
1298   if (!theAttribute.get()) {
1299     theError = "Error: empty selection.";
1300     return false;
1301   }
1302   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1303   AttributeSelectionListPtr anAttrSelectionList =
1304     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1305   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1306     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1307     if (!anAttrSelection.get()) {
1308       theError = "Error: empty attribute selection.";
1309       return false;
1310     }
1311     ResultPtr aContext = anAttrSelection->context();
1312     if (!aContext.get()) {
1313       theError = "Error: empty selection context.";
1314       return false;
1315     }
1316     FeaturePtr aFeature = ModelAPI_Feature::feature(aContext);
1317     if (!aFeature.get()) {
1318       theError = "Error: empty feature.";
1319       return false;
1320     }
1321     std::string aFeatureKind = aFeature->getKind();
1322     if (aFeatureKind == "Sketch" ||
1323         aFeatureKind == "Plane" ||
1324         aFeatureKind == "Axis") {
1325       theError = "Error: %1 shape is not allowed for selection.";
1326       theError.arg(aFeatureKind);
1327       return false;
1328     }
1329     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1330     GeomShapePtr aContextShape = aContext->shape();
1331     if (!aShape.get()) {
1332       aShape = aContextShape;
1333     }
1334     if (!aShape.get()) {
1335       theError = "Error: empty shape.";
1336       return false;
1337     }
1338     if (!aShape->isEqual(aContextShape)) {
1339       theError = "Error: Local selection not allowed.";
1340       return false;
1341     }
1342
1343     int aShapeType = aShape->shapeType();
1344     // Allow to select edges, faces and solids.
1345     if (aShapeType != GeomAPI_Shape::EDGE &&
1346         aShapeType != GeomAPI_Shape::FACE &&
1347         aShapeType != GeomAPI_Shape::SOLID &&
1348         aShapeType != GeomAPI_Shape::COMPSOLID &&
1349         aShapeType != GeomAPI_Shape::COMPOUND) {
1350       theError = "Error: selected shape has the wrong type.";
1351       return false;
1352     }
1353   }
1354
1355   return true;
1356 }