Salome HOME
Issue #3236: Generalization of extrusion
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
index 30993f225bd44544afc1544cedc0f00bb8a5a095..9235d933e78d40e886dc4902e2f84649f016f7e3 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2020  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
@@ -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"
@@ -30,7 +31,7 @@
 #include <Events_InfoMessage.h>
 
 #include <ModelAPI_Attribute.h>
-#include <ModelAPI_AttributeDouble.h>>
+#include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeInteger.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeString.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>
 
+#ifdef _MSC_VER
+#pragma warning(disable: 4100)
+#endif
+
 //==================================================================================================
 bool FeaturesPlugin_ValidatorPipePath::isValid(const AttributePtr& theAttribute,
                                                const std::list<std::string>& theArguments,
@@ -271,9 +279,8 @@ bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theA
         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
             GeomShapePtr aSubShape = anIt.current();
-            if(aSubShape->shapeType() != GeomAPI_Shape::VERTEX
-                && aSubShape->shapeType() != GeomAPI_Shape::EDGE
-                && aSubShape->shapeType() != GeomAPI_Shape::FACE) {
+            if (aSubShape->shapeType() > GeomAPI_Shape::VERTEX ||
+                aSubShape->shapeType() < GeomAPI_Shape::FACE) {
               theError = "Error: Compound should contain only faces, edges or vertices.";
               return false;
             }
@@ -299,7 +306,7 @@ bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theA
 
           if(aSelectedWiresFromObjects.isBound(aWire)) {
             theError =
-              "Error: Objects with such wire already selected. Don't allow to select this object.";
+              "Error: Objects with this wire already selected. Don't allow to select this object.";
             return false;
           }
 
@@ -394,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;
       }
     }
@@ -429,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;
       }
 
-      GeomShapePtr aContextShape = aContext->shape();
+      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.";
@@ -461,7 +495,7 @@ bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const Attribute
     GeomValidators_ShapeType aShapeTypeValidator;
     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
-                 "wires on sketch, whole sketch(if it has at least one face), "
+                 "wires on sketch, whole sketch (if it has at least one face), "
                  "and whole objects with shape types: %1";
       std::string anArgumentString;
       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
@@ -547,8 +581,7 @@ bool FeaturesPlugin_ValidatorExtrusionDir::isValid(
 // LCOV_EXCL_STOP
   }
 
-  std::list<std::string>::const_iterator
-    anArgsIt = theArguments.begin(), aLast = theArguments.end();
+  std::list<std::string>::const_iterator anArgsIt = theArguments.begin();
 
   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
   ++anArgsIt;
@@ -913,8 +946,9 @@ bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAtt
       }
     }
 
-    ResultBodyPtr aContextOwner = ModelAPI_Tools::bodyOwner(aContext);
-    GeomShapePtr anOwner = aContextOwner.get() ? aContextOwner->shape() : aContext->shape();
+    ResultBodyPtr aContextOwner = ModelAPI_Tools::bodyOwner(aContext, true);
+    GeomShapePtr anOwner = aContext->shape();
+    GeomShapePtr aTopLevelOwner = aContextOwner.get() ? aContextOwner->shape() : anOwner;
 
     if (!anOwner) {
       theError = "Error: wrong feature is selected.";
@@ -928,8 +962,8 @@ bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAtt
     }
 
     if (!aBaseSolid)
-      aBaseSolid = anOwner;
-    else if (!aBaseSolid->isEqual(anOwner)) {
+      aBaseSolid = aTopLevelOwner;
+    else if (!aBaseSolid->isEqual(aTopLevelOwner)) {
       theError = "Error: Sub-shapes of different solids have been selected.";
       return false;
     }
@@ -938,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,
@@ -1135,7 +1242,6 @@ bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttr
   }
 
   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
-    bool isSameFound = false;
     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
     ResultPtr aContext = anAttrSelectionInList->context();
     if (!aContext.get()) {
@@ -1561,16 +1667,16 @@ bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttrib
       return false;
     }
     ResultPtr aContext = anAttrSelection->context();
-    if(!aContext.get()) {
-      FeaturePtr aContFeat = anAttrSelection->contextFeature();
-      if (!aContFeat.get() || !aContFeat->results().size() ||
-          aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
+    if (aContext.get()) {
+      aFeature = ModelAPI_Feature::feature(aContext);
+    } else {
+      aFeature = anAttrSelection->contextFeature();
+      if (!aFeature.get() || !aFeature->results().size() ||
+          aFeature->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
         theError = "Error: Empty selection context.";
         return false;
       }
     }
-    FeaturePtr aFeature = anAttrSelection->contextFeature().get() ?
-      anAttrSelection->contextFeature() : ModelAPI_Feature::feature(aContext);
     if (!aFeature.get()) {
       theError = "Error: empty feature.";
       return false;
@@ -1686,7 +1792,7 @@ bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
 
   int anObjectsNb = 0, aToolsNb = 0;
 
-  std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
+  std::list<std::string>::const_iterator anIt = theArguments.begin();
 
   bool isAllInSameCompSolid = true;
   ResultBodyPtr aCompSolid;
@@ -1737,14 +1843,9 @@ bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
     }
   }
 
-  anIt++;
-
   if (anObjectsNb + aToolsNb < 2) {
     theError = "Not enough arguments for Fuse operation.";
     return false;
-  } else if (isAllInSameCompSolid) {
-    theError = "Operations only between sub-shapes of the same shape not allowed.";
-    return false;
   }
 
   return true;
@@ -1843,9 +1944,8 @@ bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
 
   int anObjectsNb = 0, aToolsNb = 0;
 
-  std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
+  std::list<std::string>::const_iterator anIt = theArguments.begin();
 
-  bool isAllInSameCompSolid = true;
   ResultBodyPtr aCompSolid;
 
   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
@@ -1880,3 +1980,42 @@ bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
   return false;
 }
 // LCOV_EXCL_STOP
+
+//==================================================================================================
+bool FeaturesPlugin_ValidatorDefeaturingSelection::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.";
+    return false;
+    // LCOV_EXCL_STOP
+  }
+
+  // Check selected entities are sub-shapes of solid or compsolid
+  GeomShapePtr aBaseSolid;
+  for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
+    AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
+    if (!anAttrSelection.get()) {
+      theError = "Error: Empty attribute selection.";
+      return false;
+    }
+    ResultPtr aContext = anAttrSelection->context();
+    if (!aContext.get()) {
+      theError = "Error: Empty selection context.";
+      return false;
+    }
+
+    GeomShapePtr aContextShape = aContext->shape();
+    if (aContextShape->shapeType() != GeomAPI_Shape::SOLID) {
+      theError = "Error: Not all selected shapes are sub-shapes of solids.";
+      return false;
+    }
+  }
+
+  return true;
+}