Base: simplify UnitsSchemas management

Fixes: Maintaining schemas is difficult and error-prone

- Facilitate easy schemas add, remove, change, etc.
- Remove 14 files containing approx 2,190 lines of if/else code and data
- Place data in one file (UnitsSchemasData.h) using a normalized structure (including special functions)
- Isolate and simplify data operations (code)
- Remove schemas enum to keep data independent of code
- Separate responsibilities: Specifications, data, schemas, schema
- Add schema data 'isDefault'
- Add schema data name
- Prefer algorithms to raw loops
- Add schemas unit tests
- Tweak quantity unit tests
This commit is contained in:
bofdahof
2025-01-22 09:40:00 +10:00
committed by Ladislav Michl
parent ef6f60510a
commit 1155f0d752
39 changed files with 1983 additions and 2928 deletions

View File

@@ -2795,12 +2795,10 @@ void Application::initApplication()
// set up Unit system default // set up Unit system default
const ParameterGrp::handle hGrp = GetApplication().GetParameterGroupByPath const ParameterGrp::handle hGrp = GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Units"); ("User parameter:BaseApp/Preferences/Units");
Base::UnitsApi::setSchema(static_cast<Base::UnitSystem>(hGrp->GetInt("UserSchema", 0))); Base::UnitsApi::setSchema(hGrp->GetInt("UserSchema", Base::UnitsApi::getDefSchemaNum()));
Base::UnitsApi::setDecimals(static_cast<int>(hGrp->GetInt("Decimals", Base::UnitsApi::getDecimals()))); Base::UnitsApi::setDecimals(hGrp->GetInt("Decimals", Base::UnitsApi::getDecimals()));
Base::QuantityFormat::setDefaultDenominator(
// In case we are using fractional inches, get user setting for min unit hGrp->GetInt("FracInch", Base::QuantityFormat::getDefaultDenominator()));
const int denom = static_cast<int>(hGrp->GetInt("FracInch", Base::QuantityFormat::getDefaultDenominator()));
Base::QuantityFormat::setDefaultDenominator(denom);
#if defined (_DEBUG) #if defined (_DEBUG)
Base::Console().Log("Application is built with debug information\n"); Base::Console().Log("Application is built with debug information\n");

View File

@@ -876,13 +876,8 @@ Document::Document(const char* documentName)
"Additional tag to save the name of the company"); "Additional tag to save the name of the company");
ADD_PROPERTY_TYPE(UnitSystem, (""), 0, Prop_None, "Unit system to use in this project"); ADD_PROPERTY_TYPE(UnitSystem, (""), 0, Prop_None, "Unit system to use in this project");
// Set up the possible enum values for the unit system // Set up the possible enum values for the unit system
int num = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes);
std::vector<std::string> enumValsAsVector; UnitSystem.setEnums(Base::UnitsApi::getDescriptions());
for (int i = 0; i < num; i++) {
QString item = Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i));
enumValsAsVector.emplace_back(item.toStdString());
}
UnitSystem.setEnums(enumValsAsVector);
// Get the preferences/General unit system as the default for a new document // Get the preferences/General unit system as the default for a new document
ParameterGrp::handle hGrpu = ParameterGrp::handle hGrpu =
App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units"); App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units");

View File

