subsurface/core/units.cpp
Berthold Stoeger 77b12bbccf core: add cast_int<> function
We had a pattern where doubles were converted to long with
lrint() and then down-cast to a narrower int type.

Because this is unwieldy, introduce a function encapsulating
this.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-09-11 10:23:07 +02:00

201 lines
4.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: GPL-2.0
#include "units.h"
#include "gettext.h"
#include "pref.h"
const struct units SI_units = SI_UNITS;
const struct units IMPERIAL_units = {
.length = units::FEET, .volume = units::CUFT, .pressure = units::PSI, .temperature = units::FAHRENHEIT, .weight = units::LBS,
.vertical_speed_time = units::MINUTES, .duration_units = units::MIXED, .show_units_table = false
};
int get_pressure_units(int mb, const char **units)
{
int pressure;
const char *unit;
const struct units *units_p = get_units();
switch (units_p->pressure) {
case units::BAR:
default:
pressure = (mb + 500) / 1000;
unit = translate("gettextFromC", "bar");
break;
case units::PSI:
pressure = int_cast<int>(mbar_to_PSI(mb));
unit = translate("gettextFromC", "psi");
break;
}
if (units)
*units = unit;
return pressure;
}
double get_temp_units(unsigned int mk, const char **units)
{
double deg;
const char *unit;
const struct units *units_p = get_units();
if (units_p->temperature == units::FAHRENHEIT) {
deg = mkelvin_to_F(mk);
unit = "°F";
} else {
deg = mkelvin_to_C(mk);
unit = "°C";
}
if (units)
*units = unit;
return deg;
}
double get_volume_units(unsigned int ml, int *frac, const char **units)
{
int decimals;
double vol;
const char *unit;
const struct units *units_p = get_units();
switch (units_p->volume) {
case units::LITER:
default:
vol = ml / 1000.0;
unit = translate("gettextFromC", "");
decimals = 1;
break;
case units::CUFT:
vol = ml_to_cuft(ml);
unit = translate("gettextFromC", "cuft");
decimals = 2;
break;
}
if (frac)
*frac = decimals;
if (units)
*units = unit;
return vol;
}
int units_to_sac(double volume)
{
if (get_units()->volume == units::CUFT)
return lrint(cuft_to_l(volume) * 1000.0);
else
return lrint(volume * 1000);
}
depth_t units_to_depth(double depth)
{
depth_t internaldepth;
if (get_units()->length == units::METERS) {
internaldepth.mm = lrint(depth * 1000);
} else {
internaldepth.mm = feet_to_mm(depth);
}
return internaldepth;
}
double get_depth_units(int mm, int *frac, const char **units)
{
int decimals;
double d;
const char *unit;
const struct units *units_p = get_units();
switch (units_p->length) {
case units::METERS:
default:
d = mm / 1000.0;
unit = translate("gettextFromC", "m");
decimals = d < 20;
break;
case units::FEET:
d = mm_to_feet(mm);
unit = translate("gettextFromC", "ft");
decimals = 0;
break;
}
if (frac)
*frac = decimals;
if (units)
*units = unit;
return d;
}
double get_vertical_speed_units(unsigned int mms, int *frac, const char **units)
{
double d;
const char *unit;
const struct units *units_p = get_units();
const double time_factor = units_p->vertical_speed_time == units::MINUTES ? 60.0 : 1.0;
switch (units_p->length) {
case units::METERS:
default:
d = mms / 1000.0 * time_factor;
if (units_p->vertical_speed_time == units::MINUTES)
unit = translate("gettextFromC", "m/min");
else
unit = translate("gettextFromC", "m/s");
break;
case units::FEET:
d = mm_to_feet(mms) * time_factor;
if (units_p->vertical_speed_time == units::MINUTES)
unit = translate("gettextFromC", "ft/min");
else
unit = translate("gettextFromC", "ft/s");
break;
}
if (frac)
*frac = d < 10;
if (units)
*units = unit;
return d;
}
double get_weight_units(unsigned int grams, int *frac, const char **units)
{
int decimals;
double value;
const char *unit;
const struct units *units_p = get_units();
if (units_p->weight == units::LBS) {
value = grams_to_lbs(grams);
unit = translate("gettextFromC", "lbs");
decimals = 0;
} else {
value = grams / 1000.0;
unit = translate("gettextFromC", "kg");
decimals = 1;
}
if (frac)
*frac = decimals;
if (units)
*units = unit;
return value;
}
const struct units *get_units()
{
return &prefs.units;
}
// Calculate the distance in meters between two coordinates.
unsigned int get_distance(location_t loc1, location_t loc2)
{
double lat1_r = udeg_to_radians(loc1.lat.udeg);
double lat2_r = udeg_to_radians(loc2.lat.udeg);
double lat_d_r = udeg_to_radians(loc2.lat.udeg - loc1.lat.udeg);
double lon_d_r = udeg_to_radians(loc2.lon.udeg - loc1.lon.udeg);
double a = sin(lat_d_r/2) * sin(lat_d_r/2) +
cos(lat1_r) * cos(lat2_r) * sin(lon_d_r/2) * sin(lon_d_r/2);
if (a < 0.0) a = 0.0;
if (a > 1.0) a = 1.0;
double c = 2 * atan2(sqrt(a), sqrt(1.0 - a));
// Earth radius in metres
return lrint(6371000 * c);
}