pts 1.0.1 → 1.0.2
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/dist/index.d.mts +9 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3930 -3879
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3930 -3879
- package/dist/index.mjs.map +1 -1
- package/dist/pts.js +3961 -3910
- package/dist/pts.js.map +1 -1
- package/dist/pts.min.js +2 -2
- package/dist/pts.min.js.map +1 -1
- package/package.json +1 -1
- package/src/Color.ts +48 -28
- package/src/Create.ts +2 -1
- package/src/LinearAlgebra.ts +7 -6
- package/src/Num.ts +15 -10
- package/src/Svg.ts +3 -3
- package/src/UI.ts +21 -1
- package/src/Util.ts +23 -1
- package/src/_triangulate.ts +36 -15
package/package.json
CHANGED
package/src/Color.ts
CHANGED
|
@@ -5,6 +5,32 @@ import { Util } from "./Util";
|
|
|
5
5
|
import { Num, Geom } from "./Num";
|
|
6
6
|
import { type PtLike, type ColorType } from "./Types";
|
|
7
7
|
|
|
8
|
+
// Module state behind Color's static accessors: a static field would be
|
|
9
|
+
// emitted as an assignment after the class, which bundlers keep, and with it
|
|
10
|
+
// the class and everything it references (see Util.ts). The initializers are
|
|
11
|
+
// marked pure so a bundle without Color drops them. Internal code reads
|
|
12
|
+
// `Color.ranges`, not `_colorRanges`, so redefining the static still reaches
|
|
13
|
+
// the conversions.
|
|
14
|
+
|
|
15
|
+
// XYZ property for Standard Observer 2deg, Daylight/sRGB illuminant D65
|
|
16
|
+
const D65 = /* @__PURE__ */ new Pt(95.047, 100, 108.883, 1);
|
|
17
|
+
|
|
18
|
+
let _colorRanges: { [name: string]: Group } = /* @__PURE__ */ colorRanges();
|
|
19
|
+
|
|
20
|
+
function colorRanges(): { [name: string]: Group } {
|
|
21
|
+
return {
|
|
22
|
+
rgb: new Group(new Pt(0, 255), new Pt(0, 255), new Pt(0, 255)),
|
|
23
|
+
hsl: new Group(new Pt(0, 360), new Pt(0, 1), new Pt(0, 1)),
|
|
24
|
+
hsb: new Group(new Pt(0, 360), new Pt(0, 1), new Pt(0, 1)),
|
|
25
|
+
lab: new Group(new Pt(0, 100), new Pt(-128, 127), new Pt(-128, 127)),
|
|
26
|
+
lch: new Group(new Pt(0, 100), new Pt(0, 100), new Pt(0, 360)),
|
|
27
|
+
luv: new Group(new Pt(0, 100), new Pt(-134, 220), new Pt(-140, 122)),
|
|
28
|
+
xyz: new Group(new Pt(0, 100), new Pt(0, 100), new Pt(0, 100)),
|
|
29
|
+
oklab: new Group(new Pt(0, 1), new Pt(-0.4, 0.4), new Pt(-0.4, 0.4)),
|
|
30
|
+
oklch: new Group(new Pt(0, 1), new Pt(0, 0.4), new Pt(0, 360)),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
8
34
|
/**
|
|
9
35
|
* Color is a subclass of Pt. Since a color in a color space is analogous to a point or vector in a space, you can apply all Pt operations to colors too. The Color class provides support for many color spaces like HSL and LAB.
|
|
10
36
|
* Convert non-RGB colors to RGB before using `.hex`, `.rgb`, or `.rgba` for rendering. These getters format the channels; they don't convert between color spaces.
|
|
@@ -15,26 +41,28 @@ import { type PtLike, type ColorType } from "./Types";
|
|
|
15
41
|
* ```
|
|
16
42
|
*/
|
|
17
43
|
export class Color extends Pt {
|
|
18
|
-
// XYZ property for Standard Observer 2deg, Daylight/sRGB illuminant D65
|
|
19
|
-
private static D65: PtLike = new Pt(95.047, 100, 108.883, 1);
|
|
20
|
-
|
|
21
44
|
protected _mode: ColorType = "rgb";
|
|
22
45
|
private _isNorm: boolean = false;
|
|
23
46
|
|
|
24
47
|
/**
|
|
25
48
|
* Value range for each color space
|
|
26
49
|
*/
|
|
27
|
-
static ranges: { [name: string]: Group }
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
static get ranges(): { [name: string]: Group } {
|
|
51
|
+
return _colorRanges;
|
|
52
|
+
}
|
|
53
|
+
static set ranges(value: { [name: string]: Group }) {
|
|
54
|
+
// as with a static field, an assignment on a subclass stays on the subclass
|
|
55
|
+
if (this === Color) {
|
|
56
|
+
_colorRanges = value;
|
|
57
|
+
} else {
|
|
58
|
+
Object.defineProperty(this, "ranges", {
|
|
59
|
+
value,
|
|
60
|
+
writable: true,
|
|
61
|
+
enumerable: true,
|
|
62
|
+
configurable: true,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
38
66
|
|
|
39
67
|
/**
|
|
40
68
|
* Create a Color. Same as creating a Pt. Optionally you may use [`Color.from`](#link) to create a color.
|
|
@@ -779,7 +807,7 @@ export class Color extends Pt {
|
|
|
779
807
|
const kap = 24389 / 27;
|
|
780
808
|
|
|
781
809
|
// adjust for D65
|
|
782
|
-
c.divide(
|
|
810
|
+
c.divide(D65);
|
|
783
811
|
|
|
784
812
|
const fn = (n: number) => (n > eps ? Math.cbrt(n) : (kap * n + 16) / 116);
|
|
785
813
|
const cy = fn(c[1]);
|
|
@@ -812,7 +840,7 @@ export class Color extends Pt {
|
|
|
812
840
|
const eps = 216 / 24389;
|
|
813
841
|
const kap = 24389 / 27;
|
|
814
842
|
|
|
815
|
-
const d =
|
|
843
|
+
const d = D65;
|
|
816
844
|
const xxx = Math.pow(x, 3);
|
|
817
845
|
const zzz = Math.pow(z, 3);
|
|
818
846
|
|
|
@@ -850,12 +878,8 @@ export class Color extends Pt {
|
|
|
850
878
|
y = y / 100;
|
|
851
879
|
const L = y > eps ? 116 * Math.cbrt(y) - 16 : kap * y;
|
|
852
880
|
|
|
853
|
-
const refU =
|
|
854
|
-
|
|
855
|
-
(Color.D65[0] + 15 * Color.D65[1] + 3 * Color.D65[2]);
|
|
856
|
-
const refV =
|
|
857
|
-
(9 * Color.D65[1]) /
|
|
858
|
-
(Color.D65[0] + 15 * Color.D65[1] + 3 * Color.D65[2]);
|
|
881
|
+
const refU = (4 * D65[0]) / (D65[0] + 15 * D65[1] + 3 * D65[2]);
|
|
882
|
+
const refV = (9 * D65[1]) / (D65[0] + 15 * D65[1] + 3 * D65[2]);
|
|
859
883
|
|
|
860
884
|
const cc = Color.luv(
|
|
861
885
|
L,
|
|
@@ -891,12 +915,8 @@ export class Color extends Pt {
|
|
|
891
915
|
const fy = (l + 16) / 116;
|
|
892
916
|
let y = l > kap * eps ? fy * fy * fy : l / kap;
|
|
893
917
|
|
|
894
|
-
const refU =
|
|
895
|
-
|
|
896
|
-
(Color.D65[0] + 15 * Color.D65[1] + 3 * Color.D65[2]);
|
|
897
|
-
const refV =
|
|
898
|
-
(9 * Color.D65[1]) /
|
|
899
|
-
(Color.D65[0] + 15 * Color.D65[1] + 3 * Color.D65[2]);
|
|
918
|
+
const refU = (4 * D65[0]) / (D65[0] + 15 * D65[1] + 3 * D65[2]);
|
|
919
|
+
const refV = (9 * D65[1]) / (D65[0] + 15 * D65[1] + 3 * D65[2]);
|
|
900
920
|
|
|
901
921
|
u = u / (13 * l) + refU;
|
|
902
922
|
v = v / (13 * l) + refV;
|
package/src/Create.ts
CHANGED
|
@@ -261,7 +261,8 @@ const __noise_permTable = [
|
|
|
261
261
|
// The doubled base permutation table, built once and shared by every unseeded
|
|
262
262
|
// Noise instance (a per-instance copy would allocate 512 entries per point in
|
|
263
263
|
// `Create.noisePts`). `seed()` swaps in a seeded table instead of mutating.
|
|
264
|
-
const __noise_permDoubled =
|
|
264
|
+
const __noise_permDoubled =
|
|
265
|
+
/* @__PURE__ */ __noise_permTable.concat(__noise_permTable);
|
|
265
266
|
|
|
266
267
|
// Memoize the last seeded table: `Create.noisePts` seeds every point with the
|
|
267
268
|
// same value, so all its Noise Pts share one table.
|
package/src/LinearAlgebra.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/*! Pts.js is licensed under Apache License 2.0. Copyright © 2017-current William Ngan and contributors. (https://github.com/williamngan/pts) */
|
|
2
2
|
|
|
3
3
|
import { Pt, Group } from "./Pt";
|
|
4
|
-
import { Line } from "./Op";
|
|
5
4
|
import { type PtLike, type GroupLike } from "./Types";
|
|
6
5
|
|
|
7
6
|
/**
|
|
@@ -506,17 +505,19 @@ export class Mat {
|
|
|
506
505
|
* @param p1 second end point to define the reflection line
|
|
507
506
|
*/
|
|
508
507
|
static reflectAt2DMatrix(p1: PtLike, p2: PtLike) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
508
|
+
// The slope and y-intercept as `Line.intercept` computes them, inlined so
|
|
509
|
+
// this module does not import Op: a Pt-only bundle would otherwise keep
|
|
510
|
+
// every geometry class.
|
|
511
|
+
if (p2[0] - p1[0] === 0) {
|
|
512
512
|
return [
|
|
513
513
|
new Pt([-1, 0, 0]),
|
|
514
514
|
new Pt([0, 1, 0]),
|
|
515
515
|
new Pt([p1[0] + p2[0], 0, 1]),
|
|
516
516
|
];
|
|
517
517
|
} else {
|
|
518
|
-
const
|
|
519
|
-
const
|
|
518
|
+
const slope = (p2[1] - p1[1]) / (p2[0] - p1[0]);
|
|
519
|
+
const yi = p1[1] - slope * p1[0];
|
|
520
|
+
const ang2 = Math.atan(slope) * 2;
|
|
520
521
|
const cosA = Math.cos(ang2);
|
|
521
522
|
const sinA = Math.sin(ang2);
|
|
522
523
|
|
package/src/Num.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/*! Pts.js is licensed under Apache License 2.0. Copyright © 2017-current William Ngan and contributors. (https://github.com/williamngan/pts) */
|
|
2
2
|
|
|
3
3
|
import { Const, Util } from "./Util";
|
|
4
|
-
import { Curve } from "./Op";
|
|
5
4
|
import { Pt, Group } from "./Pt";
|
|
6
5
|
import { Vec, Mat } from "./LinearAlgebra";
|
|
7
6
|
import {
|
|
@@ -890,7 +889,7 @@ export class Shaping {
|
|
|
890
889
|
}
|
|
891
890
|
|
|
892
891
|
/**
|
|
893
|
-
* Cubic bezier curve
|
|
892
|
+
* Cubic bezier curve from (0, 0) to (1, 1) with two control points. Note that `t` is the curve parameter, not the x position: unlike CSS `cubic-bezier(...)`, this returns the curve's y value at parameter `t` rather than solving y at x = t.
|
|
894
893
|
* @param t a value between 0 to 1
|
|
895
894
|
* @param c the value to shape, default is 1
|
|
896
895
|
* @param p1` a Pt object specifying the first control Pt. Default is `Pt(0.1, 0.7).
|
|
@@ -902,14 +901,20 @@ export class Shaping {
|
|
|
902
901
|
p1: PtLike = [0.1, 0.7],
|
|
903
902
|
p2: PtLike = [0.9, 0.2],
|
|
904
903
|
): number {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
);
|
|
904
|
+
// `Curve.bezierStep` on the controls (0, 0), p1, p2, (1, 1), inlined so
|
|
905
|
+
// this module does not import Op (a Pt-only bundle would otherwise keep
|
|
906
|
+
// every geometry class). The float32 rounding of that Pt-based evaluation
|
|
907
|
+
// is kept: the powers of t, the control values and the result are float32,
|
|
908
|
+
// and the weighted sum has the same terms in the same order.
|
|
909
|
+
const t3 = Math.fround(t * t * t);
|
|
910
|
+
const t2 = Math.fround(t * t);
|
|
911
|
+
const t1 = Math.fround(t);
|
|
912
|
+
const y =
|
|
913
|
+
(-t3 + 3 * t2 - 3 * t1 + 1) * 0 +
|
|
914
|
+
(3 * t3 - 6 * t2 + 3 * t1) * new Pt(p1)[1] +
|
|
915
|
+
(-3 * t3 + 3 * t2) * new Pt(p2)[1] +
|
|
916
|
+
t3 * 1;
|
|
917
|
+
return c * Math.fround(y);
|
|
913
918
|
}
|
|
914
919
|
|
|
915
920
|
/**
|
package/src/Svg.ts
CHANGED
|
@@ -963,6 +963,7 @@ export class SVGSpace extends DOMSpace {
|
|
|
963
963
|
|
|
964
964
|
let _svgFormGroupID = 0;
|
|
965
965
|
let _svgFormDomID = 0;
|
|
966
|
+
let _svgFormOffscreenWarned = false;
|
|
966
967
|
|
|
967
968
|
// rendering-context style keys and their legacy inline-style names
|
|
968
969
|
const _legacyStyleKeys: Record<string, string> = {
|
|
@@ -1081,10 +1082,9 @@ export class SVGForm extends CanvasForm<SVGSpace> {
|
|
|
1081
1082
|
SVGForm._warnOffscreen();
|
|
1082
1083
|
}
|
|
1083
1084
|
|
|
1084
|
-
private static _offscreenWarned = false;
|
|
1085
1085
|
private static _warnOffscreen() {
|
|
1086
|
-
if (
|
|
1087
|
-
|
|
1086
|
+
if (_svgFormOffscreenWarned) return;
|
|
1087
|
+
_svgFormOffscreenWarned = true;
|
|
1088
1088
|
Util.warn(
|
|
1089
1089
|
"offscreen canvases are not supported in SVG output; use CanvasSpace",
|
|
1090
1090
|
);
|
package/src/UI.ts
CHANGED
|
@@ -98,6 +98,11 @@ export const UIPointerActions = {
|
|
|
98
98
|
export type UIPointerAction =
|
|
99
99
|
(typeof UIPointerActions)[keyof typeof UIPointerActions];
|
|
100
100
|
|
|
101
|
+
// module state behind the `_counter` accessor, so no static field assignment
|
|
102
|
+
// follows the class (which would defeat tree-shaking); internal code still
|
|
103
|
+
// uses `UI._counter` (see Util.ts)
|
|
104
|
+
let _uiCounter = 0;
|
|
105
|
+
|
|
101
106
|
/**
|
|
102
107
|
* **[Experimental]** An abstract class that represents an UI element. It wraps a [`Group`](#link) and supports UI event handling.
|
|
103
108
|
* Extend this class to create custom UI elements.
|
|
@@ -107,7 +112,22 @@ export class UI {
|
|
|
107
112
|
_group: Group;
|
|
108
113
|
_shape: string;
|
|
109
114
|
|
|
110
|
-
protected static _counter: number
|
|
115
|
+
protected static get _counter(): number {
|
|
116
|
+
return _uiCounter;
|
|
117
|
+
}
|
|
118
|
+
protected static set _counter(n: number) {
|
|
119
|
+
// as with a static field, an assignment on a subclass stays on the subclass
|
|
120
|
+
if (this === UI) {
|
|
121
|
+
_uiCounter = n;
|
|
122
|
+
} else {
|
|
123
|
+
Object.defineProperty(this, "_counter", {
|
|
124
|
+
value: n,
|
|
125
|
+
writable: true,
|
|
126
|
+
enumerable: true,
|
|
127
|
+
configurable: true,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
111
131
|
protected _id: string;
|
|
112
132
|
protected _actions: { [type: string]: (UIHandler | null)[] };
|
|
113
133
|
// built-in machinery (UIButton hover, UIDragger drag) registers here, so
|
package/src/Util.ts
CHANGED
|
@@ -94,11 +94,33 @@ export const Const = {
|
|
|
94
94
|
gaussian: 0.3989422804014327,
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
+
// Mutable statics live in module state behind accessors: a static field would
|
|
98
|
+
// be emitted as an assignment after the class, which bundlers keep, and with
|
|
99
|
+
// it the class and everything it references (see Svg.ts). Internal code still
|
|
100
|
+
// goes through the public static, so redefining it (Object.defineProperty, an
|
|
101
|
+
// assignment through a Proxy) takes effect as it did with a field.
|
|
102
|
+
let _utilWarnLevel: WarningType = "mute";
|
|
103
|
+
|
|
97
104
|
/**
|
|
98
105
|
* Util class provides static helper functions.
|
|
99
106
|
*/
|
|
100
107
|
export class Util {
|
|
101
|
-
static _warnLevel: WarningType
|
|
108
|
+
static get _warnLevel(): WarningType {
|
|
109
|
+
return _utilWarnLevel;
|
|
110
|
+
}
|
|
111
|
+
static set _warnLevel(lv: WarningType) {
|
|
112
|
+
// as with a static field, an assignment on a subclass stays on the subclass
|
|
113
|
+
if (this === Util) {
|
|
114
|
+
_utilWarnLevel = lv;
|
|
115
|
+
} else {
|
|
116
|
+
Object.defineProperty(this, "_warnLevel", {
|
|
117
|
+
value: lv,
|
|
118
|
+
writable: true,
|
|
119
|
+
enumerable: true,
|
|
120
|
+
configurable: true,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
102
124
|
|
|
103
125
|
/**
|
|
104
126
|
* Set a global warning level setting. If no parameter is passed, this will return the current warn-level. See [`Util.warn`](#link).
|
package/src/_triangulate.ts
CHANGED
|
@@ -43,9 +43,12 @@ const EMPTY: Triangulation = {
|
|
|
43
43
|
const EPS = 1.1102230246251565e-16;
|
|
44
44
|
// Bounds on the rounding error of the determinants below, relative to the sum
|
|
45
45
|
// of the absolute values of their terms (the classic forward error analysis
|
|
46
|
-
// of the orientation and in-circle determinants).
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
// of the orientation and in-circle determinants). Computed through a function
|
|
47
|
+
// marked pure so bundles that never triangulate drop them: a bundler that
|
|
48
|
+
// turns these consts into vars cannot prove the bare products side-effect free.
|
|
49
|
+
const errorBound = (a: number, b: number) => (a + b * EPS) * EPS;
|
|
50
|
+
const ORIENT_BOUND = /* @__PURE__ */ errorBound(3, 16);
|
|
51
|
+
const INCIRCLE_BOUND = /* @__PURE__ */ errorBound(10, 96);
|
|
49
52
|
// Coordinates that become integers below 2^31 when scaled by one power of two
|
|
50
53
|
// (pixel grids, halves, quarters, every Float32 value in a sane range) keep
|
|
51
54
|
// their differences exact in a double; the products those differences form are
|
|
@@ -322,15 +325,28 @@ function _incircleInt(
|
|
|
322
325
|
// Exact evaluation: each double is sign * mantissa * 2^exponent with an
|
|
323
326
|
// integer mantissa, so scaling every input to the smallest exponent gives
|
|
324
327
|
// exact integers whose determinant has the same sign as the real one.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const
|
|
328
|
+
// Views over one buffer, and the indices of the words holding a double's
|
|
329
|
+
// high bits (sign, exponent, top of the mantissa) and low bits. Every
|
|
330
|
+
// initializer is a call marked pure, so a bundle that never triangulates
|
|
331
|
+
// drops all of it (a bundler cannot prove `HI ^ 1` free of side effects).
|
|
332
|
+
const _buffer = /* @__PURE__ */ new ArrayBuffer(8);
|
|
333
|
+
const _bits = /* @__PURE__ */ new Float64Array(_buffer);
|
|
334
|
+
const _words = /* @__PURE__ */ new Uint32Array(_buffer);
|
|
335
|
+
const HI = /* @__PURE__ */ wordIndex(true);
|
|
336
|
+
const LO = /* @__PURE__ */ wordIndex(false);
|
|
337
|
+
|
|
338
|
+
function wordIndex(high: boolean): number {
|
|
339
|
+
// little-endian hosts store the high word of 1.0 (0x3ff00000) second
|
|
340
|
+
const probe = new Float64Array([1]);
|
|
341
|
+
const highSecond = new Uint32Array(probe.buffer)[1] === 0x3ff00000;
|
|
342
|
+
return high === highSecond ? 1 : 0;
|
|
343
|
+
}
|
|
344
|
+
|
|
330
345
|
const _mant = new Float64Array(8);
|
|
331
346
|
const _expo = new Int32Array(8);
|
|
332
|
-
// BigInt is only
|
|
333
|
-
//
|
|
347
|
+
// BigInt is used only when called: by `crossingParameter` (every proper
|
|
348
|
+
// crossing in the polygon overlay) and by the exact predicates below, so
|
|
349
|
+
// loading this module never requires it
|
|
334
350
|
|
|
335
351
|
function _scaled(values: Float64Array, count: number): bigint[] {
|
|
336
352
|
let minExpo = 0x7fffffff;
|
|
@@ -360,8 +376,9 @@ function _scaled(values: Float64Array, count: number): bigint[] {
|
|
|
360
376
|
}
|
|
361
377
|
|
|
362
378
|
// `Number(bigint)` is finite below 2^1024; shift in whole limbs until then.
|
|
363
|
-
|
|
364
|
-
|
|
379
|
+
// Created on first use, so loading this module never evaluates BigInt.
|
|
380
|
+
let _finiteLimit: bigint | undefined;
|
|
381
|
+
let _shiftStep: bigint;
|
|
365
382
|
|
|
366
383
|
/**
|
|
367
384
|
* Parameter of a known proper crossing along a→b. Evaluate the determinants
|
|
@@ -391,11 +408,15 @@ export function crossingParameter(
|
|
|
391
408
|
// Keep the conversion finite even when the input doubles span hundreds of
|
|
392
409
|
// binary exponents. The numerator is between zero and the denominator, and
|
|
393
410
|
// a denominator of ordinary size needs no shift at all.
|
|
411
|
+
if (_finiteLimit === undefined) {
|
|
412
|
+
_finiteLimit = BigInt(1) << BigInt(1023);
|
|
413
|
+
_shiftStep = BigInt(64);
|
|
414
|
+
}
|
|
394
415
|
let shift = BigInt(0);
|
|
395
416
|
let scaled = denominator;
|
|
396
|
-
while (scaled >=
|
|
397
|
-
scaled >>=
|
|
398
|
-
shift +=
|
|
417
|
+
while (scaled >= _finiteLimit) {
|
|
418
|
+
scaled >>= _shiftStep;
|
|
419
|
+
shift += _shiftStep;
|
|
399
420
|
}
|
|
400
421
|
return Number(numerator >> shift) / Number(scaled);
|
|
401
422
|
}
|