Salome HOME
81c16c770faee3e8ab8cae572f92a5c9f58eaa76
[modules/shaper.git] / src / BuildPlugin / BuildPlugin_Validators.cpp
1 // Copyright (C) 2014-2023  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   //check only planar onjects
357   bool isPlanarBelongToOnePlane(false);
358   if (!aPlanarEdges.empty()) {
359     // Check that they are planar.
360     std::shared_ptr<GeomAPI_Pln> aPln = GeomAlgoAPI_ShapeTools::findPlane(aPlanarEdges);
361     if(aPln.get()) {
362       // Check that selected objects have closed contours.
363       isPlanarBelongToOnePlane = true;
364       GeomAlgoAPI_SketchBuilder aBuilder(aPln, aPlanarEdges);
365       const ListOfShape& aFaces = aBuilder.faces();
366       if(aFaces.empty()) {
367         theError = "Selected planar objects do not generate closed contour.";
368         return false;
369       }
370     }
371   }
372
373   //check non planar objects
374   if(!aNonPlanarEdges.empty() || (!aPlanarEdges.empty() && !isPlanarBelongToOnePlane))
375   {
376     GeomAlgoAPI_NonPlanarFace aNonPlanarFaceBuilder(isPlanarBelongToOnePlane? aNonPlanarEdges : anAllEdges);
377     const ListOfShape& aFaces = aNonPlanarFaceBuilder.faces();
378     if(aFaces.empty()) {
379       theError = "Selected non-planar objects do not generate closed contour.";
380       return false;
381     }
382   }
383
384   return true;
385 }
386
387 //=================================================================================================
388 bool BuildPlugin_ValidatorBaseForSolids::isValid(
389   const std::shared_ptr<ModelAPI_Feature>& theFeature, const std::list<std::string>& theArguments,
390   Events_InfoMessage& theError) const
391 {
392   // Get base objects list.
393   AttributeSelectionListPtr aSelectionList = theFeature->selectionList(theArguments.front());
394   if (!aSelectionList.get()) {
395     theError = "Could not get selection list.";
396     return false;
397   }
398   if (aSelectionList->size() == 0) {
399     theError = "Empty selection list.";
400     return false;
401   }
402
403   if (theFeature->getKind() == BuildPlugin_Solid::ID()) {
404     /// remove objects of sub-type if ojects of correct type is in List,  in some cases :
405     /// Solid builder: faces and shapes shells or solids seleted
406     ///                --> remove faces
407
408     std::set<int> aRemove;
409     for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
410       AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
411       GeomShapePtr aShape = aSelection->value();
412       if (aShape.get()) {
413         GeomAPI_Shape::ShapeType aType = aShape->shapeType();
414         if ((aType == GeomAPI_Shape::SHAPE) ||
415           (aType == GeomAPI_Shape::SOLID) ||
416           (aType == GeomAPI_Shape::SHELL)) {
417
418           GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::FACE);
419           for (; anExp.more(); anExp.next()) {
420             GeomShapePtr aFace = anExp.current();
421             for (int i = 0; i < aSelectionList->size(); ++i) {
422               AttributeSelectionPtr aSel = aSelectionList->value(i);
423               GeomShapePtr aShp = aSel->value();
424               if (aShp.get()) {
425                 if (aShp->shapeType() == GeomAPI_Shape::FACE) {
426                   if (aShp->isEqual(aFace))
427                     aRemove.insert(i);
428                 }
429               }
430               else {
431                 aRemove.insert(anIndex);
432               }
433             }
434           }
435         }
436       }
437     }
438     if (aRemove.size() > 0)
439       aSelectionList->remove(aRemove);
440   }
441
442   // Collect base shapes.
443   ListOfShape anOriginalShapes;
444   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
445     AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
446     if (!aSelection->context().get()) {
447       theError = "Invalid selection.";
448       return false;
449     }
450     GeomShapePtr aShape = aSelection->value();
451     if (!aShape.get())
452       aShape = aSelection->context()->shape();
453     anOriginalShapes.push_back(aShape);
454   }
455
456   std::shared_ptr<GeomAlgoAPI_MakeVolume> anAlgorithm(
457     new GeomAlgoAPI_MakeVolume(anOriginalShapes, false));
458
459   std::string anErr;
460   if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(anAlgorithm, "MakeVolume", anErr)) {
461     theError = anErr;
462     return false;
463   }
464
465   // set of allowed types of results
466   std::set<GeomAPI_Shape::ShapeType> aResultType;
467   std::string aType = theArguments.back();
468   if (aType == "solid")
469     aResultType.insert(GeomAPI_Shape::SOLID);
470   else if (aType == "compsolid") {
471     aResultType.insert(GeomAPI_Shape::COMPSOLID);
472     aResultType.insert(GeomAPI_Shape::SOLID);
473   }
474
475   GeomShapePtr aCompound = anAlgorithm->shape();
476   if (aCompound->shapeType() == GeomAPI_Shape::COMPOUND) {
477     GeomAPI_ShapeIterator anIt(aCompound);
478     GeomShapePtr aFoundSub;
479     for (; anIt.more() && !aFoundSub; anIt.next()) {
480       aFoundSub = anIt.current();
481       if (aResultType.count(aFoundSub->shapeType()) == 0) {
482         theError = "Unable to build a solid";
483         return false;
484       }
485     }
486     if (anIt.more() || !aFoundSub.get()) {
487       theError = "Unable to build a solid";
488       return false;
489     }
490   } else if (aResultType.count(aCompound->shapeType()) == 0) {
491     theError = "Unable to build a solid";
492     return false;
493   }
494   // check the internal faces presence
495   for(GeomAPI_ShapeExplorer aFaces(aCompound, GeomAPI_Shape::FACE); aFaces.more(); aFaces.next()) {
496     if (aFaces.current()->orientation() == GeomAPI_Shape::INTERNAL) {
497       theError = "Internal faces are not allowed in the resulting solid";
498       return false;
499     }
500   }
501
502   return true;
503 }
504
505
506 //=================================================================================================
507 bool BuildPlugin_ValidatorSubShapesSelection::isValid(const AttributePtr& theAttribute,
508                                                       const std::list<std::string>& theArguments,
509                                                       Events_InfoMessage& theError) const
510 {
511   if(theArguments.size() != 1) {
512     // LCOV_EXCL_START
513     std::string aMsg = "Error: BuildPlugin_ValidatorSubShapesSelection should be used only with "
514       "1 parameter(Sketch feature id).";
515     Events_InfoMessage("BuildPlugin_Validators", aMsg).send();
516     return false;
517     // LCOV_EXCL_STOP
518   }
519
520   // Get base objects list.
521   if(theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
522     // LCOV_EXCL_START
523     std::string aMsg =
524       "Error: BuildPlugin_ValidatorSubShapesSelection does not support attribute type \""
525       "%1\"\n Only \"%2\" supported.";
526     Events_InfoMessage("BuildPlugin_Validators", aMsg).
527       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
528     return false;
529     // LCOV_EXCL_STOP
530   }
531   AttributeSelectionListPtr aSelectionList =
532     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
533   if(!aSelectionList.get()) {
534     theError = "Could not get selection list.";
535     return false;
536   }
537
538   // Get base shape.
539   const std::string aBaseShapeId = "base_shape";
540   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
541   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeId);
542
543   if(!aShapeAttrSelection.get()) {
544     theError = "Base shape is empty.";
545     return false;
546   }
547
548   ResultPtr aBaseContext = aShapeAttrSelection->context();
549
550   GeomShapePtr aBaseShape  = aShapeAttrSelection->value();
551   if(!aBaseShape.get()) {
552     theError = "Base shape is empty.";
553     return false;
554   }
555
556   GeomAlgoAPI_ShapeBuilder aBuilder;
557   aBuilder.removeInternal(aBaseShape);
558   aBaseShape = aBuilder.shape();
559
560   // If selected shape is wire allow to select only vertices. If face - allow vertices and edges.
561   std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
562   switch(aBaseShape->shapeType()) {
563     case GeomAPI_Shape::FACE: anAllowedTypes.insert(GeomAPI_Shape::EDGE);
564     case GeomAPI_Shape::WIRE: anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
565     default: break;
566   }
567
568   // Check selected shapes.
569   GeomValidators_FeatureKind aFeatureKindValidator;
570   std::list<std::string> anArguments;
571   anArguments.push_back(theArguments.front());
572   for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
573     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
574     if(!aSelectionAttrInList.get()) {
575       theError = "Empty attribute in list.";
576       return false;
577     }
578
579     // If context of selection same skip.
580     if(aBaseContext == aSelectionAttrInList->context()) {
581       continue;
582     }
583
584     // Check that it is a selection on Sketch.
585     if(!aFeatureKindValidator.isValid(aSelectionAttrInList, anArguments, theError)) {
586       return false;
587     }
588
589     // Check shape type.
590     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
591     if(!aShapeInList.get()) {
592       aShapeInList = aSelectionAttrInList->context()->shape();
593     }
594     if(anAllowedTypes.find(aShapeInList->shapeType()) == anAllowedTypes.cend()) {
595       theError = "Selected shape has unacceptable type.";
596       return false;
597     }
598
599     // Check that shape inside wire or face.
600     if(!GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(aShapeInList, aBaseShape)) {
601       theError = "Selected shape is not inside base face.";
602       return false;
603     }
604   }
605
606   return true;
607 }
608
609
610 //=================================================================================================
611 bool BuildPlugin_ValidatorFillingSelection::isValid(const AttributePtr& theAttribute,
612                                                     const std::list<std::string>& /*theArguments*/,
613                                                     Events_InfoMessage& theError) const
614 {
615   // Get base objects list.
616   if (theAttribute->attributeType() != ModelAPI_AttributeSelectionList::typeId()) {
617     // LCOV_EXCL_START
618     std::string aMsg =
619       "Error: BuildPlugin_ValidatorFillingSelection does not support attribute type \""
620       "%1\"\n Only \"%2\" supported.";
621     Events_InfoMessage("BuildPlugin_Validators", aMsg).
622       arg(theAttribute->attributeType()).arg(ModelAPI_AttributeSelectionList::typeId()).send();
623     return false;
624     // LCOV_EXCL_STOP
625   }
626   AttributeSelectionListPtr aSelectionList =
627     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
628   if (!aSelectionList.get()) {
629     theError = "Could not get selection list.";
630     return false;
631   }
632
633   //FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
634
635   // Check selected shapes.
636   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
637     AttributeSelectionPtr aSelectionAttrInList = aSelectionList->value(anIndex);
638     if (!aSelectionAttrInList.get()) {
639       theError = "Empty attribute in list.";
640       return false;
641     }
642
643     // Check shape exists.
644     GeomShapePtr aShapeInList = aSelectionAttrInList->value();
645     if (!aShapeInList.get()) {
646       theError = "Object has no shape";
647       return false;
648     }
649
650     // Check shape type.
651     GeomAPI_Shape::ShapeType aType = aShapeInList->shapeType();
652     if (aType != GeomAPI_Shape::EDGE && aType != GeomAPI_Shape::WIRE) {
653       theError = "Incorrect objects selected";
654       return false;
655     }
656   }
657
658   return true;
659 }
660
661
662 //=================================================================================================
663 bool BuildPlugin_ValidatorBaseForVertex::isValid(const AttributePtr& theAttribute,
664                                                  const std::list<std::string>& /*theArguments*/,
665                                                  Events_InfoMessage& theError) const
666 {
667   if (!theAttribute.get()) {
668     theError = "Error: empty selection.";
669     return false;
670   }
671
672   AttributeSelectionListPtr aSelectionList =
673     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
674   if (!aSelectionList.get()) {
675     theError = "Could not get selection list.";
676     return false;
677   }
678
679   for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
680     AttributeSelectionPtr aSelectionAttr = aSelectionList->value(anIndex);
681     if (!aSelectionAttr.get()) {
682       theError = "Empty attribute in list.";
683       return false;
684     }
685
686     // Vertex?
687     bool isVertex = false;
688     GeomShapePtr aShape = aSelectionAttr->value();
689     ResultPtr aContext = aSelectionAttr->context();
690     if (!aShape.get() && aContext.get())
691       aShape = aContext->shape();
692     if (aShape.get())
693       isVertex = (aShape->shapeType() == GeomAPI_Shape::VERTEX);
694
695     if (!isVertex) {
696       // Sketch?
697       FeaturePtr aFeature = aSelectionAttr->contextFeature();
698       if (!aFeature.get()) {
699         GeomShapePtr aValue = aSelectionAttr->value();
700         // whole sketch is allowed only
701         if (aContext.get() && !aValue.get()) {
702           aFeature = ModelAPI_Feature::feature(aContext);
703         }
704       }
705
706       if (!aFeature.get()) {
707         theError = "Error: Incorrect selection.";
708         return false;
709       }
710
711       if (aFeature->getKind() != SketchPlugin_Sketch::ID()) {
712         theError = "Error: %1 shape is not allowed for selection.";
713         theError.arg(aFeature->getKind());
714         return false;
715       }
716     }
717   }
718
719   return true;
720 }
721
722 //=================================================================================================
723 bool BuildPlugin_ValidatorExpressionInterpolation::isValid(const AttributePtr& theAttribute,
724                                                    const std::list<std::string>& /*theArguments*/,
725                                                    Events_InfoMessage& theError) const
726 {
727   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
728
729   AttributeStringPtr aStrAttr =
730       std::dynamic_pointer_cast<ModelAPI_AttributeString>(theAttribute);
731   if (!aStrAttr->isInitialized()) {
732     theError = "Attribute \"%1\" is not initialized.";
733     theError.arg(aStrAttr->id());
734     return false;
735   }
736   bool isEmptyExpr = aStrAttr->value().empty();
737   if (isEmptyExpr) {
738     theError = "Expression is empty.";
739     return false;
740   }
741
742   theError = aFeature->string(BuildPlugin_Interpolation::EXPRESSION_ERROR_ID())->value();
743   return theError.empty();
744 }