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,32 @@
|
|
|
1
|
+
import { ROW_COUNT } from "../row-count";
|
|
2
|
+
import { Cell } from "../types/cell";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param colCount
|
|
8
|
+
* @param padCount
|
|
9
|
+
*/
|
|
10
|
+
function createEmptyGrid(
|
|
11
|
+
colCount: number,
|
|
12
|
+
padCount: number) {
|
|
13
|
+
|
|
14
|
+
const grid: Cell[][] = [];
|
|
15
|
+
// for (let u=0; u<ROW_COUNT + 2*padCount; u++) {
|
|
16
|
+
for (let u=0; u<colCount + 2*padCount; u++) {
|
|
17
|
+
const cells: Cell[] = [];
|
|
18
|
+
for (let v=0; v<ROW_COUNT + 2*padCount; v++) {
|
|
19
|
+
cells.push({
|
|
20
|
+
lineSegs: [],
|
|
21
|
+
closeCells: [],
|
|
22
|
+
crossingCells: []
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
grid.push(cells);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return grid;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
export { createEmptyGrid }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ROW_COUNT } from "../row-count";
|
|
2
|
+
import { Strip } from "../types/strip";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param count the number of strips
|
|
8
|
+
*/
|
|
9
|
+
// TODO - remove
|
|
10
|
+
function createEmptyStrips() {
|
|
11
|
+
const strips: Strip[] = [];
|
|
12
|
+
for (let v=0; v<ROW_COUNT; v++) {
|
|
13
|
+
// TODO - simplify
|
|
14
|
+
strips.push({ lineSegs: [] });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return strips;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export { createEmptyStrips }
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
const { min, max, sqrt } = Math;
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns the minimum distance from the given line segment to the origin.
|
|
7
|
+
*/
|
|
8
|
+
function distanceSegToP(
|
|
9
|
+
seg: number[][],
|
|
10
|
+
p: number[]) {
|
|
11
|
+
|
|
12
|
+
const seg0 = seg[0];
|
|
13
|
+
const seg1 = seg[1];
|
|
14
|
+
const _x1 = seg0[0];
|
|
15
|
+
const _y1 = seg0[1];
|
|
16
|
+
const _x2 = seg1[0];
|
|
17
|
+
const _y2 = seg1[1];
|
|
18
|
+
|
|
19
|
+
const x = p[0];
|
|
20
|
+
const y = p[1];
|
|
21
|
+
|
|
22
|
+
const x1 = _x1 - x;
|
|
23
|
+
const y1 = _y1 - y;
|
|
24
|
+
const x2 = _x2 - x;
|
|
25
|
+
const y2 = _y2 - y;
|
|
26
|
+
|
|
27
|
+
// Vector from point 1 to point 2
|
|
28
|
+
const dx = x2 - x1;
|
|
29
|
+
const dy = y2 - y1;
|
|
30
|
+
|
|
31
|
+
const lengthSq = dx*dx + dy*dy;
|
|
32
|
+
|
|
33
|
+
// Calculate projection parameter t
|
|
34
|
+
// t represents where the closest point lies on the line segment
|
|
35
|
+
// t = 0 means closest point is at seg[0], t = 1 means closest point is at seg[1]
|
|
36
|
+
const t = max(0, min(1, -(x1*dx + y1*dy) / lengthSq));
|
|
37
|
+
|
|
38
|
+
// Find the closest point on the segment
|
|
39
|
+
const closestX = x1 + t*dx;
|
|
40
|
+
const closestY = y1 + t*dy;
|
|
41
|
+
|
|
42
|
+
// Return distance from origin to closest point
|
|
43
|
+
return sqrt(closestX*closestX + closestY*closestY);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
export { distanceSegToP }
|
|
48
|
+
|
|
49
|
+
// Quokka tests
|
|
50
|
+
// distanceSegToOrigin([[0,1],[-1,-2]]);//?
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { Cell } from "../types/cell";
|
|
2
|
+
import { ROW_COUNT } from "../row-count";
|
|
3
|
+
import { circsCache } from "./calc-circs";
|
|
4
|
+
import { distanceSegToP } from "./distance-seg-to-p";
|
|
5
|
+
import { jumpIdx } from "./jump-idx";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const { min, SQRT2 } = Math;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function findCloseCells(
|
|
12
|
+
grid: Cell[][],
|
|
13
|
+
colCount: number,
|
|
14
|
+
cellSize: number,
|
|
15
|
+
maxDistance: number,
|
|
16
|
+
padCount: number) {
|
|
17
|
+
|
|
18
|
+
const findCloseCellsFor_ = findCloseCellsFor(grid, colCount, cellSize, maxDistance, padCount)
|
|
19
|
+
|
|
20
|
+
let _minD = 0; // minimum for previous row, col 0
|
|
21
|
+
let minD = 0;
|
|
22
|
+
for (let i=padCount; i<colCount + padCount; i++) {
|
|
23
|
+
minD = _minD;
|
|
24
|
+
for (let j=padCount; j<ROW_COUNT + padCount; j++) {
|
|
25
|
+
minD = findCloseCellsFor_(i, j, minD);
|
|
26
|
+
if (j === padCount) { _minD = minD; }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
function findCloseCellsFor(
|
|
33
|
+
grid: Cell[][],
|
|
34
|
+
colCount: number,
|
|
35
|
+
cellSize: number,
|
|
36
|
+
maxDistance: number,
|
|
37
|
+
padCount: number) {
|
|
38
|
+
|
|
39
|
+
return function findCloseCellsFor_(
|
|
40
|
+
i: number,
|
|
41
|
+
j: number,
|
|
42
|
+
_minD: number): number {
|
|
43
|
+
|
|
44
|
+
// reduce current circle search range since we moved one square
|
|
45
|
+
let k = jumpIdx((_minD - SQRT2*cellSize) / cellSize);
|
|
46
|
+
let minD = Number.POSITIVE_INFINITY;
|
|
47
|
+
while (k < circsCache.length) {
|
|
48
|
+
const from = circsCache[k].from;
|
|
49
|
+
|
|
50
|
+
// `SQRT2` to account for diagonal
|
|
51
|
+
if (cellSize*from > maxDistance + SQRT2*cellSize) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// uncomment loop below to search all equidistant squares
|
|
56
|
+
// while (circsCache?.[k].from === from) {
|
|
57
|
+
const { u, v } = circsCache[k];
|
|
58
|
+
const u_ = u + i;
|
|
59
|
+
const v_ = v + j;
|
|
60
|
+
if (u_ < 0 || u_ >= colCount + 2*padCount ||
|
|
61
|
+
v_ < 0 || v_ >= ROW_COUNT + 2*padCount) {
|
|
62
|
+
|
|
63
|
+
k++; continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { lineSegs } = grid[u_][v_];
|
|
67
|
+
for (let l=0; l<lineSegs.length; l++) {
|
|
68
|
+
// center of square
|
|
69
|
+
const c = [(i - padCount + 0.5)*cellSize, (j - padCount + 0.5)*cellSize];
|
|
70
|
+
const d = distanceSegToP(lineSegs[l], c);
|
|
71
|
+
if (d < minD) {
|
|
72
|
+
minD = d;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
k++;
|
|
77
|
+
// }
|
|
78
|
+
|
|
79
|
+
if (minD !== Number.POSITIVE_INFINITY) {
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (minD === Number.POSITIVE_INFINITY) {
|
|
85
|
+
return min(
|
|
86
|
+
maxDistance + SQRT2*cellSize,
|
|
87
|
+
cellSize * circsCache[circsCache.length - 1].from
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const { closeCells } = grid[i][j];
|
|
92
|
+
let l = jumpIdx((_minD - 2*SQRT2*cellSize) / cellSize);
|
|
93
|
+
while (l < circsCache.length) {
|
|
94
|
+
const { from, u, v } = circsCache[l];
|
|
95
|
+
|
|
96
|
+
// `SQRT2` to account for diagonal
|
|
97
|
+
if (cellSize*from > min(minD, maxDistance) + SQRT2*cellSize) {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const u_ = u + i;
|
|
102
|
+
const v_ = v + j;
|
|
103
|
+
if (u_ < 0 || u_ >= colCount + 2*padCount ||
|
|
104
|
+
v_ < 0 || v_ >= ROW_COUNT + 2*padCount) {
|
|
105
|
+
|
|
106
|
+
l++; continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const { lineSegs } = grid[u_][v_];
|
|
110
|
+
if (lineSegs.length > 0) {
|
|
111
|
+
closeCells.push((2*padCount + ROW_COUNT)*u_ + v_);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
l++;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return minD;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
export { findCloseCells }
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
// Quokka tests
|
|
126
|
+
// const grid: Cell[][] = [
|
|
127
|
+
// [
|
|
128
|
+
// { u: 0, v: 0, lineSegs: [], closeCells: [], crossingCells: [] },
|
|
129
|
+
// { u: 0, v: 1, lineSegs: [], closeCells: [], crossingCells: [] },
|
|
130
|
+
// { u: 0, v: 2, lineSegs: [], closeCells: [], crossingCells: [] },
|
|
131
|
+
// { u: 0, v: 3, lineSegs: [], closeCells: [], crossingCells: [] }
|
|
132
|
+
// ],
|
|
133
|
+
// [
|
|
134
|
+
// { u: 1, v: 0, lineSegs: [], closeCells: [], crossingCells: [] },
|
|
135
|
+
// {
|
|
136
|
+
// u: 1, v: 1,
|
|
137
|
+
// lineSegs: [[[175, 163], [175, 355]]],
|
|
138
|
+
// closeCells: [], crossingCells: []
|
|
139
|
+
// },
|
|
140
|
+
// {
|
|
141
|
+
// u: 1, v: 2,
|
|
142
|
+
// lineSegs: [[[175, 355], [335, 355]]],
|
|
143
|
+
// closeCells: [], crossingCells: []
|
|
144
|
+
// },
|
|
145
|
+
// { u: 1, v: 3, lineSegs: [], closeCells: [], crossingCells: [] }
|
|
146
|
+
// ],
|
|
147
|
+
// [
|
|
148
|
+
// { u: 2, v: 0, lineSegs: [], closeCells: [], crossingCells: [] },
|
|
149
|
+
// {
|
|
150
|
+
// u: 2, v: 1,
|
|
151
|
+
// lineSegs: [[[335, 163], [175, 163]]],
|
|
152
|
+
// closeCells: [], crossingCells: []
|
|
153
|
+
// },
|
|
154
|
+
// {
|
|
155
|
+
// u: 2, v: 2,
|
|
156
|
+
// lineSegs: [[[335, 355], [335, 163]]],
|
|
157
|
+
// closeCells: [], crossingCells: []
|
|
158
|
+
// },
|
|
159
|
+
// { u: 2, v: 3, lineSegs: [], closeCells: [], crossingCells: [] }
|
|
160
|
+
// ],
|
|
161
|
+
// [
|
|
162
|
+
// { u: 3, v: 0, lineSegs: [], closeCells: [], crossingCells: [] },
|
|
163
|
+
// { u: 3, v: 1, lineSegs: [], closeCells: [], crossingCells: [] },
|
|
164
|
+
// { u: 3, v: 2, lineSegs: [], closeCells: [], crossingCells: [] },
|
|
165
|
+
// { u: 3, v: 3, lineSegs: [], closeCells: [], crossingCells: [] }
|
|
166
|
+
// ]
|
|
167
|
+
// ];
|
|
168
|
+
|
|
169
|
+
// findCloseCells(grid);
|
|
170
|
+
// const v = grid.map(cells => cells.map(c => ({ u: c.u, v: c.v, closeCells: c.closeCells })));
|
|
171
|
+
// v;//?
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ROW_COUNT } from "../row-count";
|
|
2
|
+
import type { Cell } from "../types/cell";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// TODO - simplify?
|
|
6
|
+
// TODO - could be made much faster by also checking intersections here
|
|
7
|
+
// and passing the result to the next cell
|
|
8
|
+
function findCrossingCells(
|
|
9
|
+
grid: Cell[][],
|
|
10
|
+
colCount: number,
|
|
11
|
+
padCount: number) {
|
|
12
|
+
|
|
13
|
+
for (let i=padCount; i<colCount + padCount; i++) {
|
|
14
|
+
for (let j=padCount; j<ROW_COUNT + padCount; j++) {
|
|
15
|
+
const cc = grid[i][j].crossingCells;
|
|
16
|
+
|
|
17
|
+
for (let k=padCount; k<=i; k++) {
|
|
18
|
+
if (grid[k][j].lineSegs.length === 0) { continue; }
|
|
19
|
+
cc.push((ROW_COUNT + 2*padCount)*k + j);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export { findCrossingCells }
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
// Quokka tests
|
|
30
|
+
// import { createEmptyGrid } from "./create-empty-grid";
|
|
31
|
+
// // const g = createEmptyGrid(0);
|
|
32
|
+
// const g = createEmptyGrid(0);
|
|
33
|
+
// // g[0][0].lineSegs.push([[]]);
|
|
34
|
+
// g[2][0].lineSegs.push([[]]);
|
|
35
|
+
// g[2][2].lineSegs.push([[]]);
|
|
36
|
+
// findCrossingCells(g);
|
|
37
|
+
// let r = 2;
|
|
38
|
+
// // g.map(r => r.map(c => c.crossingCells))[r].map(v => v);//?
|
|
39
|
+
// g.map(r => r.map(c => c.crossingCells))[r].map(v => v.map(r => r[1]));//?
|
|
40
|
+
// g;//?
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
|
|
2
|
+
const { sqrt } = Math;
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns a function that returns the signed distance to the given line from
|
|
7
|
+
* the given point.
|
|
8
|
+
*
|
|
9
|
+
* @param pS a point on the line
|
|
10
|
+
* @param pE a different point on the line; if `pS` is the same as `pE` then
|
|
11
|
+
* the distance to the point `pS` (or `pE`) will be returned.
|
|
12
|
+
*/
|
|
13
|
+
function getDistanceToLineFunction(
|
|
14
|
+
pS: number[],
|
|
15
|
+
pE: number[]) {
|
|
16
|
+
|
|
17
|
+
const xS = pS[0];
|
|
18
|
+
const yS = pS[1];
|
|
19
|
+
const xE = pE[0];
|
|
20
|
+
const yE = pE[1];
|
|
21
|
+
|
|
22
|
+
const s = yS - yE;
|
|
23
|
+
const t = xE - xS;
|
|
24
|
+
const v = xS*yE - xE*yS;
|
|
25
|
+
|
|
26
|
+
// Calculate the length of the line for normalization
|
|
27
|
+
const lineLength = sqrt(s*s + t*t);
|
|
28
|
+
|
|
29
|
+
return function(p: number[]): number {
|
|
30
|
+
const x = p[0];
|
|
31
|
+
const y = p[1];
|
|
32
|
+
|
|
33
|
+
// Calculate the perpendicular distance from point to line
|
|
34
|
+
return lineLength !== 0
|
|
35
|
+
? (s*x + t*y + v) / lineLength
|
|
36
|
+
: sqrt((x - xS)**2 + (y - yS)**2)
|
|
37
|
+
;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
export { getDistanceToLineFunction }
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
// Quokka tests
|
|
46
|
+
{
|
|
47
|
+
const pS = [6,2];
|
|
48
|
+
const pE = [6,2];
|
|
49
|
+
const p = [10,1];
|
|
50
|
+
const f = getDistanceToLineFunction(pS,pE);
|
|
51
|
+
f(p);//?
|
|
52
|
+
}
|
|
53
|
+
// {
|
|
54
|
+
// const p0 = [0,0];
|
|
55
|
+
// const p1 = [6,1];
|
|
56
|
+
// const p2 = [10,1];
|
|
57
|
+
// const f = getDistanceToLineFunction(p0,p2);
|
|
58
|
+
// f(p1);//?
|
|
59
|
+
// }
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { circsCache } from "./calc-circs";
|
|
2
|
+
|
|
3
|
+
const { trunc, max, E } = Math;
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param v
|
|
8
|
+
*/
|
|
9
|
+
function binarySearchRange<T>(
|
|
10
|
+
v: number) {
|
|
11
|
+
|
|
12
|
+
let min = 0;
|
|
13
|
+
let max = circsCache.length - 1;
|
|
14
|
+
|
|
15
|
+
let mid = 0;
|
|
16
|
+
while (min <= max) {
|
|
17
|
+
mid = (min + max) >>> 1;//?
|
|
18
|
+
const midVal = circsCache[mid].from;
|
|
19
|
+
if (midVal === v) {
|
|
20
|
+
// return [min,mid,max];
|
|
21
|
+
return mid;
|
|
22
|
+
} else if (v > midVal) {
|
|
23
|
+
min = mid + 1;
|
|
24
|
+
} else {
|
|
25
|
+
max = mid - 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// return [min,mid,max];
|
|
30
|
+
return mid;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
// const [Q,R] = [10.606601717798213, 35.531676008879735];
|
|
35
|
+
// const [A1,B1,F1] = [102.42126, 0.153169, -117.56077];
|
|
36
|
+
// const [A2,B2,C2,D2,F2] = [-0.000660087, 0.388148, 841.25744, -0.0529616, -1089.49916];
|
|
37
|
+
// const [A3,B3,C3,D3,F3] = [-7567711.63, -0.0251756, 7562560.69, 0.025054, -7475.16953];
|
|
38
|
+
// function jumpIdxOld(
|
|
39
|
+
// c: number) {
|
|
40
|
+
|
|
41
|
+
// let idx = trunc(
|
|
42
|
+
// c <= 0 ? 0 : c <= 0.7071067811865476 ? 1 : c <= 1.5 ? 5
|
|
43
|
+
// // Three-part regression (faster than binary search in this case)
|
|
44
|
+
// : (c <= Q)
|
|
45
|
+
// ? A1*(E**(B1*c)) + F1
|
|
46
|
+
// : c <= R
|
|
47
|
+
// ? A2*(E**(B2*c)) + C2*(E**(-D2*c)) + F2
|
|
48
|
+
// : A3*(E**(B3*c)) + C3*(E**(-D3*c)) + F3);
|
|
49
|
+
|
|
50
|
+
// c = max(0, c);
|
|
51
|
+
// while (circsCache[idx].from > c) { idx--; }
|
|
52
|
+
// while (circsCache[idx + 1].from < c) { idx++; }
|
|
53
|
+
|
|
54
|
+
// return idx;
|
|
55
|
+
// }
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
function jumpIdx(
|
|
59
|
+
c: number) {
|
|
60
|
+
|
|
61
|
+
let idx = binarySearchRange(c);
|
|
62
|
+
|
|
63
|
+
c = max(0, c);
|
|
64
|
+
while (idx !== 0 && circsCache[idx].from >= c) { idx--; }
|
|
65
|
+
while (idx < circsCache.length - 2 && circsCache[idx + 1].from < c) { idx++; }
|
|
66
|
+
|
|
67
|
+
return idx;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
export { jumpIdx }
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
// Quokka tests
|
|
75
|
+
// // circsCache.slice(0,30).map(c => c.from);//?
|
|
76
|
+
// circsCache[12].from;//?
|
|
77
|
+
// circsCache[15].from;//?
|
|
78
|
+
// // circsCache.length;//?
|
|
79
|
+
|
|
80
|
+
// // jumpIdxOld(1.5811388300841898);//?
|
|
81
|
+
// jumpIdx(0.5);//?
|
|
82
|
+
// binarySearchRange(1.5811388300841898);//?
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
// jumpIdxOld(3.7);//?
|
|
86
|
+
// jumpIdx(3.7);//?
|
|
87
|
+
// // binarySearchRange(3.7);//?
|
|
88
|
+
|
|
89
|
+
// jumpIdxOld(0);//?
|
|
90
|
+
// jumpIdx(0);//?
|
|
91
|
+
// // binarySearchRange(0);//?
|
|
92
|
+
|
|
93
|
+
// jumpIdxOld(13.7);//?
|
|
94
|
+
// jumpIdx(13.7);//?
|
|
95
|
+
// // binarySearchRange(13.7);//?
|
|
96
|
+
|
|
97
|
+
// jumpIdxOld(33.7);//?
|
|
98
|
+
// jumpIdx(33.7);//?
|
|
99
|
+
// // binarySearchRange(33.7);//?
|
|
100
|
+
|
|
101
|
+
// // jumpIdxOld(55);//?
|
|
102
|
+
// // jumpIdx(55);//?
|
|
103
|
+
// binarySearchRange(55);//?
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
function mapToViewbox(
|
|
3
|
+
viewbox: [number,number,number,number],
|
|
4
|
+
width: number,
|
|
5
|
+
height: number,
|
|
6
|
+
psss: (number[][])[][]): (number[][])[][] {
|
|
7
|
+
|
|
8
|
+
if (viewbox[0] === 0 && viewbox[1] === 0 &&
|
|
9
|
+
viewbox[2] === width && viewbox[3] === height) {
|
|
10
|
+
|
|
11
|
+
return psss;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const [vx, vy, vw, vh] = viewbox;
|
|
15
|
+
|
|
16
|
+
const scaleX = width/vw;
|
|
17
|
+
const scaleY = height/vh;
|
|
18
|
+
const psss_: number[][][][] = [];
|
|
19
|
+
for (let i=0; i<psss.length; i++) {
|
|
20
|
+
const pss = psss[i];
|
|
21
|
+
const pss_: (number[][])[] = [];
|
|
22
|
+
for (let j=0; j<pss.length; j++) {
|
|
23
|
+
const ps = pss[j];
|
|
24
|
+
const ps_: number[][] = [];
|
|
25
|
+
for (let k=0; k<ps.length; k++) {
|
|
26
|
+
const [x,y] = ps[k];
|
|
27
|
+
|
|
28
|
+
const x_ = scaleX*x - vx;
|
|
29
|
+
const y_ = scaleY*y - vy;
|
|
30
|
+
ps_.push([x_,y_]);
|
|
31
|
+
}
|
|
32
|
+
pss_.push(ps_);
|
|
33
|
+
}
|
|
34
|
+
psss_.push(pss_);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return psss_;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
export { mapToViewbox }
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
|
|
2
|
+
// /**
|
|
3
|
+
// * Find the point on a quadratic bezier curve at t where t is in the range [0, 1]
|
|
4
|
+
// */
|
|
5
|
+
// function pointOnQuadraticBezier (
|
|
6
|
+
// x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, t: number,
|
|
7
|
+
// pointOut: { x: number; y: number }) {
|
|
8
|
+
|
|
9
|
+
// const t2 = 1 - t
|
|
10
|
+
// pointOut.x = t2*t2*x0 + 2*t2*t*x1 + t*t*x2;
|
|
11
|
+
// pointOut.y = t2*t2*y0 + 2*t2*t*y1 + t*t*y2;
|
|
12
|
+
// }
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// /**
|
|
16
|
+
// * Find the point on a cubic bezier curve at t where t is in the range [0, 1]
|
|
17
|
+
// */
|
|
18
|
+
// function pointOnCubicBezier (
|
|
19
|
+
// x0: number, y0: number, x1: number, y1: number,
|
|
20
|
+
// x2: number, y2: number, x3: number, y3: number,
|
|
21
|
+
// t: number,
|
|
22
|
+
// pointOut: { x: number; y: number }) {
|
|
23
|
+
|
|
24
|
+
// const t2 = 1 - t;
|
|
25
|
+
// pointOut.x = t2*t2*t2*x0 + 3*t2*t2*t*x1 + 3*t2*t*t*x2 + t*t*t*x3;
|
|
26
|
+
// pointOut.y = t2*t2*t2*y0 + 3*t2*t2*t*y1 + 3*t2*t*t*y2 + t*t*t*y3;
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// /**
|
|
31
|
+
// * Parse a path string into its constituent line/curve commands, invoking a callback for each.
|
|
32
|
+
// * @param {string} pathString - An SVG-like path string to parse; should only contain commands: M/L/Q/C/Z
|
|
33
|
+
// * @param {function(
|
|
34
|
+
// * command: 'L'|'Q'|'C',
|
|
35
|
+
// * startX: number,
|
|
36
|
+
// * startY: number,
|
|
37
|
+
// * endX: number,
|
|
38
|
+
// * endY: number,
|
|
39
|
+
// * ctrl1X?: number,
|
|
40
|
+
// * ctrl1Y?: number,
|
|
41
|
+
// * ctrl2X?: number,
|
|
42
|
+
// * ctrl2Y?: number
|
|
43
|
+
// * )} commandCallback - A callback function that will be called once for each parsed path command, passing the
|
|
44
|
+
// * command identifier (only L/Q/C commands) and its numeric arguments.
|
|
45
|
+
// */
|
|
46
|
+
// export function forEachPathCommand(
|
|
47
|
+
// pathString: string, commandCallback: Function) {
|
|
48
|
+
|
|
49
|
+
// const segmentRE = /([MLQCZ])([^MLQCZ]*)/g
|
|
50
|
+
// let match, firstX, firstY, prevX, prevY
|
|
51
|
+
// while ((match = segmentRE.exec(pathString))) {
|
|
52
|
+
// const args = match[2].split(/[,\s]+/)
|
|
53
|
+
// switch (match[1]) {
|
|
54
|
+
// case 'M':
|
|
55
|
+
// prevX = firstX = +args[0]
|
|
56
|
+
// prevY = firstY = +args[1]
|
|
57
|
+
// break
|
|
58
|
+
// case 'L':
|
|
59
|
+
// if (+args[0] !== prevX || +args[1] !== prevY) { // yup, some fonts have zero-length line commands
|
|
60
|
+
// commandCallback('L', prevX, prevY, (prevX = +args[0]), (prevY = +args[1]))
|
|
61
|
+
// }
|
|
62
|
+
// break
|
|
63
|
+
// case 'Q': {
|
|
64
|
+
// commandCallback('Q', prevX, prevY, (prevX = +args[2]), (prevY = +args[3]), +args[0], +args[1])
|
|
65
|
+
// break
|
|
66
|
+
// }
|
|
67
|
+
// case 'C': {
|
|
68
|
+
// commandCallback('C', prevX, prevY, (prevX = +args[4]), (prevY = +args[5]), +args[0], +args[1], +args[2], +args[3])
|
|
69
|
+
// break
|
|
70
|
+
// }
|
|
71
|
+
// case 'Z':
|
|
72
|
+
// if (prevX !== firstX || prevY !== firstY) {
|
|
73
|
+
// commandCallback('L', prevX, prevY, firstX, firstY)
|
|
74
|
+
// }
|
|
75
|
+
// break
|
|
76
|
+
// }
|
|
77
|
+
// }
|
|
78
|
+
// }
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// /**
|
|
82
|
+
// * Convert a path string to a series of straight line segments
|
|
83
|
+
// * @param {string} pathString - An SVG-like path string to parse; should only contain commands: M/L/Q/C/Z
|
|
84
|
+
// * @param {function(x1:number, y1:number, x2:number, y2:number)} segmentCallback - A callback
|
|
85
|
+
// * function that will be called once for every line segment
|
|
86
|
+
// * @param {number} [curvePoints] - How many straight line segments to use when approximating a
|
|
87
|
+
// * bezier curve in the path. Defaults to 16.
|
|
88
|
+
// */
|
|
89
|
+
// export function pathToLineSegments (pathString: any, segmentCallback: any, curvePoints = 16) {
|
|
90
|
+
// const tempPoint = { x: 0, y: 0 }
|
|
91
|
+
// forEachPathCommand(
|
|
92
|
+
// pathString,
|
|
93
|
+
// (command: any, startX: any, startY: any, endX: any, endY: any,
|
|
94
|
+
// ctrl1X: any, ctrl1Y: any, ctrl2X: any, ctrl2Y: any) => {
|
|
95
|
+
|
|
96
|
+
// switch (command) {
|
|
97
|
+
// case 'L':
|
|
98
|
+
// segmentCallback(startX, startY, endX, endY);
|
|
99
|
+
// break;
|
|
100
|
+
// case 'Q': {
|
|
101
|
+
// let prevCurveX = startX
|
|
102
|
+
// let prevCurveY = startY
|
|
103
|
+
// for (let i = 1; i < curvePoints; i++) {
|
|
104
|
+
// pointOnQuadraticBezier(
|
|
105
|
+
// startX, startY,
|
|
106
|
+
// ctrl1X, ctrl1Y,
|
|
107
|
+
// endX, endY,
|
|
108
|
+
// i / (curvePoints - 1),
|
|
109
|
+
// tempPoint
|
|
110
|
+
// )
|
|
111
|
+
// segmentCallback(prevCurveX, prevCurveY, tempPoint.x, tempPoint.y)
|
|
112
|
+
// prevCurveX = tempPoint.x
|
|
113
|
+
// prevCurveY = tempPoint.y
|
|
114
|
+
// }
|
|
115
|
+
// break;
|
|
116
|
+
// }
|
|
117
|
+
// case 'C': {
|
|
118
|
+
// let prevCurveX = startX
|
|
119
|
+
// let prevCurveY = startY
|
|
120
|
+
// for (let i = 1; i < curvePoints; i++) {
|
|
121
|
+
// pointOnCubicBezier(
|
|
122
|
+
// startX, startY,
|
|
123
|
+
// ctrl1X, ctrl1Y,
|
|
124
|
+
// ctrl2X, ctrl2Y,
|
|
125
|
+
// endX, endY,
|
|
126
|
+
// i / (curvePoints - 1),
|
|
127
|
+
// tempPoint
|
|
128
|
+
// )
|
|
129
|
+
// segmentCallback(prevCurveX, prevCurveY, tempPoint.x, tempPoint.y)
|
|
130
|
+
// prevCurveX = tempPoint.x
|
|
131
|
+
// prevCurveY = tempPoint.y
|
|
132
|
+
// }
|
|
133
|
+
// break
|
|
134
|
+
// }
|
|
135
|
+
// }
|
|
136
|
+
// });
|
|
137
|
+
// }
|