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