Base: Quantity: use isDimensionless whenever feasible

Quantity is often queried for Unit just to see if it has a dimension.
Ask Quantity directly using isDimensionless() method and modify that
method not to care about Quantity value validity; no user was ever
asking for value validity.
This commit is contained in:
Ladislav Michl
2025-04-10 17:43:41 +02:00
parent f486b7c84b
commit 913c30429c
10 changed files with 31 additions and 58 deletions

View File

@@ -488,7 +488,7 @@ static inline Quantity pyToQuantity(const Py::Object &pyobj,
}
Py::Object pyFromQuantity(const Quantity &quantity) {
if(!quantity.getUnit().isEmpty())
if (!quantity.isDimensionless())
return Py::asObject(new QuantityPy(new Quantity(quantity)));
double v = quantity.getValue();
long l;

View File

@@ -105,13 +105,12 @@ void PropertyQuantity::setPyObject(PyObject* value)
else {
Base::Quantity quant = createQuantityFromPy(value);
Unit unit = quant.getUnit();
if (unit.isEmpty()) {
if (quant.isDimensionless()) {
PropertyFloat::setValue(quant.getValue());
return;
}
if (unit != _Unit) {
if (_Unit != quant.getUnit()) {
throw Base::UnitsMismatchError("Not matching Unit!");
}
@@ -123,7 +122,7 @@ void PropertyQuantity::setPathValue(const ObjectIdentifier& /*path*/, const boos
{
auto q = App::anyToQuantity(value);
aboutToSetValue();
if (!q.getUnit().isEmpty()) {
if (!q.isDimensionless()) {
_Unit = q.getUnit();
}
_dValue = q.getValue();
@@ -187,7 +186,6 @@ void PropertyQuantityConstraint::setPyObject(PyObject* value)
{
Base::Quantity quant = createQuantityFromPy(value);
Unit unit = quant.getUnit();
double temp = quant.getValue();
if (_ConstStruct) {
if (temp > _ConstStruct->UpperBound) {
@@ -199,12 +197,12 @@ void PropertyQuantityConstraint::setPyObject(PyObject* value)
}
quant.setValue(temp);
if (unit.isEmpty()) {
if (quant.isDimensionless()) {
PropertyFloat::setValue(quant.getValue()); // clazy:exclude=skipped-base-method
return;
}
if (unit != _Unit) {
if (_Unit != quant.getUnit()) {
throw Base::UnitsMismatchError("Not matching Unit!");
}

View File

@@ -183,7 +183,7 @@ Quantity Quantity::operator/(double factor) const
Quantity Quantity::pow(const Quantity& other) const
{
if (!other.myUnit.isEmpty()) {
if (!other.isDimensionless()) {
throw Base::UnitsMismatchError("Quantity::pow(): exponent must not have a unit");
}
@@ -273,7 +273,7 @@ std::string Quantity::getSafeUserString() const
/// true if it has a number without a unit
bool Quantity::isDimensionless() const
{
return isValid() && myUnit.isEmpty();
return myUnit.isEmpty();
}
/// true if it has a specific unit or no dimension.
@@ -282,12 +282,6 @@ bool Quantity::isDimensionlessOrUnit(const Unit& unit) const
return isDimensionless() || myUnit == unit;
}
// true if it has a number and a valid unit
bool Quantity::isQuantity() const
{
return isValid() && !myUnit.isEmpty();
}
// true if it has a number with or without a unit
bool Quantity::isValid() const
{

View File

@@ -191,12 +191,10 @@ public:
double getValueAs(const Quantity&) const;
/// true if it has a number without a unit
/// true if it has no unit
bool isDimensionless() const;
/// true if it has a specific unit or no dimension.
bool isDimensionlessOrUnit(const Unit& unit) const;
/// true if it has a number and a valid unit
bool isQuantity() const;
/// true if it has a number with or without a unit
bool isValid() const;
/// sets the quantity invalid

View File

@@ -43,19 +43,15 @@ using Base::Quantity;
// returns a string which represents the object e.g. when printed in python
std::string QuantityPy::representation() const
{
std::stringstream ret;
double val = getQuantityPtr()->getValue();
Unit unit = getQuantityPtr()->getUnit();
std::stringstream ss;
// Use Python's implementation to repr() a float
Py::Float flt(val);
ret << static_cast<std::string>(flt.repr());
if (!unit.isEmpty()) {
ret << " " << unit.getString();
Py::Float flt(getQuantityPtr()->getValue());
ss << static_cast<std::string>(flt.repr());
if (!getQuantityPtr()->isDimensionless()) {
ss << " " << getQuantityPtr()->getUnit().getString();
}
return ret.str();
return ss.str();
}
PyObject* QuantityPy::toStr(PyObject* args) const
@@ -66,17 +62,16 @@ PyObject* QuantityPy::toStr(PyObject* args) const
}
double val = getQuantityPtr()->getValue();
Unit unit = getQuantityPtr()->getUnit();
std::stringstream ret;
ret.precision(prec);
ret.setf(std::ios::fixed, std::ios::floatfield);
ret << val;
if (!unit.isEmpty()) {
ret << " " << unit.getString();
std::stringstream ss;
ss.precision(prec);
ss.setf(std::ios::fixed, std::ios::floatfield);
ss << val;
if (!getQuantityPtr()->isDimensionless()) {
ss << " " << getQuantityPtr()->getUnit().getString();
}
return Py_BuildValue("s", ret.str().c_str());
return Py_BuildValue("s", ss.str().c_str());
}
PyObject* QuantityPy::PyMake(PyTypeObject* /*unused*/, PyObject* /*unused*/, PyObject* /*unused*/)
@@ -279,11 +274,6 @@ PyObject* QuantityPy::getValueAs(PyObject* args) const
}
const auto qpUnit = qPtr->getUnit();
if (qpUnit.isEmpty()) {
err("QuantityPtr returned empty unit");
return false;
}
if (const auto qUnit = quant.getUnit(); qUnit != qpUnit) {
err("Unit mismatch (`" + qUnit.getString() + "` != `" + qpUnit.getString() + "`)");
return false;
@@ -301,7 +291,7 @@ PyObject* QuantityPy::getValueAs(PyObject* args) const
}
const auto quant = optQuant.value();
if (quant.isQuantity()) {
if (!quant.isDimensionless()) {
if (!checkQuant(quant)) {
return nullptr;
}

View File

@@ -295,13 +295,13 @@ void DlgExpressionInput::checkExpression(const QString& text)
auto msg = value.getUserString();
if (!impliedUnit.isEmpty()) {
if (!value.getUnit().isEmpty() && value.getUnit() != impliedUnit)
if (!value.isDimensionless() && value.getUnit() != impliedUnit)
throw Base::UnitsMismatchError("Unit mismatch between result and required unit");
value.setUnit(impliedUnit);
}
else if (!value.getUnit().isEmpty()) {
else if (!value.isDimensionless()) {
msg += " (Warning: unit discarded)";
QPalette p(ui->msg->palette());

View File

@@ -278,11 +278,11 @@ void InputField::newInput(const QString & text)
return;
}
if (res.getUnit().isEmpty())
if (res.isDimensionless())
res.setUnit(this->actUnit);
// check if unit fits!
if(!actUnit.isEmpty() && !res.getUnit().isEmpty() && actUnit != res.getUnit()){
if (!actUnit.isEmpty() && !res.isDimensionless() && actUnit != res.getUnit()){
if (iconLabel->isHidden()) {
iconLabel->setVisible(true);
}
@@ -644,7 +644,7 @@ void InputField::focusInEvent(QFocusEvent *event)
void InputField::focusOutEvent(QFocusEvent *event)
{
try {
if (Quantity::parse(this->text().toStdString()).getUnit().isEmpty()) {
if (Quantity::parse(this->text().toStdString()).isDimensionless()) {
// if user didn't enter a unit, we virtually compensate
// the multiplication factor induced by user unit system
double factor;

View File

@@ -224,7 +224,7 @@ public:
ok = parseString(copy, res, value, path);
// If result does not have unit: add default unit
if (res.getUnit().isEmpty()){
if (res.isDimensionless()) {
res.setUnit(unit);
}

View File

@@ -201,8 +201,8 @@ int EditDatumDialog::exec(bool atCursor)
void EditDatumDialog::accepted()
{
Base::Quantity newQuant = ui_ins_datum->labelEdit->value();
if (newQuant.isQuantity() || (Constr->Type == Sketcher::SnellsLaw && newQuant.isDimensionless())
|| (Constr->Type == Sketcher::Weight && newQuant.isDimensionless())) {
if (Constr->Type == Sketcher::SnellsLaw || Constr->Type == Sketcher::Weight
|| !newQuant.isDimensionless()) {
// save the value for the history
ui_ins_datum->labelEdit->pushToHistory();

View File

@@ -27,13 +27,6 @@ TEST(BaseQuantity, TestParse)
EXPECT_THROW(auto rew [[maybe_unused]] = Quantity::parse("1,234,500.12 kg"), ParserError);
}
TEST(BaseQuantity, TestDim)
{
const Quantity q1 {0, Unit::Area};
EXPECT_EQ(q1.isQuantity(), true);
}
TEST(BaseQuantity, TestNoDim)
{
const Quantity q1 {};