@@ -150,20 +150,10 @@ SET(FreeCADBase_UNITAPI_SRCS
UnitsApi.h UnitsApi.h
UnitsSchema.h UnitsSchema.h
UnitsSchema.cpp UnitsSchema.cpp
UnitsSchemaInternal.h UnitsSchemas.cpp
UnitsSchemaInternal.cpp UnitsSchemas.h
UnitsSchemaMKS.h UnitsSchemasData.h
UnitsSchemaMKS.cpp UnitsSchemasSpecs.h
UnitsSchemaImperial1.h
UnitsSchemaImperial1.cpp
UnitsSchemaCentimeters.h
UnitsSchemaCentimeters.cpp
UnitsSchemaMmMin.h
UnitsSchemaMmMin.cpp
UnitsSchemaFemMilliMeterNewton.h
UnitsSchemaFemMilliMeterNewton.cpp
UnitsSchemaMeterDecimal.h
UnitsSchemaMeterDecimal.cpp
Quantity.h Quantity.h
Quantity.cpp Quantity.cpp
QuantityPyImp.cpp QuantityPyImp.cpp

View File

@@ -64,7 +64,7 @@ int QuantityFormat::defaultDenominator = 8; // for 1/8"
QuantityFormat::QuantityFormat() QuantityFormat::QuantityFormat()
: option(OmitGroupSeparator | RejectGroupSeparator) : option(OmitGroupSeparator | RejectGroupSeparator)
, format(Fixed) , format(Fixed)
, precision(UnitsApi::getDecimals()) , precision(static_cast<int>(UnitsApi::getDecimals()))
, denominator(defaultDenominator) , denominator(defaultDenominator)
{} {}
@@ -256,14 +256,15 @@ std::string Quantity::getUserString(double& factor, std::string& unitString) con
std::string std::string
Quantity::getUserString(UnitsSchema* schema, double& factor, std::string& unitString) const 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 std::string Quantity::getSafeUserString() const
{ {
auto userStr = getUserString(); auto userStr = getUserString();
if (myValue != 0.0 && parse(userStr).getValue() == 0) { 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); return Tools::escapeQuotesFromString(userStr);

View File

@@ -20,124 +20,91 @@
* * * *
***************************************************************************/ ***************************************************************************/
#include "PreCompiled.h" #include "PreCompiled.h"
#ifndef _PreComp_
#include <sstream>
#include <iomanip> #include <iomanip>
#include <memory> #include <sstream>
#endif
#include <CXX/WrapPython.h> #include <CXX/WrapPython.h>
#include <fmt/format.h> #include <fmt/format.h>
#include <QString>
#include "Exception.h" #include "Exception.h"
#include "UnitsApi.h" #include "UnitsApi.h"
#include "UnitsSchemaCentimeters.h" #include "UnitsSchema.h"
#include "UnitsSchemaInternal.h" #include "UnitsSchemas.h"
#include "UnitsSchemaImperial1.h" #include "UnitsSchemasData.h"
#include "UnitsSchemaMKS.h"
#include "UnitsSchemaMmMin.h"
#include "UnitsSchemaFemMilliMeterNewton.h"
#include "UnitsSchemaMeterDecimal.h"
using namespace Base; using Base::UnitsApi;
using Base::UnitsSchema;
using Base::UnitsSchemas;
// === static attributes ================================================ void UnitsApi::init()
UnitsSchemaPtr UnitsApi::UserPrefSystem(new UnitsSchemaInternal());
UnitSystem UnitsApi::currentSystem = UnitSystem::SI1;
int UnitsApi::UserPrefDecimals = 2;
QString UnitsApi::getDescription(UnitSystem system)
{ {
switch (system) { schemas = std::make_unique<UnitsSchemas>(UnitsSchemasData::unitSchemasDataPack);
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");
}
} }
UnitsSchemaPtr UnitsApi::createSchema(UnitSystem system) std::vector<std::string> UnitsApi::getDescriptions()
{ {
switch (system) { return schemas->descriptions();
case UnitSystem::SI1:
return std::make_unique<UnitsSchemaInternal>();
case UnitSystem::SI2:
return std::make_unique<UnitsSchemaMKS>();
case UnitSystem::Imperial1:
return std::make_unique<UnitsSchemaImperial1>();
case UnitSystem::ImperialDecimal:
return std::make_unique<UnitsSchemaImperialDecimal>();
case UnitSystem::Centimeters:
return std::make_unique<UnitsSchemaCentimeters>();
case UnitSystem::ImperialBuilding:
return std::make_unique<UnitsSchemaImperialBuilding>();
case UnitSystem::MmMin:
return std::make_unique<UnitsSchemaMmMin>();
case UnitSystem::ImperialCivil:
return std::make_unique<UnitsSchemaImperialCivil>();
case UnitSystem::FemMilliMeterNewton:
return std::make_unique<UnitsSchemaFemMilliMeterNewton>();
case UnitSystem::MeterDecimal:
return std::make_unique<UnitsSchemaMeterDecimal>();
default:
break;
}
return nullptr;
} }
void UnitsApi::setSchema(UnitSystem system) std::vector<std::string> UnitsApi::getNames()
{ {
if (UserPrefSystem) { return schemas->names();
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<UnitsSchemaInternal>();
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).
} }
std::string UnitsApi::toString(const Base::Quantity& quantity, const QuantityFormat& format) std::size_t UnitsApi::count()
{
return static_cast<int>(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<UnitsSchema> UnitsApi::createSchema(const std::size_t num)
{
return std::make_unique<UnitsSchema>(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()); 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); 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; std::stringstream ss;
@@ -156,31 +123,6 @@ std::string UnitsApi::toNumber(double value, const QuantityFormat& format)
return ss.str(); 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) double UnitsApi::toDouble(PyObject* args, const Base::Unit& u)
{ {
if (PyUnicode_Check(args)) { if (PyUnicode_Check(args)) {
@@ -203,34 +145,30 @@ double UnitsApi::toDouble(PyObject* args, const Base::Unit& u)
throw Base::UnitsMismatchError("Wrong parameter type!"); 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 {}; return schemas->currentSchema()->translate(quant, factor, unitString);
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<double>(PyLong_AsLong(args));
}
else {
throw Base::UnitsMismatchError("Wrong parameter type!");
}
return Quantity(d, u);
} }
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();
} }

View File

@@ -20,13 +20,12 @@
* * * *
***************************************************************************/ ***************************************************************************/
#ifndef BASE_UNITSAPI_H #ifndef BASE_UNITSAPI_H
#define BASE_UNITSAPI_H #define BASE_UNITSAPI_H
#include <memory>
#include <QCoreApplication>
#include "UnitsSchema.h" #include "UnitsSchema.h"
#include "UnitsSchemas.h"
#include "UnitsSchemasData.h"
#include "Quantity.h" #include "Quantity.h"
@@ -37,96 +36,71 @@ using PyMethodDef = struct PyMethodDef;
namespace Base namespace Base
{ {
using UnitsSchemaPtr = std::unique_ptr<UnitsSchema>;
/**
* The UnitsApi
*/
class BaseExport UnitsApi class BaseExport UnitsApi
{ {
Q_DECLARE_TR_FUNCTIONS(UnitsApi)
public: public:
/** set Schema static void init();
* set the UnitsSchema of the Application static std::unique_ptr<UnitsSchema> createSchema(std::size_t num);
* this a represented by a class of type UnitSchema which static void setSchema(const std::string& name);
* defines a set of standard units for that schema and rules static void setSchema(std::size_t num);
* 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 std::string static std::string
schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString); schemaTranslate(const 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);
}
/** Get a number as string for a quantity of a given format. static std::string schemaTranslate(const Quantity& quant);
* 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. /**
*/ * toString & toNumber:
static std::string toString(const Base::Quantity& q, * Quantity to string. Optionally apply format
const QuantityFormat& f = QuantityFormat(QuantityFormat::Default)); * The string is a number in C locale (i.e. the decimal separator is always a dot)
/** Get a number as string for a quantity of a given format. * Scientific notation (if needed).
* 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. /** INCLUDES unit */
*/ static std::string
static std::string toNumber(const Base::Quantity& q, toString(const Quantity& quantity,
const QuantityFormat& f = QuantityFormat(QuantityFormat::Default)); const QuantityFormat& format = 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 /** Does NOT include unit */
* needed represented in scientific notation. The string doesn't include the unit of the static std::string
* quantity. toNumber(const Quantity& quantity,
*/ const QuantityFormat& format = QuantityFormat(QuantityFormat::Default));
static std::string toNumber(double value,
const QuantityFormat& f = 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()); 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(std::size_t);
static void setDecimals(int); static std::size_t getDecimals();
// get the number of decimals static std::size_t getDefDecimals();
static int getDecimals();
//@}
// double Result; static std::vector<std::string> getDescriptions();
static std::vector<std::string> getNames();
// return true if the current user schema uses multiple units for length (ex. Ft/In) static std::size_t count();
static bool isMultiUnitLength();
// return true if the current user schema uses multiple units for angles (ex. DMS)
static bool isMultiUnitAngle(); static bool isMultiUnitAngle();
static bool isMultiUnitLength();
// return the basic unit of measure for length in the current user schema.
static std::string getBasicLengthUnit(); static std::string getBasicLengthUnit();
static std::size_t getFractDenominator();
static std::size_t getDefSchemaNum()
{
return schemas->spec().num;
}
// Python interface // Python interface
static PyMethodDef Methods[]; static PyMethodDef Methods[];
/// return an instance of the given enum value
static UnitsSchemaPtr createSchema(UnitSystem s);
protected: protected:
static UnitsSchemaPtr UserPrefSystem; static inline auto schemas =
static UnitSystem currentSystem; std::make_unique<UnitsSchemas>(UnitsSchemasData::unitSchemasDataPack);
/// number of decimals for floats static inline std::size_t decimals {2};
static int UserPrefDecimals; static inline std::size_t denominator {2};
protected:
// the python API wrapper methods // the python API wrapper methods
static PyObject* sParseQuantity(PyObject* self, PyObject* args); static PyObject* sParseQuantity(PyObject* self, PyObject* args);
static PyObject* sListSchemas(PyObject* self, PyObject* args); static PyObject* sListSchemas(PyObject* self, PyObject* args);
@@ -138,5 +112,4 @@ protected:
} // namespace Base } // namespace Base
#endif // BASE_UNITSAPI_H #endif // BASE_UNITSAPI_H

View File

@@ -20,9 +20,7 @@
* * * *
***************************************************************************/ ***************************************************************************/
#include "PreCompiled.h" #include "PreCompiled.h"
#ifndef _PreComp_ #ifndef _PreComp_
#include <memory> #include <memory>
#endif #endif
@@ -39,10 +37,9 @@ using namespace Base;
//************************************************************************** //**************************************************************************
// Python stuff of UnitsApi // Python stuff of UnitsApi
// UnitsApi Methods
PyMethodDef UnitsApi::Methods[] = { PyMethodDef UnitsApi::Methods[] = {
{"parseQuantity", {"parseQuantity",
UnitsApi::sParseQuantity, sParseQuantity,
METH_VARARGS, METH_VARARGS,
"parseQuantity(string) -> Base.Quantity()\n\n" "parseQuantity(string) -> Base.Quantity()\n\n"
"calculate a mathematical expression with units to a quantity object. \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" "or for more complex espressions:\n"
"parseQuantity('sin(pi)/50.0 m/s^2')\n"}, "parseQuantity('sin(pi)/50.0 m/s^2')\n"},
{"listSchemas", {"listSchemas",
UnitsApi::sListSchemas, sListSchemas,
METH_VARARGS, METH_VARARGS,
"listSchemas() -> a tuple of schemas\n\n" "listSchemas() -> a tuple of schemas\n\n"
"listSchemas(int) -> description of the given schema\n\n"}, "listSchemas(int) -> description of the given schema\n\n"},
{"getSchema", {"getSchema",
UnitsApi::sGetSchema, sGetSchema,
METH_VARARGS, METH_VARARGS,
"getSchema() -> int\n\n" "getSchema() -> int\n\n"
"The int is the position of the tuple returned by listSchemas"}, "The int is the position of the tuple returned by listSchemas"},
{"setSchema", {"setSchema",
UnitsApi::sSetSchema, sSetSchema,
METH_VARARGS, METH_VARARGS,
"setSchema(int) -> None\n\n" "setSchema(int) -> None\n\n"
"Sets the current schema to the given number, if possible"}, "Sets the current schema to the given number, if possible"},
{"schemaTranslate", {"schemaTranslate",
UnitsApi::sSchemaTranslate, sSchemaTranslate,
METH_VARARGS, METH_VARARGS,
"schemaTranslate(Quantity, int) -> tuple\n\n" "schemaTranslate(Quantity, int) -> tuple\n\n"
"Translate a quantity to a given schema"}, "Translate a quantity to a given schema"},
{"toNumber", {"toNumber",
UnitsApi::sToNumber, sToNumber,
METH_VARARGS, METH_VARARGS,
"toNumber(Quantity or float, [format='g', decimals=-1]) -> str\n\n" "toNumber(Quantity or float, [format='g', decimals=-1]) -> str\n\n"
"Convert a quantity or float to a string"}, "Convert a quantity or float to a string"},
@@ -86,30 +83,32 @@ PyObject* UnitsApi::sParseQuantity(PyObject* /*self*/, PyObject* args)
return nullptr; return nullptr;
} }
Quantity rtn; const std::string str {pstr};
std::string str(pstr);
PyMem_Free(pstr); PyMem_Free(pstr);
try { try {
rtn = Quantity::parse(str); return new QuantityPy(new Quantity(Quantity::parse(str)));
} }
catch (const Base::ParserError&) { catch (const ParserError&) {
PyErr_Format(PyExc_ValueError, "invalid unit expression \n"); PyErr_Format(PyExc_ValueError,
"invalid unit expression: '%s'\n",
std::string {pstr}.c_str());
return nullptr; return nullptr;
} }
return new QuantityPy(new Quantity(rtn));
} }
PyObject* UnitsApi::sListSchemas(PyObject* /*self*/, PyObject* args) PyObject* UnitsApi::sListSchemas(PyObject* /*self*/, PyObject* args)
{ {
auto names = UnitsApi::getNames();
const int num = static_cast<int>(names.size());
if (PyArg_ParseTuple(args, "")) { if (PyArg_ParseTuple(args, "")) {
int num = static_cast<int>(UnitSystem::NumUnitSystemTypes); Py::Tuple tuple {num};
Py::Tuple tuple(num);
for (int i = 0; i < num; i++) { auto addItem = [&, i {0}](const std::string& name) mutable {
const auto description { tuple.setItem(i++, Py::String {name.c_str()});
UnitsApi::getDescription(static_cast<UnitSystem>(i)).toStdString()}; };
tuple.setItem(i, Py::String(description.c_str()));
} std::for_each(names.begin(), names.end(), addItem);
return Py::new_reference_to(tuple); return Py::new_reference_to(tuple);
} }
@@ -117,14 +116,12 @@ PyObject* UnitsApi::sListSchemas(PyObject* /*self*/, PyObject* args)
PyErr_Clear(); PyErr_Clear();
int index {}; int index {};
if (PyArg_ParseTuple(args, "i", &index)) { if (PyArg_ParseTuple(args, "i", &index)) {
int num = static_cast<int>(UnitSystem::NumUnitSystemTypes);
if (index < 0 || index >= num) { if (index < 0 || index >= num) {
PyErr_SetString(PyExc_ValueError, "invalid schema value"); PyErr_SetString(PyExc_ValueError, "invalid schema value");
return nullptr; return nullptr;
} }
const auto description { const auto description = schemas->descriptions().at(index);
UnitsApi::getDescription(static_cast<UnitSystem>(index)).toStdString()};
return Py_BuildValue("s", description.c_str()); return Py_BuildValue("s", description.c_str());
} }
@@ -138,20 +135,21 @@ PyObject* UnitsApi::sGetSchema(PyObject* /*self*/, PyObject* args)
return nullptr; return nullptr;
} }
return Py_BuildValue("i", static_cast<int>(currentSystem)); return Py_BuildValue("i", count());
} }
PyObject* UnitsApi::sSetSchema(PyObject* /*self*/, PyObject* args) PyObject* UnitsApi::sSetSchema(PyObject* /*self*/, PyObject* args)
{ {
PyErr_Clear(); PyErr_Clear();
int index {}; int index {};
if (PyArg_ParseTuple(args, "i", &index)) { if (PyArg_ParseTuple(args, "i", &index) != 0) {
int num = static_cast<int>(UnitSystem::NumUnitSystemTypes);
if (index < 0 || index >= num) { if (index < 0 || index >= static_cast<int>(count())) {
PyErr_SetString(PyExc_ValueError, "invalid schema value"); PyErr_SetString(PyExc_ValueError, "invalid schema value");
return nullptr; return nullptr;
} }
setSchema(static_cast<UnitSystem>(index));
schemas->select(index);
} }
Py_Return; Py_Return;
} }
@@ -160,27 +158,26 @@ PyObject* UnitsApi::sSchemaTranslate(PyObject* /*self*/, PyObject* args)
{ {
PyObject* py {}; PyObject* py {};
int index {}; int index {};
if (!PyArg_ParseTuple(args, "O!i", &(QuantityPy::Type), &py, &index)) { if (!PyArg_ParseTuple(args, "O!i", &QuantityPy::Type, &py, &index)) {
return nullptr; return nullptr;
} }
Quantity quant; if (index < 0 || index >= static_cast<int>(count())) {
quant = *static_cast<Base::QuantityPy*>(py)->getQuantityPtr(); PyErr_SetString(PyExc_ValueError,
std::string {"invalid schema index:" + std::to_string(index)}.c_str());
std::unique_ptr<UnitsSchema> schema(createSchema(static_cast<UnitSystem>(index)));
if (!schema) {
PyErr_SetString(PyExc_ValueError, "invalid schema value");
return nullptr; return nullptr;
} }
const Quantity quant {*static_cast<QuantityPy*>(py)->getQuantityPtr()};
double factor {}; double factor {};
std::string uus; std::string unitStr;
std::string uss = schema->schemaTranslate(quant, factor, uus); const std::string unitStrLocalised = schemaTranslate(quant, factor, unitStr);
Py::Tuple res(3); Py::Tuple res {3};
res[0] = Py::String(uss, "utf-8"); res[0] = Py::String {unitStrLocalised, "utf-8"};
res[1] = Py::Float(factor); res[1] = Py::Float {factor};
res[2] = Py::String(uus, "utf-8"); res[2] = Py::String {unitStr, "utf-8"};
return Py::new_reference_to(res); return Py::new_reference_to(res);
} }

View File

@@ -1,49 +1,142 @@
/*************************************************************************** /************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> * * *
* * * This file is part of the FreeCAD CAx development system. *
* This file is part of the FreeCAD CAx development system. * * *
* * * This library is free software; you can redistribute it and/or *
* This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public *
* modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either *
* License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. *
* version 2 of the License, or (at your option) any later version. * * *
* * * This library is distributed in the hope that it will be useful, *
* This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. *
* GNU Library General Public License for more details. * * *
* * * You should have received a copy of the GNU Library General Public *
* You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, *
* License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, *
* write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA *
* Suite 330, Boston, MA 02111-1307, USA * * *
* * ************************************************************************/
***************************************************************************/
#include "PreCompiled.h"
#include "PreCompiled.h"
#ifdef __GNUC__ #include <iomanip>
#include <unistd.h> #include <sstream>
#endif #include <string>
#include <QLocale> #include <QLocale>
#include <QString> #include <QString>
#include "Quantity.h" #include "Quantity.h"
#include "UnitsSchema.h" #include "UnitsSchema.h"
#include "UnitsSchemasData.h"
using namespace Base; #include "UnitsSchemasSpecs.h"
#include "Exception.h"
std::string UnitsSchema::toLocale(const Base::Quantity& quant, #include "Quantity.h"
double factor,
const std::string& unitString) const using Base::UnitsSchema;
{ using Base::UnitsSchemaSpec;
QLocale Lc;
const QuantityFormat& format = quant.getFormat();
if (format.option != QuantityFormat::None) { UnitsSchema::UnitsSchema(UnitsSchemaSpec spec)
int opt = format.option; : spec {std::move(spec)}
Lc.setNumberOptions(static_cast<QLocale::NumberOptions>(opt)); {}
}
std::string UnitsSchema::translate(const Quantity& quant) const
QString Ln = Lc.toString((quant.getValue() / factor), format.toFormat(), format.precision); { // to satisfy GCC
return QStringLiteral("%1 %2").arg(Ln, QString::fromStdString(unitString)).toStdString(); 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<QLocale::NumberOptions>(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<int>(spec.num);
}

View File

@@ -24,78 +24,41 @@
#define BASE_UNITSSCHEMA_H #define BASE_UNITSSCHEMA_H
#include <string> #include <string>
#include <memory>
#include "UnitsSchemasSpecs.h"
#include "Base/Quantity.h"
namespace Base namespace Base
{ {
class Quantity; class Quantity;
/** Units systems */ /**
enum class UnitSystem * An individual schema object
{
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.
*/ */
class UnitsSchema class UnitsSchema
{ {
public: public:
UnitsSchema() = default; explicit UnitsSchema(UnitsSchemaSpec spec);
UnitsSchema(const UnitsSchema&) = default; UnitsSchema() = delete;
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()
{}
/// This method translates the quantity in a string as the user may expect it. [[nodiscard]] bool isMultiUnitLength() const;
virtual std::string [[nodiscard]] bool isMultiUnitAngle() const;
schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) = 0; [[nodiscard]] std::string getBasicLengthUnit() const;
[[nodiscard]] std::string getName() const;
[[nodiscard]] std::string getDescription() const;
[[nodiscard]] int getNum() const;
std::string std::string translate(const Quantity& quant) const;
toLocale(const Base::Quantity& quant, double factor, const std::string& unitString) 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) private:
virtual bool isMultiUnitLength() const [[nodiscard]] static std::string
{ toLocale(const Quantity& quant, double factor, const std::string& unitString);
return false;
}
// return true if this schema uses multiple units for angles (ex. DMS) UnitsSchemaSpec spec;
virtual bool isMultiUnitAngle() const
{
return false;
}
// return the basic length unit for this schema
virtual std::string getBasicLengthUnit() const
{
return {"mm"};
}
}; };
} // namespace Base
} // namespace Base
#endif // BASE_UNITSSCHEMA_H #endif // BASE_UNITSSCHEMA_H

View File

@@ -1,65 +0,0 @@
/***************************************************************************
* Copyright (c) 2016 Yorik van Havre <yorik@uncreated.net> *
* *
* 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 <algorithm>
#include <array>
#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<std::pair<Unit, std::pair<std::string, double>>, 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);
}

View File

@@ -1,48 +0,0 @@
/***************************************************************************
* Copyright (c) 2016 Yorik van Havre <yorik@uncreated.net> *
* *
* 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

View File

@@ -1,61 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* Copyright (c) 2020 Bernd Hahnebach <bernd@bimstatik.org> *
* *
* 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 <algorithm>
#include <array>
#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<std::pair<Unit, std::pair<std::string, double>>, 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);
}

View File

@@ -1,47 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* Copyright (c) 2020 Bernd Hahnebach <bernd@bimstatik.org> *
* *
* 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

View File

@@ -1,400 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* *
* 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 <cmath>
#include <sstream>
#endif
#ifdef __GNUC__
#include <unistd.h>
#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<int>(std::round(totalInches * static_cast<double>(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<int>(std::floor(ntot / (12 * minden)));
ntot = ntot - 12 * minden * feet;
// Compute the remaining number of whole inches
inches = static_cast<int>(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<int>(wholeDegrees);
int outMin = static_cast<int>(wholeMinutes);
int outSec = static_cast<int>(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);
}

View File

@@ -1,105 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* *
* 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

View File

@@ -1,671 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* *
* 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 <cmath>
#endif
#ifdef __GNUC__
#include <unistd.h>
#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);
}

View File

@@ -1,45 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* *
* 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

View File

@@ -1,634 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* *
* 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 <cmath>
#endif
#ifdef __GNUC__
#include <unistd.h>
#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);
}

View File

@@ -1,43 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* *
* 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

View File

@@ -1,72 +0,0 @@
/***************************************************************************
* Copyright (c) WandererFan <wandererfan@gmail.com> *
* *
* 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 <algorithm>
#include <array>
#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<std::pair<Unit, std::pair<std::string, double>>, 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);
}

View File

@@ -1,60 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* *
* 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 <algorithm>
#include <array>
#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<std::pair<Unit, std::pair<std::string, double>>, 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);
}

View File

@@ -1,45 +0,0 @@
/***************************************************************************
* Copyright (c) 2009 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
* *
* 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

145
src/Base/UnitsSchemas.cpp Normal file
View File

@@ -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 <algorithm>
#include <memory>
#include <string>
#include <vector>
#include <QCoreApplication>
#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<std::string> UnitsSchemas::getVec(const std::function<std::string(UnitsSchemaSpec)>& fn)
{
std::vector<std::string> vec;
std::transform(pack.specs.begin(), pack.specs.end(), std::back_inserter(vec), fn);
return vec;
}
std::vector<std::string> UnitsSchemas::names()
{
return getVec([](const UnitsSchemaSpec& spec) {
return spec.name;
});
}
std::vector<std::string> 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<UnitsSchema>(spec);
}
UnitsSchemaSpec UnitsSchemas::findSpec(const std::function<bool(UnitsSchemaSpec)>& 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;
});
}

77
src/Base/UnitsSchemas.h Normal file
View File

@@ -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 <functional>
#include <string>
#include <vector>
#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<std::string> names();
std::vector<std::string> 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<std::string> getVec(const std::function<std::string(UnitsSchemaSpec)>& fn);
UnitsSchemaSpec findSpec(const std::function<bool(UnitsSchemaSpec)>& fn);
void makeCurr(const UnitsSchemaSpec& spec);
UnitsSchemasDataPack pack;
std::unique_ptr<UnitsSchema> current {std::make_unique<UnitsSchema>(spec())};
std::size_t denominator;
std::size_t decimals;
};
} // namespace Base
#endif // SRC_BASE_UNITSSCHEMAS_H

749
src/Base/UnitsSchemasData.h Normal file
View File

@@ -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 <map>
#include <vector>
#include <QtGlobal>
#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 , "" , 1e6 }}},
{ "Volume", {{ 0 , "" , 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 , "" , 1e6 },
{ 0 , "km²" , 1e12 }}
},
{ "Volume", {
{ 1e3 , "mm³" , 1.0 },
{ 1e6 , "ml" , 1e3 },
{ 1e9 , "l" , 1e6 },
{ 0 , "" , 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 , "" , 1e6 },
{ 0 , "km²" , 1e12 }}
},
{ "Volume", {
{ 1e3 , "mm³" , 1.0 },
{ 1e6 , "ml" , 1e3 },
{ 1e9 , "l" , 1e6 },
{ 0 , "" , 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 , "" , 1e6 }}
},
{ "Volume", {
{ 0 , "" , 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.: 34-1/4″
*/
inline std::string toFractional(const double value)
{
constexpr auto inchPerFoot {12};
constexpr auto mmPerInch {25.4};
auto numFractUnits =
static_cast<std::size_t>(std::round(std::abs(value) / mmPerInch * defDenominator));
if (numFractUnits == 0) {
return "0";
}
const auto feet =
static_cast<std::size_t>(std::floor(numFractUnits / (inchPerFoot * defDenominator)));
numFractUnits = numFractUnits - (inchPerFoot * defDenominator * feet);
const auto inches = static_cast<std::size_t>(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<std::string> 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<int, double> {
const double whole = std::floor(total);
return {static_cast<int>(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<std::string, std::function<std::string(double)>> 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

View File

@@ -1,54 +1,69 @@
/*************************************************************************** /************************************************************************
* Copyright (c) 2023 WandererFan <wandererfan@gmail.com> * * *
* * * This file is part of the FreeCAD CAx development system. *
* This file is part of the FreeCAD CAx development system. * * *
* * * This library is free software; you can redistribute it and/or *
* This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public *
* modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either *
* License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. *
* version 2 of the License, or (at your option) any later version. * * *
* * * This library is distributed in the hope that it will be useful, *
* This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. *
* GNU Library General Public License for more details. * * *
* * * You should have received a copy of the GNU Library General Public *
* You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, *
* License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, *
* write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA *
* Suite 330, Boston, MA 02111-1307, USA * * *
* * ************************************************************************/
***************************************************************************/
#ifndef UNITSCHEMASPECS_H
/* Metric units schema intended for design of large objects #define UNITSCHEMASPECS_H
* Lengths are always in metres.
* Angles in degrees (use degree symbol) #include <map>
* Velocities in m/sec #include <string>
*/ #include <vector>
#include <functional>
#ifndef BASE_UNITSSCHEMAMETERS_H
#define BASE_UNITSSCHEMAMETERS_H namespace Base
{
#include "UnitsSchema.h"
namespace Base struct UnitTranslationSpec
{ {
double threshold {1};
/** std::string unitString;
* The UnitSchema class double factor {1};
*/ std::function<std::string(double)> fn {nullptr};
class UnitsSchemaMeterDecimal: public UnitsSchema };
{
public: struct UnitsSchemaSpec
std::string {
schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override; std::size_t num;
std::string name;
std::string getBasicLengthUnit() const override std::string basicLengthUnitStr;
{ bool isMultUnitLen {false};
return {"m"}; bool isMultUnitAngle {false};
} const char* description;
}; bool isDefault {false};
} // namespace Base /**
* Applicable spec is the first with threshold > value under test
#endif // BASE_UNITSSCHEMAMETRES_H * Special case: Threshold = 0 : default
* Special case: Factor = 0 : unitString contains name of special function to run
*/
std::map<std::string, std::vector<UnitTranslationSpec>> translationSpecs;
};
struct UnitsSchemasDataPack
{
std::vector<UnitsSchemaSpec> specs;
size_t defDecimals;
size_t defDenominator;
};
} // namespace Base
#endif // UNITSCHEMASPECS_H

View File

@@ -1072,12 +1072,12 @@ void Application::slotActiveDocument(const App::Document& Doc)
"User parameter:BaseApp/Preferences/Units"); "User parameter:BaseApp/Preferences/Units");
if (!hGrp->GetBool("IgnoreProjectSchema")) { if (!hGrp->GetBool("IgnoreProjectSchema")) {
int userSchema = Doc.UnitSystem.getValue(); int userSchema = Doc.UnitSystem.getValue();
Base::UnitsApi::setSchema(static_cast<Base::UnitSystem>(userSchema)); Base::UnitsApi::setSchema(userSchema);
getMainWindow()->setUserSchema(userSchema); getMainWindow()->setUserSchema(userSchema);
Application::Instance->onUpdate(); Application::Instance->onUpdate();
} }
else { // set up Unit system default 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())); Base::UnitsApi::setDecimals(hGrp->GetInt("Decimals", Base::UnitsApi::getDecimals()));
} }
signalActiveDocument(*doc->second); signalActiveDocument(*doc->second);

View File

@@ -83,11 +83,12 @@ DlgProjectInformationImp::DlgProjectInformationImp(App::Document* doc,
ui->lineEditCompany->setText(QString::fromUtf8(doc->Company.getValue())); ui->lineEditCompany->setText(QString::fromUtf8(doc->Company.getValue()));
// Load comboBox with unit systems // Load comboBox with unit systems
int num = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes); auto addDesc = [&, index {0}](const std::string& item) mutable {
for (int i = 0; i < num; i++) { ui->comboBox_unitSystem->addItem(QString::fromStdString(item), index++);
QString item = Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i)); };
ui->comboBox_unitSystem->addItem(item, i); const auto descriptions = Base::UnitsApi::getDescriptions();
} std::for_each(descriptions.begin(), descriptions.end(), addDesc);
ui->comboBox_unitSystem->setCurrentIndex(doc->UnitSystem.getValue()); ui->comboBox_unitSystem->setCurrentIndex(doc->UnitSystem.getValue());
// load comboBox with license names // load comboBox with license names

View File

@@ -51,12 +51,12 @@ DlgUnitsCalculator::DlgUnitsCalculator(QWidget* parent, Qt::WindowFlags fl)
ui->setupUi(this); ui->setupUi(this);
this->setAttribute(Qt::WA_DeleteOnClose); this->setAttribute(Qt::WA_DeleteOnClose);
ui->comboBoxScheme->addItem(QStringLiteral("Preference system"), static_cast<int>(-1)); ui->comboBoxScheme->addItem(QStringLiteral("Preference system"), -1);
int num = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes); auto addItem = [&, index {0}](const auto& item) mutable {
for (int i = 0; i < num; i++) { ui->comboBoxScheme->addItem(QString::fromStdString(item), index++);
QString item = Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i)); };
ui->comboBoxScheme->addItem(item, i); auto descriptions = Base::UnitsApi::getDescriptions();
} std::for_each(descriptions.begin(), descriptions.end(), addItem);
// clang-format off // clang-format off
connect(ui->unitsBox, qOverload<int>(&QComboBox::activated), connect(ui->unitsBox, qOverload<int>(&QComboBox::activated),
@@ -214,7 +214,7 @@ void DlgUnitsCalculator::onComboBoxSchemeActivated(int index)
{ {
int item = ui->comboBoxScheme->itemData(index).toInt(); int item = ui->comboBoxScheme->itemData(index).toInt();
if (item > 0) { if (item > 0) {
ui->quantitySpinBox->setSchema(static_cast<Base::UnitSystem>(item)); ui->quantitySpinBox->setSchema(item);
} }
else { else {
ui->quantitySpinBox->clearSchema(); ui->quantitySpinBox->clearSchema();

View File

@@ -65,6 +65,7 @@
#endif #endif
#endif #endif
#include <algorithm>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <App/Application.h> #include <App/Application.h>
@@ -179,13 +180,16 @@ public:
//create the action buttons //create the action buttons
auto* menu = new QMenu(this); auto* menu = new QMenu(this);
auto* actionGrp = new QActionGroup(menu); auto* actionGrp = new QActionGroup(menu);
int num = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes);
for (int i = 0; i < num; i++) { auto setAction = [&, index {0}](const std::string&) mutable {
QAction* action = menu->addAction(QStringLiteral("UnitSchema%1").arg(i)); QAction* action = menu->addAction(QStringLiteral("UnitSchema%1").arg(index));
actionGrp->addAction(action); actionGrp->addAction(action);
action->setCheckable(true); 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) { QObject::connect(actionGrp, &QActionGroup::triggered, this, [this](QAction* action) {
int userSchema = action->data().toInt(); int userSchema = action->data().toInt();
setUserSchema(userSchema); setUserSchema(userSchema);
@@ -236,7 +240,7 @@ public:
getWindowParameter()->SetInt("UserSchema", userSchema); getWindowParameter()->SetInt("UserSchema", userSchema);
unitChanged(); unitChanged();
Base::UnitsApi::setSchema(static_cast<Base::UnitSystem>(userSchema)); Base::UnitsApi::setSchema(userSchema);
// Update the main window to show the unit change // Update the main window to show the unit change
Gui::Application::Instance->onUpdate(); Gui::Application::Instance->onUpdate();
} }
@@ -261,12 +265,12 @@ private:
void retranslateUi() { void retranslateUi() {
auto actions = menu()->actions(); auto actions = menu()->actions();
int maxSchema = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes); auto addAction = [&, index {0}](const std::string& action)mutable {
assert(actions.size() <= maxSchema); actions[index++]->setText(QString::fromStdString(action));
for(int i = 0; i < maxSchema ; i++) };
{ auto descriptions = Base::UnitsApi::getDescriptions();
actions[i]->setText(Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i))); assert(actions.size() <= static_cast<qsizetype>(descriptions.size()));
} std::for_each(descriptions.begin(), descriptions.end(), addAction);
} }
}; };

View File

@@ -63,7 +63,8 @@
using namespace Gui; using namespace Gui;
using namespace Gui::Dialog; using namespace Gui::Dialog;
namespace fs = std::filesystem; namespace fs = std::filesystem;
using namespace Base; using Base::UnitsApi;
using Base::QuantityFormat;
/* TRANSLATOR Gui::Dialog::DlgSettingsGeneral */ /* TRANSLATOR Gui::Dialog::DlgSettingsGeneral */
@@ -117,14 +118,14 @@ DlgSettingsGeneral::DlgSettingsGeneral( QWidget* parent )
connect(ui->comboBox_UnitSystem, qOverload<int>(&QComboBox::currentIndexChanged), this, &DlgSettingsGeneral::onUnitSystemIndexChanged); connect(ui->comboBox_UnitSystem, qOverload<int>(&QComboBox::currentIndexChanged), this, &DlgSettingsGeneral::onUnitSystemIndexChanged);
ui->spinBoxDecimals->setMaximum(std::numeric_limits<double>::digits10 + 1); ui->spinBoxDecimals->setMaximum(std::numeric_limits<double>::digits10 + 1);
int num = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes); auto addItem = [&, index {0}](const std::string& item) mutable {
for (int i = 0; i < num; i++) { ui->comboBox_UnitSystem->addItem(QString::fromStdString(item), index++);
QString item = Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i)); };
ui->comboBox_UnitSystem->addItem(item, i); auto descriptions = UnitsApi::getDescriptions();
} std::for_each(descriptions.begin(), descriptions.end(), addItem);
// Enable/disable the fractional inch option depending on system // 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->comboBox_FracInch->setVisible(visible);
ui->fractionalInchLabel->setVisible(visible); ui->fractionalInchLabel->setVisible(visible);
} }
@@ -204,7 +205,7 @@ void DlgSettingsGeneral::saveUnitSystemSettings()
hGrpu->SetBool("IgnoreProjectSchema", ui->checkBox_projectUnitSystemIgnore->isChecked()); hGrpu->SetBool("IgnoreProjectSchema", ui->checkBox_projectUnitSystemIgnore->isChecked());
// Set actual value // Set actual value
Base::UnitsApi::setDecimals(ui->spinBoxDecimals->value()); UnitsApi::setDecimals(ui->spinBoxDecimals->value());
// Convert the combobox index to the its integer denominator. Currently // Convert the combobox index to the its integer denominator. Currently
// with 1/2, 1/4, through 1/128, this little equation directly computes the // 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); hGrpu->SetInt("FracInch", FracInch);
// Set the actual format value // Set the actual format value
Base::QuantityFormat::setDefaultDenominator(FracInch); QuantityFormat::setDefaultDenominator(FracInch);
// Set and save the Unit System // Set and save the Unit System
if (ui->checkBox_projectUnitSystemIgnore->isChecked()) { if (ui->checkBox_projectUnitSystemIgnore->isChecked()) {
// currently selected View System (unit system) // currently selected View System (unit system)
int viewSystemIndex = ui->comboBox_UnitSystem->currentIndex(); int viewSystemIndex = ui->comboBox_UnitSystem->currentIndex();
UnitsApi::setSchema(static_cast<UnitSystem>(viewSystemIndex)); UnitsApi::setSchema(viewSystemIndex);
} }
else if (App::Document* doc = App::GetApplication().getActiveDocument()) { else if (App::Document* doc = App::GetApplication().getActiveDocument()) {
UnitsApi::setSchema(static_cast<UnitSystem>(doc->UnitSystem.getValue())); UnitsApi::setSchema(doc->UnitSystem.getValue());
} }
else { else {
// if there is no existing document then the unit must still be set // if there is no existing document then the unit must still be set
int viewSystemIndex = ui->comboBox_UnitSystem->currentIndex(); int viewSystemIndex = ui->comboBox_UnitSystem->currentIndex();
UnitsApi::setSchema(static_cast<UnitSystem>(viewSystemIndex)); UnitsApi::setSchema(viewSystemIndex);
} }
ui->SubstituteDecimal->onSave(); ui->SubstituteDecimal->onSave();
@@ -287,11 +288,11 @@ void DlgSettingsGeneral::loadSettings()
ParameterGrp::handle hGrpu = App::GetApplication().GetParameterGroupByPath ParameterGrp::handle hGrpu = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Units"); ("User parameter:BaseApp/Preferences/Units");
ui->comboBox_UnitSystem->setCurrentIndex(hGrpu->GetInt("UserSchema", 0)); 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)); ui->checkBox_projectUnitSystemIgnore->setChecked(hGrpu->GetBool("IgnoreProjectSchema", false));
// Get the current user setting for the minimum fractional inch // 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 // Convert fractional inch to the corresponding combobox index using this
// handy little equation. // handy little equation.
@@ -529,11 +530,11 @@ void DlgSettingsGeneral::translateIconSizes()
void DlgSettingsGeneral::retranslateUnits() void DlgSettingsGeneral::retranslateUnits()
{ {
int num = ui->comboBox_UnitSystem->count(); auto setItem = [&, index {0}](const std::string& item) mutable {
for (int i = 0; i < num; i++) { ui->comboBox_UnitSystem->setItemText(index++, QString::fromStdString(item));
QString item = Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i)); };
ui->comboBox_UnitSystem->setItemText(i, item); const auto descriptions = UnitsApi::getDescriptions();
} std::for_each(descriptions.begin(), descriptions.end(), setItem);
} }
void DlgSettingsGeneral::changeEvent(QEvent *event) 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) if (index < 0) {
return; // happens when clearing the combo box in retranslateUi() return; // happens when clearing the combo box in retranslateUi()
}
// Enable/disable the fractional inch option depending on system // Enable/disable the fractional inch option depending on system
const auto visible = (static_cast<UnitSystem>(index) == UnitSystem::ImperialBuilding); const auto visible = UnitsApi::isMultiUnitLength();
ui->comboBox_FracInch->setVisible(visible); ui->comboBox_FracInch->setVisible(visible);
ui->fractionalInchLabel->setVisible(visible); ui->fractionalInchLabel->setVisible(visible);
} }

