Merge pull request #20540 from 3x380V/cleanup-schemas-management

Simplify UnitsSchemas management
This commit is contained in:
Chris Hennes
2025-05-05 10:43:27 -05:00
committed by GitHub
46 changed files with 2315 additions and 3268 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

@@ -877,13 +877,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

@@ -26,14 +26,16 @@
#include <cmath>
#include <limits>
#include <numbers>
#include <string>
#endif
#include <fmt/format.h>
#include <Base/Tools.h>
#include "Exception.h"
#include "Quantity.h"
#include "Tools.h"
#include "UnitsApi.h"
#include "UnitsSchema.h"
/** \defgroup Units Units system
\ingroup BASE
@@ -50,7 +52,9 @@
#pragma warning(disable : 4335) // disable MAC file format warning on VC
#endif
using namespace Base;
using Base::Quantity;
using Base::QuantityFormat;
using Base::UnitsSchema;
// ====== Static attributes =========================
// NOLINTNEXTLINE
@@ -60,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)
{}
@@ -237,6 +241,13 @@ Quantity Quantity::operator-() const
return Quantity(-(this->myValue), this->myUnit);
}
std::string Quantity::getUserString() const
{
double dummy1 {}; // to satisfy GCC
std::string dummy2 {};
return getUserString(dummy1, dummy2);
}
std::string Quantity::getUserString(double& factor, std::string& unitString) const
{
return Base::UnitsApi::schemaTranslate(*this, factor, unitString);
@@ -245,20 +256,18 @@ 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 ret = getUserString();
if (this->myValue) {
auto feedbackQty = parse(ret);
auto feedbackVal = feedbackQty.getValue();
if (feedbackVal == 0) {
ret = fmt::format("{} {}", this->myValue, this->getUnit().getString());
}
auto userStr = getUserString();
if (myValue != 0.0 && parse(userStr).getValue() == 0) {
auto unitStr = getUnit().getString();
userStr = fmt::format("{}{}{}", myValue, unitStr.empty() ? "" : " ", unitStr);
}
return Base::Tools::escapeQuotesFromString(ret);
return Tools::escapeQuotesFromString(userStr);
}
/// true if it has a number without a unit

View File

@@ -156,14 +156,10 @@ public:
{
myFormat = fmt;
}
std::string getUserString() const;
/// transfer to user preferred unit/potence
std::string getUserString(double& factor, std::string& unitString) const;
std::string getUserString() const
{ // to satisfy GCC
double dummy1 {};
std::string dummy2 {};
return getUserString(dummy1, dummy2);
}
std::string getUserString(UnitsSchema* schema, double& factor, std::string& unitString) const;
std::string getSafeUserString() const;

View File

@@ -22,7 +22,12 @@
#include "PreCompiled.h"
#ifndef _PreComp_
#include <cmath>
#include <limits>
#include <optional>
#include <sstream>
#include <string>
#include <vector>
#endif
#include "Unit.h"
@@ -33,7 +38,7 @@
#include "UnitPy.h"
using namespace Base;
using Base::Quantity;
// returns a string which represents the object e.g. when printed in python
std::string QuantityPy::representation() const
@@ -181,84 +186,128 @@ PyObject* QuantityPy::getUserPreferred(PyObject* /*args*/) const
PyObject* QuantityPy::getValueAs(PyObject* args) const
{
Quantity quant;
quant.setInvalid();
// first try Quantity
if (!quant.isValid()) {
auto tryQuantity = [&]() -> std::optional<Quantity> {
PyObject* object {};
if (PyArg_ParseTuple(args, "O!", &(QuantityPy::Type), &object)) {
quant = *static_cast<QuantityPy*>(object)->getQuantityPtr();
if (!PyArg_ParseTuple(args, "O!", &(QuantityPy::Type), &object)) {
return std::nullopt;
}
}
if (!quant.isValid()) {
return *getQuantityPtr();
};
auto tryUnit = [&]() -> std::optional<Quantity> {
PyObject* object {};
PyErr_Clear();
if (PyArg_ParseTuple(args, "O!", &(UnitPy::Type), &object)) {
quant.setUnit(*static_cast<UnitPy*>(object)->getUnitPtr());
quant.setValue(1.0);
if (!PyArg_ParseTuple(args, "O!", &(UnitPy::Type), &object)) {
return std::nullopt;
}
}
if (!quant.isValid()) {
return Quantity {1.0, *static_cast<UnitPy*>(object)->getUnitPtr()};
};
auto tryUnitAndValue = [&]() -> std::optional<Quantity> {
PyObject* object {};
double value {};
PyErr_Clear();
if (PyArg_ParseTuple(args, "dO!", &value, &(UnitPy::Type), &object)) {
quant.setUnit(*static_cast<UnitPy*>(object)->getUnitPtr());
quant.setValue(value);
if (!PyArg_ParseTuple(args, "dO!", &value, &(UnitPy::Type), &object)) {
return std::nullopt;
}
}
if (!quant.isValid()) {
return Quantity {value, *static_cast<UnitPy*>(object)->getUnitPtr()};
};
auto tryUnitPartsAndValue = [&]() -> std::optional<Quantity> {
double f = std::numeric_limits<double>::max();
int i1 = 0;
int i2 = 0;
int i3 = 0;
int i4 = 0;
int i5 = 0;
int i6 = 0;
int i7 = 0;
int i8 = 0;
int i1 {0};
int i2 {0};
int i3 {0};
int i4 {0};
int i5 {0};
int i6 {0};
int i7 {0};
int i8 {0};
PyErr_Clear();
if (PyArg_ParseTuple(args, "d|iiiiiiii", &f, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
if (f < std::numeric_limits<double>::max()) {
quant = Quantity(f,
Unit {static_cast<int8_t>(i1),
static_cast<int8_t>(i2),
static_cast<int8_t>(i3),
static_cast<int8_t>(i4),
static_cast<int8_t>(i5),
static_cast<int8_t>(i6),
static_cast<int8_t>(i7),
static_cast<int8_t>(i8)});
if (!PyArg_ParseTuple(args, "d|iiiiiiii", &f, &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8)) {
return std::nullopt;
}
if (f >= std::numeric_limits<double>::max()) {
return std::nullopt;
}
auto re = [](auto val) {
return static_cast<int8_t>(val);
};
return Quantity {f, Unit {re(i1), re(i2), re(i3), re(i4), re(i5), re(i6), re(i7), re(i8)}};
};
auto tryString = [&]() -> std::optional<Quantity> {
char* string {};
if (!PyArg_ParseTuple(args, "et", "utf-8", &string)) {
return std::nullopt;
}
const std::string str {string};
PyMem_Free(string);
return Quantity::parse(str);
};
const std::vector<std::function<std::optional<Quantity>()>> funcs = {tryQuantity,
tryUnit,
tryUnitAndValue,
tryUnitPartsAndValue,
tryString};
auto tryFuncs = [&]() -> std::optional<Quantity> {
for (const auto& func : funcs) {
PyErr_Clear();
if (auto quant = func(); quant.has_value()) {
return quant;
}
}
return std::nullopt;
};
auto checkQuant = [&](const Quantity& quant) -> bool {
auto err = [&](const std::string& str) {
PyErr_SetString(PyExc_ValueError, str.c_str());
};
const auto* qPtr = getQuantityPtr();
if (!qPtr) {
err("QuantityPtr is null");
return false;
}
const auto qpUnit = qPtr->getUnit();
if (qpUnit.isEmpty()) {
err("QuantityPtr returned empty unit");
return false;
}
if (const auto qUnit = quant.getUnit(); qUnit != qpUnit) {
err("Unit mismatch (`" + qUnit.getString() + "` != `" + qpUnit.getString() + "`)");
return false;
}
return true;
};
//----------------------------------------------------------------------------------------------
const auto optQuant = tryFuncs();
if (!optQuant.has_value()) {
PyErr_SetString(PyExc_TypeError, "Expected quantity, string, float or unit");
return nullptr;
}
if (!quant.isValid()) {
PyErr_Clear();
char* string {};
if (PyArg_ParseTuple(args, "et", "utf-8", &string)) {
std::string str(string);
PyMem_Free(string);
quant = Quantity::parse(str);
const auto quant = optQuant.value();
if (quant.isQuantity()) {
if (!checkQuant(quant)) {
return nullptr;
}
}
if (!quant.isValid()) {
PyErr_SetString(PyExc_TypeError, "Either quantity, string, float or unit expected");
return nullptr;
}
if (getQuantityPtr()->getUnit() != quant.getUnit() && quant.isQuantity()) {
PyErr_SetString(PyExc_ValueError, "Unit mismatch");
return nullptr;
}
quant = Quantity(getQuantityPtr()->getValueAs(quant));
return new QuantityPy(new Quantity(quant));
return new QuantityPy(new Quantity(getQuantityPtr()->getValue() / quant.getValue()));
}
PyObject* QuantityPy::__round__(PyObject* args) const

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

@@ -37,7 +37,7 @@
#include "MainWindow.h"
#if 0 // needed for Qt's lupdate utility
#if 0 // needed for Qt's lupdate utility
qApp->translate("Gui::Dialog::DlgSettingsDocument", "All rights reserved");
qApp->translate("Gui::Dialog::DlgSettingsDocument", "Creative Commons Attribution");
qApp->translate("Gui::Dialog::DlgSettingsDocument", "Creative Commons Attribution-ShareAlike");
@@ -64,8 +64,12 @@ using namespace Gui::Dialog;
* The dialog will by default be modeless, unless you set 'modal' to
* true to construct a modal dialog.
*/
DlgProjectInformationImp::DlgProjectInformationImp(App::Document* doc, QWidget* parent, Qt::WindowFlags fl)
: QDialog(parent, fl), _doc(doc), ui(new Ui_DlgProjectInformation)
DlgProjectInformationImp::DlgProjectInformationImp(App::Document* doc,
QWidget* parent,
Qt::WindowFlags fl)
: QDialog(parent, fl)
, _doc(doc)
, ui(new Ui_DlgProjectInformation)
{
ui->setupUi(this);
ui->lineEditName->setText(QString::fromUtf8(doc->Label.getValue()));
@@ -79,11 +83,12 @@ DlgProjectInformationImp::DlgProjectInformationImp(App::Document* doc, QWidget*
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
@@ -114,11 +119,15 @@ DlgProjectInformationImp::DlgProjectInformationImp(App::Document* doc, QWidget*
QStringList lines = comment.split(QLatin1String("\\n"), Qt::KeepEmptyParts);
QString text = lines.join(QLatin1String("\n"));
ui->textEditComment->setPlainText( text );
connect(ui->pushButtonOpenURL, &QPushButton::clicked,
this, &DlgProjectInformationImp::open_url);
connect(ui->comboLicense, qOverload<int>(&QComboBox::currentIndexChanged),
this, &DlgProjectInformationImp::onLicenseTypeChanged);
ui->textEditComment->setPlainText(text);
connect(ui->pushButtonOpenURL,
&QPushButton::clicked,
this,
&DlgProjectInformationImp::open_url);
connect(ui->comboLicense,
qOverload<int>(&QComboBox::currentIndexChanged),
this,
&DlgProjectInformationImp::onLicenseTypeChanged);
}
/**
@@ -148,8 +157,8 @@ void DlgProjectInformationImp::accept()
_doc->LicenseURL.setValue(ui->lineEditLicenseURL->text().toUtf8());
// Replace newline escape sequence through '\\n' string
QStringList lines = ui->textEditComment->toPlainText().split
(QLatin1String("\n"), Qt::KeepEmptyParts);
QStringList lines =
ui->textEditComment->toPlainText().split(QLatin1String("\n"), Qt::KeepEmptyParts);
QString text = lines.join(QLatin1String("\\n"));
_doc->Comment.setValue(text.isEmpty() ? QByteArray() : text.toUtf8());
@@ -159,8 +168,9 @@ void DlgProjectInformationImp::accept()
void DlgProjectInformationImp::onLicenseTypeChanged(int index)
{
const char* url {index >= 0 && index < App::countOfLicenses ? App::licenseItems.at(index).at(App::posnOfUrl)
: _doc->LicenseURL.getValue()};
const char* url {index >= 0 && index < App::countOfLicenses
? App::licenseItems.at(index).at(App::posnOfUrl)
: _doc->LicenseURL.getValue()};
ui->lineEditLicenseURL->setText(QString::fromLatin1(url));
}

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,23 +118,16 @@ 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
if (UnitsApi::getSchema() == UnitSystem::ImperialBuilding)
{
ui->comboBox_FracInch->setVisible(true);
ui->fractionalInchLabel->setVisible(true);
}
else
{
ui->comboBox_FracInch->setVisible(false);
ui->fractionalInchLabel->setVisible(false);
}
const auto visible = UnitsApi::isMultiUnitLength();
ui->comboBox_FracInch->setVisible(visible);
ui->fractionalInchLabel->setVisible(visible);
}
/**
@@ -211,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
@@ -225,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();
@@ -294,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.
@@ -536,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)
@@ -768,22 +762,16 @@ 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
if (static_cast<UnitSystem>(index) == UnitSystem::ImperialBuilding)
{
ui->comboBox_FracInch->setVisible(true);
ui->fractionalInchLabel->setVisible(true);
}
else
{
ui->comboBox_FracInch->setVisible(false);
ui->fractionalInchLabel->setVisible(false);
}
const auto visible = UnitsApi::isMultiUnitLength();
ui->comboBox_FracInch->setVisible(visible);
ui->fractionalInchLabel->setVisible(visible);
}
void DlgSettingsGeneral::onThemeChanged(int index) {

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

@@ -27,6 +27,7 @@ Test module for FreeCAD material cards and APIs
import unittest
import FreeCAD
import Materials
import sys
parseQuantity = FreeCAD.Units.parseQuantity
@@ -37,6 +38,15 @@ class MaterialTestCases(unittest.TestCase):
def setUp(self):
""" Setup function to initialize test data """
# The test for ThermalExpansionCoefficient causes problems with some localizations
# due to the Unicode mu ('\u03bc') character in the units. This will happen with
# locales that don't support UTF8 such as zh_CN (It does support UTF-8)
try:
sys.stdout.reconfigure(errors='replace')
except:
# reconfigure appeared in 3.7, hope for the best...
pass
self.ModelManager = Materials.ModelManager()
self.MaterialManager = Materials.MaterialManager()
self.uuids = Materials.UUIDs()
@@ -145,12 +155,6 @@ class MaterialTestCases(unittest.TestCase):
self.assertIn("SpecularColor", properties)
self.assertIn("Transparency", properties)
#
# The test for ThermalExpansionCoefficient causes problems with some localizations
# due to the Unicode mu character in the units. This will happen with
# locales that don't support UTF8 such as zh_CN (It does support UTF-8)
#
# When this is a problem simply comment the lines printing ThermalExpansionCoefficient
print("Density " + properties["Density"])
# print("BulkModulus " + properties["BulkModulus"])
print("PoissonRatio " + properties["PoissonRatio"])

View File

@@ -2100,100 +2100,77 @@ void EditModeConstraintCoinManager::rebuildConstraintNodes(
QString EditModeConstraintCoinManager::getPresentationString(const Constraint* constraint)
{
std::string nameStr; // name parameter string
QString valueStr; // dimensional value string
std::string unitStr; // the actual unit string
std::string baseUnitStr; // the expected base unit string
double factor; // unit scaling factor, currently not used
Base::UnitSystem unitSys; // current unit system
if (!constraint->isActive) {
return QStringLiteral(" ");
}
// Get the current name parameter string of the constraint
nameStr = constraint->Name;
/**
* Hide units if
* - user has requested it,
* - is being displayed in the base units, -and-
* - the schema being used has a clear base unit in the first place.
*
* Remove unit string if expected unit string matches actual unit string
* Example code from: Mod/TechDraw/App/DrawViewDimension.cpp:372
*
* Hide the default length unit
*/
auto fixValueStr = [&](const QString& valueStr, const auto& unitStr) -> std::optional<QString> {
if (!constraintParameters.bHideUnits || constraint->Type == Sketcher::Angle) {
return std::nullopt;
}
const auto baseUnitStr {Base::UnitsApi::getBasicLengthUnit()};
if (baseUnitStr.empty() || baseUnitStr != unitStr) {
return std::nullopt;
}
// trailing space or non-dig
const QRegularExpression rxUnits {QString::fromUtf8(" \\D*$")};
auto vStr = valueStr;
vStr.remove(rxUnits);
return {vStr};
};
// Get the current value string including units
valueStr =
QString::fromStdString(constraint->getPresentationValue().getUserString(factor, unitStr));
double factor {};
std::string unitStr; // the actual unit string
const auto constrPresValue {constraint->getPresentationValue().getUserString(factor, unitStr)};
auto valueStr = QString::fromStdString(constrPresValue);
// Hide units if user has requested it, is being displayed in the base
// units, and the schema being used has a clear base unit in the first
// place. Otherwise, display units.
if (constraintParameters.bHideUnits && constraint->Type != Sketcher::Angle) {
// Only hide the default length unit. Right now there is not an easy way
// to get that from the Unit system so we have to manually add it here.
// Hopefully this can be added in the future so this code won't have to
// be updated if a new units schema is added.
unitSys = Base::UnitsApi::getSchema();
// If this is a supported unit system then define what the base unit is.
switch (unitSys) {
case Base::UnitSystem::SI1:
case Base::UnitSystem::MmMin:
baseUnitStr = "mm";
break;
case Base::UnitSystem::SI2:
baseUnitStr = "m";
break;
case Base::UnitSystem::ImperialDecimal:
baseUnitStr = "in";
break;
case Base::UnitSystem::Centimeters:
baseUnitStr = "cm";
break;
default:
// Nothing to do
break;
}
if (!baseUnitStr.empty()) {
// expected unit string matches actual unit string. remove.
if (baseUnitStr.compare(unitStr) == 0) {
// Example code from: Mod/TechDraw/App/DrawViewDimension.cpp:372
QRegularExpression rxUnits(
QStringLiteral(" \\D*$")); // space + any non digits at end of string
valueStr.remove(rxUnits); // getUserString(defaultDecimals) without units
}
}
auto fixedValueStr = fixValueStr(valueStr, unitStr).value_or(valueStr);
switch (constraint->Type) {
case Sketcher::Diameter:
fixedValueStr.prepend(QChar(0x2300));
break;
case Sketcher::Radius:
fixedValueStr.prepend(QLatin1Char('R'));
break;
default:
break;
}
if (constraint->Type == Sketcher::Diameter) {
valueStr.prepend(QChar(216)); // Diameter sign
}
else if (constraint->Type == Sketcher::Radius) {
valueStr.prepend(QChar(82)); // Capital letter R
if (!constraintParameters.bShowDimensionalName || constraint->Name.empty()) {
return fixedValueStr;
}
/**
Create the representation string from the user defined format string
Format options are:
%N - the constraint name parameter
%V - the value of the dimensional constraint, including any unit characters
*/
if (constraintParameters.bShowDimensionalName && !nameStr.empty()) {
QString presentationStr;
if (constraintParameters.sDimensionalStringFormat.contains(QLatin1String("%V"))
|| constraintParameters.sDimensionalStringFormat.contains(QLatin1String("%N"))) {
presentationStr = constraintParameters.sDimensionalStringFormat;
presentationStr.replace(QLatin1String("%N"), QString::fromStdString(nameStr));
presentationStr.replace(QLatin1String("%V"), valueStr);
}
else {
// user defined format string does not contain any valid parameter, using default format
// "%N = %V"
presentationStr = QString::fromStdString(nameStr) + QStringLiteral(" = ") + valueStr;
}
* Create the representation string from the user defined format string
* Format options are:
* %N - the constraint name parameter
* %V - the value of the dimensional constraint, including any unit characters
*/
auto sDimFmt {constraintParameters.sDimensionalStringFormat};
if (!sDimFmt.contains(QLatin1String("%V"))
&& !sDimFmt.contains(QLatin1String("%N"))) { // using default format "%N = %V"
return presentationStr;
return QString::fromStdString(constraint->Name) + QString::fromLatin1(" = ") + valueStr;
}
return valueStr;
sDimFmt.replace(QLatin1String("%N"), QString::fromStdString(constraint->Name));
sDimFmt.replace(QLatin1String("%V"), fixedValueStr);
return sDimFmt;
}
std::set<int> EditModeConstraintCoinManager::detectPreselectionConstr(const SoPickedPoint* Point,

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

@@ -39,17 +39,11 @@ using namespace TechDraw;
bool DimensionFormatter::isMultiValueSchema() const
{
bool angularMeasure = (m_dimension->Type.isValue("Angle") ||
m_dimension->Type.isValue("Angle3Pt"));
const bool angularMeasure =
(m_dimension->Type.isValue("Angle") || m_dimension->Type.isValue("Angle3Pt"));
if (Base::UnitsApi::isMultiUnitAngle() &&
angularMeasure) {
return true;
} else if (Base::UnitsApi::isMultiUnitLength() &&
!angularMeasure) {
return true;
}
return false;
return (Base::UnitsApi::isMultiUnitAngle() && angularMeasure)
|| (Base::UnitsApi::isMultiUnitLength() && !angularMeasure);
}
std::string DimensionFormatter::formatValue(const qreal value,
@@ -57,145 +51,117 @@ std::string DimensionFormatter::formatValue(const qreal value,
const Format partial,
const bool isDim) const
{
// Base::Console().Message("DF::formatValue() - %s isRestoring: %d\n",
// m_dimension->getNameInDocument(), m_dimension->isRestoring());
bool angularMeasure = m_dimension->Type.isValue("Angle") || m_dimension->Type.isValue("Angle3Pt");
bool areaMeasure = m_dimension->Type.isValue("Area");
QLocale loc;
const bool angularMeasure =
m_dimension->Type.isValue("Angle") || m_dimension->Type.isValue("Angle3Pt");
const bool areaMeasure = m_dimension->Type.isValue("Area");
Base::Quantity asQuantity;
asQuantity.setValue(value);
Base::Unit unit;
if (angularMeasure) {
asQuantity.setUnit(Base::Unit::Angle);
unit = Base::Unit::Angle;
}
else if (areaMeasure) {
asQuantity.setUnit(Base::Unit::Area);
unit = Base::Unit::Area;
}
else {
asQuantity.setUnit(Base::Unit::Length);
unit = Base::Unit::Length;
}
Base::Quantity asQuantity {value, unit};
QStringList qsl = getPrefixSuffixSpec(qFormatSpec);
const std::string formatPrefix = qsl[0].toStdString();
const std::string formatSuffix = qsl[1].toStdString();
QString formatSpecifier = qsl[2];
// this handles mm to inch/km/parsec etc and decimal positions but
// won't give more than Global_Decimals precision
QString qUserString = QString::fromStdString(asQuantity.getUserString());
std::string basicString = formatPrefix + asQuantity.getUserString() + formatSuffix;
//get formatSpec prefix/suffix/specifier
QStringList qsl = getPrefixSuffixSpec(qFormatSpec);
QString formatPrefix = qsl[0]; //FormatSpec prefix
QString formatSuffix = qsl[1]; //FormatSpec suffix
QString formatSpecifier = qsl[2]; //FormatSpec specifier
QString qMultiValueStr;
QString qBasicUnit = QString::fromStdString(Base::UnitsApi::getBasicLengthUnit());
QString formattedValue;
if (isMultiValueSchema() && partial == Format::UNALTERED) {
//handle multi value schemes (yd/ft/in, dms, etc). don't even try to use Alt Decimals or hide units
qMultiValueStr = formatPrefix + qUserString + formatSuffix;
return qMultiValueStr.toStdString();
} else {
//not multivalue schema
if (formatSpecifier.isEmpty()) {
Base::Console().Warning("Warning - no numeric format in Format Spec %s - %s\n",
qPrintable(qFormatSpec), m_dimension->getNameInDocument());
return qFormatSpec.toStdString();
}
return basicString; // Don't even try to use Alt Decimals or hide units
}
// for older TD drawings the formatSpecifier "%g" was used, but the number of decimals was
// neverheless limited. To keep old drawings, we limit the number of decimals too
// if the TD preferences option to use the global decimal number is set
// the formatSpecifier can have a prefix and/or suffix
if (m_dimension->useDecimals() && formatSpecifier.contains(QStringLiteral("%g"), Qt::CaseInsensitive)) {
int globalPrecision = Base::UnitsApi::getDecimals();
// change formatSpecifier to e.g. "%.2f"
QString newSpecifier = QString::fromStdString("%." + std::to_string(globalPrecision) + "f");
formatSpecifier.replace(QStringLiteral("%g"), newSpecifier, Qt::CaseInsensitive);
}
if (formatSpecifier.isEmpty()) {
Base::Console().Warning("Warning - no numeric format in Format Spec %s - %s\n",
qPrintable(qFormatSpec),
m_dimension->getNameInDocument());
return qFormatSpec.toStdString();
}
// since we are not using a multiValueSchema, we know that angles are in '°' and for
// lengths we can get the unit of measure from UnitsApi::getBasicLengthUnit.
// for older TD drawings the formatSpecifier "%g" was used, but the number of decimals was
// nevertheless limited. To keep old drawings, we limit the number of decimals too
// if the TD preferences option to use the global decimal number is set
// the formatSpecifier can have a prefix and/or suffix
if (m_dimension->useDecimals()
&& formatSpecifier.contains(QStringLiteral("%g"), Qt::CaseInsensitive)) {
const int globalPrecision = Base::UnitsApi::getDecimals();
// change formatSpecifier to e.g. "%.2f"
const QString newSpecifier =
QString::fromStdString("%." + std::to_string(globalPrecision) + "f");
formatSpecifier.replace(QStringLiteral("%g"), newSpecifier, Qt::CaseInsensitive);
}
// TODO: check the weird schemas (MKS, Imperial1)that report different UoM
// for different values
// since we are not using a multiValueSchema, we know that angles are in '°' and for
// lengths we can get the unit of measure from UnitsApi::getBasicLengthUnit.
// get value in the base unit with default decimals
// for the conversion we use the same method as in DlgUnitsCalculator::valueChanged
// get the conversion factor for the unit
// the result is now just val / convertValue because val is always in the base unit
// don't do this for angular values since they are not in the BaseLengthUnit
double userVal;
if (angularMeasure) {
userVal = asQuantity.getValue();
qBasicUnit = QStringLiteral("°");
}
else {
double convertValue = Base::Quantity::parse("1" + qBasicUnit.toStdString()).getValue();
userVal = asQuantity.getValue() / convertValue;
if (areaMeasure) {
userVal = userVal / convertValue; // divide again as area is length²
qBasicUnit = qBasicUnit + QStringLiteral("²");
}
}
// TODO: check the weird schemas (MKS, Imperial1) that report different UoM for different values
if (isTooSmall(userVal, formatSpecifier)) {
Base::Console().Warning("Dimension %s value %.6f is too small for format specifier: %s\n",
m_dimension->getNameInDocument(), userVal, qPrintable(formatSpecifier));
}
// get value in the base unit with default decimals
// for the conversion we use the same method as in DlgUnitsCalculator::valueChanged
// get the conversion factor for the unit
// the result is now just val / convertValue because val is always in the base unit
// don't do this for angular values since they are not in the BaseLengthUnit
std::string qBasicUnit =
angularMeasure ? "°" : Base::UnitsApi::getBasicLengthUnit();
double userVal = asQuantity.getValue();
formattedValue = formatValueToSpec(userVal, formatSpecifier);
// replace decimal sign if necessary
QChar dp = QChar::fromLatin1('.');
if (loc.decimalPoint() != dp) {
formattedValue.replace(dp, loc.decimalPoint());
if (!angularMeasure) {
const double convertValue = Base::Quantity::parse("1" + qBasicUnit).getValue();
userVal /= convertValue;
if (areaMeasure) {
userVal /= convertValue; // divide again as area is length²
qBasicUnit += "²";
}
}
//formattedValue is now in formatSpec format with local decimal separator
if (isTooSmall(userVal, formatSpecifier)) {
Base::Console().Warning("Dimension %s value %.6f is too small for format specifier: %s\n",
m_dimension->getNameInDocument(),
userVal,
qPrintable(formatSpecifier));
}
QString formattedValue = formatValueToSpec(userVal, formatSpecifier);
// replace decimal sign if necessary
constexpr QChar dp = QChar::fromLatin1('.');
if (const QLocale loc; loc.decimalPoint() != dp) {
formattedValue.replace(dp, loc.decimalPoint());
}
// formattedValue is now in formatSpec format with local decimal separator
std::string formattedValueString = formattedValue.toStdString();
if (partial == Format::UNALTERED) { // prefix + unit subsystem string + suffix
return formatPrefix.toStdString() +
qUserString.toStdString() +
formatSuffix.toStdString();
if (partial == Format::UNALTERED) {
return basicString;
}
else if (partial == Format::FORMATTED) {
if (partial == Format::FORMATTED) {
std::string unitStr {};
if (angularMeasure) {
//always insert unit after value
return formatPrefix.toStdString() + formattedValueString + "°" +
formatSuffix.toStdString();
unitStr = "°";
}
else if (m_dimension->showUnits() || areaMeasure){
if (isDim && m_dimension->haveTolerance()) {
//unit will be included in tolerance so don't repeat it here
return formatPrefix.toStdString() +
formattedValueString +
formatSuffix.toStdString();
}
else {
//no tolerance, so we need to include unit
return formatPrefix.toStdString() +
formattedValueString + " " +
qBasicUnit.toStdString() +
formatSuffix.toStdString();
}
}
else {
//showUnits is false
return formatPrefix.toStdString() +
formattedValueString +
formatSuffix.toStdString();
else if ((m_dimension->showUnits() || areaMeasure)
&& !(isDim && m_dimension->haveTolerance())) {
unitStr = " " + qBasicUnit;
}
return formatPrefix + formattedValueString + unitStr + formatSuffix;
}
else if (partial == Format::UNIT) {
if (angularMeasure) {
return qBasicUnit.toStdString();
}
else if (m_dimension->showUnits() || areaMeasure) {
return qBasicUnit.toStdString();
}
else {
return "";
}
if (partial == Format::UNIT) {
return angularMeasure || m_dimension->showUnits() || areaMeasure ? qBasicUnit : "";
}
return formattedValueString;
@@ -368,13 +334,10 @@ QString DimensionFormatter::formatValueToSpec(const double value, QString format
bool DimensionFormatter::isNumericFormat(const QString& formatSpecifier) const
{
QRegularExpression rxFormat(QStringLiteral("%[+-]?[0-9]*\\.*[0-9]*[aefgwAEFGW]")); //printf double format spec
//printf double format spec
const QRegularExpression rxFormat(QStringLiteral("%[+-]?[0-9]*\\.*[0-9]*[aefgwAEFGW]"));
QRegularExpressionMatch rxMatch;
int pos = formatSpecifier.indexOf(rxFormat, 0, &rxMatch);
if (pos != -1) {
return true;
}
return false;
return formatSpecifier.indexOf(rxFormat, 0, &rxMatch) != -1;
}
//TODO: similar code here and above

View File

@@ -41,28 +41,28 @@ public:
UNIT // return only the unit of measure
};
DimensionFormatter() {}
DimensionFormatter(DrawViewDimension* dim) { m_dimension = dim; }
DimensionFormatter() = default;
explicit DimensionFormatter(DrawViewDimension* dim)
: m_dimension {dim}
{}
~DimensionFormatter() = default;
//void setDimension(DrawViewDimension* dim) { m_dimension = dim; }
bool isMultiValueSchema() const;
std::string formatValue(const qreal value,
const QString& qFormatSpec,
const Format partial,
const bool isDim) const;
std::string getFormattedToleranceValue(const Format partial) const;
std::pair<std::string, std::string> getFormattedToleranceValues(const Format partial) const;
std::string getFormattedDimensionValue(const Format partial) const;
std::string formatValue(qreal value, const QString& qFormatSpec, Format partial, bool isDim) const;
std::string getFormattedToleranceValue(Format partial) const;
std::pair<std::string, std::string> getFormattedToleranceValues(Format partial) const;
std::string getFormattedDimensionValue(Format partial) const;
QStringList getPrefixSuffixSpec(const QString& fSpec) const;
std::string getDefaultFormatSpec(bool isToleranceFormat) const;
bool isTooSmall(const double value, const QString& formatSpec) const;
QString formatValueToSpec(const double value, QString formatSpecifier) const;
bool isNumericFormat(const QString& formatSpecifier) const;
private:
DrawViewDimension* m_dimension;
bool isTooSmall(double value, const QString& formatSpec) const;
QString formatValueToSpec(double value, QString formatSpecifier) const;
bool isNumericFormat(const QString& formatSpecifier) const;
DrawViewDimension* m_dimension {nullptr};
};
} //end namespace TechDraw
} // end namespace TechDraw
#endif

View File

@@ -96,9 +96,9 @@ class UnitBasicCases(unittest.TestCase):
qu2 = FreeCAD.Units.Quantity("m/s")
self.assertTrue(qu1 / qu2, 1)
def testSchemes(self):
schemes = FreeCAD.Units.listSchemas()
num = len(schemes)
def testSchemas(self):
schemas = FreeCAD.Units.listSchemas()
num = len(schemas)
psi = FreeCAD.Units.parseQuantity("1psi")
for i in range(num):
@@ -108,7 +108,7 @@ class UnitBasicCases(unittest.TestCase):
1,
v.Value,
msg='Failed with "{0}" scheme: {1} != 1 (delta: {2})'.format(
schemes[i], v.Value, self.delta
schemas[i], v.Value, self.delta
),
delta=self.delta,
)
@@ -121,7 +121,7 @@ class UnitBasicCases(unittest.TestCase):
1,
v.Value,
msg='Failed with "{0}" scheme: {1} != 1 (delta: {2})'.format(
schemes[i], v.Value, self.delta
schemas[i], v.Value, self.delta
),
delta=self.delta,
)
@@ -135,7 +135,7 @@ class UnitBasicCases(unittest.TestCase):
1,
v.Value,
msg='Failed with "{0}" scheme: {1} != 1 (delta: {2})'.format(
schemes[i], v.Value, self.delta
schemas[i], v.Value, self.delta
),
delta=self.delta,
)
@@ -146,12 +146,12 @@ class UnitBasicCases(unittest.TestCase):
if issubclass(type(getattr(FreeCAD.Units, i)), FreeCAD.Units.Quantity):
quantities.append(i)
schemes = FreeCAD.Units.listSchemas()
schemas = FreeCAD.Units.listSchemas()
for i in quantities:
q1 = getattr(FreeCAD.Units, i)
q1 = FreeCAD.Units.Quantity(q1)
q1.Format = {"Precision": 16}
for idx, val in enumerate(schemes):
for idx, val in enumerate(schemas):
[t, amountPerUnit, unit] = FreeCAD.Units.schemaTranslate(q1, idx)
try:
q2 = FreeCAD.Units.Quantity(t)