Salome HOME
f8a07c778d2a45a41fa937e253df6122dc5d5845
[modules/shaper.git] / src / BuildPlugin / BuildPlugin_Validators.cpp
1 // Copyright (C) 2014-2024  CEA, EDF
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 #include "BuildPlugin_Solid.h"
22 #include "BuildPlugin_Face.h"
23 #include "BuildPlugin_Wire.h"
24
25 #include <ModelAPI_AttributeSelectionList.h>
26 #include <ModelAPI_AttributeString.h>
27 #include <ModelAPI_ResultConstruction.h>
28
29 #include <GeomAPI_PlanarEdges.h>
30 #include <GeomAPI_Pln.h>
31 #include <GeomAPI_ShapeExplorer.h>
32 #include <GeomAPI_ShapeIterator.h>
33
34 #include <GeomAlgoAPI_CompoundBuilder.h>
35 #include <GeomAlgoAPI_PaveFiller.h>
36 #include <GeomAlgoAPI_ShapeBuilder.h>
37 #include <GeomAlgoAPI_ShapeTools.h>
38 #include <GeomAlgoAPI_SketchBuilder.h>
39 #include <GeomAlgoAPI_WireBuilder.h>
40 #include <GeomAlgoAPI_MakeVolume.h>
41 #include <GeomAlgoAPI_Tools.h>
42 #include <GeomAlgoAPI_NonPlanarFace.h>
43
44 #include <GeomValidators_FeatureKind.h>
45 #include <GeomValidators_ShapeType.h>
46
47 #include <BuildPlugin_Interpolation.h>
48
49 #include <SketchPlugin_Sketch.h>
50
51 #include <Events_InfoMessage.h>
52
53 //=================================================================================================
54 bool BuildPlugin_ValidatorBaseForBuild::isValid(const AttributePtr& theAttribute,
55                                                 const std::list<std::string>& theArguments,
56                                                 Events_InfoMessage& theError) const
57 {
58   // Get base objects list.
59   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
60     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForBuild does "
61                        "not support attribute type '%1'\nOnly '%2' is supported.";
62     Events_InfoMessage("BuildPlugin_Validators", aMsg).
63       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
64     return false;
65   }
66   AttributeSelectionListPtr aSelectionList =
67     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
68   if(!aSelectionList.get()) {
69     theError = "Could not get selection list.";
70     return false;
71   }
72   if(aSelectionList->size() == 0) {
73     theError = "Empty selection list.";
74     return false;
75   }
76
77   // Collect base shapes.
78   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
79     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
80     if(!aSelection.get()) {
81       theError = "Could not get selection.";
82       return false;
83     }
84     ResultPtr aContext = aSelection->context();
85     if(!aContext.get()) {
86       theError = "Attribute have empty context.";
87       return false;
88     }
89
90     GeomShapePtr aShape = aSelection->value();
91     GeomShapePtr aContextShape = aContext->shape();
92     if(!aShape.get()) {
93       aShape = aContextShape;
94     }
95     if(!aShape.get()) {
96       theError = "Empty shape selected.";
97       return false;
98     }
99
100     // Check that shapes has acceptable type.
101     GeomValidators_ShapeType aValidatorShapeType;
102     if(!aValidatorShapeType.isValid(aSelection, theArguments, theError)) {
103       return false;
104     }
105
106     // Check that it is shape on sketch.
107     ResultConstructionPtr aConstruction =
108       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
109     if(aConstruction.get()) {
110       if(aConstruction->isInfinite()) {
111         theError = "Infinite objects not acceptable.";
112         return false;
113       }
114     }
115   }
116
117   return true;
118 }
119
120 //=================================================================================================
121 bool BuildPlugin_ValidatorBaseForWire::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
122                                                const std::list<std::string>& theArguments,
123                                                Events_InfoMessage& theError) const
124 {
125   // Get attribute.
126   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
127   if(!aSelectionList.get()) {
128     theError = "Empty attribute \"%1\".";
129     theError.arg(theArguments.front());
130     return false;
131   }
132
133   if (theFeature->getKind() == BuildPlugin_Wire::ID()) {
134     /// remove objects of sub-type if ojects of correct type is in List,  in some cases :
135     /// Wire builder: wires and edges selected
136     std::set<int> aRemove;
137     for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
138       AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
139       GeomShapePtr aShape = aSelection->value();
140       if (aShape.get()) {
141         GeomAPI_Shape::ShapeType aType = aShape->shapeType();
142         if (aType == GeomAPI_Shape::WIRE) {
143           // check for edges
144           GeomAPI_ShapeExplorer anEdgeExp(aShape, GeomAPI_Shape::EDGE);
145           for (; anEdgeExp.more(); anEdgeExp.next()) {
146             GeomShapePtr aEdge = anEdgeExp.current();
147             for (int i = 0; i < aSelectionList->size(); ++i) {
148               AttributeSelectionPtr aSel = aSelectionList->value(i);
149               GeomShapePtr aShp = aSel->value();
150               if (aShp.get()) {
151                 if (aShp->shapeType() == GeomAPI_Shape::EDGE) {
152                   if (aShp->isEqual(aEdge) || aShp->isSameGeometry(aEdge))
153                     aRemove.insert(i);
154                 }
155               }
156               else {
157                 aRemove.insert(anIndex);
158               }
159             }
160           }
161         }
162       }
163     }
164     if (aRemove.size() > 0)
165       aSelectionList->remove(aRemove);
166   }
167
168   GeomAPI_Shape::ShapeType aShapeType = GeomAPI_Shape::shapeTypeByStr(theArguments.back());
169   // Collect base shapes.
170   ListOfShape aListOfShapes;
171   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
172     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
173     GeomShapePtr aShape = aSelection->value();
174     ResultPtr aContext = aSelection->context();
175     if (!aShape.get() && aContext.get())
176       aShape = aContext->shape();
177
178     bool isProper = aShape.get() &&
179         (aShape->shapeType() == GeomAPI_Shape::EDGE || aShape->shapeType() == aShapeType);
180
181     if (isProper)
182       aListOfShapes.push_back(aShape);
183     else {
184       // is it a sketch?
185       FeaturePtr aFeature = aSelection->contextFeature();
186       if (!aFeature.get()) {
187         GeomShapePtr aValue = aSelection->value();
188         // whole sketch is allowed only
189         if (aContext.get() && !aValue.get()) {
190           aFeature = ModelAPI_Feature::feature(aContext);
191         }
192       }
193
194       if (!aFeature.get()) {
195         theError = "Error: Incorrect selection.";
196         return false;
197       }
198
199       if (aFeature->getKind() != SketchPlugin_Sketch::ID()) {
200         theError = "Error: %1 shape is not allowed for selection.";
201         theError.arg(aFeature->getKind());
202         return false;
203       }
204     }
205   }
206
207   if (aShapeType == GeomAPI_Shape::WIRE) {
208     // Create wire.
209     GeomShapePtr aWire = GeomAlgoAPI_WireBuilder::wire(aListOfShapes);
210     if (!aWire.get() && !aListOfShapes.empty()) {
211       theError = "Result wire empty. Probably it has disconnected edges or non-manifold.";
212       return false;
213     }
214   }
215
216   return true;
217 }
218
219 //=================================================================================================
220 bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
221                                                const std::list<std::string>& theArguments,
222                                                Events_InfoMessage& theError) const
223 {
224   // Get attribute.
225   if(theArguments.size() != 1) {
226     std::string aMsg = "Error: BuildPlugin_ValidatorBaseForFace should be used only with "
227       "1 parameter (ID of base objects list).";
228     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
229     return false;
230   }
231   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
232   if(!aSelectionList.get()) {
233     theError = "Empty attribute \"%1\".";
234     theError.arg(theArguments.front());
235     return false;
236   }
237
238   if (theFeature->getKind() == BuildPlugin_Face::ID()) {
239     /// remove objects of sub-type if ojects of correct type is in List,  in some cases :
240     /// - Face builder: edges, faces and wires selected
241     ///                 --> remove edges and wires
242     std::set<int> aRemove;
243     for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
244       AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
245       GeomShapePtr aShape = aSelection->value();
246       if (aShape.get()) {
247         GeomAPI_Shape::ShapeType aType = aShape->shapeType();
248         if (aType == GeomAPI_Shape::FACE) {
249           // Check for wires
250           GeomAPI_ShapeExplorer anWireExp(aShape, GeomAPI_Shape::WIRE);
251           for (; anWireExp.more(); anWireExp.next()) {
252             GeomShapePtr aWire = anWireExp.current();
253             for (int i = 0; i < aSelectionList->size(); ++i) {
254               AttributeSelectionPtr aSel = aSelectionList->value(i);
255               GeomShapePtr aShp = aSel->value();
256               if (aShp.get()) {
257                 if (aShp->shapeType() == GeomAPI_Shape::WIRE) {
258                   if (aShp->isEqual(aWire) || aShp->isSameGeometry(aWire))
259                     aRemove.insert(i);
260                 }
261               }
262               else {
263                 aRemove.insert(anIndex);
264               }
265             }
266           }
267
268           // check for edges
269           GeomAPI_ShapeExplorer anEdgeExp(aShape, GeomAPI_Shape::EDGE);
270           for (; anEdgeExp.more(); anEdgeExp.next()) {
271             GeomShapePtr aEdge = anEdgeExp.current();
272             for (int i = 0; i < aSelectionList->size(); ++i) {
273               AttributeSelectionPtr aSel = aSelectionList->value(i);
274               GeomShapePtr aShp = aSel->value();
275               if (aShp.get()) {
276                 if (aShp->shapeType() == GeomAPI_Shape::EDGE) {
277                   if (aShp->isEqual(aEdge) || aShp->isSameGeometry(aEdge))
278                     aRemove.insert(i);
279                 }
280               }
281               else {
282                 aRemove.insert(anIndex);
283               }
284             }
285           }
286         }
287       }
288     }
289     if (aRemove.size() > 0)
290       aSelectionList->remove(aRemove);
291   }
292   bool hasEdgesOrWires = false;
293   bool hasFaces = false;
294
295   // Collect base shapes.
296   ListOfShape anAllEdges;
297   ListOfShape aPlanarEdges;
298   ListOfShape aNonPlanarEdges;
299   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
300     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
301     GeomShapePtr aShape = aSelection->value();
302     if(!aShape.get()) {
303       if (!aSelection->context()) {
304         theError = "Objects are not selected.";
305         return false;
306       }
307       aShape = aSelection->context()->shape();
308     }
309     ResultConstructionPtr aSketchRes =
310         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSelection->context());
311
312     if (aShape->shapeType() == GeomAPI_Shape::FACE ||
313         (!aSelection->value() && aSketchRes && aSketchRes->facesNum() > 0)) {
314       // skip faces exploding
315       hasFaces = true;
316       continue;
317     }
318
319     bool isPlanar(aShape->isPlanar());
320     for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
321       hasEdgesOrWires = true;
322       GeomShapePtr anEdge = anExp.current();
323       anAllEdges.push_back(anEdge);
324       isPlanar? aPlanarEdges.push_back(anEdge): aNonPlanarEdges.push_back(anEdge);
325     }
326   }
327
328   if (hasFaces && hasEdgesOrWires) {
329     theError = "Faces and edges/wires should be selected together.";
330     return false;
331   } else if (hasEdgesOrWires && anAllEdges.empty()) {
332     theError = "Objects are not selected.";
333     return false;
334   }
335
336   // Check that edges does not have intersections.
337   if(anAllEdges.size() > 1) {
338     GeomAlgoAPI_PaveFiller aPaveFiller(anAllEdges, false);
339     if(!aPaveFiller.isDone()) {
340       theError = "Error while checking if edges intersects.";
341       return false;
342     }
343     GeomShapePtr aSectedEdges = aPaveFiller.shape();
344
345     size_t anEdgesNum = 0;
346     for(GeomAPI_ShapeExplorer
347         anExp(aSectedEdges, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
348       anEdgesNum++;
349     }
350     if(anEdgesNum != anAllEdges.size()) {
351       theError = "Selected objects have intersections.";
352       return false;
353     }
354   }
355
356   if (!anAllEdges.empty()) {
357     // Check that they are planar.
358     std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(anAllEdges);
359     if(aPln.get()) {
360         // Check that selected objects have closed contours.
361       GeomAlgoAPI_SketchBuilder aBuilder(aPln, anAllEdges);
362       const ListOfShape& aFaces = aBuilder.faces();
363       if(!aFaces.empty()) {
364         return true;
365       }
366     }
367   }
368
369
370   //check only planar onjects
371   bool isPlanarBelongToOnePlane(false);
372   if (!aPlanarEdges.empty()) {
373     // Check that they are planar.
374     std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(aPlanarEdges);
375     if(aPln.get()) {
376       // Check that selected objects have closed contours.
377       isPlanarBelongToOnePlane = true;
378       GeomAlgoAPI_SketchBuilder aBuilder(aPln, aPlanarEdges);
379       const ListOfShape& aFaces = aBuilder.faces();
380       if(aFaces.empty()) {
381         theError = "Selected planar objects do not generate closed contour.";
382         return false;
383       }
384     }
385   }
386
387   //check non planar objects
388   if(!aNonPlanarEdges.empty() || (!aPlanarEdges.empty() && !isPlanarBelongToOnePlane))
389   {
390     GeomAlgoAPI_NonPlanarFace aNonPlanarFaceBuilder(isPlanarBelongToOnePlane? aNonPlanarEdges : anAllEdges);
391     const ListOfShape& aFaces = aNonPlanarFaceBuilder.faces();
392     if(aFaces.empty()) {
393       theError = "Selected non-planar objects do not generate closed contour.";
394       return false;
395     }
396   }
397
398   return true;
399 }
400
401 //=================================================================================================
402 bool BuildPlugin_ValidatorBaseForSolids::isValid(
403   const std::shared_ptr<ModelAPI_Feature>& theFeature, const std::list<std::string>& theArguments,
404   Events_InfoMessage& theError) const
405 {
406   // Get base objects list.
407   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
408   if (!aSelectionList.get()) {
409     theError = "Could not get selection list.";
410     return false;
411   }
412   if (aSelectionList->size() == 0) {
413     theError = "Empty selection list.";
414     return false;
415   }
416
417   if (theFeature->getKind() == BuildPlugin_Solid::ID()) {
418     /// remove objects of sub-type if ojects of correct type is in List,  in some cases :
419     /// Solid builder: faces and shapes shells or solids seleted
420     ///                --> remove faces
421
422     std::set<int> aRemove;
423     for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
424       AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
425       GeomShapePtr aShape = aSelection->value();
426       if (aShape.get()) {
427         GeomAPI_Shape::ShapeType aType = aShape->shapeType();
428         if ((aType == GeomAPI_Shape::SHAPE) ||
429           (aType == GeomAPI_Shape::SOLID) ||
430           (aType == GeomAPI_Shape::SHELL)) {
431
432           GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::FACE);
433           for (; anExp.more(); anExp.next()) {
434             GeomShapePtr aFace = anExp.current();
435             for (int i = 0; i < aSelectionList->size(); ++i) {
436               AttributeSelectionPtr aSel = aSelectionList->value(i);
437               GeomShapePtr aShp = aSel->value();
438               if (aShp.get()) {
439                 if (aShp->shapeType() == GeomAPI_Shape::FACE) {
440                   if (aShp->isEqual(aFace))
441                     aRemove.insert(i);
442                 }
443               }
444               else {
445                 aRemove.insert(anIndex);
446               }
447             }
448           }
449         }
450       }
451     }
452     if (aRemove.size() > 0)
453       aSelectionList->remove(aRemove);
454   }
455
456   // Collect base shapes.
457   ListOfShape anOriginalShapes;
458   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
459     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
460     if (!aSelection->context().get()) {
461       theError = "Invalid selection.";
462       return false;
463     }
464     GeomShapePtr aShape = aSelection->value();
465     if (!aShape.get())
466       aShape = aSelection->context()->shape();
467     anOriginalShapes.push_back(aShape);
468   }
469
470   std::shared_ptr<GeomAlgoAPI_MakeVolume> anAlgorithm(
471     new GeomAlgoAPI_MakeVolume(anOriginalShapes, false));
472
473   std::string anErr;
474   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(anAlgorithm, "MakeVolume", anErr)) {
475     theError = anErr;
476     return false;
477   }
478
479   // set of allowed types of results
480   std::set<GeomAPI_Shape::ShapeType> aResultType;
481   std::string aType = theArguments.back();
482   if (aType == "solid")
483     aResultType.insert(GeomAPI_Shape::SOLID);
484   else if (aType == "compsolid") {
485     aResultType.insert(GeomAPI_Shape::COMPSOLID);
486     aResultType.insert(GeomAPI_Shape::SOLID);
487   }
488
489   GeomShapePtr aCompound = anAlgorithm->shape();
490   if (aCompound->shapeType() == GeomAPI_Shape::COMPOUND) {
491     GeomAPI_ShapeIterator anIt(aCompound);
492     GeomShapePtr aFoundSub;
493     for (; anIt.more() && !aFoundSub; anIt.next()) {
494       aFoundSub = anIt.current();
495       if (aResultType.count(aFoundSub->shapeType()) == 0) {
496         theError = "Unable to build a solid";
497         return false;
498       }
499     }
500     if (anIt.more() || !aFoundSub.get()) {
501       theError = "Unable to build a solid";
502       return false;
503     }
504   } else if (aResultType.count(aCompound->shapeType()) == 0) {
505     theError = "Unable to build a solid";
506     return false;
507   }
508   // check the internal faces presence
509   for(GeomAPI_ShapeExplorer aFaces(aCompound, GeomAPI_Shape::FACE); aFaces.more(); aFaces.next()) {
510     if (aFaces.current()->orientation() == GeomAPI_Shape::INTERNAL) {
511       theError = "Internal faces are not allowed in the resulting solid";
512       return false;
513     }
514   }
515
516   return true;
517 }
518
519
520 //=================================================================================================
521 bool BuildPlugin_ValidatorSubShapesSelection::isValid(const AttributePtr& theAttribute,
522                                                       const std::list<std::string>& theArguments,
523                                                       Events_InfoMessage& theError) const
524 {
525   if(theArguments.size() != 1) {
526     // LCOV_EXCL_START
527     std::string aMsg = "Error: BuildPlugin_ValidatorSubShapesSelection should be used only with "
528       "1 parameter(Sketch feature id).";
529     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
530     return false;
531     // LCOV_EXCL_STOP
532   }
533
534   // Get base objects list.
535   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
536     // LCOV_EXCL_START
537     std::string aMsg =
538       "Error: BuildPlugin_ValidatorSubShapesSelection does not support attribute type \""
539       "%1\"\n Only \"%2\" supported.";
540     Events_InfoMessage("BuildPlugin_Validators", aMsg).
541       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
542     return false;
543     // LCOV_EXCL_STOP
544   }
545   AttributeSelectionListPtr aSelectionList =
546     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
547   if(!aSelectionList.get()) {
548     theError = "Could not get selection list.";
549     return false;
550   }
551
552   // Get base shape.
553   const std::string aBaseShapeId = "base_shape";
554   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
555   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeId);
556
557   if(!aShapeAttrSelection.get()) {
558     theError = "Base shape is empty.";
559     return false;
560   }
561
562   ResultPtr aBaseContext = aShapeAttrSelection->context();
563
564   GeomShapePtr aBaseShape  = aShapeAttrSelection->value();
565   if(!aBaseShape.get()) {
566     theError = "Base shape is empty.";
567     return false;
568   }
569
570   GeomAlgoAPI_ShapeBuilder aBuilder;
571   aBuilder.removeInternal(aBaseShape);
572   aBaseShape = aBuilder.shape();
573
574   // If selected shape is wire allow to select only vertices. If face - allow vertices and edges.
575   std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
576   switch(aBaseShape->shapeType()) {
577     case GeomAPI_Shape::FACE: anAllowedTypes.insert(GeomAPI_Shape::EDGE);
578     case GeomAPI_Shape::WIRE: anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
579     default: break;
580   }
581
582   // Check selected shapes.
583   GeomValidators_FeatureKind aFeatureKindValidator;
584   std::list<std::string> anArguments;
585   anArguments.push_back(theArguments.front());
586   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
587     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
588     if(!aSelectionAttrInList.get()) {
589       theError = "Empty attribute in list.";
590       return false;
591     }
592
593     // If context of selection same skip.
594     if(aBaseContext == aSelectionAttrInList->context()) {
595       continue;
596     }
597
598     // Check that it is a selection on Sketch.
599     if(!aFeatureKindValidator.isValid(aSelectionAttrInList, anArguments, theError)) {
600       return false;
601     }
602
603     // Check shape type.
604     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
605     if(!aShapeInList.get()) {
606       aShapeInList = aSelectionAttrInList->context()->shape();
607     }
608     if(anAllowedTypes.find(aShapeInList->shapeType()) == anAllowedTypes.cend()) {
609       theError = "Selected shape has unacceptable type.";
610       return false;
611     }
612
613     // Check that shape inside wire or face.
614     if(!GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aShapeInList, aBaseShape)) {
615       theError = "Selected shape is not inside base face.";
616       return false;
617     }
618   }
619
620   return true;
621 }
622
623
624 //=================================================================================================
625 bool BuildPlugin_ValidatorFillingSelection::isValid(const AttributePtr& theAttribute,
626                                                     const std::list<std::string>& /*theArguments*/,
627                                                     Events_InfoMessage& theError) const
628 {
629   // Get base objects list.
630   if (theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
631     // LCOV_EXCL_START
632     std::string aMsg =
633       "Error: BuildPlugin_ValidatorFillingSelection does not support attribute type \""
634       "%1\"\n Only \"%2\" supported.";
635     Events_InfoMessage("BuildPlugin_Validators", aMsg).
636       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
637     return false;
638     // LCOV_EXCL_STOP
639   }
640   AttributeSelectionListPtr aSelectionList =
641     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
642   if (!aSelectionList.get()) {
643     theError = "Could not get selection list.";
644     return false;
645   }
646
647   //FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
648
649   // Check selected shapes.
650   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
651     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
652     if (!aSelectionAttrInList.get()) {
653       theError = "Empty attribute in list.";
654       return false;
655     }
656
657     // Check shape exists.
658     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
659     if (!aShapeInList.get()) {
660       theError = "Object has no shape";
661       return false;
662     }
663
664     // Check shape type.
665     GeomAPI_Shape::ShapeType aType = aShapeInList->shapeType();
666     if (aType != GeomAPI_Shape::EDGE && aType != GeomAPI_Shape::WIRE) {
667       theError = "Incorrect objects selected";
668       return false;
669     }
670   }
671
672   return true;
673 }
674
675
676 //=================================================================================================
677 bool BuildPlugin_ValidatorBaseForVertex::isValid(const AttributePtr& theAttribute,
678                                                  const std::list<std::string>& /*theArguments*/,
679                                                  Events_InfoMessage& theError) const
680 {
681   if (!theAttribute.get()) {
682     theError = "Error: empty selection.";
683     return false;
684   }
685
686   AttributeSelectionListPtr aSelectionList =
687     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
688   if (!aSelectionList.get()) {
689     theError = "Could not get selection list.";
690     return false;
691   }
692
693   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
694     AttributeSelectionPtr aSelectionAttr = aSelectionList->value(anIndex);
695     if (!aSelectionAttr.get()) {
696       theError = "Empty attribute in list.";
697       return false;
698     }
699
700     // Vertex?
701     bool isVertex = false;
702     GeomShapePtr aShape = aSelectionAttr->value();
703     ResultPtr aContext = aSelectionAttr->context();
704     if (!aShape.get() && aContext.get())
705       aShape = aContext->shape();
706     if (aShape.get())
707       isVertex = (aShape->shapeType() == GeomAPI_Shape::VERTEX);
708
709     if (!isVertex) {
710       // Sketch?
711       FeaturePtr aFeature = aSelectionAttr->contextFeature();
712       if (!aFeature.get()) {
713         GeomShapePtr aValue = aSelectionAttr->value();
714         // whole sketch is allowed only
715         if (aContext.get() && !aValue.get()) {
716           aFeature = ModelAPI_Feature::feature(aContext);
717         }
718       }
719
720       if (!aFeature.get()) {
721         theError = "Error: Incorrect selection.";
722         return false;
723       }
724
725       if (aFeature->getKind() != SketchPlugin_Sketch::ID()) {
726         theError = "Error: %1 shape is not allowed for selection.";
727         theError.arg(aFeature->getKind());
728         return false;
729       }
730     }
731   }
732
733   return true;
734 }
735
736 //=================================================================================================
737 bool BuildPlugin_ValidatorExpressionInterpolation::isValid(const AttributePtr& theAttribute,
738                                                    const std::list<std::string>& /*theArguments*/,
739                                                    Events_InfoMessage& theError) const
740 {
741   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
742
743   AttributeStringPtr aStrAttr =
744       std::dynamic_pointer_cast<ModelAPI_AttributeString>(theAttribute);
745   if (!aStrAttr->isInitialized()) {
746     theError = "Attribute \"%1\" is not initialized.";
747     theError.arg(aStrAttr->id());
748     return false;
749   }
750   bool isEmptyExpr = aStrAttr->value().empty();
751   if (isEmptyExpr) {
752     theError = "Expression is empty.";
753     return false;
754   }
755
756   theError = aFeature->string(BuildPlugin_Interpolation::EXPRESSION_ERROR_ID())->value();
757   return theError.empty();
758 }