Salome HOME
Issue #1463: Updated validator message
[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_AttributeSelectionList.h>
11 #include <ModelAPI_AttributeString.h>
12 #include <ModelAPI_ResultConstruction.h>
13 #include <ModelAPI_AttributeReference.h>
14
15 #include <Events_Error.h>
16
17 #include <GeomValidators_FeatureKind.h>
18 #include <GeomValidators_ShapeType.h>
19
20 #include <GeomAPI_PlanarEdges.h>
21 #include <GeomAlgoAPI_WireBuilder.h>
22
23 //=================================================================================================
24 bool FeaturesPlugin_ValidatorPipeLocations::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
25                                                     const std::list<std::string>& theArguments,
26                                                     std::string& theError) const
27 {
28   static const std::string aCreationMethodID = "creation_method";
29   static const std::string aBaseObjectsID = "base_objects";
30   static const std::string aLocationsID = "locations_objects";
31
32   if(theFeature->getKind() != "Pipe") {
33     theError = "Feature \"" + theFeature->getKind() + "\" does not supported by this validator.";
34     return false;
35   }
36
37   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
38   if(!aCreationMethodAttr.get()) {
39     theError = "Could not get \"" + aCreationMethodID + "\" attribute.";
40     return false;
41   }
42
43   if(aCreationMethodAttr->value() != "locations") {
44     return true;
45   }
46
47   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
48   if(!aBaseObjectsSelectionList.get()) {
49     theError = "Could not get \"" + aBaseObjectsID + "\" attribute.";
50     return false;
51   }
52
53   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
54   if(!aLocationsSelectionList.get()) {
55     theError = "Could not get \"" + aBaseObjectsID + "\" attribute.";
56     return false;
57   }
58
59   if(aLocationsSelectionList->size() > 0 && aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
60     theError = "Number of locations should be the same as base objects.";
61     return false;
62   }
63
64   return true;
65 }
66
67 //=================================================================================================
68 bool FeaturesPlugin_ValidatorPipeLocations::isNotObligatory(std::string theFeature, std::string theAttribute)
69 {
70   return false;
71 }
72
73 //=================================================================================================
74 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
75                                                         const std::list<std::string>& theArguments,
76                                                         std::string& theError) const
77 {
78   if(theArguments.empty()) {
79     theError = "Validator parameters is empty.";
80     return false;
81   }
82
83   // Checking attribute.
84   if(!isValidAttribute(theAttribute, theArguments, theError)) {
85     if(theError.empty()) {
86       theError = "Attribute contains unacceptable shape.";
87     }
88     return false;
89   }
90
91   return true;
92 }
93
94 //=================================================================================================
95 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
96                                                                  const std::list<std::string>& theArguments,
97                                                                  std::string& theError) const
98 {
99   if(!theAttribute.get()) {
100     theError = "Empty attribute.";
101     return false;
102   }
103
104   std::string anAttributeType = theAttribute->attributeType();
105   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
106     AttributeSelectionListPtr aListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
107     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
108       // If at least one attribute is invalid, the result is false.
109       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
110         return false;
111       }
112     }
113   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
114     // Getting context.
115     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
116     ResultPtr aContext = anAttr->context();
117     if(!aContext.get()) {
118       theError = "Attribute have empty context.";
119       return false;
120     }
121
122     GeomShapePtr aShape = anAttr->value();
123     GeomShapePtr aContextShape = aContext->shape();
124     if(!aShape.get()) {
125       aShape = aContextShape;
126     }
127     if(!aShape.get()) {
128       theError = "Empty shape selected";
129       return false;
130     }
131
132     ResultConstructionPtr aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
133     if(aConstruction.get()) {
134       // Construciotn selected. Check that is is not infinite.
135       if(aConstruction->isInfinite()) {
136         theError = "Infinite constructions is not allowed as base.";
137         return false;
138       }
139
140       if(aShape->isEqual(aContextShape)) {
141         // Whole construction selected. Check that it have faces.
142         if(aConstruction->facesNum() > 0) {
143           return true;
144         }
145       } else {
146         // Shape on construction selected. Check that it is a face or wire.
147         if(aShape->shapeType() == GeomAPI_Shape::WIRE || aShape->shapeType() == GeomAPI_Shape::FACE) {
148           return true;
149         }
150       }
151
152       return false;
153     }
154
155     if(!aShape->isEqual(aContextShape)) {
156       // Local selection on body does not allowed.
157       theError = "Selected shape is in the local selection. Only global selection is allowed.";
158       return false;
159     }
160
161     // Check that object is a shape with allowed type.
162     GeomValidators_ShapeType aShapeTypeValidator;
163     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
164       theError = "Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, \
165 whole sketch(if it has at least one face), and whole objects with shape types: ";
166       std::list<std::string>::const_iterator anIt = theArguments.cbegin();
167       theError += *anIt;
168       for(++anIt; anIt != theArguments.cend(); ++anIt) {
169         theError += ", " + *anIt;
170       }
171       return false;
172     }
173
174   } else {
175     theError = "Following attribute does not supported: " + anAttributeType + ".";
176     return false;
177   }
178
179   return true;
180 }
181
182 //=================================================================================================
183 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
184                                                         const std::list<std::string>& theArguments,
185                                                         std::string& theError) const
186 {
187   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
188     theError = "The attribute with the " + theAttribute->attributeType() + " type is not processed";
189     return false;
190   }
191   if (theArguments.size() != 2) {
192     theError = "Wrong parameters in XML definition for " + theAttribute->attributeType() + " type";
193     return false;
194   }
195   // first argument is for the base attribute, second - for skipping feature kind
196   std::list<std::string>::const_iterator anIt = theArguments.begin();
197   std::string aBaseAttributeId = *anIt;
198   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
199   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
200   if (!aBaseAttribute.get()) {
201     theError = "Wrong parameters in XML definition for " + theAttribute->attributeType() + " type";
202     return false;
203   }
204   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
205     // this validator is not necessary anymore
206     return true;
207
208   anIt++;
209   std::string aFeatureAttributeKind = *anIt;
210   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
211   // check whether the selection is on the sketch
212   std::list<std::string> anArguments;
213   anArguments.push_back(aFeatureAttributeKind);
214
215   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
216   bool aPlanarFace = false;
217   // check if selection has Face selected
218   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
219   anArguments.clear();
220   anArguments.push_back("face");
221   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
222
223   bool aValid = !aFeatureKind && aPlanarFace;
224   return aValid;
225 }
226
227 //=================================================================================================
228 bool FeaturesPlugin_ValidatorCanBeEmpty::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
229                                                  const std::list<std::string>& theArguments,
230                                                  std::string& theError) const
231 {
232   if(theArguments.size() != 2) {
233     theError = "Validator should be used with 2 parameters for extrusion.";
234     return false;
235   }
236
237   std::list<std::string>::const_iterator anArgsIt = theArguments.begin(), aLast = theArguments.end();
238
239   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
240   ++anArgsIt;
241
242   if(isShapesCanBeEmpty(aCheckAttribute, theError)) {
243     return true;
244   }
245
246   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
247   if(!aSelAttr.get()) {
248     theError = "Could not get selection attribute \"" + *anArgsIt + "\".";
249     return false;
250   }
251
252   GeomShapePtr aShape = aSelAttr->value();
253   if(!aShape.get()) {
254     ResultPtr aContext = aSelAttr->context();
255     if(!aContext.get()) {
256       theError = "Base objects list contains vertex or edge, so attribute \"" + *anArgsIt
257                + "\" can not be used with default value. Select direction for extrusion.";
258       return false;
259     }
260
261     aShape = aContext->shape();
262   }
263
264   if(!aShape.get()) {
265     theError = "Base objects list contains vertex or edge, so attribute \"" + *anArgsIt
266               + "\" can not be used with default value. Select direction for extrusion.";
267     return false;
268   }
269
270   return true;
271 }
272
273 //=================================================================================================
274 bool FeaturesPlugin_ValidatorCanBeEmpty::isNotObligatory(std::string theFeature, std::string theAttribute)
275 {
276   return false;
277 }
278
279 //=================================================================================================
280 bool FeaturesPlugin_ValidatorCanBeEmpty::isShapesCanBeEmpty(const AttributePtr& theAttribute,
281                                                             std::string& theError) const
282 {
283   if(!theAttribute.get()) {
284     return true;
285   }
286
287   std::string anAttributeType = theAttribute->attributeType();
288   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
289     AttributeSelectionListPtr aListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
290     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
291       // If at least one attribute is invalid, the result is false.
292       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
293         return false;
294       }
295     }
296   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
297     // Getting context.
298     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
299     ResultPtr aContext = anAttr->context();
300     if(!aContext.get()) {
301       return false;
302     }
303
304     GeomShapePtr aShape = anAttr->value();
305     GeomShapePtr aContextShape = aContext->shape();
306     if(!aShape.get()) {
307       aShape = aContextShape;
308     }
309     if(!aShape.get()) {
310       return false;
311     }
312
313     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
314        aShape->shapeType() == GeomAPI_Shape::EDGE ||
315        !aShape->isPlanar()) {
316       return false;
317     }
318   } else {
319     return false;
320   }
321
322   return true;
323 }
324
325 //=================================================================================================
326 bool FeaturesPlugin_ValidatorBaseForWire::isValid(const AttributePtr& theAttribute,
327                                                   const std::list<std::string>& theArguments,
328                                                   std::string& theError) const
329 {
330   // Get base objects list.
331   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
332     Events_Error::send("Validator does not support attribute type \"" + theAttribute->attributeType()
333       + "\"\n Only \"" + ModelAPI_AttributeSelectionList::typeId() + "\" supported.");
334     return false;
335   }
336   AttributeSelectionListPtr aSelectionList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
337   if(!aSelectionList.get()) {
338     theError = "Could not get selection list.";
339     return false;
340   }
341   if(aSelectionList->size() == 0) {
342     theError = "Empty selection list.";
343     return false;
344   }
345
346   // Collect base shapes.
347   ListOfShape aListOfShapes;
348   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
349     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
350     if(!aSelection.get()) {
351       theError = "Could not get selection.";
352       return false;
353     }
354     ResultPtr aContext = aSelection->context();
355     if(!aContext.get()) {
356       theError = "Attribute have empty context.";
357       return false;
358     }
359
360     GeomShapePtr aShape = aSelection->value();
361     GeomShapePtr aContextShape = aContext->shape();
362     if(!aShape.get()) {
363       aShape = aContextShape;
364     }
365     if(!aShape.get()) {
366       theError = "Empty shape selected.";
367       return false;
368     }
369
370     // Check that shape has acceptable type.
371     if(aShape->shapeType() != GeomAPI_Shape::EDGE && aShape->shapeType() != GeomAPI_Shape::WIRE) {
372       theError = "Selected shape has wrong type. Only edges and wires acceptable.";
373       return false;
374     }
375
376     // Check that it is edge on sketch.
377     ResultConstructionPtr aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
378     if(aConstruction.get()) {
379       if(aConstruction->isInfinite()) {
380         theError = "Inifinte objects not acceptable.";
381         return false;
382       }
383
384       std::shared_ptr<GeomAPI_PlanarEdges> anEdges = std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aContextShape);
385       if(!anEdges.get()) {
386         // It is not an edge on the sketch.
387         // Check that it is not local selection.
388         if(!aShape->isEqual(aContextShape)) {
389           // Local selection on body does not allowed.
390           theError = "Selected shape is in the local selection. Only global selection is allowed.";
391           return false;
392         }
393       }
394     }
395
396     aListOfShapes.push_back(aShape);
397   }
398
399   // Create wire.
400   GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes);
401   if(!aWire.get()) {
402     theError = "Result wire empty. Probably it has disconnected edges or non-manifold.";
403     return false;
404   }
405
406   return true;
407 }