From 96aea8545b2bbcbe31790c01a3aa13f3b87d5d4f Mon Sep 17 00:00:00 2001 From: marioalexis Date: Mon, 30 Dec 2024 17:45:38 -0300 Subject: [PATCH 1/2] App: Assign constraints for integer and float properties using dictionary --- src/App/PropertyStandard.cpp | 146 +++++++++++++++++++++++------------ 1 file changed, 95 insertions(+), 51 deletions(-) diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 606b47e07f..96e3984005 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "PropertyStandard.h" #include "Application.h" @@ -663,7 +664,7 @@ long PropertyIntegerConstraint::getMinimum() const return _ConstStruct->LowerBound; } // return the min of int, not long - return std::numeric_limits::min(); + return std::numeric_limits::lowest(); } long PropertyIntegerConstraint::getMaximum() const @@ -700,41 +701,64 @@ void PropertyIntegerConstraint::setPyObject(PyObject* value) _lValue = temp; hasSetValue(); } - else if (PyTuple_Check(value) && PyTuple_Size(value) == 4) { - long values[4]; - for (int i = 0; i < 4; i++) { - PyObject* item; - item = PyTuple_GetItem(value, i); - if (PyLong_Check(item)) { - values[i] = PyLong_AsLong(item); + else { + long valConstr[] = {0, + std::numeric_limits::lowest(), + std::numeric_limits::max(), + 1}; + + if (PyDict_Check(value)) { + Py::Tuple dummy; + static const std::array kw = {"value", + "min", + "max", + "step", + nullptr}; + + if (!Base::Wrapped_ParseTupleAndKeywords(dummy.ptr(), + value, + "l|lll", + kw, + &(valConstr[0]), + &(valConstr[1]), + &(valConstr[2]), + &(valConstr[3]))) { + throw Py::Exception(); } - else { - throw Base::TypeError("Type in tuple must be int"); + } + else if (PyTuple_Check(value)) { + if (!PyArg_ParseTuple(value, + "llll", + &(valConstr[0]), + &(valConstr[1]), + &(valConstr[2]), + &(valConstr[3]))) { + throw Py::Exception(); } } + else { + std::string error = std::string("type must be int, dict or tuple, not "); + error += value->ob_type->tp_name; + throw Base::TypeError(error); + } Constraints* c = new Constraints(); c->setDeletable(true); - c->LowerBound = values[1]; - c->UpperBound = values[2]; - c->StepSize = std::max(1, values[3]); - if (values[0] > c->UpperBound) { - values[0] = c->UpperBound; + c->LowerBound = valConstr[1]; + c->UpperBound = valConstr[2]; + c->StepSize = std::max(1, valConstr[3]); + if (valConstr[0] > c->UpperBound) { + valConstr[0] = c->UpperBound; } - else if (values[0] < c->LowerBound) { - values[0] = c->LowerBound; + else if (valConstr[0] < c->LowerBound) { + valConstr[0] = c->LowerBound; } setConstraints(c); aboutToSetValue(); - _lValue = values[0]; + _lValue = valConstr[0]; hasSetValue(); } - else { - std::string error = std::string("type must be int, not "); - error += value->ob_type->tp_name; - throw Base::TypeError(error); - } } //************************************************************************** @@ -1122,7 +1146,7 @@ double PropertyFloatConstraint::getMinimum() const if (_ConstStruct) { return _ConstStruct->LowerBound; } - return std::numeric_limits::min(); + return std::numeric_limits::lowest(); } double PropertyFloatConstraint::getMaximum() const @@ -1159,7 +1183,7 @@ void PropertyFloatConstraint::setPyObject(PyObject* value) hasSetValue(); } else if (PyLong_Check(value)) { - double temp = (double)PyLong_AsLong(value); + double temp = static_cast(PyLong_AsLong(value)); if (_ConstStruct) { if (temp > _ConstStruct->UpperBound) { temp = _ConstStruct->UpperBound; @@ -1173,23 +1197,48 @@ void PropertyFloatConstraint::setPyObject(PyObject* value) _dValue = temp; hasSetValue(); } - else if (PyTuple_Check(value) && PyTuple_Size(value) == 4) { - double values[4]; - for (int i = 0; i < 4; i++) { - PyObject* item; - item = PyTuple_GetItem(value, i); - if (PyFloat_Check(item)) { - values[i] = PyFloat_AsDouble(item); - } - else if (PyLong_Check(item)) { - values[i] = PyLong_AsLong(item); - } - else { - throw Base::TypeError("Type in tuple must be float or int"); + else { + double valConstr[] = {0.0, + std::numeric_limits::lowest(), + std::numeric_limits::max(), + 1.0}; + + if (PyDict_Check(value)) { + Py::Tuple dummy; + static const std::array kw = {"value", + "min", + "max", + "step", + nullptr}; + + if (!Base::Wrapped_ParseTupleAndKeywords(dummy.ptr(), + value, + "d|ddd", + kw, + &(valConstr[0]), + &(valConstr[1]), + &(valConstr[2]), + &(valConstr[3]))) { + throw Py::Exception(); } } + else if (PyTuple_Check(value)) { + if (!PyArg_ParseTuple(value, + "dddd", + &(valConstr[0]), + &(valConstr[1]), + &(valConstr[2]), + &(valConstr[3]))) { + throw Py::Exception(); + } + } + else { + std::string error = std::string("type must be float, dict or tuple, not "); + error += value->ob_type->tp_name; + throw Base::TypeError(error); + } - double stepSize = values[3]; + double stepSize = valConstr[3]; // need a value > 0 if (stepSize < DBL_EPSILON) { throw Base::ValueError("Step size must be greater than zero"); @@ -1197,26 +1246,21 @@ void PropertyFloatConstraint::setPyObject(PyObject* value) Constraints* c = new Constraints(); c->setDeletable(true); - c->LowerBound = values[1]; - c->UpperBound = values[2]; + c->LowerBound = valConstr[1]; + c->UpperBound = valConstr[2]; c->StepSize = stepSize; - if (values[0] > c->UpperBound) { - values[0] = c->UpperBound; + if (valConstr[0] > c->UpperBound) { + valConstr[0] = c->UpperBound; } - else if (values[0] < c->LowerBound) { - values[0] = c->LowerBound; + else if (valConstr[0] < c->LowerBound) { + valConstr[0] = c->LowerBound; } setConstraints(c); aboutToSetValue(); - _dValue = values[0]; + _dValue = valConstr[0]; hasSetValue(); } - else { - std::string error = std::string("type must be float, not "); - error += value->ob_type->tp_name; - throw Base::TypeError(error); - } } //************************************************************************** From 604a764a6fdc5f0fb2dc523ca48dbe4450dfc308 Mon Sep 17 00:00:00 2001 From: marioalexis Date: Mon, 30 Dec 2024 17:56:55 -0300 Subject: [PATCH 2/2] Fem: Use property constraints on mesh netgen object --- src/Mod/Fem/femobjects/mesh_netgen.py | 70 +++++++++++++-------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/Mod/Fem/femobjects/mesh_netgen.py b/src/Mod/Fem/femobjects/mesh_netgen.py index 9d7048a4d9..ec9f5e9067 100644 --- a/src/Mod/Fem/femobjects/mesh_netgen.py +++ b/src/Mod/Fem/femobjects/mesh_netgen.py @@ -77,11 +77,11 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="OptimizationSteps3d", group="Mesh Parameters", doc="Number of 3d optimization steps", - value=3, + value={"value": 3, "min": 0}, ) ) prop.append( @@ -98,11 +98,11 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="OptimizationSteps2d", group="Mesh Parameters", doc="Number of 2d optimization steps", - value=3, + value={"value": 3, "min": 0}, ) ) prop.append( @@ -134,20 +134,20 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyFloat", + type="App::PropertyFloatConstraint", name="Safety", group="Mesh Parameters", doc="Radius of local environment (times h)", - value=5.0, + value={"value": 5.0, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( - type="App::PropertyFloat", + type="App::PropertyFloatConstraint", name="RelinnerSafety", group="Mesh Parameters", doc="Radius of active environment (times h)", - value=3.0, + value={"value": 3.0, "min": 0, "step": 0.1}, ) ) prop.append( @@ -170,11 +170,11 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyFloat", + type="App::PropertyFloatConstraint", name="GrowthRate", group="Mesh Parameters", doc="Grading for local h", - value=0.3, + value={"value": 0.3, "min": 0, "step": 0.1}, ) ) prop.append( @@ -215,11 +215,11 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyFloat", + type="App::PropertyFloatConstraint", name="CloseEdgeFactor", group="Mesh Parameters", doc="Factor to restrict meshing based on close edges", - value=2.0, + value={"value": 2.0, "min": 0, "step": 0.1}, ) ) prop.append( @@ -260,29 +260,29 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyFloat", + type="App::PropertyFloatConstraint", name="CurvatureSafety", group="Mesh Parameters", doc="Safety factor for curvatures (elements per radius)", - value=2.0, + value={"value": 2.0, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( - type="App::PropertyFloat", + type="App::PropertyFloatConstraint", name="SegmentsPerEdge", group="Mesh Parameters", doc="Minimal number of segments per edge", - value=2.0, + value={"value": 2.0, "min": 0, "step": 0.1}, ) ) prop.append( _PropHelper( - type="App::PropertyFloat", + type="App::PropertyFloatConstraint", name="ElementSizeWeight", group="Mesh Parameters", - doc="Weight of element size respect to element shape", - value=0.2, + doc="Weight of element size respect to element shape", + value={"value": 0.2, "min": 0, "step": 0.1}, ) ) @@ -316,47 +316,47 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="GiveUpTolerance2d", group="Mesh Parameters", doc="Give up quality class, 2d meshing", - value=200, + value={"value": 200, "min": 0}, ) ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="GiveUpTolerance", group="Mesh Parameters", doc="Give up quality class, 3d meshing", - value=10, + value={"value": 10, "min": 0}, ) ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="GiveUpToleranceOpenQuads", group="Mesh Parameters", doc="Give up quality class, for closing open quads, greater than 100 for free pyramids", - value=15, + value={"value": 15, "min": 0}, ) ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="MaxOuterSteps", group="Mesh Parameters", doc="Maximal outer steps", - value=10, + value={"value": 10, "min": 0}, ) ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="StarShapeClass", group="Mesh Parameters", doc="Class starting star-shape filling", - value=5, + value={"value": 5, "min": 0}, ) ) prop.append( @@ -370,20 +370,20 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="Sloppy", group="Mesh Parameters", doc="Quality tolerances are handled less careful", - value=10, + value={"value": 10, "min": 0}, ) ) prop.append( _PropHelper( - type="App::PropertyFloat", + type="App::PropertyFloatConstraint", name="BadElementLimit", group="Mesh Parameters", doc="Limit for max element angle (150-180)", - value=175, + value={"value": 175, "min": 0}, ) ) prop.append( @@ -424,11 +424,11 @@ class MeshNetgen(base_fempythonobject.BaseFemPythonObject): ) prop.append( _PropHelper( - type="App::PropertyInteger", + type="App::PropertyIntegerConstraint", name="ElementOrder", group="Mesh Parameters", doc="High order element curvature", - value=False, + value={"value": 1, "min": 1}, ) ) prop.append(