Salome HOME
Filling operation: create a face from a set of edges/wires
authorazv <azv@opencascade.com>
Thu, 21 Dec 2017 05:55:42 +0000 (08:55 +0300)
committerazv <azv@opencascade.com>
Thu, 21 Dec 2017 08:58:53 +0000 (11:58 +0300)
1. Filling feature implementation
2. Python API for the Filling feature
3. Python dump
4. Unit tests

29 files changed:
src/BuildAPI/BuildAPI.i
src/BuildAPI/BuildAPI_Filling.cpp [new file with mode: 0644]
src/BuildAPI/BuildAPI_Filling.h [new file with mode: 0644]
src/BuildAPI/BuildAPI_swig.h
src/BuildAPI/CMakeLists.txt
src/BuildPlugin/BuildPlugin_Filling.cpp [new file with mode: 0644]
src/BuildPlugin/BuildPlugin_Filling.h [new file with mode: 0644]
src/BuildPlugin/BuildPlugin_Plugin.cpp
src/BuildPlugin/CMakeLists.txt
src/BuildPlugin/Test/TestFilling_ByEdges.py [new file with mode: 0644]
src/BuildPlugin/Test/TestFilling_ByWires.py [new file with mode: 0644]
src/BuildPlugin/Test/TestFilling_Mixed.py [new file with mode: 0644]
src/BuildPlugin/filling_widget.xml [new file with mode: 0644]
src/BuildPlugin/icons/feature_filling.png [new file with mode: 0644]
src/BuildPlugin/plugin-Build.xml
src/GeomAPI/GeomAPI_Shape.cpp
src/GeomAPI/GeomAPI_Shape.h
src/GeomAPI/GeomAPI_Wire.cpp
src/GeomAPI/GeomAPI_Wire.h
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_Filling.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_Filling.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h
src/GeomValidators/CMakeLists.txt
src/GeomValidators/GeomValidators_ValueOrder.cpp [new file with mode: 0644]
src/GeomValidators/GeomValidators_ValueOrder.h [new file with mode: 0644]
src/ModelHighAPI/ModelHighAPI_Dumper.cpp
src/PythonAPI/model/build/__init__.py

index 5156e2742d75a0a89d42f7b1b4ce5a4aba922cf7..8977df7ce92343e2b6a699da5559325d7895da4f 100644 (file)
@@ -41,6 +41,7 @@
 // shared pointers
 %shared_ptr(BuildAPI_Edge)
 %shared_ptr(BuildAPI_Face)
+%shared_ptr(BuildAPI_Filling)
 %shared_ptr(BuildAPI_Shell)
 %shared_ptr(BuildAPI_SubShapes)
 %shared_ptr(BuildAPI_Vertex)
@@ -49,6 +50,7 @@
 // all supported interfaces
 %include "BuildAPI_Edge.h"
 %include "BuildAPI_Face.h"
+%include "BuildAPI_Filling.h"
 %include "BuildAPI_Shell.h"
 %include "BuildAPI_SubShapes.h"
 %include "BuildAPI_Vertex.h"