View File

@@ -45,6 +45,7 @@
#include <Base/Exception.h> #include <Base/Exception.h>
#include <Base/UnitsApi.h> #include <Base/UnitsApi.h>
#include <Base/Tools.h> #include <Base/Tools.h>
#include <Base/UnitsSchema.h>
#include "QuantitySpinBox.h" #include "QuantitySpinBox.h"
#include "QuantitySpinBox_p.h" #include "QuantitySpinBox_p.h"
@@ -714,7 +715,7 @@ void QuantitySpinBox::setDecimals(int v)
updateText(d->quantity); updateText(d->quantity);
} }
void QuantitySpinBox::setSchema(const Base::UnitSystem& s) void QuantitySpinBox::setSchema(const int s)
{ {
Q_D(QuantitySpinBox); Q_D(QuantitySpinBox);
d->scheme = Base::UnitsApi::createSchema(s); d->scheme = Base::UnitsApi::createSchema(s);
@@ -732,7 +733,7 @@ QString QuantitySpinBox::getUserString(const Base::Quantity& val, double& factor
{ {
Q_D(const QuantitySpinBox); Q_D(const QuantitySpinBox);
std::string unitStr; 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); : val.getUserString(factor, unitStr);
unitString = QString::fromStdString(unitStr); unitString = QString::fromStdString(unitStr);
return QString::fromStdString(str); return QString::fromStdString(str);

View File

@@ -24,7 +24,6 @@
#ifndef GUI_QUANTITYSPINBOX_H #ifndef GUI_QUANTITYSPINBOX_H
#define GUI_QUANTITYSPINBOX_H #define GUI_QUANTITYSPINBOX_H
#include <Base/UnitsSchema.h>
#include <Gui/MetaTypes.h> #include <Gui/MetaTypes.h>
#include <Gui/SpinBox.h> #include <Gui/SpinBox.h>
@@ -99,7 +98,7 @@ public:
/// Sets a specific unit schema to handle quantities. /// Sets a specific unit schema to handle quantities.
/// The system-wide schema won't be used any more. /// 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. /// Clears the schemaand again use the system-wide schema.
void clearSchema(); void clearSchema();

View File

@@ -841,7 +841,7 @@ QString getPreselectionInfo(const char* documentName,
{ {
auto pts = schemaTranslatePoint(x, y, z, precision); auto pts = schemaTranslatePoint(x, y, z, precision);
int numberDecimals = std::min(6, Base::UnitsApi::getDecimals()); int numberDecimals = std::min(6, static_cast<int>(Base::UnitsApi::getDecimals()));
QString message = QStringLiteral("Preselected: %1.%2.%3 (%4 %5, %6 %7, %8 %9)") QString message = QStringLiteral("Preselected: %1.%2.%3 (%4 %5, %6 %7, %8 %9)")
.arg(QString::fromUtf8(documentName)) .arg(QString::fromUtf8(documentName))

View File

@@ -33,6 +33,7 @@
#include <QWidget> #include <QWidget>
#endif #endif
#include <algorithm>
#include "GeneralSettingsWidget.h" #include "GeneralSettingsWidget.h"
#include <gsl/pointers> #include <gsl/pointers>
#include <App/Application.h> #include <App/Application.h>
@@ -182,7 +183,7 @@ void GeneralSettingsWidget::onUnitSystemChanged(int index)
if (index < 0) { if (index < 0) {
return; // happens when clearing the combo box in retranslateUi() return; // happens when clearing the combo box in retranslateUi()
} }
Base::UnitsApi::setSchema(static_cast<Base::UnitSystem>(index)); Base::UnitsApi::setSchema(index);
ParameterGrp::handle hGrp = ParameterGrp::handle hGrp =
App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units"); App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units");
hGrp->SetInt("UserSchema", index); hGrp->SetInt("UserSchema", index);
@@ -213,15 +214,16 @@ void GeneralSettingsWidget::retranslateUi()
_unitSystemLabel->setText(createLabelText(tr("Unit System"))); _unitSystemLabel->setText(createLabelText(tr("Unit System")));
_unitSystemComboBox->clear(); _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"); App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Units");
auto userSchema = hGrpUnits->GetInt("UserSchema", 0); _unitSystemComboBox->setCurrentIndex(static_cast<int>(hGrpUnits->GetInt("UserSchema", 0)));
int num = static_cast<int>(Base::UnitSystem::NumUnitSystemTypes);
for (int i = 0; i < num; i++) {
QString item = Base::UnitsApi::getDescription(static_cast<Base::UnitSystem>(i));
_unitSystemComboBox->addItem(item, i);
}
_unitSystemComboBox->setCurrentIndex(userSchema);
_navigationStyleLabel->setText(createLabelText(tr("Navigation Style"))); _navigationStyleLabel->setText(createLabelText(tr("Navigation Style")));
_navigationStyleComboBox->clear(); _navigationStyleComboBox->clear();

View File

@@ -15,6 +15,7 @@ target_sources(Tests_run PRIVATE
Quantity.cpp Quantity.cpp
Reader.cpp Reader.cpp
Rotation.cpp Rotation.cpp
SchemaTests.cpp
ServiceProvider.cpp ServiceProvider.cpp
Stream.cpp Stream.cpp
TimeInfo.cpp TimeInfo.cpp

View File

@@ -1,16 +1,18 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <Base/Exception.h> #include <Base/Exception.h>
#include <Base/Quantity.h> #include <Base/Quantity.h>
#include <Base/UnitsApi.h>
#include <Base/UnitsSchemaImperial1.h>
#include <QLocale> #include <QLocale>
#include <boost/core/ignore_unused.hpp>
// NOLINTBEGIN using Base::ParserError;
using Base::Quantity;
using Base::Unit;
using Base::UnitsMismatchError;
TEST(BaseQuantity, TestValid) TEST(BaseQuantity, TestValid)
{ {
Base::Quantity q1 {1.0, Base::Unit::Length}; const Quantity q1 {1.0, Unit::Length};
Base::Quantity q2 {1.0, Base::Unit::Area}; Quantity q2 {1.0, Unit::Area};
q2.setInvalid(); q2.setInvalid();
EXPECT_EQ(q1.isValid(), true); EXPECT_EQ(q1.isValid(), true);
@@ -19,77 +21,87 @@ TEST(BaseQuantity, TestValid)
TEST(BaseQuantity, TestParse) TEST(BaseQuantity, TestParse)
{ {
Base::Quantity q1 = Base::Quantity::parse("1,234 kg"); const Quantity q1 = Quantity::parse("1,234 kg");
constexpr auto val {1.2340};
EXPECT_EQ(q1, Base::Quantity(1.2340, Base::Unit::Mass)); EXPECT_EQ(q1, Quantity(val, Unit::Mass));
EXPECT_THROW(boost::ignore_unused(Base::Quantity::parse("1,234,500.12 kg")), Base::ParserError); EXPECT_THROW(auto rew [[maybe_unused]] = Quantity::parse("1,234,500.12 kg"), ParserError);
} }
TEST(BaseQuantity, TestDim) TEST(BaseQuantity, TestDim)
{ {
Base::Quantity q1 {0, Base::Unit::Area}; const Quantity q1 {0, Unit::Area};
EXPECT_EQ(q1.isQuantity(), true); EXPECT_EQ(q1.isQuantity(), true);
} }
TEST(BaseQuantity, TestNoDim) 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); EXPECT_EQ(q1.isDimensionless(), true);
} }
TEST(BaseQuantity, TestPowEQ1) TEST(BaseQuantity, TestPowEQ1)
{ {
Base::Quantity q1 {2, Base::Unit::Area}; const Quantity q1 {2, Unit::Area};
EXPECT_EQ(q1.pow(1), Base::Quantity(2, Base::Unit::Area)); const auto expect = Quantity {2, Unit::Area};
EXPECT_EQ(q1.pow(1), expect);
} }
TEST(BaseQuantity, TestPowEQ0) TEST(BaseQuantity, TestPowEQ0)
{ {
Base::Quantity q1 {2, Base::Unit::Area}; const Quantity q1 {2, Unit::Area};
EXPECT_EQ(q1.pow(0), Base::Quantity {1}); EXPECT_EQ(q1.pow(0), Quantity {1});
} }
TEST(BaseQuantity, TestPowGT1) TEST(BaseQuantity, TestPowGT1)
{ {
Base::Quantity q1 {2, Base::Unit::Length}; constexpr auto v2 {2};
EXPECT_EQ(q1.pow(2), Base::Quantity(4, Base::Unit::Area)); constexpr auto v4 {4};
const Quantity q1 {v2, Unit::Length};
EXPECT_EQ(q1.pow(v2), Quantity(v4, Unit::Area));
} }
TEST(BaseQuantity, TestPowLT1) TEST(BaseQuantity, TestPowLT1)
{ {
Base::Quantity q1 {8, Base::Unit::Volume}; constexpr auto v8 {8};
EXPECT_EQ(q1.pow(1.0 / 3.0), Base::Quantity(2, Base::Unit::Length)); 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) TEST(BaseQuantity, TestPow3DIV2)
{ {
Base::Quantity unit {8, Base::Unit::Volume}; constexpr auto v2 {2.0};
EXPECT_THROW(unit.pow(3.0 / 2.0), Base::UnitsMismatchError); 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) TEST(BaseQuantity, TestString)
{ {
Base::Quantity q1 {2, "kg*m/s^2"}; constexpr auto v2 {2};
EXPECT_EQ(q1.getUnit(), Base::Unit::Force); const Quantity q1 {v2, "kg*m/s^2"};
EXPECT_EQ(q1.getUnit(), Unit::Force);
Base::Quantity q2 {2, "kg*m^2/s^2"}; const Quantity q2 {v2, "kg*m^2/s^2"};
EXPECT_EQ(q2.getUnit(), Base::Unit::Work); EXPECT_EQ(q2.getUnit(), Unit::Work);
} }
TEST(BaseQuantity, TestCopy) 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) TEST(BaseQuantity, TestEqual)
{ {
Base::Quantity q1 {1.0, Base::Unit::Force}; const Quantity q1 {1.0, Unit::Force};
Base::Quantity q2 {1.0, "kg*mm/s^2"}; const Quantity q2 {1.0, "kg*mm/s^2"};
EXPECT_EQ(q1 == q1, true); EXPECT_EQ(q1 == q1, true);
EXPECT_EQ(q1 == q2, true); EXPECT_EQ(q1 == q2, true);
@@ -97,9 +109,10 @@ TEST(BaseQuantity, TestEqual)
TEST(BaseQuantity, TestNotEqual) TEST(BaseQuantity, TestNotEqual)
{ {
Base::Quantity q1 {1.0, Base::Unit::Force}; constexpr auto v2 {2.0};
Base::Quantity q2 {2.0, "kg*m/s^2"}; const Quantity q1 {1.0, Unit::Force};
Base::Quantity q3 {1.0, Base::Unit::Work}; const Quantity q2 {v2, "kg*m/s^2"};
const Quantity q3 {1.0, Unit::Work};
EXPECT_EQ(q1 != q2, true); EXPECT_EQ(q1 != q2, true);
EXPECT_EQ(q1 != q3, true); EXPECT_EQ(q1 != q3, true);
@@ -107,73 +120,77 @@ TEST(BaseQuantity, TestNotEqual)
TEST(BaseQuantity, TestLessOrGreater) TEST(BaseQuantity, TestLessOrGreater)
{ {
Base::Quantity q1 {1.0, Base::Unit::Force}; constexpr auto v2 {2.0};
Base::Quantity q2 {2.0, "kg*m/s^2"}; Quantity q1 {1.0, Unit::Force};
Base::Quantity q3 {2.0, Base::Unit::Work}; Quantity q2 {v2, "kg*m/s^2"};
Quantity q3 {v2, Unit::Work};
EXPECT_EQ(q1 < q2, true); EXPECT_EQ(q1 < q2, true);
EXPECT_EQ(q1 > q2, false); EXPECT_EQ(q1 > q2, false);
EXPECT_EQ(q1 <= q1, true); EXPECT_EQ(q1 <= q1, true);
EXPECT_EQ(q1 >= q1, true); EXPECT_EQ(q1 >= q1, true);
EXPECT_THROW(boost::ignore_unused(q1 < q3), Base::UnitsMismatchError); EXPECT_THROW(auto res [[maybe_unused]] = (q1 < q3), UnitsMismatchError);
EXPECT_THROW(boost::ignore_unused(q1 > q3), Base::UnitsMismatchError); EXPECT_THROW(auto res [[maybe_unused]] = (q1 > q3), UnitsMismatchError);
EXPECT_THROW(boost::ignore_unused(q1 <= q3), Base::UnitsMismatchError); EXPECT_THROW(auto res [[maybe_unused]] = (q1 <= q3), UnitsMismatchError);
EXPECT_THROW(boost::ignore_unused(q1 >= q3), Base::UnitsMismatchError); EXPECT_THROW(auto res [[maybe_unused]] = (q1 >= q3), UnitsMismatchError);
} }
TEST(BaseQuantity, TestAdd) TEST(BaseQuantity, TestAdd)
{ {
Base::Quantity q1 {1.0, Base::Unit::Length}; Quantity q1 {1.0, Unit::Length};
Base::Quantity q2 {1.0, Base::Unit::Area}; Quantity q2 {1.0, Unit::Area};
EXPECT_THROW(q1 + q2, Base::UnitsMismatchError); EXPECT_THROW(q1 + q2, UnitsMismatchError);
EXPECT_THROW(q1 += q2, Base::UnitsMismatchError); EXPECT_THROW(q1 += q2, UnitsMismatchError);
EXPECT_EQ(q1 + q1, Base::Quantity(2, Base::Unit::Length)); EXPECT_EQ(q1 + q1, Quantity(2, Unit::Length));
EXPECT_EQ(q1 += q1, Base::Quantity(2, Base::Unit::Length)); EXPECT_EQ(q1 += q1, Quantity(2, Unit::Length));
} }
TEST(BaseQuantity, TestSub) TEST(BaseQuantity, TestSub)
{ {
Base::Quantity q1 {1.0, Base::Unit::Length}; Quantity q1 {1.0, Unit::Length};
Base::Quantity q2 {1.0, Base::Unit::Area}; Quantity q2 {1.0, Unit::Area};
EXPECT_THROW(q1 - q2, Base::UnitsMismatchError); EXPECT_THROW(q1 - q2, UnitsMismatchError);
EXPECT_THROW(q1 -= q2, Base::UnitsMismatchError); EXPECT_THROW(q1 -= q2, UnitsMismatchError);
EXPECT_EQ(q1 - q1, Base::Quantity(0, Base::Unit::Length)); EXPECT_EQ(q1 - q1, Quantity(0, Unit::Length));
EXPECT_EQ(q1 -= q1, Base::Quantity(0, Base::Unit::Length)); EXPECT_EQ(q1 -= q1, Quantity(0, Unit::Length));
} }
TEST(BaseQuantity, TestNeg) TEST(BaseQuantity, TestNeg)
{ {
Base::Quantity q1 {1.0, Base::Unit::Length}; const Quantity q1 {1.0, Unit::Length};
EXPECT_EQ(-q1, Base::Quantity(-1.0, Base::Unit::Length)); EXPECT_EQ(-q1, Quantity(-1.0, Unit::Length));
} }
TEST(BaseQuantity, TestMult) TEST(BaseQuantity, TestMult)
{ {
Base::Quantity q1 {1.0, Base::Unit::Length}; const Quantity q1 {1.0, Unit::Length};
Base::Quantity q2 {1.0, Base::Unit::Area}; const Quantity q2 {1.0, Unit::Area};
EXPECT_EQ(q1 * q2, Base::Quantity(1.0, Base::Unit::Volume)); EXPECT_EQ(q1 * q2, Quantity(1.0, Unit::Volume));
EXPECT_EQ(q1 * 2.0, Base::Quantity(2.0, Base::Unit::Length)); EXPECT_EQ(q1 * 2.0, Quantity(2.0, Unit::Length));
} }
TEST(BaseQuantity, TestDiv) TEST(BaseQuantity, TestDiv)
{ {
Base::Quantity q1 {1.0, Base::Unit::Length}; const Quantity q1 {1.0, Unit::Length};
Base::Quantity q2 {1.0, Base::Unit::Area}; const Quantity q2 {1.0, Unit::Area};
EXPECT_EQ(q1 / q2, Base::Quantity(1.0, Base::Unit::InverseLength)); EXPECT_EQ(q1 / q2, Quantity(1.0, Unit::InverseLength));
EXPECT_EQ(q1 / 2.0, Base::Quantity(0.5, Base::Unit::Length)); EXPECT_EQ(q1 / 2.0, Quantity(0.5, Unit::Length));
} }
TEST(BaseQuantity, TestPow) TEST(BaseQuantity, TestPow)
{ {
Base::Quantity q1 {2.0, Base::Unit::Length}; constexpr auto v2 {2.0};
Base::Quantity q2 {2.0, Base::Unit::Area}; constexpr auto v4 {4};
Base::Quantity q3 {0.0};
EXPECT_EQ(q1.pow(q3), Base::Quantity {1}); Quantity q1 {v2, Unit::Length};
EXPECT_EQ(q1.pow(2.0), Base::Quantity(4, Base::Unit::Area)); Quantity q2 {v2, Unit::Area};
EXPECT_THROW(q1.pow(q2), Base::UnitsMismatchError); 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: protected:
void SetUp() override 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}; const auto qParsed = Quantity::parse("1 psi");
EXPECT_EQ(qParsed.getValue(), 6.8947448254939996);
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");
} }
TEST_F(Quantity, TestSchemeImperialOne) TEST_F(BaseQuantityLoc, psi_parse_no_space)
{ {
Base::Quantity quantity {1.0, Base::Unit::Length}; const auto qParsed = Quantity::parse("1psi");
EXPECT_EQ(qParsed.getValue(), 6.8947448254939996);
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");
} }
TEST_F(Quantity, TestSafeUserString) TEST_F(BaseQuantityLoc, psi_parse_user_str)
{ {
Base::UnitsApi::setSchema(Base::UnitSystem::ImperialDecimal); const auto qParsed = Quantity::parse("1 psi");
EXPECT_EQ(qParsed.getUserString(), "6894.74 Pa");
Base::Quantity quantity {1.0, Base::Unit::Length}; }
Base::QuantityFormat format = quantity.getFormat();
format.precision = 1; TEST_F(BaseQuantityLoc, psi_parse_safe_user_str)
quantity.setFormat(format); {
const auto qParsed = Quantity::parse("1 psi");
std::string result = quantity.getSafeUserString(); EXPECT_EQ(qParsed.getSafeUserString(), "6894.74 Pa");
}
EXPECT_EQ(result, "1 mm");
TEST_F(BaseQuantityLoc, psi_parse_unit_type)
Base::UnitsApi::setSchema(Base::UnitSystem::Imperial1); {
const auto qParsed = Quantity::parse("1 psi");
quantity = Base::Quantity {304.8, Base::Unit::Length}; EXPECT_EQ(qParsed.getUnit().getTypeString(), "Pressure");
quantity.setFormat(format); }
result = quantity.getSafeUserString(); TEST_F(BaseQuantityLoc, psi_to_Pa)
{
EXPECT_EQ(result, "1.0 \\'"); const auto result = Quantity::parse("1 psi").getValueAs(Quantity::Pascal);
const auto expect = 6894.7448254939991;
quantity = Base::Quantity {25.4, Base::Unit::Length};
quantity.setFormat(format); EXPECT_EQ(result, expect);
}
result = quantity.getSafeUserString();
TEST_F(BaseQuantityLoc, psi_to_KPa)
EXPECT_EQ(result, "1.0 \\\""); {
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

View File

@@ -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 <gtest/gtest.h>
#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 <QLocale>
#include <string>
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<UnitsSchemas> 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 {"12-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 {"-12-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°636″"};
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°636″"};
EXPECT_EQ(result, expect);
}
TEST_F(SchemaTest, unknown_schema_name_throws)
{
EXPECT_THROW(UnitsApi::setSchema("Unknown"), RuntimeError);
}

View File

@@ -130,7 +130,7 @@ TEST_F(TestMaterialValue, TestQuantityType)
EXPECT_EQ(variant.toString().size(), 0); EXPECT_EQ(variant.toString().size(), 0);
auto quantity = variant.value<Base::Quantity>(); auto quantity = variant.value<Base::Quantity>();
EXPECT_FALSE(quantity.isValid()); EXPECT_FALSE(quantity.isValid());
EXPECT_EQ(quantity.getUserString(), "nan "); EXPECT_EQ(quantity.getUserString(), "nan");
EXPECT_TRUE(std::isnan(quantity.getValue())); EXPECT_TRUE(std::isnan(quantity.getValue()));
// Test a copy // Test a copy
@@ -146,7 +146,7 @@ TEST_F(TestMaterialValue, TestQuantityType)
EXPECT_EQ(variant.toString().size(), 0); EXPECT_EQ(variant.toString().size(), 0);
quantity = variant.value<Base::Quantity>(); quantity = variant.value<Base::Quantity>();
EXPECT_FALSE(quantity.isValid()); EXPECT_FALSE(quantity.isValid());
EXPECT_EQ(quantity.getUserString(), "nan "); EXPECT_EQ(quantity.getUserString(), "nan");
EXPECT_TRUE(std::isnan(quantity.getValue())); EXPECT_TRUE(std::isnan(quantity.getValue()));
} }