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

View File

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

View File

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

View File

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

View File

@@ -20,124 +20,91 @@
* *
***************************************************************************/
#include "PreCompiled.h"
#include <sstream>
#ifndef _PreComp_
#include <iomanip>
#include <memory>
#include <sstream>
#endif
#include <CXX/WrapPython.h>
#include <fmt/format.h>
#include <QString>
#include "Exception.h"
#include "UnitsApi.h"
#include "UnitsSchemaCentimeters.h"
#include "UnitsSchemaInternal.h"
#include "UnitsSchemaImperial1.h"
#include "UnitsSchemaMKS.h"
#include "UnitsSchemaMmMin.h"
#include "UnitsSchemaFemMilliMeterNewton.h"
#include "UnitsSchemaMeterDecimal.h"
#include "UnitsSchema.h"
#include "UnitsSchemas.h"
#include "UnitsSchemasData.h"
using namespace Base;
using Base::UnitsApi;
using Base::UnitsSchema;
using Base::UnitsSchemas;
// === static attributes ================================================
UnitsSchemaPtr UnitsApi::UserPrefSystem(new UnitsSchemaInternal());
UnitSystem UnitsApi::currentSystem = UnitSystem::SI1;
int UnitsApi::UserPrefDecimals = 2;
QString UnitsApi::getDescription(UnitSystem system)
void UnitsApi::init()
{
switch (system) {
case UnitSystem::SI1:
return tr("Standard (mm, kg, s, °)");
case UnitSystem::SI2:
return tr("MKS (m, kg, s, °)");
case UnitSystem::Imperial1:
return tr("US customary (in, lb)");
case UnitSystem::ImperialDecimal:
return tr("Imperial decimal (in, lb)");
case UnitSystem::Centimeters:
return tr("Building Euro (cm, m², m³)");
case UnitSystem::ImperialBuilding:
return tr("Building US (ft-in, sqft, cft)");
case UnitSystem::MmMin:
return tr("Metric small parts & CNC (mm, mm/min)");
case UnitSystem::ImperialCivil:
return tr("Imperial for Civil Eng (ft, ft/s)");
case UnitSystem::FemMilliMeterNewton:
return tr("FEM (mm, N, s)");
case UnitSystem::MeterDecimal:
return tr("Meter decimal (m, m², m³)");
default:
return tr("Unknown schema");
}
schemas = std::make_unique<UnitsSchemas>(UnitsSchemasData::unitSchemasDataPack);
}
UnitsSchemaPtr UnitsApi::createSchema(UnitSystem system)
std::vector<std::string> UnitsApi::getDescriptions()
{
switch (system) {
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;
return schemas->descriptions();
}
void UnitsApi::setSchema(UnitSystem system)
std::vector<std::string> UnitsApi::getNames()
{
if (UserPrefSystem) {
UserPrefSystem->resetSchemaUnits(); // for schemas changed the Quantity constants
}
UserPrefSystem = createSchema(system);
currentSystem = system;
// for wrong value fall back to standard schema
if (!UserPrefSystem) {
UserPrefSystem = std::make_unique<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).
return schemas->names();
}
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());
}
std::string UnitsApi::toNumber(const Base::Quantity& quantity, const QuantityFormat& format)
std::string UnitsApi::toNumber(const Quantity& quantity, const QuantityFormat& format)
{
return toNumber(quantity.getValue(), format);
}
std::string UnitsApi::toNumber(double value, const QuantityFormat& format)
std::string UnitsApi::toNumber(const double value, const QuantityFormat& format)
{
std::stringstream ss;
@@ -156,31 +123,6 @@ std::string UnitsApi::toNumber(double value, const QuantityFormat& format)
return ss.str();
}
// return true if the current user schema uses multiple units for length (ex. Ft/In)
bool UnitsApi::isMultiUnitLength()
{
return UserPrefSystem->isMultiUnitLength();
}
// return true if the current user schema uses multiple units for angles (ex. DMS)
bool UnitsApi::isMultiUnitAngle()
{
return UserPrefSystem->isMultiUnitAngle();
}
std::string UnitsApi::getBasicLengthUnit()
{
return UserPrefSystem->getBasicLengthUnit();
}
// === static translation methods ==========================================
std::string
UnitsApi::schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString)
{
return UserPrefSystem->schemaTranslate(quant, factor, unitString);
}
double UnitsApi::toDouble(PyObject* args, const Base::Unit& u)
{
if (PyUnicode_Check(args)) {
@@ -203,34 +145,30 @@ double UnitsApi::toDouble(PyObject* args, const Base::Unit& u)
throw Base::UnitsMismatchError("Wrong parameter type!");
}
Quantity UnitsApi::toQuantity(PyObject* args, const Base::Unit& u)
std::string
UnitsApi::schemaTranslate(const Quantity& quant, double& factor, std::string& unitString)
{
double d {};
if (PyUnicode_Check(args)) {
std::string str(PyUnicode_AsUTF8(args));
// Parse the string
Quantity q = Quantity::parse(str);
d = q.getValue();
}
else if (PyFloat_Check(args)) {
d = PyFloat_AsDouble(args);
}
else if (PyLong_Check(args)) {
d = static_cast<double>(PyLong_AsLong(args));
}
else {
throw Base::UnitsMismatchError("Wrong parameter type!");
}
return Quantity(d, u);
return schemas->currentSchema()->translate(quant, factor, unitString);
}
void UnitsApi::setDecimals(int prec)
std::string UnitsApi::schemaTranslate(const Quantity& quant)
{
UserPrefDecimals = prec;
double dummy1 {}; // to satisfy GCC
std::string dummy2;
return schemas->currentSchema()->translate(quant, dummy1, dummy2);
}
int UnitsApi::getDecimals()
void UnitsApi::setDecimals(const std::size_t prec)
{
return UserPrefDecimals;
decimals = prec;
}
size_t UnitsApi::getDecimals()
{
return decimals;
}
size_t UnitsApi::getDefDecimals()
{
return schemas->getDecimals();
}

View File

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

View File

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

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 library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifdef __GNUC__
#include <unistd.h>
#endif
#include <QLocale>
#include <QString>
#include "Quantity.h"
#include "UnitsSchema.h"
using namespace Base;
std::string UnitsSchema::toLocale(const Base::Quantity& quant,
double factor,
const std::string& unitString) const
{
QLocale Lc;
const QuantityFormat& format = quant.getFormat();
if (format.option != QuantityFormat::None) {
int opt = format.option;
Lc.setNumberOptions(static_cast<QLocale::NumberOptions>(opt));
}
QString Ln = Lc.toString((quant.getValue() / factor), format.toFormat(), format.precision);
return QStringLiteral("%1 %2").arg(Ln, QString::fromStdString(unitString)).toStdString();
}
/************************************************************************
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
************************************************************************/
#include "PreCompiled.h"
#include <iomanip>
#include <sstream>
#include <string>
#include <QLocale>
#include <QString>
#include "Quantity.h"
#include "UnitsSchema.h"
#include "UnitsSchemasData.h"
#include "UnitsSchemasSpecs.h"
#include "Exception.h"
#include "Quantity.h"
using Base::UnitsSchema;
using Base::UnitsSchemaSpec;
UnitsSchema::UnitsSchema(UnitsSchemaSpec spec)
: spec {std::move(spec)}
{}
std::string UnitsSchema::translate(const Quantity& quant) const
{ // to satisfy GCC
double dummy1 {};
std::string dummy2;
return translate(quant, dummy1, dummy2);
}
std::string
UnitsSchema::translate(const Quantity& quant, double& factor, std::string& unitString) const
{
if (spec.translationSpecs.empty()) {
return toLocale(quant, 1.0, unitString);
}
const auto unitName = quant.getUnit().getTypeString();
if (spec.translationSpecs.count(unitName) == 0) {
// no schema-level translation. Use defaults.
factor = 1.0;
unitString = quant.getUnit().getString();
return toLocale(quant, factor, unitString);
}
const auto value = quant.getValue();
auto isSuitable = [&](const UnitTranslationSpec& row) {
return row.threshold > value || row.threshold == 0; // zero indicates default
};
auto unitSpecs = spec.translationSpecs.at(unitName);
const auto unitSpec = std::find_if(unitSpecs.begin(), unitSpecs.end(), isSuitable);
if (unitSpec == unitSpecs.end()) {
throw RuntimeError("Suitable threshhold not found. Schema: " + spec.name
+ " value: " + std::to_string(value));
}
if (unitSpec->factor == 0) {
return UnitsSchemasData::runSpecial(unitSpec->unitString, value);
}
factor = unitSpec->factor;
unitString = unitSpec->unitString;
return toLocale(quant, factor, unitString);
}
std::string
UnitsSchema::toLocale(const Quantity& quant, const double factor, const std::string& unitString)
{
QLocale Lc;
const QuantityFormat& format = quant.getFormat();
if (format.option != QuantityFormat::None) {
int opt = format.option;
Lc.setNumberOptions(static_cast<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
#include <string>
#include <memory>
#include "UnitsSchemasSpecs.h"
#include "Base/Quantity.h"
namespace Base
{
class Quantity;
/** Units systems */
enum class UnitSystem
{
SI1 = 0, /** internal (mm,kg,s) SI system
(http://en.wikipedia.org/wiki/International_System_of_Units) */
SI2 = 1, /** MKS (m,kg,s) SI system */
Imperial1 = 2, /** the Imperial system (http://en.wikipedia.org/wiki/Imperial_units) */
ImperialDecimal = 3, /** Imperial with length in inch only */
Centimeters = 4, /** All lengths in centimeters, areas and volumes in square/cubic meters */
ImperialBuilding = 5, /** All lengths in feet + inches + fractions */
MmMin = 6, /** Lengths in mm, Speed in mm/min. Angle in degrees. Useful for small parts & CNC */
ImperialCivil = 7, /** Lengths in ft, Speed in ft/s. Used in Civil Eng in North America */
FemMilliMeterNewton = 8, /** Lengths in mm, Mass in t, TimeSpan in s, thus force is in N */
MeterDecimal = 9, /** Lengths in metres always */
NumUnitSystemTypes // must be the last item!
};
/** The UnitSchema class
* The subclasses of this class define the stuff for a
* certain units schema.
/**
* An individual schema object
*/
class UnitsSchema
{
public:
UnitsSchema() = default;
UnitsSchema(const UnitsSchema&) = default;
UnitsSchema(UnitsSchema&&) = default;
UnitsSchema& operator=(const UnitsSchema&) = default;
UnitsSchema& operator=(UnitsSchema&&) = default;
virtual ~UnitsSchema() = default;
/** Gets called if this schema gets activated.
* Here it's theoretically possible that you can change the static factors
* for certain units (e.g. mi = 1,8km instead of mi=1.6km).
*/
virtual void setSchemaUnits()
{}
/// If you use setSchemaUnits() you also have to impment this method to undo your changes!
virtual void resetSchemaUnits()
{}
explicit UnitsSchema(UnitsSchemaSpec spec);
UnitsSchema() = delete;
/// This method translates the quantity in a string as the user may expect it.
virtual std::string
schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) = 0;
[[nodiscard]] bool isMultiUnitLength() const;
[[nodiscard]] bool isMultiUnitAngle() const;
[[nodiscard]] std::string getBasicLengthUnit() const;
[[nodiscard]] std::string getName() const;
[[nodiscard]] std::string getDescription() const;
[[nodiscard]] int getNum() const;
std::string
toLocale(const Base::Quantity& quant, double factor, const std::string& unitString) const;
std::string translate(const Quantity& quant) const;
std::string translate(const Quantity& quant, double& factor, std::string& unitString) const;
// return true if this schema uses multiple units for length (ex. Ft/In)
virtual bool isMultiUnitLength() const
{
return false;
}
private:
[[nodiscard]] static std::string
toLocale(const Quantity& quant, double factor, const std::string& unitString);
// return true if this schema uses multiple units for angles (ex. DMS)
virtual bool isMultiUnitAngle() const
{
return false;
}
// return the basic length unit for this schema
virtual std::string getBasicLengthUnit() const
{
return {"mm"};
}
UnitsSchemaSpec spec;
};
} // namespace Base
} // namespace Base
#endif // BASE_UNITSSCHEMA_H

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 library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
/* Metric units schema intended for design of large objects
* Lengths are always in metres.
* Angles in degrees (use degree symbol)
* Velocities in m/sec
*/
#ifndef BASE_UNITSSCHEMAMETERS_H
#define BASE_UNITSSCHEMAMETERS_H
#include "UnitsSchema.h"
namespace Base
{
/**
* The UnitSchema class
*/
class UnitsSchemaMeterDecimal: public UnitsSchema
{
public:
std::string
schemaTranslate(const Base::Quantity& quant, double& factor, std::string& unitString) override;
std::string getBasicLengthUnit() const override
{
return {"m"};
}
};
} // namespace Base
#endif // BASE_UNITSSCHEMAMETRES_H
/************************************************************************
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
************************************************************************/
#ifndef UNITSCHEMASPECS_H
#define UNITSCHEMASPECS_H
#include <map>
#include <string>
#include <vector>
#include <functional>
namespace Base
{
struct UnitTranslationSpec
{
double threshold {1};
std::string unitString;
double factor {1};
std::function<std::string(double)> fn {nullptr};
};
struct UnitsSchemaSpec
{
std::size_t num;
std::string name;
std::string basicLengthUnitStr;
bool isMultUnitLen {false};
bool isMultUnitAngle {false};
const char* description;
bool isDefault {false};
/**
* Applicable spec is the first with threshold > value under test
* Special case: Threshold = 0 : default
* Special case: Factor = 0 : unitString contains name of special function to run
*/
std::map<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");
if (!hGrp->GetBool("IgnoreProjectSchema")) {
int userSchema = Doc.UnitSystem.getValue();
Base::UnitsApi::setSchema(static_cast<Base::UnitSystem>(userSchema));
Base::UnitsApi::setSchema(userSchema);
getMainWindow()->setUserSchema(userSchema);
Application::Instance->onUpdate();
}
else { // set up Unit system default
Base::UnitsApi::setSchema((Base::UnitSystem)hGrp->GetInt("UserSchema", 0));
Base::UnitsApi::setSchema(hGrp->GetInt("UserSchema", 0));
Base::UnitsApi::setDecimals(hGrp->GetInt("Decimals", Base::UnitsApi::getDecimals()));
}
signalActiveDocument(*doc->second);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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