Salome HOME
Replace error construction with + with using %1 placeholders
[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 not support attribute type '%1'\nOnly '%2' is supported.";
36     Events_InfoMessage("BuildPlugin_Validators", aMsg).
37       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
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                                                Events_InfoMessage& theError) const
113 {
114   // Get attribute.
115   if(theArguments.size() != 1) {
116     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForWire should be used only with 1 parameter (ID of base objects list).";
117     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
118     return false;
119   }
120   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
121   if(!aSelectionList.get()) {
122     theError = "Empty attribute \"%1\".";
123     theError.arg(theArguments.front());
124     return false;
125   }
126
127
128   // Collect base shapes.
129   ListOfShape aListOfShapes;
130   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
131     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
132     GeomShapePtr aShape = aSelection->value();
133     if(!aShape.get()) {
134       aShape = aSelection->context()->shape();
135     }
136     aListOfShapes.push_back(aShape);
137   }
138
139   // Create wire.
140   GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes);
141   if(!aWire.get()) {
142     theError = "Result wire empty. Probably it has disconnected edges or non-manifold.";
143     return false;
144   }
145
146   return true;
147 }
148
149 //=================================================================================================
150 bool BuildPlugin_ValidatorBaseForWire::isNotObligatory(std::string theFeature, std::string theAttribute)
151 {
152   return false;
153 }
154
155 //=================================================================================================
156 bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
157                                                const std::list<std::string>& theArguments,
158                                                Events_InfoMessage& theError) const
159 {
160   // Get attribute.
161   if(theArguments.size() != 1) {
162     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForFace should be used only with "
163       "1 parameter (ID of base objects list).";
164     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
165     return false;
166   }
167   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
168   if(!aSelectionList.get()) {
169     theError = "Empty attribute \"%1\".";
170     theError.arg(theArguments.front());
171     return false;
172   }
173
174   // Collect base shapes.
175   ListOfShape anEdges;
176   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
177     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
178     GeomShapePtr aShape = aSelection->value();
179     if(!aShape.get()) {
180       aShape = aSelection->context()->shape();
181     }
182     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
183       GeomShapePtr anEdge = anExp.current();
184       anEdges.push_back(anEdge);
185     }
186   }
187
188   // Check that edges does not have intersections.
189   if(anEdges.size() > 1) {
190     GeomAlgoAPI_PaveFiller aPaveFiller(anEdges, false);
191     if(!aPaveFiller.isDone()) {
192       theError = "Error while checking if edges intersects.";
193       return false;
194     }
195     GeomShapePtr aSectedEdges = aPaveFiller.shape();
196
197     int anEdgesNum = 0;
198     for(GeomAPI_ShapeExplorer anExp(aSectedEdges, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
199       anEdgesNum++;
200     }
201     if(anEdgesNum != anEdges.size()) {
202       theError = "Selected objects have intersections.";
203       return false;
204     }
205   }
206
207   // Check that they are planar.
208   std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
209   if(!aPln.get()) {
210     theError = "Selected objects are not planar.";
211     return false;
212   }
213
214   // Check that selected objects have closed contours.
215   ListOfShape aFaces;
216   GeomAlgoAPI_SketchBuilder::createFaces(aPln->location(), aPln->xDirection(), aPln->direction(), anEdges, aFaces);
217   if(aFaces.empty()) {
218     theError = "Selected objects does not have closed contours.";
219     return false;
220   }
221
222   return true;
223 }
224
225 //=================================================================================================
226 bool BuildPlugin_ValidatorBaseForFace::isNotObligatory(std::string theFeature, std::string theAttribute)
227 {
228   return false;
229 }
230
231 //=================================================================================================
232 bool BuildPlugin_ValidatorSubShapesSelection::isValid(const AttributePtr& theAttribute,
233                                                       const std::list<std::string>& theArguments,
234                                                       Events_InfoMessage& theError) const
235 {
236   if(theArguments.size() != 1) {
237     std::string aMsg = "Error: BuildPlugin_ValidatorSubShapesSelection should be used only with "
238       "1 parameter(Sketch feature id).";
239     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
240     return false;
241   }
242
243   // Get base objects list.
244   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
245     std::string aMsg = "Error: BuildPlugin_ValidatorSubShapesSelection does not support attribute type \""
246       "%1\"\n Only \"%2\" supported.";
247     Events_InfoMessage("BuildPlugin_Validators", aMsg).
248       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
249     return false;
250   }
251   AttributeSelectionListPtr aSelectionList =
252     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
253   if(!aSelectionList.get()) {
254     theError = "Could not get selection list.";
255     return false;
256   }
257
258   // Get base shape.
259   const std::string aBaseShapeId = "base_shape";
260   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
261   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeId);
262
263   if(!aShapeAttrSelection.get()) {
264     theError = "Base shape is empty.";
265     return false;
266   }
267
268   ResultPtr aBaseContext = aShapeAttrSelection->context();
269
270   GeomShapePtr aBaseShape  = aShapeAttrSelection->value();
271   if(!aBaseShape.get()) {
272     theError = "Base shape is empty.";
273     return false;
274   }
275
276   GeomAlgoAPI_ShapeBuilder aBuilder;
277   aBuilder.removeInternal(aBaseShape);
278   aBaseShape = aBuilder.shape();
279
280   // If selected shape is wire allow to select only vertices. If face - allow vertices and edges.
281   std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
282   switch(aBaseShape->shapeType()) {
283     case GeomAPI_Shape::FACE: anAllowedTypes.insert(GeomAPI_Shape::EDGE);
284     case GeomAPI_Shape::WIRE: anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
285     default: break;
286   }
287
288   // Check selected shapes.
289   GeomValidators_FeatureKind aFeatureKindValidator;
290   std::list<std::string> anArguments;
291   anArguments.push_back(theArguments.front());
292   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
293     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
294     if(!aSelectionAttrInList.get()) {
295       theError = "Empty attribute in list.";
296       return false;
297     }
298
299     // If context of selection same skip.
300     if(aBaseContext == aSelectionAttrInList->context()) {
301       continue;
302     }
303
304     // Check that it is a selection on Sketch.
305     if(!aFeatureKindValidator.isValid(aSelectionAttrInList, anArguments, theError)) {
306       return false;
307     }
308
309     // Check shape type.
310     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
311     if(!aShapeInList.get()) {
312       aShapeInList = aSelectionAttrInList->context()->shape();
313     }
314     if(anAllowedTypes.find(aShapeInList->shapeType()) == anAllowedTypes.cend()) {
315       theError = "Selected shape has unacceptable type.";
316       return false;
317     }
318
319     // Check that shape inside wire or face.
320     if(!GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aShapeInList, aBaseShape)) {
321       theError = "Selected shape is not inside base face.";
322       return false;
323     }
324   }
325
326   return true;
327 }