webgl2-sdf 0.0.1
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/README.md +100 -0
- package/node/bezier/bezier-curves-to-line-segs.d.ts +10 -0
- package/node/bezier/eval-de-casteljau.d.ts +17 -0
- package/node/bezier/from-to/from-to-2.d.ts +12 -0
- package/node/bezier/from-to/from-to-3.d.ts +12 -0
- package/node/bezier/from-to/from-to.d.ts +10 -0
- package/node/bezier/is-cubic-obtuse.d.ts +11 -0
- package/node/bezier/is-quad-obtuse.d.ts +11 -0
- package/node/bezier/is-really-point.d.ts +9 -0
- package/node/bezier/split-by-deviation-from-straight-line-cubic.d.ts +20 -0
- package/node/bezier/split-by-deviation-from-straight-line-quad.d.ts +11 -0
- package/node/bezier/split-into-line-segments.d.ts +10 -0
- package/node/debug-shaders.d.ts +9 -0
- package/node/generate-sdf.d.ts +18 -0
- package/node/helpers/calc-circs.d.ts +11 -0
- package/node/helpers/clip-line-segment-to-grid.d.ts +14 -0
- package/node/helpers/clip-line-segment-to-strips.d.ts +13 -0
- package/node/helpers/create-empty-grid.d.ts +8 -0
- package/node/helpers/create-empty-strips.d.ts +7 -0
- package/node/helpers/distance-seg-to-p.d.ts +5 -0
- package/node/helpers/find-close-cells.d.ts +3 -0
- package/node/helpers/find-crossing-cells.d.ts +3 -0
- package/node/helpers/get-distance-to-line-function.d.ts +10 -0
- package/node/helpers/jump-idx.d.ts +2 -0
- package/node/helpers/map-to-viewbox.d.ts +2 -0
- package/node/helpers/seg-box-x.d.ts +10 -0
- package/node/helpers/seg-strip-x.d.ts +9 -0
- package/node/index.d.ts +1 -0
- package/node/main-program.d.ts +4 -0
- package/node/max-aspect-ratio-before-stretch.d.ts +2 -0
- package/node/prepare-buffers.d.ts +10 -0
- package/node/row-count.d.ts +2 -0
- package/node/shaders/main.fragment.d.ts +2 -0
- package/node/shaders/main.vertex.d.ts +2 -0
- package/node/svg/get-beziers-from-raw-paths.d.ts +12 -0
- package/node/svg/get-paths-from-str.d.ts +9 -0
- package/node/svg/path-data-polyfill/parse-number.d.ts +10 -0
- package/node/svg/path-data-polyfill/parse-path-data-string.d.ts +9 -0
- package/node/svg/path-data-polyfill/source.d.ts +19 -0
- package/node/svg/path-segment/c.d.ts +19 -0
- package/node/svg/path-segment/h.d.ts +15 -0
- package/node/svg/path-segment/l.d.ts +16 -0
- package/node/svg/path-segment/q.d.ts +16 -0
- package/node/svg/path-segment/s.d.ts +20 -0
- package/node/svg/path-segment/t.d.ts +18 -0
- package/node/svg/path-segment/v.d.ts +15 -0
- package/node/svg/path-segment/z.d.ts +13 -0
- package/node/svg/path-state.d.ts +11 -0
- package/node/tex-width.d.ts +11 -0
- package/node/types/attribute.d.ts +6 -0
- package/node/types/cell.d.ts +18 -0
- package/node/types/gl-context.d.ts +28 -0
- package/node/types/gl-type.d.ts +2 -0
- package/node/types/gl-usage.d.ts +2 -0
- package/node/types/program.d.ts +16 -0
- package/node/types/strip.d.ts +8 -0
- package/node/types/texture.d.ts +4 -0
- package/node/utils/calc-circs.d.ts +11 -0
- package/node/utils/clip-line-segment-to-grid.d.ts +14 -0
- package/node/utils/clip-line-segment-to-strips.d.ts +13 -0
- package/node/utils/create-empty-grid.d.ts +8 -0
- package/node/utils/create-empty-strips.d.ts +7 -0
- package/node/utils/distance-seg-to-p.d.ts +5 -0
- package/node/utils/find-close-cells.d.ts +3 -0
- package/node/utils/find-crossing-cells.d.ts +3 -0
- package/node/utils/get-distance-to-line-function.d.ts +10 -0
- package/node/utils/jump-idx.d.ts +2 -0
- package/node/utils/map-to-viewbox.d.ts +2 -0
- package/node/utils/seg-box-x.d.ts +10 -0
- package/node/utils/seg-strip-x.d.ts +9 -0
- package/node/vector/dot.d.ts +8 -0
- package/node/vector/from-to-vec.d.ts +8 -0
- package/node/vector/len.d.ts +6 -0
- package/node/webgl-utils/compile-shader.d.ts +2 -0
- package/node/webgl-utils/get-gl-context.d.ts +10 -0
- package/node/webgl-utils/set-attribute.d.ts +15 -0
- package/node/webgl-utils/set-uniform-block.d.ts +9 -0
- package/node/webgl-utils/set-uniform.d.ts +4 -0
- package/node/webgl-utils/uniform-block.d.ts +6 -0
- package/node/webgl-utils/uniform-type.d.ts +2 -0
- package/node/webgl-utils/use-program.d.ts +17 -0
- package/node/webgl-utils/use-texture.d.ts +9 -0
- package/node/webgl2.d.ts +2 -0
- package/package.json +56 -0
- package/src/bezier/bezier-curves-to-line-segs.ts +39 -0
- package/src/bezier/eval-de-casteljau.ts +78 -0
- package/src/bezier/from-to/from-to-2.ts +159 -0
- package/src/bezier/from-to/from-to-3.ts +176 -0
- package/src/bezier/from-to/from-to.ts +30 -0
- package/src/bezier/is-cubic-obtuse.ts +31 -0
- package/src/bezier/is-quad-obtuse.ts +26 -0
- package/src/bezier/is-really-point.ts +25 -0
- package/src/bezier/split-by-deviation-from-straight-line-cubic.ts +109 -0
- package/src/bezier/split-by-deviation-from-straight-line-quad.ts +66 -0
- package/src/bezier/split-into-line-segments.ts +39 -0
- package/src/debug-shaders.ts +38 -0
- package/src/generate-sdf.ts +91 -0
- package/src/index.ts +2 -0
- package/src/main-program.ts +160 -0
- package/src/max-aspect-ratio-before-stretch.ts +5 -0
- package/src/prepare-buffers.ts +149 -0
- package/src/row-count.ts +6 -0
- package/src/shaders/main.fragment.ts +157 -0
- package/src/shaders/main.vertex.ts +55 -0
- package/src/svg/get-beziers-from-raw-paths.ts +112 -0
- package/src/svg/get-paths-from-str.ts +19 -0
- package/src/svg/path-data-polyfill/parse-number.ts +138 -0
- package/src/svg/path-data-polyfill/parse-path-data-string.ts +26 -0
- package/src/svg/path-data-polyfill/source.ts +176 -0
- package/src/svg/path-segment/c.ts +34 -0
- package/src/svg/path-segment/h.ts +28 -0
- package/src/svg/path-segment/l.ts +30 -0
- package/src/svg/path-segment/q.ts +30 -0
- package/src/svg/path-segment/s.ts +40 -0
- package/src/svg/path-segment/t.ts +35 -0
- package/src/svg/path-segment/v.ts +28 -0
- package/src/svg/path-segment/z.ts +27 -0
- package/src/svg/path-state.ts +15 -0
- package/src/tex-width.ts +14 -0
- package/src/types/attribute.ts +9 -0
- package/src/types/cell.ts +21 -0
- package/src/types/gl-context.ts +28 -0
- package/src/types/gl-type.ts +16 -0
- package/src/types/gl-usage.ts +14 -0
- package/src/types/program.ts +14 -0
- package/src/types/strip.ts +11 -0
- package/src/types/texture.ts +7 -0
- package/src/types/typed-array.ts +16 -0
- package/src/utils/calc-circs.ts +129 -0
- package/src/utils/clip-line-segment-to-grid.ts +133 -0
- package/src/utils/clip-line-segment-to-strips.ts +196 -0
- package/src/utils/create-empty-grid.ts +32 -0
- package/src/utils/create-empty-strips.ts +21 -0
- package/src/utils/distance-seg-to-p.ts +50 -0
- package/src/utils/find-close-cells.ts +171 -0
- package/src/utils/find-crossing-cells.ts +40 -0
- package/src/utils/get-distance-to-line-function.ts +59 -0
- package/src/utils/is-point-in-box.ts +16 -0
- package/src/utils/jump-idx.ts +107 -0
- package/src/utils/map-to-viewbox.ts +41 -0
- package/src/utils/path.ts +137 -0
- package/src/utils/seg-box-x.ts +84 -0
- package/src/utils/seg-strip-x.ts +72 -0
- package/src/utils/sum.ts +13 -0
- package/src/vector/dot.ts +13 -0
- package/src/vector/from-to-vec.ts +13 -0
- package/src/vector/len.ts +11 -0
- package/src/webgl-utils/compile-shader.ts +15 -0
- package/src/webgl-utils/get-gl-context.ts +61 -0
- package/src/webgl-utils/set-attribute.ts +74 -0
- package/src/webgl-utils/set-uniform-block.ts +45 -0
- package/src/webgl-utils/set-uniform.ts +24 -0
- package/src/webgl-utils/uniform-block.ts +9 -0
- package/src/webgl-utils/uniform-type.ts +10 -0
- package/src/webgl-utils/use-program.ts +48 -0
- package/src/webgl-utils/use-texture.ts +34 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PathState } from '../path-state.js';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @hidden
|
|
6
|
+
* V and v: (from www.w3.org)
|
|
7
|
+
*
|
|
8
|
+
* params: y
|
|
9
|
+
*
|
|
10
|
+
* Draws a vertical line from the current point (cpx, cpy) to (cpx, y). V
|
|
11
|
+
* (uppercase) indicates that absolute coordinates will follow; v (lowercase)
|
|
12
|
+
* indicates that relative coordinates will follow. Multiple y values can be
|
|
13
|
+
* provided (although usually this doesn't make sense). At the end of the
|
|
14
|
+
* command, the new current point becomes (cpx, y) for the final value of y.
|
|
15
|
+
*/
|
|
16
|
+
function v(s: PathState): number[][] {
|
|
17
|
+
const ps = [
|
|
18
|
+
s.p,
|
|
19
|
+
[s.p[0], s.vals![0]]
|
|
20
|
+
];
|
|
21
|
+
s.prev2ndCubicControlPoint = undefined;
|
|
22
|
+
s.prev2ndQuadraticControlPoint = undefined;
|
|
23
|
+
|
|
24
|
+
return ps;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export { v }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PathState } from '../path-state.js';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @hidden
|
|
6
|
+
* Z and z: (from www.w3.org)
|
|
7
|
+
*
|
|
8
|
+
* params: (none)
|
|
9
|
+
*
|
|
10
|
+
* Close the current subpath by drawing a straight line from the current point
|
|
11
|
+
* to current subpath's initial point. Since the Z and z commands take no
|
|
12
|
+
* parameters, they have an identical effect.
|
|
13
|
+
*/
|
|
14
|
+
function z(s: PathState): number[][] {
|
|
15
|
+
const ps = [
|
|
16
|
+
s.p,
|
|
17
|
+
s.initialPoint!
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
s.prev2ndCubicControlPoint = undefined;
|
|
21
|
+
s.prev2ndQuadraticControlPoint = undefined;
|
|
22
|
+
|
|
23
|
+
return ps;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
export { z }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
/** @hidden */
|
|
3
|
+
interface PathState {
|
|
4
|
+
initialPoint?: number[] | undefined;
|
|
5
|
+
p: number[];
|
|
6
|
+
vals?: number[] | undefined;
|
|
7
|
+
|
|
8
|
+
/** Used in conjunction with "S", "s" */
|
|
9
|
+
prev2ndCubicControlPoint?: number[] | undefined;
|
|
10
|
+
/** Used in conjunction with "T", "t" */
|
|
11
|
+
prev2ndQuadraticControlPoint?: number[] | undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export { PathState };
|
package/src/tex-width.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Just a general texture width for our textures holding general data.
|
|
4
|
+
* * width cannot be too small otherwise width or height might exceed
|
|
5
|
+
* `gl.getParameter(gl.MAX_TEXTURE_SIZE)`
|
|
6
|
+
* * if width is too large we might need to pad too many zeros so `256` is a
|
|
7
|
+
* good balance since we are guaranteed at least 4096 for MAX_TEXTURE_SIZE
|
|
8
|
+
* so we can store 256 * 4096 = 1_048_576 values per texture, more than
|
|
9
|
+
* adequate for our purposes
|
|
10
|
+
*/
|
|
11
|
+
const TEX_WIDTH = 256;
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export { TEX_WIDTH }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* A single cell in the grid
|
|
4
|
+
*/
|
|
5
|
+
interface Cell {
|
|
6
|
+
/** line segments contained within the cell */
|
|
7
|
+
readonly lineSegs: number[][][];
|
|
8
|
+
/**
|
|
9
|
+
* other cells (represented by their u and v indexes as ROW_COUNT*u + v)
|
|
10
|
+
* containing line segments and being close to this one in
|
|
11
|
+
* some (specific) sense
|
|
12
|
+
*/
|
|
13
|
+
readonly closeCells: number[];
|
|
14
|
+
/**
|
|
15
|
+
* represented by their u and v indexes as ROW_COUNT*u + v
|
|
16
|
+
*/
|
|
17
|
+
readonly crossingCells: number[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export type { Cell }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Program } from "./program";
|
|
2
|
+
import type { Texture } from "./texture";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An object wrapping a `WebGL2RenderingContext` and including additional state
|
|
7
|
+
* which includes the following:
|
|
8
|
+
*
|
|
9
|
+
* * `textures`
|
|
10
|
+
* * `programs`
|
|
11
|
+
* * `framebufferStack`
|
|
12
|
+
*
|
|
13
|
+
* so they don't have to be recreated on each draw call.
|
|
14
|
+
*
|
|
15
|
+
* * an optional `width` and `height` that can be used for any purpose and that are not
|
|
16
|
+
* set or read by any function within the library
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
interface GlContext {
|
|
20
|
+
readonly gl: WebGL2RenderingContext;
|
|
21
|
+
readonly textures: { [index:string]: Texture };
|
|
22
|
+
readonly programs: { [index:string]: Program };
|
|
23
|
+
readonly framebufferStack: WebGLFramebuffer[];
|
|
24
|
+
readonly onContextLoss: () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
export type { GlContext }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
type GLattrType =
|
|
3
|
+
| typeof WebGL2RenderingContext.BYTE
|
|
4
|
+
| typeof WebGL2RenderingContext.SHORT
|
|
5
|
+
| typeof WebGL2RenderingContext.UNSIGNED_BYTE
|
|
6
|
+
| typeof WebGL2RenderingContext.UNSIGNED_SHORT
|
|
7
|
+
| typeof WebGL2RenderingContext.FLOAT
|
|
8
|
+
// WebGL2 only
|
|
9
|
+
| typeof WebGL2RenderingContext.HALF_FLOAT
|
|
10
|
+
| typeof WebGL2RenderingContext.INT
|
|
11
|
+
| typeof WebGL2RenderingContext.UNSIGNED_INT
|
|
12
|
+
| typeof WebGL2RenderingContext.INT_2_10_10_10_REV
|
|
13
|
+
| typeof WebGL2RenderingContext.UNSIGNED_INT_2_10_10_10_REV;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export type { GLattrType }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
type GLusage =
|
|
3
|
+
| typeof WebGL2RenderingContext.STATIC_DRAW
|
|
4
|
+
| typeof WebGL2RenderingContext.DYNAMIC_DRAW
|
|
5
|
+
| typeof WebGL2RenderingContext.STREAM_DRAW
|
|
6
|
+
| typeof WebGL2RenderingContext.STATIC_READ
|
|
7
|
+
| typeof WebGL2RenderingContext.DYNAMIC_READ
|
|
8
|
+
| typeof WebGL2RenderingContext.STREAM_READ
|
|
9
|
+
| typeof WebGL2RenderingContext.STATIC_COPY
|
|
10
|
+
| typeof WebGL2RenderingContext.DYNAMIC_COPY
|
|
11
|
+
| typeof WebGL2RenderingContext.STREAM_COPY;
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export type { GLusage }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Attribute } from "./attribute";
|
|
2
|
+
import type { UniformBlock } from "../webgl-utils/uniform-block";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
interface Program {
|
|
6
|
+
readonly gl: WebGL2RenderingContext;
|
|
7
|
+
readonly program: WebGLProgram;
|
|
8
|
+
readonly attributes: { [index:string]: Attribute };
|
|
9
|
+
readonly uniforms: { [index:string]: WebGLUniformLocation | null };
|
|
10
|
+
readonly uniformBlocks: { [index:string]: UniformBlock };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export { Program }
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { MAX_ASPECT_RATIO_BEFORE_STRETCH } from '../max-aspect-ratio-before-stretch';
|
|
2
|
+
import { ROW_COUNT } from '../row-count';
|
|
3
|
+
import { len } from '../vector/len';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents the max distance (in cell side length units) from one corner of
|
|
8
|
+
* the viewbox to the opposing corner.
|
|
9
|
+
*/
|
|
10
|
+
// const diagLen = ceil(sqrt((MAX_ASPECT_RATIO_BEFORE_STRETCH*ROW_COUNT)**2 + ROW_COUNT**2));
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const circsCache = calcCircs();
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
interface Range {
|
|
17
|
+
readonly from: number;
|
|
18
|
+
readonly u: number;
|
|
19
|
+
readonly v: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
function calcCircs() {
|
|
24
|
+
const ranges: Range[] = [{ from: 0, u: 0, v: 0 }];
|
|
25
|
+
|
|
26
|
+
// for (let i=0; i<ROW_COUNT; i++) {
|
|
27
|
+
for (let i=0; i<MAX_ASPECT_RATIO_BEFORE_STRETCH*ROW_COUNT; i++) {
|
|
28
|
+
ranges.push({ from: i + 0.5, u: i + 1, v: 0 });
|
|
29
|
+
ranges.push({ from: i + 0.5, u: -i - 1, v: 0 });
|
|
30
|
+
ranges.push({ from: i + 0.5, u: 0, v: i + 1 });
|
|
31
|
+
ranges.push({ from: i + 0.5, u: 0, v: -i - 1 });
|
|
32
|
+
for (let j=0; j<ROW_COUNT; j++) {
|
|
33
|
+
const p = [0.5 + i, 0.5 + j];
|
|
34
|
+
const d = len(p);
|
|
35
|
+
|
|
36
|
+
const u = i + 1;
|
|
37
|
+
const v = j + 1;
|
|
38
|
+
ranges.push({ from: d, u, v });
|
|
39
|
+
if (u !== 0) {
|
|
40
|
+
ranges.push({ from: d, u: -u, v });
|
|
41
|
+
}
|
|
42
|
+
if (v !== 0) {
|
|
43
|
+
ranges.push({ from: d, u, v: -v });
|
|
44
|
+
}
|
|
45
|
+
if (u !== 0 && v !== 0) {
|
|
46
|
+
ranges.push({ from: d, u: -u, v: -v });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
ranges.sort((a,b) => (a.from - b.from));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
return ranges;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
export { circsCache }
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// Quokka tests
|
|
63
|
+
// const { E, trunc, max, sqrt, ceil } = Math;
|
|
64
|
+
|
|
65
|
+
// calcCircs().length;//?
|
|
66
|
+
|
|
67
|
+
// const cs = calcCircs().map(c => c.from);
|
|
68
|
+
|
|
69
|
+
// const longest = (() => {
|
|
70
|
+
// let l = 0;
|
|
71
|
+
// let maxL = 0;
|
|
72
|
+
// let _v = 0;
|
|
73
|
+
// for (let i=0; i<cs.length; i++) {
|
|
74
|
+
// const v = cs[i];
|
|
75
|
+
// if (_v === cs[i]) {
|
|
76
|
+
// l++;
|
|
77
|
+
// } else {
|
|
78
|
+
// l = 0;
|
|
79
|
+
// }
|
|
80
|
+
// _v = v;
|
|
81
|
+
// if (l > maxL) {
|
|
82
|
+
// maxL = l;
|
|
83
|
+
// }
|
|
84
|
+
// }
|
|
85
|
+
|
|
86
|
+
// return maxL;
|
|
87
|
+
// })();//?
|
|
88
|
+
|
|
89
|
+
// const froms = [
|
|
90
|
+
// { from: 0, to: 50, skip: 1 },
|
|
91
|
+
// { from: 50, to: 3050, skip: 50 },
|
|
92
|
+
// { from: 400, to: 4000, skip: 100 },
|
|
93
|
+
// // { from: 10, to: 100, skip: 10 }
|
|
94
|
+
// ];
|
|
95
|
+
|
|
96
|
+
// for (let j=0; j<froms.length; j++) {
|
|
97
|
+
// const { from, to, skip } = froms[j];
|
|
98
|
+
// let strs: string[] = [];
|
|
99
|
+
// for (let i=from; i<to; i += skip) {
|
|
100
|
+
// const v = cs[i];
|
|
101
|
+
// strs.push(`${v.toString()} ${i}`);
|
|
102
|
+
// }
|
|
103
|
+
// const csStr = strs.join('\n');
|
|
104
|
+
|
|
105
|
+
// console.log(csStr);
|
|
106
|
+
// }
|
|
107
|
+
|
|
108
|
+
// jumpIdx(3.7);//?
|
|
109
|
+
// for (let i=30; i<44; i += 0.25) {
|
|
110
|
+
// jumpIdx(i);//?
|
|
111
|
+
// [(cs[jumpIdx(i)]), i];//?
|
|
112
|
+
// }
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
// let tot = 0;
|
|
116
|
+
// const vs: number[] = [];
|
|
117
|
+
// for (let i=400; i<=3800; i++) {
|
|
118
|
+
// const c = cs[i];
|
|
119
|
+
// const ap = A*(E**(B*c)) + C*(E**(-D*c)) + F;
|
|
120
|
+
// const S = B*A*(E**(B*c)) + -D*C*(E**(-D*c));
|
|
121
|
+
// // i;//?
|
|
122
|
+
// // ap;//?
|
|
123
|
+
// const err = abs(i - ap);
|
|
124
|
+
// tot += err;
|
|
125
|
+
// vs.push(err);
|
|
126
|
+
// }
|
|
127
|
+
// vs.sort((a,b) => b - a);//?
|
|
128
|
+
// vs[3400];//?
|
|
129
|
+
// tot/(3800 - 400);//?
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { Cell } from "../types/cell";
|
|
2
|
+
import { ROW_COUNT } from "../row-count";
|
|
3
|
+
import { segBoxX } from "./seg-box-x";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const { floor, ceil } = Math;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Clips a line segment to grid boundaries and returns multiple segments.
|
|
11
|
+
*
|
|
12
|
+
* * modifies grid by adding line segments to cells
|
|
13
|
+
* * size/count *must* be a power of 2
|
|
14
|
+
*
|
|
15
|
+
* @param count the number of grid cells per dimension
|
|
16
|
+
* @param width
|
|
17
|
+
* @param height
|
|
18
|
+
* @param seg the line segment (array of 2 points)
|
|
19
|
+
*/
|
|
20
|
+
function clipLineSegmentToGrid(
|
|
21
|
+
grid: Cell[][],
|
|
22
|
+
width: number,
|
|
23
|
+
height: number,
|
|
24
|
+
colCount: number,
|
|
25
|
+
cellSize: number,
|
|
26
|
+
seg: number[][],
|
|
27
|
+
padCount: number): void {
|
|
28
|
+
|
|
29
|
+
/** `cellSize` *must* be a power of two */
|
|
30
|
+
// const cellSize = width/ROW_COUNT;
|
|
31
|
+
|
|
32
|
+
const padding = cellSize*padCount;
|
|
33
|
+
|
|
34
|
+
const [[x0,y0],[x1,y1]] = seg;
|
|
35
|
+
|
|
36
|
+
const paddedWidth = width + padding;
|
|
37
|
+
const paddedHeight = height + padding;
|
|
38
|
+
// TODO - investigate lines on edge and corners - ps could be length 4!!
|
|
39
|
+
const ps = segBoxX(seg, [[-padding,-padding],[paddedWidth,paddedHeight]]);
|
|
40
|
+
|
|
41
|
+
const p0IsInBox = x0 > -padding && x0 < paddedWidth && y0 > -padding && y0 < paddedHeight;
|
|
42
|
+
const p1IsInBox = x1 > -padding && x1 < paddedWidth && y1 > -padding && y1 < paddedHeight;
|
|
43
|
+
|
|
44
|
+
// if line is completely outside box
|
|
45
|
+
if (ps.length < 2 && !p0IsInBox && !p1IsInBox) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Determine which grid cells the line passes through
|
|
50
|
+
|
|
51
|
+
const dX = x1 - x0;
|
|
52
|
+
const dY = y1 - y0;
|
|
53
|
+
|
|
54
|
+
// Use Bresenham-like approach to find all grid cells the line crosses
|
|
55
|
+
const stepX = x1 > x0 ? cellSize : -cellSize;
|
|
56
|
+
const stepY = y1 > y0 ? cellSize : -cellSize;
|
|
57
|
+
|
|
58
|
+
/** first point of each line segment to connect */
|
|
59
|
+
|
|
60
|
+
/** current x position */
|
|
61
|
+
let x = x0;
|
|
62
|
+
/** current y position */
|
|
63
|
+
let y = y0;
|
|
64
|
+
|
|
65
|
+
// current intersection index
|
|
66
|
+
let xIdx = 0;
|
|
67
|
+
// left-to-right
|
|
68
|
+
const ltr = stepX > 0;
|
|
69
|
+
// bottom-to-top
|
|
70
|
+
const btt = stepY > 0;
|
|
71
|
+
|
|
72
|
+
// // line segment min-y excluded
|
|
73
|
+
// const crossing =
|
|
74
|
+
// (seg.y > y != seg.w > y) &&
|
|
75
|
+
// (x > (seg.z - seg.x)*(y - seg.y) / (seg.w - seg.y) + seg.x);
|
|
76
|
+
|
|
77
|
+
const fX = ltr ? floor : ceil;
|
|
78
|
+
const fY = btt ? floor : ceil;
|
|
79
|
+
while (true) {
|
|
80
|
+
// Find next grid boundary
|
|
81
|
+
let nextGridX = cellSize*fX((x + stepX)/cellSize);
|
|
82
|
+
let nextGridY = cellSize*fY((y + stepY)/cellSize);
|
|
83
|
+
|
|
84
|
+
// Calculate parameter t for intersection with vertical and horizontal grid lines
|
|
85
|
+
// eq. (1)
|
|
86
|
+
const tX = (nextGridX - x0)/dX;
|
|
87
|
+
// eq. (2)
|
|
88
|
+
const tY = (nextGridY - y0)/dY;
|
|
89
|
+
|
|
90
|
+
const useTx = (tX < tY && dX !== 0) || dY === 0;
|
|
91
|
+
/** intersection X */
|
|
92
|
+
const xX = useTx ? nextGridX : x0 + tY*dX;
|
|
93
|
+
/** intersection Y */
|
|
94
|
+
const xY = useTx ? y0 + tX*dY : nextGridY;
|
|
95
|
+
|
|
96
|
+
// if we're past the line endpoint
|
|
97
|
+
if ((tX > 1 || dX === 0) && (tY > 1 || dY === 0)) {
|
|
98
|
+
const u = floor(x1/cellSize) + padCount;
|
|
99
|
+
const v = floor(y1/cellSize) + padCount;
|
|
100
|
+
grid[u]?.[v]?.lineSegs.push([[x,y], [x1,y1]]);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// if next grid intersection is on edge of grid
|
|
105
|
+
if ((xX <= -padding || xY <= -padding) || (xX >= paddedWidth || xY >= paddedHeight)) {
|
|
106
|
+
const entering = !p0IsInBox && xIdx === 0;
|
|
107
|
+
|
|
108
|
+
if (entering) {
|
|
109
|
+
[x,y] = ps[0]; // update current x,y position
|
|
110
|
+
xIdx++;
|
|
111
|
+
continue;
|
|
112
|
+
} else {
|
|
113
|
+
const u = fX(x/cellSize) - (ltr ? 0 : 1) + padCount; // current u
|
|
114
|
+
const v = fY(y/cellSize) - (btt ? 0 : 1) + padCount; // current v
|
|
115
|
+
const seg_ = [[x,y], ps[xIdx]];
|
|
116
|
+
grid[u]?.[v]?.lineSegs.push(seg_);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const u = fX(x/cellSize) - (ltr ? 0 : 1) + padCount; // current u
|
|
122
|
+
const v = fY(y/cellSize) - (btt ? 0 : 1) + padCount; // current v
|
|
123
|
+
|
|
124
|
+
grid[u]?.[v]?.lineSegs.push([[x,y], [xX,xY]]);
|
|
125
|
+
|
|
126
|
+
// update current position
|
|
127
|
+
x = xX;
|
|
128
|
+
y = xY;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
export { clipLineSegmentToGrid }
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { Strip } from "../types/strip";
|
|
2
|
+
import { segStripX } from "./seg-strip-x";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const { floor, ceil } = Math;
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Clips a line segment to strip boundaries and returns multiple segments.
|
|
10
|
+
*
|
|
11
|
+
* * modifies strips by adding line segments to each strip
|
|
12
|
+
* * size/count *must* be a power of 2
|
|
13
|
+
*
|
|
14
|
+
* @param count the number of strips
|
|
15
|
+
* @param height the height of a strip
|
|
16
|
+
* @param seg the line segment (array of 2 points)
|
|
17
|
+
*/
|
|
18
|
+
function clipLineSegmentToStrips(
|
|
19
|
+
strips: Strip[],
|
|
20
|
+
height: number,
|
|
21
|
+
seg: number[][]): void {
|
|
22
|
+
|
|
23
|
+
const count = strips.length;
|
|
24
|
+
/** `cellSize` *must* be a power of two */
|
|
25
|
+
const cellSize = height/count;
|
|
26
|
+
|
|
27
|
+
const [p0,p1] = seg;
|
|
28
|
+
const ps = segStripX(seg, [0,0,height]);
|
|
29
|
+
const [x0,y0] = p0;
|
|
30
|
+
const [x1,y1] = p1;
|
|
31
|
+
|
|
32
|
+
const dX = x1 - x0;
|
|
33
|
+
const dY = y1 - y0;
|
|
34
|
+
|
|
35
|
+
const p0IsInStrip = x0 < 0 && y0 > 0 && y0 < height;
|
|
36
|
+
const p1IsInStrip = x1 < 0 && y1 > 0 && y1 < height;
|
|
37
|
+
|
|
38
|
+
// if line is completely outside strip
|
|
39
|
+
if ((ps.length < 2 && !p0IsInStrip && !p1IsInStrip) &&
|
|
40
|
+
((x0 !== 0 || dX !== 0) ||
|
|
41
|
+
((y0 <= 0 && y1 <= 0) || (y0 >= height && y1 >= height)))) {
|
|
42
|
+
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Determine which strips the line passes through
|
|
47
|
+
|
|
48
|
+
if (dY === 0) { // no crossings possible
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Use Bresenham-like approach to find all strips the line crosses
|
|
53
|
+
const stepY = y1 > y0 ? cellSize : -cellSize;
|
|
54
|
+
|
|
55
|
+
/** first point of each line segment to connect */
|
|
56
|
+
|
|
57
|
+
/** current x position */
|
|
58
|
+
let x = x0;
|
|
59
|
+
/** current y position */
|
|
60
|
+
let y = y0;
|
|
61
|
+
|
|
62
|
+
let i = 0;
|
|
63
|
+
// left-to-right
|
|
64
|
+
const ltr = x1 > x0;
|
|
65
|
+
// bottom-to-top
|
|
66
|
+
const btt = y1 > y0;
|
|
67
|
+
|
|
68
|
+
// // line segment min-y excluded
|
|
69
|
+
// const crossing =
|
|
70
|
+
// (seg.y > y != seg.w > y) &&
|
|
71
|
+
// (x > (seg.z - seg.x)*(y - seg.y) / (seg.w - seg.y) + seg.x);
|
|
72
|
+
|
|
73
|
+
const fY = btt ? floor : ceil;
|
|
74
|
+
while (true) {
|
|
75
|
+
// Find next strip boundary
|
|
76
|
+
let nextGridX = ((ltr && x < 0) || (!ltr && x > 0)) ? 0 : Number.NEGATIVE_INFINITY;
|
|
77
|
+
|
|
78
|
+
let nextGridY = cellSize*fY((y + stepY)/cellSize);
|
|
79
|
+
|
|
80
|
+
// Calculate parameter t for intersection with horizontal strip lines
|
|
81
|
+
// eq. (1)
|
|
82
|
+
const tX = (nextGridX - x0)/dX;
|
|
83
|
+
// eq. (2)
|
|
84
|
+
const tY = (nextGridY - y0)/dY;
|
|
85
|
+
|
|
86
|
+
const useTx = tX < tY && dX !== 0;
|
|
87
|
+
|
|
88
|
+
/** intersection X */
|
|
89
|
+
const xX = useTx ? 0 : x0 + tY*dX;
|
|
90
|
+
/** intersection Y */
|
|
91
|
+
const xY = useTx ? y0 + tX*dY : nextGridY;
|
|
92
|
+
|
|
93
|
+
// if we're past the line endpoint
|
|
94
|
+
if ((tX > 1 || dX === 0) && tY > 1) {
|
|
95
|
+
const v = floor(p1[1]/cellSize);
|
|
96
|
+
strips[v]?.lineSegs.push([[x,y],p1]);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (((xX >= 0 && (x0 !== 0 || dX !== 0)) || xY <= 0 || xY >= height)) {
|
|
101
|
+
// next strip intersection is on edge of strips
|
|
102
|
+
const entering = !p0IsInStrip && i === 0;
|
|
103
|
+
|
|
104
|
+
if (entering) {
|
|
105
|
+
// update current x,y position
|
|
106
|
+
[x,y] = ps[0];
|
|
107
|
+
i++;
|
|
108
|
+
continue;
|
|
109
|
+
} else {
|
|
110
|
+
const v = fY(y/cellSize) - (btt ? 0 : 1); // previous v
|
|
111
|
+
const seg_ = [[x,y],ps[i]];
|
|
112
|
+
strips[v]?.lineSegs.push(seg_);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// previous v
|
|
118
|
+
const v = fY(y/cellSize) - (btt ? 0 : 1);
|
|
119
|
+
|
|
120
|
+
strips[v]?.lineSegs.push([[x,y], [xX,xY]]);
|
|
121
|
+
|
|
122
|
+
// update current position
|
|
123
|
+
x = xX;
|
|
124
|
+
y = xY;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
export { clipLineSegmentToStrips }
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
// Quokka tests - https://www.desmos.com/calculator/uyqsdkviih
|
|
133
|
+
// import { createEmptyStrips } from "./create-empty-strips";
|
|
134
|
+
|
|
135
|
+
// {
|
|
136
|
+
// const strips = createEmptyStrips(8);
|
|
137
|
+
// const seg = [[0, 100], [0, 400]];
|
|
138
|
+
|
|
139
|
+
// toDesmosStr(seg);
|
|
140
|
+
// clipLineSegmentToStrips(strips, 512, seg);
|
|
141
|
+
// testAllEmptyExcept(strips,[1,2,3,4,5,6]);
|
|
142
|
+
// }
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
// {
|
|
146
|
+
// const strips = createEmptyStrips(8);
|
|
147
|
+
// const seg = [[83, 166], [-90, 440]];
|
|
148
|
+
|
|
149
|
+
// toDesmosStr(seg);
|
|
150
|
+
// clipLineSegmentToStrips(strips, 512, seg);
|
|
151
|
+
// testAllEmptyExcept(strips,[4,5,6]);
|
|
152
|
+
// }
|
|
153
|
+
|
|
154
|
+
// {
|
|
155
|
+
// const strips = createEmptyStrips(8);
|
|
156
|
+
// const seg = [[-570, 236], [-392, 546]];
|
|
157
|
+
|
|
158
|
+
// toDesmosStr(seg);
|
|
159
|
+
// clipLineSegmentToStrips(strips, 512, seg);
|
|
160
|
+
// testAllEmptyExcept(strips,[3,4,5,6,7]);
|
|
161
|
+
// }
|
|
162
|
+
|
|
163
|
+
// {
|
|
164
|
+
// const strips = createEmptyStrips(8);
|
|
165
|
+
// const seg = [[-462, 632], [-152, 611]];
|
|
166
|
+
|
|
167
|
+
// toDesmosStr(seg);
|
|
168
|
+
// clipLineSegmentToStrips(strips, 512, seg);
|
|
169
|
+
// testAllEmptyExcept(strips,[]);
|
|
170
|
+
// }
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
// function toDesmosStr(seg: number[][]) {
|
|
174
|
+
// const [[x0,y0],[x1,y1]] = seg;
|
|
175
|
+
// return `\\left(\\left(1-t\\right)\\cdot${x0.toFixed(2)}+t\\cdot\\left(${x1.toFixed(2)}\\right),\\left(1-t\\right)\\cdot${y0.toFixed(2)}+t\\cdot${y1.toFixed(2)}\\right)`;
|
|
176
|
+
// }
|
|
177
|
+
// function testAllEmptyExcept(
|
|
178
|
+
// strips: Strip[],
|
|
179
|
+
// exceptions: number[]) {
|
|
180
|
+
|
|
181
|
+
// for (let i=0; i<strips.length; i++) {
|
|
182
|
+
// const strip = strips[i];
|
|
183
|
+
// const idx = exceptions.findIndex(v => v === i);
|
|
184
|
+
// const exception = exceptions[idx];
|
|
185
|
+
// const len = strip.lineSegs.length;
|
|
186
|
+
// if (exception === undefined) {
|
|
187
|
+
// if (len !== 0) {
|
|
188
|
+
// throw new Error(`Strip ${i} must be empty`);
|
|
189
|
+
// }
|
|
190
|
+
// } else {
|
|
191
|
+
// if (len !== 1) {
|
|
192
|
+
// throw new Error(`Strip ${i} must contain 1 segments, found ${len}`);
|
|
193
|
+
// }
|
|
194
|
+
// }
|
|
195
|
+
// }
|
|
196
|
+
// }
|