Salome HOME
Issue #3236: Generalization of extrusion
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
index e92148495868ded97bada247c73ca484abfb356b..9235d933e78d40e886dc4902e2f84649f016f7e3 100644 (file)
@@ -23,6 +23,7 @@
 #include "FeaturesPlugin_BooleanFuse.h"
 #include "FeaturesPlugin_BooleanCommon.h"
 #include "FeaturesPlugin_BooleanSmash.h"
+#include "FeaturesPlugin_CompositeBoolean.h"
 #include "FeaturesPlugin_Extrusion.h"
 #include "FeaturesPlugin_Pipe.h"
 #include "FeaturesPlugin_Union.h"
 #include <GeomAPI_ShapeIterator.h>
 
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_MapShapesAndAncestors.h>
 #include <GeomAlgoAPI_Prism.h>
 #include <GeomAlgoAPI_ShapeBuilder.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 #include <GeomAlgoAPI_WireBuilder.h>
 
+#include <algorithm>
+
 #define _USE_MATH_DEFINES
 #include <math.h>
 
@@ -397,9 +401,32 @@ bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const Attribute
   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
     AttributeSelectionListPtr aListAttr =
       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+
+    const std::string& aSelType = aListAttr->selectionType();
+    std::list<std::string> anApplicableTypes;
+    switch (GeomValidators_ShapeType::shapeType(aSelType)) {
+    case GeomValidators_ShapeType::Vertex:
+      anApplicableTypes.push_back("vertex");
+      break;
+    case GeomValidators_ShapeType::Edge:
+      anApplicableTypes.push_back("edge");
+      anApplicableTypes.push_back("wire");
+      break;
+    case GeomValidators_ShapeType::Face:
+      anApplicableTypes.push_back("face");
+      anApplicableTypes.push_back("shell");
+      // wire should not be the first in this list to be able to check
+      // the type of selection when evaluating shape by shape
+      anApplicableTypes.push_back("wire");
+      break;
+    default:
+      anApplicableTypes = theArguments;
+      break;
+    }
+
     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
       // If at least one attribute is invalid, the result is false.
-      if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
+      if(!isValidAttribute(aListAttr->value(anIndex), anApplicableTypes, theError)) {
         return false;
       }
     }
@@ -432,28 +459,32 @@ bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const Attribute
       aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
     if(aConstruction.get()) {
       // Construction selected. Check that it is not infinite.
-      if(aConstruction->isInfinite()) {
+      if(aConstruction->isInfinite() && !aConstruction->shape()->isVertex()) {
         theError = "Error: Infinite constructions is not allowed as base.";
         return false;
       }
 
       aContextShape = aContext->shape();
       if(aShape->isEqual(aContextShape)) {
-        // Whole construction selected. Check that it have faces.
-        if(aConstruction->facesNum() > 0) {
+        // Whole construction selected. Check that it has faces.
+        if((theArguments.front() == "face" && aConstruction->facesNum() > 0) ||
+            theArguments.front() == "edge") {
           return true;
         }
       } else {
-        // Shape on construction selected. Check that it is a face or wire.
-        if(aShape->shapeType() == GeomAPI_Shape::WIRE ||
-           aShape->shapeType() == GeomAPI_Shape::FACE) {
-          return true;
+        // CUT operation supports only FACE or WIRE as a tool base
+        std::shared_ptr<FeaturesPlugin_CompositeBoolean> aComposite =
+            std::dynamic_pointer_cast<FeaturesPlugin_CompositeBoolean>(
+            ModelAPI_Feature::feature(theAttribute->owner()));
+        if (aComposite &&
+            aComposite->operationType() == FeaturesPlugin_CompositeBoolean::BOOL_CUT) {
+          return aShape->shapeType() == GeomAPI_Shape::WIRE ||
+                 aShape->shapeType() == GeomAPI_Shape::FACE;
         }
       }
-      return false;
     }
 
-    if(aContextShape.get() && !aShape->isEqual(aContextShape)) {
+    if(!aConstruction && aContextShape.get() && !aShape->isEqual(aContextShape)) {
       // Local selection on body does not allowed.
       theError =
         "Error: Selected shape is in the local selection. Only global selection is allowed.";
@@ -941,6 +972,79 @@ bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAtt
   return true;
 }
 
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorFillet1DSelection::isValid(const AttributePtr& theAttribute,
+                                                        const std::list<std::string>& theArguments,
+                                                        Events_InfoMessage& theError) const
+{
+  AttributeSelectionListPtr anAttrSelectionList =
+    std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
+  if (!anAttrSelectionList.get()) {
+    // LCOV_EXCL_START
+    theError =
+      "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
+    return false;
+    // LCOV_EXCL_STOP
+  }
+
+  // check each selected vertex is a sharp corner between adjacent edges,
+  // and these edges are in the same plane
+  std::map<GeomShapePtr, MapShapeToShapes> aWireSubshapes;
+  int aNbSel = anAttrSelectionList->size();
+  for (int ind = 0; ind < aNbSel; ++ind) {
+    AttributeSelectionPtr aCurSel = anAttrSelectionList->value(ind);
+    GeomShapePtr aContext = aCurSel->context()->shape();
+    GeomShapePtr aVertex = aCurSel->value();
+    // check wire already processed, if not, store all vertices and edges, sharing them
+    std::map<GeomShapePtr, MapShapeToShapes>::iterator aProcessed = aWireSubshapes.find(aContext);
+    if (aProcessed == aWireSubshapes.end()) {
+      if (aContext->shapeType() != GeomAPI_Shape::WIRE) {
+        theError = "Selected vertex is not a wire corner";
+        return false;
+      }
+      if (aVertex->shapeType() != GeomAPI_Shape::VERTEX) {
+        theError = "Selected shape is not a vertex";
+        return false;
+      }
+
+      GeomAlgoAPI_MapShapesAndAncestors aMapVE(aContext, GeomAPI_Shape::VERTEX,
+                                                         GeomAPI_Shape::EDGE);
+      aWireSubshapes[aContext] = aMapVE.map();
+      aProcessed = aWireSubshapes.find(aContext);
+    }
+
+    // check the vertex
+    MapShapeToShapes::iterator aFound = aProcessed->second.find(aVertex);
+    if (aFound == aProcessed->second.end()) {
+      theError = "Selected vertex does not exist in the wire";
+      return true;
+    }
+    else if (aFound->second.size() != 2) {
+      theError = "Vertex should be shared between 2 edges exactly";
+      return false;
+    }
+
+    ListOfShape anEdges;
+    anEdges.insert(anEdges.end(), aFound->second.begin(), aFound->second.end());
+    GeomPlanePtr aPlane = GeomAlgoAPI_ShapeTools::findPlane(anEdges);
+    if (!aPlane) {
+      theError = "Error: Edges are not planar";
+      return false;
+    }
+
+    GeomEdgePtr anEdge1(new GeomAPI_Edge(anEdges.front()));
+    GeomEdgePtr anEdge2(new GeomAPI_Edge(anEdges.back()));
+    GeomVertexPtr aSharedVertex(new GeomAPI_Vertex(aVertex));
+    if (GeomAlgoAPI_ShapeTools::isTangent(anEdge1, anEdge2, aSharedVertex)) {
+      theError = "Error: Edges are tangent";
+      return false;
+    }
+  }
+
+  return true;
+}
+
 //==================================================================================================
 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
                                                        const std::list<std::string>& theArguments,