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