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