]> SALOME platform Git repositories - modules/shaper.git/blob - src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
Salome HOME
Issue #1366: Remove Sub-Shapes feature added.
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:        FeaturesPlugin_Validators.cpp
4 // Created:     22 March 2016
5 // Author:      Dmitry Bobylev
6
7 #include "FeaturesPlugin_Validators.h"
8
9 #include <ModelAPI_Attribute.h>
10 #include <ModelAPI_AttributeInteger.h>
11 #include <ModelAPI_AttributeSelectionList.h>
12 #include <ModelAPI_AttributeString.h>
13 #include <ModelAPI_AttributeReference.h>
14 #include <ModelAPI_Feature.h>
15 #include <ModelAPI_ResultConstruction.h>
16
17 #include <Events_Error.h>
18
19 #include <GeomValidators_BodyShapes.h>
20 #include <GeomValidators_FeatureKind.h>
21 #include <GeomValidators_ShapeType.h>
22
23 #include <GeomAPI_DataMapOfShapeShape.h>
24 #include <GeomAPI_PlanarEdges.h>
25 #include <GeomAPI_ShapeExplorer.h>
26 #include <GeomAPI_ShapeIterator.h>
27
28 #include <GeomAlgoAPI_ShapeBuilder.h>
29 #include <GeomAlgoAPI_ShapeTools.h>
30 #include <GeomAlgoAPI_WireBuilder.h>
31
32 //==================================================================================================
33 bool FeaturesPlugin_ValidatorPipeLocations::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
34                                                     const std::list<std::string>& theArguments,
35                                                     std::string& theError) const
36 {
37   static const std::string aCreationMethodID = "creation_method";
38   static const std::string aBaseObjectsID = "base_objects";
39   static const std::string aLocationsID = "locations_objects";
40
41   if(theFeature->getKind() != "Pipe") {
42     theError = "Error: Feature \"" + theFeature->getKind() + "\" does not supported by this validator.";
43     return false;
44   }
45
46   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
47   if(!aCreationMethodAttr.get()) {
48     theError = "Error: Could not get \"" + aCreationMethodID + "\" attribute.";
49     return false;
50   }
51
52   if(aCreationMethodAttr->value() != "locations") {
53     return true;
54   }
55
56   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
57   if(!aBaseObjectsSelectionList.get()) {
58     theError = "Error: Could not get \"" + aBaseObjectsID + "\" attribute.";
59     return false;
60   }
61
62   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
63   if(!aLocationsSelectionList.get()) {
64     theError = "Error: Could not get \"" + aBaseObjectsID + "\" attribute.";
65     return false;
66   }
67
68   if(aLocationsSelectionList->size() > 0 && aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
69     theError = "Error: Number of locations should be the same as base objects.";
70     return false;
71   }
72
73   return true;
74 }
75
76 //==================================================================================================
77 bool FeaturesPlugin_ValidatorPipeLocations::isNotObligatory(std::string theFeature, std::string theAttribute)
78 {
79   return false;
80 }
81
82 //==================================================================================================
83 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
84                                                         const std::list<std::string>& theArguments,
85                                                         std::string& theError) const
86 {
87   if(theArguments.empty()) {
88     theError = "Error: Validator parameters is empty.";
89     return false;
90   }
91
92   // Checking attribute.
93   if(!isValidAttribute(theAttribute, theArguments, theError)) {
94     if(theError.empty()) {
95       theError = "Error: Attribute contains unacceptable shape.";
96     }
97     return false;
98   }
99
100   std::set<ResultConstructionPtr> aSelectedSketches;
101   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
102   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
103   std::string anAttributeType = theAttribute->attributeType();
104   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
105     AttributeSelectionListPtr aListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
106     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
107       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
108       ResultConstructionPtr aContext = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSelectionAttr->context());
109       if(!aContext.get()) {
110         // It is not a result construction, continue.
111         continue;
112       }
113
114       GeomShapePtr aShape = aSelectionAttr->value();
115       GeomShapePtr aContextShape = aContext->shape();
116       if(!aShape.get()) {
117         // Whole sketch selected.
118         if(aSelectedSketchesFromObjects.find(aContext) != aSelectedSketchesFromObjects.cend()) {
119           theError = "Error: Object from this sketch is already selected. Sketch is not allowed for selection.";
120           return false;
121         }
122
123         aSelectedSketches.insert(aContext);
124       } else {
125         // Object from sketch selected.
126         if(aSelectedSketches.find(aContext) != aSelectedSketches.cend()) {
127           theError = "Error: Whole sketch with this object is already selected. Don't allow to select this object.";
128           return false;
129         }
130
131         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
132           GeomShapePtr aWire = anExp.current();
133           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
134             theError = "Error: Wire with wrong orientation selected.";
135             return false;
136           }
137
138           if(aSelectedWiresFromObjects.isBound(aWire)) {
139             theError = "Error: Objects with such wire already selected. Don't allow to select this object.";
140             return false;
141           }
142
143           aSelectedWiresFromObjects.bind(aWire, aWire);
144           aSelectedSketchesFromObjects.insert(aContext);
145         }
146       }
147     }
148   }
149
150   return true;
151 }
152
153 //==================================================================================================
154 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
155                                                                  const std::list<std::string>& theArguments,
156                                                                  std::string& theError) const
157 {
158   if(!theAttribute.get()) {
159     theError = "Error: Empty attribute.";
160     return false;
161   }
162
163   std::string anAttributeType = theAttribute->attributeType();
164   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
165     AttributeSelectionListPtr aListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
166     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
167       // If at least one attribute is invalid, the result is false.
168       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
169         return false;
170       }
171     }
172   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
173     // Getting context.
174     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
175     ResultPtr aContext = anAttr->context();
176     if(!aContext.get()) {
177       theError = "Error: Attribute have empty context.";
178       return false;
179     }
180
181     GeomShapePtr aShape = anAttr->value();
182     GeomShapePtr aContextShape = aContext->shape();
183     if(!aShape.get()) {
184       aShape = aContextShape;
185     }
186     if(!aShape.get()) {
187       theError = "Error: Empty shape selected";
188       return false;
189     }
190
191     ResultConstructionPtr aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
192     if(aConstruction.get()) {
193       // Construciotn selected. Check that is is not infinite.
194       if(aConstruction->isInfinite()) {
195         theError = "Error: Infinite constructions is not allowed as base.";
196         return false;
197       }
198
199       if(aShape->isEqual(aContextShape)) {
200         // Whole construction selected. Check that it have faces.
201         if(aConstruction->facesNum() > 0) {
202           return true;
203         }
204       } else {
205         // Shape on construction selected. Check that it is a face or wire.
206         if(aShape->shapeType() == GeomAPI_Shape::WIRE || aShape->shapeType() == GeomAPI_Shape::FACE) {
207           return true;
208         }
209       }
210
211       return false;
212     }
213
214     if(!aShape->isEqual(aContextShape)) {
215       // Local selection on body does not allowed.
216       theError = "Error: Selected shape is in the local selection. Only global selection is allowed.";
217       return false;
218     }
219
220     // Check that object is a shape with allowed type.
221     GeomValidators_ShapeType aShapeTypeValidator;
222     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
223       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or wires on sketch, "
224                  "whole sketch(if it has at least one face), and whole objects with shape types: ";
225       std::list<std::string>::const_iterator anIt = theArguments.cbegin();
226       theError += *anIt;
227       for(++anIt; anIt != theArguments.cend(); ++anIt) {
228         theError += ", " + *anIt;
229       }
230       return false;
231     }
232
233   } else {
234     theError = "Error: Attribute \"" + anAttributeType + "\" does not supported by this validator.";
235     return false;
236   }
237
238   return true;
239 }
240
241 //==================================================================================================
242 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
243                                                         const std::list<std::string>& theArguments,
244                                                         std::string& theError) const
245 {
246   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
247     theError = "Error: The attribute with the " + theAttribute->attributeType() + " type is not processed";
248     return false;
249   }
250   if (theArguments.size() != 2) {
251     theError = "Error: Wrong parameters in XML definition for " + theAttribute->attributeType() + " type";
252     return false;
253   }
254   // first argument is for the base attribute, second - for skipping feature kind
255   std::list<std::string>::const_iterator anIt = theArguments.begin();
256   std::string aBaseAttributeId = *anIt;
257   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
258   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
259   if (!aBaseAttribute.get()) {
260     theError = "Wrong parameters in XML definition for " + theAttribute->attributeType() + " type";
261     return false;
262   }
263   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
264     // this validator is not necessary anymore
265     return true;
266
267   anIt++;
268   std::string aFeatureAttributeKind = *anIt;
269   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
270   // check whether the selection is on the sketch
271   std::list<std::string> anArguments;
272   anArguments.push_back(aFeatureAttributeKind);
273
274   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
275   bool aPlanarFace = false;
276   // check if selection has Face selected
277   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
278   anArguments.clear();
279   anArguments.push_back("face");
280   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
281
282   bool aValid = !aFeatureKind && aPlanarFace;
283   return aValid;
284 }
285
286 //==================================================================================================
287 bool FeaturesPlugin_ValidatorCanBeEmpty::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
288                                                  const std::list<std::string>& theArguments,
289                                                  std::string& theError) const
290 {
291   if(theArguments.size() != 2) {
292     theError = "Error: Validator should be used with 2 parameters for extrusion.";
293     return false;
294   }
295
296   std::list<std::string>::const_iterator anArgsIt = theArguments.begin(), aLast = theArguments.end();
297
298   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
299   ++anArgsIt;
300
301   if(isShapesCanBeEmpty(aCheckAttribute, theError)) {
302     return true;
303   }
304
305   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
306   if(!aSelAttr.get()) {
307     theError = "Error: Could not get selection attribute \"" + *anArgsIt + "\".";
308     return false;
309   }
310
311   GeomShapePtr aShape = aSelAttr->value();
312   if(!aShape.get()) {
313     ResultPtr aContext = aSelAttr->context();
314     if(!aContext.get()) {
315       theError = "Error: Base objects list contains vertex or edge, so attribute \"" + *anArgsIt
316                + "\" can not be used with default value. Select direction for extrusion.";
317       return false;
318     }
319
320     aShape = aContext->shape();
321   }
322
323   if(!aShape.get()) {
324     theError = "Error: Base objects list contains vertex or edge, so attribute \"" + *anArgsIt
325               + "\" can not be used with default value. Select direction for extrusion.";
326     return false;
327   }
328
329   return true;
330 }
331
332 //==================================================================================================
333 bool FeaturesPlugin_ValidatorCanBeEmpty::isNotObligatory(std::string theFeature, std::string theAttribute)
334 {
335   return false;
336 }
337
338 //==================================================================================================
339 bool FeaturesPlugin_ValidatorCanBeEmpty::isShapesCanBeEmpty(const AttributePtr& theAttribute,
340                                                             std::string& theError) const
341 {
342   if(!theAttribute.get()) {
343     return true;
344   }
345
346   std::string anAttributeType = theAttribute->attributeType();
347   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
348     AttributeSelectionListPtr aListAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
349     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
350       // If at least one attribute is invalid, the result is false.
351       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
352         return false;
353       }
354     }
355   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
356     // Getting context.
357     AttributeSelectionPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
358     ResultPtr aContext = anAttr->context();
359     if(!aContext.get()) {
360       return false;
361     }
362
363     GeomShapePtr aShape = anAttr->value();
364     GeomShapePtr aContextShape = aContext->shape();
365     if(!aShape.get()) {
366       aShape = aContextShape;
367     }
368     if(!aShape.get()) {
369       return false;
370     }
371
372     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
373        aShape->shapeType() == GeomAPI_Shape::EDGE ||
374        !aShape->isPlanar()) {
375       return false;
376     }
377   } else {
378     return false;
379   }
380
381   return true;
382 }
383
384 //==================================================================================================
385 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
386                                                        const std::list<std::string>& theArguments,
387                                                        std::string& theError) const
388 {
389   AttributeSelectionListPtr anAttrSelectionList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
390   if(!anAttrSelectionList.get()) {
391     theError = "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
392     return false;
393   }
394   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
395   int anOperationType = aFeature->integer("bool_type")->value();
396
397   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
398     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
399     if(!anAttrSelection.get()) {
400       theError = "Error: Empty attribute selection.";
401       return false;
402     }
403     ResultPtr aContext = anAttrSelection->context();
404     if(!aContext.get()) {
405       theError = "Error: Empty selection context.";
406       return false;
407     }
408     ResultConstructionPtr aResultConstruction =
409       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
410     if(aResultConstruction.get()) {
411       theError = "Error: Result construction not allowed for selection.";
412       return false;
413     }
414     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
415     if(!aShape.get()) {
416       aShape = aContext->shape();
417     }
418     if(!aShape.get()) {
419       theError = "Error: Empty shape.";
420       return false;
421     }
422     int aShapeType = aShape->shapeType();
423     if(anOperationType == 1) {
424       // Fuse operation. Allow to select edges, faces and solids.
425       if(aShapeType != GeomAPI_Shape::EDGE &&
426          aShapeType != GeomAPI_Shape::FACE &&
427          aShapeType != GeomAPI_Shape::SOLID &&
428          aShapeType != GeomAPI_Shape::COMPSOLID &&
429          aShapeType != GeomAPI_Shape::COMPOUND) {
430         theError = "Error: Selected shape has the wrong type.";
431         return false;
432       }
433     } else {
434       if(aShapeType != GeomAPI_Shape::SOLID &&
435          aShapeType != GeomAPI_Shape::COMPSOLID &&
436          aShapeType != GeomAPI_Shape::COMPOUND) {
437         theError = "Error: Selected shape has the wrong type.";
438         return false;
439       }
440     }
441   }
442
443   return true;
444 }
445
446 //==================================================================================================
447 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
448                                                          const std::list<std::string>& theArguments,
449                                                          std::string& theError) const
450 {
451   AttributeSelectionListPtr anAttrSelectionList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
452   if(!anAttrSelectionList.get()) {
453     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
454     return false;
455   }
456
457   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
458     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
459
460     //GeomValidators_BodyShapes aBodyValidator;
461     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
462     //  continue;
463     //}
464
465     GeomValidators_FeatureKind aFeatureKindValidator;
466     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
467       continue;
468     }
469
470     ResultPtr aContext = aSelectAttr->context();
471     ResultConstructionPtr aResultConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
472     if(aResultConstruction.get()) {
473
474     }
475
476     theError = "Error: Only body shapes and construction planes are allowed for selection.";
477     return false;
478   }
479
480   return true;
481 }
482
483 //==================================================================================================
484 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
485                                                                const std::list<std::string>& theArguments,
486                                                                std::string& theError) const
487 {
488   AttributeSelectionListPtr aSubShapesAttrList = std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
489   if(!aSubShapesAttrList.get()) {
490     theError = "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
491     return false;
492   }
493
494   static const std::string aBaseShapeID = "base_shape";
495   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
496   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
497
498   if(!aShapeAttrSelection.get()) {
499     theError = "Error: Could not get \"" + aBaseShapeID + "\" attribute.";
500     return false;
501   }
502
503   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
504   ResultPtr aContext = aShapeAttrSelection->context();
505   if(!aContext.get()) {
506     theError = "Error: Empty context.";
507     return false;
508   }
509   if(!aBaseShape.get()) {
510     aBaseShape = aContext->shape();
511   }
512   if(!aBaseShape.get()) {
513     theError = "Error: Empty base shape.";
514     return false;
515   }
516
517   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
518     bool isSameFound = false;
519     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
520     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
521     for(GeomAPI_ShapeIterator anIt(aBaseShape); anIt.more(); anIt.next()) {
522       if(anIt.current()->isEqual(aShapeToAdd)) {
523         isSameFound = true;
524         break;
525       }
526     }
527     if(!isSameFound) {
528       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
529       return false;
530     }
531   }
532
533   return true;
534 }
535
536 //==================================================================================================
537 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(const std::shared_ptr<ModelAPI_Feature>& theFeature,
538                                                             const std::list<std::string>& theArguments,
539                                                             std::string& theError) const
540 {
541   static const std::string aBaseShapeID = "base_shape";
542   static const std::string aSubShapesID = "subshapes";
543
544   if(theFeature->getKind() != "Remove_SubShapes") {
545     theError = "Error: Feature \"" + theFeature->getKind() + "\" does not supported by this validator.";
546     return false;
547   }
548
549   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
550   if(!aShapeAttrSelection.get()) {
551     theError = "Error: Could not get \"" + aBaseShapeID + "\" attribute.";
552     return false;
553   }
554
555   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
556   if(!aSubShapesAttrList.get()) {
557     theError = "Error: Could not get \"" + aSubShapesID + "\" attribute.";
558     return false;
559   }
560
561   // Copy base shape.
562   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
563   if(!aBaseShape.get()) {
564     return false;
565   }
566   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
567
568   // Copy sub-shapes from list to new shape.
569   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
570     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
571     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
572     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
573   }
574
575   // Check new shape.
576   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
577     theError = "Error: Resulting shape is not valid.";
578     return false;
579   }
580
581   return true;
582 }
583
584 //==================================================================================================
585 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isNotObligatory(std::string theFeature,
586                                                                     std::string theAttribute)
587 {
588   return false;
589 }