UNPKG

@qudtlib/core

Version:

Data model for QUDTLib

272 lines (271 loc) 9.67 kB
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