diff --git a/src/BuildAPI/BuildAPI_Filling.cpp b/src/BuildAPI/BuildAPI_Filling.cpp
new file mode 100644 (file)
index 0000000..8951bd8
--- /dev/null
@@ -0,0 +1,180 @@
+// Copyright (C) 2017-20xx  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "BuildAPI_Filling.h"
+
+#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Tools.h>
+
+BuildAPI_Filling::BuildAPI_Filling(const std::shared_ptr<ModelAPI_Feature>& theFeature)
+  : ModelHighAPI_Interface(theFeature)
+{
+  initialize();
+}
+
+BuildAPI_Filling::BuildAPI_Filling(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                   const std::list<ModelHighAPI_Selection>& theBaseObjects)
+  : ModelHighAPI_Interface(theFeature)
+{
+  if(initialize())
+    setBase(theBaseObjects);
+}
+
+BuildAPI_Filling::BuildAPI_Filling(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                                   const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                                   const std::string& theOrientCorrection,
+                                   const int theMinDegree,
+                                   const int theMaxDegree,
+                                   const int theNbIter,
+                                   const double theTolerance2D,
+                                   const double theTolerance3D,
+                                   const bool theApproximate)
+  : ModelHighAPI_Interface(theFeature)
+{
+  if(initialize()) {
+    setOrientationMethod(theOrientCorrection);
+    setMinDegree(theMinDegree);
+    setMaxDegree(theMaxDegree);
+    setNbIterations(theNbIter);
+    setTolerance2d(theTolerance2D);
+    setTolerance3d(theTolerance3D);
+    setApproximation(theApproximate);
+    setAdvancedOptions();
+    setBase(theBaseObjects);
+  }
+}
+
+BuildAPI_Filling::~BuildAPI_Filling()
+{
+}
+
+void BuildAPI_Filling::execIfBaseNotEmpty()
+{
+  if (baseObjects()->size() > 0)
+    execute();
+}
+
+void BuildAPI_Filling::setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects)
+{
+  fillAttribute(theBaseObjects, mybaseObjects);
+  execIfBaseNotEmpty();
+}
+
+void BuildAPI_Filling::setOrientationMethod(const std::string& theMethod)
+{
+  fillAttribute(theMethod, myorientationMethod);
+  if (theMethod != BuildPlugin_Filling::METHOD_DEFAULT())
+    setAdvancedOptions();
+  execIfBaseNotEmpty();
+}
+
+void BuildAPI_Filling::setMinDegree(const int theMinDegree)
+{
+  fillAttribute(theMinDegree, myminDegree);
+  if (theMinDegree != BuildPlugin_Filling::MINIMAL_DEGREE_DEFAULT())
+    setAdvancedOptions();
+  execIfBaseNotEmpty();
+}
+
+void BuildAPI_Filling::setMaxDegree(const int theMaxDegree)
+{
+  fillAttribute(theMaxDegree, mymaxDegree);
+  if (theMaxDegree != BuildPlugin_Filling::MAXIMAL_DEGREE_DEFAULT())
+    setAdvancedOptions();
+  execIfBaseNotEmpty();
+}
+
+void BuildAPI_Filling::setNbIterations(const int theNbIter)
+{
+  fillAttribute(theNbIter, mynbIterations);
+  if (theNbIter != BuildPlugin_Filling::NUMBER_OF_ITERATIONS_DEFAULT())
+    setAdvancedOptions();
+  execIfBaseNotEmpty();
+}
+
+void BuildAPI_Filling::setTolerance2d(const double theTol2d)
+{
+  fillAttribute(theTol2d, mytolerance2d);
+  if (theTol2d != BuildPlugin_Filling::TOLERANCE_2D_DEFAULT())
+    setAdvancedOptions();
+  execIfBaseNotEmpty();
+}
+
+void BuildAPI_Filling::setTolerance3d(const double theTol3d)
+{
+  fillAttribute(theTol3d, mytolerance3d);
+  if (theTol3d != BuildPlugin_Filling::TOLERANCE_3D_DEFAULT())
+    setAdvancedOptions();
+  execIfBaseNotEmpty();
+}
+
+void BuildAPI_Filling::setApproximation(const bool theApproximate)
+{
+  fillAttribute(theApproximate, myapproximate);
+  if (theApproximate != BuildPlugin_Filling::APPROXIMATION_DEFAULT())
+    setAdvancedOptions();
+  execIfBaseNotEmpty();
+}
+
+void BuildAPI_Filling::setAdvancedOptions()
+{
+  feature()->string(BuildPlugin_Filling::ADVANCED_OPTIONS_ID())->setValue("true");
+}
+
+void BuildAPI_Filling::dump(ModelHighAPI_Dumper& theDumper) const
+{
+  FeaturePtr aBase = feature();
+  std::string aPartName = theDumper.name(aBase->document());
+
+  theDumper << aBase << " = model.addFilling(" << aPartName << ", " << baseObjects();
+
+  if (!aBase->string(BuildPlugin_Filling::ADVANCED_OPTIONS_ID())->value().empty()) {
+    // dump options too,
+    theDumper << ", " << orientationMethod()
+              << ", " << minDegree() << ", " << maxDegree() << ", " << nbIterations()
+              << ", " << tolerance2d() << ", " << tolerance3d()
+              << ", " << approximate();
+  }
+  theDumper << ")" << std::endl;
+}
+
+//==================================================================================================
+
+FillingPtr addFilling(const std::shared_ptr<ModelAPI_Document>& thePart,
+                      const std::list<ModelHighAPI_Selection>& theBaseObjects)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(BuildAPI_Filling::ID());
+  return FillingPtr(new BuildAPI_Filling(aFeature, theBaseObjects));
+}
+
+FillingPtr addFilling(const std::shared_ptr<ModelAPI_Document>& thePart,
+                      const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                      const std::string& theOrientCorrection,
+                      const int theMinDegree,
+                      const int theMaxDegree,
+                      const int theNbIter,
+                      const double theTolerance2D,
+                      const double theTolerance3D,
+                      const bool theApproximate)
+{
+  std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(BuildAPI_Filling::ID());
+  return FillingPtr(new BuildAPI_Filling(aFeature, theBaseObjects, theOrientCorrection,
+      theMinDegree, theMaxDegree, theNbIter, theTolerance2D, theTolerance3D, theApproximate));
+}
diff --git a/src/BuildAPI/BuildAPI_Filling.h b/src/BuildAPI/BuildAPI_Filling.h
new file mode 100644 (file)
index 0000000..8ccab1f
--- /dev/null
@@ -0,0 +1,141 @@
+// Copyright (C) 2017-20xx  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef BuildAPI_Filling_H_
+#define BuildAPI_Filling_H_
+
+#include "BuildAPI.h"
+
+#include <BuildPlugin_Filling.h>
+
+#include <ModelHighAPI_Interface.h>
+#include <ModelHighAPI_Macro.h>
+
+class ModelHighAPI_Selection;
+
+/// \class BuildAPI_Filling
+/// \ingroup CPPHighAPI
+/// \brief Interface for Filling feature.
+class BuildAPI_Filling : public ModelHighAPI_Interface
+{
+public:
+  /// Constructor without values.
+  BUILDAPI_EXPORT explicit BuildAPI_Filling(const std::shared_ptr<ModelAPI_Feature>& theFeature);
+
+  /// Constructor with base objects.
+  BUILDAPI_EXPORT
+  explicit BuildAPI_Filling(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                            const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+  /// Constructor with values.
+  BUILDAPI_EXPORT
+  explicit BuildAPI_Filling(const std::shared_ptr<ModelAPI_Feature>& theFeature,
+                            const std::list<ModelHighAPI_Selection>& theBaseObjects,
+                            const std::string& theOrientCorrection,
+                            const int theMinDegree,
+                            const int theMaxDegree,
+                            const int theNbIter,
+                            const double theTolerance2D,
+                            const double theTolerance3D,
+                            const bool theApproximate);
+
+  /// Destructor.
+  BUILDAPI_EXPORT virtual ~BuildAPI_Filling();
+
+  INTERFACE_8(BuildPlugin_Filling::ID(),
+              baseObjects, BuildPlugin_Filling::BASE_OBJECTS_ID(),
+                           ModelAPI_AttributeSelectionList,
+                           /** Base objects */,
+              orientationMethod, BuildPlugin_Filling::METHOD_ID(),
+                                 ModelAPI_AttributeString,
+                                 /** Method to keep edge orientaion */,
+              minDegree, BuildPlugin_Filling::MINIMAL_DEGREE_ID(),
+                         ModelAPI_AttributeInteger,
+                         /** Minimal degree */,
+              maxDegree, BuildPlugin_Filling::MAXIMAL_DEGREE_ID(),
+                         ModelAPI_AttributeInteger,
+                         /** Maximal degree */,
+              nbIterations, BuildPlugin_Filling::NUMBER_OF_ITERATIONS_ID(),
+                            ModelAPI_AttributeInteger,
+                            /** Number of iterations */,
+              tolerance2d, BuildPlugin_Filling::TOLERANCE_2D_ID(),
+                           ModelAPI_AttributeDouble,
+                           /** 2D tolerance */,
+              tolerance3d, BuildPlugin_Filling::TOLERANCE_3D_ID(),
+                           ModelAPI_AttributeDouble,
+                           /** 3D tolerance */,
+              approximate, BuildPlugin_Filling::APPROXIMATION_ID(),
+                           ModelAPI_AttributeBoolean,
+                           /** Approximate original edges */)
+
+  /// Modify base attribute of the feature.
+  BUILDAPI_EXPORT void setBase(const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+  /// Modify orientation method
+  BUILDAPI_EXPORT void setOrientationMethod(const std::string& theMethod);
+
+  /// Modify minimal degree of result B-spline
+  BUILDAPI_EXPORT void setMinDegree(const int theMinDegree);
+
+  /// Modify maximal degree of result B-spline
+  BUILDAPI_EXPORT void setMaxDegree(const int theMaxDegree);
+
+  /// Modify number of iterations
+  BUILDAPI_EXPORT void setNbIterations(const int theNbIter);
+
+  /// Set 2D tolerance
+  BUILDAPI_EXPORT void setTolerance2d(const double theTol2d);
+
+  /// Set 3D tolerance
+  BUILDAPI_EXPORT void setTolerance3d(const double theTol3d);
+
+  /// Set approximation flag
+  BUILDAPI_EXPORT void setApproximation(const bool theApproximate);
+
+  /// Dump wrapped feature
+  BUILDAPI_EXPORT virtual void dump(ModelHighAPI_Dumper& theDumper) const;
+
+private:
+  void execIfBaseNotEmpty();
+  void setAdvancedOptions();
+};
+
+/// Pointer on Face object.
+typedef std::shared_ptr<BuildAPI_Filling> FillingPtr;
+
+/// \ingroup CPPHighAPI
+/// \brief Create Filling feature.
+BUILDAPI_EXPORT FillingPtr addFilling(const std::shared_ptr<ModelAPI_Document>& thePart,
+                                      const std::list<ModelHighAPI_Selection>& theBaseObjects);
+
+/// \ingroup CPPHighAPI
+/// \brief Create Filling feature.
+BUILDAPI_EXPORT FillingPtr addFilling(
+      const std::shared_ptr<ModelAPI_Document>& thePart,
+      const std::list<ModelHighAPI_Selection>& theBaseObjects,
+      const std::string& theOrientCorrection,
+      const int theMinDegree = BuildPlugin_Filling::MINIMAL_DEGREE_DEFAULT(),
+      const int theMaxDegree = BuildPlugin_Filling::MAXIMAL_DEGREE_DEFAULT(),
+      const int theNbIter = BuildPlugin_Filling::NUMBER_OF_ITERATIONS_DEFAULT(),
+      const double theTolerance2D = BuildPlugin_Filling::TOLERANCE_2D_DEFAULT(),
+      const double theTolerance3D = BuildPlugin_Filling::TOLERANCE_3D_DEFAULT(),
+      const bool theApproximate = BuildPlugin_Filling::APPROXIMATION_DEFAULT());
+
+#endif // BuildAPI_Filling_H_
index b0bddae3b31288f1eaf03c2023adbbee7653e438..96ee58c0edc380bc7a935174e2be1ccde86d279d 100644 (file)
@@ -25,6 +25,7 @@
 
   #include "BuildAPI_Edge.h"
   #include "BuildAPI_Face.h"
+  #include "BuildAPI_Filling.h"
   #include "BuildAPI_Shell.h"
   #include "BuildAPI_SubShapes.h"
   #include "BuildAPI_Vertex.h"
index 3ffcf78ccd22faee6a68abe8972a81ce8013cf68..bf49512102d243af10aa08d12ab5ab4a27ac4565 100644 (file)
@@ -24,6 +24,7 @@ SET(PROJECT_HEADERS
   BuildAPI.h
   BuildAPI_Edge.h
   BuildAPI_Face.h
+  BuildAPI_Filling.h
   BuildAPI_Shell.h
   BuildAPI_SubShapes.h
   BuildAPI_Vertex.h
@@ -33,6 +34,7 @@ SET(PROJECT_HEADERS
 SET(PROJECT_SOURCES
   BuildAPI_Edge.cpp
   BuildAPI_Face.cpp
+  BuildAPI_Filling.cpp
   BuildAPI_Shell.cpp
   BuildAPI_SubShapes.cpp
   BuildAPI_Vertex.cpp
diff --git a/src/BuildPlugin/BuildPlugin_Filling.cpp b/src/BuildPlugin/BuildPlugin_Filling.cpp
new file mode 100644 (file)
index 0000000..a5597f6
--- /dev/null
@@ -0,0 +1,232 @@
+// Copyright (C) 2017-20xx  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "BuildPlugin_Filling.h"
+
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_ResultBody.h>
+
+#include <GeomAlgoAPI_Filling.h>
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_ShapeExplorer.h>
+#include <GeomAPI_Wire.h>
+
+#include <cmath>
+
+struct FillingParameters
+{
+  std::string method;
+  int minDegree;
+  int maxDegree;
+  int nbIter;
+  double tol2D;
+  double tol3D;
+  bool isApprox;
+};
+
+
+//=================================================================================================
+BuildPlugin_Filling::BuildPlugin_Filling()
+{
+}
+
+//=================================================================================================
+void BuildPlugin_Filling::initAttributes()
+{
+  data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId());
+  data()->addAttribute(ADVANCED_OPTIONS_ID(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(METHOD_ID(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(MINIMAL_DEGREE_ID(), ModelAPI_AttributeInteger::typeId());
+  data()->addAttribute(MAXIMAL_DEGREE_ID(), ModelAPI_AttributeInteger::typeId());
+  data()->addAttribute(NUMBER_OF_ITERATIONS_ID(), ModelAPI_AttributeInteger::typeId());
+  data()->addAttribute(TOLERANCE_2D_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(TOLERANCE_3D_ID(), ModelAPI_AttributeDouble::typeId());
+  data()->addAttribute(APPROXIMATION_ID(), ModelAPI_AttributeBoolean::typeId());
+
+  restoreDefaultParameters();
+  string(ADVANCED_OPTIONS_ID())->setValue("");
+}
+
+//=================================================================================================
+void BuildPlugin_Filling::execute()
+{
+  // get parameters of algorithm
+  FillingParameters aParameters;
+  aParameters.method = string(METHOD_ID())->value();
+  aParameters.minDegree = integer(MINIMAL_DEGREE_ID())->value();
+  aParameters.maxDegree = integer(MAXIMAL_DEGREE_ID())->value();
+  aParameters.nbIter = integer(NUMBER_OF_ITERATIONS_ID())->value();
+  aParameters.tol2D = real(TOLERANCE_2D_ID())->value();
+  aParameters.tol3D = real(TOLERANCE_3D_ID())->value();
+  aParameters.isApprox = boolean(APPROXIMATION_ID())->value();
+
+  if (aParameters.minDegree > aParameters.maxDegree) {
+    setError("Error: " + getKind() + " algorithm failed (max deg < min deg).");
+    return;
+  }
+
+  std::shared_ptr<GeomAlgoAPI_Filling> aFilling(
+      new GeomAlgoAPI_Filling(aParameters.minDegree, aParameters.maxDegree, aParameters.nbIter,
+                              aParameters.tol2D, aParameters.tol3D));
+
+  // get base objects list
+  AttributeSelectionListPtr aSelectionList = selectionList(BASE_OBJECTS_ID());
+  if (aSelectionList->size() <= 1)
+    return;
+
+  // collect base shapes
+  for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) {
+    AttributeSelectionPtr aSelection = aSelectionList->value(anIndex);
+    GeomEdgePtr anEdge = toEdge(aSelection->value(), aParameters.method);
+    if (!anEdge) {
+      myLastEdgeStartPoint = GeomPointPtr();
+      myLastEdgeEndPoint = GeomPointPtr();
+      return;
+    }
+    aFilling->add(anEdge);
+  }
+  myLastEdgeStartPoint = GeomPointPtr();
+  myLastEdgeEndPoint = GeomPointPtr();
+
+  // build result
+  aFilling->build(aParameters.isApprox);
+  if (isFailed(aFilling)) {
+    removeResults(0);
+    return;
+  }
+
+  /// store result
+  GeomShapePtr aCreatedFace = aFilling->shape();
+  ResultBodyPtr aResultBody = document()->createBody(data());
+  aResultBody->store(aCreatedFace);
+  // store edges
+  int anEdgeInd = 0;
+  for(GeomAPI_ShapeExplorer anExp(aCreatedFace, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) {
+    GeomShapePtr anEdge = anExp.current();
+    aResultBody->generated(anEdge, "Edge_" + std::to_string((long long)anEdgeInd), ++anEdgeInd);
+  }
+  setResult(aResultBody, 0);
+}
+
+bool BuildPlugin_Filling::isFailed(
+    const std::shared_ptr<GeomAlgoAPI_MakeShape>& theAlgorithm)
+{
+  if (!theAlgorithm->isDone()) {
+    static const std::string aFeatureError = "Error: filling algorithm failed.";
+    setError(aFeatureError);
+    return true;
+  }
+  if (theAlgorithm->shape()->isNull()) {
+    static const std::string aShapeError = "Error: Resulting shape of filling is Null.";
+    setError(aShapeError);
+    return true;
+  }
+  if (!theAlgorithm->isValid()) {
+    std::string aFeatureError = "Error: Resulting shape of filling is not valid.";
+    setError(aFeatureError);
+    return true;
+  }
+  return false;
+}
+
+//=================================================================================================
+void BuildPlugin_Filling::attributeChanged(const std::string& theID)
+{
+  if (theID == ADVANCED_OPTIONS_ID() && string(ADVANCED_OPTIONS_ID())->value().empty()) {
+    // Advanced options flag just unchecked => restore default state of all parameters
+    restoreDefaultParameters();
+  }
+}
+
+//=================================================================================================
+GeomEdgePtr BuildPlugin_Filling::toEdge(const GeomShapePtr& theShape, const std::string& theMethod)
+{
+  GeomEdgePtr anEdge;
+  switch (theShape->shapeType()) {
+  case GeomAPI_Shape::EDGE:
+    anEdge = GeomEdgePtr(new GeomAPI_Edge(theShape));
+    break;
+  case GeomAPI_Shape::WIRE:
+    anEdge = GeomAlgoAPI_ShapeTools::wireToEdge(
+        GeomWirePtr(new GeomAPI_Wire(theShape)));
+    break;
+  default:
+    break;
+  }
+
+  if (!anEdge || anEdge->empty()) {
+    static const std::string aFeatureError =
+        "Error: incorrect type of input feature (edges/wire are supported only).";
+    setError(aFeatureError);
+    return anEdge;
+  }
+
+  // correct edge orientation according to filling method
+  if (theMethod == Method::AUTO_CORRECT_ORIENTATION()) {
+    // check the distance to previous edge boundaries, reverse edge if necessary
+    GeomPointPtr aStartPnt = anEdge->firstPoint();
+    GeomPointPtr aEndPnt = anEdge->lastPoint();
+    bool isReverse = false;
+    if (myLastEdgeStartPoint) {
+      double d1 = myLastEdgeStartPoint->distance(aStartPnt)
+                + myLastEdgeEndPoint->distance(aEndPnt);
+      double d2 = myLastEdgeStartPoint->distance(aEndPnt)
+                + myLastEdgeEndPoint->distance(aStartPnt);
+      if (fabs(d1 - d2) < 1.e-7) {
+        // undefined case => check distance to start point only
+        d1 = myLastEdgeStartPoint->distance(aStartPnt);
+        d2 = myLastEdgeStartPoint->distance(aEndPnt);
+      }
+      isReverse = d2 < d1;
+    }
+
+    if (isReverse) {
+      anEdge->reverse();
+      myLastEdgeStartPoint = aEndPnt;
+      myLastEdgeEndPoint = aStartPnt;
+    } else {
+      myLastEdgeStartPoint = aStartPnt;
+      myLastEdgeEndPoint = aEndPnt;
+    }
+  }
+  else if (theMethod == Method::USE_CURVE_INFORMATION()) {
+    // make all edges FORWARD to avoid reversing the curves by GeomAlgoAPI_Filling algorithm
+    anEdge->setOrientation(GeomAPI_Shape::FORWARD);
+  }
+  return anEdge;
+}
+
+//=================================================================================================
+void BuildPlugin_Filling::restoreDefaultParameters()
+{
+  string(METHOD_ID())->setValue(METHOD_DEFAULT());
+  integer(MINIMAL_DEGREE_ID())->setValue(MINIMAL_DEGREE_DEFAULT());
+  integer(MAXIMAL_DEGREE_ID())->setValue(MAXIMAL_DEGREE_DEFAULT());
+  integer(NUMBER_OF_ITERATIONS_ID())->setValue(NUMBER_OF_ITERATIONS_DEFAULT());
+  real(TOLERANCE_2D_ID())->setValue(TOLERANCE_2D_DEFAULT());
+  real(TOLERANCE_3D_ID())->setValue(TOLERANCE_3D_DEFAULT());
+  boolean(APPROXIMATION_ID())->setValue(APPROXIMATION_DEFAULT());
+}
diff --git a/src/BuildPlugin/BuildPlugin_Filling.h b/src/BuildPlugin/BuildPlugin_Filling.h
new file mode 100644 (file)
index 0000000..e4a23b6
--- /dev/null
@@ -0,0 +1,182 @@
+// Copyright (C) 2014-2017  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef BuildPlugin_Filling_H_
+#define BuildPlugin_Filling_H_
+
+#include "BuildPlugin.h"
+
+#include <ModelAPI_Feature.h>
+
+#include <memory>
+#include <string>
+
+class GeomAlgoAPI_MakeShape;
+class GeomAPI_Edge;
+class GeomAPI_Pnt;
+class GeomAPI_Shape;
+
+/// \class BuildPlugin_Filling
+/// \ingroup Plugins
+/// \brief Feature for creation of face from list of edges (1D objects).
+class BuildPlugin_Filling: public ModelAPI_Feature
+{
+public:
+  /// Use plugin manager for features creation
+  BuildPlugin_Filling();
+
+  /// Feature kind.
+  inline static const std::string& ID()
+  {
+    static const std::string MY_ID("Filling");
+    return MY_ID;
+  }
+
+  /// \return the kind of a feature.
+  BUILDPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = BuildPlugin_Filling::ID();
+    return MY_KIND;
+  }
+
+  /// Attribute name of base objects.
+  inline static const std::string& BASE_OBJECTS_ID()
+  {
+    static const std::string MY_BASE_OBJECTS_ID("base_objects");
+    return MY_BASE_OBJECTS_ID;
+  }
+
+  /// Attribute name of advanced options.
+  inline static const std::string& ADVANCED_OPTIONS_ID()
+  {
+    static const std::string MY_ADVANCED_OPTIONS_ID("advanced_options");
+    return MY_ADVANCED_OPTIONS_ID;
+  }
+
+  /// Attribute name of method of edge orientation.
+  inline static const std::string& METHOD_ID()
+  {
+    static const std::string MY_METHOD_ID("orientation");
+    return MY_METHOD_ID;
+  }
+
+  /// Supported methods for edge orientation correction
+  struct Method {
+    inline static const std::string& AUTO_CORRECT_ORIENTATION()
+    {
+      static const std::string MY_AUTO_CORRECT_ORIENTATION("auto_correct");
+      return MY_AUTO_CORRECT_ORIENTATION;
+    }
+    inline static const std::string& USE_CURVE_INFORMATION()
+    {
+      static const std::string MY_USE_CURVE_INFORMATION("curve_info");
+      return MY_USE_CURVE_INFORMATION;
+    }
+    inline static const std::string& USE_EDGES_ORIENTATION()
+    {
+      static const std::string MY_USE_EDGES_ORIENTATION("edge_orient");
+      return MY_USE_EDGES_ORIENTATION;
+    }
+  };
+
+  /// Attribute name of minimal degree.
+  inline static const std::string& MINIMAL_DEGREE_ID()
+  {
+    static const std::string MY_MINIMAL_DEGREE_ID("min_degree");
+    return MY_MINIMAL_DEGREE_ID;
+  }
+
+  /// Attribute name of maximal degree.
+  inline static const std::string& MAXIMAL_DEGREE_ID()
+  {
+    static const std::string MY_MAXIMAL_DEGREE_ID("max_degree");
+    return MY_MAXIMAL_DEGREE_ID;
+  }
+
+  /// Attribute name of number of iterations.
+  inline static const std::string& NUMBER_OF_ITERATIONS_ID()
+  {
+    static const std::string MY_NUMBER_OF_ITERATIONS_ID("nb_iter");
+    return MY_NUMBER_OF_ITERATIONS_ID;
+  }
+
+  /// Attribute name of 2D tolerance.
+  inline static const std::string& TOLERANCE_2D_ID()
+  {
+    static const std::string MY_TOLERANCE_2D_ID("tol_2d");
+    return MY_TOLERANCE_2D_ID;
+  }
+
+  /// Attribute name of 3D tolerance.
+  inline static const std::string& TOLERANCE_3D_ID()
+  {
+    static const std::string MY_TOLERANCE_3D_ID("tol_3d");
+    return MY_TOLERANCE_3D_ID;
+  }
+
+  /// Attribute name of approximation.
+  inline static const std::string& APPROXIMATION_ID()
+  {
+    static const std::string MY_APPROXIMATION_ID("approximation");
+    return MY_APPROXIMATION_ID;
+  }
+
+  /// Default value of the orientation
+  inline static const std::string& METHOD_DEFAULT() { return Method::AUTO_CORRECT_ORIENTATION(); }
+  /// Default value of minimal degree
+  inline static int MINIMAL_DEGREE_DEFAULT() { return 2; }
+  /// Default value of maximal degree
+  inline static int MAXIMAL_DEGREE_DEFAULT() { return 5; }
+  /// Default value of number of iterations
+  inline static int NUMBER_OF_ITERATIONS_DEFAULT() { return 0; }
+  /// Default value of 2D tolerance
+  inline static double TOLERANCE_2D_DEFAULT() { return 1.e-4; }
+  /// Default value of 3D tolerance
+  inline static double TOLERANCE_3D_DEFAULT() { return 1.e-4; }
+  /// Default value of the approximation attribute
+  inline static bool APPROXIMATION_DEFAULT() { return false; }
+
+  /// Request for initialization of data model of the feature: adding all attributes.
+  BUILDPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Creates a new part document if needed.
+  BUILDPLUGIN_EXPORT virtual void execute();
+
+  /// Called on change of any argument-attribute of this object.
+  /// \param[in] theID identifier of changed attribute.
+  BUILDPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+private:
+  /// Check the filling algorithm is failed
+  bool isFailed(const std::shared_ptr<GeomAlgoAPI_MakeShape>& theAlgorithm);
+
+  /// Convert shape to edge according to construction method
+  std::shared_ptr<GeomAPI_Edge> toEdge(const std::shared_ptr<GeomAPI_Shape>& theShape,
+                                       const std::string& theMethod);
+
+  /// Update values of attributes by their default values
+  void restoreDefaultParameters();
+
+private:
+  std::shared_ptr<GeomAPI_Pnt> myLastEdgeStartPoint;
+  std::shared_ptr<GeomAPI_Pnt> myLastEdgeEndPoint;
+};
+
+#endif
index 8849b519ab7156dd87d467ad107f073a8e62327f..fed1877f9ef64aae4d5bbb77af0669c4114fbee0 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2017-20xx  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
@@ -29,6 +29,7 @@
 #include <BuildPlugin_Face.h>
 #include <BuildPlugin_Shell.h>
 #include <BuildPlugin_SubShapes.h>
+#include <BuildPlugin_Filling.h>
 #include <BuildPlugin_Validators.h>
 
 // the only created instance of this plugin
@@ -68,6 +69,8 @@ FeaturePtr BuildPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new BuildPlugin_Shell());
   } else if(theFeatureID == BuildPlugin_SubShapes::ID()) {
     return FeaturePtr(new BuildPlugin_SubShapes());
+  } else if(theFeatureID == BuildPlugin_Filling::ID()) {
+    return FeaturePtr(new BuildPlugin_Filling());
   }
 
   // Feature of such kind is not found.
index 9331922f701be1acfbbf302788d79d14d7370882..aeba2d0bc6ed8b6ee4d5c775346ad9e3ebdd4a11 100644 (file)
@@ -38,6 +38,7 @@ SET(PROJECT_HEADERS
     BuildPlugin_Face.h
     BuildPlugin_Shell.h
     BuildPlugin_SubShapes.h
+    BuildPlugin_Filling.h
     BuildPlugin_Validators.h
 )
 
@@ -49,6 +50,7 @@ SET(PROJECT_SOURCES
     BuildPlugin_Face.cpp
     BuildPlugin_Shell.cpp
     BuildPlugin_SubShapes.cpp
+    BuildPlugin_Filling.cpp
     BuildPlugin_Validators.cpp
 )
 
@@ -60,6 +62,7 @@ SET(XML_RESOURCES
     face_widget.xml
     shell_widget.xml
     subshapes_widget.xml
+    filling_widget.xml
 )
 
 SET(TEXT_RESOURCES
@@ -92,4 +95,7 @@ ADD_UNIT_TESTS(TestVertex.py
                TestFace.py
                TestShell.py
                TestSubShapes.py
+               TestFilling_ByEdges.py
+               TestFilling_ByWires.py
+               TestFilling_Mixed.py
                Test1920.py)
diff --git a/src/BuildPlugin/Test/TestFilling_ByEdges.py b/src/BuildPlugin/Test/TestFilling_ByEdges.py
new file mode 100644 (file)
index 0000000..ac2468a
--- /dev/null
@@ -0,0 +1,154 @@
+## Copyright (C) 2017-20xx  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
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+# Initialization of the test
+from ModelAPI import *
+from GeomDataAPI import *
+from GeomAlgoAPI import *
+from GeomAPI import *
+
+# Get document
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+
+# Create a part
+aSession.startOperation()
+aPartFeature = aDocument.addFeature("Part")
+aSession.finishOperation()
+aPartResult = modelAPI_ResultPart(aPartFeature.firstResult())
+aPart = aPartResult.partDoc()
+
+# Create first edge in a sketch
+aSession.startOperation()
+aSketch1 = featureToCompositeFeature(aPart.addFeature("Sketch"))
+anOrigin = geomDataAPI_Point(aSketch1.attribute("Origin"))
+anOrigin.setValue(0, 0, 0)
+aDirX = geomDataAPI_Dir(aSketch1.attribute("DirX"))
+aDirX.setValue(1, 0, 0)
+aNorm = geomDataAPI_Dir(aSketch1.attribute("Norm"))
+aNorm.setValue(0, 0, 1)
+# an arc
+anArc = aSketch1.addFeature("SketchArc")
+anArcCenter = geomDataAPI_Point2D(anArc.attribute("center_point"))
+anArcCenter.setValue(1, 1)
+anArcStartPoint = geomDataAPI_Point2D(anArc.attribute("start_point"))
+anArcStartPoint.setValue(20, 5)
+anArcEndPoint = geomDataAPI_Point2D(anArc.attribute("end_point"))
+anArcEndPoint.setValue(5, 20)
+aSession.finishOperation()
+aSketch1Result = aSketch1.firstResult()
+
+# Create second edge in another sketch
+aSession.startOperation()
+aSketch2 = featureToCompositeFeature(aPart.addFeature("Sketch"))
+anOrigin = geomDataAPI_Point(aSketch2.attribute("Origin"))
+anOrigin.setValue(0, 0, 0)
+aDirX = geomDataAPI_Dir(aSketch2.attribute("DirX"))
+aDirX.setValue(1, 0, 0)
+aNorm = geomDataAPI_Dir(aSketch2.attribute("Norm"))
+aNorm.setValue(0, 0.7071067811865475, 0.7071067811865475)
+# a line
+aLine = aSketch2.addFeature("SketchLine")
+aLineStartPoint = geomDataAPI_Point2D(aLine.attribute("StartPoint"))
+aLineStartPoint.setValue(0, 0)
+aLineEndPoint = geomDataAPI_Point2D(aLine.attribute("EndPoint"))
+aLineEndPoint.setValue(20, 20)
+aSession.finishOperation()
+aSketch2Result = aSketch2.firstResult()
+# an edge
+aSession.startOperation()
+anEdge = aPart.addFeature("Edge")
+aBaseObjectsList = anEdge.selectionList("base_objects")
+aBaseObjectsList.append(aSketch2Result, aLine.lastResult().shape())
+aSession.finishOperation()
+
+# Create filling
+aSession.startOperation()
+aFillingFeature = aPart.addFeature("Filling")
+aBaseObjectsList = aFillingFeature.selectionList("base_objects")
+aBaseObjectsList.append(aSketch1Result, anArc.lastResult().shape())
+aSession.finishOperation()
+
+# =============================================================================
+# Test 1. Filling on one edge is failed (error is reported)
+# =============================================================================
+assert(len(aFillingFeature.results()) == 0)
+assert(aFillingFeature.error() != "")
+
+# =============================================================================
+# Test 2. Add another edge, filling should be completed
+# =============================================================================
+aSession.startOperation()
+aBaseObjectsList.append(anEdge.lastResult(), None)
+aSession.finishOperation()
+assert(len(aFillingFeature.results()) > 0)
+
+# =============================================================================
+# Test 3. Change parameters one-by-one and check validity of result
+# =============================================================================
+aSession.startOperation()
+aFillingFeature.string("advanced_options").setValue("true")
+aSession.finishOperation()
+orientations = ["auto_correct", "curve_info", "edge_orient"]
+tolerances = [0.0001, 0.001]
+for ori in orientations:
+  for minDeg in range(2, 4):
+    for maxDeg in range(5, 7):
+      for nbIter in range(0, 3, 2):
+        for tol2d in tolerances:
+          for tol3d in tolerances:
+            for approx in [False, True]:
+              aSession.startOperation()
+              aFillingFeature.string("orientation").setValue(ori)
+              aFillingFeature.integer("min_degree").setValue(minDeg)
+              aFillingFeature.integer("max_degree").setValue(maxDeg)
+              aFillingFeature.integer("nb_iter").setValue(nbIter)
+              aFillingFeature.real("tol_2d").setValue(tol2d)
+              aFillingFeature.real("tol_3d").setValue(tol3d)
+              aFillingFeature.boolean("approximation").setValue(approx)
+              aSession.finishOperation()
+              assert(len(aFillingFeature.results()) > 0), "Filling feature failed with parameters:\n  orientation={}\n  min deg={}\n  max deg={}\n  nb iter={}\n  tol 2d={}\n  tol 3d={}\n  approximation={}".format(ori, minDeg, maxDeg, nbIter, tol2d, tol3d, approx)
+
+# =============================================================================
+# Test 4. Discard parameters to default and add one more edge
+# =============================================================================
+aSession.startOperation()
+aFillingFeature.string("advanced_options").setValue("")
+aSession.finishOperation()
+# new arc
+aSession.startOperation()
+anArc2 = aSketch1.addFeature("SketchArc")
+anArc2Center = geomDataAPI_Point2D(anArc2.attribute("center_point"))
+anArc2Center.setValue(0, -5)
+anArc2StartPoint = geomDataAPI_Point2D(anArc2.attribute("start_point"))
+anArc2StartPoint.setValue(-20, -5)
+anArc2EndPoint = geomDataAPI_Point2D(anArc2.attribute("end_point"))
+anArc2EndPoint.setValue(20, -5)
+aSession.finishOperation()
+aSketch1Result = aSketch1.firstResult()
+# update filling
+aSession.startOperation()
+aPart.setCurrentFeature(aFillingFeature, True)
+aBaseObjectsList.append(aSketch1Result, anArc2.lastResult().shape())
+aSession.finishOperation()
+assert(len(aFillingFeature.results()) > 0)
+
+from salome.shaper import model
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestFilling_ByWires.py b/src/BuildPlugin/Test/TestFilling_ByWires.py
new file mode 100644 (file)
index 0000000..238e776
--- /dev/null
@@ -0,0 +1,152 @@
+## Copyright (C) 2017-20xx  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
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+# Initialization of the test
+from ModelAPI import *
+from GeomDataAPI import *
+from GeomAlgoAPI import *
+from GeomAPI import *
+
+# Get document
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+
+# Create a part
+aSession.startOperation()
+aPartFeature = aDocument.addFeature("Part")
+aSession.finishOperation()
+aPartResult = modelAPI_ResultPart(aPartFeature.firstResult())
+aPart = aPartResult.partDoc()
+
+# Create first wire in a sketch
+aSession.startOperation()
+aSketch1 = featureToCompositeFeature(aPart.addFeature("Sketch"))
+anOrigin = geomDataAPI_Point(aSketch1.attribute("Origin"))
+anOrigin.setValue(0, 0, 0)
+aDirX = geomDataAPI_Dir(aSketch1.attribute("DirX"))
+aDirX.setValue(1, 0, 0)
+aNorm = geomDataAPI_Dir(aSketch1.attribute("Norm"))
+aNorm.setValue(0, 0, 1)
+# arc 1
+anArc1 = aSketch1.addFeature("SketchArc")
+anArcCenter = geomDataAPI_Point2D(anArc1.attribute("center_point"))
+anArcCenter.setValue(1, 1)
+anArcStartPoint = geomDataAPI_Point2D(anArc1.attribute("start_point"))
+anArcStartPoint.setValue(20, 5)
+anArcEndPoint = geomDataAPI_Point2D(anArc1.attribute("end_point"))
+anArcEndPoint.setValue(5, 20)
+# arc 2
+anArc2 = aSketch1.addFeature("SketchArc")
+anArcCenter = geomDataAPI_Point2D(anArc2.attribute("center_point"))
+anArcCenter.setValue(12.5, 12.5)
+anArcStartPoint = geomDataAPI_Point2D(anArc2.attribute("start_point"))
+anArcStartPoint.setValue(5, 20)
+anArcEndPoint = geomDataAPI_Point2D(anArc2.attribute("end_point"))
+anArcEndPoint.setValue(20, 5)
+aSession.finishOperation()
+aSketch1Result = aSketch1.firstResult()
+# a wire
+aSession.startOperation()
+aWire1 = aPart.addFeature("Wire")
+aBaseObjectsList = aWire1.selectionList("base_objects")
+aBaseObjectsList.append(aSketch1Result, anArc1.lastResult().shape())
+aBaseObjectsList.append(aSketch1Result, anArc2.lastResult().shape())
+aSession.finishOperation()
+
+# Create second wire in another sketch
+aSession.startOperation()
+aSketch2 = featureToCompositeFeature(aPart.addFeature("Sketch"))
+anOrigin = geomDataAPI_Point(aSketch2.attribute("Origin"))
+anOrigin.setValue(0, 0, 0)
+aDirX = geomDataAPI_Dir(aSketch2.attribute("DirX"))
+aDirX.setValue(1, 0, 0)
+aNorm = geomDataAPI_Dir(aSketch2.attribute("Norm"))
+aNorm.setValue(0, 0.7071067811865475, 0.7071067811865475)
+# line 1
+aLine1 = aSketch2.addFeature("SketchLine")
+aLineStartPoint = geomDataAPI_Point2D(aLine1.attribute("StartPoint"))
+aLineStartPoint.setValue(30, 0)
+aLineEndPoint = geomDataAPI_Point2D(aLine1.attribute("EndPoint"))
+aLineEndPoint.setValue(20, 20)
+# line 2
+aLine2 = aSketch2.addFeature("SketchLine")
+aLineStartPoint = geomDataAPI_Point2D(aLine2.attribute("StartPoint"))
+aLineStartPoint.setValue(20, 20)
+aLineEndPoint = geomDataAPI_Point2D(aLine2.attribute("EndPoint"))
+aLineEndPoint.setValue(20, 0)
+aSession.finishOperation()
+aSketch2Result = aSketch2.firstResult()
+# a wire
+aSession.startOperation()
+aWire2 = aPart.addFeature("Wire")
+aBaseObjectsList = aWire2.selectionList("base_objects")
+aBaseObjectsList.append(aSketch2Result, aLine1.lastResult().shape())
+aBaseObjectsList.append(aSketch2Result, aLine2.lastResult().shape())
+aSession.finishOperation()
+
+# Create filling
+aSession.startOperation()
+aFillingFeature = aPart.addFeature("Filling")
+aBaseObjectsList = aFillingFeature.selectionList("base_objects")
+aBaseObjectsList.append(aWire1.lastResult(), None)
+aSession.finishOperation()
+
+# =============================================================================
+# Test 1. Filling on one wire is failed (error is reported)
+# =============================================================================
+assert(len(aFillingFeature.results()) == 0)
+assert(aFillingFeature.error() != "")
+
+# =============================================================================
+# Test 2. Add another wire, filling should be completed
+# =============================================================================
+aSession.startOperation()
+aBaseObjectsList.append(aWire2.lastResult(), None)
+aSession.finishOperation()
+assert(len(aFillingFeature.results()) > 0)
+
+# =============================================================================
+# Test 3. Change parameters one-by-one and check validity of result
+# =============================================================================
+aSession.startOperation()
+aFillingFeature.string("advanced_options").setValue("true")
+aSession.finishOperation()
+orientations = ["auto_correct", "curve_info", "edge_orient"]
+tolerances = [0.0001, 0.001]
+for ori in orientations:
+  for minDeg in range(2, 4):
+    for maxDeg in range(5, 7):
+      for nbIter in range(0, 3, 2):
+        for tol2d in tolerances:
+          for tol3d in tolerances:
+            for approx in [False, True]:
+              aSession.startOperation()
+              aFillingFeature.string("orientation").setValue(ori)
+              aFillingFeature.integer("min_degree").setValue(minDeg)
+              aFillingFeature.integer("max_degree").setValue(maxDeg)
+              aFillingFeature.integer("nb_iter").setValue(nbIter)
+              aFillingFeature.real("tol_2d").setValue(tol2d)
+              aFillingFeature.real("tol_3d").setValue(tol3d)
+              aFillingFeature.boolean("approximation").setValue(approx)
+              aSession.finishOperation()
+              assert(len(aFillingFeature.results()) > 0), "Filling feature failed with parameters:\n  orientation={}\n  min deg={}\n  max deg={}\n  nb iter={}\n  tol 2d={}\n  tol 3d={}\n  approximation={}".format(ori, minDeg, maxDeg, nbIter, tol2d, tol3d, approx)
+
+from salome.shaper import model
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/Test/TestFilling_Mixed.py b/src/BuildPlugin/Test/TestFilling_Mixed.py
new file mode 100644 (file)
index 0000000..c6d4365
--- /dev/null
@@ -0,0 +1,168 @@
+## Copyright (C) 2017-20xx  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
+## License as published by the Free Software Foundation; either
+## version 2.1 of the License, or (at your option) any later version.
+##
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public
+## License along with this library; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+## See http:##www.salome-platform.org/ or
+## email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+##
+
+# Initialization of the test
+from ModelAPI import *
+from GeomDataAPI import *
+from GeomAlgoAPI import *
+from GeomAPI import *
+
+# Get document
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+
+# Create a part
+aSession.startOperation()
+aPartFeature = aDocument.addFeature("Part")
+aSession.finishOperation()
+aPartResult = modelAPI_ResultPart(aPartFeature.firstResult())
+aPart = aPartResult.partDoc()
+
+# Create first edge in a sketch
+aSession.startOperation()
+aSketch1 = featureToCompositeFeature(aPart.addFeature("Sketch"))
+anOrigin = geomDataAPI_Point(aSketch1.attribute("Origin"))
+anOrigin.setValue(0, 0, 0)
+aDirX = geomDataAPI_Dir(aSketch1.attribute("DirX"))
+aDirX.setValue(1, 0, 0)
+aNorm = geomDataAPI_Dir(aSketch1.attribute("Norm"))
+aNorm.setValue(0, 0, 1)
+# an arc
+anArc = aSketch1.addFeature("SketchArc")
+anArcCenter = geomDataAPI_Point2D(anArc.attribute("center_point"))
+anArcCenter.setValue(1, 1)
+anArcStartPoint = geomDataAPI_Point2D(anArc.attribute("start_point"))
+anArcStartPoint.setValue(20, 5)
+anArcEndPoint = geomDataAPI_Point2D(anArc.attribute("end_point"))
+anArcEndPoint.setValue(5, 20)
+aSession.finishOperation()
+aSketch1Result = aSketch1.firstResult()
+
+# Create a wire in another sketch
+aSession.startOperation()
+aSketch2 = featureToCompositeFeature(aPart.addFeature("Sketch"))
+anOrigin = geomDataAPI_Point(aSketch2.attribute("Origin"))
+anOrigin.setValue(0, 0, 0)
+aDirX = geomDataAPI_Dir(aSketch2.attribute("DirX"))
+aDirX.setValue(1, 0, 0)
+aNorm = geomDataAPI_Dir(aSketch2.attribute("Norm"))
+aNorm.setValue(0, 0.7071067811865475, 0.7071067811865475)
+# line 1
+aLine1 = aSketch2.addFeature("SketchLine")
+aLineStartPoint = geomDataAPI_Point2D(aLine1.attribute("StartPoint"))
+aLineStartPoint.setValue(0, 0)
+aLineEndPoint = geomDataAPI_Point2D(aLine1.attribute("EndPoint"))
+aLineEndPoint.setValue(10, 10)
+# line 2
+aLine2 = aSketch2.addFeature("SketchLine")
+aLineStartPoint = geomDataAPI_Point2D(aLine2.attribute("StartPoint"))
+aLineStartPoint.setValue(10, 10)
+aLineEndPoint = geomDataAPI_Point2D(aLine2.attribute("EndPoint"))
+aLineEndPoint.setValue(30, 0)
+aSession.finishOperation()
+aSketch2Result = aSketch2.firstResult()
+# a wire
+aSession.startOperation()
+aWire = aPart.addFeature("Wire")
+aBaseObjectsList = aWire.selectionList("base_objects")
+aBaseObjectsList.append(aSketch2Result, aLine1.lastResult().shape())
+aBaseObjectsList.append(aSketch2Result, aLine2.lastResult().shape())
+aSession.finishOperation()
+
+# Create filling
+aSession.startOperation()
+aFillingFeature = aPart.addFeature("Filling")
+aBaseObjectsList = aFillingFeature.selectionList("base_objects")
+aBaseObjectsList.append(aSketch1Result, anArc.lastResult().shape())
+aSession.finishOperation()
+
+# =============================================================================
+# Test 1. Filling on one edge is failed (error is reported)
+# =============================================================================
+assert(len(aFillingFeature.results()) == 0)
+assert(aFillingFeature.error() != "")
+
+# =============================================================================
+# Test 2. Add a wire, filling should be completed
+# =============================================================================
+aSession.startOperation()
+aBaseObjectsList.append(aWire.lastResult(), None)
+aSession.finishOperation()
+assert(len(aFillingFeature.results()) > 0)
+
+# =============================================================================
+# Test 3. Change parameters one-by-one and check validity of result
+# =============================================================================
+aSession.startOperation()
+aFillingFeature.string("advanced_options").setValue("true")
+aSession.finishOperation()
+orientations = ["auto_correct", "curve_info", "edge_orient"]
+tolerances = [0.0001, 0.001]
+for ori in orientations:
+  for minDeg in range(2, 4):
+    for maxDeg in range(5, 7):
+      for nbIter in range(0, 3, 2):
+        for tol2d in tolerances:
+          for tol3d in tolerances:
+            for approx in [False, True]:
+              aSession.startOperation()
+              aFillingFeature.string("orientation").setValue(ori)
+              aFillingFeature.integer("min_degree").setValue(minDeg)
+              aFillingFeature.integer("max_degree").setValue(maxDeg)
+              aFillingFeature.integer("nb_iter").setValue(nbIter)
+              aFillingFeature.real("tol_2d").setValue(tol2d)
+              aFillingFeature.real("tol_3d").setValue(tol3d)
+              aFillingFeature.boolean("approximation").setValue(approx)
+              aSession.finishOperation()
+              assert(len(aFillingFeature.results()) > 0), "Filling feature failed with parameters:\n  orientation={}\n  min deg={}\n  max deg={}\n  nb iter={}\n  tol 2d={}\n  tol 3d={}\n  approximation={}".format(ori, minDeg, maxDeg, nbIter, tol2d, tol3d, approx)
+
+# =============================================================================
+# Test 4. Discard parameters to default and add one more edge
+# =============================================================================
+aSession.startOperation()
+aFillingFeature.string("advanced_options").setValue("")
+aSession.finishOperation()
+# new arc
+aSession.startOperation()
+anArc2 = aSketch1.addFeature("SketchArc")
+anArc2Center = geomDataAPI_Point2D(anArc2.attribute("center_point"))
+anArc2Center.setValue(0, -5)
+anArc2StartPoint = geomDataAPI_Point2D(anArc2.attribute("start_point"))
+anArc2StartPoint.setValue(-20, -5)
+anArc2EndPoint = geomDataAPI_Point2D(anArc2.attribute("end_point"))
+anArc2EndPoint.setValue(20, -5)
+aSession.finishOperation()
+aSketch1Result = aSketch1.firstResult()
+# an edge
+aSession.startOperation()
+aPart.setCurrentFeature(aWire, True)
+anEdge = aPart.addFeature("Edge")
+anEdgeObjectsList = anEdge.selectionList("base_objects")
+anEdgeObjectsList.append(aSketch1Result, anArc2.lastResult().shape())
+aSession.finishOperation()
+# update filling
+aSession.startOperation()
+aPart.setCurrentFeature(aFillingFeature, True)
+aBaseObjectsList.append(anEdge.lastResult(), None)
+aSession.finishOperation()
+assert(len(aFillingFeature.results()) > 0)
+
+from salome.shaper import model
+assert(model.checkPythonDump())
diff --git a/src/BuildPlugin/filling_widget.xml b/src/BuildPlugin/filling_widget.xml
new file mode 100644 (file)
index 0000000..a9e3930
--- /dev/null
@@ -0,0 +1,47 @@
+<!--
+Copyright (C) 2017-20xx  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
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+See http:##www.salome-platform.org/ or
+email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+-->
+
+<source>
+  <multi_selector id="base_objects"
+                  label="Segments and wires:"
+                  tooltip="Select edges or wires."
+                  type_choice="edges wires"
+                  concealment="false">
+    <validator id="PartSet_DifferentObjects"/>
+  </multi_selector>
+  <optionalbox id="advanced_options" title="Advanced options">
+    <switch id="orientation" label="Orientation">
+      <case id="auto_correct" title="Auto-correct edges orientation"/>
+      <case id="curve_info" title="Use curve information"/>
+      <case id="edge_orient" title="Use edges orientation"/>
+    </switch>
+    <integervalue id="min_degree" label="Min deg" min="1" default="2">
+      <validator id="GeomValidators_LessOrEqual" parameters="max_degree"/>
+    </integervalue>
+    <integervalue id="max_degree" label="Max deg" min="1" default="5">
+      <validator id="GeomValidators_GreaterOrEqual" parameters="min_degree"/>
+    </integervalue>
+    <integervalue id="nb_iter" label="Nb iter" min="0" default="0"/>
+    <doublevalue id="tol_2d" label="Tol 2D" min="0" default="0.0001" step="0.0001"/>
+    <doublevalue id="tol_3d" label="Tol 3D" min="0" default="0.0001" step="0.0001"/>
+    <boolvalue id="approximation" label="Approximation"/>
+  </optionalbox>
+</source>
diff --git a/src/BuildPlugin/icons/feature_filling.png b/src/BuildPlugin/icons/feature_filling.png
new file mode 100644 (file)
index 0000000..ef16696
Binary files /dev/null and b/src/BuildPlugin/icons/feature_filling.png differ
index e73d1da3cba123ee46e7e3da1376de9141c2e7b4..4fde67f69a20af2cad4be7889dcbd802b7667517 100644 (file)
@@ -43,5 +43,10 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
         <source path="subshapes_widget.xml"/>
       </feature>
     </group>
-   </workbench>
+    <group id="Advanced">
+      <feature id="Filling" title="Filling" tooltip="Create face from list of edges" icon="icons/Build/feature_filling.png">
+        <source path="filling_widget.xml"/>
+      </feature>
+    </group>
+  </workbench>
 </plugin>
index f66a6a1e6f8e9351cfa20cd7e1d0ed40292f488e..b634f3dcc28f17cef09b31e721bfc28ccece0b07 100644 (file)
@@ -103,6 +103,12 @@ bool GeomAPI_Shape::isEdge() const
   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_EDGE;
 }
 
+bool GeomAPI_Shape::isWire() const
+{
+  const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
+  return !aShape.IsNull() && aShape.ShapeType() == TopAbs_WIRE;
+}
+
 bool GeomAPI_Shape::isFace() const
 {
   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
@@ -408,6 +414,11 @@ void GeomAPI_Shape::setOrientation(const GeomAPI_Shape::Orientation theOrientati
   }
 }
 
+void GeomAPI_Shape::reverse()
+{
+  MY_SHAPE->Reverse();
+}
+
 bool GeomAPI_Shape::isSubShape(const std::shared_ptr<GeomAPI_Shape> theShape,
                                const bool theCheckOrientation) const
 {
index 242a85bc7fcabca5368a687a771ae9bd57e27294..7138a776dce347f6dacc99dafde533c9fd8bfe75 100644 (file)
@@ -78,6 +78,10 @@ public:
   GEOMAPI_EXPORT
   virtual bool isEdge() const;
 
+  /// Returns whether the shape is a wire
+  GEOMAPI_EXPORT
+  virtual bool isWire() const;
+
   /// Returns whether the shape is a face
   GEOMAPI_EXPORT
   virtual bool isFace() const;
@@ -123,6 +127,9 @@ public:
   /// Sets the shape orientation.
   GEOMAPI_EXPORT virtual void setOrientation(const Orientation theOrientation);
 
+  /// Reverse shape
+  GEOMAPI_EXPORT virtual void reverse();
+
   /// \return true if passed shape is a sub-shape of this shape.
   /// \param theShape shape to search.
   /// \param theCheckOrientation if false, returns true even if orientation of shape differs
index 039be40a873ffb450f9b7ad609a0b1bffd9c2453..e750f3ac59270b32f64ac6c65de31e72a9ec8bfa 100644 (file)
@@ -33,3 +33,11 @@ GeomAPI_Wire::GeomAPI_Wire()
 
   this->setImpl(aWire);
 }
+
+//==================================================================================================
+GeomAPI_Wire::GeomAPI_Wire(const std::shared_ptr<GeomAPI_Shape>& theShape)
+{
+  if (!theShape->isNull() && theShape->isWire()) {
+    setImpl(new TopoDS_Shape(theShape->impl<TopoDS_Shape>()));
+  }
+}
index 837039d4c15cc1473ceae00fb560bf35e80ac324..888e9b19c4165e2853fa7a1291118ebf62e3b5a1 100644 (file)
@@ -31,7 +31,11 @@ class GeomAPI_Wire: public GeomAPI_Shape
 public:
   /// Makes an undefined Wire.
   GEOMAPI_EXPORT GeomAPI_Wire();
+
+  /// Creation of wire by the wire-shape
+  GEOMAPI_EXPORT GeomAPI_Wire(const std::shared_ptr<GeomAPI_Shape>& theShape);
 };
 
-#endif
+typedef std::shared_ptr<GeomAPI_Wire> GeomWirePtr;
 
+#endif
index c9f493d712e08a7e8cc469a3a8e322bdede4aa60..81c0d1f0f422b740224e1c9b8013d78a52bdcc11 100644 (file)
@@ -76,6 +76,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_UnifySameDomain.h
     GeomAlgoAPI_Fillet.h
     GeomAlgoAPI_SortListOfShapes.h
+    GeomAlgoAPI_Filling.h
 )
 
 SET(PROJECT_SOURCES
@@ -130,6 +131,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_UnifySameDomain.cpp
     GeomAlgoAPI_Fillet.cpp
     GeomAlgoAPI_SortListOfShapes.cpp
+    GeomAlgoAPI_Filling.cpp
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Filling.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Filling.cpp
new file mode 100644 (file)
index 0000000..338409a
--- /dev/null
@@ -0,0 +1,191 @@
+// Copyright (C) 2017-20xx  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "GeomAlgoAPI_Filling.h"
+
+#include <BRep_Tool.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <Geom_BSplineCurve.hxx>
+#include <Geom_BSplineSurface.hxx>
+#include <Geom_TrimmedCurve.hxx>
+#include <GeomAPI_PointsToBSplineSurface.hxx>
+#include <GeomFill_AppSurf.hxx>
+#include <GeomFill_Line.hxx>
+#include <GeomFill_SectionGenerator.hxx>
+#include <Precision.hxx>
+#include <ShapeFix_Face.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+
+static void edgesToCurves(const std::list<GeomEdgePtr>& theEdges,
+                          std::list<Handle(Geom_Curve)>& theCurves)
+{
+  for (std::list<GeomEdgePtr>::const_iterator anIt = theEdges.begin();
+       anIt != theEdges.end(); ++anIt) {
+    const TopoDS_Edge& anEdge = (*anIt)->impl<TopoDS_Edge>();
+    if (BRep_Tool::Degenerated(anEdge))
+      continue;
+
+    double aFirst, aLast;
+    Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
+
+    aCurve = new Geom_TrimmedCurve(aCurve, aFirst, aLast);
+    if (anEdge.Orientation() == TopAbs_REVERSED)
+      aCurve->Reverse();
+
+    theCurves.push_back(aCurve);
+  }
+}
+
+
+GeomAlgoAPI_Filling::GeomAlgoAPI_Filling(const int theMinDegree,
+                                         const int theMaxDegree,
+                                         const int theNbIter,
+                                         const double theTol2D,
+                                         const double theTol3D)
+  : myMinDegree(theMinDegree),
+    myMaxDegree(theMaxDegree),
+    myNbIter(theNbIter),
+    myTol2D(theTol2D),
+    myTol3D(theTol3D)
+{
+}
+
+void GeomAlgoAPI_Filling::add(const GeomEdgePtr theEdge)
+{
+  myConstraints.push_back(theEdge);
+}
+
+void GeomAlgoAPI_Filling::build(bool isApproximate)
+{
+  if (myConstraints.size() <= 1) // not enough edges
+    return;
+
+  if (isApproximate)
+    buildByControlPoints();
+  else
+    buildByEdges();
+}
+
+void GeomAlgoAPI_Filling::buildByEdges()
+{
+  GeomFill_SectionGenerator aSection;
+
+  // obtain section curves
+  std::list<Handle(Geom_Curve)> aCurves;
+  edgesToCurves(myConstraints, aCurves);
+  for (std::list<Handle(Geom_Curve)>::iterator anIt = aCurves.begin();
+       anIt != aCurves.end(); ++anIt)
+    aSection.AddCurve(*anIt);
+
+  // a 'tolerance' is used to compare 2 knots
+  aSection.Perform(Precision::PConfusion());
+  Handle(GeomFill_Line) aLine = new GeomFill_Line((int)aCurves.size());
+
+  // perform filling by sections
+  GeomFill_AppSurf anAppSurf(myMinDegree, myMaxDegree, myTol3D, myTol2D, myNbIter);
+  anAppSurf.Perform(aLine, aSection);
+  if (!anAppSurf.IsDone())
+    return;
+
+  // build calculated surface
+  Standard_Integer UDegree, VDegree, NbUPoles, NbVPoles, NbUKnots, NbVKnots;
+  anAppSurf.SurfShape(UDegree, VDegree, NbUPoles, NbVPoles, NbUKnots, NbVKnots);
+  Handle(Geom_BSplineSurface) GBS = new Geom_BSplineSurface(
+    anAppSurf.SurfPoles(), anAppSurf.SurfWeights(), anAppSurf.SurfUKnots(), anAppSurf.SurfVKnots(),
+    anAppSurf.SurfUMults(), anAppSurf.SurfVMults(), anAppSurf.UDegree(), anAppSurf.VDegree());
+
+  if (GBS.IsNull())
+    return;
+
+  // store result
+  TopoDS_Face aFace = BRepBuilderAPI_MakeFace(GBS, Precision::Confusion());
+  std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+  aShape->setImpl(new TopoDS_Shape(aFace));
+  setShape(aShape);
+  setDone(true);
+}
+
+static Handle(Geom_Curve) removeTrim(const Handle(Geom_Curve)& theCurve)
+{
+  Handle(Geom_Curve) aCurve = theCurve;
+  Handle(Geom_TrimmedCurve) aTC = Handle(Geom_TrimmedCurve)::DownCast(aCurve);
+  while (!aTC.IsNull()) {
+    aCurve = aTC->BasisCurve();
+    aTC = Handle(Geom_TrimmedCurve)::DownCast(aCurve);
+  }
+  return aCurve;
+}
+
+void GeomAlgoAPI_Filling::buildByControlPoints()
+{
+  // obtain section curves
+  std::list<Handle(Geom_Curve)> aCurves;
+  edgesToCurves(myConstraints, aCurves);
+
+  // compute maximal number of poles in B-spline curves
+  int aMaxPoles = 0;
+  std::list<Handle(Geom_Curve)>::iterator anIt = aCurves.begin();
+  for (; anIt != aCurves.end(); ++anIt) {
+    Handle(Geom_BSplineCurve) aBC = Handle(Geom_BSplineCurve)::DownCast(removeTrim(*anIt));
+    if (!aBC.IsNull())
+      aMaxPoles = Max(aMaxPoles, aBC->NbPoles());
+  }
+
+  // prepare array of points for creation bspline surface
+  // size of this array: by U parameter - number of curves,
+  // by V parameter - determ using MaxNbPoles but it's
+  // value must be between 21(min) and 101(max)
+  int aNbSections = (int) aCurves.size();
+  int aNbPntInSection = Max(21, 2 * aMaxPoles - 1);
+  TColgp_Array2OfPnt aPoints(1, aNbSections, 1, aNbPntInSection);
+  anIt = aCurves.begin();
+  for (int i = 1; anIt != aCurves.end(); ++i, ++anIt) {
+    Handle(Geom_Curve) aC = *anIt;
+    double fp = aC->FirstParameter();
+    double lp = aC->LastParameter();
+    double dp = (lp - fp) / (aNbPntInSection - 1);
+
+    gp_Pnt aPnt;
+    for (int j = 0; j < aNbPntInSection; j++) {
+      aC->D0(fp + dp * j, aPnt);
+      aPoints.SetValue(i, j+1, aPnt);
+    }
+  }
+
+  // convert a grid of points to B-spline surface
+  GeomAPI_PointsToBSplineSurface aPTB(aPoints, myMinDegree, myMaxDegree, GeomAbs_C2, myTol3D);
+  Handle(Geom_BSplineSurface) aBS = aPTB.Surface();
+  if (aBS.IsNull())
+    return;
+
+  // fix face orientation
+  TopoDS_Face aFace = BRepBuilderAPI_MakeFace(aBS, Precision::Confusion());
+  Handle(ShapeFix_Face) aFix = new ShapeFix_Face(aFace);
+  aFix->Perform();
+  aFix->FixOrientation();
+  aFace = aFix->Face();
+
+  // store result
+  std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape());
+  aShape->setImpl(new TopoDS_Shape(aFace));
+  setShape(aShape);
+  setDone(true);
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Filling.h b/src/GeomAlgoAPI/GeomAlgoAPI_Filling.h
new file mode 100644 (file)
index 0000000..99275bf
--- /dev/null
@@ -0,0 +1,65 @@
+// Copyright (C) 2017-20xx  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef GeomAlgoAPI_Filling_H_
+#define GeomAlgoAPI_Filling_H_
+
+#include <GeomAlgoAPI.h>
+#include <GeomAlgoAPI_MakeShape.h>
+
+#include <GeomAPI_Edge.h>
+
+/// \class GeomAlgoAPI_Filling
+/// \ingroup DataAlgo
+/// \brief Perform building face by the set of edges/wires
+class GeomAlgoAPI_Filling : public GeomAlgoAPI_MakeShape
+{
+public:
+  /// \brief Construct filling operation by the parameters.
+  GEOMALGOAPI_EXPORT GeomAlgoAPI_Filling(const int theMinDegree = 2,
+                                         const int theMaxDegree = 5,
+                                         const int theNbIter    = 0,
+                                         const double theTol2D = 1.e-4,
+                                         const double theTol3D = 1.e-4);
+
+  /// \brief Add an edge to constrain filling (the result face should pass through the edge)
+  GEOMALGOAPI_EXPORT void add(const GeomEdgePtr theEdge);
+
+  /// \brief Perform filling operation
+  /// \param isApproximate approximate curves before building a face
+  GEOMALGOAPI_EXPORT void build(bool isApproximate = false);
+
+private:
+  /// \brief Perform filling using the given edges
+  void buildByEdges();
+
+  /// \brief Perform filling by a set of points calculated on each edge
+  void buildByControlPoints();
+
+private:
+  int myMinDegree;
+  int myMaxDegree;
+  int myNbIter;
+  double myTol2D;
+  double myTol3D;
+  std::list<GeomEdgePtr> myConstraints;
+};
+
+#endif
index fd854afb74009ba5ea90e2adfdfd31eeaece85ed..60b9fe4531168004468d09c66bee1393db19ca88 100644 (file)
 #include <GeomAPI_Face.h>
 #include <GeomAPI_Pln.h>
 #include <GeomAPI_Pnt.h>
+#include <GeomAPI_Wire.h>
 
 #include <Bnd_Box.hxx>
 #include <BOPTools.hxx>
 #include <BRep_Builder.hxx>
 #include <BRepAdaptor_Curve.hxx>
+#include <BRepAlgo.hxx>
 #include <BRepAlgo_FaceRestrictor.hxx>
 #include <BRepBndLib.hxx>
 #include <BRepBuilderAPI_FindPlane.hxx>
@@ -953,3 +955,17 @@ std::shared_ptr<GeomAPI_Dir> GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape(
                                                     aCentreOfMassPoint.Z()-aPoint.Z()));
   return aDir;
 }
+
+//==================================================================================================
+std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_ShapeTools::wireToEdge(
+      const std::shared_ptr<GeomAPI_Wire>& theWire)
+{
+  GeomEdgePtr anEdge;
+  if (theWire) {
+    const TopoDS_Wire& aWire = theWire->impl<TopoDS_Wire>();
+    TopoDS_Edge aNewEdge = BRepAlgo::ConcatenateWireC0(aWire);
+    anEdge = GeomEdgePtr(new GeomAPI_Edge);
+    anEdge->setImpl(new TopoDS_Edge(aNewEdge));
+  }
+  return anEdge;
+}
index 7745c4011f5640a6053f3b7635eda575dcbf3866..42f87c8626ce40d8725329917da8a7305cc5d41c 100644 (file)
@@ -36,6 +36,7 @@ class GeomAPI_Face;
 class GeomAPI_PlanarEdges;
 class GeomAPI_Pln;
 class GeomAPI_Pnt;
+class GeomAPI_Wire;
 class GeomDataAPI_Point2D;
 class ModelAPI_Object;
 
@@ -174,6 +175,10 @@ public:
   GEOMALGOAPI_EXPORT static std::shared_ptr<GeomAPI_Dir> buildDirFromAxisAndShape(
                                     const std::shared_ptr<GeomAPI_Shape> theBaseShape,
                                     const std::shared_ptr<GeomAPI_Ax1> theAxis);
+
+  /// \brief Reapproximate a wire to build a single edge
+  GEOMALGOAPI_EXPORT static std::shared_ptr<GeomAPI_Edge> wireToEdge(
+      const std::shared_ptr<GeomAPI_Wire>& theWire);
 };
 
 #endif
index 92bed77b3f47d050ad541238a79e000e765c2661..3b343b2926f792021ec168c46ce8dc59e0c782ea 100644 (file)
@@ -38,6 +38,7 @@ SET(PROJECT_HEADERS
     GeomValidators_Different.h
     GeomValidators_IntersectionSelection.h
     GeomValidators_MinObjectsSelected.h
+    GeomValidators_ValueOrder.h
 )
 
 SET(PROJECT_SOURCES
@@ -57,6 +58,7 @@ SET(PROJECT_SOURCES
     GeomValidators_Different.cpp
     GeomValidators_IntersectionSelection.cpp
     GeomValidators_MinObjectsSelected.cpp
+    GeomValidators_ValueOrder.cpp
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/GeomValidators/GeomValidators_ValueOrder.cpp b/src/GeomValidators/GeomValidators_ValueOrder.cpp
new file mode 100644 (file)
index 0000000..0365438
--- /dev/null
@@ -0,0 +1,132 @@
+// Copyright (C) 2017-20xx  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "GeomValidators_ValueOrder.h"
+
+#include <Config_PropManager.h>
+#include <Events_InfoMessage.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+static double attributeValue(AttributePtr theAttr)
+{
+  AttributeIntegerPtr anIntAttr = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttr);
+  if (anIntAttr)
+    return (double)anIntAttr->value();
+  AttributeDoublePtr aDoubleAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttr);
+  if (aDoubleAttr)
+    return aDoubleAttr->value();
+  return 0.0;
+}
+
+static bool isGreaterOrEqual(AttributePtr theFirstArg, AttributePtr theSecondArg)
+{
+  if (theFirstArg && theFirstArg->isInitialized() &&
+      theSecondArg && theSecondArg->isInitialized())
+    return attributeValue(theFirstArg) >= attributeValue(theSecondArg);
+  return false;
+}
+
+static bool isLessOrEqual(AttributePtr theFirstArg, AttributePtr theSecondArg)
+{
+  if (theFirstArg && theFirstArg->isInitialized() &&
+      theSecondArg && theSecondArg->isInitialized())
+    return attributeValue(theFirstArg) <= attributeValue(theSecondArg);
+  return false;
+}
+
+// Check the attributes are satisfy theCompare function
+static bool isValidOrder(const AttributePtr& theAttribute,
+                         const std::list<std::string>& theArguments,
+                         Events_InfoMessage& theError,
+                         bool (*theCompare)(AttributePtr, AttributePtr))
+{
+  std::string anAttrType = theAttribute->attributeType();
+  if (anAttrType != ModelAPI_AttributeDouble::typeId() &&
+      anAttrType != ModelAPI_AttributeInteger::typeId()) {
+    theError = "Unsupported attribute type (integer or double applicable)";
+    return false;
+  }
+
+  FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
+  if (!anOwner) {
+    theError = "Attribute without owner";
+    return false;
+  }
+
+  for (std::list<std::string>::const_iterator anIt = theArguments.begin();
+       anIt != theArguments.end(); ++anIt) {
+    // check the argument links to the attribute of the current feature
+    AttributePtr aCurAttr = anOwner->attribute(*anIt);
+    if (!aCurAttr) {
+      theError = "Arguments should be names of attributes of current feature";
+      return false;
+    }
+
+    // compare values
+    if (!(*theCompare)(theAttribute, aCurAttr)) {
+      theError = "Attributes have incorrect order";
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+
+/// Global instance for validators factory
+GeomValidators_GreaterOrEqual MY_GEQ_INSTANCE;
+GeomValidators_LessOrEqual MY_LEQ_INSTANCE;
+
+GeomValidators_GreaterOrEqual::GeomValidators_GreaterOrEqual()
+{
+  // this validator is registered in the factory on this library loading
+  SessionPtr aMgr = ModelAPI_Session::get();
+  ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
+  aFactory->registerValidator("GeomValidators_GreaterOrEqual", this);
+}
+
+bool GeomValidators_GreaterOrEqual::isValid(const AttributePtr& theAttribute,
+                                            const std::list<std::string>& theArguments,
+                                            Events_InfoMessage& theError) const
+{
+  return isValidOrder(theAttribute, theArguments, theError, &isGreaterOrEqual);
+}
+
+
+
+GeomValidators_LessOrEqual::GeomValidators_LessOrEqual()
+{
+  // this validator is registered in the factory on this library loading
+  SessionPtr aMgr = ModelAPI_Session::get();
+  ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
+  aFactory->registerValidator("GeomValidators_LessOrEqual", this);
+}
+
+bool GeomValidators_LessOrEqual::isValid(const AttributePtr& theAttribute,
+                                         const std::list<std::string>& theArguments,
+                                         Events_InfoMessage& theError) const
+{
+  return isValidOrder(theAttribute, theArguments, theError, &isLessOrEqual);
+}
diff --git a/src/GeomValidators/GeomValidators_ValueOrder.h b/src/GeomValidators/GeomValidators_ValueOrder.h
new file mode 100644 (file)
index 0000000..f4dd4fb
--- /dev/null
@@ -0,0 +1,63 @@
+// Copyright (C) 2017-20xx  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
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or
+// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef GeomValidators_ValueOrder_H
+#define GeomValidators_ValueOrder_H
+
+#include <GeomValidators.h>
+#include <ModelAPI_AttributeValidator.h>
+
+/**
+ * Validates that the integer/double attribute is greater or equal to another attribute values
+ */
+class GeomValidators_GreaterOrEqual : public ModelAPI_AttributeValidator
+{
+public:
+  //! Constructor for only one instance per application: will register the validator
+  GeomValidators_GreaterOrEqual();
+  //! returns true if attribute is valid
+  //! \param[in] theAttribute the checked attribute
+  //! \param[in] theArguments arguments of the attribute
+  //! \param[out] theError error message.
+  GEOMVALIDATORS_EXPORT virtual bool isValid(const AttributePtr& theAttribute,
+                                             const std::list<std::string>& theArguments,
+                                             Events_InfoMessage& theError) const;
+
+};
+
+/**
+ * Validates that the integer/double attribute is less or equal to another attribute values
+ */
+class GeomValidators_LessOrEqual : public ModelAPI_AttributeValidator
+{
+public:
+  //! Constructor for only one instance per application: will register the validator
+  GeomValidators_LessOrEqual();
+  //! returns true if attribute is valid
+  //! \param[in] theAttribute the checked attribute
+  //! \param[in] theArguments arguments of the attribute
+  //! \param[out] theError error message.
+  GEOMVALIDATORS_EXPORT virtual bool isValid(const AttributePtr& theAttribute,
+                                             const std::list<std::string>& theArguments,
+                                             Events_InfoMessage& theError) const;
+
+};
+
+#endif
index 20e8ff20f36c221f489705c00c7b8ca20b1eb388..89546d145200f2a34446018bd4e34e5201c14e50 100644 (file)
@@ -975,36 +975,56 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
 ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
     const std::shared_ptr<ModelAPI_AttributeSelectionList>& theAttrSelList)
 {
-  myDumpBuffer << "[";
+  static const int aThreshold = 2;
+  // if number of elements in the list if greater than a threshold,
+  // dump it in a separate line with specific name
+  std::string aDumped = myDumpBuffer.str();
 
-  GeomShapePtr aShape;
-  std::string aShapeTypeStr;
+  if (aDumped.empty() || theAttrSelList->size() <= aThreshold) {
+    myDumpBuffer << "[";
 
-  bool isAdded = false;
+    GeomShapePtr aShape;
+    std::string aShapeTypeStr;
 
-  for(int anIndex = 0; anIndex < theAttrSelList->size(); ++anIndex) {
-    AttributeSelectionPtr anAttribute = theAttrSelList->value(anIndex);
-    aShape = anAttribute->value();
-    if(!aShape.get()) {
-      ResultPtr aContext = anAttribute->context();
-      if (aContext.get())
-        aShape = aContext->shape();
-    }
+    bool isAdded = false;
 
-    if(!aShape.get()) {
-      continue;
-    }
+    for(int anIndex = 0; anIndex < theAttrSelList->size(); ++anIndex) {
+      AttributeSelectionPtr anAttribute = theAttrSelList->value(anIndex);
+      aShape = anAttribute->value();
+      if(!aShape.get()) {
+        ResultPtr aContext = anAttribute->context();
+        if (aContext.get())
+          aShape = aContext->shape();
+      }
 
-    if(isAdded) {
-      myDumpBuffer << ", ";
-    } else {
-      isAdded = true;
+      if(!aShape.get()) {
+        continue;
+      }
+
+      if(isAdded) {
+        myDumpBuffer << ", ";
+      } else {
+        isAdded = true;
+      }
+      myDumpBuffer << "model.selection(\"" <<
+        aShape->shapeTypeStr() << "\", \"" << anAttribute->namingName() << "\")";
     }
-    myDumpBuffer << "model.selection(\"" <<
-      aShape->shapeTypeStr() << "\", \"" << anAttribute->namingName() << "\")";
-  }
 
-  myDumpBuffer << "]";
+    myDumpBuffer << "]";
+  } else {
+    // clear buffer and store list "as is"
+    myDumpBuffer.str("");
+    *this << theAttrSelList;
+    // save buffer and clear it again
+    std::string aDumpedList = myDumpBuffer.str();
+    myDumpBuffer.str("");
+    // obtain name of list
+    FeaturePtr anOwner = ModelAPI_Feature::feature(theAttrSelList->owner());
+    std::string aListName = name(anOwner) + "_objects";
+    // store all previous data
+    myDumpBuffer << aListName << " = " << aDumpedList << std::endl
+                 << aDumped << aListName;
+  }
   return *this;
 }
 
index 1556669bf59169b91825a4d74842d646bffad431..ed30370e42f3c16d807a8be98fa02c05b6e6afe1 100644 (file)
@@ -3,3 +3,4 @@
 
 from BuildAPI import addVertex, addEdge, addWire, addFace, addShell
 from BuildAPI import addSubShapes
+from BuildAPI import addFilling