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