diff --git a/src/App/Application.cpp b/src/App/Application.cpp index 3e7d942e29..4e3aac3216 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -2795,12 +2795,10 @@ void Application::initApplication() // set up Unit system default const ParameterGrp::handle hGrp = GetApplication().GetParameterGroupByPath ("User parameter:BaseApp/Preferences/Units"); - Base::UnitsApi::setSchema(static_cast(hGrp->GetInt("UserSchema", 0))); - Base::UnitsApi::setDecimals(static_cast(hGrp->GetInt("Decimals", Base::UnitsApi::getDecimals()))); - - // In case we are using fractional inches, get user setting for min unit - const int denom = static_cast(hGrp->GetInt("FracInch", Base::QuantityFormat::getDefaultDenominator())); - Base::QuantityFormat::setDefaultDenominator(denom); + Base::UnitsApi::setSchema(hGrp->GetInt("UserSchema", Base::UnitsApi::getDefSchemaNum())); + Base::UnitsApi::setDecimals(hGrp->GetInt("Decimals", Base::UnitsApi::getDecimals())); + Base::QuantityFormat::setDefaultDenominator( + hGrp->GetInt("FracInch", Base::QuantityFormat::getDefaultDenominator())); #if defined (_DEBUG) Base::Console().Log("Application is built with debug information\n"); diff --git a/src/App/Document.cpp b/src/App/Document.cpp index bc195831b4..245a6d7198 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -876,13 +876,8 @@ Document::Document(const char* documentName) "Additional tag to save the name of the company"); ADD_PROPERTY_TYPE(UnitSystem, (""), 0, Prop_None, "Unit system to use in this project"); // Set up the possible enum values for the unit system - int num = static_cast(Base::UnitSystem::NumUnitSystemTypes); - std::vector enumValsAsVector; - for (int i = 0; i < num; i++) { - QString item = Base::UnitsApi::getDescription(static_cast(i)); - enumValsAsVector.emplace_back(item.toStdString()); - } - UnitSystem.setEnums(enumValsAsVector); + + UnitSystem.setEnums(Base::UnitsApi::getDescriptions()); // Get the preferences/General unit system as the default for a new document ParameterGrp::handle hGrpu = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units"); diff --git a/src/Base/CMakeLists.txt b/src/Base/CMakeLists.txt index b21250c43c..607772a213 100644 --- a/src/Base/CMakeLists.txt +++ b/src/Base/CMakeLists.txt @@ -150,20 +150,10 @@ SET(FreeCADBase_UNITAPI_SRCS UnitsApi.h UnitsSchema.h UnitsSchema.cpp - UnitsSchemaInternal.h - UnitsSchemaInternal.cpp - UnitsSchemaMKS.h - UnitsSchemaMKS.cpp - UnitsSchemaImperial1.h - UnitsSchemaImperial1.cpp - UnitsSchemaCentimeters.h - UnitsSchemaCentimeters.cpp - UnitsSchemaMmMin.h - UnitsSchemaMmMin.cpp - UnitsSchemaFemMilliMeterNewton.h - UnitsSchemaFemMilliMeterNewton.cpp - UnitsSchemaMeterDecimal.h - UnitsSchemaMeterDecimal.cpp + UnitsSchemas.cpp + UnitsSchemas.h + UnitsSchemasData.h + UnitsSchemasSpecs.h Quantity.h Quantity.cpp QuantityPyImp.cpp diff --git a/src/Base/Quantity.cpp b/src/Base/Quantity.cpp index 73ecaacf6f..efa8c37a3c 100644 --- a/src/Base/Quantity.cpp +++ b/src/Base/Quantity.cpp @@ -64,7 +64,7 @@ int QuantityFormat::defaultDenominator = 8; // for 1/8" QuantityFormat::QuantityFormat() : option(OmitGroupSeparator | RejectGroupSeparator) , format(Fixed) - , precision(UnitsApi::getDecimals()) + , precision(static_cast(UnitsApi::getDecimals())) , denominator(defaultDenominator) {} @@ -256,14 +256,15 @@ std::string Quantity::getUserString(double& factor, std::string& unitString) con std::string Quantity::getUserString(UnitsSchema* schema, double& factor, std::string& unitString) const { - return schema->schemaTranslate(*this, factor, unitString); + return schema->translate(*this, factor, unitString); } std::string Quantity::getSafeUserString() const { auto userStr = getUserString(); if (myValue != 0.0 && parse(userStr).getValue() == 0) { - userStr = fmt::format("{} {}", myValue, getUnit().getString()); + auto unitStr = getUnit().getString(); + userStr = fmt::format("{}{}{}", myValue, unitStr.empty() ? "" : " ", unitStr); } return Tools::escapeQuotesFromString(userStr); diff --git a/src/Base/UnitsApi.cpp b/src/Base/UnitsApi.cpp index 0cf3133d0e..41328297fd 100644 --- a/src/Base/UnitsApi.cpp +++ b/src/Base/UnitsApi.cpp @@ -20,124 +20,91 @@ * * ***************************************************************************/ - #include "PreCompiled.h" - -#include +#ifndef _PreComp_ #include -#include +#include +#endif #include #include -#include + #include "Exception.h" - #include "UnitsApi.h" -#include "UnitsSchemaCentimeters.h" -#include "UnitsSchemaInternal.h" -#include "UnitsSchemaImperial1.h" -#include "UnitsSchemaMKS.h" -#include "UnitsSchemaMmMin.h" -#include "UnitsSchemaFemMilliMeterNewton.h" -#include "UnitsSchemaMeterDecimal.h" +#include "UnitsSchema.h" +#include "UnitsSchemas.h" +#include "UnitsSchemasData.h" -using namespace Base; +using Base::UnitsApi; +using Base::UnitsSchema; +using Base::UnitsSchemas; -// === static attributes ================================================ - -UnitsSchemaPtr UnitsApi::UserPrefSystem(new UnitsSchemaInternal()); -UnitSystem UnitsApi::currentSystem = UnitSystem::SI1; - -int UnitsApi::UserPrefDecimals = 2; - -QString UnitsApi::getDescription(UnitSystem system) +void UnitsApi::init() { - switch (system) { - case UnitSystem::SI1: - return tr("Standard (mm, kg, s, °)"); - case UnitSystem::SI2: - return tr("MKS (m, kg, s, °)"); - case UnitSystem::Imperial1: - return tr("US customary (in, lb)"); - case UnitSystem::ImperialDecimal: - return tr("Imperial decimal (in, lb)"); - case UnitSystem::Centimeters: - return tr("Building Euro (cm, m², m³)"); - case UnitSystem::ImperialBuilding: - return tr("Building US (ft-in, sqft, cft)"); - case UnitSystem::MmMin: - return tr("Metric small parts & CNC (mm, mm/min)"); - case UnitSystem::ImperialCivil: - return tr("Imperial for Civil Eng (ft, ft/s)"); - case UnitSystem::FemMilliMeterNewton: - return tr("FEM (mm, N, s)"); - case UnitSystem::MeterDecimal: - return tr("Meter decimal (m, m², m³)"); - default: - return tr("Unknown schema"); - } + schemas = std::make_unique(UnitsSchemasData::unitSchemasDataPack); } -UnitsSchemaPtr UnitsApi::createSchema(UnitSystem system) +std::vector UnitsApi::getDescriptions() { - switch (system) { - case UnitSystem::SI1: - return std::make_unique(); - case UnitSystem::SI2: - return std::make_unique(); - case UnitSystem::Imperial1: - return std::make_unique(); - case UnitSystem::ImperialDecimal: - return std::make_unique(); - case UnitSystem::Centimeters: - return std::make_unique(); - case UnitSystem::ImperialBuilding: - return std::make_unique(); - case UnitSystem::MmMin: - return std::make_unique(); - case UnitSystem::ImperialCivil: - return std::make_unique(); - case UnitSystem::FemMilliMeterNewton: - return std::make_unique(); - case UnitSystem::MeterDecimal: - return std::make_unique(); - default: - break; - } - - return nullptr; + return schemas->descriptions(); } -void UnitsApi::setSchema(UnitSystem system) +std::vector UnitsApi::getNames() { - if (UserPrefSystem) { - UserPrefSystem->resetSchemaUnits(); // for schemas changed the Quantity constants - } - - UserPrefSystem = createSchema(system); - currentSystem = system; - - // for wrong value fall back to standard schema - if (!UserPrefSystem) { - UserPrefSystem = std::make_unique(); - currentSystem = UnitSystem::SI1; - } - - UserPrefSystem->setSchemaUnits(); // if necessary a unit schema can change the constants in - // Quantity (e.g. mi=1.8km rather then 1.6km). + return schemas->names(); } -std::string UnitsApi::toString(const Base::Quantity& quantity, const QuantityFormat& format) +std::size_t UnitsApi::count() +{ + return static_cast(schemas->count()); +} + +bool UnitsApi::isMultiUnitAngle() +{ + return schemas->currentSchema()->isMultiUnitAngle(); +} + +bool UnitsApi::isMultiUnitLength() +{ + return schemas->currentSchema()->isMultiUnitLength(); +} + +std::string UnitsApi::getBasicLengthUnit() +{ + return schemas->currentSchema()->getBasicLengthUnit(); +} + +std::size_t UnitsApi::getFractDenominator() +{ + return schemas->defFractDenominator(); +} + +std::unique_ptr UnitsApi::createSchema(const std::size_t num) +{ + return std::make_unique(schemas->spec(num)); +} + +void UnitsApi::setSchema(const std::string& name) +{ + schemas->select(name); +} + +void UnitsApi::setSchema(const size_t num) +{ + schemas->select(num); +} + +std::string UnitsApi::toString(const Quantity& quantity, const QuantityFormat& format) { return fmt::format("'{} {}'", toNumber(quantity, format), quantity.getUnit().getString()); } -std::string UnitsApi::toNumber(const Base::Quantity& quantity, const QuantityFormat& format) +std::string UnitsApi::toNumber(const Quantity& quantity, const QuantityFormat& format) { return toNumber(quantity.getValue(), format); } -std::string UnitsApi::toNumber(double value, const QuantityFormat& format) +std::string UnitsApi::toNumber(const double value, const QuantityFormat& format) { std::stringstream ss; @@ -156,31 +123,6 @@ std::string UnitsApi::toNumber(double value, const QuantityFormat& format) return ss.str(); } -// return true if the current user schema uses multiple units for length (ex. Ft/In) -bool UnitsApi::isMultiUnitLength() -{ - return UserPrefSystem->isMultiUnitLength(); -} - -// return true if the current user schema uses multiple units for angles (ex. DMS) -bool UnitsApi::isMultiUnitAngle() -{ - return UserPrefSystem->isMultiUnitAngle(); -} - -std::string UnitsApi::getBasicLengthUnit() -{ - return UserPrefSystem->getBasicLengthUnit(); -} - -// === static translation methods ========================================== - -std::string -UnitsApi::schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) -{ - return UserPrefSystem->schemaTranslate(quant, factor, unitString); -} - double UnitsApi::toDouble(PyObject* args, const Base::Unit& u) { if (PyUnicode_Check(args)) { @@ -203,34 +145,30 @@ double UnitsApi::toDouble(PyObject* args, const Base::Unit& u) throw Base::UnitsMismatchError("Wrong parameter type!"); } -Quantity UnitsApi::toQuantity(PyObject* args, const Base::Unit& u) +std::string +UnitsApi::schemaTranslate(const Quantity& quant, double& factor, std::string& unitString) { - double d {}; - if (PyUnicode_Check(args)) { - std::string str(PyUnicode_AsUTF8(args)); - // Parse the string - Quantity q = Quantity::parse(str); - d = q.getValue(); - } - else if (PyFloat_Check(args)) { - d = PyFloat_AsDouble(args); - } - else if (PyLong_Check(args)) { - d = static_cast(PyLong_AsLong(args)); - } - else { - throw Base::UnitsMismatchError("Wrong parameter type!"); - } - - return Quantity(d, u); + return schemas->currentSchema()->translate(quant, factor, unitString); } -void UnitsApi::setDecimals(int prec) +std::string UnitsApi::schemaTranslate(const Quantity& quant) { - UserPrefDecimals = prec; + double dummy1 {}; // to satisfy GCC + std::string dummy2; + return schemas->currentSchema()->translate(quant, dummy1, dummy2); } -int UnitsApi::getDecimals() +void UnitsApi::setDecimals(const std::size_t prec) { - return UserPrefDecimals; + decimals = prec; +} + +size_t UnitsApi::getDecimals() +{ + return decimals; +} + +size_t UnitsApi::getDefDecimals() +{ + return schemas->getDecimals(); } diff --git a/src/Base/UnitsApi.h b/src/Base/UnitsApi.h index 3a0b7e19f8..d5a6d95af3 100644 --- a/src/Base/UnitsApi.h +++ b/src/Base/UnitsApi.h @@ -20,13 +20,12 @@ * * ***************************************************************************/ - #ifndef BASE_UNITSAPI_H #define BASE_UNITSAPI_H -#include -#include #include "UnitsSchema.h" +#include "UnitsSchemas.h" +#include "UnitsSchemasData.h" #include "Quantity.h" @@ -37,96 +36,71 @@ using PyMethodDef = struct PyMethodDef; namespace Base { -using UnitsSchemaPtr = std::unique_ptr; -/** - * The UnitsApi - */ + class BaseExport UnitsApi { - Q_DECLARE_TR_FUNCTIONS(UnitsApi) - public: - /** set Schema - * set the UnitsSchema of the Application - * this a represented by a class of type UnitSchema which - * defines a set of standard units for that schema and rules - * for representative strings. - */ - static void setSchema(UnitSystem s); - /// return the active schema - static UnitSystem getSchema() - { - return currentSystem; - } - /// Returns a brief description of a schema - static QString getDescription(UnitSystem); + static void init(); + static std::unique_ptr createSchema(std::size_t num); + static void setSchema(const std::string& name); + static void setSchema(std::size_t num); static std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString); - static std::string schemaTranslate(const Base::Quantity& quant) - { // to satisfy GCC - double dummy1 {}; - std::string dummy2; - return UnitsApi::schemaTranslate(quant, dummy1, dummy2); - } + schemaTranslate(const Quantity& quant, double& factor, std::string& unitString); - /** Get a number as string for a quantity of a given format. - * The string is a number in C locale (i.e. the decimal separator is always a dot) and if - * needed represented in scientific notation. The string also includes the unit of the quantity. - */ - static std::string toString(const Base::Quantity& q, - const QuantityFormat& f = QuantityFormat(QuantityFormat::Default)); - /** Get a number as string for a quantity of a given format. - * The string is a number in C locale (i.e. the decimal separator is always a dot) and if - * needed represented in scientific notation. The string doesn't include the unit of the - * quantity. - */ - static std::string toNumber(const Base::Quantity& q, - const QuantityFormat& f = QuantityFormat(QuantityFormat::Default)); - /** Get a number as string for a double of a given format. - * The string is a number in C locale (i.e. the decimal separator is always a dot) and if - * needed represented in scientific notation. The string doesn't include the unit of the - * quantity. - */ - static std::string toNumber(double value, - const QuantityFormat& f = QuantityFormat(QuantityFormat::Default)); + static std::string schemaTranslate(const Quantity& quant); + + /** + * toString & toNumber: + * Quantity to string. Optionally apply format + * The string is a number in C locale (i.e. the decimal separator is always a dot) + * Scientific notation (if needed). + */ + + /** INCLUDES unit */ + static std::string + toString(const Quantity& quantity, + const QuantityFormat& format = QuantityFormat(QuantityFormat::Default)); + + /** Does NOT include unit */ + static std::string + toNumber(const Quantity& quantity, + const QuantityFormat& format = QuantityFormat(QuantityFormat::Default)); + + /** Does NOT include unit */ + static std::string + toNumber(double value, const QuantityFormat& format = QuantityFormat(QuantityFormat::Default)); - /// generate a value for a quantity with default user preferred system static double toDouble(PyObject* args, const Base::Unit& u = Base::Unit()); - /// generate a value for a quantity with default user preferred system - static Quantity toQuantity(PyObject* args, const Base::Unit& u = Base::Unit()); - // set the number of decimals - static void setDecimals(int); - // get the number of decimals - static int getDecimals(); - //@} + static void setDecimals(std::size_t); + static std::size_t getDecimals(); + static std::size_t getDefDecimals(); - // double Result; + static std::vector getDescriptions(); + static std::vector getNames(); - // return true if the current user schema uses multiple units for length (ex. Ft/In) - static bool isMultiUnitLength(); + static std::size_t count(); - // return true if the current user schema uses multiple units for angles (ex. DMS) static bool isMultiUnitAngle(); - - // return the basic unit of measure for length in the current user schema. + static bool isMultiUnitLength(); static std::string getBasicLengthUnit(); + static std::size_t getFractDenominator(); + static std::size_t getDefSchemaNum() + { + return schemas->spec().num; + } // Python interface static PyMethodDef Methods[]; - /// return an instance of the given enum value - static UnitsSchemaPtr createSchema(UnitSystem s); - protected: - static UnitsSchemaPtr UserPrefSystem; - static UnitSystem currentSystem; - /// number of decimals for floats - static int UserPrefDecimals; + static inline auto schemas = + std::make_unique(UnitsSchemasData::unitSchemasDataPack); + static inline std::size_t decimals {2}; + static inline std::size_t denominator {2}; -protected: // the python API wrapper methods static PyObject* sParseQuantity(PyObject* self, PyObject* args); static PyObject* sListSchemas(PyObject* self, PyObject* args); @@ -138,5 +112,4 @@ protected: } // namespace Base - #endif // BASE_UNITSAPI_H diff --git a/src/Base/UnitsApiPy.cpp b/src/Base/UnitsApiPy.cpp index 730d915f43..f6a0d49870 100644 --- a/src/Base/UnitsApiPy.cpp +++ b/src/Base/UnitsApiPy.cpp @@ -20,9 +20,7 @@ * * ***************************************************************************/ - #include "PreCompiled.h" - #ifndef _PreComp_ #include #endif @@ -39,10 +37,9 @@ using namespace Base; //************************************************************************** // Python stuff of UnitsApi -// UnitsApi Methods PyMethodDef UnitsApi::Methods[] = { {"parseQuantity", - UnitsApi::sParseQuantity, + sParseQuantity, METH_VARARGS, "parseQuantity(string) -> Base.Quantity()\n\n" "calculate a mathematical expression with units to a quantity object. \n" @@ -51,27 +48,27 @@ PyMethodDef UnitsApi::Methods[] = { "or for more complex espressions:\n" "parseQuantity('sin(pi)/50.0 m/s^2')\n"}, {"listSchemas", - UnitsApi::sListSchemas, + sListSchemas, METH_VARARGS, "listSchemas() -> a tuple of schemas\n\n" "listSchemas(int) -> description of the given schema\n\n"}, {"getSchema", - UnitsApi::sGetSchema, + sGetSchema, METH_VARARGS, "getSchema() -> int\n\n" "The int is the position of the tuple returned by listSchemas"}, {"setSchema", - UnitsApi::sSetSchema, + sSetSchema, METH_VARARGS, "setSchema(int) -> None\n\n" "Sets the current schema to the given number, if possible"}, {"schemaTranslate", - UnitsApi::sSchemaTranslate, + sSchemaTranslate, METH_VARARGS, "schemaTranslate(Quantity, int) -> tuple\n\n" "Translate a quantity to a given schema"}, {"toNumber", - UnitsApi::sToNumber, + sToNumber, METH_VARARGS, "toNumber(Quantity or float, [format='g', decimals=-1]) -> str\n\n" "Convert a quantity or float to a string"}, @@ -86,30 +83,32 @@ PyObject* UnitsApi::sParseQuantity(PyObject* /*self*/, PyObject* args) return nullptr; } - Quantity rtn; - std::string str(pstr); + const std::string str {pstr}; PyMem_Free(pstr); try { - rtn = Quantity::parse(str); + return new QuantityPy(new Quantity(Quantity::parse(str))); } - catch (const Base::ParserError&) { - PyErr_Format(PyExc_ValueError, "invalid unit expression \n"); + catch (const ParserError&) { + PyErr_Format(PyExc_ValueError, + "invalid unit expression: '%s'\n", + std::string {pstr}.c_str()); return nullptr; } - - return new QuantityPy(new Quantity(rtn)); } PyObject* UnitsApi::sListSchemas(PyObject* /*self*/, PyObject* args) { + auto names = UnitsApi::getNames(); + const int num = static_cast(names.size()); + if (PyArg_ParseTuple(args, "")) { - int num = static_cast(UnitSystem::NumUnitSystemTypes); - Py::Tuple tuple(num); - for (int i = 0; i < num; i++) { - const auto description { - UnitsApi::getDescription(static_cast(i)).toStdString()}; - tuple.setItem(i, Py::String(description.c_str())); - } + Py::Tuple tuple {num}; + + auto addItem = [&, i {0}](const std::string& name) mutable { + tuple.setItem(i++, Py::String {name.c_str()}); + }; + + std::for_each(names.begin(), names.end(), addItem); return Py::new_reference_to(tuple); } @@ -117,14 +116,12 @@ PyObject* UnitsApi::sListSchemas(PyObject* /*self*/, PyObject* args) PyErr_Clear(); int index {}; if (PyArg_ParseTuple(args, "i", &index)) { - int num = static_cast(UnitSystem::NumUnitSystemTypes); if (index < 0 || index >= num) { PyErr_SetString(PyExc_ValueError, "invalid schema value"); return nullptr; } - const auto description { - UnitsApi::getDescription(static_cast(index)).toStdString()}; + const auto description = schemas->descriptions().at(index); return Py_BuildValue("s", description.c_str()); } @@ -138,20 +135,21 @@ PyObject* UnitsApi::sGetSchema(PyObject* /*self*/, PyObject* args) return nullptr; } - return Py_BuildValue("i", static_cast(currentSystem)); + return Py_BuildValue("i", count()); } PyObject* UnitsApi::sSetSchema(PyObject* /*self*/, PyObject* args) { PyErr_Clear(); int index {}; - if (PyArg_ParseTuple(args, "i", &index)) { - int num = static_cast(UnitSystem::NumUnitSystemTypes); - if (index < 0 || index >= num) { + if (PyArg_ParseTuple(args, "i", &index) != 0) { + + if (index < 0 || index >= static_cast(count())) { PyErr_SetString(PyExc_ValueError, "invalid schema value"); return nullptr; } - setSchema(static_cast(index)); + + schemas->select(index); } Py_Return; } @@ -160,27 +158,26 @@ PyObject* UnitsApi::sSchemaTranslate(PyObject* /*self*/, PyObject* args) { PyObject* py {}; int index {}; - if (!PyArg_ParseTuple(args, "O!i", &(QuantityPy::Type), &py, &index)) { + if (!PyArg_ParseTuple(args, "O!i", &QuantityPy::Type, &py, &index)) { return nullptr; } - Quantity quant; - quant = *static_cast(py)->getQuantityPtr(); - - std::unique_ptr schema(createSchema(static_cast(index))); - if (!schema) { - PyErr_SetString(PyExc_ValueError, "invalid schema value"); + if (index < 0 || index >= static_cast(count())) { + PyErr_SetString(PyExc_ValueError, + std::string {"invalid schema index:" + std::to_string(index)}.c_str()); return nullptr; } + const Quantity quant {*static_cast(py)->getQuantityPtr()}; + double factor {}; - std::string uus; - std::string uss = schema->schemaTranslate(quant, factor, uus); + std::string unitStr; + const std::string unitStrLocalised = schemaTranslate(quant, factor, unitStr); - Py::Tuple res(3); - res[0] = Py::String(uss, "utf-8"); - res[1] = Py::Float(factor); - res[2] = Py::String(uus, "utf-8"); + Py::Tuple res {3}; + res[0] = Py::String {unitStrLocalised, "utf-8"}; + res[1] = Py::Float {factor}; + res[2] = Py::String {unitStr, "utf-8"}; return Py::new_reference_to(res); } diff --git a/src/Base/UnitsSchema.cpp b/src/Base/UnitsSchema.cpp index bb544f3259..c576d65919 100644 --- a/src/Base/UnitsSchema.cpp +++ b/src/Base/UnitsSchema.cpp @@ -1,49 +1,142 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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 * - * * - ***************************************************************************/ - -#include "PreCompiled.h" -#ifdef __GNUC__ -#include -#endif - -#include -#include - -#include "Quantity.h" -#include "UnitsSchema.h" - -using namespace Base; - -std::string UnitsSchema::toLocale(const Base::Quantity& quant, - double factor, - const std::string& unitString) const -{ - QLocale Lc; - const QuantityFormat& format = quant.getFormat(); - if (format.option != QuantityFormat::None) { - int opt = format.option; - Lc.setNumberOptions(static_cast(opt)); - } - - QString Ln = Lc.toString((quant.getValue() / factor), format.toFormat(), format.precision); - return QStringLiteral("%1 %2").arg(Ln, QString::fromStdString(unitString)).toStdString(); -} +/************************************************************************ + * * + * 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 * + * * + ************************************************************************/ + +#include "PreCompiled.h" + +#include +#include +#include + +#include +#include + +#include "Quantity.h" +#include "UnitsSchema.h" +#include "UnitsSchemasData.h" +#include "UnitsSchemasSpecs.h" +#include "Exception.h" +#include "Quantity.h" + +using Base::UnitsSchema; +using Base::UnitsSchemaSpec; + + +UnitsSchema::UnitsSchema(UnitsSchemaSpec spec) + : spec {std::move(spec)} +{} + +std::string UnitsSchema::translate(const Quantity& quant) const +{ // to satisfy GCC + double dummy1 {}; + std::string dummy2; + return translate(quant, dummy1, dummy2); +} + +std::string +UnitsSchema::translate(const Quantity& quant, double& factor, std::string& unitString) const +{ + if (spec.translationSpecs.empty()) { + return toLocale(quant, 1.0, unitString); + } + + const auto unitName = quant.getUnit().getTypeString(); + + if (spec.translationSpecs.count(unitName) == 0) { + // no schema-level translation. Use defaults. + factor = 1.0; + unitString = quant.getUnit().getString(); + + return toLocale(quant, factor, unitString); + } + + const auto value = quant.getValue(); + + auto isSuitable = [&](const UnitTranslationSpec& row) { + return row.threshold > value || row.threshold == 0; // zero indicates default + }; + + auto unitSpecs = spec.translationSpecs.at(unitName); + const auto unitSpec = std::find_if(unitSpecs.begin(), unitSpecs.end(), isSuitable); + if (unitSpec == unitSpecs.end()) { + throw RuntimeError("Suitable threshhold not found. Schema: " + spec.name + + " value: " + std::to_string(value)); + } + + if (unitSpec->factor == 0) { + return UnitsSchemasData::runSpecial(unitSpec->unitString, value); + } + + factor = unitSpec->factor; + unitString = unitSpec->unitString; + + return toLocale(quant, factor, unitString); +} + +std::string +UnitsSchema::toLocale(const Quantity& quant, const double factor, const std::string& unitString) +{ + QLocale Lc; + const QuantityFormat& format = quant.getFormat(); + if (format.option != QuantityFormat::None) { + int opt = format.option; + Lc.setNumberOptions(static_cast(opt)); + } + + std::string valueString = + Lc.toString((quant.getValue() / factor), format.toFormat(), format.precision).toStdString(); + + return fmt::format( + "{}{}{}", + valueString, + unitString.empty() || unitString == "°" || unitString == "″" || unitString == "′" ? "" + : " ", + unitString); +} + +bool UnitsSchema::isMultiUnitLength() const +{ + return spec.isMultUnitLen; +} + +bool UnitsSchema::isMultiUnitAngle() const +{ + return spec.isMultUnitAngle; +} + +std::string UnitsSchema::getBasicLengthUnit() const +{ + return spec.basicLengthUnitStr; +} + +std::string UnitsSchema::getName() const +{ + return spec.name; +} + +std::string UnitsSchema::getDescription() const +{ + return spec.description; +} + +int UnitsSchema::getNum() const +{ + return static_cast(spec.num); +} diff --git a/src/Base/UnitsSchema.h b/src/Base/UnitsSchema.h index 117b46e86a..6587d5359b 100644 --- a/src/Base/UnitsSchema.h +++ b/src/Base/UnitsSchema.h @@ -24,78 +24,41 @@ #define BASE_UNITSSCHEMA_H #include +#include + +#include "UnitsSchemasSpecs.h" +#include "Base/Quantity.h" namespace Base { class Quantity; -/** Units systems */ -enum class UnitSystem -{ - SI1 = 0, /** internal (mm,kg,s) SI system - (http://en.wikipedia.org/wiki/International_System_of_Units) */ - SI2 = 1, /** MKS (m,kg,s) SI system */ - Imperial1 = 2, /** the Imperial system (http://en.wikipedia.org/wiki/Imperial_units) */ - ImperialDecimal = 3, /** Imperial with length in inch only */ - Centimeters = 4, /** All lengths in centimeters, areas and volumes in square/cubic meters */ - ImperialBuilding = 5, /** All lengths in feet + inches + fractions */ - MmMin = 6, /** Lengths in mm, Speed in mm/min. Angle in degrees. Useful for small parts & CNC */ - ImperialCivil = 7, /** Lengths in ft, Speed in ft/s. Used in Civil Eng in North America */ - FemMilliMeterNewton = 8, /** Lengths in mm, Mass in t, TimeSpan in s, thus force is in N */ - MeterDecimal = 9, /** Lengths in metres always */ - NumUnitSystemTypes // must be the last item! -}; - - -/** The UnitSchema class - * The subclasses of this class define the stuff for a - * certain units schema. +/** + * An individual schema object */ class UnitsSchema { public: - UnitsSchema() = default; - UnitsSchema(const UnitsSchema&) = default; - UnitsSchema(UnitsSchema&&) = default; - UnitsSchema& operator=(const UnitsSchema&) = default; - UnitsSchema& operator=(UnitsSchema&&) = default; - virtual ~UnitsSchema() = default; - /** Gets called if this schema gets activated. - * Here it's theoretically possible that you can change the static factors - * for certain units (e.g. mi = 1,8km instead of mi=1.6km). - */ - virtual void setSchemaUnits() - {} - /// If you use setSchemaUnits() you also have to impment this method to undo your changes! - virtual void resetSchemaUnits() - {} + explicit UnitsSchema(UnitsSchemaSpec spec); + UnitsSchema() = delete; - /// This method translates the quantity in a string as the user may expect it. - virtual std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) = 0; + [[nodiscard]] bool isMultiUnitLength() const; + [[nodiscard]] bool isMultiUnitAngle() const; + [[nodiscard]] std::string getBasicLengthUnit() const; + [[nodiscard]] std::string getName() const; + [[nodiscard]] std::string getDescription() const; + [[nodiscard]] int getNum() const; - std::string - toLocale(const Base::Quantity& quant, double factor, const std::string& unitString) const; + std::string translate(const Quantity& quant) const; + std::string translate(const Quantity& quant, double& factor, std::string& unitString) const; - // return true if this schema uses multiple units for length (ex. Ft/In) - virtual bool isMultiUnitLength() const - { - return false; - } +private: + [[nodiscard]] static std::string + toLocale(const Quantity& quant, double factor, const std::string& unitString); - // return true if this schema uses multiple units for angles (ex. DMS) - virtual bool isMultiUnitAngle() const - { - return false; - } - - // return the basic length unit for this schema - virtual std::string getBasicLengthUnit() const - { - return {"mm"}; - } + UnitsSchemaSpec spec; }; -} // namespace Base +} // namespace Base #endif // BASE_UNITSSCHEMA_H diff --git a/src/Base/UnitsSchemaCentimeters.cpp b/src/Base/UnitsSchemaCentimeters.cpp deleted file mode 100644 index f1b45119ca..0000000000 --- a/src/Base/UnitsSchemaCentimeters.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2016 Yorik van Havre * - * * - * 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 * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" -#ifndef _PreComp_ -#include -#include -#endif - -#include "Quantity.h" -#include "Unit.h" -#include "UnitsSchemaCentimeters.h" - -using namespace Base; - -std::string UnitsSchemaCentimeters::schemaTranslate(const Base::Quantity& quant, - double& factor, - std::string& unitString) -{ - static std::array>, 7> unitSpecs {{ - {Unit::Length, {"cm", 10.0}}, - {Unit::Area, {"m^2", 1000000.0}}, - {Unit::Volume, {"m^3", 1000000000.0}}, - {Unit::Power, {"W", 1000000.0}}, - {Unit::ElectricPotential, {"V", 1000000.0}}, - {Unit::HeatFlux, {"W/m^2", 1.0}}, - {Unit::Velocity, {"mm/min", 1.0 / 60}}, - }}; - - const auto unit = quant.getUnit(); - const auto spec = std::find_if(unitSpecs.begin(), unitSpecs.end(), [&](const auto& pair) { - return pair.first == unit; - }); - - if (spec != std::end(unitSpecs)) { - unitString = spec->second.first; - factor = spec->second.second; - } - else { - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} diff --git a/src/Base/UnitsSchemaCentimeters.h b/src/Base/UnitsSchemaCentimeters.h deleted file mode 100644 index afe555bb3e..0000000000 --- a/src/Base/UnitsSchemaCentimeters.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2016 Yorik van Havre * - * * - * 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_UNITSSCHEMACENTIMETERS_H -#define BASE_UNITSSCHEMACENTIMETERS_H - -#include "UnitsSchema.h" - -namespace Base -{ - -/** - * The UnitSchema class - */ -class UnitsSchemaCentimeters: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; - - std::string getBasicLengthUnit() const override - { - return {"cm"}; - } -}; - -} // namespace Base - -#endif // BASE_UNITSSCHEMACENTIMETERS_H diff --git a/src/Base/UnitsSchemaFemMilliMeterNewton.cpp b/src/Base/UnitsSchemaFemMilliMeterNewton.cpp deleted file mode 100644 index 602f825304..0000000000 --- a/src/Base/UnitsSchemaFemMilliMeterNewton.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * Copyright (c) 2020 Bernd Hahnebach * - * * - * 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 * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" -#ifndef _PreComp_ -#include -#include -#endif - -#include "Quantity.h" -#include "Unit.h" -#include "UnitsSchemaFemMilliMeterNewton.h" - -using namespace Base; - -std::string UnitsSchemaFemMilliMeterNewton::schemaTranslate(const Quantity& quant, - double& factor, - std::string& unitString) -{ - static std::array>, 2> unitSpecs {{ - {Unit::Length, {"mm", 1.0}}, - {Unit::Mass, {"t", 1e3}}, - }}; - - const auto unit = quant.getUnit(); - const auto spec = std::find_if(unitSpecs.begin(), unitSpecs.end(), [&](const auto& pair) { - return pair.first == unit; - }); - - if (spec != std::end(unitSpecs)) { - unitString = spec->second.first; - factor = spec->second.second; - } - else { - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} diff --git a/src/Base/UnitsSchemaFemMilliMeterNewton.h b/src/Base/UnitsSchemaFemMilliMeterNewton.h deleted file mode 100644 index 313139b17f..0000000000 --- a/src/Base/UnitsSchemaFemMilliMeterNewton.h +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * Copyright (c) 2020 Bernd Hahnebach * - * * - * 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_UNITSSCHEMAFEMMLLIMETERNEWTON_H -#define BASE_UNITSSCHEMAFEMMLLIMETERNEWTON_H - -#include "UnitsSchema.h" - -namespace Base -{ - -/* Milli metric / Newton / Seconds unit schema for use in FEM. - * Lengths are always in mm. - * Mass is in t. - * TimeSpann in S. - * Thus the Force is in Newton - */ -class UnitsSchemaFemMilliMeterNewton: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; -}; - -} // namespace Base - -#endif // BASE_UNITSSCHEMAFEMMLLIMETERNEWTON_H diff --git a/src/Base/UnitsSchemaImperial1.cpp b/src/Base/UnitsSchemaImperial1.cpp deleted file mode 100644 index 49f36e322f..0000000000 --- a/src/Base/UnitsSchemaImperial1.cpp +++ /dev/null @@ -1,400 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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 * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" -#ifndef _PreComp_ -#include -#include -#endif -#ifdef __GNUC__ -#include -#endif - -#include "Quantity.h" -#include "UnitsSchemaImperial1.h" - -using namespace Base; - -std::string UnitsSchemaImperial1::schemaTranslate(const Quantity& quant, - double& factor, - std::string& unitString) -{ - double UnitValue = std::abs(quant.getValue()); - Unit unit = quant.getUnit(); - // for imperial user/programmer mind; UnitValue is in internal system, that means - // mm/kg/s. And all combined units have to be calculated from there! - - // now do special treatment on all cases seems necessary: - if (unit == Unit::Length) { // Length handling ============================ - if (UnitValue < 0.00000254) { // smaller then 0.001 thou -> inch and scientific notation - unitString = "in"; - factor = 25.4; - } - else if (UnitValue < 2.54) { // smaller then 0.1 inch -> Thou (mil) - unitString = "thou"; - factor = 0.0254; - } - else if (UnitValue < 304.8) { - unitString = "\""; - factor = 25.4; - } - else if (UnitValue < 914.4) { - unitString = "\'"; - factor = 304.8; - } - else if (UnitValue < 1609344.0) { - unitString = "yd"; - factor = 914.4; - } - else if (UnitValue < 1609344000.0) { - unitString = "mi"; - factor = 1609344.0; - } - else { // bigger then 1000 mi -> scientific notation - unitString = "in"; - factor = 25.4; - } - } - else if (unit == Unit::Angle) { - unitString = "\xC2\xB0"; - factor = 1.0; - } - else if (unit == Unit::Area) { - // TODO: Cascade for the Areas - // default action for all cases without special treatment: - unitString = "in^2"; - factor = 645.16; - } - else if (unit == Unit::Volume) { - // TODO: Cascade for the Volume - // default action for all cases without special treatment: - unitString = "in^3"; - factor = 16387.064; - } - else if (unit == Unit::Mass) { - // TODO: Cascade for the weights - // default action for all cases without special treatment: - unitString = "lb"; - factor = 0.45359237; - } - else if (unit == Unit::Pressure) { - if (UnitValue < 6894.744) { // psi is the smallest - unitString = "psi"; - factor = 6.894744825494; - } - else if (UnitValue < 6894744.825) { - unitString = "ksi"; - factor = 6894.744825494; - } - else { // bigger then 1000 ksi -> psi + scientific notation - unitString = "psi"; - factor = 6.894744825494; - } - } - else if (unit == Unit::Stiffness) { // Conversion to lbf/in - unitString = "lbf/in"; - factor = 4.448222 / 0.0254; - } - else if (unit == Unit::Velocity) { - unitString = "in/min"; - factor = 25.4 / 60; - } - else { - // default action for all cases without special treatment: - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} - -std::string UnitsSchemaImperialDecimal::schemaTranslate(const Base::Quantity& quant, - double& factor, - std::string& unitString) -{ - Unit unit = quant.getUnit(); - // for imperial user/programmer mind; UnitValue is in internal system, that means - // mm/kg/s. And all combined units have to be calculated from there! - - // now do special treatment on all cases seems necessary: - if (unit == Unit::Length) { // Length handling ============================ - unitString = "in"; - factor = 25.4; - } - else if (unit == Unit::Angle) { - unitString = "\xC2\xB0"; - factor = 1.0; - } - else if (unit == Unit::Area) { - // TODO: Cascade for the Areas - // default action for all cases without special treatment: - unitString = "in^2"; - factor = 645.16; - } - else if (unit == Unit::Volume) { - // TODO: Cascade for the Volume - // default action for all cases without special treatment: - unitString = "in^3"; - factor = 16387.064; - } - else if (unit == Unit::Mass) { - // TODO: Cascade for the weights - // default action for all cases without special treatment: - unitString = "lb"; - factor = 0.45359237; - } - else if (unit == Unit::Pressure) { - unitString = "psi"; - factor = 6.894744825494; - } - else if (unit == Unit::Stiffness) { - unitString = "lbf/in"; - factor = 4.448222 / 0.0254; - } - else if (unit == Unit::Velocity) { - unitString = "in/min"; - factor = 25.4 / 60; - } - else if (unit == Unit::Acceleration) { - unitString = "in/min^2"; - factor = 25.4 / 3600; - } - else { - // default action for all cases without special treatment: - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} - -std::string UnitsSchemaImperialBuilding::schemaTranslate(const Quantity& quant, - double& factor, - std::string& unitString) -{ - // this schema expresses distances in feet + inches + fractions - // ex: 3'- 4 1/4" with proper rounding - Unit unit = quant.getUnit(); - if (unit == Unit::Length) { - unitString = "in"; - factor = 25.4; - - // Total number of inches to format - double totalInches = std::abs(quant.getValue()) / factor; - - // minimum denominator (8 for 1/8, 16 for 1/16, etc) - int minden {}; - - // Outputs - int feet {}; // whole feet - int inches {}; // whole inches - int num {}, den {}; // numerator and denominator of fractional val - std::stringstream output; // output stream - - // Intermediate values - int ntot {}; // total fractional units - int a {}, b {}, d {}; // used to compute greatest common denominator - int tmp {}; // temporary variable for GCD - - // Get the current user specified minimum denominator - minden = quant.getFormat().getDenominator(); - - // Compute and round the total number of fractional units - ntot = static_cast(std::round(totalInches * static_cast(minden))); - - // If this is zero, nothing to do but return - if (ntot == 0) { - return "0"; - } - - // Compute the whole number of feet and remaining units - feet = static_cast(std::floor(ntot / (12 * minden))); - ntot = ntot - 12 * minden * feet; - - // Compute the remaining number of whole inches - inches = static_cast(std::floor(ntot / minden)); - - // Lastly the fractional quantities - num = ntot - inches * minden; - den = minden; - - // If numerator is not zero, compute greatest common divisor and reduce - // fraction - if (num != 0) { - // initialize - a = num; - b = den; - while (b != 0) { - tmp = a % b; - - a = b; - b = tmp; - } - d = a; - - num /= d; - den /= d; - } - - // Process into string. Start with negative sign if quantity is less - // than zero - char plusOrMinus {}; - if (quant.getValue() < 0) { - output << "-"; - plusOrMinus = '-'; - } - else { - plusOrMinus = '+'; - } - - bool trailingNumber = false; - // Print feet if we have any - if (feet != 0) { - output << feet << "'"; - trailingNumber = true; - } - // Print whole inches if we have any - if (inches != 0) { - if (trailingNumber) { - output << " "; - } - output << inches << "\""; - trailingNumber = true; - } - // Print fractional inches if we have any - if (num != 0) { - if (trailingNumber) { - output << " " << plusOrMinus << " "; - } - output << num << "/" << den << "\""; - } - - // Done! - return output.str(); - } - else if (unit == Unit::Angle) { - unitString = "\xC2\xB0"; - factor = 1.0; - } - else if (unit == Unit::Area) { - unitString = "sqft"; - factor = 92903.04; - } - else if (unit == Unit::Volume) { - unitString = "cft"; - factor = 28316846.592; - } - else if (unit == Unit::Velocity) { - unitString = "in/min"; - factor = 25.4 / 60; - } - else { - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} - -std::string UnitsSchemaImperialCivil::schemaTranslate(const Base::Quantity& quant, - double& factor, - std::string& unitString) -{ - Unit unit = quant.getUnit(); - // for imperial user/programmer mind; UnitValue is in internal system, that means - // mm/kg/s. And all combined units have to be calculated from there! - - // now do special treatment on all cases seems necessary: - if (unit == Unit::Length) { // Length handling ============================ - unitString = "ft"; // always ft - factor = 304.8; // 12 * 25.4 - } - else if (unit == Unit::Area) { - unitString = "ft^2"; // always sq.ft - factor = 92903.04; - } - else if (unit == Unit::Volume) { - unitString = "ft^3"; // always cu. ft - factor = 28316846.592; - } - else if (unit == Unit::Mass) { - unitString = "lb"; // always lbs. - factor = 0.45359237; - } - else if (unit == Unit::Pressure) { - unitString = "psi"; - factor = 6.894744825494; - } - else if (unit == Unit::Stiffness) { - unitString = "lbf/in"; - factor = 4.448222 / 0.0254; - } - else if (unit == Unit::Velocity) { - unitString = "mph"; - factor = 447.04; // 1mm/sec => mph - } - // this schema expresses angles in degrees + minutes + seconds - else if (unit == Unit::Angle) { - unitString = "deg"; - std::string degreeString = "\xC2\xB0"; // degree symbol - std::string minuteString = "\xE2\x80\xB2"; // prime symbol - std::string secondString = "\xE2\x80\xB3"; // double prime symbol - factor = 1.0; // 1deg = 1"\xC2\xB0 " - - double totalDegrees = quant.getValue() / factor; - double wholeDegrees = std::floor(totalDegrees); - double sumMinutes = totalDegrees * 60.0; // quant as minutes - double rawMinutes = sumMinutes - wholeDegrees * 60.0; - double wholeMinutes = std::floor(rawMinutes); - double sumSeconds = totalDegrees * 3600.0; // quant as seconds - double rawSeconds = sumSeconds - (wholeDegrees * 3600.0) - (wholeMinutes * 60); - - int outDeg = static_cast(wholeDegrees); - int outMin = static_cast(wholeMinutes); - int outSec = static_cast(std::round(rawSeconds)); - - std::stringstream output; - output << outDeg << degreeString; - if ((outMin > 0) || (outSec > 0)) { - output << outMin << minuteString; - } - if (outSec > 0) { - output << outSec << secondString; - } - // uncomment this for decimals on seconds - // if (remainSeconds < (1.0 * pow(10.0,-Base::UnitsApi::getDecimals())) ) { - // //NOP too small to display - // } else { - // output << std::setprecision(Base::UnitsApi::getDecimals()) << std::fixed << - // rawSeconds << secondString.toStdString(); - // } - return output.str(); - } - else { - // default action for all cases without special treatment: - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} diff --git a/src/Base/UnitsSchemaImperial1.h b/src/Base/UnitsSchemaImperial1.h deleted file mode 100644 index fe4f10eff5..0000000000 --- a/src/Base/UnitsSchemaImperial1.h +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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_UNITSSCHEMAIMPERIAL1_H -#define BASE_UNITSSCHEMAIMPERIAL1_H - -#include "UnitsSchema.h" - -namespace Base -{ - -/** The schema class for the imperial unit system - * Here are the definitions for the imperial unit system. - * It also defines how the value/units get printed. - */ -class UnitsSchemaImperial1: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; - std::string getBasicLengthUnit() const override - { - return {"in"}; - } -}; - -/** The schema class for the imperial unit system - * Here are the definitions for the imperial unit system. - * It also defines how the value/units get printed. - */ -class UnitsSchemaImperialDecimal: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; - std::string getBasicLengthUnit() const override - { - return {"in"}; - } -}; - -/** The schema class for the imperial unit system - * Here are the definitions for the imperial unit system. - * It also defines how the value/units get printed. - */ -class UnitsSchemaImperialBuilding: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; - std::string getBasicLengthUnit() const override - { - return {"ft"}; - } - - // return true if this schema uses multiple units for length (ex. Ft/In) - bool isMultiUnitLength() const override - { - return true; - } -}; - -/** The schema class for Civil Engineering in the imperial unit system - * All measurements in ft, ft^2, ft^3, ft/sec. - * Pressure is in psi. - */ -class UnitsSchemaImperialCivil: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; - std::string getBasicLengthUnit() const override - { - return {"ft"}; - } - - // return true if this schema uses multiple units for angles (ex. DMS) - bool isMultiUnitAngle() const override - { - return true; - } -}; - -} // namespace Base - -#endif // BASE_UNITSSCHEMAIMPERIAL1_H diff --git a/src/Base/UnitsSchemaInternal.cpp b/src/Base/UnitsSchemaInternal.cpp deleted file mode 100644 index f06286ff3e..0000000000 --- a/src/Base/UnitsSchemaInternal.cpp +++ /dev/null @@ -1,671 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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 * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" -#ifndef _PreComp_ -#include -#endif -#ifdef __GNUC__ -#include -#endif - - -#include "Quantity.h" -#include "Unit.h" -#include "UnitsSchemaInternal.h" - -using namespace Base; - -std::string -UnitsSchemaInternal::schemaTranslate(const Quantity& quant, double& factor, std::string& unitString) -{ - double UnitValue = std::abs(quant.getValue()); - Unit unit = quant.getUnit(); - - // In order to get the right factor always express the target - // units as internal units where length is in mm and mass in kg - // Example: - // For W/mm/K we get the factor of 1000000.0 because - // W/mm/K = kg*m^2/s^3/mm/K - // = 10e6 * kg*mm^2/s^3/mm/K - // = 10e6 * kg*mm/s^3/K - - // now do special treatment on all cases seems necessary: - if (unit == Unit::Length) { // Length handling ============================ - if (UnitValue < 1e-6) { // smaller than 0.001 nm -> scientific notation - unitString = "mm"; - factor = 1.0; - } - else if (UnitValue < 1e-3) { - unitString = "nm"; - factor = 1e-6; - } - else if (UnitValue < 0.1) { - unitString = "\xC2\xB5m"; - factor = 1e-3; - } - else if (UnitValue < 1e4) { - unitString = "mm"; - factor = 1.0; - } - else if (UnitValue < 1e7) { - unitString = "m"; - factor = 1e3; - } - else if (UnitValue < 1e10) { - unitString = "km"; - factor = 1e6; - } - else { // bigger than 1000 km -> scientific notation - unitString = "m"; - factor = 1e3; - } - } - else if (unit == Unit::Area) { - if (UnitValue < 100) { - unitString = "mm^2"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "cm^2"; - factor = 100; - } - else if (UnitValue < 1e12) { - unitString = "m^2"; - factor = 1e6; - } - else { // bigger than 1 square kilometer - unitString = "km^2"; - factor = 1e12; - } - } - else if (unit == Unit::Volume) { - if (UnitValue < 1e3) { // smaller than 1 ul - unitString = "mm^3"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "ml"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "l"; - factor = 1e6; - } - else { // bigger than 1000 l - unitString = "m^3"; - factor = 1e9; - } - } - else if (unit == Unit::Angle) { - // TODO: Cascade for the Areas - // default action for all cases without special treatment: - unitString = "\xC2\xB0"; - factor = 1.0; - } - else if (unit == Unit::Mass) { - if (UnitValue < 1e-6) { - unitString = "\xC2\xB5g"; - factor = 1e-9; - } - else if (UnitValue < 1e-3) { - unitString = "mg"; - factor = 1e-6; - } - else if (UnitValue < 1.0) { - unitString = "g"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "kg"; - factor = 1.0; - } - else { - unitString = "t"; - factor = 1e3; - } - } - else if (unit == Unit::Density) { - if (UnitValue < 0.0001) { - unitString = "kg/m^3"; - factor = 1e-9; - } - else if (UnitValue < 1.0) { - unitString = "kg/cm^3"; - factor = 0.001; - } - else { - unitString = "kg/mm^3"; - factor = 1.0; - } - } - else if (unit == Unit::ThermalConductivity) { - if (UnitValue > 1e6) { - unitString = "W/mm/K"; - factor = 1e6; - } - else { - unitString = "W/m/K"; - factor = 1000.0; - } - } - else if (unit == Unit::ThermalExpansionCoefficient) { - if (UnitValue < 0.001) { - unitString = "\xC2\xB5m/m/K"; // micro-meter/meter/K - factor = 1e-6; - } - else { - unitString = "mm/mm/K"; - factor = 1.0; - } - } - else if (unit == Unit::VolumetricThermalExpansionCoefficient) { - if (UnitValue < 0.001) { - unitString = "mm^3/m^3/K"; - factor = 1e-9; - } - else { - unitString = "m^3/m^3/K"; - factor = 1.0; - } - } - else if (unit == Unit::SpecificHeat) { - unitString = "J/kg/K"; - factor = 1e6; - } - else if (unit == Unit::ThermalTransferCoefficient) { - unitString = "W/m^2/K"; - factor = 1.0; - } - else if ((unit == Unit::Pressure) || (unit == Unit::Stress)) { - if (UnitValue < 10.0) { // Pa is the smallest - unitString = "Pa"; - factor = 0.001; - } - else if (UnitValue < 10000.0) { - unitString = "kPa"; - factor = 1.0; - } - else if (UnitValue < 10000000.0) { - unitString = "MPa"; - factor = 1000.0; - } - else if (UnitValue < 10000000000.0) { - unitString = "GPa"; - factor = 1e6; - } - else { // bigger -> scientific notation - unitString = "Pa"; - factor = 0.001; - } - } - else if ((unit == Unit::Stiffness)) { - if (UnitValue < 1) { // mN/m is the smallest - unitString = "mN/m"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "N/m"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "kN/m"; - factor = 1e3; - } - else { - unitString = "MN/m"; - factor = 1e6; - } - } - else if ((unit == Unit::StiffnessDensity)) { - if (UnitValue < 1e-3) { - unitString = "Pa/m"; - factor = 1e-6; - } - else if (UnitValue < 1) { - unitString = "kPa/m"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "MPa/m"; - factor = 1.0; - } - else { - unitString = "GPa/m"; - factor = 1e3; - } - } - else if (unit == Unit::Force) { - if (UnitValue < 1e3) { - unitString = "mN"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "N"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "kN"; - factor = 1e6; - } - else { - unitString = "MN"; - factor = 1e9; - } - } - // else if (unit == Unit::Moment) { - // if (UnitValue < 1e6) { - // unitString = "mNm"; - // factor = 1e3; - // } - // else if (UnitValue < 1e9) { - // unitString = "Nm"; - // factor = 1e6; - // } - // else if (UnitValue < 1e12) { - // unitString = "kNm"; - // factor = 1e9; - // } - // else { - // unitString = "MNm"; - // factor = 1e12; - // } - // } - else if (unit == Unit::Power) { - if (UnitValue < 1e6) { - unitString = "mW"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "W"; - factor = 1e6; - } - else { - unitString = "kW"; - factor = 1e9; - } - } - else if (unit == Unit::ElectricPotential) { - if (UnitValue < 1e6) { - unitString = "mV"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "V"; - factor = 1e6; - } - else if (UnitValue < 1e12) { - unitString = "kV"; - factor = 1e9; - } - else { // > 1000 kV scientificc notation - unitString = "V"; - factor = 1e6; - } - } - else if (unit == Unit::Work) { - if (UnitValue < 1.602176634e-10) { - unitString = "eV"; - factor = 1.602176634e-13; - } - else if (UnitValue < 1.602176634e-7) { - unitString = "keV"; - factor = 1.602176634e-10; - } - else if (UnitValue < 1.602176634e-4) { - unitString = "MeV"; - factor = 1.602176634e-7; - } - else if (UnitValue < 1e6) { - unitString = "mJ"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "J"; - factor = 1e6; - } - else if (UnitValue < 1e12) { - unitString = "kJ"; - factor = 1e9; - } - else if (UnitValue < 3.6e+15) { - unitString = "kWh"; - factor = 3.6e+12; - } - else { // bigger than 1000 kWh -> scientific notation - unitString = "J"; - factor = 1e6; - } - } - else if (unit == Unit::SpecificEnergy) { - unitString = "m^2/s^2"; - factor = 1e6; - } - else if (unit == Unit::HeatFlux) { - unitString = "W/m^2"; - factor = 1; // unit signature (0,1,-3,0,0) is length independent - } - else if (unit == Unit::ElectricCharge) { - unitString = "C"; - factor = 1.0; - } - else if (unit == Unit::SurfaceChargeDensity) { - if (UnitValue <= 1e-4) { - unitString = "C/m^2"; - factor = 1e-6; - } - else if (UnitValue <= 1e-2) { - unitString = "C/cm^2"; - factor = 1e-2; - } - else { - unitString = "C/mm^2"; - factor = 1; - } - } - else if (unit == Unit::VolumeChargeDensity) { - if (UnitValue <= 1e-4) { - unitString = "C/m^3"; - factor = 1e-9; - } - else if (UnitValue <= 1e-2) { - unitString = "C/cm^3"; - factor = 1e-3; - } - else { - unitString = "C/mm^3"; - factor = 1; - } - } - else if (unit == Unit::CurrentDensity) { - if (UnitValue <= 1e-4) { - unitString = "A/m^2"; - factor = 1e-6; - } - else if (UnitValue <= 1e-2) { - unitString = "A/cm^2"; - factor = 1e-2; - } - else { - unitString = "A/mm^2"; - factor = 1; - } - } - else if (unit == Unit::MagneticFluxDensity) { - if (UnitValue <= 1e-3) { - unitString = "G"; - factor = 1e-4; - } - else { - unitString = "T"; - factor = 1.0; - } - } - else if (unit == Unit::MagneticFieldStrength) { - unitString = "A/m"; - factor = 1e-3; - } - else if (unit == Unit::MagneticFlux) { - unitString = "Wb"; - factor = 1e6; - } - else if (unit == Unit::Magnetization) { - unitString = "A/m"; - factor = 1e-3; - } - else if (unit == Unit::ElectromagneticPotential) { - unitString = "Wb/m"; - factor = 1e3; - } - else if (unit == Unit::ElectricalConductance) { - if (UnitValue < 1e-9) { - unitString = "\xC2\xB5S"; - factor = 1e-12; - } - else if (UnitValue < 1e-6) { - unitString = "mS"; - factor = 1e-9; - } - else { - unitString = "S"; - factor = 1e-6; - } - } - else if (unit == Unit::ElectricalResistance) { - if (UnitValue < 1e9) { - unitString = "Ohm"; - factor = 1e6; - } - else if (UnitValue < 1e12) { - unitString = "kOhm"; - factor = 1e9; - } - else { - unitString = "MOhm"; - factor = 1e12; - } - } - else if (unit == Unit::ElectricalConductivity) { - if (UnitValue < 1e-3) { - unitString = "mS/m"; - factor = 1e-12; - } - else if (UnitValue < 1.0) { - unitString = "S/m"; - factor = 1e-9; - } - else if (UnitValue < 1e3) { - unitString = "kS/m"; - factor = 1e-6; - } - else { - unitString = "MS/m"; - factor = 1e-3; - } - } - else if (unit == Unit::ElectricalCapacitance) { - if (UnitValue < 1e-15) { - unitString = "pF"; - factor = 1e-18; - } - else if (UnitValue < 1e-12) { - unitString = "nF"; - factor = 1e-15; - } - else if (UnitValue < 1e-9) { - // \x reads everything to the end, therefore split - unitString = "\xC2\xB5" - "F"; - factor = 1e-12; - } - else if (UnitValue < 1e-6) { - unitString = "mF"; - factor = 1e-9; - } - else { - unitString = "F"; - factor = 1e-6; - } - } - else if (unit == Unit::ElectricalInductance) { - if (UnitValue < 1.0) { - unitString = "nH"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "\xC2\xB5H"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "mH"; - factor = 1e3; - } - else { - unitString = "H"; - factor = 1e6; - } - } - else if (unit == Unit::VacuumPermittivity) { - unitString = "F/m"; - factor = 1e-9; - } - else if (unit == Unit::Frequency) { - if (UnitValue < 1e3) { - unitString = "Hz"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "kHz"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "MHz"; - factor = 1e6; - } - else if (UnitValue < 1e12) { - unitString = "GHz"; - factor = 1e9; - } - else { - unitString = "THz"; - factor = 1e12; - } - } - else if (unit == Unit::Velocity) { - unitString = "mm/s"; - factor = 1.0; - } - else if (unit == Unit::DynamicViscosity) { - unitString = "Pa*s"; - factor = 0.001; - } - else if (unit == Unit::KinematicViscosity) { - if (UnitValue < 1e3) { - unitString = "mm^2/s"; - factor = 1.0; - } - else { - unitString = "m^2/s"; - factor = 1e6; - } - } - else if (unit == Unit::VolumeFlowRate) { - if (UnitValue < 1e3) { - unitString = "mm^3/s"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "ml/s"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "l/s"; - factor = 1e6; - } - else { - unitString = "m^3/s"; - factor = 1e9; - } - } - else if (unit == Unit::DissipationRate) { - unitString = "W/kg"; - factor = 1e6; - } - else if (unit == Unit::InverseLength) { - if (UnitValue < 1e-6) { // smaller than 0.001 1/km -> scientific notation - unitString = "1/m"; - factor = 1e-3; - } - else if (UnitValue < 1e-3) { - unitString = "1/km"; - factor = 1e-6; - } - else if (UnitValue < 1.0) { - unitString = "1/m"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "1/mm"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "1/\xC2\xB5m"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "1/nm"; - factor = 1e6; - } - else { // larger -> scientific notation - unitString = "1/m"; - factor = 1e-3; - } - } - else if (unit == Unit::InverseArea) { - if (UnitValue < 1e-12) { // smaller than 0.001 1/km^2 -> scientific notation - unitString = "1/m^2"; - factor = 1e-6; - } - else if (UnitValue < 1e-6) { - unitString = "1/km^2"; - factor = 1e-12; - } - else if (UnitValue < 1.0) { - unitString = "1/m^2"; - factor = 1e-6; - } - else if (UnitValue < 1e2) { - unitString = "1/cm^2"; - factor = 1e-2; - } - else { - unitString = "1/mm^2"; - factor = 1.0; - } - } - else if (unit == Unit::InverseVolume) { - if (UnitValue < 1e-6) { - unitString = "1/m^3"; - factor = 1e-9; - } - else if (UnitValue < 1e-3) { - unitString = "1/l"; - factor = 1e-6; - } - else if (UnitValue < 1.0) { - unitString = "1/ml"; - factor = 1e-3; - } - else { - unitString = "1/mm^3"; - factor = 1.0; - } - } - else { - // default action for all cases without special treatment: - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} diff --git a/src/Base/UnitsSchemaInternal.h b/src/Base/UnitsSchemaInternal.h deleted file mode 100644 index 0231112d60..0000000000 --- a/src/Base/UnitsSchemaInternal.h +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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_UNITSSCHEMAINTERNAL_H -#define BASE_UNITSSCHEMAINTERNAL_H - -#include "UnitsSchema.h" - -namespace Base -{ - -/** The standard units schema - * Here is defined what internal (base) units FreeCAD uses. - * FreeCAD uses a mm/kg/deg scala. - * Also it defines how the units get presented. - */ -class UnitsSchemaInternal: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; -}; - -} // namespace Base - -#endif // BASE_UNITSSCHEMAINTERNAL_H diff --git a/src/Base/UnitsSchemaMKS.cpp b/src/Base/UnitsSchemaMKS.cpp deleted file mode 100644 index 42ea0b0c79..0000000000 --- a/src/Base/UnitsSchemaMKS.cpp +++ /dev/null @@ -1,634 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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 * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" -#ifndef _PreComp_ -#include -#endif -#ifdef __GNUC__ -#include -#endif - -#include "Quantity.h" -#include "Unit.h" -#include "UnitsSchemaMKS.h" - -using namespace Base; - -std::string -UnitsSchemaMKS::schemaTranslate(const Quantity& quant, double& factor, std::string& unitString) -{ - double UnitValue = std::abs(quant.getValue()); - Unit unit = quant.getUnit(); - - // now do special treatment on all cases seems necessary: - if (unit == Unit::Length) { // Length handling ============================ - if (UnitValue < 1e-6) { // smaller than 0.001 nm -> scientific notation - unitString = "mm"; - factor = 1.0; - } - else if (UnitValue < 1e-3) { - unitString = "nm"; - factor = 1e-6; - } - else if (UnitValue < 0.1) { - unitString = "\xC2\xB5m"; - factor = 1e-3; - } - else if (UnitValue < 1e4) { - unitString = "mm"; - factor = 1.0; - } - else if (UnitValue < 1e7) { - unitString = "m"; - factor = 1e3; - } - else if (UnitValue < 1e10) { - unitString = "km"; - factor = 1e6; - } - else { // bigger than 1000 km -> scientific notation - unitString = "m"; - factor = 1e3; - } - } - else if (unit == Unit::Area) { - if (UnitValue < 100) { - unitString = "mm^2"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "cm^2"; - factor = 100; - } - else if (UnitValue < 1e12) { - unitString = "m^2"; - factor = 1e6; - } - else { // bigger than 1 square kilometer - unitString = "km^2"; - factor = 1e12; - } - } - else if (unit == Unit::Volume) { - if (UnitValue < 1e3) { // smaller than 1 ul - unitString = "mm^3"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "ml"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "l"; - factor = 1e6; - } - else { // bigger than 1000 l - unitString = "m^3"; - factor = 1e9; - } - } - else if (unit == Unit::Mass) { - if (UnitValue < 1e-6) { - unitString = "\xC2\xB5g"; - factor = 1e-9; - } - else if (UnitValue < 1e-3) { - unitString = "mg"; - factor = 1e-6; - } - else if (UnitValue < 1.0) { - unitString = "g"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "kg"; - factor = 1.0; - } - else { - unitString = "t"; - factor = 1e3; - } - } - else if (unit == Unit::Density) { - if (UnitValue < 0.0001) { - unitString = "kg/m^3"; - factor = 0.000000001; - } - else if (UnitValue < 1.0) { - unitString = "kg/cm^3"; - factor = 0.001; - } - else { - unitString = "kg/mm^3"; - factor = 1.0; - } - } - else if (unit == Unit::Acceleration) { - unitString = "m/s^2"; - factor = 1000.0; - } - else if ((unit == Unit::Pressure) || (unit == Unit::Stress)) { - if (UnitValue < 10.0) { // Pa is the smallest - unitString = "Pa"; - factor = 0.001; - } - else if (UnitValue < 10000.0) { - unitString = "kPa"; - factor = 1.0; - } - else if (UnitValue < 10000000.0) { - unitString = "MPa"; - factor = 1000.0; - } - else if (UnitValue < 10000000000.0) { - unitString = "GPa"; - factor = 1000000.0; - } - else { // bigger then 1000 GPa -> scientific notation - unitString = "Pa"; - factor = 0.001; - } - } - else if ((unit == Unit::Stiffness)) { - if (UnitValue < 1) { // mN/m is the smallest - unitString = "mN/m"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "N/m"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "kN/m"; - factor = 1e3; - } - else { - unitString = "MN/m"; - factor = 1e6; - } - } - else if ((unit == Unit::StiffnessDensity)) { - if (UnitValue < 1e-3) { - unitString = "Pa/m"; - factor = 1e-6; - } - else if (UnitValue < 1) { - unitString = "kPa/m"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "MPa/m"; - factor = 1.0; - } - else { - unitString = "GPa/m"; - factor = 1e3; - } - } - else if (unit == Unit::ThermalConductivity) { - if (UnitValue > 1000000) { - unitString = "W/mm/K"; - factor = 1000000.0; - } - else { - unitString = "W/m/K"; - factor = 1000.0; - } - } - else if (unit == Unit::ThermalExpansionCoefficient) { - if (UnitValue < 0.001) { - unitString = "\xC2\xB5m/m/K"; - factor = 0.000001; - } - else { - unitString = "m/m/K"; - factor = 1.0; - } - } - else if (unit == Unit::VolumetricThermalExpansionCoefficient) { - if (UnitValue < 0.001) { - unitString = "mm^3/m^3/K"; - factor = 1e-9; - } - else { - unitString = "m^3/m^3/K"; - factor = 1.0; - } - } - else if (unit == Unit::SpecificHeat) { - unitString = "J/kg/K"; - factor = 1000000.0; - } - else if (unit == Unit::ThermalTransferCoefficient) { - unitString = "W/m^2/K"; - factor = 1.0; - } - else if (unit == Unit::Force) { - if (UnitValue < 1e3) { - unitString = "mN"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "N"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "kN"; - factor = 1e6; - } - else { - unitString = "MN"; - factor = 1e9; - } - } - // else if (unit == Unit::Moment) { - // if (UnitValue < 1e6) { - // unitString = "mNm"; - // factor = 1e3; - // } - // else if (UnitValue < 1e9) { - // unitString = "Nm"; - // factor = 1e6; - // } - // else if (UnitValue < 1e12) { - // unitString = "kNm"; - // factor = 1e9; - // } - // else { - // unitString = "MNm"; - // factor = 1e12; - // } - // } - else if (unit == Unit::Power) { - if (UnitValue < 1e6) { - unitString = "mW"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "W"; - factor = 1e6; - } - else { - unitString = "kW"; - factor = 1e9; - } - } - else if (unit == Unit::ElectricPotential) { - if (UnitValue < 1e6) { - unitString = "mV"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "V"; - factor = 1e6; - } - else if (UnitValue < 1e12) { - unitString = "kV"; - factor = 1e9; - } - else { // > 1000 kV scientificc notation - unitString = "V"; - factor = 1e6; - } - } - else if (unit == Unit::ElectricCharge) { - unitString = "C"; - factor = 1.0; - } - else if (unit == Unit::SurfaceChargeDensity) { - unitString = "C/m^2"; - factor = 1e-6; - } - else if (unit == Unit::VolumeChargeDensity) { - unitString = "C/m^3"; - factor = 1e-9; - } - else if (unit == Unit::CurrentDensity) { - if (UnitValue <= 1e3) { - unitString = "A/m^2"; - factor = 1e-6; - } - else { - unitString = "A/mm^2"; - factor = 1; - } - } - else if (unit == Unit::MagneticFluxDensity) { - if (UnitValue <= 1e-3) { - unitString = "G"; - factor = 1e-4; - } - else { - unitString = "T"; - factor = 1.0; - } - } - else if (unit == Unit::MagneticFieldStrength) { - unitString = "A/m"; - factor = 1e-3; - } - else if (unit == Unit::MagneticFlux) { - unitString = "Wb"; - factor = 1e6; - } - else if (unit == Unit::Magnetization) { - unitString = "A/m"; - factor = 1e-3; - } - else if (unit == Unit::ElectromagneticPotential) { - unitString = "Wb/m"; - factor = 1e3; - } - else if (unit == Unit::ElectricalConductance) { - if (UnitValue < 1e-9) { - unitString = "\xC2\xB5S"; - factor = 1e-12; - } - else if (UnitValue < 1e-6) { - unitString = "mS"; - factor = 1e-9; - } - else { - unitString = "S"; - factor = 1e-6; - } - } - else if (unit == Unit::ElectricalResistance) { - if (UnitValue < 1e9) { - unitString = "Ohm"; - factor = 1e6; - } - else if (UnitValue < 1e12) { - unitString = "kOhm"; - factor = 1e9; - } - else { - unitString = "MOhm"; - factor = 1e12; - } - } - else if (unit == Unit::ElectricalConductivity) { - if (UnitValue < 1e-3) { - unitString = "mS/m"; - factor = 1e-12; - } - else if (UnitValue < 1.0) { - unitString = "S/m"; - factor = 1e-9; - } - else if (UnitValue < 1e3) { - unitString = "kS/m"; - factor = 1e-6; - } - else { - unitString = "MS/m"; - factor = 1e-3; - } - } - else if (unit == Unit::ElectricalCapacitance) { - if (UnitValue < 1e-15) { - unitString = "pF"; - factor = 1e-18; - } - else if (UnitValue < 1e-12) { - unitString = "nF"; - factor = 1e-15; - } - else if (UnitValue < 1e-9) { - // \x reads everything to the end, therefore split - unitString = "\xC2\xB5" - "F"; - factor = 1e-12; - } - else if (UnitValue < 1e-6) { - unitString = "mF"; - factor = 1e-9; - } - else { - unitString = "F"; - factor = 1e-6; - } - } - else if (unit == Unit::ElectricalInductance) { - if (UnitValue < 1e-6) { - unitString = "nH"; - factor = 1e-3; - } - else if (UnitValue < 1e-3) { - unitString = "\xC2\xB5H"; - factor = 1.0; - } - else if (UnitValue < 1.0) { - unitString = "mH"; - factor = 1e3; - } - else { - unitString = "H"; - factor = 1e6; - } - } - else if (unit == Unit::VacuumPermittivity) { - unitString = "F/m"; - factor = 1e-9; - } - else if (unit == Unit::Work) { - if (UnitValue < 1.602176634e-10) { - unitString = "eV"; - factor = 1.602176634e-13; - } - else if (UnitValue < 1.602176634e-7) { - unitString = "keV"; - factor = 1.602176634e-10; - } - else if (UnitValue < 1.602176634e-4) { - unitString = "MeV"; - factor = 1.602176634e-7; - } - else if (UnitValue < 1e6) { - unitString = "mJ"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "J"; - factor = 1e6; - } - else if (UnitValue < 1e12) { - unitString = "kJ"; - factor = 1e9; - } - else if (UnitValue < 3.6e+15) { - unitString = "kWh"; - factor = 3.6e+12; - } - else { // bigger than 1000 kWh -> scientific notation - unitString = "J"; - factor = 1e6; - } - } - else if (unit == Unit::SpecificEnergy) { - unitString = "m^2/s^2"; - factor = 1000000; - } - else if (unit == Unit::HeatFlux) { - unitString = "W/m^2"; - factor = 1.0; - } - else if (unit == Unit::Frequency) { - if (UnitValue < 1e3) { - unitString = "Hz"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "kHz"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "MHz"; - factor = 1e6; - } - else if (UnitValue < 1e12) { - unitString = "GHz"; - factor = 1e9; - } - else { - unitString = "THz"; - factor = 1e12; - } - } - else if (unit == Unit::Velocity) { - unitString = "m/s"; - factor = 1000.0; - } - else if (unit == Unit::DynamicViscosity) { - unitString = "Pa*s"; - factor = 0.001; - } - else if (unit == Unit::KinematicViscosity) { - unitString = "m^2/s"; - factor = 1e6; - } - else if (unit == Unit::VolumeFlowRate) { - if (UnitValue < 1e-3) { // smaller than 0.001 mm^3/s -> scientific notation - unitString = "m^3/s"; - factor = 1e9; - } - else if (UnitValue < 1e3) { - unitString = "mm^3/s"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "ml/s"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "l/s"; - factor = 1e6; - } - else { - unitString = "m^3/s"; - factor = 1e9; - } - } - else if (unit == Unit::DissipationRate) { - unitString = "W/kg"; - factor = 1e6; - } - else if (unit == Unit::InverseLength) { - if (UnitValue < 1e-6) { // smaller than 0.001 1/km -> scientific notation - unitString = "1/m"; - factor = 1e-3; - } - else if (UnitValue < 1e-3) { - unitString = "1/km"; - factor = 1e-6; - } - else if (UnitValue < 1.0) { - unitString = "1/m"; - factor = 1e-3; - } - else if (UnitValue < 1e3) { - unitString = "1/mm"; - factor = 1.0; - } - else if (UnitValue < 1e6) { - unitString = "1/\xC2\xB5m"; - factor = 1e3; - } - else if (UnitValue < 1e9) { - unitString = "1/nm"; - factor = 1e6; - } - else { // larger -> scientific notation - unitString = "1/m"; - factor = 1e-3; - } - } - else if (unit == Unit::InverseArea) { - if (UnitValue < 1e-12) { // smaller than 0.001 1/km^2 -> scientific notation - unitString = "1/m^2"; - factor = 1e-6; - } - else if (UnitValue < 1e-6) { - unitString = "1/km^2"; - factor = 1e-12; - } - else if (UnitValue < 1.0) { - unitString = "1/m^2"; - factor = 1e-6; - } - else if (UnitValue < 1e2) { - unitString = "1/cm^2"; - factor = 1e-2; - } - else { - unitString = "1/mm^2"; - factor = 1.0; - } - } - else if (unit == Unit::InverseVolume) { - if (UnitValue < 1e-6) { - unitString = "1/m^3"; - factor = 1e-9; - } - else if (UnitValue < 1e-3) { - unitString = "1/l"; - factor = 1e-6; - } - else if (UnitValue < 1.0) { - unitString = "1/ml"; - factor = 1e-3; - } - else { - unitString = "1/mm^3"; - factor = 1.0; - } - } - else { - // default action for all cases without special treatment: - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} diff --git a/src/Base/UnitsSchemaMKS.h b/src/Base/UnitsSchemaMKS.h deleted file mode 100644 index d6fc11c95f..0000000000 --- a/src/Base/UnitsSchemaMKS.h +++ /dev/null @@ -1,43 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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_UNITSSCHEMAMKS_H -#define BASE_UNITSSCHEMAMKS_H - -#include "UnitsSchema.h" - -namespace Base -{ - -/** - * The UnitSchema class - */ -class UnitsSchemaMKS: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; -}; - -} // namespace Base - -#endif // BASE_UNITSSCHEMAMKS_H diff --git a/src/Base/UnitsSchemaMeterDecimal.cpp b/src/Base/UnitsSchemaMeterDecimal.cpp deleted file mode 100644 index 52a6a9ca41..0000000000 --- a/src/Base/UnitsSchemaMeterDecimal.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************** - * Copyright (c) WandererFan * - * * - * 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 * - * * - ***************************************************************************/ - -/* Metric units schema intended for design of large objects - * Lengths are always in metres. - * Areas are always in square metres - * Volumes are always in cubic metres - * Angles in decimal degrees (use degree symbol) - * Velocities in m/sec - */ - -#include "PreCompiled.h" -#ifndef _PreComp_ -#include -#include -#endif - -#include "Quantity.h" -#include "Unit.h" -#include "UnitsSchemaMeterDecimal.h" - -using namespace Base; - -std::string UnitsSchemaMeterDecimal::schemaTranslate(const Base::Quantity& quant, - double& factor, - std::string& unitString) -{ - static std::array>, 7> unitSpecs {{ - {Unit::Length, {"m", 1e3}}, - {Unit::Area, {"m^2", 1e6}}, - {Unit::Volume, {"m^3", 1e9}}, - {Unit::Power, {"W", 1000000}}, - {Unit::ElectricPotential, {"V", 1000000}}, - {Unit::HeatFlux, {"W/m^2", 1.0}}, - {Unit::Velocity, {"m/s", 1e3}}, - }}; - - const auto unit = quant.getUnit(); - const auto spec = std::find_if(unitSpecs.begin(), unitSpecs.end(), [&](const auto& pair) { - return pair.first == unit; - }); - - if (spec != std::end(unitSpecs)) { - unitString = spec->second.first; - factor = spec->second.second; - } - else { - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} diff --git a/src/Base/UnitsSchemaMmMin.cpp b/src/Base/UnitsSchemaMmMin.cpp deleted file mode 100644 index ab7752a0c4..0000000000 --- a/src/Base/UnitsSchemaMmMin.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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 * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" -#ifndef _PreComp_ -#include -#include -#endif - -#include "Quantity.h" -#include "Unit.h" -#include "UnitsSchemaMmMin.h" - -using namespace Base; - -std::string -UnitsSchemaMmMin::schemaTranslate(const Quantity& quant, double& factor, std::string& unitString) -{ - static std::array>, 3> unitSpecs {{ - {Unit::Length, {"mm", 1.0}}, - {Unit::Angle, {"\xC2\xB0", 1.0}}, - {Unit::Velocity, {"mm/min", 1.0 / 60.0}}, - }}; - - const auto unit = quant.getUnit(); - const auto spec = std::find_if(unitSpecs.begin(), unitSpecs.end(), [&](const auto& pair) { - return pair.first == unit; - }); - - if (spec != std::end(unitSpecs)) { - unitString = spec->second.first; - factor = spec->second.second; - } - else { - unitString = quant.getUnit().getString(); - factor = 1.0; - } - - return toLocale(quant, factor, unitString); -} diff --git a/src/Base/UnitsSchemaMmMin.h b/src/Base/UnitsSchemaMmMin.h deleted file mode 100644 index 1f6a0262a7..0000000000 --- a/src/Base/UnitsSchemaMmMin.h +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2009 Jürgen Riegel * - * * - * 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_UNITSSCHEMAMMMIN_H -#define BASE_UNITSSCHEMAMMMIN_H - -#include "UnitsSchema.h" - -namespace Base -{ - -/* Metric units schema intended for design of small parts and for CNC - * Lengths are always in mm. - * Angles in degrees (use degree symbol) - * Velocities in mm/min (as used in g-code). - */ -class UnitsSchemaMmMin: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; -}; - -} // namespace Base - -#endif // BASE_UNITSSCHEMAMMMIN_H diff --git a/src/Base/UnitsSchemas.cpp b/src/Base/UnitsSchemas.cpp new file mode 100644 index 0000000000..f79e1d4317 --- /dev/null +++ b/src/Base/UnitsSchemas.cpp @@ -0,0 +1,145 @@ +/************************************************************************ + * * + * 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 * + * * + ************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "UnitsSchemas.h" +#include "Exception.h" +#include "Quantity.h" +#include "UnitsApi.h" +#include "UnitsSchema.h" +#include "UnitsSchemasSpecs.h" +#include "UnitsSchemasData.h" + +using Base::Quantity; +using Base::UnitsSchema; +using Base::UnitsSchemas; +using Base::UnitsSchemaSpec; + +UnitsSchemas::UnitsSchemas(const UnitsSchemasDataPack& pack) + : pack {pack} + , denominator {pack.defDenominator} + , decimals {pack.defDecimals} +{} + +size_t UnitsSchemas::count() const +{ + return pack.specs.size(); +} + +std::vector UnitsSchemas::getVec(const std::function& fn) +{ + std::vector vec; + std::transform(pack.specs.begin(), pack.specs.end(), std::back_inserter(vec), fn); + + return vec; +} + +std::vector UnitsSchemas::names() +{ + return getVec([](const UnitsSchemaSpec& spec) { + return spec.name; + }); +} + +std::vector UnitsSchemas::descriptions() +{ + return getVec([](const UnitsSchemaSpec& spec) { + return QCoreApplication::translate("UnitsApi", spec.description).toStdString(); + }); +} + +std::size_t UnitsSchemas::getDecimals() const +{ + return pack.defDecimals; +} + +std::size_t UnitsSchemas::defFractDenominator() const +{ + return pack.defDenominator; +} + +void UnitsSchemas::setdefFractDenominator(const std::size_t size) +{ + denominator = size; +} + +void UnitsSchemas::select() +{ + makeCurr(spec()); +} + +void UnitsSchemas::select(const std::string_view& name) +{ + makeCurr(spec(name)); +} + +void UnitsSchemas::select(const std::size_t num) +{ + makeCurr(spec(num)); +} + +UnitsSchema* UnitsSchemas::currentSchema() const +{ + return current.get(); +} + +void UnitsSchemas::makeCurr(const UnitsSchemaSpec& spec) +{ + current = std::make_unique(spec); +} + +UnitsSchemaSpec UnitsSchemas::findSpec(const std::function& fn) +{ + const auto found = std::find_if(pack.specs.begin(), pack.specs.end(), fn); + + if (found == pack.specs.end()) { + throw RuntimeError {"UnitSchemaSpec not found"}; + } + + return *found; +} + +UnitsSchemaSpec UnitsSchemas::spec() +{ + return findSpec([](const UnitsSchemaSpec& spec) { + return spec.isDefault; + }); +} + +UnitsSchemaSpec UnitsSchemas::spec(const std::string_view& name) +{ + return findSpec([&name](const UnitsSchemaSpec& spec) { + return spec.name == name; + }); +} + +UnitsSchemaSpec UnitsSchemas::spec(const std::size_t num) +{ + return findSpec([&num](const UnitsSchemaSpec& spec) { + return spec.num == num; + }); +} diff --git a/src/Base/UnitsSchemas.h b/src/Base/UnitsSchemas.h new file mode 100644 index 0000000000..38e4aafffc --- /dev/null +++ b/src/Base/UnitsSchemas.h @@ -0,0 +1,77 @@ +/************************************************************************ + * * + * 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 SRC_BASE_UNITSSCHEMAS_H +#define SRC_BASE_UNITSSCHEMAS_H + +#include +#include +#include + +#include "UnitsSchema.h" +#include "UnitsSchemasSpecs.h" + +namespace Base +{ + +/** + * The interface to schema specifications + * Has pointer to current schema + */ +class UnitsSchemas +{ +public: + explicit UnitsSchemas(const UnitsSchemasDataPack& pack); + + /** Make a schema and set as current*/ + void select(); // default + void select(const std::string_view& name); + void select(std::size_t num); + + /** Get a schema specification*/ + UnitsSchemaSpec spec(); // default, or the first spec + UnitsSchemaSpec spec(const std::string_view& name); + UnitsSchemaSpec spec(std::size_t num); + + size_t count() const; + std::vector names(); + std::vector descriptions(); + std::size_t getDecimals() const; + std::size_t defFractDenominator() const; + void setdefFractDenominator(std::size_t size); + + UnitsSchema* currentSchema() const; + +private: + /** DRY utils */ + std::vector getVec(const std::function& fn); + UnitsSchemaSpec findSpec(const std::function& fn); + void makeCurr(const UnitsSchemaSpec& spec); + + UnitsSchemasDataPack pack; + std::unique_ptr current {std::make_unique(spec())}; + std::size_t denominator; + std::size_t decimals; +}; + + +} // namespace Base +#endif // SRC_BASE_UNITSSCHEMAS_H diff --git a/src/Base/UnitsSchemasData.h b/src/Base/UnitsSchemasData.h new file mode 100644 index 0000000000..0c8ab3ca87 --- /dev/null +++ b/src/Base/UnitsSchemasData.h @@ -0,0 +1,749 @@ +/************************************************************************ + * * + * 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_UNITSSCHEMASDATA_H +#define BASE_UNITSSCHEMASDATA_H + +#include +#include + +#include + +#include "fmt/format.h" +#include "fmt/ranges.h" + +#include "UnitsSchemasSpecs.h" + +/** + * UnitSchemas raw data + */ + +namespace Base::UnitsSchemasData +{ + +constexpr std::size_t defDecimals {2}; +constexpr std::size_t defDenominator {8}; + +// NOLINTBEGIN +// clang-format off +inline const UnitsSchemaSpec s0 +{ 6, "MmMin", "mm" , false, false , QT_TRANSLATE_NOOP("UnitsApi", "Metric small parts & CNC (mm, mm/min)"), false, + { + { "Length", {{ 0 , "mm" , 1.0 }}}, + { "Angle", {{ 0 , "°" , 1.0 }}}, + { "Velocity", {{ 0 , "mm/min" , 1.0 / 60.0 }}} + } +}; + +inline const UnitsSchemaSpec s1 +{ 9, "MeterDecimal", "m", false, false, QT_TRANSLATE_NOOP("UnitsApi", "Meter decimal (m, m², m³)"), false, + { + { "Length", {{ 0 , "m" , 1e3 }}}, + { "Area", {{ 0 , "m²" , 1e6 }}}, + { "Volume", {{ 0 , "m³" , 1e9 }}}, + { "Power", {{ 0 , "W" , 1e6 }}}, + { "ElectricPotential", {{ 0 , "V" , 1e6 }}}, + { "HeatFlux", {{ 0 , "W/m²" , 1.0 }}}, + { "Velocity", {{ 0 , "m/s" , 1e3 }}} + } +}; + +inline const UnitsSchemaSpec s2 +{ 3, "ImperialDecimal", "in", false, false, QT_TRANSLATE_NOOP("UnitsApi", "Imperial decimal (in, lb)"), false, + { + { "Length", {{ 0 , "in" , 25.4 }}}, + { "Angle", {{ 0 , "°" , 1.0 }}}, + { "Area", {{ 0 , "in²" , 645.16 }}}, + { "Volume", {{ 0 , "in³" , 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²" , 25.4 / 3600 }}} + } +}; + +inline const UnitsSchemaSpec s3 +{ 0, "Internal", "m", false, false, QT_TRANSLATE_NOOP("UnitsApi", "Internal (m, m², m³)"), true, + { + { "Length", { + { 1e-6 , "mm" , 1.0 }, + { 1e-3 , "nm" , 1e-6 }, + { 1e-1 , "μm" , 1e-3 }, + { 1e4 , "mm" , 1.0 }, + { 1e7 , "m" , 1e3 }, + { 1e10 , "mm" , 1e6 }, + { 0 , "m" , 1.0 }} + }, + { "Area", { + { 1e2 , "mm²" , 1.0 }, + { 1e6 , "cm²" , 1e2 }, + { 1e12 , "m²" , 1e6 }, + { 0 , "km²" , 1e12 }} + }, + { "Volume", { + { 1e3 , "mm³" , 1.0 }, + { 1e6 , "ml" , 1e3 }, + { 1e9 , "l" , 1e6 }, + { 0 , "m³" , 1e9 }} + }, + { "Angle", { + { 0 , "°" , 1.0 }} + }, + { "Mass", { + { 1e-6 , "μg" , 1.0 }, + { 1e-3 , "mg" , 1e-6 }, + { 1.0 , "g" , 1e-3 }, + { 1e3 , "kg" , 1.0 }, + { 0 , "t" , 1e3 }} + }, + { "Density", { + { 1e-4 , "kg/m³" , 1e-9 }, + { 1.0 , "kg/cm³" , 1e-3 }, + { 0 , "kg/mm³" , 1.0 }} + }, + { "ThermalConductivity", { + { 1e6 , "W/m/K" , 1e6 }, + { 0 , "W/mm/K" , 1e3 }} + }, + { "ThermalExpansionCoefficient", { + { 1e-3 , "μm/m/K" , 1e-6 }, + { 0 , "mm/mm/K" , 1.0 }} + }, + { "VolumetricThermalExpansionCoefficient", { + { 1e-3 , "mm³/m³/K" , 1e-9 }, + { 0 , "m³/m³/K" , 1.0 }} + }, + { "SpecificHeat", { + { 0 , "J/kg/K" , 1e6 }} + }, + { "ThermalTransferCoefficient", { + { 0 , "W/m²/K" , 1.0 }} + }, + { "Pressure", { + { 10.0 , "Pa" , 1e-3 }, + { 1e4 , "kPa" , 1.0 }, + { 1e7 , "MPa" , 1e3 }, + { 1e10 , "GPa" , 1e6 }, + { 0 , "Pa" , 1e-3 }} + }, + { "Stress", { + { 10.0 , "Pa" , 1e-3 }, + { 1e4 , "kPa" , 1.0 }, + { 1e7 , "MPa" , 1e3 }, + { 1e10 , "GPa" , 1e6 }, + { 0 , "Pa" , 1e-3 }} + }, + { "Stiffness", { + { 1e-3 , "Pa/m" , 1e-6 }, + { 1 , "mN/m" , 1e-3 }, + { 1e3 , "N/m" , 1.0 }, + { 1e6 , "kN/m" , 1e3 }, + { 0 , "MN/m" , 1e6 }} + }, + { "StiffnessDensity", { + { 1 , "kPa/m" , 1e-3 }, + { 1e3 , "MPa/m" , 1.0 }, + { 1e3 , "mN" , 1.0 }, + { 0 , "GPa/m" , 1e3 }} + }, + { "Force", { + { 1e6 , "N" , 1e3 }, + { 1e9 , "kN" , 1e6 }, + { 0 , "MN" , 1e9 }} + }, + { "Power", { + { 1e6 , "mW" , 1e3 }, + { 1e9 , "W" , 1e6 }, + { 0 , "kW" , 1e9 }} + }, + { "ElectricPotential", { + { 1e6 , "mV" , 1e3 }, + { 1e9 , "V" , 1e6 }, + { 1e12 , "kV" , 1e9 }, + { 0 , "V" , 1e6 }} + }, + { "Work", { + { 1.602176634e-10 , "eV" , 1.602176634e-13 }, + { 1.602176634e-7 , "keV" , 1.602176634e-10 }, + { 1.602176634e-4 , "MeV" , 1.602176634e-7 }, + { 1e6 , "mJ" , 1e3 }, + { 1e9 , "J" , 1e6 }, + { 1e12 , "kJ" , 1e9 }, + { 3.6e+15 , "kWh" , 3.6e+12 }, + { 0 , "J" , 1e6 }} + }, + { "SpecificEnergy", { + { 0 , "m²/s²" , 1e6 }} + }, + { "HeatFlux", { + { 0 , "W/m²" , 1.0 }} + }, + { "ElectricCharge", { + { 0 , "C" , 1.0 }} + }, + { "SurfaceChargeDensity", { + { 1e-4 , "C/m²" , 1e-6 }, + { 1e-2 , "C/cm²" , 1e-2 }, + { 0 , "C/mm²" , 1.0 }} + }, + { "VolumeChargeDensity", { + { 1e-4 , "C/m³" , 1e-9 }, + { 1e-2 , "C/cm³" , 1e-3 }, + { 0 , "C/mm³" , 1.0 }} + }, + { "CurrentDensity", { + { 1e-4 , "A/m²" , 1e-6 }, + { 1e-2 , "A/cm²" , 1e-2 }, + { 0 , "A/mm²" , 1 }} + }, + { "MagneticFluxDensity", { + { 1e-3 , "G" , 1e-4 }, + { 0 , "T" , 1.0 }} + }, + { "MagneticFieldStrength", { + { 0 , "A/m" , 1e-3 }} + }, + { "MagneticFlux", { + { 0 , "Wb" , 1e6 }} + }, + { "Magnetization", { + { 0 , "A/m" , 1e-3 }} + }, + { "ElectricalConductance", { + { 1e-9 , "μS" , 1e-12 }, + { 1e-6 , "mS" , 1e-9 }, + { 0 , "S" , 1e-6 }} + }, + { "ElectricalResistance", { + { 1e9 , "Ohm" , 1e6 }, + { 1e12 , "kOhm" , 1e9 }, + { 0 , "MOhm" , 1e12 }} + }, + { "ElectricalConductivity", { + { 0 , "MS/m" , 1e-3 }, + { 1e-3 , "mS/m" , 1e-12 }, + { 1.0 , "S/m" , 1e-9 }, + { 1e3 , "kS/m" , 1e-6 }} + }, + { "ElectricalCapacitance", { + { 1e-15 , "pF" , 1e-18 }, + { 1e-12 , "nF" , 1e-15 }, + { 1e-9 , "μF" , 1e-12 }, + { 1e-6 , "mF" , 1e-9 }, + { 0 , "F" , 1e-6 }} + }, + { "ElectricalInductance", { + { 1.0 , "nH" , 1e-3 }, + { 1e3 , "μH" , 1.0 }, + { 1e6 , "mH" , 1e3 }, + { 0 , "H" , 1e6 }} + }, + { "VacuumPermittivity", { + { 0 , "F/m" , 1e-9 }} + }, + { "Frequency", { + { 1e3 , "Hz" , 1.0 }, + { 1e6 , "kHz" , 1e3 }, + { 1e9 , "MHz" , 1e6 }, + { 1e12 , "GHz" , 1e9 }, + { 0 , "THz" , 1e12 }} + }, + { "Velocity", { + { 0 , "mm/s" , 1.0 }} + }, + { "DynamicViscosity", { + { 0 , "Pa*s" , 1e-3 }} + }, + { "KinematicViscosity", { + { 1e3 , "mm²/s" , 1.0 }, + { 0 , "m²/s" , 1e6 }} + }, + { "VolumeFlowRate", { + { 1e3 , "mm³/s" , 1.0 }, + { 1e6 , "ml/s" , 1e3 }, + { 1e9 , "l/s" , 1e6 }, + { 0 , "m³/s" , 1e9 }} + }, + { "DissipationRate", { + { 0 , "W/kg" , 1e6 }} + }, + { "InverseLength", { + { 1e-6 , "1/m" , 1e-3 }, + { 1e-3 , "1/km" , 1e-6 }, + { 1.0 , "1/m" , 1e-3 }, + { 1e3 , "1/mm" , 1.0 }, + { 1e6 , "1/μm" , 1e3 }, + { 1e9 , "1/nm" , 1e6 }, + { 0 , "1/m" , 1e-3 }} + }, + { "InverseArea", { + { 1e-12 , "1/m²" , 1e-6 }, + { 1e-6 , "1/km²" , 1e-12 }, + { 1.0 , "1/m²" , 1e-6 }, + { 1e2 , "1/cm²" , 1e-2 }, + { 0 , "1/mm²" , 1.0 }} + }, + { "InverseVolume", { + { 1e-6 , "1/m³" , 1e-9 }, + { 1e-3 , "1/l" , 1e-6 }, + { 1.0 , "1/ml" , 1e-3 }, + { 0 , "1/mm³" , 1.0 }} + } + } +}; + +inline const UnitsSchemaSpec s4 +{ 1, "MKS", "m", false, false, QT_TRANSLATE_NOOP("UnitsApi", "MKS (m, kg, s, °)") , false, + { + { "Length", { + { 1e-6 , "mm" , 1.0 }, + { 1e-3 , "nm" , 1e-6 }, + { 0.1 , "μm" , 1e-3 }, + { 1e4 , "mm" , 1.0 }, + { 1e7 , "m" , 1e3 }, + { 1e10 , "km" , 1e6 }, + { 0 , "m" , 1e3 }} + }, + { "Area", { + { 100 , "mm²" , 1.0 }, + { 1e6 , "cm²" , 100 }, + { 1e12 , "m²" , 1e6 }, + { 0 , "km²" , 1e12 }} + }, + { "Volume", { + { 1e3 , "mm³" , 1.0 }, + { 1e6 , "ml" , 1e3 }, + { 1e9 , "l" , 1e6 }, + { 0 , "m³" , 1e9 }} + }, + { "Mass", { + { 1e-6 , "μg" , 1e-9 }, + { 1e-3 , "mg" , 1e-6 }, + { 1.0 , "g" , 1e-3 }, + { 1e3 , "kg" , 1.0 }, + { 0 , "t" , 1e3 }} + }, + { "Density", { + { 0.0001 , "kg/m³" , 0.000000001 }, + { 1.0 , "kg/cm³" , 0.001 }, + { 0 , "kg/mm³" , 1.0 }} + }, + { "Acceleration", { + { 0 , "m/s²" , 1000.0 }} + }, + { "Pressure", { + { 10.0 , "Pa" , 0.001 }, + { 10'000.0 , "kPa" , 1.0 }, + { 10'000'000.0 , "MPa" , 1'000.0 }, + { 10'000'000'000.0 , "GPa" , 1'000'000.0 }, + { 0 , "Pa" , 1000.0 }} + }, + { "Stress", { + { 10.0 , "Pa" , 0.001 }, + { 10'000.0 , "kPa" , 1.0 }, + { 10'000'000.0 , "MPa" , 1'000.0 }, + { 10'000'000'000.0 , "GPa" , 1'000'000.0 }, + { 0 , "Pa" , 0.001 }} + }, + { "Stiffness", { + { 1 , "mN/m" , 1e-3 }, + { 1e3 , "N/m" , 1.0 }, + { 1e6 , "kN/m" , 1e3 }, + { 0 , "MN/m" , 1e6 }} + }, + { "StiffnessDensity", { + { 1e-3 , "Pa/m" , 1e-6 }, + { 1 , "kPa/m" , 1e-3 }, + { 1e3 , "MPa/m" , 1.0 }, + { 0 , "GPa/m" , 1e3 }} + }, + { "ThermalConductivity", { + { 1'000'000 , "W/mm/K" , 1'000'000.0 }, + { 0 , "W/m/K" , 1'000.0 }} + }, + { "ThermalExpansionCoefficient", { + { 0.001 , "μm/m/K" , 0.000001 }, + { 0 , "m/m/K" , 1.0 }} + }, + { "VolumetricThermalExpansionCoefficient", { + { 0.001 , "mm³/m³/K" , 1e-9 }, + { 0 , "m³/m³/K" , 1.0 }} + }, + { "SpecificHeat", { + { 0 , "J/kg/K" , 1'000'000.0 }} + }, + { "ThermalTransferCoefficient", { + { 0 , "W/m²/K" , 1.0 }} + }, + { "Force", { + { 1e3 , "mN" , 1.0 }, + { 1e6 , "N" , 1e3 }, + { 1e9 , "kN" , 1e6 }, + { 0 , "MN" , 1e9 }} + }, + { "Power", { + { 1e6 , "mW" , 1e3 }, + { 1e9 , "W" , 1e6 }, + { 0 , "kW" , 1e9 }} + }, + { "ElectricPotential", { + { 1e6 , "mV" , 1e3 }, + { 1e9 , "V" , 1e6 }, + { 1e12 , "kV" , 1e9 }, + { 0 , "V" , 1e6 }} + }, + { "ElectricCharge", { + { 0 , "C" , 1.0 }} + }, + { "SurfaceChargeDensity", { + { 0 , "C/m²" , 1e-6 }} + }, + { "VolumeChargeDensity", { + { 0 , "C/m³" , 1e-9 }} + }, + { "CurrentDensity", { + { 1e3 , "A/m²" , 1e-6 }, + { 0 , "A/mm²" , 1.0 }} + }, + { "MagneticFluxDensity", { + { 1e-3 , "G" , 1e-4 }, + { 0 , "T" , 1.0 }} + }, + { "MagneticFieldStrength", { + { 0 , "A/m" , 1e-3 }} + }, + { "MagneticFlux", { + { 0 , "Wb" , 1e6 }} + }, + { "Magnetization", { + { 0 , "A/m" , 1e-3 }} + }, + { "ElectricalConductance", { + { 1e-9 , "μS" , 1e-12 }, + { 1e-6 , "mS" , 1e-9 }, + { 0 , "S" , 1e-6 }} + }, + { "ElectricalResistance", { + { 1e9 , "Ohm" , 1e6 }, + { 1e12 , "kOhm" , 1e9 }, + { 0 , "MOhm" , 1e12 }} + }, + { "ElectricalConductivity", { + { 1e-3 , "mS/m" , 1e-12 }, + { 1.0 , "S/m" , 1e-9 }, + { 1e3 , "kS/m" , 1e-6 }, + { 0 , "MS/m" , 1e-3 }} + }, + { "ElectricalCapacitance", { + { 1e-15 , "pF" , 1e-18 }, + { 1e-12 , "nF" , 1e-15 }, + { 1e-9 , "μ" "F" , 1e-12 }, + { 1e-6 , "mF" , 1e-9 }, + { 0 , "F" , 1e-6 }} + }, + { "ElectricalInductance", { + { 1e-6 , "nH" , 1e-3 }, + { 1e-3 , "μH" , 1.0 }, + { 1.0 , "mH" , 1e3 }, + { 0 , "H" , 1e6 }} + }, + { "VacuumPermittivity", { + { 0 , "F/m" , 1e-9 }} + }, + { "Work", { + { 1.602176634e-10 , "eV" , 1.602176634e-13 }, + { 1.602176634e-7 , "keV" , 1.602176634e-10 }, + { 1.602176634e-4 , "MeV" , 1.602176634e-7 }, + { 1e6 , "mJ" , 1e3 }, + { 1e9 , "J" , 1e6 }, + { 1e12 , "kJ" , 1e9 }, + { 3.6e+15 , "kWh" , 3.6e+12 }, + { 0 , "J" , 1e6 }} + }, + { "SpecificEnergy", { + { 0 , "m²/s²" , 1000000 }} + }, + { "HeatFlux", { + { 0 , "W/m²" , 1.0 }} + }, + { "Frequency", { + { 1e3 , "Hz" , 1.0 }, + { 1e6 , "kHz" , 1e3 }, + { 1e9 , "MHz" , 1e6 }, + { 1e12 , "GHz" , 1e9 }, + { 0 , "THz" , 1e12 }} + }, + { "Velocity", { + { 0 , "m/s" , 1000.0 }} + }, + { "DynamicViscosity", { + { 0 , "Pa*s" , 0.001 }} + }, + { "KinematicViscosity", { + { 0 , "m²/s" , 1e6 }} + }, + { "VolumeFlowRate", { + { 1e-3 , "m³/s" , 1e9 }, + { 1e3 , "mm³/s" , 1.0 }, + { 1e6 , "ml/s" , 1e3 }, + { 1e9 , "l/s" , 1e6 }, + { 0 , "m³/s" , 1e9 }} + }, + { "DissipationRate", { + { 0 , "W/kg" , 1e6 }} + }, + { "InverseLength", { + { 1e-6 , "1/m" , 1e-3 }, + { 1e-3 , "1/km" , 1e-6 }, + { 1.0 , "1/m" , 1e-3 }, + { 1e3 , "1/mm" , 1.0 }, + { 1e6 , "1/μm" , 1e3 }, + { 1e9 , "1/nm" , 1e6 }, + { 0 , "1/m" , 1e-3 }} + }, + { "InverseArea", { + { 1e-12 , "1/m²" , 1e-6 }, + { 1e-6 , "1/km²" , 1e-12 }, + { 1.0 , "1/m²" , 1e-6 }, + { 1e2 , "1/cm²" , 1e-2 }, + { 0 , "1/mm²" , 1.0 }} + }, + { "InverseVolume", { + { 1e-6 , "1/m³" , 1e-9 }, + { 1e-3 , "1/l" , 1e-6 }, + { 1.0 , "1/ml" , 1e-3 }, + { 0 , "1/mm³" , 1.0 }} + } + } +}; + +inline const UnitsSchemaSpec s5 +{ 4, "Centimeter", "cm", false, false, QT_TRANSLATE_NOOP("UnitsApi", "Building Euro (cm, m², m³)") , false, + { + { "Length", { + { 0 , "cm" , 10.0 }} + }, + { "Area", { + { 0 , "m²" , 1e6 }} + }, + { "Volume", { + { 0 , "m³" , 1e9 }} + }, + { "Power", { + { 0 , "W" , 1e6 }} + }, + { "ElectricPotential", { + { 0 , "V" , 1e6 }} + }, + { "HeatFlux", { + { 0 , "W/m²" , 1.0 }} + }, + { "Velocity", { + { 0 , "mm/min" , 1.0 / 60 }} + } + } +}; + +inline const UnitsSchemaSpec s6 +{ 8, "FEM", "mm", false , false , QT_TRANSLATE_NOOP("UnitsApi", "FEM (mm, N, s)"), false, + { + { "Length", { + { 0 , "mm" , 1.0 }} + }, + { "Mass", { + { 0 , "t" , 1e3 }} + } + } +}; + +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 }} + }, + { "Angle", { + { 0 , "°" , 1.0 }} + }, + { "Area", { + { 0 , "in²" , 645.16 }} + }, + { "Volume", { + { 0 , "in³" , 16'387.064 }} + }, + { "Mass", { + { 0 , "lb" , 0.45359237 }} + }, + { "Pressure", { + { 6'894.744 , "psi" , 6.894744825494 }, + { 6'894'744.825 , "ksi" , 6'894.744825494 }, + { 0 , "psi" , 6.894744825494 }} + }, + { "Stiffness", { + { 0 , "lbf/in" , 4.448222 / 0.0254 }} + }, + { "Velocity", { + { 0 , "in/min" , 25.4 / 60 }} + } + } +}; + +inline const UnitsSchemaSpec s8 +{ 5, "ImperialBuilding", "ft", true, false , QT_TRANSLATE_NOOP("UnitsApi", "Building US (ft-in, sqft, cft)"), false, + { + { "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 }}} + } +}; + +inline const UnitsSchemaSpec s9 +{ 7, "ImperialCivil", "ft", false, true, QT_TRANSLATE_NOOP("UnitsApi", "Imperial for Civil Eng (ft, ft/s)"), false, + { + { "Angle" , {{ 0 , "toDMS" , 0 }}} // <== ! + } +}; + +// clang-format on +// NOLINTEND +inline const std::vector schemaSpecs {s3, s4, s5, s6, s7, s8, s9, s0, s1, s2}; + +/** + * Special functions + * + * A schema unit can have custom formatting via a special function + * Such functions must be included here and also registered in special functions caller (below) + */ + +/** utility function for toFractional */ +inline std::size_t greatestCommonDenominator(const std::size_t a, const std::size_t b) +{ + return b == 0 ? a : greatestCommonDenominator(b, a % b); // Euclid's algorithm +} + +/** + * double -> [feet′][inches[-fraction]″], e.g.: 3′4-1/4″ + */ +inline std::string toFractional(const double value) +{ + constexpr auto inchPerFoot {12}; + constexpr auto mmPerInch {25.4}; + + auto numFractUnits = + static_cast(std::round(std::abs(value) / mmPerInch * defDenominator)); + if (numFractUnits == 0) { + return "0"; + } + + const auto feet = + static_cast(std::floor(numFractUnits / (inchPerFoot * defDenominator))); + numFractUnits = numFractUnits - (inchPerFoot * defDenominator * feet); + const auto inches = static_cast(std::floor(numFractUnits / defDenominator)); + const std::size_t fractNumerator = numFractUnits - (defDenominator * inches); + + const std::size_t common_denom = greatestCommonDenominator(fractNumerator, defDenominator); + const std::size_t numerator = fractNumerator / common_denom; + const std::size_t denominator = defDenominator / common_denom; + + std::vector resultParts {}; + if (inches > 0) { + resultParts.push_back(fmt::format("{}", inches)); + if (numerator == 0) { + resultParts.emplace_back("″"); + } + } + if (numerator > 0) { + if (inches > 0) { + resultParts.emplace_back("-"); + } + resultParts.push_back(fmt::format("{}/{}″", numerator, denominator)); + } + + return fmt::format("{}{}{}", + value < 0 ? "-" : "", + feet > 0 ? fmt::format("{}′", feet) : "", + fmt::join(resultParts, "")); +} + +/** + * double -> degrees°[minutes′[seconds″]] + */ +inline std::string toDms(const double value) +{ + constexpr auto dmsRatio {60.0}; + + auto calc = [&](const double total) -> std::pair { + const double whole = std::floor(total); + return {static_cast(whole), dmsRatio * (total - whole)}; + }; + + auto [degrees, totalMinutes] = calc(value); + std::string out = fmt::format("{}°", degrees); + + if (totalMinutes > 0) { + auto [minutes, totalSeconds] = calc(totalMinutes); + out += fmt::format("{}′", minutes); + + if (totalSeconds > 0) { + out += fmt::format("{}″", std::round(totalSeconds)); + } + } + + return out; +} + + +/** + * Special functions caller + */ + +inline const std::map> specials // clang-format off +{ + { + { "toDMS" , [](const double val) { return toDms(val); }}, + { "toFractional" , [](const double val) { return toFractional(val); }} + } +}; // clang-format on + +inline std::string runSpecial(const std::string& name, const double value) +{ + return specials.contains(name) ? specials.at(name)(value) : ""; +} + + +/** + * Build data pack + */ + +inline const UnitsSchemasDataPack unitSchemasDataPack {schemaSpecs, defDecimals, defDenominator}; + + +} // namespace Base::UnitsSchemasData +#endif // BASE_UNITSSCHEMASDATA_H diff --git a/src/Base/UnitsSchemaMeterDecimal.h b/src/Base/UnitsSchemasSpecs.h similarity index 53% rename from src/Base/UnitsSchemaMeterDecimal.h rename to src/Base/UnitsSchemasSpecs.h index c3302602b9..b642385d37 100644 --- a/src/Base/UnitsSchemaMeterDecimal.h +++ b/src/Base/UnitsSchemasSpecs.h @@ -1,54 +1,69 @@ -/*************************************************************************** - * Copyright (c) 2023 WandererFan * - * * - * 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 * - * * - ***************************************************************************/ - -/* Metric units schema intended for design of large objects - * Lengths are always in metres. - * Angles in degrees (use degree symbol) - * Velocities in m/sec - */ - -#ifndef BASE_UNITSSCHEMAMETERS_H -#define BASE_UNITSSCHEMAMETERS_H - -#include "UnitsSchema.h" - -namespace Base -{ - -/** - * The UnitSchema class - */ -class UnitsSchemaMeterDecimal: public UnitsSchema -{ -public: - std::string - schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; - - std::string getBasicLengthUnit() const override - { - return {"m"}; - } -}; - -} // namespace Base - -#endif // BASE_UNITSSCHEMAMETRES_H +/************************************************************************ + * * + * 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 UNITSCHEMASPECS_H +#define UNITSCHEMASPECS_H + +#include +#include +#include +#include + +namespace Base +{ + + +struct UnitTranslationSpec +{ + double threshold {1}; + std::string unitString; + double factor {1}; + std::function fn {nullptr}; +}; + +struct UnitsSchemaSpec +{ + std::size_t num; + std::string name; + std::string basicLengthUnitStr; + bool isMultUnitLen {false}; + bool isMultUnitAngle {false}; + const char* description; + bool isDefault {false}; + + /** + * Applicable spec is the first with threshold > value under test + * Special case: Threshold = 0 : default + * Special case: Factor = 0 : unitString contains name of special function to run + */ + std::map> translationSpecs; +}; + +struct UnitsSchemasDataPack +{ + std::vector specs; + size_t defDecimals; + size_t defDenominator; +}; + + +} // namespace Base +#endif // UNITSCHEMASPECS_H diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index f7680c8b91..9ceb3679d3 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -1072,12 +1072,12 @@ void Application::slotActiveDocument(const App::Document& Doc) "User parameter:BaseApp/Preferences/Units"); if (!hGrp->GetBool("IgnoreProjectSchema")) { int userSchema = Doc.UnitSystem.getValue(); - Base::UnitsApi::setSchema(static_cast(userSchema)); + Base::UnitsApi::setSchema(userSchema); getMainWindow()->setUserSchema(userSchema); Application::Instance->onUpdate(); } else { // set up Unit system default - Base::UnitsApi::setSchema((Base::UnitSystem)hGrp->GetInt("UserSchema", 0)); + Base::UnitsApi::setSchema(hGrp->GetInt("UserSchema", 0)); Base::UnitsApi::setDecimals(hGrp->GetInt("Decimals", Base::UnitsApi::getDecimals())); } signalActiveDocument(*doc->second); diff --git a/src/Gui/Dialogs/DlgProjectInformationImp.cpp b/src/Gui/Dialogs/DlgProjectInformationImp.cpp index 187ed2cb46..465c04106c 100644 --- a/src/Gui/Dialogs/DlgProjectInformationImp.cpp +++ b/src/Gui/Dialogs/DlgProjectInformationImp.cpp @@ -83,11 +83,12 @@ DlgProjectInformationImp::DlgProjectInformationImp(App::Document* doc, ui->lineEditCompany->setText(QString::fromUtf8(doc->Company.getValue())); // Load comboBox with unit systems - int num = static_cast(Base::UnitSystem::NumUnitSystemTypes); - for (int i = 0; i < num; i++) { - QString item = Base::UnitsApi::getDescription(static_cast(i)); - ui->comboBox_unitSystem->addItem(item, i); - } + auto addDesc = [&, index {0}](const std::string& item) mutable { + ui->comboBox_unitSystem->addItem(QString::fromStdString(item), index++); + }; + const auto descriptions = Base::UnitsApi::getDescriptions(); + std::for_each(descriptions.begin(), descriptions.end(), addDesc); + ui->comboBox_unitSystem->setCurrentIndex(doc->UnitSystem.getValue()); // load comboBox with license names diff --git a/src/Gui/Dialogs/DlgUnitsCalculatorImp.cpp b/src/Gui/Dialogs/DlgUnitsCalculatorImp.cpp index f63e080e2e..65947b6179 100644 --- a/src/Gui/Dialogs/DlgUnitsCalculatorImp.cpp +++ b/src/Gui/Dialogs/DlgUnitsCalculatorImp.cpp @@ -51,12 +51,12 @@ DlgUnitsCalculator::DlgUnitsCalculator(QWidget* parent, Qt::WindowFlags fl) ui->setupUi(this); this->setAttribute(Qt::WA_DeleteOnClose); - ui->comboBoxScheme->addItem(QStringLiteral("Preference system"), static_cast(-1)); - int num = static_cast(Base::UnitSystem::NumUnitSystemTypes); - for (int i = 0; i < num; i++) { - QString item = Base::UnitsApi::getDescription(static_cast(i)); - ui->comboBoxScheme->addItem(item, i); - } + ui->comboBoxScheme->addItem(QStringLiteral("Preference system"), -1); + auto addItem = [&, index {0}](const auto& item) mutable { + ui->comboBoxScheme->addItem(QString::fromStdString(item), index++); + }; + auto descriptions = Base::UnitsApi::getDescriptions(); + std::for_each(descriptions.begin(), descriptions.end(), addItem); // clang-format off connect(ui->unitsBox, qOverload(&QComboBox::activated), @@ -214,7 +214,7 @@ void DlgUnitsCalculator::onComboBoxSchemeActivated(int index) { int item = ui->comboBoxScheme->itemData(index).toInt(); if (item > 0) { - ui->quantitySpinBox->setSchema(static_cast(item)); + ui->quantitySpinBox->setSchema(item); } else { ui->quantitySpinBox->clearSchema(); diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index d10a117dd3..cdac561181 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -65,6 +65,7 @@ #endif #endif +#include #include #include @@ -179,13 +180,16 @@ public: //create the action buttons auto* menu = new QMenu(this); auto* actionGrp = new QActionGroup(menu); - int num = static_cast(Base::UnitSystem::NumUnitSystemTypes); - for (int i = 0; i < num; i++) { - QAction* action = menu->addAction(QStringLiteral("UnitSchema%1").arg(i)); + + auto setAction = [&, index {0}](const std::string&) mutable { + QAction* action = menu->addAction(QStringLiteral("UnitSchema%1").arg(index)); actionGrp->addAction(action); action->setCheckable(true); - action->setData(i); - } + action->setData(index++); + }; + auto descriptions = Base::UnitsApi::getDescriptions(); + std::for_each(descriptions.begin(), descriptions.end(), setAction); + QObject::connect(actionGrp, &QActionGroup::triggered, this, [this](QAction* action) { int userSchema = action->data().toInt(); setUserSchema(userSchema); @@ -236,7 +240,7 @@ public: getWindowParameter()->SetInt("UserSchema", userSchema); unitChanged(); - Base::UnitsApi::setSchema(static_cast(userSchema)); + Base::UnitsApi::setSchema(userSchema); // Update the main window to show the unit change Gui::Application::Instance->onUpdate(); } @@ -261,12 +265,12 @@ private: void retranslateUi() { auto actions = menu()->actions(); - int maxSchema = static_cast(Base::UnitSystem::NumUnitSystemTypes); - assert(actions.size() <= maxSchema); - for(int i = 0; i < maxSchema ; i++) - { - actions[i]->setText(Base::UnitsApi::getDescription(static_cast(i))); - } + auto addAction = [&, index {0}](const std::string& action)mutable { + actions[index++]->setText(QString::fromStdString(action)); + }; + auto descriptions = Base::UnitsApi::getDescriptions(); + assert(actions.size() <= static_cast(descriptions.size())); + std::for_each(descriptions.begin(), descriptions.end(), addAction); } }; diff --git a/src/Gui/PreferencePages/DlgSettingsGeneral.cpp b/src/Gui/PreferencePages/DlgSettingsGeneral.cpp index 5bebdd08ce..b12c80fbe1 100644 --- a/src/Gui/PreferencePages/DlgSettingsGeneral.cpp +++ b/src/Gui/PreferencePages/DlgSettingsGeneral.cpp @@ -63,7 +63,8 @@ using namespace Gui; using namespace Gui::Dialog; namespace fs = std::filesystem; -using namespace Base; +using Base::UnitsApi; +using Base::QuantityFormat; /* TRANSLATOR Gui::Dialog::DlgSettingsGeneral */ @@ -117,14 +118,14 @@ DlgSettingsGeneral::DlgSettingsGeneral( QWidget* parent ) connect(ui->comboBox_UnitSystem, qOverload(&QComboBox::currentIndexChanged), this, &DlgSettingsGeneral::onUnitSystemIndexChanged); ui->spinBoxDecimals->setMaximum(std::numeric_limits::digits10 + 1); - int num = static_cast(Base::UnitSystem::NumUnitSystemTypes); - for (int i = 0; i < num; i++) { - QString item = Base::UnitsApi::getDescription(static_cast(i)); - ui->comboBox_UnitSystem->addItem(item, i); - } + auto addItem = [&, index {0}](const std::string& item) mutable { + ui->comboBox_UnitSystem->addItem(QString::fromStdString(item), index++); + }; + auto descriptions = UnitsApi::getDescriptions(); + std::for_each(descriptions.begin(), descriptions.end(), addItem); // Enable/disable the fractional inch option depending on system - const auto visible = (UnitsApi::getSchema() == UnitSystem::ImperialBuilding); + const auto visible = UnitsApi::isMultiUnitLength(); ui->comboBox_FracInch->setVisible(visible); ui->fractionalInchLabel->setVisible(visible); } @@ -204,7 +205,7 @@ void DlgSettingsGeneral::saveUnitSystemSettings() hGrpu->SetBool("IgnoreProjectSchema", ui->checkBox_projectUnitSystemIgnore->isChecked()); // Set actual value - Base::UnitsApi::setDecimals(ui->spinBoxDecimals->value()); + UnitsApi::setDecimals(ui->spinBoxDecimals->value()); // Convert the combobox index to the its integer denominator. Currently // with 1/2, 1/4, through 1/128, this little equation directly computes the @@ -218,21 +219,21 @@ void DlgSettingsGeneral::saveUnitSystemSettings() hGrpu->SetInt("FracInch", FracInch); // Set the actual format value - Base::QuantityFormat::setDefaultDenominator(FracInch); + QuantityFormat::setDefaultDenominator(FracInch); // Set and save the Unit System if (ui->checkBox_projectUnitSystemIgnore->isChecked()) { // currently selected View System (unit system) int viewSystemIndex = ui->comboBox_UnitSystem->currentIndex(); - UnitsApi::setSchema(static_cast(viewSystemIndex)); + UnitsApi::setSchema(viewSystemIndex); } else if (App::Document* doc = App::GetApplication().getActiveDocument()) { - UnitsApi::setSchema(static_cast(doc->UnitSystem.getValue())); + UnitsApi::setSchema(doc->UnitSystem.getValue()); } else { // if there is no existing document then the unit must still be set int viewSystemIndex = ui->comboBox_UnitSystem->currentIndex(); - UnitsApi::setSchema(static_cast(viewSystemIndex)); + UnitsApi::setSchema(viewSystemIndex); } ui->SubstituteDecimal->onSave(); @@ -287,11 +288,11 @@ void DlgSettingsGeneral::loadSettings() ParameterGrp::handle hGrpu = App::GetApplication().GetParameterGroupByPath ("User parameter:BaseApp/Preferences/Units"); ui->comboBox_UnitSystem->setCurrentIndex(hGrpu->GetInt("UserSchema", 0)); - ui->spinBoxDecimals->setValue(hGrpu->GetInt("Decimals", Base::UnitsApi::getDecimals())); + ui->spinBoxDecimals->setValue(hGrpu->GetInt("Decimals", UnitsApi::getDecimals())); ui->checkBox_projectUnitSystemIgnore->setChecked(hGrpu->GetBool("IgnoreProjectSchema", false)); // Get the current user setting for the minimum fractional inch - FracInch = hGrpu->GetInt("FracInch", Base::QuantityFormat::getDefaultDenominator()); + FracInch = hGrpu->GetInt("FracInch", QuantityFormat::getDefaultDenominator()); // Convert fractional inch to the corresponding combobox index using this // handy little equation. @@ -529,11 +530,11 @@ void DlgSettingsGeneral::translateIconSizes() void DlgSettingsGeneral::retranslateUnits() { - int num = ui->comboBox_UnitSystem->count(); - for (int i = 0; i < num; i++) { - QString item = Base::UnitsApi::getDescription(static_cast(i)); - ui->comboBox_UnitSystem->setItemText(i, item); - } + auto setItem = [&, index {0}](const std::string& item) mutable { + ui->comboBox_UnitSystem->setItemText(index++, QString::fromStdString(item)); + }; + const auto descriptions = UnitsApi::getDescriptions(); + std::for_each(descriptions.begin(), descriptions.end(), setItem); } void DlgSettingsGeneral::changeEvent(QEvent *event) @@ -761,13 +762,14 @@ void DlgSettingsGeneral::onLoadPreferencePackClicked(const std::string& packName } } -void DlgSettingsGeneral::onUnitSystemIndexChanged(int index) +void DlgSettingsGeneral::onUnitSystemIndexChanged(const int index) { - if (index < 0) - return; // happens when clearing the combo box in retranslateUi() + if (index < 0) { + return; // happens when clearing the combo box in retranslateUi() + } // Enable/disable the fractional inch option depending on system - const auto visible = (static_cast(index) == UnitSystem::ImperialBuilding); + const auto visible = UnitsApi::isMultiUnitLength(); ui->comboBox_FracInch->setVisible(visible); ui->fractionalInchLabel->setVisible(visible); } diff --git a/src/Gui/QuantitySpinBox.cpp b/src/Gui/QuantitySpinBox.cpp index 326e04bc4b..2a1d79f885 100644 --- a/src/Gui/QuantitySpinBox.cpp +++ b/src/Gui/QuantitySpinBox.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "QuantitySpinBox.h" #include "QuantitySpinBox_p.h" @@ -714,7 +715,7 @@ void QuantitySpinBox::setDecimals(int v) updateText(d->quantity); } -void QuantitySpinBox::setSchema(const Base::UnitSystem& s) +void QuantitySpinBox::setSchema(const int s) { Q_D(QuantitySpinBox); d->scheme = Base::UnitsApi::createSchema(s); @@ -732,7 +733,7 @@ QString QuantitySpinBox::getUserString(const Base::Quantity& val, double& factor { Q_D(const QuantitySpinBox); std::string unitStr; - std::string str = d->scheme ? val.getUserString(d->scheme.get(), factor, unitStr) + const std::string str = d->scheme ? val.getUserString(d->scheme.get(), factor, unitStr) : val.getUserString(factor, unitStr); unitString = QString::fromStdString(unitStr); return QString::fromStdString(str); diff --git a/src/Gui/QuantitySpinBox.h b/src/Gui/QuantitySpinBox.h index 780553718c..7c17216436 100644 --- a/src/Gui/QuantitySpinBox.h +++ b/src/Gui/QuantitySpinBox.h @@ -24,7 +24,6 @@ #ifndef GUI_QUANTITYSPINBOX_H #define GUI_QUANTITYSPINBOX_H -#include #include #include @@ -99,7 +98,7 @@ public: /// Sets a specific unit schema to handle quantities. /// The system-wide schema won't be used any more. - void setSchema(const Base::UnitSystem& s); + void setSchema(int s); /// Clears the schemaand again use the system-wide schema. void clearSchema(); diff --git a/src/Gui/Selection/Selection.cpp b/src/Gui/Selection/Selection.cpp index 112edc9e3b..1af17faebe 100644 --- a/src/Gui/Selection/Selection.cpp +++ b/src/Gui/Selection/Selection.cpp @@ -841,7 +841,7 @@ QString getPreselectionInfo(const char* documentName, { auto pts = schemaTranslatePoint(x, y, z, precision); - int numberDecimals = std::min(6, Base::UnitsApi::getDecimals()); + int numberDecimals = std::min(6, static_cast(Base::UnitsApi::getDecimals())); QString message = QStringLiteral("Preselected: %1.%2.%3 (%4 %5, %6 %7, %8 %9)") .arg(QString::fromUtf8(documentName)) diff --git a/src/Mod/Start/Gui/GeneralSettingsWidget.cpp b/src/Mod/Start/Gui/GeneralSettingsWidget.cpp index 3d6b024458..3f365193c0 100644 --- a/src/Mod/Start/Gui/GeneralSettingsWidget.cpp +++ b/src/Mod/Start/Gui/GeneralSettingsWidget.cpp @@ -33,6 +33,7 @@ #include #endif +#include #include "GeneralSettingsWidget.h" #include #include @@ -182,7 +183,7 @@ void GeneralSettingsWidget::onUnitSystemChanged(int index) if (index < 0) { return; // happens when clearing the combo box in retranslateUi() } - Base::UnitsApi::setSchema(static_cast(index)); + Base::UnitsApi::setSchema(index); ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units"); hGrp->SetInt("UserSchema", index); @@ -213,15 +214,16 @@ void GeneralSettingsWidget::retranslateUi() _unitSystemLabel->setText(createLabelText(tr("Unit System"))); _unitSystemComboBox->clear(); - ParameterGrp::handle hGrpUnits = + + auto addItem = [&, index {0}](const std::string& item) mutable { + _unitSystemComboBox->addItem(QString::fromStdString(item), index++); + }; + auto descriptions = Base::UnitsApi::getDescriptions(); + std::for_each(descriptions.begin(), descriptions.end(), addItem); + + const ParameterGrp::handle hGrpUnits = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units"); - auto userSchema = hGrpUnits->GetInt("UserSchema", 0); - int num = static_cast(Base::UnitSystem::NumUnitSystemTypes); - for (int i = 0; i < num; i++) { - QString item = Base::UnitsApi::getDescription(static_cast(i)); - _unitSystemComboBox->addItem(item, i); - } - _unitSystemComboBox->setCurrentIndex(userSchema); + _unitSystemComboBox->setCurrentIndex(static_cast(hGrpUnits->GetInt("UserSchema", 0))); _navigationStyleLabel->setText(createLabelText(tr("Navigation Style"))); _navigationStyleComboBox->clear(); diff --git a/tests/src/Base/CMakeLists.txt b/tests/src/Base/CMakeLists.txt index 154831216f..9bc17b29ec 100644 --- a/tests/src/Base/CMakeLists.txt +++ b/tests/src/Base/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(Tests_run PRIVATE Quantity.cpp Reader.cpp Rotation.cpp + SchemaTests.cpp ServiceProvider.cpp Stream.cpp TimeInfo.cpp diff --git a/tests/src/Base/Quantity.cpp b/tests/src/Base/Quantity.cpp index 525c57541b..7e555d7e71 100644 --- a/tests/src/Base/Quantity.cpp +++ b/tests/src/Base/Quantity.cpp @@ -1,16 +1,18 @@ #include #include #include -#include -#include #include -#include -// NOLINTBEGIN +using Base::ParserError; +using Base::Quantity; +using Base::Unit; +using Base::UnitsMismatchError; + + TEST(BaseQuantity, TestValid) { - Base::Quantity q1 {1.0, Base::Unit::Length}; - Base::Quantity q2 {1.0, Base::Unit::Area}; + const Quantity q1 {1.0, Unit::Length}; + Quantity q2 {1.0, Unit::Area}; q2.setInvalid(); EXPECT_EQ(q1.isValid(), true); @@ -19,77 +21,87 @@ TEST(BaseQuantity, TestValid) TEST(BaseQuantity, TestParse) { - Base::Quantity q1 = Base::Quantity::parse("1,234 kg"); - - EXPECT_EQ(q1, Base::Quantity(1.2340, Base::Unit::Mass)); - EXPECT_THROW(boost::ignore_unused(Base::Quantity::parse("1,234,500.12 kg")), Base::ParserError); + const Quantity q1 = Quantity::parse("1,234 kg"); + constexpr auto val {1.2340}; + EXPECT_EQ(q1, Quantity(val, Unit::Mass)); + EXPECT_THROW(auto rew [[maybe_unused]] = Quantity::parse("1,234,500.12 kg"), ParserError); } TEST(BaseQuantity, TestDim) { - Base::Quantity q1 {0, Base::Unit::Area}; + const Quantity q1 {0, Unit::Area}; EXPECT_EQ(q1.isQuantity(), true); } TEST(BaseQuantity, TestNoDim) { - Base::Quantity q1 {}; + const Quantity q1 {}; - EXPECT_EQ(q1.pow(2), Base::Quantity {0}); + EXPECT_EQ(q1.pow(2), Quantity {0}); EXPECT_EQ(q1.isDimensionless(), true); } TEST(BaseQuantity, TestPowEQ1) { - Base::Quantity q1 {2, Base::Unit::Area}; - EXPECT_EQ(q1.pow(1), Base::Quantity(2, Base::Unit::Area)); + const Quantity q1 {2, Unit::Area}; + const auto expect = Quantity {2, Unit::Area}; + EXPECT_EQ(q1.pow(1), expect); } TEST(BaseQuantity, TestPowEQ0) { - Base::Quantity q1 {2, Base::Unit::Area}; - EXPECT_EQ(q1.pow(0), Base::Quantity {1}); + const Quantity q1 {2, Unit::Area}; + EXPECT_EQ(q1.pow(0), Quantity {1}); } TEST(BaseQuantity, TestPowGT1) { - Base::Quantity q1 {2, Base::Unit::Length}; - EXPECT_EQ(q1.pow(2), Base::Quantity(4, Base::Unit::Area)); + constexpr auto v2 {2}; + constexpr auto v4 {4}; + const Quantity q1 {v2, Unit::Length}; + EXPECT_EQ(q1.pow(v2), Quantity(v4, Unit::Area)); } TEST(BaseQuantity, TestPowLT1) { - Base::Quantity q1 {8, Base::Unit::Volume}; - EXPECT_EQ(q1.pow(1.0 / 3.0), Base::Quantity(2, Base::Unit::Length)); + constexpr auto v8 {8}; + constexpr auto v2 {2}; + constexpr auto v3 {3.0}; + const Quantity q1 {v8, Unit::Volume}; + EXPECT_EQ(q1.pow(1.0 / v3), Quantity(v2, Unit::Length)); } TEST(BaseQuantity, TestPow3DIV2) { - Base::Quantity unit {8, Base::Unit::Volume}; - EXPECT_THROW(unit.pow(3.0 / 2.0), Base::UnitsMismatchError); + constexpr auto v2 {2.0}; + constexpr auto v3 {3.0}; + constexpr auto v8 {8}; + const Quantity unit {v8, Unit::Volume}; + EXPECT_THROW(unit.pow(v3 / v2), UnitsMismatchError); } TEST(BaseQuantity, TestString) { - Base::Quantity q1 {2, "kg*m/s^2"}; - EXPECT_EQ(q1.getUnit(), Base::Unit::Force); + constexpr auto v2 {2}; + const Quantity q1 {v2, "kg*m/s^2"}; + EXPECT_EQ(q1.getUnit(), Unit::Force); - Base::Quantity q2 {2, "kg*m^2/s^2"}; - EXPECT_EQ(q2.getUnit(), Base::Unit::Work); + const Quantity q2 {v2, "kg*m^2/s^2"}; + EXPECT_EQ(q2.getUnit(), Unit::Work); } TEST(BaseQuantity, TestCopy) { - Base::Quantity q1 {1.0, Base::Unit::Length}; + const Quantity q1 {1.0, Unit::Length}; - EXPECT_EQ(Base::Quantity {q1}, q1); + EXPECT_EQ(Quantity {q1}, q1); } TEST(BaseQuantity, TestEqual) { - Base::Quantity q1 {1.0, Base::Unit::Force}; - Base::Quantity q2 {1.0, "kg*mm/s^2"}; + const Quantity q1 {1.0, Unit::Force}; + const Quantity q2 {1.0, "kg*mm/s^2"}; EXPECT_EQ(q1 == q1, true); EXPECT_EQ(q1 == q2, true); @@ -97,9 +109,10 @@ TEST(BaseQuantity, TestEqual) TEST(BaseQuantity, TestNotEqual) { - Base::Quantity q1 {1.0, Base::Unit::Force}; - Base::Quantity q2 {2.0, "kg*m/s^2"}; - Base::Quantity q3 {1.0, Base::Unit::Work}; + constexpr auto v2 {2.0}; + const Quantity q1 {1.0, Unit::Force}; + const Quantity q2 {v2, "kg*m/s^2"}; + const Quantity q3 {1.0, Unit::Work}; EXPECT_EQ(q1 != q2, true); EXPECT_EQ(q1 != q3, true); @@ -107,73 +120,77 @@ TEST(BaseQuantity, TestNotEqual) TEST(BaseQuantity, TestLessOrGreater) { - Base::Quantity q1 {1.0, Base::Unit::Force}; - Base::Quantity q2 {2.0, "kg*m/s^2"}; - Base::Quantity q3 {2.0, Base::Unit::Work}; + constexpr auto v2 {2.0}; + Quantity q1 {1.0, Unit::Force}; + Quantity q2 {v2, "kg*m/s^2"}; + Quantity q3 {v2, Unit::Work}; EXPECT_EQ(q1 < q2, true); EXPECT_EQ(q1 > q2, false); EXPECT_EQ(q1 <= q1, true); EXPECT_EQ(q1 >= q1, true); - EXPECT_THROW(boost::ignore_unused(q1 < q3), Base::UnitsMismatchError); - EXPECT_THROW(boost::ignore_unused(q1 > q3), Base::UnitsMismatchError); - EXPECT_THROW(boost::ignore_unused(q1 <= q3), Base::UnitsMismatchError); - EXPECT_THROW(boost::ignore_unused(q1 >= q3), Base::UnitsMismatchError); + EXPECT_THROW(auto res [[maybe_unused]] = (q1 < q3), UnitsMismatchError); + EXPECT_THROW(auto res [[maybe_unused]] = (q1 > q3), UnitsMismatchError); + EXPECT_THROW(auto res [[maybe_unused]] = (q1 <= q3), UnitsMismatchError); + EXPECT_THROW(auto res [[maybe_unused]] = (q1 >= q3), UnitsMismatchError); } TEST(BaseQuantity, TestAdd) { - Base::Quantity q1 {1.0, Base::Unit::Length}; - Base::Quantity q2 {1.0, Base::Unit::Area}; - EXPECT_THROW(q1 + q2, Base::UnitsMismatchError); - EXPECT_THROW(q1 += q2, Base::UnitsMismatchError); - EXPECT_EQ(q1 + q1, Base::Quantity(2, Base::Unit::Length)); - EXPECT_EQ(q1 += q1, Base::Quantity(2, Base::Unit::Length)); + Quantity q1 {1.0, Unit::Length}; + Quantity q2 {1.0, Unit::Area}; + EXPECT_THROW(q1 + q2, UnitsMismatchError); + EXPECT_THROW(q1 += q2, UnitsMismatchError); + EXPECT_EQ(q1 + q1, Quantity(2, Unit::Length)); + EXPECT_EQ(q1 += q1, Quantity(2, Unit::Length)); } TEST(BaseQuantity, TestSub) { - Base::Quantity q1 {1.0, Base::Unit::Length}; - Base::Quantity q2 {1.0, Base::Unit::Area}; - EXPECT_THROW(q1 - q2, Base::UnitsMismatchError); - EXPECT_THROW(q1 -= q2, Base::UnitsMismatchError); - EXPECT_EQ(q1 - q1, Base::Quantity(0, Base::Unit::Length)); - EXPECT_EQ(q1 -= q1, Base::Quantity(0, Base::Unit::Length)); + Quantity q1 {1.0, Unit::Length}; + Quantity q2 {1.0, Unit::Area}; + EXPECT_THROW(q1 - q2, UnitsMismatchError); + EXPECT_THROW(q1 -= q2, UnitsMismatchError); + EXPECT_EQ(q1 - q1, Quantity(0, Unit::Length)); + EXPECT_EQ(q1 -= q1, Quantity(0, Unit::Length)); } TEST(BaseQuantity, TestNeg) { - Base::Quantity q1 {1.0, Base::Unit::Length}; - EXPECT_EQ(-q1, Base::Quantity(-1.0, Base::Unit::Length)); + const Quantity q1 {1.0, Unit::Length}; + EXPECT_EQ(-q1, Quantity(-1.0, Unit::Length)); } TEST(BaseQuantity, TestMult) { - Base::Quantity q1 {1.0, Base::Unit::Length}; - Base::Quantity q2 {1.0, Base::Unit::Area}; - EXPECT_EQ(q1 * q2, Base::Quantity(1.0, Base::Unit::Volume)); - EXPECT_EQ(q1 * 2.0, Base::Quantity(2.0, Base::Unit::Length)); + const Quantity q1 {1.0, Unit::Length}; + const Quantity q2 {1.0, Unit::Area}; + EXPECT_EQ(q1 * q2, Quantity(1.0, Unit::Volume)); + EXPECT_EQ(q1 * 2.0, Quantity(2.0, Unit::Length)); } TEST(BaseQuantity, TestDiv) { - Base::Quantity q1 {1.0, Base::Unit::Length}; - Base::Quantity q2 {1.0, Base::Unit::Area}; - EXPECT_EQ(q1 / q2, Base::Quantity(1.0, Base::Unit::InverseLength)); - EXPECT_EQ(q1 / 2.0, Base::Quantity(0.5, Base::Unit::Length)); + const Quantity q1 {1.0, Unit::Length}; + const Quantity q2 {1.0, Unit::Area}; + EXPECT_EQ(q1 / q2, Quantity(1.0, Unit::InverseLength)); + EXPECT_EQ(q1 / 2.0, Quantity(0.5, Unit::Length)); } TEST(BaseQuantity, TestPow) { - Base::Quantity q1 {2.0, Base::Unit::Length}; - Base::Quantity q2 {2.0, Base::Unit::Area}; - Base::Quantity q3 {0.0}; - EXPECT_EQ(q1.pow(q3), Base::Quantity {1}); - EXPECT_EQ(q1.pow(2.0), Base::Quantity(4, Base::Unit::Area)); - EXPECT_THROW(q1.pow(q2), Base::UnitsMismatchError); + constexpr auto v2 {2.0}; + constexpr auto v4 {4}; + + Quantity q1 {v2, Unit::Length}; + Quantity q2 {v2, Unit::Area}; + Quantity q3 {0.0}; + EXPECT_EQ(q1.pow(q3), Quantity {1}); + EXPECT_EQ(q1.pow(v2), Quantity(v4, Unit::Area)); + EXPECT_THROW(q1.pow(q2), UnitsMismatchError); } -class Quantity: public ::testing::Test +class BaseQuantityLoc: public ::testing::Test { protected: void SetUp() override @@ -185,60 +202,77 @@ protected: {} }; -TEST_F(Quantity, TestSchemeImperialTwo) +TEST_F(BaseQuantityLoc, psi_parse_spaced) { - Base::Quantity quantity {1.0, Base::Unit::Length}; - - double factor {}; - std::string unitString; - auto scheme = Base::UnitsApi::createSchema(Base::UnitSystem::ImperialDecimal); - std::string result = scheme->schemaTranslate(quantity, factor, unitString); - EXPECT_EQ(result, "0.04 in"); + const auto qParsed = Quantity::parse("1 psi"); + EXPECT_EQ(qParsed.getValue(), 6.8947448254939996); } -TEST_F(Quantity, TestSchemeImperialOne) +TEST_F(BaseQuantityLoc, psi_parse_no_space) { - Base::Quantity quantity {1.0, Base::Unit::Length}; - - Base::QuantityFormat format = quantity.getFormat(); - format.precision = 1; - quantity.setFormat(format); - - double factor {}; - std::string unitString; - auto scheme = Base::UnitsApi::createSchema(Base::UnitSystem::ImperialDecimal); - std::string result = scheme->schemaTranslate(quantity, factor, unitString); - - EXPECT_EQ(result, "0.0 in"); + const auto qParsed = Quantity::parse("1psi"); + EXPECT_EQ(qParsed.getValue(), 6.8947448254939996); } -TEST_F(Quantity, TestSafeUserString) +TEST_F(BaseQuantityLoc, psi_parse_user_str) { - Base::UnitsApi::setSchema(Base::UnitSystem::ImperialDecimal); - - Base::Quantity quantity {1.0, Base::Unit::Length}; - Base::QuantityFormat format = quantity.getFormat(); - format.precision = 1; - quantity.setFormat(format); - - std::string result = quantity.getSafeUserString(); - - EXPECT_EQ(result, "1 mm"); - - Base::UnitsApi::setSchema(Base::UnitSystem::Imperial1); - - quantity = Base::Quantity {304.8, Base::Unit::Length}; - quantity.setFormat(format); - - result = quantity.getSafeUserString(); - - EXPECT_EQ(result, "1.0 \\'"); - - quantity = Base::Quantity {25.4, Base::Unit::Length}; - quantity.setFormat(format); - - result = quantity.getSafeUserString(); - - EXPECT_EQ(result, "1.0 \\\""); + const auto qParsed = Quantity::parse("1 psi"); + EXPECT_EQ(qParsed.getUserString(), "6894.74 Pa"); +} + +TEST_F(BaseQuantityLoc, psi_parse_safe_user_str) +{ + const auto qParsed = Quantity::parse("1 psi"); + EXPECT_EQ(qParsed.getSafeUserString(), "6894.74 Pa"); +} + +TEST_F(BaseQuantityLoc, psi_parse_unit_type) +{ + const auto qParsed = Quantity::parse("1 psi"); + EXPECT_EQ(qParsed.getUnit().getTypeString(), "Pressure"); +} + +TEST_F(BaseQuantityLoc, psi_to_Pa) +{ + const auto result = Quantity::parse("1 psi").getValueAs(Quantity::Pascal); + const auto expect = 6894.7448254939991; + + EXPECT_EQ(result, expect); +} + +TEST_F(BaseQuantityLoc, psi_to_KPa) +{ + const auto result = Quantity::parse("1 psi").getValueAs(Quantity::KiloPascal); + const auto expect = 6.8947448254939996; + + EXPECT_EQ(result, expect); +} + +TEST_F(BaseQuantityLoc, psi_to_MPa) +{ + const auto result = Quantity::parse("1 psi").getValueAs(Quantity::MegaPascal); + const auto expect = 0.0068947448254939999; + + EXPECT_EQ(result, expect); +} + +TEST_F(BaseQuantityLoc, voltage_unit) +{ + const auto qq = Quantity::parse("1e20 V"); + + EXPECT_EQ(qq.getUnit(), Unit::ElectricPotential); +} + +TEST_F(BaseQuantityLoc, voltage_val) +{ + const auto qq = Quantity::parse("1e20 V"); + + EXPECT_EQ(qq.getValue(), 1e+26); +} + +TEST_F(BaseQuantityLoc, voltage_val_smaller) +{ + const auto qq = Quantity::parse("1e3 V"); + + EXPECT_EQ(qq.getValue(), 1e+9); } -// NOLINTEND diff --git a/tests/src/Base/SchemaTests.cpp b/tests/src/Base/SchemaTests.cpp new file mode 100644 index 0000000000..8cfc3644c3 --- /dev/null +++ b/tests/src/Base/SchemaTests.cpp @@ -0,0 +1,373 @@ +/************************************************************************ + * * + * 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 * + * * + ************************************************************************/ + +#include +#include "Base/Exception.h" +#include "Base/Unit.h" +#include "Base/Quantity.h" +#include "Base/UnitsApi.h" +#include "Base/UnitsSchemasData.h" +#include "Base/UnitsSchemas.h" + +#include +#include + +using Base::Quantity; +using Base::QuantityFormat; +using Base::RuntimeError; +using Base::Unit; +using Base::UnitsApi; +using Base::UnitsSchema; +using Base::UnitsSchemas; + +class SchemaTest: public testing::Test +{ +protected: + void SetUp() override + { + const QLocale loc(QLocale::C); + QLocale::setDefault(loc); + } + + void TearDown() override + {} + + static std::string + set(const std::string& schemaName, const Unit unit, const double value) // NOLINT + { + UnitsApi::setSchema(schemaName); + const auto quantity = Quantity {value, unit}; + return quantity.getSafeUserString(); + } + + static std::string setWithPrecision(const std::string& name, + const double value, + const Unit unit, + const int precision) + { + UnitsApi::setSchema(name); + Quantity quantity {value, unit}; + QuantityFormat format = quantity.getFormat(); + format.precision = precision; + quantity.setFormat(format); + return quantity.getSafeUserString(); + } + + std::unique_ptr schemas; // NOLINT +}; + +TEST_F(SchemaTest, imperial_decimal_1_mm_default_precision) +{ + const std::string result = set("ImperialDecimal", Unit::Length, 1.0); + const auto expect {"0.04 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, internal_1_mm_precision_0) +{ + const std::string result = setWithPrecision("Internal", 1.0, Unit::Length, 0); + const auto expect {"1 mm"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, internal_100_mm_precision_0) +{ + const std::string result = setWithPrecision("Internal", 100.0, Unit::Length, 0); + const auto expect {"100 mm"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, internal_100_mm_precision_1) +{ + const std::string result = setWithPrecision("Internal", 100.0, Unit::Length, 1); + const auto expect {"100.0 mm"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, internal_20000_mm_precision_2) +{ + const std::string result = setWithPrecision("Internal", 20000.0, Unit::Length, 2); + const auto expect {"20.00 m"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_1_mm_precision_0) +{ + const std::string result = setWithPrecision("ImperialDecimal", 1.0, Unit::Length, 0); + const auto expect {"1 mm"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_10_mm_precision_0) +{ + const std::string result = setWithPrecision("ImperialDecimal", 10.0, Unit::Length, 0); + const auto expect {"10 mm"}; + // https://github.com/FreeCAD/FreeCAD/commit/569154b73f818c6a88b010def687d5e684ce64c2 + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_20_mm_precision_0) +{ + const std::string result = setWithPrecision("ImperialDecimal", 20.0, Unit::Length, 0); + const auto expect {"1 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_1_mm_precision_0) +{ + const std::string result = setWithPrecision("Imperial", 1.0, Unit::Length, 0); + const auto expect {"39 thou"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_0_mm_precision_0) +{ + const std::string result = setWithPrecision("Imperial", 0.0, Unit::Length, 0); + const auto expect {"0 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_0_mm_precision_1) +{ + const std::string result = setWithPrecision("Imperial", 0.0, Unit::Length, 1); + const auto expect {"0.0 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_0_mm_precision_0) +{ + const std::string result = setWithPrecision("ImperialDecimal", 0.0, Unit::Length, 0); + const auto expect {"0 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_0_mm_precision_1) +{ + const std::string result = setWithPrecision("ImperialDecimal", 0.0, Unit::Length, 1); + const auto expect {"0.0 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_civil_0_mm_precision_0) +{ + const std::string result = setWithPrecision("ImperialCivil", 0.0, Unit::Length, 0); + const auto expect {"0 mm"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_civil_0_mm_precision_1) +{ + const std::string result = setWithPrecision("ImperialCivil", 0.0, Unit::Length, 1); + const auto expect {"0.0 mm"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_building_0_mm_precision_0) +{ + const std::string result = setWithPrecision("ImperialBuilding", 0.0, Unit::Length, 0); + const auto expect {"0"}; // don't know why + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_building_0_mm_precision_1) +{ + const std::string result = setWithPrecision("ImperialBuilding", 0.0, Unit::Length, 1); + const auto expect {"0"}; // don't know why + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_1_mm_precision_1) +{ + const std::string result = setWithPrecision("ImperialDecimal", 1.0, Unit::Length, 1); + const auto expect {"1 mm"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_100_mm_precision_0) +{ + const std::string result = setWithPrecision("ImperialDecimal", 100.0, Unit::Length, 0); + const auto expect {"4 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_100_mm_precision_1) +{ + const std::string result = setWithPrecision("ImperialDecimal", 100.0, Unit::Length, 1); + const auto expect {"3.9 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_100_mm_precision_2) +{ + const std::string result = setWithPrecision("ImperialDecimal", 100.0, Unit::Length, 2); + const auto expect {"3.94 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_1_mm_precision_2) +{ + const std::string result = setWithPrecision("ImperialDecimal", 1.0, Unit::Length, 2); + const auto expect {"0.04 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_decimal_1_mm_precision_4) +{ + const std::string result = setWithPrecision("ImperialDecimal", 1.0, Unit::Length, 4); + const auto expect {"0.0394 in"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_safe_user_str_same) +{ + constexpr auto val {304.8}; + const auto result = set("Imperial", Unit::Length, val); + const auto expect {"1.00′"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_safe_user_str_more) +{ + constexpr auto val {310.0}; + const auto result = set("Imperial", Unit::Length, val); + const auto expect {"1.02′"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_safe_user_str_less) +{ + constexpr auto val {300.0}; + const auto result = set("Imperial", Unit::Length, val); + const auto expect {"11.81″"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_safe_user_str_one_inch) +{ + constexpr auto val {25.4}; + const auto result = set("Imperial", Unit::Length, val); + const auto expect {"1.00″"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_building_special_function_length_inch) +{ + constexpr auto val {25.4}; + const auto result = set("ImperialBuilding", Unit::Length, val); + const auto expect {"1″"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_building_special_function_length_foot) +{ + constexpr auto val {25.4 * 12}; + const auto result = set("ImperialBuilding", Unit::Length, val); + const auto expect {"1′"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_building_special_function_length) +{ + constexpr auto val {360.6}; + const auto result = set("ImperialBuilding", Unit::Length, val); + const auto expect {"1′2-1/4″"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_building_special_function_length_neg) +{ + constexpr auto val {-360.6}; + const auto result = set("ImperialBuilding", Unit::Length, val); + const auto expect {"-1′2-1/4″"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_civil_special_function_angle_degrees) +{ + constexpr auto val {180}; + const auto result = set("ImperialCivil", Unit::Angle, val); + const auto expect {"180°"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_civil_special_function_angle_minutes) +{ + constexpr auto val {180.5}; + const auto result = set("ImperialCivil", Unit::Angle, val); + const auto expect {"180°30′"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_civil_special_function_angle_seconds) +{ + constexpr auto val {180.11}; + const auto result = set("ImperialCivil", Unit::Angle, val); + const auto expect {"180°6′36″"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, imperial_civil_special_function_angle_no_degrees) +{ + constexpr auto val {0.11}; + const auto result = set("ImperialCivil", Unit::Angle, val); + const auto expect {"0°6′36″"}; + + EXPECT_EQ(result, expect); +} + +TEST_F(SchemaTest, unknown_schema_name_throws) +{ + EXPECT_THROW(UnitsApi::setSchema("Unknown"), RuntimeError); +} diff --git a/tests/src/Mod/Material/App/TestMaterialValue.cpp b/tests/src/Mod/Material/App/TestMaterialValue.cpp index 1a5d1d12e4..9a6cbe79ef 100644 --- a/tests/src/Mod/Material/App/TestMaterialValue.cpp +++ b/tests/src/Mod/Material/App/TestMaterialValue.cpp @@ -130,7 +130,7 @@ TEST_F(TestMaterialValue, TestQuantityType) EXPECT_EQ(variant.toString().size(), 0); auto quantity = variant.value(); EXPECT_FALSE(quantity.isValid()); - EXPECT_EQ(quantity.getUserString(), "nan "); + EXPECT_EQ(quantity.getUserString(), "nan"); EXPECT_TRUE(std::isnan(quantity.getValue())); // Test a copy @@ -146,7 +146,7 @@ TEST_F(TestMaterialValue, TestQuantityType) EXPECT_EQ(variant.toString().size(), 0); quantity = variant.value(); EXPECT_FALSE(quantity.isValid()); - EXPECT_EQ(quantity.getUserString(), "nan "); + EXPECT_EQ(quantity.getUserString(), "nan"); EXPECT_TRUE(std::isnan(quantity.getValue())); }