@qudtlib/core
Version:
Data model for QUDTLib
272 lines (271 loc) • 9.67 kB
JavaScript
import { FactorUnit } from "./factorUnit.js";
import { arrayContains, getLastIriElement, isNullish, ZERO } from "./utils.js";
import { FactorUnits } from "./factorUnits.js";
import { Decimal } from "decimal.js";
import { QudtNamespaces } from "./qudtNamespaces.js";
export class Unit {
constructor(iri, quantityKindIris, exactMatchIris, dimensionVectorIri, conversionMultiplier, conversionOffset, prefixIri, scalingOfIri, scalingOf, symbol, labels, currencyCode, currencyNumber, unitOfSystemIris, dependents, deprecated, generated) {
this.quantityKinds = [];
this.factorUnits = FactorUnits.empty();
this.iri = iri;
this.prefixIri = prefixIri;
this.conversionMultiplier =
typeof conversionMultiplier === "undefined"
? new Decimal("1.0")
: conversionMultiplier;
this.conversionOffset =
typeof conversionOffset === "undefined"
? new Decimal("0.0")
: conversionOffset;
this.symbol = symbol;
this.scalingOfIri = scalingOfIri;
this.scalingOf = scalingOf;
this.dimensionVectorIri = dimensionVectorIri;
this.prefix = undefined;
if (typeof quantityKindIris === "undefined") {
this.quantityKindIris = [];
}
else {
this.quantityKindIris = quantityKindIris;
}
if (typeof exactMatchIris === "undefined") {
this.exactMatchIris = [];
}
else {
this.exactMatchIris = exactMatchIris;
}
if (typeof labels === "undefined") {
this.labels = [];
}
else {
this.labels = labels;
}
this.currencyCode = currencyCode;
this.currencyNumber = currencyNumber;
if (typeof unitOfSystemIris === "undefined") {
this.unitOfSystemIris = [];
}
else {
this.unitOfSystemIris = unitOfSystemIris;
}
this.factorUnits = FactorUnits.ofUnit(this); //might be replaced later by this.setFactorUnits().
this.dependents = dependents ?? 0;
this.deprecated = deprecated ?? false;
this.generated = generated ?? false;
}
equals(other) {
return !!other && this.iri === other.iri;
}
toString() {
if (this.symbol) {
return this.symbol;
}
if (this.scalingOf?.symbol && this.prefix?.symbol) {
return this.prefix.symbol + this.scalingOf.symbol;
}
return "unit:" + getLastIriElement(this.iri);
}
getIriLocalname() {
return getLastIriElement(this.iri);
}
getIriAbbreviated() {
return QudtNamespaces.unit.abbreviate(this.iri);
}
isCurrencyUnit() {
return this.getIriLocalname().startsWith("CCY_");
}
matchesFactorUnitSpec(...factorUnitSpec) {
return this.matches(FactorUnits.ofFactorUnitSpec(...factorUnitSpec));
}
matches(selection) {
const thisNormalized = this.normalize();
const selectionNormalized = selection.normalize();
return thisNormalized.equals(selectionNormalized);
}
hasFactorUnits() {
return this.factorUnits.hasFactorUnits();
}
/**
* Returns true if this unit is defined to be another unit, such as litre is defined as cubic decimetre.
*/
isDefinedAsOtherUnit() {
return this.factorUnits.isOneOtherUnitWithExponentOne();
}
isScaled() {
return !!this.scalingOfIri;
}
hasSymbol() {
return typeof this.symbol !== "undefined";
}
isConvertible(toUnit) {
return this.dimensionVectorIri === toUnit.dimensionVectorIri;
}
getConversionMultiplier(toUnit) {
if (this.equals(toUnit)) {
return new Decimal(1);
}
if (this.conversionOffsetDiffers(toUnit)) {
throw `Cannot convert from ${this} to ${toUnit} just by multiplication as their conversion offsets differ`;
}
const fromMultiplier = this.conversionMultiplier
? this.conversionMultiplier
: new Decimal(1);
const toMultiplier = toUnit.conversionMultiplier
? toUnit.conversionMultiplier
: new Decimal(1);
return fromMultiplier.div(toMultiplier);
}
findInBasesRecursively(toFind) {
if (!this.isScaled()) {
return this.equals(toFind);
}
if (!!this.scalingOf) {
return this.scalingOf.findInBasesRecursively(toFind);
}
else {
throw `No base unit found for ${this} - this is a bug`;
}
}
isSameScaleAs(other) {
if (this.equals(other)) {
return true;
}
if (!!this.scalingOfIri && this.scalingOfIri === other.scalingOfIri) {
return true;
}
return (this.findInBasesRecursively(other) || other.findInBasesRecursively(this));
}
static isUnitless(unit) {
return unit.iri === "http://qudt.org/vocab/unit/UNITLESS";
}
convert(value, toUnit, quantityKind) {
if (isNullish(value)) {
throw "Parameter 'value' is required";
}
if (isNullish(toUnit)) {
throw "Parameter 'toUnit' is required";
}
let ignoreOffset = false;
if (!isNullish(quantityKind)) {
if (quantityKind?.getIriLocalname() === Unit.TEMPERATURE_DIFFERENCE) {
ignoreOffset = true;
}
}
if (this.equals(toUnit)) {
return value;
}
if (Unit.isUnitless(this) || Unit.isUnitless(toUnit)) {
return value;
}
if (!this.isConvertible(toUnit)) {
throw `Not convertible: ${this} -> ${toUnit}`;
}
const fromOffset = ignoreOffset
? ZERO
: this.conversionOffset
? this.conversionOffset
: ZERO;
const fromMultiplier = this.conversionMultiplier
? this.conversionMultiplier
: new Decimal(1);
const toOffset = ignoreOffset
? ZERO
: toUnit.conversionOffset
? toUnit.conversionOffset
: ZERO;
const toMultiplier = toUnit.conversionMultiplier
? toUnit.conversionMultiplier
: new Decimal(1);
return value
.add(fromOffset)
.mul(fromMultiplier)
.div(toMultiplier)
.minus(toOffset);
}
addLabel(label) {
this.labels.push(label);
}
addQuantityKindIri(quantityKindIri) {
this.quantityKindIris.push(quantityKindIri);
}
addExactMatchIri(exactMatchIri) {
this.exactMatchIris.push(exactMatchIri);
}
hasLabel(label) {
return this.labels.some((l) => label === l.text);
}
getLabelForLanguageTag(languageTag) {
const label = this.labels.find((l) => languageTag === l.languageTag);
return label?.text;
}
addQuantityKind(quantityKind) {
this.quantityKinds.push(quantityKind);
}
setFactorUnits(factorUnits) {
this.factorUnits = factorUnits;
}
setPrefix(prefix) {
if (prefix.iri !== this.prefixIri)
throw "prefix.iri does not equal this.prefixIri";
this.prefix = prefix;
}
setScalingOf(scalingOf) {
if (scalingOf.iri !== this.scalingOfIri)
throw "scalingOf.iri does not equal this.scalingOfIri";
this.scalingOf = scalingOf;
}
/**
* Returns this unit as a set of exponent-reduced factors, unless they are two factors that cancel each other out, in
* which case return the unit as a factor unit with exponent 1. For example, Steradian is m²/m² and will
* therefore return SR.
*/
normalize() {
if (this.hasFactorUnits()) {
return this.factorUnits.normalize();
}
else if (this.scalingOf !== null &&
typeof this.scalingOf !== "undefined") {
return this.scalingOf
.normalize()
.scale(this.getConversionMultiplier(this.scalingOf));
}
return this.factorUnits;
}
getLeafFactorUnitsWithCumulativeExponents() {
if (this.hasFactorUnits()) {
const result = this.factorUnits.factorUnits.flatMap((fu) => fu.getLeafFactorUnitsWithCumulativeExponents());
return result;
}
else {
return [FactorUnit.ofUnit(this)];
}
}
getAllPossibleFactorUnitCombinations() {
if (!this.hasFactorUnits()) {
if (!!this.scalingOf) {
return this.scalingOf.getAllPossibleFactorUnitCombinations();
}
return [[FactorUnit.ofUnit(this)]];
}
const result = FactorUnit.getAllPossibleFactorUnitCombinations(this.factorUnits.factorUnits);
const thisAsResult = [FactorUnit.ofUnit(this)];
if (!arrayContains(result, thisAsResult, (l, r) => l.every((le) => r.some((re) => le.equals(re))))) {
result.push(thisAsResult);
}
return result;
}
conversionOffsetDiffers(other) {
if (this.hasNonzeroConversionOffset() &&
other.hasNonzeroConversionOffset()) {
if (!!this.conversionOffset && !!other.conversionOffset) {
return !this.conversionOffset.eq(other.conversionOffset);
}
}
return false;
}
hasNonzeroConversionOffset() {
return !!this.conversionOffset && !this.conversionOffset.eq(ZERO);
}
}
Unit.TEMPERATURE_DIFFERENCE = "TemperatureDifference";
//# sourceMappingURL=unit.js.map