Salome HOME
761fc6fa542c9acea0db48d56dfd66b820fe782e
[modules/shaper.git] / src / BuildPlugin / BuildPlugin_Validators.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "BuildPlugin_Validators.h"
21
22 #include <ModelAPI_AttributeSelectionList.h>
23 #include <ModelAPI_ResultConstruction.h>
24
25 #include <GeomAPI_PlanarEdges.h>
26 #include <GeomAPI_Pln.h>
27 #include <GeomAPI_ShapeExplorer.h>
28 #include <GeomAPI_ShapeIterator.h>
29
30 #include <GeomAlgoAPI_CompoundBuilder.h>
31 #include <GeomAlgoAPI_PaveFiller.h>
32 #include <GeomAlgoAPI_ShapeBuilder.h>
33 #include <GeomAlgoAPI_ShapeTools.h>
34 #include <GeomAlgoAPI_SketchBuilder.h>
35 #include <GeomAlgoAPI_WireBuilder.h>
36 #include <GeomAlgoAPI_MakeVolume.h>
37 #include <GeomAlgoAPI_Tools.h>
38
39 #include <GeomValidators_FeatureKind.h>
40 #include <GeomValidators_ShapeType.h>
41
42 #include <SketchPlugin_Sketch.h>
43
44 #include <Events_InfoMessage.h>
45
46 //=================================================================================================
47 bool BuildPlugin_ValidatorBaseForBuild::isValid(const AttributePtr& theAttribute,
48                                                 const std::list<std::string>& theArguments,
49                                                 Events_InfoMessage& theError) const
50 {
51   // Get base objects list.
52   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
53     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForBuild does "
54                        "not support attribute type '%1'\nOnly '%2' is supported.";
55     Events_InfoMessage("BuildPlugin_Validators", aMsg).
56       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
57     return false;
58   }
59   AttributeSelectionListPtr aSelectionList =
60     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
61   if(!aSelectionList.get()) {
62     theError = "Could not get selection list.";
63     return false;
64   }
65   if(aSelectionList->size() == 0) {
66     theError = "Empty selection list.";
67     return false;
68   }
69
70   // Collect base shapes.
71   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
72     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
73     if(!aSelection.get()) {
74       theError = "Could not get selection.";
75       return false;
76     }
77     ResultPtr aContext = aSelection->context();
78     if(!aContext.get()) {
79       theError = "Attribute have empty context.";
80       return false;
81     }
82
83     GeomShapePtr aShape = aSelection->value();
84     GeomShapePtr aContextShape = aContext->shape();
85     if(!aShape.get()) {
86       aShape = aContextShape;
87     }
88     if(!aShape.get()) {
89       theError = "Empty shape selected.";
90       return false;
91     }
92
93     // Check that shapes has acceptable type.
94     GeomValidators_ShapeType aValidatorShapeType;
95     if(!aValidatorShapeType.isValid(aSelection, theArguments, theError)) {
96       return false;
97     }
98
99     // Check that it is shape on sketch.
100     ResultConstructionPtr aConstruction =
101       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
102     if(aConstruction.get()) {
103       if(aConstruction->isInfinite()) {
104         theError = "Infinite objects not acceptable.";
105         return false;
106       }
107     }
108   }
109
110   return true;
111 }
112
113 //=================================================================================================
114 bool BuildPlugin_ValidatorBaseForWire::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
115                                                const std::list<std::string>& theArguments,
116                                                Events_InfoMessage& theError) const
117 {
118   // Get attribute.
119   if(theArguments.size() != 1) {
120     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForWire should be used only "
121                        "with 1 parameter (ID of base objects list).";
122     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
123     return false;
124   }
125   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
126   if(!aSelectionList.get()) {
127     theError = "Empty attribute \"%1\".";
128     theError.arg(theArguments.front());
129     return false;
130   }
131
132
133   // Collect base shapes.
134   ListOfShape aListOfShapes;
135   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
136     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
137     GeomShapePtr aShape = aSelection->value();
138     if(!aShape.get()) {
139       if (aSelection->context().get())
140         aShape = aSelection->context()->shape();
141     }
142     if (aShape.get())
143       aListOfShapes.push_back(aShape);
144   }
145
146   // Create wire.
147   GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes);
148   if(!aWire.get()) {
149     theError = "Result wire empty. Probably it has disconnected edges or non-manifold.";
150     return false;
151   }
152
153   return true;
154 }
155
156 //=================================================================================================
157 bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
158                                                const std::list<std::string>& theArguments,
159                                                Events_InfoMessage& theError) const
160 {
161   // Get attribute.
162   if(theArguments.size() != 1) {
163     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForFace should be used only with "
164       "1 parameter (ID of base objects list).";
165     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
166     return false;
167   }
168   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
169   if(!aSelectionList.get()) {
170     theError = "Empty attribute \"%1\".";
171     theError.arg(theArguments.front());
172     return false;
173   }
174
175   bool hasEdgesOrWires = false;
176   bool hasFaces = false;
177
178   // Collect base shapes.
179   ListOfShape anEdges;
180   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
181     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
182     GeomShapePtr aShape = aSelection->value();
183     if(!aShape.get()) {
184       if (!aSelection->context()) {
185         theError = "Objects are not selected.";
186         return false;
187       }
188       aShape = aSelection->context()->shape();
189     }
190     ResultConstructionPtr aSketchRes =
191         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSelection->context());
192
193     if (aShape->shapeType() == GeomAPI_Shape::FACE ||
194         (!aSelection->value() && aSketchRes && aSketchRes->facesNum() > 0)) {
195       // skip faces exploding
196       hasFaces = true;
197       continue;
198     }
199
200     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
201       hasEdgesOrWires = true;
202       GeomShapePtr anEdge = anExp.current();
203       anEdges.push_back(anEdge);
204     }
205   }
206
207   if (hasFaces && hasEdgesOrWires) {
208     theError = "Faces and edges/wires should be selected together.";
209     return false;
210   } else if (hasEdgesOrWires && anEdges.empty()) {
211     theError = "Objects are not selected.";
212     return false;
213   }
214
215   // Check that edges does not have intersections.
216   if(anEdges.size() > 1) {
217     GeomAlgoAPI_PaveFiller aPaveFiller(anEdges, false);
218     if(!aPaveFiller.isDone()) {
219       theError = "Error while checking if edges intersects.";
220       return false;
221     }
222     GeomShapePtr aSectedEdges = aPaveFiller.shape();
223
224     int anEdgesNum = 0;
225     for(GeomAPI_ShapeExplorer
226         anExp(aSectedEdges, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
227       anEdgesNum++;
228     }
229     if(anEdgesNum != anEdges.size()) {
230       theError = "Selected objects have intersections.";
231       return false;
232     }
233   }
234
235   if (!anEdges.empty()) {
236     // Check that they are planar.
237     std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
238     if(!aPln.get()) {
239       theError = "Selected object(s) should belong to only one plane.";
240       return false;
241     }
242
243     // Check that selected objects have closed contours.
244     GeomAlgoAPI_SketchBuilder aBuilder(aPln, anEdges);
245     const ListOfShape& aFaces = aBuilder.faces();
246     if(aFaces.empty()) {
247       theError = "Selected objects do not generate closed contour.";
248       return false;
249     }
250   }
251
252   return true;
253 }
254
255 //=================================================================================================
256 bool BuildPlugin_ValidatorBaseForSolids::isValid(
257   const std::shared_ptr<ModelAPI_Feature>& theFeature, const std::list<std::string>& theArguments,
258   Events_InfoMessage& theError) const
259 {
260   // Get base objects list.
261   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
262   if (!aSelectionList.get()) {
263     theError = "Could not get selection list.";
264     return false;
265   }
266   if (aSelectionList->size() == 0) {
267     theError = "Empty selection list.";
268     return false;
269   }
270
271   // Collect base shapes.
272   ListOfShape anOriginalShapes;
273   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
274     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
275     if (!aSelection->context().get()) {
276       theError = "Invalid selection.";
277       return false;
278     }
279     GeomShapePtr aShape = aSelection->value();
280     if (!aShape.get())
281       aShape = aSelection->context()->shape();
282     anOriginalShapes.push_back(aShape);
283   }
284
285   std::shared_ptr<GeomAlgoAPI_MakeVolume> anAlgorithm(
286     new GeomAlgoAPI_MakeVolume(anOriginalShapes, false));
287
288   std::string anErr;
289   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(anAlgorithm, "MakeVolume", anErr)) {
290     theError = anErr;
291     return false;
292   }
293
294   // set of allowed types of results
295   std::set<GeomAPI_Shape::ShapeType> aResultType;
296   std::string aType = theArguments.back();
297   if (aType == "solid")
298     aResultType.insert(GeomAPI_Shape::SOLID);
299   else if (aType == "compsolid") {
300     aResultType.insert(GeomAPI_Shape::COMPSOLID);
301     aResultType.insert(GeomAPI_Shape::SOLID);
302   }
303
304   GeomShapePtr aCompound = anAlgorithm->shape();
305   if (aCompound->shapeType() == GeomAPI_Shape::COMPOUND) {
306     GeomAPI_ShapeIterator anIt(aCompound);
307     GeomShapePtr aFoundSub;
308     for (; anIt.more() && !aFoundSub; anIt.next()) {
309       aFoundSub = anIt.current();
310       if (aResultType.count(aFoundSub->shapeType()) == 0) {
311         theError = "Unable to build a solid";
312         return false;
313       }
314     }
315     if (anIt.more() || !aFoundSub.get()) {
316       theError = "Unable to build a solid";
317       return false;
318     }
319   } else if (aResultType.count(aCompound->shapeType()) == 0) {
320     theError = "Unable to build a solid";
321     return false;
322   }
323   // check the internal faces presence
324   for(GeomAPI_ShapeExplorer aFaces(aCompound, GeomAPI_Shape::FACE); aFaces.more(); aFaces.next()) {
325     if (aFaces.current()->orientation() == GeomAPI_Shape::INTERNAL) {
326       theError = "Internal faces are not allowed in the resulting solid";
327       return false;
328     }
329   }
330
331   return true;
332 }
333
334
335 //=================================================================================================
336 bool BuildPlugin_ValidatorSubShapesSelection::isValid(const AttributePtr& theAttribute,
337                                                       const std::list<std::string>& theArguments,
338                                                       Events_InfoMessage& theError) const
339 {
340   if(theArguments.size() != 1) {
341     // LCOV_EXCL_START
342     std::string aMsg = "Error: BuildPlugin_ValidatorSubShapesSelection should be used only with "
343       "1 parameter(Sketch feature id).";
344     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
345     return false;
346     // LCOV_EXCL_STOP
347   }
348
349   // Get base objects list.
350   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
351     // LCOV_EXCL_START
352     std::string aMsg =
353       "Error: BuildPlugin_ValidatorSubShapesSelection does not support attribute type \""
354       "%1\"\n Only \"%2\" supported.";
355     Events_InfoMessage("BuildPlugin_Validators", aMsg).
356       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
357     return false;
358     // LCOV_EXCL_STOP
359   }
360   AttributeSelectionListPtr aSelectionList =
361     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
362   if(!aSelectionList.get()) {
363     theError = "Could not get selection list.";
364     return false;
365   }
366
367   // Get base shape.
368   const std::string aBaseShapeId = "base_shape";
369   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
370   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeId);
371
372   if(!aShapeAttrSelection.get()) {
373     theError = "Base shape is empty.";
374     return false;
375   }
376
377   ResultPtr aBaseContext = aShapeAttrSelection->context();
378
379   GeomShapePtr aBaseShape  = aShapeAttrSelection->value();
380   if(!aBaseShape.get()) {
381     theError = "Base shape is empty.";
382     return false;
383   }
384
385   GeomAlgoAPI_ShapeBuilder aBuilder;
386   aBuilder.removeInternal(aBaseShape);
387   aBaseShape = aBuilder.shape();
388
389   // If selected shape is wire allow to select only vertices. If face - allow vertices and edges.
390   std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
391   switch(aBaseShape->shapeType()) {
392     case GeomAPI_Shape::FACE: anAllowedTypes.insert(GeomAPI_Shape::EDGE);
393     case GeomAPI_Shape::WIRE: anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
394     default: break;
395   }
396
397   // Check selected shapes.
398   GeomValidators_FeatureKind aFeatureKindValidator;
399   std::list<std::string> anArguments;
400   anArguments.push_back(theArguments.front());
401   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
402     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
403     if(!aSelectionAttrInList.get()) {
404       theError = "Empty attribute in list.";
405       return false;
406     }
407
408     // If context of selection same skip.
409     if(aBaseContext == aSelectionAttrInList->context()) {
410       continue;
411     }
412
413     // Check that it is a selection on Sketch.
414     if(!aFeatureKindValidator.isValid(aSelectionAttrInList, anArguments, theError)) {
415       return false;
416     }
417
418     // Check shape type.
419     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
420     if(!aShapeInList.get()) {
421       aShapeInList = aSelectionAttrInList->context()->shape();
422     }
423     if(anAllowedTypes.find(aShapeInList->shapeType()) == anAllowedTypes.cend()) {
424       theError = "Selected shape has unacceptable type.";
425       return false;
426     }
427
428     // Check that shape inside wire or face.
429     if(!GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aShapeInList, aBaseShape)) {
430       theError = "Selected shape is not inside base face.";
431       return false;
432     }
433   }
434
435   return true;
436 }
437
438
439 //=================================================================================================
440 bool BuildPlugin_ValidatorFillingSelection::isValid(const AttributePtr& theAttribute,
441                                                       const std::list<std::string>& theArguments,
442                                                       Events_InfoMessage& theError) const
443 {
444   // Get base objects list.
445   if (theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
446     // LCOV_EXCL_START
447     std::string aMsg =
448       "Error: BuildPlugin_ValidatorFillingSelection does not support attribute type \""
449       "%1\"\n Only \"%2\" supported.";
450     Events_InfoMessage("BuildPlugin_Validators", aMsg).
451       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
452     return false;
453     // LCOV_EXCL_STOP
454   }
455   AttributeSelectionListPtr aSelectionList =
456     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
457   if (!aSelectionList.get()) {
458     theError = "Could not get selection list.";
459     return false;
460   }
461
462   //FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
463
464   // Check selected shapes.
465   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
466     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
467     if (!aSelectionAttrInList.get()) {
468       theError = "Empty attribute in list.";
469       return false;
470     }
471
472     // Check shape exists.
473     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
474     if (!aShapeInList.get()) {
475       theError = "Object has no shape";
476       return false;
477     }
478
479     // Check shape type.
480     GeomAPI_Shape::ShapeType aType = aShapeInList->shapeType();
481     if (aType != GeomAPI_Shape::EDGE && aType != GeomAPI_Shape::WIRE) {
482       theError = "Incorrect objects selected";
483       return false;
484     }
485   }
486
487   return true;
488 }
489
490
491 //=================================================================================================
492 bool BuildPlugin_ValidatorBaseForVertex::isValid(const AttributePtr& theAttribute,
493                                                  const std::list<std::string>& /*theArguments*/,
494                                                  Events_InfoMessage& theError) const
495 {
496   if (!theAttribute.get()) {
497     theError = "Error: empty selection.";
498     return false;
499   }
500
501   AttributeSelectionListPtr aSelectionList =
502     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
503   if (!aSelectionList.get()) {
504     theError = "Could not get selection list.";
505     return false;
506   }
507
508   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
509     AttributeSelectionPtr aSelectionAttr = aSelectionList->value(anIndex);
510     if (!aSelectionAttr.get()) {
511       theError = "Empty attribute in list.";
512       return false;
513     }
514
515     // Vertex?
516     bool isVertex = false;
517     GeomShapePtr aShape = aSelectionAttr->value();
518     ResultPtr aContext = aSelectionAttr->context();
519     if (!aShape.get() && aContext.get())
520       aShape = aContext->shape();
521     if (aShape.get())
522       isVertex = (aShape->shapeType() == GeomAPI_Shape::VERTEX);
523
524     if (!isVertex) {
525       // Sketch?
526       FeaturePtr aFeature = aSelectionAttr->contextFeature();
527       if (!aFeature.get()) {
528         GeomShapePtr aValue = aSelectionAttr->value();
529         // whole sketch is allowed only
530         if (aContext.get() && !aValue.get()) {
531           aFeature = ModelAPI_Feature::feature(aContext);
532         }
533       }
534
535       if (!aFeature.get()) {
536         theError = "Error: Incorrect selection.";
537         return false;
538       }
539
540       if (aFeature->getKind() != SketchPlugin_Sketch::ID()) {
541         theError = "Error: %1 shape is not allowed for selection.";
542         theError.arg(aFeature->getKind());
543         return false;
544       }
545     }
546   }
547
548   return true;
549 }