Salome HOME
b451667acad83e8d703d5be7c7433596a1fcfc6a
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        FeaturesPlugin_Validators.cpp
4 // Created:     22 March 2016
5 // Author:      Dmitry Bobylev
6
7 #include "FeaturesPlugin_Validators.h"
8
9 #include <ModelAPI_Attribute.h>
10 #include <ModelAPI_AttributeInteger.h>
11 #include <ModelAPI_AttributeSelectionList.h>
12 #include <ModelAPI_AttributeString.h>
13 #include <ModelAPI_AttributeReference.h>
14 #include <ModelAPI_Feature.h>
15 #include <ModelAPI_ResultConstruction.h>
16
17 #include <Events_Error.h>
18
19 #include <GeomValidators_BodyShapes.h>
20 #include <GeomValidators_FeatureKind.h>
21 #include <GeomValidators_ShapeType.h>
22
23 #include <GeomAPI_DataMapOfShapeShape.h>
24 #include <GeomAPI_PlanarEdges.h>
25 #include <GeomAPI_ShapeExplorer.h>
26 #include <GeomAlgoAPI_WireBuilder.h>
27
28 //==================================================================================================
29 bool FeaturesPlugin_ValidatorPipeLocations::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
30                                                     const std::list<std::string>& theArguments,
31                                                     std::string& theError) const
32 {
33   static const std::string aCreationMethodID = "creation_method";
34   static const std::string aBaseObjectsID = "base_objects";
35   static const std::string aLocationsID = "locations_objects";
36
37   if(theFeature->getKind() != "Pipe") {
38     theError = "Feature \"" + theFeature->getKind() + "\" does not supported by this validator.";
39     return false;
40   }
41
42   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
43   if(!aCreationMethodAttr.get()) {
44     theError = "Could not get \"" + aCreationMethodID + "\" attribute.";
45     return false;
46   }
47
48   if(aCreationMethodAttr->value() != "locations") {
49     return true;
50   }
51
52   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
53   if(!aBaseObjectsSelectionList.get()) {
54     theError = "Could not get \"" + aBaseObjectsID + "\" attribute.";
55     return false;
56   }
57
58   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
59   if(!aLocationsSelectionList.get()) {
60     theError = "Could not get \"" + aBaseObjectsID + "\" attribute.";
61     return false;
62   }
63
64   if(aLocationsSelectionList->size() > 0 && aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
65     theError = "Number of locations should be the same as base objects.";
66     return false;
67   }
68
69   return true;
70 }
71
72 //==================================================================================================
73 bool FeaturesPlugin_ValidatorPipeLocations::isNotObligatory(std::string theFeature, std::string theAttribute)
74 {
75   return false;
76 }
77
78 //==================================================================================================
79 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
80                                                         const std::list<std::string>& theArguments,
81                                                         std::string& theError) const
82 {
83   if(theArguments.empty()) {
84     theError = "Validator parameters is empty.";
85     return false;
86   }
87
88   // Checking attribute.
89   if(!isValidAttribute(theAttribute, theArguments, theError)) {
90     if(theError.empty()) {
91       theError = "Attribute contains unacceptable shape.";
92     }
93     return false;
94   }
95
96   std::set<ResultConstructionPtr> aSelectedSketches;
97   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
98   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
99   std::string anAttributeType = theAttribute->attributeType();
100   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
101     AttributeSelectionListPtr aListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
102     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
103       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
104       ResultConstructionPtr aContext = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSelectionAttr->context());
105       if(!aContext.get()) {
106         // It is not a result construction, continue.
107         continue;
108       }
109
110       GeomShapePtr aShape = aSelectionAttr->value();
111       GeomShapePtr aContextShape = aContext->shape();
112       if(!aShape.get()) {
113         // Whole sketch selected.
114         if(aSelectedSketchesFromObjects.find(aContext) != aSelectedSketchesFromObjects.cend()) {
115           theError = "Object from this sketch is already selected. Sketch is not allowed for selection.";
116           return false;
117         }
118
119         aSelectedSketches.insert(aContext);
120       } else {
121         // Object from sketch selected.
122         if(aSelectedSketches.find(aContext) != aSelectedSketches.cend()) {
123           theError = "Whole sketch with this object is already selected. Don't allow to select this object.";
124           return false;
125         }
126
127         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
128           GeomShapePtr aWire = anExp.current();
129           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
130             theError = "Wire with wrong orientation selected.";
131             return false;
132           }
133
134           if(aSelectedWiresFromObjects.isBound(aWire)) {
135             theError = "Objects with such wire already selected. Don't allow to select this object.";
136             return false;
137           }
138
139           aSelectedWiresFromObjects.bind(aWire, aWire);
140           aSelectedSketchesFromObjects.insert(aContext);
141         }
142       }
143     }
144   }
145
146   return true;
147 }
148
149 //==================================================================================================
150 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
151                                                                  const std::list<std::string>& theArguments,
152                                                                  std::string& theError) const
153 {
154   if(!theAttribute.get()) {
155     theError = "Empty attribute.";
156     return false;
157   }
158
159   std::string anAttributeType = theAttribute->attributeType();
160   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
161     AttributeSelectionListPtr aListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
162     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
163       // If at least one attribute is invalid, the result is false.
164       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
165         return false;
166       }
167     }
168   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
169     // Getting context.
170     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
171     ResultPtr aContext = anAttr->context();
172     if(!aContext.get()) {
173       theError = "Attribute have empty context.";
174       return false;
175     }
176
177     GeomShapePtr aShape = anAttr->value();
178     GeomShapePtr aContextShape = aContext->shape();
179     if(!aShape.get()) {
180       aShape = aContextShape;
181     }
182     if(!aShape.get()) {
183       theError = "Empty shape selected";
184       return false;
185     }
186
187     ResultConstructionPtr aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
188     if(aConstruction.get()) {
189       // Construciotn selected. Check that is is not infinite.
190       if(aConstruction->isInfinite()) {
191         theError = "Infinite constructions is not allowed as base.";
192         return false;
193       }
194
195       if(aShape->isEqual(aContextShape)) {
196         // Whole construction selected. Check that it have faces.
197         if(aConstruction->facesNum() > 0) {
198           return true;
199         }
200       } else {
201         // Shape on construction selected. Check that it is a face or wire.
202         if(aShape->shapeType() == GeomAPI_Shape::WIRE || aShape->shapeType() == GeomAPI_Shape::FACE) {
203           return true;
204         }
205       }
206
207       return false;
208     }
209
210     if(!aShape->isEqual(aContextShape)) {
211       // Local selection on body does not allowed.
212       theError = "Selected shape is in the local selection. Only global selection is allowed.";
213       return false;
214     }
215
216     // Check that object is a shape with allowed type.
217     GeomValidators_ShapeType aShapeTypeValidator;
218     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
219       theError = "Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, "
220                  "whole sketch(if it has at least one face), and whole objects with shape types: ";
221       std::list<std::string>::const_iterator anIt = theArguments.cbegin();
222       theError += *anIt;
223       for(++anIt; anIt != theArguments.cend(); ++anIt) {
224         theError += ", " + *anIt;
225       }
226       return false;
227     }
228
229   } else {
230     theError = "Following attribute does not supported: " + anAttributeType + ".";
231     return false;
232   }
233
234   return true;
235 }
236
237 //==================================================================================================
238 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
239                                                         const std::list<std::string>& theArguments,
240                                                         std::string& theError) const
241 {
242   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
243     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
244     return false;
245   }
246   if (theArguments.size() != 2) {
247     theError = "Wrong parameters in XML definition for " + theAttribute->attributeType() + " type";
248     return false;
249   }
250   // first argument is for the base attribute, second - for skipping feature kind
251   std::list<std::string>::const_iterator anIt = theArguments.begin();
252   std::string aBaseAttributeId = *anIt;
253   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
254   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
255   if (!aBaseAttribute.get()) {
256     theError = "Wrong parameters in XML definition for " + theAttribute->attributeType() + " type";
257     return false;
258   }
259   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
260     // this validator is not necessary anymore
261     return true;
262
263   anIt++;
264   std::string aFeatureAttributeKind = *anIt;
265   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
266   // check whether the selection is on the sketch
267   std::list<std::string> anArguments;
268   anArguments.push_back(aFeatureAttributeKind);
269
270   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
271   bool aPlanarFace = false;
272   // check if selection has Face selected
273   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
274   anArguments.clear();
275   anArguments.push_back("face");
276   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
277
278   bool aValid = !aFeatureKind && aPlanarFace;
279   return aValid;
280 }
281
282 //==================================================================================================
283 bool FeaturesPlugin_ValidatorCanBeEmpty::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
284                                                  const std::list<std::string>& theArguments,
285                                                  std::string& theError) const
286 {
287   if(theArguments.size() != 2) {
288     theError = "Validator should be used with 2 parameters for extrusion.";
289     return false;
290   }
291
292   std::list<std::string>::const_iterator anArgsIt = theArguments.begin(), aLast = theArguments.end();
293
294   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
295   ++anArgsIt;
296
297   if(isShapesCanBeEmpty(aCheckAttribute, theError)) {
298     return true;
299   }
300
301   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
302   if(!aSelAttr.get()) {
303     theError = "Could not get selection attribute \"" + *anArgsIt + "\".";
304     return false;
305   }
306
307   GeomShapePtr aShape = aSelAttr->value();
308   if(!aShape.get()) {
309     ResultPtr aContext = aSelAttr->context();
310     if(!aContext.get()) {
311       theError = "Base objects list contains vertex or edge, so attribute \"" + *anArgsIt
312                + "\" can not be used with default value. Select direction for extrusion.";
313       return false;
314     }
315
316     aShape = aContext->shape();
317   }
318
319   if(!aShape.get()) {
320     theError = "Base objects list contains vertex or edge, so attribute \"" + *anArgsIt
321               + "\" can not be used with default value. Select direction for extrusion.";
322     return false;
323   }
324
325   return true;
326 }
327
328 //==================================================================================================
329 bool FeaturesPlugin_ValidatorCanBeEmpty::isNotObligatory(std::string theFeature, std::string theAttribute)
330 {
331   return false;
332 }
333
334 //==================================================================================================
335 bool FeaturesPlugin_ValidatorCanBeEmpty::isShapesCanBeEmpty(const AttributePtr& theAttribute,
336                                                             std::string& theError) const
337 {
338   if(!theAttribute.get()) {
339     return true;
340   }
341
342   std::string anAttributeType = theAttribute->attributeType();
343   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
344     AttributeSelectionListPtr aListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
345     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
346       // If at least one attribute is invalid, the result is false.
347       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
348         return false;
349       }
350     }
351   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
352     // Getting context.
353     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
354     ResultPtr aContext = anAttr->context();
355     if(!aContext.get()) {
356       return false;
357     }
358
359     GeomShapePtr aShape = anAttr->value();
360     GeomShapePtr aContextShape = aContext->shape();
361     if(!aShape.get()) {
362       aShape = aContextShape;
363     }
364     if(!aShape.get()) {
365       return false;
366     }
367
368     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
369        aShape->shapeType() == GeomAPI_Shape::EDGE ||
370        !aShape->isPlanar()) {
371       return false;
372     }
373   } else {
374     return false;
375   }
376
377   return true;
378 }
379
380 //==================================================================================================
381 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
382                                                        const std::list<std::string>& theArguments,
383                                                        std::string& theError) const
384 {
385   AttributeSelectionListPtr anAttrSelectionList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
386   if(!anAttrSelectionList.get()) {
387     theError = "Error: this validator can only work with selection list attributes in Boolean feature.";
388     return false;
389   }
390   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
391   int anOperationType = aFeature->integer("bool_type")->value();
392
393   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
394     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
395     if(!anAttrSelection.get()) {
396       theError = "Error: empty attribute selection.";
397       return false;
398     }
399     ResultPtr aContext = anAttrSelection->context();
400     if(!aContext.get()) {
401       theError = "Error: empty selection context.";
402       return false;
403     }
404     ResultConstructionPtr aResultConstruction =
405       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
406     if(aResultConstruction.get()) {
407       theError = "Error: Result construction not allowed for selection.";
408       return false;
409     }
410     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
411     if(!aShape.get()) {
412       aShape = aContext->shape();
413     }
414     if(!aShape.get()) {
415       theError = "Error: empty shape.";
416       return false;
417     }
418     int aShapeType = aShape->shapeType();
419     if(anOperationType == 1) {
420       // Fuse operation. Allow to select edges, faces and solids.
421       if(aShapeType != GeomAPI_Shape::EDGE &&
422          aShapeType != GeomAPI_Shape::FACE &&
423          aShapeType != GeomAPI_Shape::SOLID &&
424          aShapeType != GeomAPI_Shape::COMPSOLID &&
425          aShapeType != GeomAPI_Shape::COMPOUND) {
426         theError = "Error: selected shape has the wrong type.";
427         return false;
428       }
429     } else {
430       if(aShapeType != GeomAPI_Shape::SOLID &&
431          aShapeType != GeomAPI_Shape::COMPSOLID &&
432          aShapeType != GeomAPI_Shape::COMPOUND) {
433         theError = "Error: selected shape has the wrong type.";
434         return false;
435       }
436     }
437   }
438
439   return true;
440 }
441
442 //==================================================================================================
443 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
444                                                          const std::list<std::string>& theArguments,
445                                                          std::string& theError) const
446 {
447   std::string anAttributeType = theAttribute->attributeType();
448   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
449     AttributeSelectionListPtr aSelectionListAttr =
450         std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
451
452     for(int anIndex = 0; anIndex < aSelectionListAttr->size(); ++anIndex) {
453       AttributeSelectionPtr aSelectAttr = aSelectionListAttr->value(anIndex);
454
455       GeomValidators_BodyShapes aBodyValidator;
456       if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
457         continue;
458       }
459
460       GeomValidators_FeatureKind aFeatureKindValidator;
461       if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
462         continue;
463       }
464
465       theError = "Only body shapes and construction planes are allowed for selection.";
466       return false;
467     }
468   } else {
469     theError = "This validator supports only " + ModelAPI_AttributeSelectionList::typeId() + " attribute type.";
470     return false;
471   }
472
473   return true;
474 }