Salome HOME
First implementation of the sketch drawer: helper for creation of sketch on imported...
[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 anObjectsNb = 0, aToolsNb = 0;
1172   //int anOperationType = 0;
1173
1174   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1175
1176   bool isAllInSameCompSolid = true;
1177   ResultBodyPtr aCompSolid;
1178
1179   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1180   if (anAttrSelList)
1181   {
1182     anObjectsNb = anAttrSelList->size();
1183     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex)
1184     {
1185       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1186       ResultPtr aContext = anAttr->context();
1187       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1188       if (aResCompSolidPtr.get())
1189       {
1190         if (aCompSolid.get())
1191         {
1192           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1193         }
1194         else
1195         {
1196           aCompSolid = aResCompSolidPtr;
1197         }
1198       }
1199       else
1200       {
1201         isAllInSameCompSolid = false;
1202         break;
1203       }
1204     }
1205   }
1206   anIt++;
1207
1208
1209   anAttrSelList = theFeature->selectionList(*anIt);
1210   if (anAttrSelList)
1211   {
1212     aToolsNb = anAttrSelList->size();
1213     if (isAllInSameCompSolid)
1214     {
1215       for (int anIndex = 0; anIndex < aToolsNb; ++anIndex)
1216       {
1217         AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1218         ResultPtr aContext = anAttr->context();
1219         ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1220         if (aResCompSolidPtr.get())
1221         {
1222           if (aCompSolid.get())
1223           {
1224             isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1225           }
1226           else
1227           {
1228             aCompSolid = aResCompSolidPtr;
1229           }
1230         }
1231         else
1232         {
1233           isAllInSameCompSolid = false;
1234           break;
1235         }
1236       }
1237     }
1238   }
1239   anIt++;
1240
1241   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1242     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1243   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1244
1245   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1246   {
1247     // Fuse operation
1248     if (anObjectsNb + aToolsNb < 2)
1249     {
1250       theError = "Not enough arguments for Fuse operation.";
1251       return false;
1252     }
1253     else if (isAllInSameCompSolid)
1254     {
1255       theError = "Operations only between sub-shapes of the same shape not allowed.";
1256       return false;
1257     }
1258   }
1259   else
1260   {
1261     if (anObjectsNb < 1)
1262     {
1263       theError = "Objects not selected.";
1264       return false;
1265     }
1266     if (aToolsNb < 1)
1267     {
1268       theError = "Tools not selected.";
1269       return false;
1270     }
1271     if (isAllInSameCompSolid)
1272     {
1273       theError = "Operations only between sub-shapes of the same shape not allowed.";
1274       return false;
1275     }
1276   }
1277
1278   return true;
1279 }
1280
1281 //=================================================================================================
1282 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1283                                                                std::string theAttribute)
1284 {
1285   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1286   {
1287     return true;
1288   }
1289
1290   return false;
1291 }
1292
1293 //==================================================================================================
1294 bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
1295   const AttributePtr& theAttribute,
1296   const std::list<std::string>& theArguments,
1297   Events_InfoMessage& theError) const
1298 {
1299   std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
1300     std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
1301
1302   AttributeSelectionListPtr anAttrSelectionList =
1303     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1304   if (!aFeature.get() || !anAttrSelectionList.get()) {
1305     theError =
1306       "Error: Validator used in wrong feature or attribute";
1307     return false;
1308   }
1309
1310   AttributeSelectionListPtr anOtherAttrSelectionList;
1311   if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
1312     anOtherAttrSelectionList =
1313       aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
1314   } else {
1315     anOtherAttrSelectionList =
1316       aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
1317   }
1318
1319   GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
1320   GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
1321   GeomPlanePtr aFacesPln;
1322
1323   for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
1324     AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
1325
1326     if (anAttrSelection->contextFeature().get()) {
1327       theError = "Error: Features not allowed for selection.";
1328       return false;
1329     }
1330
1331     ResultPtr aContext = anAttrSelection->context();
1332     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1333     GeomShapePtr aContextShape = aContext->shape();
1334     if (!aShape.get()) {
1335       aShape = aContextShape;
1336     }
1337
1338     if (aShape->isSolid() || aShape->isCompSolid()) {
1339       aSelectedShapesType = GeomAPI_Shape::SOLID;
1340       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1341       if (aResCompSolidPtr.get()) {
1342         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1343         aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
1344       }
1345     } else {
1346       aSelectedShapesType = GeomAPI_Shape::FACE;
1347       GeomAPI_Face aFace(aShape);
1348       aFacesPln = aFace.getPlane();
1349       break;
1350     }
1351   }
1352
1353   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1354     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1355     if (!anAttrSelection.get()) {
1356       theError = "Error: Empty attribute selection.";
1357       return false;
1358     }
1359
1360     if (anAttrSelection->contextFeature().get()) {
1361       theError = "Error: Features not allowed for selection.";
1362       return false;
1363     }
1364
1365     ResultPtr aContext = anAttrSelection->context();
1366     if(!aContext.get()) {
1367       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1368       if (!aContFeat.get() || !aContFeat->results().size() ||
1369           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1370         theError = "Error: Empty selection context.";
1371         return false;
1372       }
1373     }
1374     ResultConstructionPtr aResultConstruction =
1375       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1376     if (aResultConstruction.get()) {
1377       theError = "Error: Result construction not allowed for selection.";
1378       return false;
1379     }
1380     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1381     GeomShapePtr aContextShape = aContext->shape();
1382     if (!aShape.get()) {
1383       aShape = aContextShape;
1384     }
1385     if (!aShape.get()) {
1386       theError = "Error: Empty shape.";
1387       return false;
1388     }
1389     if (!aShape->isEqual(aContextShape)) {
1390       theError = "Error: Local selection not allowed.";
1391       return false;
1392     }
1393
1394     if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
1395       // Other list is empty.
1396       if (aShape->isSolid() || aShape->isCompSolid()) {
1397         aSelectedShapesType = GeomAPI_Shape::SOLID;
1398       } else {
1399         aSelectedShapesType = GeomAPI_Shape::FACE;
1400         GeomAPI_Face aFace(aShape);
1401         aFacesPln = aFace.getPlane();
1402
1403         if (!aFacesPln.get()) {
1404           theError = "Error: Only planar faces allowed.";
1405           return false;
1406         }
1407       }
1408
1409       continue;
1410     } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
1411       if (!aShape->isSolid() && !aShape->isCompSolid()) {
1412         theError = "Error: Selected shapes should have the same type.";
1413         return false;
1414       }
1415
1416       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1417       if (aResCompSolidPtr.get()) {
1418         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1419         if (aSelectedCompSolidsInOtherList.isBound(aCompSolidShape)) {
1420           theError = "Error: Solids from compsolid in other list not allowed.";
1421           return false;
1422         }
1423       }
1424     } else {
1425       GeomAPI_Face aFace(aShape);
1426       GeomPlanePtr aPln = aFace.getPlane();
1427
1428       if (!aPln.get()) {
1429         theError = "Error: Only planar faces allowed.";
1430         return false;
1431       }
1432
1433       if (!aFacesPln->isCoincident(aPln)) {
1434         theError = "Error: Only coincident faces allowed.";
1435         return false;
1436       }
1437     }
1438   }
1439
1440   return true;
1441 }
1442
1443 //==================================================================================================
1444 bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttribute,
1445                                                    const std::list<std::string>& theArguments,
1446                                                    Events_InfoMessage& theError) const
1447 {
1448   if (!theAttribute.get()) {
1449     theError = "Error: empty selection.";
1450     return false;
1451   }
1452   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1453   AttributeSelectionListPtr anAttrSelectionList =
1454     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1455   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1456     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1457     if (!anAttrSelection.get()) {
1458       theError = "Error: empty attribute selection.";
1459       return false;
1460     }
1461     ResultPtr aContext = anAttrSelection->context();
1462     if(!aContext.get()) {
1463       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1464       if (!aContFeat.get() || !aContFeat->results().size() ||
1465           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1466         theError = "Error: Empty selection context.";
1467         return false;
1468       }
1469     }
1470     FeaturePtr aFeature = anAttrSelection->contextFeature().get() ?
1471       anAttrSelection->contextFeature() : ModelAPI_Feature::feature(aContext);
1472     if (!aFeature.get()) {
1473       theError = "Error: empty feature.";
1474       return false;
1475     }
1476     std::string aFeatureKind = aFeature->getKind();
1477     if (aFeatureKind == "Sketch" ||
1478         aFeatureKind == "Plane" ||
1479         aFeatureKind == "Axis") {
1480       theError = "Error: %1 shape is not allowed for selection.";
1481       theError.arg(aFeatureKind);
1482       return false;
1483     }
1484     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1485     if (!aShape.get()) {
1486       GeomShapePtr aContextShape = aContext->shape();
1487       aShape = aContextShape;
1488     }
1489     if (!aShape.get()) {
1490       theError = "Error: empty shape.";
1491       return false;
1492     }
1493     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1494       theError = "Error: Local selection not allowed.";
1495       return false;
1496     }
1497
1498     int aShapeType = aShape->shapeType();
1499     // Allow to select edges, faces and solids.
1500     if (aShapeType != GeomAPI_Shape::EDGE &&
1501         aShapeType != GeomAPI_Shape::FACE &&
1502         aShapeType != GeomAPI_Shape::SOLID &&
1503         aShapeType != GeomAPI_Shape::COMPSOLID &&
1504         aShapeType != GeomAPI_Shape::COMPOUND) {
1505       theError = "Error: selected shape has the wrong type.";
1506       return false;
1507     }
1508   }
1509
1510   return true;
1511 }
1512
1513 //==================================================================================================
1514 bool FeaturesPlugin_ValidatorBooleanFuseSelection::isValid(
1515   const AttributePtr& theAttribute,
1516   const std::list<std::string>& theArguments,
1517   Events_InfoMessage& theError) const
1518 {
1519   AttributeSelectionListPtr anAttrSelectionList =
1520     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1521   if (!anAttrSelectionList.get()) {
1522     theError =
1523       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1524     return false;
1525   }
1526
1527   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1528     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1529     if (!anAttrSelection.get()) {
1530       theError = "Error: Empty attribute selection.";
1531       return false;
1532     }
1533     ResultPtr aContext = anAttrSelection->context();
1534     if(!aContext.get()) {
1535       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1536       if (!aContFeat.get() || !aContFeat->results().size() ||
1537           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1538         theError = "Error: Empty selection context.";
1539         return false;
1540       }
1541     }
1542     ResultConstructionPtr aResultConstruction =
1543       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1544     if (aResultConstruction.get()) {
1545       theError = "Error: Result construction not allowed for selection.";
1546       return false;
1547     }
1548     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1549     if (!aShape.get()) {
1550       GeomShapePtr aContextShape = aContext->shape();
1551       aShape = aContextShape;
1552     }
1553     if (!aShape.get()) {
1554       theError = "Error: Empty shape.";
1555       return false;
1556     }
1557     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1558       theError = "Error: Local selection not allowed.";
1559       return false;
1560     }
1561   }
1562
1563   return true;
1564 }
1565
1566 //=================================================================================================
1567 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
1568   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1569   const std::list<std::string>& theArguments,
1570   Events_InfoMessage& theError) const
1571 {
1572   if (theArguments.size() != 2) {
1573     theError = "Wrong number of arguments (expected 2).";
1574     return false;
1575   }
1576
1577   std::shared_ptr<FeaturesPlugin_BooleanFuse> aFeature =
1578     std::dynamic_pointer_cast<FeaturesPlugin_BooleanFuse>(theFeature);
1579
1580   int anObjectsNb = 0, aToolsNb = 0;
1581
1582   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1583
1584   bool isAllInSameCompSolid = true;
1585   ResultBodyPtr aCompSolid;
1586
1587   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1588   if (anAttrSelList) {
1589     anObjectsNb = anAttrSelList->size();
1590     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex) {
1591       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1592       ResultPtr aContext = anAttr->context();
1593       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1594       if (aResCompSolidPtr.get()) {
1595         if (aCompSolid.get()) {
1596           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1597         } else {
1598           aCompSolid = aResCompSolidPtr;
1599         }
1600       } else {
1601         isAllInSameCompSolid = false;
1602         break;
1603       }
1604     }
1605   }
1606   anIt++;
1607
1608   if (aFeature->string(FeaturesPlugin_BooleanFuse::CREATION_METHOD())->value()
1609       == FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED()) {
1610     anAttrSelList = theFeature->selectionList(*anIt);
1611     if (anAttrSelList) {
1612       aToolsNb = anAttrSelList->size();
1613       if (isAllInSameCompSolid) {
1614         for (int anIndex = 0; anIndex < aToolsNb; ++anIndex) {
1615           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1616           ResultPtr aContext = anAttr->context();
1617           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1618           if (aResCompSolidPtr.get()) {
1619             if (aCompSolid.get()) {
1620               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1621             } else {
1622               aCompSolid = aResCompSolidPtr;
1623             }
1624           } else {
1625             isAllInSameCompSolid = false;
1626             break;
1627           }
1628         }
1629       }
1630     }
1631   }
1632
1633   anIt++;
1634
1635   if (anObjectsNb + aToolsNb < 2) {
1636     theError = "Not enough arguments for Fuse operation.";
1637     return false;
1638   } else if (isAllInSameCompSolid) {
1639     theError = "Operations only between sub-shapes of the same shape not allowed.";
1640     return false;
1641   }
1642
1643   return true;
1644 }
1645
1646 //=================================================================================================
1647 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isNotObligatory(
1648   std::string theFeature,
1649   std::string theAttribute)
1650 {
1651   if (theAttribute == "main_objects" || theAttribute == "tool_objects") {
1652     return true;
1653   }
1654
1655   return false;
1656 }
1657
1658 //==================================================================================================
1659 bool FeaturesPlugin_ValidatorBooleanCommonSelection::isValid(
1660   const AttributePtr& theAttribute,
1661   const std::list<std::string>& theArguments,
1662   Events_InfoMessage& theError) const
1663 {
1664   AttributeSelectionListPtr anAttrSelectionList =
1665     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1666   if (!anAttrSelectionList.get()) {
1667     theError =
1668       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1669     return false;
1670   }
1671
1672   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1673     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1674     if (!anAttrSelection.get()) {
1675       theError = "Error: Empty attribute selection.";
1676       return false;
1677     }
1678     ResultPtr aContext = anAttrSelection->context();
1679     if (!aContext.get() && !anAttrSelection->contextFeature().get()) {
1680       theError = "Error: Empty selection context.";
1681       return false;
1682     }
1683     ResultConstructionPtr aResultConstruction =
1684       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1685     if (aResultConstruction.get()) {
1686       if (theAttribute->id() != FeaturesPlugin_BooleanCommon::TOOL_LIST_ID()) {
1687         theError = "Error: Result construction not allowed for selection.";
1688         return false;
1689       }
1690     }
1691     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1692     GeomShapePtr aContextShape;
1693     if (aContext.get()) {
1694       aContextShape = aContext->shape();
1695     }
1696     if (!aShape.get()) {
1697       aShape = aContextShape;
1698     }
1699     if (!aShape.get()) {
1700       theError = "Error: Empty shape.";
1701       return false;
1702     }
1703     if (aContextShape.get() && !aShape->isEqual(aContextShape)) {
1704       theError = "Error: Local selection not allowed.";
1705       return false;
1706     }
1707
1708     if (aResultConstruction.get() && aShape->shapeType() != GeomAPI_Shape::FACE) {
1709       theError = "Error: Result construction should be plane.";
1710       return false;
1711     }
1712   }
1713
1714   return true;
1715 }
1716
1717 //=================================================================================================
1718 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
1719   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1720   const std::list<std::string>& theArguments,
1721   Events_InfoMessage& theError) const
1722 {
1723   if (theArguments.size() != 2) {
1724     theError = "Wrong number of arguments (expected 2).";
1725     return false;
1726   }
1727
1728   std::shared_ptr<FeaturesPlugin_BooleanCommon> aFeature =
1729     std::dynamic_pointer_cast<FeaturesPlugin_BooleanCommon>(theFeature);
1730
1731   int anObjectsNb = 0, aToolsNb = 0;
1732
1733   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1734
1735   bool isAllInSameCompSolid = true;
1736   ResultBodyPtr aCompSolid;
1737
1738   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1739   if (anAttrSelList) {
1740     anObjectsNb = anAttrSelList->size();
1741   }
1742
1743   bool isSimpleMode = aFeature->string(FeaturesPlugin_BooleanCommon::CREATION_METHOD())->value()
1744                       == FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE();
1745
1746   if (!isSimpleMode) {
1747     anAttrSelList = theFeature->selectionList(*anIt);
1748     if (anAttrSelList) {
1749       aToolsNb = anAttrSelList->size();
1750     }
1751   }
1752
1753   if ((isSimpleMode && anObjectsNb < 2)
1754       || (!isSimpleMode && (anObjectsNb == 0 || aToolsNb == 0))) {
1755     theError = "Not enough arguments for Fuse operation.";
1756     return false;
1757   }
1758   return true;
1759 }
1760
1761 //=================================================================================================
1762 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
1763   std::string theFeature,
1764   std::string theAttribute)
1765 {
1766   return false;
1767 }