From 9f87add8cca7fecaf8013012b9a5b85dd5469484 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 3 Sep 2025 07:54:47 +0200 Subject: [PATCH] Base: UnitsSchema: use basic imperial conversion constants Use well defined basic constants for conversion of imperial units. This makes code hopefully easily readable and verificable. --- src/Base/CMakeLists.txt | 1 + src/Base/Quantity.cpp | 44 ++++++++++++----------- src/Base/Quantity.h | 9 ++--- src/Base/UnitsConvData.h | 38 ++++++++++++++++++++ src/Base/UnitsSchemasData.h | 69 +++++++++++++++++++------------------ tests/src/Base/Quantity.cpp | 14 ++++---- 6 files changed, 109 insertions(+), 66 deletions(-) create mode 100644 src/Base/UnitsConvData.h diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index dc6357a450..7e79c2fce8 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -152,6 +152,7 @@ SET(FreeCADBase_UNITAPI_SRCS UnitsApi.cpp UnitsApiPy.cpp UnitsApi.h + UnitsConvData.h UnitsSchema.h UnitsSchema.cpp UnitsSchemas.cpp diff --git a/src/Base/Quantity.cpp b/src/Base/Quantity.cpp index aad7638140..edd268fa51 100644 --- a/src/Base/Quantity.cpp +++ b/src/Base/Quantity.cpp @@ -36,6 +36,7 @@ #include "Quantity.h" #include "Tools.h" #include "UnitsApi.h" +#include "UnitsConvData.h" #include "UnitsSchema.h" /** \defgroup Units Units system @@ -324,6 +325,8 @@ void Quantity::setInvalid() // === Predefined types ===================================================== // clang-format off +using namespace Base::UnitsConvData; + const Quantity Quantity::NanoMetre ( 1.0e-6 , Unit::Length ); const Quantity Quantity::MicroMetre ( 1.0e-3 , Unit::Length ); const Quantity Quantity::MilliMetre ( 1.0 , Unit::Length ); @@ -365,22 +368,23 @@ const Quantity Quantity::Mole ( 1.0 , Unit:: const Quantity Quantity::Candela ( 1.0 , Unit::LuminousIntensity ); -const Quantity Quantity::Inch ( 25.4 , Unit::Length ); -const Quantity Quantity::Foot ( 304.8 , Unit::Length ); -const Quantity Quantity::Thou ( 0.0254 , Unit::Length ); -const Quantity Quantity::Yard ( 914.4 , Unit::Length ); -const Quantity Quantity::Mile ( 1609344.0 , Unit::Length ); +const Quantity Quantity::Inch ( in , Unit::Length ); +const Quantity Quantity::Foot ( ft , Unit::Length ); +const Quantity Quantity::Thou ( in / 1000 , Unit::Length ); +const Quantity Quantity::Yard ( yd , Unit::Length ); +const Quantity Quantity::Mile ( mi , Unit::Length ); -const Quantity Quantity::MilePerHour ( 447.04 , Unit::Velocity ); -const Quantity Quantity::SquareFoot ( 92903.04 , Unit::Area ); -const Quantity Quantity::CubicFoot ( 28316846.592 , Unit::Volume ); +const Quantity Quantity::MilePerHour ( mi / 3600 , Unit::Velocity ); -const Quantity Quantity::Pound ( 0.45359237 , Unit::Mass ); -const Quantity Quantity::Ounce ( 0.0283495231 , Unit::Mass ); -const Quantity Quantity::Stone ( 6.35029318 , Unit::Mass ); -const Quantity Quantity::Hundredweights ( 50.80234544 , Unit::Mass ); +const Quantity Quantity::SquareFoot ( ft * ft , Unit::Area ); +const Quantity Quantity::CubicFoot ( ft * ft * ft , Unit::Volume ); -const Quantity Quantity::PoundForce ( 4448.22 , Unit::Force ); // lbf are ~= 4.44822 Newton +const Quantity Quantity::Pound ( lb , Unit::Mass ); +const Quantity Quantity::Ounce ( lb / 16 , Unit::Mass ); +const Quantity Quantity::Stone ( lb * 14 , Unit::Mass ); +const Quantity Quantity::Hundredweights ( lb * 112 , Unit::Mass ); + +const Quantity Quantity::PoundForce ( 1000 * lbf , Unit::Force ); const Quantity Quantity::Newton ( 1000.0 , Unit::Force ); // Newton (kg*m/s^2) const Quantity Quantity::MilliNewton ( 1.0 , Unit::Force ); @@ -401,12 +405,12 @@ const Quantity Quantity::MilliBar ( 0.1 , Unit:: const Quantity Quantity::Bar ( 100.0 , Unit::Pressure ); // 1 bar = 100 kPa const Quantity Quantity::Torr ( 101.325 / 760.0 , Unit::Pressure ); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2) -const Quantity Quantity::mTorr ( 0.101325 / 760.0 , Unit::Pressure ); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2) -const Quantity Quantity::yTorr ( 0.000101325 / 760.0 , Unit::Pressure ); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2) +const Quantity Quantity::mTorr ( 101.325 / 760.0 / 1e3 , Unit::Pressure ); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2) +const Quantity Quantity::yTorr ( 101.325 / 760.0 / 1e6 , Unit::Pressure ); // Torr is a defined fraction of Pascal (kg/m/s^2 or N/m^2) -const Quantity Quantity::PSI ( 6.894744825494 , Unit::Pressure ); // pounds/in^2 -const Quantity Quantity::KSI ( 6894.744825494 , Unit::Pressure ); // 1000 x pounds/in^2 -const Quantity Quantity::MPSI ( 6894744.825494 , Unit::Pressure ); // 1000 ksi +const Quantity Quantity::PSI ( psi , Unit::Pressure ); +const Quantity Quantity::KSI ( psi * 1000 , Unit::Pressure ); +const Quantity Quantity::MPSI ( psi * 1000000 , Unit::Pressure ); const Quantity Quantity::Watt ( 1e+6 , Unit::Power ); // Watt (kg*m^2/s^3) const Quantity Quantity::MilliWatt ( 1e+3 , Unit::Power ); @@ -458,8 +462,8 @@ const Quantity Quantity::Calorie ( 4.1868e+6 , Unit:: const Quantity Quantity::KiloCalorie ( 4.1868e+9 , Unit::Work ); const Quantity Quantity::NewtonMeter ( 1e+6 , Unit::Moment ); // Joule (kg*m^2/s^2) -const Quantity Quantity::KMH ( 277.778 , Unit::Velocity ); // km/h -const Quantity Quantity::MPH ( 447.04 , Unit::Velocity ); // Mile/h +const Quantity Quantity::KMH ( 1e+6 / 3600 , Unit::Velocity ); // km/h +const Quantity Quantity::MPH ( mi / 3600 , Unit::Velocity ); // Mile/h const Quantity Quantity::AngMinute ( 1.0 / 60.0 , Unit::Angle ); // angular minute const Quantity Quantity::AngSecond ( 1.0 / 3600.0 , Unit::Angle ); // angular second diff --git a/src/Base/Quantity.h b/src/Base/Quantity.h index a25616330e..68e9be1dd3 100644 --- a/src/Base/Quantity.h +++ b/src/Base/Quantity.h @@ -195,7 +195,6 @@ public: /// sets the quantity invalid void setInvalid(); - /** Predefined Unit types. */ //@{ static const Quantity NanoMetre; @@ -243,14 +242,15 @@ public: static const Quantity Foot; static const Quantity Thou; static const Quantity Yard; + static const Quantity Mile; + + static const Quantity MilePerHour; static const Quantity Pound; static const Quantity Ounce; static const Quantity Stone; static const Quantity Hundredweights; - static const Quantity Mile; - static const Quantity MilePerHour; static const Quantity SquareFoot; static const Quantity CubicFoot; @@ -308,8 +308,6 @@ public: static const Quantity Weber; - // static const Quantity Oersted; - static const Quantity Farad; static const Quantity MilliFarad; static const Quantity MicroFarad; @@ -344,7 +342,6 @@ public: static const Quantity AngSecond; //@} - private: double myValue; Unit myUnit; diff --git a/src/Base/UnitsConvData.h b/src/Base/UnitsConvData.h new file mode 100644 index 0000000000..47ffb07afa --- /dev/null +++ b/src/Base/UnitsConvData.h @@ -0,0 +1,38 @@ +/************************************************************************ + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 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 Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ************************************************************************/ + +#ifndef BASE_UNITSCONVDATA_H +#define BASE_UNITSCONVDATA_H + +namespace Base::UnitsConvData +{ + +constexpr auto in {25.4}; +constexpr auto ft {12 * in}; +constexpr auto yd {3 * ft}; +constexpr auto mi {1760 * yd}; +constexpr auto lb {0.45359237}; +constexpr auto lbf {9.80665 * lb}; +constexpr auto psi {lbf / (in * in) * 1000}; + +} // namespace Base::UnitsConvData + +#endif diff --git a/src/Base/UnitsSchemasData.h b/src/Base/UnitsSchemasData.h index 6f595d38eb..1d909ea077 100644 --- a/src/Base/UnitsSchemasData.h +++ b/src/Base/UnitsSchemasData.h @@ -30,6 +30,7 @@ #include "fmt/format.h" #include "fmt/ranges.h" +#include "UnitsConvData.h" #include "UnitsSchemasSpecs.h" /** @@ -42,6 +43,8 @@ namespace Base::UnitsSchemasData constexpr std::size_t defDecimals {2}; constexpr std::size_t defDenominator {8}; +using namespace Base::UnitsConvData; + // NOLINTBEGIN // clang-format off inline const UnitsSchemaSpec s0 @@ -69,15 +72,15 @@ inline const UnitsSchemaSpec s1 inline const UnitsSchemaSpec s2 { 3, "ImperialDecimal", "in", false, false, QT_TRANSLATE_NOOP("UnitsApi", "Imperial decimal (in, lb)"), false, { - { "Length", {{ 0 , "in" , 25.4 }}}, + { "Length", {{ 0 , "in" , in }}}, { "Angle", {{ 0 , "°" , 1.0 }}}, - { "Area", {{ 0 , "in^2" , 645.16 }}}, - { "Volume", {{ 0 , "in^3" , 16387.064 }}}, - { "Mass", {{ 0 , "lb" , 0.45359237 }}}, - { "Pressure", {{ 0 , "psi" , 6.894744825494 }}}, - { "Stiffness", {{ 0 , "lbf/in" , 4.448222 / 0.0254 }}}, - { "Velocity", {{ 0 , "in/min" , 25.4 / 60 }}}, - { "Acceleration", {{ 0 , "in/min^2", 25.4 / 3600 }}} + { "Area", {{ 0 , "in^2" , in * in }}}, + { "Volume", {{ 0 , "in^3" , in * in * in }}}, + { "Mass", {{ 0 , "lb" , lb }}}, + { "Pressure", {{ 0 , "psi" , psi }}}, + { "Stiffness", {{ 0 , "lbf/in" , lbf / in * 1000 }}}, + { "Velocity", {{ 0 , "in/min" , in / 60 }}}, + { "Acceleration", {{ 0 , "in/min^2", in / 3600 }}} } }; @@ -582,36 +585,36 @@ inline const UnitsSchemaSpec s7 { 2, "Imperial", "in", false, false, QT_TRANSLATE_NOOP("UnitsApi", "US customary (in, lb)"), false, { { "Length", { - { 0.00000254 , "in" , 25.4 }, - { 2.54 , "thou" , 0.0254 }, - { 304.8 , "\"" , 25.4 }, - { 914.4 , "'" , 304.8 }, - { 1'609'344.0 , "yd" , 914.4 }, - { 1'609'344'000.0 , "mi" , 1'609'344.0 }, - { 0 , "in" , 25.4 }} + { 0.00000254 , "in" , in }, + { 2.54 , "thou" , in / 1000 }, + { 304.8 , "\"" , in }, + { 914.4 , "'" , ft }, + { 1'609'344.0 , "yd" , yd }, + { 1'609'344'000.0 , "mi" , mi }, + { 0 , "in" , in }} }, { "Angle", { { 0 , "°" , 1.0 }} }, { "Area", { - { 0 , "in^2" , 645.16 }} + { 0 , "in^2" , in * in }} }, { "Volume", { - { 0 , "in^3" , 16'387.064 }} + { 0 , "in^3" , in * in * in }} }, { "Mass", { - { 0 , "lb" , 0.45359237 }} + { 0 , "lb" , lb }} }, { "Pressure", { - { 6'894.744 , "psi" , 6.894744825494 }, - { 6'894'744.825 , "ksi" , 6'894.744825494 }, - { 0 , "psi" , 6.894744825494 }} + { 1000 * psi , "psi" , psi }, + { 1000000 * psi , "ksi" , 1000 * psi }, + { 0 , "psi" , psi }} }, { "Stiffness", { - { 0 , "lbf/in" , 4.448222 / 0.0254 }} + { 0 , "lbf/in" , lbf / in * 1000 }} }, { "Velocity", { - { 0 , "in/min" , 25.4 / 60 }} + { 0 , "in/min" , in / 60 }} } } }; @@ -621,22 +624,22 @@ inline const UnitsSchemaSpec s8 { { "Length" , {{ 0 , "toFractional" , 0 }}}, // <== ! { "Angle" , {{ 0 , "°" , 1.0 }}}, - { "Area" , {{ 0 , "sqft" , 92'903.04 }}}, - { "Volume" , {{ 0 , "cft" , 28'316'846.592 }}}, - { "Velocity" , {{ 0 , "in/min" , 25.4 / 60 }}} + { "Area" , {{ 0 , "sqft" , ft * ft }}}, + { "Volume" , {{ 0 , "cft" , ft * ft * ft }}}, + { "Velocity" , {{ 0 , "in/min" , in / 60 }}} } }; inline const UnitsSchemaSpec s9 { 7, "ImperialCivil", "ft", false, true, QT_TRANSLATE_NOOP("UnitsApi", "Imperial for Civil Eng (ft, lb, mph)"), false, { - { "Length" , {{ 0 , "ft" , 12 * 25.4 }}}, - { "Area" , {{ 0 , "ft^2" , 92'903.04 }}}, - { "Volume" , {{ 0 , "ft^3" , 28'316'846.592 }}}, - { "Mass" , {{ 0 , "lb" , 0.45359237 }}}, - { "Pressure" , {{ 0 , "psi" , 6.894744825494 }}}, - { "Stiffness", {{ 0 , "lbf/in", 4.448222 / 0.0254 }}}, - { "Velocity" , {{ 0 , "mph" , 447.04 }}}, + { "Length" , {{ 0 , "ft" , ft }}}, + { "Area" , {{ 0 , "ft^2" , ft * ft }}}, + { "Volume" , {{ 0 , "ft^3" , ft * ft * ft }}}, + { "Mass" , {{ 0 , "lb" , lb }}}, + { "Pressure" , {{ 0 , "psi" , psi }}}, + { "Stiffness", {{ 0 , "lbf/in", lbf / in * 1000 }}}, + { "Velocity" , {{ 0 , "mph" , mi / 3600 }}}, { "Angle" , {{ 0 , "toDMS" , 0 }}} // <== ! } }; diff --git a/tests/src/Base/Quantity.cpp b/tests/src/Base/Quantity.cpp index d333236271..ca05adecb7 100644 --- a/tests/src/Base/Quantity.cpp +++ b/tests/src/Base/Quantity.cpp @@ -198,25 +198,25 @@ protected: TEST_F(BaseQuantityLoc, psi_parse_spaced) { const auto qParsed = Quantity::parse("1 psi"); - EXPECT_EQ(qParsed.getValue(), 6.8947448254939996); + EXPECT_EQ(qParsed.getValue(), 6.8947572931683609); } TEST_F(BaseQuantityLoc, psi_parse_no_space) { const auto qParsed = Quantity::parse("1psi"); - EXPECT_EQ(qParsed.getValue(), 6.8947448254939996); + EXPECT_EQ(qParsed.getValue(), 6.8947572931683609); } TEST_F(BaseQuantityLoc, psi_parse_user_str) { const auto qParsed = Quantity::parse("1 psi"); - EXPECT_EQ(qParsed.getUserString(), "6894.74 Pa"); + EXPECT_EQ(qParsed.getUserString(), "6894.76 Pa"); } TEST_F(BaseQuantityLoc, psi_parse_safe_user_str) { const auto qParsed = Quantity::parse("1 psi"); - EXPECT_EQ(qParsed.getSafeUserString(), "6894.74 Pa"); + EXPECT_EQ(qParsed.getSafeUserString(), "6894.76 Pa"); } TEST_F(BaseQuantityLoc, psi_parse_unit_type) @@ -228,7 +228,7 @@ TEST_F(BaseQuantityLoc, psi_parse_unit_type) TEST_F(BaseQuantityLoc, psi_to_Pa) { const auto result = Quantity::parse("1 psi").getValueAs(Quantity::Pascal); - const auto expect = 6894.7448254939991; + const auto expect = 6894.7572931683608; EXPECT_EQ(result, expect); } @@ -236,7 +236,7 @@ TEST_F(BaseQuantityLoc, psi_to_Pa) TEST_F(BaseQuantityLoc, psi_to_KPa) { const auto result = Quantity::parse("1 psi").getValueAs(Quantity::KiloPascal); - const auto expect = 6.8947448254939996; + const auto expect = 6.8947572931683609; EXPECT_EQ(result, expect); } @@ -244,7 +244,7 @@ TEST_F(BaseQuantityLoc, psi_to_KPa) TEST_F(BaseQuantityLoc, psi_to_MPa) { const auto result = Quantity::parse("1 psi").getValueAs(Quantity::MegaPascal); - const auto expect = 0.0068947448254939999; + const auto expect = 0.0068947572931683607; EXPECT_EQ(result, expect); }