Salome HOME
#2084 Unknown error when trim: Do not copyAttribute
[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   if(anEdges.empty()) {
196     theError = "Objects not selected.";
197     return false;
198   }
199
200   // Check that edges does not have intersections.
201   if(anEdges.size() > 1) {
202     GeomAlgoAPI_PaveFiller aPaveFiller(anEdges, false);
203     if(!aPaveFiller.isDone()) {
204       theError = "Error while checking if edges intersects.";
205       return false;
206     }
207     GeomShapePtr aSectedEdges = aPaveFiller.shape();
208
209     int anEdgesNum = 0;
210     for(GeomAPI_ShapeExplorer
211         anExp(aSectedEdges, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
212       anEdgesNum++;
213     }
214     if(anEdgesNum != anEdges.size()) {
215       theError = "Selected objects have intersections.";
216       return false;
217     }
218   }
219
220   // Check that they are planar.
221   std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
222   if(!aPln.get()) {
223     theError = "Selected object(s) should belong to only one plane.";
224     return false;
225   }
226
227   // Check that selected objects have closed contours.
228   ListOfShape aFaces;
229   GeomAlgoAPI_SketchBuilder::createFaces(aPln->location(), aPln->xDirection(),
230                                          aPln->direction(), anEdges, aFaces);
231   if(aFaces.empty()) {
232     theError = "Selected objects do not generate closed contour.";
233     return false;
234   }
235
236   return true;
237 }
238
239 //=================================================================================================
240 bool BuildPlugin_ValidatorBaseForFace::isNotObligatory(std::string theFeature,
241                                                        std::string theAttribute)
242 {
243   return false;
244 }
245
246 //=================================================================================================
247 bool BuildPlugin_ValidatorSubShapesSelection::isValid(const AttributePtr& theAttribute,
248                                                       const std::list<std::string>& theArguments,
249                                                       Events_InfoMessage& theError) const
250 {
251   if(theArguments.size() != 1) {
252     std::string aMsg = "Error: BuildPlugin_ValidatorSubShapesSelection should be used only with "
253       "1 parameter(Sketch feature id).";
254     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
255     return false;
256   }
257
258   // Get base objects list.
259   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
260     std::string aMsg =
261       "Error: BuildPlugin_ValidatorSubShapesSelection does not support attribute type \""
262       "%1\"\n Only \"%2\" supported.";
263     Events_InfoMessage("BuildPlugin_Validators", aMsg).
264       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
265     return false;
266   }
267   AttributeSelectionListPtr aSelectionList =
268     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
269   if(!aSelectionList.get()) {
270     theError = "Could not get selection list.";
271     return false;
272   }
273
274   // Get base shape.
275   const std::string aBaseShapeId = "base_shape";
276   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
277   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeId);
278
279   if(!aShapeAttrSelection.get()) {
280     theError = "Base shape is empty.";
281     return false;
282   }
283
284   ResultPtr aBaseContext = aShapeAttrSelection->context();
285
286   GeomShapePtr aBaseShape  = aShapeAttrSelection->value();
287   if(!aBaseShape.get()) {
288     theError = "Base shape is empty.";
289     return false;
290   }
291
292   GeomAlgoAPI_ShapeBuilder aBuilder;
293   aBuilder.removeInternal(aBaseShape);
294   aBaseShape = aBuilder.shape();
295
296   // If selected shape is wire allow to select only vertices. If face - allow vertices and edges.
297   std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
298   switch(aBaseShape->shapeType()) {
299     case GeomAPI_Shape::FACE: anAllowedTypes.insert(GeomAPI_Shape::EDGE);
300     case GeomAPI_Shape::WIRE: anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
301     default: break;
302   }
303
304   // Check selected shapes.
305   GeomValidators_FeatureKind aFeatureKindValidator;
306   std::list<std::string> anArguments;
307   anArguments.push_back(theArguments.front());
308   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
309     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
310     if(!aSelectionAttrInList.get()) {
311       theError = "Empty attribute in list.";
312       return false;
313     }
314
315     // If context of selection same skip.
316     if(aBaseContext == aSelectionAttrInList->context()) {
317       continue;
318     }
319
320     // Check that it is a selection on Sketch.
321     if(!aFeatureKindValidator.isValid(aSelectionAttrInList, anArguments, theError)) {
322       return false;
323     }
324
325     // Check shape type.
326     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
327     if(!aShapeInList.get()) {
328       aShapeInList = aSelectionAttrInList->context()->shape();
329     }
330     if(anAllowedTypes.find(aShapeInList->shapeType()) == anAllowedTypes.cend()) {
331       theError = "Selected shape has unacceptable type.";
332       return false;
333     }
334
335     // Check that shape inside wire or face.
336     if(!GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aShapeInList, aBaseShape)) {
337       theError = "Selected shape is not inside base face.";
338       return false;
339     }
340   }
341
342   return true;
343 }