Salome HOME
Task #3236: Generalization of extrusion
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
index 07db4dd86f32d32371a2dede20b1e61811bde22f..c8b96f14403b868062e04fe60793ba918360a237 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"
@@ -54,6 +55,7 @@
 #include <GeomAPI_ShapeIterator.h>
 
 #include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_MapShapesAndAncestors.h>
 #include <GeomAlgoAPI_Prism.h>
 #include <GeomAlgoAPI_ShapeBuilder.h>
 #include <GeomAlgoAPI_ShapeTools.h>
 #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 +277,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;
             }
@@ -434,23 +439,26 @@ bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const Attribute
         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) {
           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.";
@@ -547,8 +555,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 +920,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 +936,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 +946,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 +1216,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 +1641,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 +1766,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,8 +1817,6 @@ bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
     }
   }
 
-  anIt++;
-
   if (anObjectsNb + aToolsNb < 2) {
     theError = "Not enough arguments for Fuse operation.";
     return false;
@@ -1840,9 +1918,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);
@@ -1877,3 +1954,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;
+}