@thi.ng/units 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/unit.d.ts ADDED
@@ -0,0 +1,158 @@
1
+ import { Dimensions, MaybeUnit, NamedUnit, Prefix, Unit } from "./api.js";
2
+ /**
3
+ * Cache/registry for all units defined via {@link defUnit}.
4
+ */
5
+ export declare const UNITS: Record<string, NamedUnit>;
6
+ /**
7
+ * Defines a "raw" (anonymous) unit using given dimension(s), scale factor, zero
8
+ * offset and `coherent` flag indicating if the unit is the coherent one for
9
+ * given dimensions and can later be used for deriving prefixed versions (see
10
+ * {@link coherent}).
11
+ *
12
+ * @param dim
13
+ * @param scale
14
+ * @param offset
15
+ * @param coherent
16
+ */
17
+ export declare const unit: (dim: Dimensions | number, scale: number, offset?: number, coherent?: boolean) => Unit;
18
+ /**
19
+ * Syntax sugar for defining coherent SI base units. See {@link unit}.
20
+ *
21
+ * @param dim
22
+ */
23
+ export declare const coherent: (dim: Dimensions | number) => Unit;
24
+ /**
25
+ * Returns a new dimensionless unit (i.e. all SI dimensions are zero) with given
26
+ * `scale` factor.
27
+ *
28
+ * @param scale
29
+ * @param offset
30
+ * @param coherent
31
+ */
32
+ export declare const dimensionless: (scale: number, offset?: number, coherent?: boolean) => Unit;
33
+ /**
34
+ * Takes a unit symbol, full unit name and pre-defined {@link Unit} impl and
35
+ * registers it in the {@link UNITS} cache for further lookups by symbol name.
36
+ *
37
+ * @remarks
38
+ * By default throws an error if attempting to register a unit with an existing
39
+ * symbol. If `force` is true, the existing unit will be overwritten.
40
+ *
41
+ * @param sym
42
+ * @param name
43
+ * @param unit
44
+ * @param force
45
+ */
46
+ export declare const defUnit: (sym: string, name: string, unit: Unit, force?: boolean) => NamedUnit;
47
+ /**
48
+ * Attempts to find a unit by given symbol ID/name. Throws error if unit is
49
+ * unknown.
50
+ *
51
+ * @param id
52
+ */
53
+ export declare const asUnit: (id: string) => Unit;
54
+ /**
55
+ * Creates a new re-scaled version of given unit (only coherent ones are
56
+ * allowed), using the scale factor associated with given standard metric prefix
57
+ * (see {@link PREFIXES}). If `coherent` is true (default: false), the new unit
58
+ * itself is considered coherent and can be prefixed later.
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * // create kilometer unit from (builtin) meter
63
+ * const KM = prefix("k", M);
64
+ * ```
65
+ *
66
+ * @param id
67
+ * @param unit
68
+ * @param coherent
69
+ */
70
+ export declare const prefix: (id: Prefix, unit: MaybeUnit, coherent?: boolean) => Unit;
71
+ /**
72
+ * Derives a new unit as the product of the given units. If `coherent` is true
73
+ * (default: false), the new unit itself is considered coherent and can be
74
+ * prefixed later.
75
+ *
76
+ * @param a
77
+ * @param b
78
+ * @param coherent
79
+ */
80
+ export declare const mul: (a: MaybeUnit, b: MaybeUnit | number, coherent?: boolean) => Unit;
81
+ /**
82
+ * Derives a new unit via the division of the given units. If `coherent` is true
83
+ * (default: false), the new unit itself is considered coherent and can be
84
+ * prefixed later.
85
+ *
86
+ * @param a
87
+ * @param b
88
+ * @param coherent
89
+ */
90
+ export declare const div: (a: MaybeUnit, b: MaybeUnit | number, coherent?: boolean) => Unit;
91
+ /**
92
+ * Creates the reciprocal version of given unit (i.e. all SI dimensions will
93
+ * flip sign) and the scale factor of the new unit will be `1/scale`. If
94
+ * `coherent` is true (default: false), the new unit itself is considered
95
+ * coherent and can be prefixed later.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * const HZ = reciprocal(S, true);
100
+ * ```
101
+ *
102
+ * @param u
103
+ * @param coherent
104
+ */
105
+ export declare const reciprocal: (u: MaybeUnit, coherent?: boolean) => Unit;
106
+ /**
107
+ * Raises given unit to power `k`. If `coherent` is true (default: false), the
108
+ * new unit itself is considered coherent and can be prefixed later.
109
+ *
110
+ * ```ts
111
+ * // create kilometer unit from (builtin) meter
112
+ * const SQ_METER = pow(M, 2);
113
+ *
114
+ * // acceleration aka m/s^2
115
+ * const M_S2 = div(M, pow(S, 2));
116
+ * ```
117
+ *
118
+ * @param u
119
+ * @param k
120
+ * @param coherent
121
+ */
122
+ export declare const pow: (u: MaybeUnit, k: number, coherent?: boolean) => Unit;
123
+ /**
124
+ * Attempts to convert `x` from `src` unit into `dest` unit. Throws an error if
125
+ * units are incompatible.
126
+ *
127
+ * @remarks
128
+ * Units can only be converted if their SI dimensions are compatible. See
129
+ * {@link isConvertible}.
130
+ *
131
+ * @param x
132
+ * @param src
133
+ * @param dest
134
+ */
135
+ export declare const convert: (x: number, src: MaybeUnit, dest: MaybeUnit) => number;
136
+ /**
137
+ * Returns true if `src` unit is convertible to `dest`.
138
+ *
139
+ * @param src
140
+ * @param dest
141
+ */
142
+ export declare const isConvertible: (src: MaybeUnit, dest: MaybeUnit) => boolean;
143
+ /**
144
+ * Returns true, if `u` is a dimensionless unit.
145
+ *
146
+ * @param u
147
+ */
148
+ export declare const isDimensionless: (u: MaybeUnit) => boolean;
149
+ /**
150
+ * Returns true if the two given units are reciprocal to each other (and
151
+ * therefore can be used for conversion).
152
+ *
153
+ * @param a
154
+ * @param b
155
+ */
156
+ export declare const isReciprocal: (a: MaybeUnit, b: MaybeUnit) => boolean;
157
+ export declare const formatSI: (u: MaybeUnit) => string;
158
+ //# sourceMappingURL=unit.d.ts.map
package/unit.js ADDED
@@ -0,0 +1,252 @@
1
+ import { isNumber } from "@thi.ng/checks/is-number";
2
+ import { isString } from "@thi.ng/checks/is-string";
3
+ import { equivArrayLike } from "@thi.ng/equiv";
4
+ import { assert } from "@thi.ng/errors/assert";
5
+ import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
6
+ import { PREFIXES, } from "./api.js";
7
+ /**
8
+ * Cache/registry for all units defined via {@link defUnit}.
9
+ */
10
+ export const UNITS = {};
11
+ /**
12
+ * Defines a "raw" (anonymous) unit using given dimension(s), scale factor, zero
13
+ * offset and `coherent` flag indicating if the unit is the coherent one for
14
+ * given dimensions and can later be used for deriving prefixed versions (see
15
+ * {@link coherent}).
16
+ *
17
+ * @param dim
18
+ * @param scale
19
+ * @param offset
20
+ * @param coherent
21
+ */
22
+ export const unit = (dim, scale, offset = 0, coherent = false) => ({
23
+ dim: isNumber(dim) ? __oneHot(dim) : dim,
24
+ scale,
25
+ offset,
26
+ coherent,
27
+ });
28
+ /**
29
+ * Syntax sugar for defining coherent SI base units. See {@link unit}.
30
+ *
31
+ * @param dim
32
+ */
33
+ export const coherent = (dim) => unit(dim, 1, 0, true);
34
+ /**
35
+ * Returns a new dimensionless unit (i.e. all SI dimensions are zero) with given
36
+ * `scale` factor.
37
+ *
38
+ * @param scale
39
+ * @param offset
40
+ * @param coherent
41
+ */
42
+ export const dimensionless = (scale, offset = 0, coherent = false) => unit([0, 0, 0, 0, 0, 0, 0], scale, offset, coherent);
43
+ /**
44
+ * Takes a unit symbol, full unit name and pre-defined {@link Unit} impl and
45
+ * registers it in the {@link UNITS} cache for further lookups by symbol name.
46
+ *
47
+ * @remarks
48
+ * By default throws an error if attempting to register a unit with an existing
49
+ * symbol. If `force` is true, the existing unit will be overwritten.
50
+ *
51
+ * @param sym
52
+ * @param name
53
+ * @param unit
54
+ * @param force
55
+ */
56
+ export const defUnit = (sym, name, unit, force = false) => {
57
+ if (UNITS[sym] && !force)
58
+ illegalArgs(`attempt to override unit: ${sym}`);
59
+ return (UNITS[sym] = { ...unit, sym, name });
60
+ };
61
+ /**
62
+ * Attempts to find a unit by given symbol ID/name. Throws error if unit is
63
+ * unknown.
64
+ *
65
+ * @param id
66
+ */
67
+ export const asUnit = (id) => {
68
+ for (let i = 0; i < id.length; i++) {
69
+ const pre = id.substring(0, i);
70
+ const unit = UNITS[id.substring(i)];
71
+ if (unit) {
72
+ return PREFIXES[pre] !== undefined
73
+ ? prefix(pre, unit)
74
+ : unit;
75
+ }
76
+ }
77
+ for (let u in UNITS) {
78
+ if (UNITS[u].name === id)
79
+ return UNITS[u];
80
+ }
81
+ illegalArgs(`unknown unit: ${id}`);
82
+ };
83
+ /**
84
+ * Creates a new re-scaled version of given unit (only coherent ones are
85
+ * allowed), using the scale factor associated with given standard metric prefix
86
+ * (see {@link PREFIXES}). If `coherent` is true (default: false), the new unit
87
+ * itself is considered coherent and can be prefixed later.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * // create kilometer unit from (builtin) meter
92
+ * const KM = prefix("k", M);
93
+ * ```
94
+ *
95
+ * @param id
96
+ * @param unit
97
+ * @param coherent
98
+ */
99
+ export const prefix = (id, unit, coherent = false) => {
100
+ const $u = __ensureUnit(unit);
101
+ return $u.coherent
102
+ ? mul($u, PREFIXES[id], coherent)
103
+ : illegalArgs("unit isn't coherent");
104
+ };
105
+ /**
106
+ * Derives a new unit as the product of the given units. If `coherent` is true
107
+ * (default: false), the new unit itself is considered coherent and can be
108
+ * prefixed later.
109
+ *
110
+ * @param a
111
+ * @param b
112
+ * @param coherent
113
+ */
114
+ export const mul = (a, b, coherent = false) => {
115
+ const $a = __ensureUnit(a);
116
+ if (isNumber(b)) {
117
+ return unit($a.dim, $a.scale * b, $a.offset, coherent);
118
+ }
119
+ const $b = __ensureUnit(b);
120
+ return unit($a.dim.map((x, i) => x + $b.dim[i]), $a.scale * $b.scale, 0, coherent);
121
+ };
122
+ /**
123
+ * Derives a new unit via the division of the given units. If `coherent` is true
124
+ * (default: false), the new unit itself is considered coherent and can be
125
+ * prefixed later.
126
+ *
127
+ * @param a
128
+ * @param b
129
+ * @param coherent
130
+ */
131
+ export const div = (a, b, coherent = false) => {
132
+ const $a = __ensureUnit(a);
133
+ if (isNumber(b)) {
134
+ return unit($a.dim, $a.scale / b, $a.offset, coherent);
135
+ }
136
+ const $b = __ensureUnit(b);
137
+ return unit($a.dim.map((x, i) => x - $b.dim[i]), $a.scale / $b.scale, 0, coherent);
138
+ };
139
+ /**
140
+ * Creates the reciprocal version of given unit (i.e. all SI dimensions will
141
+ * flip sign) and the scale factor of the new unit will be `1/scale`. If
142
+ * `coherent` is true (default: false), the new unit itself is considered
143
+ * coherent and can be prefixed later.
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * const HZ = reciprocal(S, true);
148
+ * ```
149
+ *
150
+ * @param u
151
+ * @param coherent
152
+ */
153
+ export const reciprocal = (u, coherent = false) => div(dimensionless(1), u, coherent);
154
+ /**
155
+ * Raises given unit to power `k`. If `coherent` is true (default: false), the
156
+ * new unit itself is considered coherent and can be prefixed later.
157
+ *
158
+ * ```ts
159
+ * // create kilometer unit from (builtin) meter
160
+ * const SQ_METER = pow(M, 2);
161
+ *
162
+ * // acceleration aka m/s^2
163
+ * const M_S2 = div(M, pow(S, 2));
164
+ * ```
165
+ *
166
+ * @param u
167
+ * @param k
168
+ * @param coherent
169
+ */
170
+ export const pow = (u, k, coherent = false) => {
171
+ const $u = __ensureUnit(u);
172
+ return unit($u.dim.map((x) => x * k), $u.scale ** k, 0, coherent);
173
+ };
174
+ /**
175
+ * Attempts to convert `x` from `src` unit into `dest` unit. Throws an error if
176
+ * units are incompatible.
177
+ *
178
+ * @remarks
179
+ * Units can only be converted if their SI dimensions are compatible. See
180
+ * {@link isConvertible}.
181
+ *
182
+ * @param x
183
+ * @param src
184
+ * @param dest
185
+ */
186
+ export const convert = (x, src, dest) => {
187
+ const $src = __ensureUnit(src);
188
+ const $dest = __ensureUnit(dest);
189
+ const xnorm = x * $src.scale + $src.offset;
190
+ if (isReciprocal($src, $dest))
191
+ return (1 / xnorm - $dest.offset) / $dest.scale;
192
+ assert(equivArrayLike($src.dim, $dest.dim), "incompatible dimensions");
193
+ return (xnorm - $dest.offset) / $dest.scale;
194
+ };
195
+ /**
196
+ * Returns true if `src` unit is convertible to `dest`.
197
+ *
198
+ * @param src
199
+ * @param dest
200
+ */
201
+ export const isConvertible = (src, dest) => {
202
+ const $src = __ensureUnit(src);
203
+ const $dest = __ensureUnit(dest);
204
+ return isReciprocal($src, $dest) || equivArrayLike($src.dim, $dest.dim);
205
+ };
206
+ /**
207
+ * Returns true, if `u` is a dimensionless unit.
208
+ *
209
+ * @param u
210
+ */
211
+ export const isDimensionless = (u) => __ensureUnit(u).dim.every((x) => x === 0);
212
+ /**
213
+ * Returns true if the two given units are reciprocal to each other (and
214
+ * therefore can be used for conversion).
215
+ *
216
+ * @param a
217
+ * @param b
218
+ */
219
+ export const isReciprocal = (a, b) => {
220
+ const { dim: $a } = __ensureUnit(a);
221
+ const { dim: $b } = __ensureUnit(b);
222
+ let ok = false;
223
+ for (let i = 0; i < 7; i++) {
224
+ const xa = $a[i];
225
+ const xb = $b[i];
226
+ if (xa === 0 && xb === 0)
227
+ continue;
228
+ if (xa !== -xb)
229
+ return false;
230
+ ok = true;
231
+ }
232
+ return ok;
233
+ };
234
+ export const formatSI = (u) => {
235
+ const { dim } = __ensureUnit(u);
236
+ const SI = ["kg", "m", "s", "A", "K", "mol", "cd"];
237
+ const acc = [];
238
+ for (let i = 0; i < 7; i++) {
239
+ const x = dim[i];
240
+ if (x !== 0)
241
+ acc.push(SI[i] + (x !== 1 ? x : ""));
242
+ }
243
+ return acc.length ? acc.join("·") : "<dimensionless>";
244
+ };
245
+ /** @internal */
246
+ const __ensureUnit = (x) => (isString(x) ? asUnit(x) : x);
247
+ /** @internal */
248
+ const __oneHot = (x) => {
249
+ const dims = new Array(7).fill(0);
250
+ dims[x] = 1;
251
+ return dims;
252
+ };
package/volume.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ export declare const m3: import("./api.js").NamedUnit;
2
+ export declare const mm3: import("./api.js").NamedUnit;
3
+ export declare const cm3: import("./api.js").NamedUnit;
4
+ export declare const km3: import("./api.js").NamedUnit;
5
+ export declare const l: import("./api.js").NamedUnit;
6
+ export declare const cl: import("./api.js").NamedUnit;
7
+ export declare const ml: import("./api.js").NamedUnit;
8
+ export declare const gal: import("./api.js").NamedUnit;
9
+ export declare const pt: import("./api.js").NamedUnit;
10
+ export declare const floz: import("./api.js").NamedUnit;
11
+ export declare const us_gal: import("./api.js").NamedUnit;
12
+ export declare const us_pt: import("./api.js").NamedUnit;
13
+ export declare const us_cup: import("./api.js").NamedUnit;
14
+ export declare const us_floz: import("./api.js").NamedUnit;
15
+ //# sourceMappingURL=volume.d.ts.map
package/volume.js ADDED
@@ -0,0 +1,16 @@
1
+ import { cm, km, m, mm } from "./length.js";
2
+ import { defUnit, mul, pow, prefix } from "./unit.js";
3
+ export const m3 = defUnit("m3", "cubic meter", pow(m, 3));
4
+ export const mm3 = defUnit("mm3", "cubic millimeter", pow(mm, 3));
5
+ export const cm3 = defUnit("cm3", "cubic centimeter", pow(cm, 3));
6
+ export const km3 = defUnit("km3", "cubic kilometer", pow(km, 3));
7
+ export const l = defUnit("l", "liter", mul(m3, 1e-3, true));
8
+ export const cl = defUnit("cl", "centiliter", prefix("c", l));
9
+ export const ml = defUnit("ml", "milliliter", prefix("m", l));
10
+ export const gal = defUnit("gal", "imperial gallon", mul(l, 4.54609));
11
+ export const pt = defUnit("pt", "imperial pint", mul(gal, 1 / 8));
12
+ export const floz = defUnit("fl oz", "imperial fluid ounce", mul(gal, 1 / 160));
13
+ export const us_gal = defUnit("us gal", "us gallon", mul(l, 3.785411784));
14
+ export const us_pt = defUnit("us pt", "us pint", mul(us_gal, 1 / 8));
15
+ export const us_cup = defUnit("us cup", "us cup", mul(us_gal, 1 / 16));
16
+ export const us_floz = defUnit("us fl oz", "us fluid ounce", mul(us_gal, 1 / 128));