OpenDroneMap-WebODM/app/static/app/js/classes/Units.js

379 wiersze
8.3 KiB
JavaScript

import { _ } from './gettext';
const types = {
LENGTH: 1,
AREA: 2,
VOLUME: 3
};
const units = {
acres: {
factor: (1 / (0.3048 * 0.3048)) / 43560,
abbr: 'ac',
round: 5,
label: _("Acres"),
type: types.AREA
},
acres_us: {
factor: Math.pow(3937 / 1200, 2) / 43560,
abbr: 'ac (US)',
round: 5,
label: _("Acres"),
type: types.AREA
},
feet: {
factor: 1 / 0.3048,
abbr: 'ft',
round: 4,
label: _("Feet"),
type: types.LENGTH
},
feet_us:{
factor: 3937 / 1200,
abbr: 'ft (US)',
round: 4,
label: _("Feet"),
type: types.LENGTH
},
hectares: {
factor: 0.0001,
abbr: 'ha',
round: 4,
label: _("Hectares"),
type: types.AREA
},
meters: {
factor: 1,
abbr: 'm',
round: 3,
label: _("Meters"),
type: types.LENGTH
},
kilometers: {
factor: 0.001,
abbr: 'km',
round: 5,
label: _("Kilometers"),
type: types.LENGTH
},
centimeters: {
factor: 100,
abbr: 'cm',
round: 1,
label: _("Centimeters"),
type: types.LENGTH
},
miles: {
factor: (1 / 0.3048) / 5280,
abbr: 'mi',
round: 5,
label: _("Miles"),
type: types.LENGTH
},
miles_us: {
factor: (3937 / 1200) / 5280,
abbr: 'mi (US)',
round: 5,
label: _("Miles"),
type: types.LENGTH
},
sqfeet: {
factor: 1 / (0.3048 * 0.3048),
abbr: 'ft²',
round: 2,
label: _("Square Feet"),
type: types.AREA
},
sqfeet_us: {
factor: Math.pow(3937 / 1200, 2),
abbr: 'ft² (US)',
round: 2,
label: _("Square Feet"),
type: types.AREA
},
sqmeters: {
factor: 1,
abbr: 'm²',
round: 2,
label: _("Square Meters"),
type: types.AREA
},
sqkilometers: {
factor: 0.000001,
abbr: 'km²',
round: 5,
label: _("Square Kilometers"),
type: types.AREA
},
sqmiles: {
factor: Math.pow((1 / 0.3048) / 5280, 2),
abbr: 'mi²',
round: 5,
label: _("Square Miles"),
type: types.AREA
},
sqmiles_us: {
factor: Math.pow((3937 / 1200) / 5280, 2),
abbr: 'mi² (US)',
round: 5,
label: _("Square Miles"),
type: types.AREA
},
cbmeters:{
factor: 1,
abbr: 'm³',
round: 4,
label: _("Cubic Meters"),
type: types.VOLUME
},
cbyards:{
factor: Math.pow(1/(0.3048*3), 3),
abbr: 'yd³',
round: 4,
label: _("Cubic Yards"),
type: types.VOLUME
},
cbyards_us:{
factor: Math.pow(3937/3600, 3),
abbr: 'yd³ (US)',
round: 4,
label: _("Cubic Yards"),
type: types.VOLUME
}
};
class ValueUnit{
constructor(value, unit){
this.value = value;
this.unit = unit;
}
toString(opts = {}){
const mul = Math.pow(10, opts.precision !== undefined ? opts.precision : this.unit.round);
const rounded = (Math.round(this.value * mul) / mul).toString();
let withCommas = "";
let parts = rounded.split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
withCommas = parts.join(".");
return `${withCommas} ${this.unit.abbr}`;
}
}
class NanUnit{
constructor(){
this.value = NaN;
this.unit = units.meters; // Don't matter
}
toString(){
return "NaN";
}
}
class UnitSystem{
lengthUnit(meters, opts = {}){ throw new Error("Not implemented"); }
areaUnit(sqmeters, opts = {}){ throw new Error("Not implemented"); }
volumeUnit(cbmeters, opts = {}){ throw new Error("Not implemented"); }
getName(){ throw new Error("Not implemented"); }
area(sqmeters, opts = {}){
sqmeters = parseFloat(sqmeters);
if (isNaN(sqmeters)) return NanUnit();
const unit = this.areaUnit(sqmeters, opts);
const val = unit.factor * sqmeters;
return new ValueUnit(val, unit);
}
length(meters, opts = {}){
meters = parseFloat(meters);
if (isNaN(meters)) return NanUnit();
const unit = this.lengthUnit(meters, opts);
const val = unit.factor * meters;
return new ValueUnit(val, unit);
}
volume(cbmeters, opts = {}){
cbmeters = parseFloat(cbmeters);
if (isNaN(cbmeters)) return NanUnit();
const unit = this.volumeUnit(cbmeters, opts);
const val = unit.factor * cbmeters;
return new ValueUnit(val, unit);
}
};
function toMetric(valueUnit, unit){
let value = NaN;
if (typeof valueUnit === "object" && unit === undefined){
value = valueUnit.value;
unit = valueUnit.unit;
}else{
value = parseFloat(valueUnit);
}
if (isNaN(value)) return NanUnit();
const val = value / unit.factor;
if (unit.type === types.LENGTH){
return new ValueUnit(val, units.meters);
}else if (unit.type === types.AREA){
return new ValueUnit(val, unit.sqmeters);
}else if (unit.type === types.VOLUME){
return new ValueUnit(val, unit.cbmeters);
}else{
throw new Error(`Unrecognized unit type: ${unit.type}`);
}
}
class MetricSystem extends UnitSystem{
getName(){
return _("Metric");
}
lengthUnit(meters, opts = {}){
if (opts.fixedUnit) return units.meters;
if (meters < 1) return units.centimeters;
else if (meters >= 1000) return units.kilometers;
else return units.meters;
}
areaUnit(sqmeters, opts = {}){
if (opts.fixedUnit) return units.sqmeters;
if (sqmeters >= 10000 && sqmeters < 1000000) return units.hectares;
else if (sqmeters >= 1000000) return units.sqkilometers;
return units.sqmeters;
}
volumeUnit(cbmeters, opts = {}){
return units.cbmeters;
}
}
class ImperialSystem extends UnitSystem{
getName(){
return _("Imperial");
}
feet(){
return units.feet;
}
sqfeet(){
return units.sqfeet;
}
miles(){
return units.miles;
}
sqmiles(){
return units.sqmiles;
}
acres(){
return units.acres;
}
cbyards(){
return units.cbyards;
}
lengthUnit(meters, opts = {}){
if (opts.fixedUnit) return this.feet();
const feet = this.feet().factor * meters;
if (feet >= 5280) return this.miles();
else return this.feet();
}
areaUnit(sqmeters, opts = {}){
if (opts.fixedUnit) return this.sqfeet();
const sqfeet = this.sqfeet().factor * sqmeters;
if (sqfeet >= 43560 && sqfeet < 27878400) return this.acres();
else if (sqfeet >= 27878400) return this.sqmiles();
else return this.sqfeet();
}
volumeUnit(cbmeters, opts = {}){
return this.cbyards();
}
}
class ImperialUSSystem extends ImperialSystem{
getName(){
return _("Imperial (US)");
}
feet(){
return units.feet_us;
}
sqfeet(){
return units.sqfeet_us;
}
miles(){
return units.miles_us;
}
sqmiles(){
return units.sqmiles_us;
}
acres(){
return units.acres_us;
}
cbyards(){
return units.cbyards_us;
}
}
const systems = {
metric: new MetricSystem(),
imperial: new ImperialSystem(),
imperialUS: new ImperialUSSystem()
}
// Expose to allow every part of the app to access this information
function getUnitSystem(){
return localStorage.getItem("unit_system") || "metric";
}
function setUnitSystem(system){
let prevSystem = getUnitSystem();
localStorage.setItem("unit_system", system);
if (prevSystem !== system){
document.dispatchEvent(new CustomEvent("onUnitSystemChanged", { detail: system }));
}
}
function onUnitSystemChanged(callback){
document.addEventListener("onUnitSystemChanged", callback);
}
function offUnitSystemChanged(callback){
document.removeEventListener("onUnitSystemChanged", callback);
}
function unitSystem(){
return systems[getUnitSystem()];
}
export {
systems,
types,
toMetric,
unitSystem,
getUnitSystem,
setUnitSystem,
onUnitSystemChanged,
offUnitSystemChanged
};