Salome HOME
Copyright update 2020
[modules/shaper.git] / src / BuildPlugin / BuildPlugin_Validators.cpp
1 // Copyright (C) 2014-2020  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   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
120   if(!aSelectionList.get()) {
121     theError = "Empty attribute \"%1\".";
122     theError.arg(theArguments.front());
123     return false;
124   }
125
126   GeomAPI_Shape::ShapeType aShapeType = GeomAPI_Shape::shapeTypeByStr(theArguments.back());
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     ResultPtr aContext = aSelection->context();
134     if (!aShape.get() && aContext.get())
135       aShape = aContext->shape();
136
137     bool isProper = aShape.get() &&
138         (aShape->shapeType() == GeomAPI_Shape::EDGE || aShape->shapeType() == aShapeType);
139
140     if (isProper)
141       aListOfShapes.push_back(aShape);
142     else {
143       // is it a sketch?
144       FeaturePtr aFeature = aSelection->contextFeature();
145       if (!aFeature.get()) {
146         GeomShapePtr aValue = aSelection->value();
147         // whole sketch is allowed only
148         if (aContext.get() && !aValue.get()) {
149           aFeature = ModelAPI_Feature::feature(aContext);
150         }
151       }
152
153       if (!aFeature.get()) {
154         theError = "Error: Incorrect selection.";
155         return false;
156       }
157
158       if (aFeature->getKind() != SketchPlugin_Sketch::ID()) {
159         theError = "Error: %1 shape is not allowed for selection.";
160         theError.arg(aFeature->getKind());
161         return false;
162       }
163     }
164   }
165
166   if (aShapeType == GeomAPI_Shape::WIRE) {
167     // Create wire.
168     GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes);
169     if (!aWire.get() && !aListOfShapes.empty()) {
170       theError = "Result wire empty. Probably it has disconnected edges or non-manifold.";
171       return false;
172     }
173   }
174
175   return true;
176 }
177
178 //=================================================================================================
179 bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
180                                                const std::list<std::string>& theArguments,
181                                                Events_InfoMessage& theError) const
182 {
183   // Get attribute.
184   if(theArguments.size() != 1) {
185     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForFace should be used only with "
186       "1 parameter (ID of base objects list).";
187     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
188     return false;
189   }
190   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
191   if(!aSelectionList.get()) {
192     theError = "Empty attribute \"%1\".";
193     theError.arg(theArguments.front());
194     return false;
195   }
196
197   bool hasEdgesOrWires = false;
198   bool hasFaces = false;
199
200   // Collect base shapes.
201   ListOfShape anEdges;
202   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
203     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
204     GeomShapePtr aShape = aSelection->value();
205     if(!aShape.get()) {
206       if (!aSelection->context()) {
207         theError = "Objects are not selected.";
208         return false;
209       }
210       aShape = aSelection->context()->shape();
211     }
212     ResultConstructionPtr aSketchRes =
213         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSelection->context());
214
215     if (aShape->shapeType() == GeomAPI_Shape::FACE ||
216         (!aSelection->value() && aSketchRes && aSketchRes->facesNum() > 0)) {
217       // skip faces exploding
218       hasFaces = true;
219       continue;
220     }
221
222     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
223       hasEdgesOrWires = true;
224       GeomShapePtr anEdge = anExp.current();
225       anEdges.push_back(anEdge);
226     }
227   }
228
229   if (hasFaces && hasEdgesOrWires) {
230     theError = "Faces and edges/wires should be selected together.";
231     return false;
232   } else if (hasEdgesOrWires && anEdges.empty()) {
233     theError = "Objects are not selected.";
234     return false;
235   }
236
237   // Check that edges does not have intersections.
238   if(anEdges.size() > 1) {
239     GeomAlgoAPI_PaveFiller aPaveFiller(anEdges, false);
240     if(!aPaveFiller.isDone()) {
241       theError = "Error while checking if edges intersects.";
242       return false;
243     }
244     GeomShapePtr aSectedEdges = aPaveFiller.shape();
245
246     int anEdgesNum = 0;
247     for(GeomAPI_ShapeExplorer
248         anExp(aSectedEdges, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
249       anEdgesNum++;
250     }
251     if(anEdgesNum != anEdges.size()) {
252       theError = "Selected objects have intersections.";
253       return false;
254     }
255   }
256
257   if (!anEdges.empty()) {
258     // Check that they are planar.
259     std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
260     if(!aPln.get()) {
261       theError = "Selected object(s) should belong to only one plane.";
262       return false;
263     }
264
265     // Check that selected objects have closed contours.
266     GeomAlgoAPI_SketchBuilder aBuilder(aPln, anEdges);
267     const ListOfShape& aFaces = aBuilder.faces();
268     if(aFaces.empty()) {
269       theError = "Selected objects do not generate closed contour.";
270       return false;
271     }
272   }
273
274   return true;
275 }
276
277 //=================================================================================================
278 bool BuildPlugin_ValidatorBaseForSolids::isValid(
279   const std::shared_ptr<ModelAPI_Feature>& theFeature, const std::list<std::string>& theArguments,
280   Events_InfoMessage& theError) const
281 {
282   // Get base objects list.
283   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
284   if (!aSelectionList.get()) {
285     theError = "Could not get selection list.";
286     return false;
287   }
288   if (aSelectionList->size() == 0) {
289     theError = "Empty selection list.";
290     return false;
291   }
292
293   // Collect base shapes.
294   ListOfShape anOriginalShapes;
295   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
296     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
297     if (!aSelection->context().get()) {
298       theError = "Invalid selection.";
299       return false;
300     }
301     GeomShapePtr aShape = aSelection->value();
302     if (!aShape.get())
303       aShape = aSelection->context()->shape();
304     anOriginalShapes.push_back(aShape);
305   }
306
307   std::shared_ptr<GeomAlgoAPI_MakeVolume> anAlgorithm(
308     new GeomAlgoAPI_MakeVolume(anOriginalShapes, false));
309
310   std::string anErr;
311   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(anAlgorithm, "MakeVolume", anErr)) {
312     theError = anErr;
313     return false;
314   }
315
316   // set of allowed types of results
317   std::set<GeomAPI_Shape::ShapeType> aResultType;
318   std::string aType = theArguments.back();
319   if (aType == "solid")
320     aResultType.insert(GeomAPI_Shape::SOLID);
321   else if (aType == "compsolid") {
322     aResultType.insert(GeomAPI_Shape::COMPSOLID);
323     aResultType.insert(GeomAPI_Shape::SOLID);
324   }
325
326   GeomShapePtr aCompound = anAlgorithm->shape();
327   if (aCompound->shapeType() == GeomAPI_Shape::COMPOUND) {
328     GeomAPI_ShapeIterator anIt(aCompound);
329     GeomShapePtr aFoundSub;
330     for (; anIt.more() && !aFoundSub; anIt.next()) {
331       aFoundSub = anIt.current();
332       if (aResultType.count(aFoundSub->shapeType()) == 0) {
333         theError = "Unable to build a solid";
334         return false;
335       }
336     }
337     if (anIt.more() || !aFoundSub.get()) {
338       theError = "Unable to build a solid";
339       return false;
340     }
341   } else if (aResultType.count(aCompound->shapeType()) == 0) {
342     theError = "Unable to build a solid";
343     return false;
344   }
345   // check the internal faces presence
346   for(GeomAPI_ShapeExplorer aFaces(aCompound, GeomAPI_Shape::FACE); aFaces.more(); aFaces.next()) {
347     if (aFaces.current()->orientation() == GeomAPI_Shape::INTERNAL) {
348       theError = "Internal faces are not allowed in the resulting solid";
349       return false;
350     }
351   }
352
353   return true;
354 }
355
356
357 //=================================================================================================
358 bool BuildPlugin_ValidatorSubShapesSelection::isValid(const AttributePtr& theAttribute,
359                                                       const std::list<std::string>& theArguments,
360                                                       Events_InfoMessage& theError) const
361 {
362   if(theArguments.size() != 1) {
363     // LCOV_EXCL_START
364     std::string aMsg = "Error: BuildPlugin_ValidatorSubShapesSelection should be used only with "
365       "1 parameter(Sketch feature id).";
366     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
367     return false;
368     // LCOV_EXCL_STOP
369   }
370
371   // Get base objects list.
372   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
373     // LCOV_EXCL_START
374     std::string aMsg =
375       "Error: BuildPlugin_ValidatorSubShapesSelection does not support attribute type \""
376       "%1\"\n Only \"%2\" supported.";
377     Events_InfoMessage("BuildPlugin_Validators", aMsg).
378       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
379     return false;
380     // LCOV_EXCL_STOP
381   }
382   AttributeSelectionListPtr aSelectionList =
383     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
384   if(!aSelectionList.get()) {
385     theError = "Could not get selection list.";
386     return false;
387   }
388
389   // Get base shape.
390   const std::string aBaseShapeId = "base_shape";
391   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
392   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeId);
393
394   if(!aShapeAttrSelection.get()) {
395     theError = "Base shape is empty.";
396     return false;
397   }
398
399   ResultPtr aBaseContext = aShapeAttrSelection->context();
400
401   GeomShapePtr aBaseShape  = aShapeAttrSelection->value();
402   if(!aBaseShape.get()) {
403     theError = "Base shape is empty.";
404     return false;
405   }
406
407   GeomAlgoAPI_ShapeBuilder aBuilder;
408   aBuilder.removeInternal(aBaseShape);
409   aBaseShape = aBuilder.shape();
410
411   // If selected shape is wire allow to select only vertices. If face - allow vertices and edges.
412   std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
413   switch(aBaseShape->shapeType()) {
414     case GeomAPI_Shape::FACE: anAllowedTypes.insert(GeomAPI_Shape::EDGE);
415     case GeomAPI_Shape::WIRE: anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
416     default: break;
417   }
418
419   // Check selected shapes.
420   GeomValidators_FeatureKind aFeatureKindValidator;
421   std::list<std::string> anArguments;
422   anArguments.push_back(theArguments.front());
423   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
424     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
425     if(!aSelectionAttrInList.get()) {
426       theError = "Empty attribute in list.";
427       return false;
428     }
429
430     // If context of selection same skip.
431     if(aBaseContext == aSelectionAttrInList->context()) {
432       continue;
433     }
434
435     // Check that it is a selection on Sketch.
436     if(!aFeatureKindValidator.isValid(aSelectionAttrInList, anArguments, theError)) {
437       return false;
438     }
439
440     // Check shape type.
441     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
442     if(!aShapeInList.get()) {
443       aShapeInList = aSelectionAttrInList->context()->shape();
444     }
445     if(anAllowedTypes.find(aShapeInList->shapeType()) == anAllowedTypes.cend()) {
446       theError = "Selected shape has unacceptable type.";
447       return false;
448     }
449
450     // Check that shape inside wire or face.
451     if(!GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aShapeInList, aBaseShape)) {
452       theError = "Selected shape is not inside base face.";
453       return false;
454     }
455   }
456
457   return true;
458 }
459
460
461 //=================================================================================================
462 bool BuildPlugin_ValidatorFillingSelection::isValid(const AttributePtr& theAttribute,
463                                                       const std::list<std::string>& theArguments,
464                                                       Events_InfoMessage& theError) const
465 {
466   // Get base objects list.
467   if (theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
468     // LCOV_EXCL_START
469     std::string aMsg =
470       "Error: BuildPlugin_ValidatorFillingSelection does not support attribute type \""
471       "%1\"\n Only \"%2\" supported.";
472     Events_InfoMessage("BuildPlugin_Validators", aMsg).
473       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
474     return false;
475     // LCOV_EXCL_STOP
476   }
477   AttributeSelectionListPtr aSelectionList =
478     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
479   if (!aSelectionList.get()) {
480     theError = "Could not get selection list.";
481     return false;
482   }
483
484   //FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
485
486   // Check selected shapes.
487   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
488     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
489     if (!aSelectionAttrInList.get()) {
490       theError = "Empty attribute in list.";
491       return false;
492     }
493
494     // Check shape exists.
495     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
496     if (!aShapeInList.get()) {
497       theError = "Object has no shape";
498       return false;
499     }
500
501     // Check shape type.
502     GeomAPI_Shape::ShapeType aType = aShapeInList->shapeType();
503     if (aType != GeomAPI_Shape::EDGE && aType != GeomAPI_Shape::WIRE) {
504       theError = "Incorrect objects selected";
505       return false;
506     }
507   }
508
509   return true;
510 }
511
512
513 //=================================================================================================
514 bool BuildPlugin_ValidatorBaseForVertex::isValid(const AttributePtr& theAttribute,
515                                                  const std::list<std::string>& /*theArguments*/,
516                                                  Events_InfoMessage& theError) const
517 {
518   if (!theAttribute.get()) {
519     theError = "Error: empty selection.";
520     return false;
521   }
522
523   AttributeSelectionListPtr aSelectionList =
524     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
525   if (!aSelectionList.get()) {
526     theError = "Could not get selection list.";
527     return false;
528   }
529
530   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
531     AttributeSelectionPtr aSelectionAttr = aSelectionList->value(anIndex);
532     if (!aSelectionAttr.get()) {
533       theError = "Empty attribute in list.";
534       return false;
535     }
536
537     // Vertex?
538     bool isVertex = false;
539     GeomShapePtr aShape = aSelectionAttr->value();
540     ResultPtr aContext = aSelectionAttr->context();
541     if (!aShape.get() && aContext.get())
542       aShape = aContext->shape();
543     if (aShape.get())
544       isVertex = (aShape->shapeType() == GeomAPI_Shape::VERTEX);
545
546     if (!isVertex) {
547       // Sketch?
548       FeaturePtr aFeature = aSelectionAttr->contextFeature();
549       if (!aFeature.get()) {
550         GeomShapePtr aValue = aSelectionAttr->value();
551         // whole sketch is allowed only
552         if (aContext.get() && !aValue.get()) {
553           aFeature = ModelAPI_Feature::feature(aContext);
554         }
555       }
556
557       if (!aFeature.get()) {
558         theError = "Error: Incorrect selection.";
559         return false;
560       }
561
562       if (aFeature->getKind() != SketchPlugin_Sketch::ID()) {
563         theError = "Error: %1 shape is not allowed for selection.";
564         theError.arg(aFeature->getKind());
565         return false;
566       }
567     }
568   }
569
570   return true;
571 }