diff --git a/src/Base/UnitsApi.cpp b/src/Base/UnitsApi.cpp index 9b493ba6ac..14ed7719fa 100644 --- a/src/Base/UnitsApi.cpp +++ b/src/Base/UnitsApi.cpp @@ -66,6 +66,11 @@ std::string UnitsApi::getBasicLengthUnit() return schemas->currentSchema()->getBasicLengthUnit(); } +std::string UnitsApi::getUnitText(const Quantity& quant) +{ + return schemas->currentSchema()->getUnitText(quant); +} + void UnitsApi::setDecimals(const int prec) { decimals = prec; diff --git a/src/Base/UnitsApi.h b/src/Base/UnitsApi.h index db2accbe9e..42a7f4684b 100644 --- a/src/Base/UnitsApi.h +++ b/src/Base/UnitsApi.h @@ -68,6 +68,7 @@ public: static bool isMultiUnitAngle(); static bool isMultiUnitLength(); static std::string getBasicLengthUnit(); + static std::string getUnitText(const Quantity& quant); static std::size_t getDefSchemaNum() { diff --git a/src/Base/UnitsSchema.cpp b/src/Base/UnitsSchema.cpp index 4a1a7a89b3..7eaabf80cd 100644 --- a/src/Base/UnitsSchema.cpp +++ b/src/Base/UnitsSchema.cpp @@ -35,6 +35,8 @@ #include "Exception.h" #include "Quantity.h" +#include "Console.h" + using Base::UnitsSchema; using Base::UnitsSchemaSpec; @@ -143,3 +145,34 @@ int UnitsSchema::getNum() const { return static_cast(spec.num); } + + +//! return the unit text for this quantity in this schema. ex 10 mm => "mm" +//! a more general approach than getBasicLengthUnit. +//! TODO: some common code here with translate() +std::string UnitsSchema::getUnitText(const Base::Quantity& quant) const +{ + std::string typeString = quant.getUnit().getTypeString(); // "Area", "Mass", ... + const auto value = quant.getValue(); + + // TODO: some common code here with translate() + if (!spec.translationSpecs.contains(typeString)) { + Base::Console().log("Schema %s has no entry for %s\n", + getName().c_str(), + typeString.c_str()); + return {}; + } + auto unitSpecs = spec.translationSpecs.at(typeString); + + auto isSuitable = [&](const UnitTranslationSpec& row) { + return row.threshold > value || row.threshold == 0; + }; + + const auto unitSpec = std::ranges::find_if(unitSpecs, isSuitable); + if (unitSpec == unitSpecs.end()) { + throw RuntimeError("Suitable threshold not found (2). Schema: " + spec.name + + " value: " + std::to_string(value)); + } + + return unitSpec->unitString; +} diff --git a/src/Base/UnitsSchema.h b/src/Base/UnitsSchema.h index 42dd340dc5..c823740fff 100644 --- a/src/Base/UnitsSchema.h +++ b/src/Base/UnitsSchema.h @@ -50,6 +50,7 @@ public: [[nodiscard]] std::string getName() const; [[nodiscard]] std::string getDescription() const; [[nodiscard]] int getNum() const; + [[nodiscard]] std::string getUnitText(const Quantity& quant) const; std::string translate(const Quantity& quant) const; std::string translate(const Quantity& quant, double& factor, std::string& unitString) const; diff --git a/src/Mod/TechDraw/App/DimensionFormatter.cpp b/src/Mod/TechDraw/App/DimensionFormatter.cpp index b7e0fec3d6..4140d33ac3 100644 --- a/src/Mod/TechDraw/App/DimensionFormatter.cpp +++ b/src/Mod/TechDraw/App/DimensionFormatter.cpp @@ -51,19 +51,19 @@ std::string DimensionFormatter::formatValue(const qreal value, const Format partial, const bool isDim) const { + bool distanceMeasure{true}; const bool angularMeasure = m_dimension->Type.isValue("Angle") || m_dimension->Type.isValue("Angle3Pt"); const bool areaMeasure = m_dimension->Type.isValue("Area"); - Base::Unit unit; + Base::Unit unit{Base::Unit::Length}; if (angularMeasure) { unit = Base::Unit::Angle; + distanceMeasure = false; } else if (areaMeasure) { unit = Base::Unit::Area; - } - else { - unit = Base::Unit::Length; + distanceMeasure = false; } Base::Quantity asQuantity {value, unit}; @@ -101,26 +101,32 @@ std::string DimensionFormatter::formatValue(const qreal value, formatSpecifier.replace(QStringLiteral("%g"), newSpecifier, Qt::CaseInsensitive); } - // since we are not using a multiValueSchema, we know that angles are in '°' and for - // lengths we can get the unit of measure from UnitsApi::getBasicLengthUnit. + std::string unitText = Base::UnitsApi::getUnitText(asQuantity); + std::string super2{"²"}; + std::string squareTag{"^2"}; - // TODO: check the weird schemas (MKS, Imperial1) that report different UoM for different values + if (unitText.empty()) { + if (distanceMeasure) { + unitText = Base::UnitsApi::getBasicLengthUnit(); + } else if (areaMeasure) { + unitText = Base::UnitsApi::getBasicLengthUnit() + squareTag; + } else if (angularMeasure) { + unitText = "°"; + } + } - // get value in the base unit with default decimals - // for the conversion we use the same method as in DlgUnitsCalculator::valueChanged - // get the conversion factor for the unit - // the result is now just val / convertValue because val is always in the base unit - // don't do this for angular values since they are not in the BaseLengthUnit - std::string qBasicUnit = - angularMeasure ? "°" : Base::UnitsApi::getBasicLengthUnit(); double userVal = asQuantity.getValue(); - if (!angularMeasure) { - const double convertValue = Base::Quantity::parse("1" + qBasicUnit).getValue(); + if (distanceMeasure || areaMeasure) { + const double convertValue = Base::Quantity::parse("1" + unitText).getValue(); userVal /= convertValue; - if (areaMeasure) { - userVal /= convertValue; // divide again as area is length² - qBasicUnit += "²"; + } + + // convert ^2 to superscript 2 for display + if (areaMeasure) { + size_t tagPosition = unitText.find(squareTag); + if (tagPosition != std::string::npos) { + unitText = unitText.replace(tagPosition, 2, super2); } } @@ -147,14 +153,14 @@ std::string DimensionFormatter::formatValue(const qreal value, } else if ((m_dimension->showUnits() || areaMeasure) && !(isDim && m_dimension->haveTolerance())) { - unitStr = " " + qBasicUnit; + unitStr = " " + unitText; } return formatPrefix + formattedValueString + unitStr + formatSuffix; } if (partial == Format::UNIT) { - return angularMeasure || m_dimension->showUnits() || areaMeasure ? qBasicUnit : ""; + return angularMeasure || m_dimension->showUnits() || areaMeasure ? unitText : ""; } return formattedValueString;