[poincare/unit] Output units based on region

When the country is USA, the units will be simplified to common imperial
units rather than metric.

Change-Id: Ia533527a429ac26526380e324b9543b359f3b400
This commit is contained in:
Gabriel Ozouf
2020-07-20 15:36:13 +02:00
committed by Émilie Feral
parent 62f598110e
commit 5a31a6c1e2
2 changed files with 68 additions and 25 deletions

View File

@@ -55,13 +55,20 @@ public:
No,
Yes
};
enum class OutputSystem {
None,
Imperial,
Metric,
All
};
template <size_t N>
constexpr Representative(const char * rootSymbol, const char * definition, const Prefixable prefixable, const Prefix * const (&outputPrefixes)[N]) :
constexpr Representative(const char * rootSymbol, const char * definition, const Prefixable prefixable, const Prefix * const (&outputPrefixes)[N], const OutputSystem outputSystem = OutputSystem::All) :
m_rootSymbol(rootSymbol),
m_definition(definition),
m_prefixable(prefixable),
m_outputPrefixes(outputPrefixes),
m_outputPrefixesLength(N)
m_outputPrefixesLength(N),
m_outputSystem(outputSystem)
{
}
const char * rootSymbol() const { return m_rootSymbol; }
@@ -73,12 +80,14 @@ public:
const Prefix * * prefix) const;
int serialize(char * buffer, int bufferSize, const Prefix * prefix) const;
const Prefix * bestPrefixForValue(double & value, const float exponent) const;
bool canOutputInSystem(Preferences::UnitFormat system) const;
private:
const char * m_rootSymbol;
const char * m_definition;
const Prefixable m_prefixable;
const Prefix * const * m_outputPrefixes;
const size_t m_outputPrefixesLength;
const OutputSystem m_outputSystem;
};
class Dimension {
@@ -287,7 +296,8 @@ public:
DistanceRepresentatives[] = {
Representative("m", nullptr,
Representative::Prefixable::Yes,
LongScalePrefixes),
LongScalePrefixes,
Representative::OutputSystem::Metric),
Representative("au", "149597870700*_m",
Representative::Prefixable::No,
NoPrefix),
@@ -299,39 +309,49 @@ public:
NoPrefix),
Representative("in", "0.0254*_m",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
Representative("ft", "12*_in",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
Representative("yd", "3*_ft",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::None),
Representative("mi", "1760*_yd",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
},
MassRepresentatives[] = {
Representative("kg", nullptr,
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Metric),
Representative("g", "0.001_kg",
Representative::Prefixable::Yes,
NegativeLongScalePrefixes),
NegativeLongScalePrefixes,
Representative::OutputSystem::Metric),
Representative("t", "1000_kg",
Representative::Prefixable::Yes,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Metric),
Representative("Da", "(6.02214076*10^23*1000)^-1*_kg",
Representative::Prefixable::Yes,
NoPrefix),
Representative("oz", "0.028349523125*_kg",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
Representative("lb", "16*_oz",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
Representative("ton", "2000*_lb",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
},
CurrentRepresentatives[] = {
Representative("A", nullptr,
@@ -435,36 +455,46 @@ public:
SurfaceRepresentatives[] = {
Representative("ha", "10^4*_m^2",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Metric),
Representative("acre", "43560*_ft^2",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
},
VolumeRepresentatives[] = {
Representative("L", "10^-3*_m^3",
Representative::Prefixable::Yes,
NegativePrefixes),
NegativePrefixes,
Representative::OutputSystem::Metric),
Representative("tsp", "4.92892159375*_mL",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::None),
Representative("Tbsp", "3*_tsp",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::None),
Representative("floz", "0.0295735295625*_L",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
Representative("cp", "8*_floz",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
Representative("pt", "2*_cp",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::None),
Representative("qt", "4*_cp",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::None),
Representative("gal", "4*_qt",
Representative::Prefixable::No,
NoPrefix),
NoPrefix,
Representative::OutputSystem::Imperial),
};
// TODO: find a better way to define these pointers
static_assert(sizeof(TimeRepresentatives)/sizeof(Representative) == 7, "The Unit::SecondRepresentative, Unit::HourRepresentative and so on might require to be fixed if the TimeRepresentatives table was changed.");

View File

@@ -97,6 +97,16 @@ const UnitNode::Prefix * UnitNode::Representative::bestPrefixForValue(double & v
return bestPre;
}
bool UnitNode::Representative::canOutputInSystem(Preferences::UnitFormat system) const {
if (m_outputSystem == OutputSystem::None) {
return false;
}
if (m_outputSystem == OutputSystem::All) {
return true;
}
return (system == Preferences::UnitFormat::Metric) == (m_outputSystem == OutputSystem::Metric);
}
template<>
size_t UnitNode::Dimension::Vector<int>::supportSize() const {
size_t supportSize = 0;
@@ -383,7 +393,7 @@ void Unit::ChooseBestMultipleForValue(Expression * units, double * value, bool t
void Unit::chooseBestMultipleForValue(double * value, const float exponent, bool tuneRepresentative, ExpressionNode::ReductionContext reductionContext) {
assert(!std::isnan(*value) && exponent != 0.0f);
if (*value == 0.0 || *value == 1.0 || std::isinf(*value)) {
if (*value == 0.0 || std::isinf(*value)) {
return;
}
UnitNode * unitNode = node();
@@ -393,12 +403,15 @@ void Unit::chooseBestMultipleForValue(double * value, const float exponent, bool
*/
const Representative * bestRep = unitNode->representative();
const Prefix * bestPre = unitNode->prefix();
double bestVal = *value;
double bestVal = (tuneRepresentative) ? DBL_MAX : *value;
// Test all representatives if tuneRepresentative is on. Otherwise, force current representative
const Representative * startRep = tuneRepresentative ? dim->stdRepresentative() : bestRep;
const Representative * endRep = tuneRepresentative ? dim->representativesUpperBound() : bestRep + 1;
for (const Representative * rep = startRep; rep < endRep; rep++) {
if (!rep->canOutputInSystem(Preferences::sharedPreferences()->unitFormat())) {
continue;
}
// evaluate quotient
double val = *value * std::pow(Division::Builder(clone(), Unit::Builder(dim, rep, &EmptyPrefix)).deepReduce(reductionContext).approximateToScalar<double>(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit()), exponent);
// Get the best prefix and update val accordingly