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