UNPKG

@qudtlib/core

Version:

Data model for QUDTLib

172 lines (171 loc) 6.37 kB
import { QudtNamespaces } from "./qudtNamespaces.js"; import { isNullish } from "./utils.js"; /** * Represents the QUDT dimension vector and allows for converting between a dimension vector IRI and * the numeric values, as well as for some manipulations. * * <p>Note that the last value, the 'D' dimension is special: it is only an indicator that the * dimension vector represents a ratio (causing all other dimensions to cancel each other out). It * never changes by multiplication, and its value is only 1 iff all other dimensions are 0. */ export class DimensionVector { static ofRequired(dimensionVectorIri) { return new DimensionVector(dimensionVectorIri); } static of(dimensionValues) { try { return new DimensionVector(dimensionValues); } catch (e) { return undefined; } } constructor(dimensionVector) { if (typeof dimensionVector === "string") { this.dimensionVectorIri = dimensionVector; this.values = this.parseDimValues(dimensionVector); } else if (Array.isArray(dimensionVector)) { this.values = dimensionVector; this.dimensionVectorIri = this.generateDimensionVectorIri(dimensionVector); } else { throw new Error(`Cannot handle constructor argument ${dimensionVector}`); } } parseDimValues(dimensionVectorIri) { if (!QudtNamespaces.dimensionVector.isFullNamespaceIri(dimensionVectorIri)) { throw new Error(`Not a dimension vector iri: ${dimensionVectorIri}`); } const localName = QudtNamespaces.dimensionVector.getLocalnameIfFullNamespaceIri(dimensionVectorIri); const dimValues = [0, 0, 0, 0, 0, 0, 0, 0]; const numbers = localName.split(/[AELIMHTD]/); const indicators = localName.split(/-?[0-9]+p?t?[0-9]*/); if (indicators.length != 9) { throw new Error(`Cannot process dimension vector iri ${dimensionVectorIri}: unexpected number of dimensions: ${numbers.length}`); } else { for (let i = 0; i < 8; i++) { if (indicators[i].charAt(0) != DimensionVector.DIMENSIONS[i]) { throw new Error(`Expected dimension indicator '${DimensionVector.DIMENSIONS[i]}', encountered '${indicators[i]}'`); } dimValues[i] = DimensionVector.noNegativeZero(Number.parseFloat(numbers[i + 1].replace("pt", "."))); // split produces an empty first array element } } return dimValues; } generateDimensionVectorIri(dimensionValues) { if (dimensionValues.length != 8) { throw new Error("wrong dimensionality, expected 8, got " + dimensionValues.length); } let result = ""; for (let i = 0; i < 8; i++) { result += DimensionVector.DIMENSIONS[i] + DimensionVector.iriFormat(dimensionValues[i]); } return "http://qudt.org/vocab/dimensionvector/" + result; } static noNegativeZero(f) { if (f === -0.0) { return 0.0; } return f; } static iriFormat(dimensionValue) { // Note: This handles a weird case where you may have "-0" as a value. if (Math.abs(dimensionValue) < 0.01) { return "0"; } return DimensionVector.FORMAT.format(dimensionValue).replace(".", "pt"); } isDimensionless() { return this.equals(DimensionVector.DIMENSIONLESS); } getDimensionVectorIri() { return this.dimensionVectorIri; } getValues() { return this.values; } getAmountOfSubstanceExponent() { return this.values[DimensionVector.INDEX_AMOUNT_OF_SUBSTANCE]; } getElectricCurrentExponent() { return this.values[DimensionVector.INDEX_ELECTRIC_CURRENT]; } getLenghExponent() { return this.values[DimensionVector.INDEX_LENGTH]; } getLuminousIntensityExponent() { return this.values[DimensionVector.INDEX_LUMINOUS_INTENSITY]; } getMassExponent() { return this.values[DimensionVector.INDEX_MASS]; } getTemperatureExponent() { return this.values[DimensionVector.INDEX_TEMPERATURE]; } getTimeExponent() { return this.values[DimensionVector.INDEX_TIME]; } multiply(by) { const mult = []; let isRatio = true; for (let i = 0; i < 7; i++) { const multDim = DimensionVector.noNegativeZero(this.values[i] * by); mult.push(multDim); if (multDim != 0) { isRatio = false; } } mult.push(0); DimensionVector.setRatio(mult, isRatio); return new DimensionVector(mult); } static setRatio(values, isRatio) { values[7] = isRatio ? 1 : 0; } combine(other) { const combined = []; let isRatio = true; for (let i = 0; i < 7; i++) { combined[i] = DimensionVector.noNegativeZero(this.values[i] + other.getValues()[i]); if (combined[i] != 0) { isRatio = false; } } DimensionVector.setRatio(combined, isRatio); return new DimensionVector(combined); } equals(o) { if (isNullish(o)) { return false; } if (this === o) return true; if (!(o instanceof DimensionVector)) return false; const that = o; return (that.getDimensionVectorIri() === this.dimensionVectorIri && this.values.every((v, i) => v === that.getValues()[i])); } } DimensionVector.DIMENSIONS = ["A", "E", "L", "I", "M", "H", "T", "D"]; //public static final DecimalFormat FORMAT = new DecimalFormat("0.#"); DimensionVector.FORMAT = new Intl.NumberFormat("en-US", { useGrouping: false, }); DimensionVector.PT = "pt"; DimensionVector.DIMENSIONLESS = new DimensionVector([ 0, 0, 0, 0, 0, 0, 0, 1, ]); DimensionVector.INDEX_AMOUNT_OF_SUBSTANCE = 0; DimensionVector.INDEX_ELECTRIC_CURRENT = 1; DimensionVector.INDEX_LENGTH = 2; DimensionVector.INDEX_LUMINOUS_INTENSITY = 3; DimensionVector.INDEX_MASS = 4; DimensionVector.INDEX_TEMPERATURE = 5; DimensionVector.INDEX_TIME = 6; //# sourceMappingURL=dimensionVector.js.map