Base: Units: introduce unit one

Dimensionless quantities have all exponents equal to zero.
Such quantities are simply numbers. The associated unit is
the unit one, symbol 1, although this is rarely explicitly
written.

See chapter 2.3.3 Dimensions of quantities, The International
System of Units, 9th edition.
This commit is contained in:
Ladislav Michl
2025-04-10 19:15:02 +02:00
parent 70bea37ddd
commit a0917bcc7c
10 changed files with 21 additions and 22 deletions

View File

@@ -194,7 +194,7 @@ void PropertyVector::getPaths(std::vector<ObjectIdentifier>& paths) const
const boost::any PropertyVector::getPathValue(const ObjectIdentifier& path) const
{
Base::Unit unit = getUnit();
if (!unit.isEmpty()) {
if (unit != Unit::One) {
std::string p = path.getSubPathStr();
if (p == ".x" || p == ".y" || p == ".z") {
// Convert double to quantity
@@ -207,7 +207,7 @@ const boost::any PropertyVector::getPathValue(const ObjectIdentifier& path) cons
bool PropertyVector::getPyPathValue(const ObjectIdentifier& path, Py::Object& res) const
{
Base::Unit unit = getUnit();
if (unit.isEmpty()) {
if (unit == Unit::One) {
return false;
}

View File

@@ -270,10 +270,10 @@ std::string Quantity::getSafeUserString() const
return Tools::escapeQuotesFromString(userStr);
}
/// true if it has a number without a unit
/// true if unit equals to 1, therefore quantity has no dimension
bool Quantity::isDimensionless() const
{
return myUnit.isEmpty();
return myUnit == Unit::One;
}
/// true if it has a specific unit or no dimension.

View File

@@ -281,11 +281,6 @@ int Unit::angle() const
return sig.Angle;
}
bool Unit::isEmpty() const
{
return Val == 0;
}
int Unit::operator [](int index) const
{
UnitSignature sig;
@@ -318,6 +313,11 @@ bool Unit::operator ==(const Unit& that) const
return Val == that.Val;
}
bool Unit::operator !=(const Unit& that) const
{
return Val != that.Val;
}
Unit Unit::operator *(const Unit &right) const
{
Unit result;
@@ -360,7 +360,7 @@ Unit Unit::operator /(const Unit &right) const
std::string Unit::getString() const
{
if (isEmpty()) {
if (Val == 0) {
return {};
}
@@ -658,6 +658,8 @@ std::string Unit::getTypeString() const
return spec->second;
}
const Unit Unit::One (0, 0, 0, 0, 0, 0, 0, 0);
// SI base units
const Unit Unit::AmountOfSubstance (0, 0, 0, 0, 0, 1);
const Unit Unit::ElectricCurrent (0, 0, 0, 1);

View File

@@ -61,10 +61,7 @@ public:
Unit operator*(const Unit&) const;
Unit operator/(const Unit&) const;
bool operator==(const Unit&) const;
bool operator!=(const Unit& that) const
{
return !(*this == that);
}
bool operator!=(const Unit& that) const;
Unit& operator=(const Unit&) = default;
Unit& operator=(Unit&&) = default;
Unit pow(double exp) const;
@@ -79,7 +76,6 @@ public:
int amountOfSubstance() const;
int luminousIntensity() const;
int angle() const;
bool isEmpty() const;
std::string getString() const;
/// get the type as an string such as "Area", "Length" or "Pressure".
@@ -87,6 +83,7 @@ public:
/** Predefined Unit types. */
//@{
static const Unit One;
/// Length unit
static const Unit Length;
/// Mass unit

View File

@@ -294,7 +294,7 @@ void DlgExpressionInput::checkExpression(const QString& text)
}
auto msg = value.getUserString();
if (!impliedUnit.isEmpty()) {
if (impliedUnit != Base::Unit::One) {
if (!value.isDimensionless() && value.getUnit() != impliedUnit)
throw Base::UnitsMismatchError("Unit mismatch between result and required unit");

View File

@@ -282,7 +282,7 @@ void InputField::newInput(const QString & text)
res.setUnit(this->actUnit);
// check if unit fits!
if (!actUnit.isEmpty() && !res.isDimensionless() && actUnit != res.getUnit()){
if (actUnit != Unit::One && !res.isDimensionless() && actUnit != res.getUnit()){
if (iconLabel->isHidden()) {
iconLabel->setVisible(true);
}

View File

@@ -607,7 +607,7 @@ void Cell::setComputedUnit(const Base::Unit& unit)
PropertySheet::AtomicPropertyChange signaller(*owner);
computedUnit = unit;
setUsed(COMPUTED_UNIT_SET, !computedUnit.isEmpty());
setUsed(COMPUTED_UNIT_SET, computedUnit != Unit::One);
setDirty();
signaller.tryInvoke();
@@ -1110,7 +1110,7 @@ std::string Cell::getFormattedQuantity()
const Base::Unit& computedUnit = floatProp->getUnit();
qFormatted = QLocale().toString(rawVal, 'f', Base::UnitsApi::getDecimals());
if (hasDisplayUnit) {
if (computedUnit.isEmpty() || computedUnit == du.unit) {
if (computedUnit == Unit::One || computedUnit == du.unit) {
QString number =
QLocale().toString(rawVal / duScale, 'f', Base::UnitsApi::getDecimals());
qFormatted = number + QString::fromStdString(" " + displayUnit.stringRep);

View File

@@ -802,7 +802,7 @@ void Sheet::updateProperty(CellAddress key)
Base::PyGILStateLocker lock;
setObjectProperty(key, constant->getPyValue());
}
else if (!number->getUnit().isEmpty()) {
else if (number->getUnit() != Unit::One) {
setQuantityProperty(key, number->getValue(), number->getUnit());
}
else if (number->isInteger(&l)) {

View File

@@ -384,7 +384,7 @@ QVariant SheetModel::data(const QModelIndex& index, int role) const
// Display locale specific decimal separator (#0003875,#0003876)
if (cell->getDisplayUnit(displayUnit)) {
if (computedUnit.isEmpty() || computedUnit == displayUnit.unit) {
if (computedUnit == Base::Unit::One || computedUnit == displayUnit.unit) {
QString number =
QLocale().toString(floatProp->getValue() / displayUnit.scaler,
'f',

View File

@@ -121,7 +121,7 @@ TEST(Unit, TestPowNoDim)
{
Base::Unit unit {};
EXPECT_EQ(unit.pow(2), Base::Unit {0});
EXPECT_EQ(unit.isEmpty(), true);
EXPECT_EQ(unit == Base::Unit::One, true);
}
TEST(Unit, TestPowEQ1)