Salome HOME
Better fix for the issue #1750
[modules/shaper.git] / src / BuildPlugin / BuildPlugin_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        BuildPlugin_Validators.cpp
4 // Created:     22 March 2016
5 // Author:      Dmitry Bobylev
6
7 #include "BuildPlugin_Validators.h"
8
9 #include <ModelAPI_AttributeSelectionList.h>
10 #include <ModelAPI_ResultConstruction.h>
11
12 #include <GeomAPI_PlanarEdges.h>
13 #include <GeomAPI_Pln.h>
14 #include <GeomAPI_ShapeExplorer.h>
15
16 #include <GeomAlgoAPI_CompoundBuilder.h>
17 #include <GeomAlgoAPI_PaveFiller.h>
18 #include <GeomAlgoAPI_ShapeBuilder.h>
19 #include <GeomAlgoAPI_ShapeTools.h>
20 #include <GeomAlgoAPI_SketchBuilder.h>
21 #include <GeomAlgoAPI_WireBuilder.h>
22
23 #include <GeomValidators_FeatureKind.h>
24 #include <GeomValidators_ShapeType.h>
25
26 #include <Events_InfoMessage.h>
27
28 //=================================================================================================
29 bool BuildPlugin_ValidatorBaseForBuild::isValid(const AttributePtr& theAttribute,
30                                                 const std::list<std::string>& theArguments,
31                                                 Events_InfoMessage& theError) const
32 {
33   // Get base objects list.
34   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
35     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForBuild does "
36                        "not support attribute type '%1'\nOnly '%2' is supported.";
37     Events_InfoMessage("BuildPlugin_Validators", aMsg).
38       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
39     return false;
40   }
41   AttributeSelectionListPtr aSelectionList =
42     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
43   if(!aSelectionList.get()) {
44     theError = "Could not get selection list.";
45     return false;
46   }
47   if(aSelectionList->size() == 0) {
48     theError = "Empty selection list.";
49     return false;
50   }
51
52   // Collect base shapes.
53   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
54     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
55     if(!aSelection.get()) {
56       theError = "Could not get selection.";
57       return false;
58     }
59     ResultPtr aContext = aSelection->context();
60     if(!aContext.get()) {
61       theError = "Attribute have empty context.";
62       return false;
63     }
64
65     GeomShapePtr aShape = aSelection->value();
66     GeomShapePtr aContextShape = aContext->shape();
67     if(!aShape.get()) {
68       aShape = aContextShape;
69     }
70     if(!aShape.get()) {
71       theError = "Empty shape selected.";
72       return false;
73     }
74
75     // Check that shapes has acceptable type.
76     GeomValidators_ShapeType aValidatorShapeType;
77     if(!aValidatorShapeType.isValid(aSelection, theArguments, theError)) {
78       return false;
79     }
80
81     // Check that it is shape on sketch.
82     ResultConstructionPtr aConstruction =
83       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
84     if(aConstruction.get()) {
85       if(aConstruction->isInfinite()) {
86         theError = "Inifinte objects not acceptable.";
87         return false;
88       }
89
90       std::shared_ptr<GeomAPI_PlanarEdges> anEdges =
91         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aContextShape);
92       if(anEdges.get()) {
93         if(aShape->isEqual(aContextShape)) {
94           // It is whole sketch.
95           return false;
96         }
97
98         continue;
99       }
100     }
101
102     if(!aShape->isEqual(aContextShape)) {
103       // Local selection on body does not allowed.
104       theError = "Selected shape is in the local selection. Only global selection is allowed.";
105       return false;
106     }
107   }
108
109   return true;
110 }
111
112 //=================================================================================================
113 bool BuildPlugin_ValidatorBaseForWire::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
114                                                const std::list<std::string>& theArguments,
115                                                Events_InfoMessage& theError) const
116 {
117   // Get attribute.
118   if(theArguments.size() != 1) {
119     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForWire should be used only "
120                        "with 1 parameter (ID of base objects list).";
121     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
122     return false;
123   }
124   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
125   if(!aSelectionList.get()) {
126     theError = "Empty attribute \"%1\".";
127     theError.arg(theArguments.front());
128     return false;
129   }
130
131
132   // Collect base shapes.
133   ListOfShape aListOfShapes;
134   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
135     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
136     GeomShapePtr aShape = aSelection->value();
137     if(!aShape.get()) {
138       if (aSelection->context().get())
139         aShape = aSelection->context()->shape();
140     }
141     if (aShape.get())
142       aListOfShapes.push_back(aShape);
143   }
144
145   // Create wire.
146   GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes);
147   if(!aWire.get()) {
148     theError = "Result wire empty. Probably it has disconnected edges or non-manifold.";
149     return false;
150   }
151
152   return true;
153 }
154
155 //=================================================================================================
156 bool BuildPlugin_ValidatorBaseForWire::isNotObligatory(std::string theFeature,
157                                                        std::string theAttribute)
158 {
159   return false;
160 }
161
162 //=================================================================================================
163 bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
164                                                const std::list<std::string>& theArguments,
165                                                Events_InfoMessage& theError) const
166 {
167   // Get attribute.
168   if(theArguments.size() != 1) {
169     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForFace should be used only with "
170       "1 parameter (ID of base objects list).";
171     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
172     return false;
173   }
174   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
175   if(!aSelectionList.get()) {
176     theError = "Empty attribute \"%1\".";
177     theError.arg(theArguments.front());
178     return false;
179   }
180
181   // Collect base shapes.
182   ListOfShape anEdges;
183   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
184     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
185     GeomShapePtr aShape = aSelection->value();
186     if(!aShape.get()) {
187       aShape = aSelection->context()->shape();
188     }
189     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
190       GeomShapePtr anEdge = anExp.current();
191       anEdges.push_back(anEdge);
192     }
193   }
194
195   // Check that edges does not have intersections.
196   if(anEdges.size() > 1) {
197     GeomAlgoAPI_PaveFiller aPaveFiller(anEdges, false);
198     if(!aPaveFiller.isDone()) {
199       theError = "Error while checking if edges intersects.";
200       return false;
201     }
202     GeomShapePtr aSectedEdges = aPaveFiller.shape();
203
204     int anEdgesNum = 0;
205     for(GeomAPI_ShapeExplorer
206         anExp(aSectedEdges, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
207       anEdgesNum++;
208     }
209     if(anEdgesNum != anEdges.size()) {
210       theError = "Selected objects have intersections.";
211       return false;
212     }
213   }
214
215   // Check that they are planar.
216   std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
217   if(!aPln.get()) {
218     theError = "Selected objects are not planar.";
219     return false;
220   }
221
222   // Check that selected objects have closed contours.
223   ListOfShape aFaces;
224   GeomAlgoAPI_SketchBuilder::createFaces(aPln->location(), aPln->xDirection(),
225                                          aPln->direction(), anEdges, aFaces);
226   if(aFaces.empty()) {
227     theError = "Selected objects does not have closed contours.";
228     return false;
229   }
230
231   return true;
232 }
233
234 //=================================================================================================
235 bool BuildPlugin_ValidatorBaseForFace::isNotObligatory(std::string theFeature,
236                                                        std::string theAttribute)
237 {
238   return false;
239 }
240
241 //=================================================================================================
242 bool BuildPlugin_ValidatorSubShapesSelection::isValid(const AttributePtr& theAttribute,
243                                                       const std::list<std::string>& theArguments,
244                                                       Events_InfoMessage& theError) const
245 {
246   if(theArguments.size() != 1) {
247     std::string aMsg = "Error: BuildPlugin_ValidatorSubShapesSelection should be used only with "
248       "1 parameter(Sketch feature id).";
249     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
250     return false;
251   }
252
253   // Get base objects list.
254   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
255     std::string aMsg =
256       "Error: BuildPlugin_ValidatorSubShapesSelection does not support attribute type \""
257       "%1\"\n Only \"%2\" supported.";
258     Events_InfoMessage("BuildPlugin_Validators", aMsg).
259       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
260     return false;
261   }
262   AttributeSelectionListPtr aSelectionList =
263     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
264   if(!aSelectionList.get()) {
265     theError = "Could not get selection list.";
266     return false;
267   }
268
269   // Get base shape.
270   const std::string aBaseShapeId = "base_shape";
271   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
272   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeId);
273
274   if(!aShapeAttrSelection.get()) {
275     theError = "Base shape is empty.";
276     return false;
277   }
278
279   ResultPtr aBaseContext = aShapeAttrSelection->context();
280
281   GeomShapePtr aBaseShape  = aShapeAttrSelection->value();
282   if(!aBaseShape.get()) {
283     theError = "Base shape is empty.";
284     return false;
285   }
286
287   GeomAlgoAPI_ShapeBuilder aBuilder;
288   aBuilder.removeInternal(aBaseShape);
289   aBaseShape = aBuilder.shape();
290
291   // If selected shape is wire allow to select only vertices. If face - allow vertices and edges.
292   std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
293   switch(aBaseShape->shapeType()) {
294     case GeomAPI_Shape::FACE: anAllowedTypes.insert(GeomAPI_Shape::EDGE);
295     case GeomAPI_Shape::WIRE: anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
296     default: break;
297   }
298
299   // Check selected shapes.
300   GeomValidators_FeatureKind aFeatureKindValidator;
301   std::list<std::string> anArguments;
302   anArguments.push_back(theArguments.front());
303   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
304     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
305     if(!aSelectionAttrInList.get()) {
306       theError = "Empty attribute in list.";
307       return false;
308     }
309
310     // If context of selection same skip.
311     if(aBaseContext == aSelectionAttrInList->context()) {
312       continue;
313     }
314
315     // Check that it is a selection on Sketch.
316     if(!aFeatureKindValidator.isValid(aSelectionAttrInList, anArguments, theError)) {
317       return false;
318     }
319
320     // Check shape type.
321     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
322     if(!aShapeInList.get()) {
323       aShapeInList = aSelectionAttrInList->context()->shape();
324     }
325     if(anAllowedTypes.find(aShapeInList->shapeType()) == anAllowedTypes.cend()) {
326       theError = "Selected shape has unacceptable type.";
327       return false;
328     }
329
330     // Check that shape inside wire or face.
331     if(!GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aShapeInList, aBaseShape)) {
332       theError = "Selected shape is not inside base face.";
333       return false;
334     }
335   }
336
337   return true;
338 }