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