@thi.ng/geom-trace-bitmap 0.3.40 → 0.3.42

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/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-12-09T19:12:03Z
3
+ - **Last updated**: 2023-12-11T10:07:09Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
package/README.md CHANGED
@@ -67,7 +67,7 @@ For Node.js REPL:
67
67
  const geomTraceBitmap = await import("@thi.ng/geom-trace-bitmap");
68
68
  ```
69
69
 
70
- Package sizes (brotli'd, pre-treeshake): ESM: 988 bytes
70
+ Package sizes (brotli'd, pre-treeshake): ESM: 991 bytes
71
71
 
72
72
  ## Dependencies
73
73
 
package/api.js CHANGED
@@ -1 +0,0 @@
1
- export {};
package/border.js CHANGED
@@ -1,31 +1,18 @@
1
- /**
2
- * Border function which only checks X coordinates.
3
- *
4
- * @param w - image width
5
- * @param h - image width
6
- */
7
- export const borderX = (w) => {
8
- w--;
9
- return (p) => p[0] === 0 || p[0] === w;
1
+ const borderX = (w) => {
2
+ w--;
3
+ return (p) => p[0] === 0 || p[0] === w;
10
4
  };
11
- /**
12
- * Border function which only checks Y coordinates.
13
- *
14
- * @param w - image width
15
- * @param h - image width
16
- */
17
- export const borderY = (_, h) => {
18
- h--;
19
- return (p) => p[1] === 0 || p[1] === h;
5
+ const borderY = (_, h) => {
6
+ h--;
7
+ return (p) => p[1] === 0 || p[1] === h;
20
8
  };
21
- /**
22
- * Border function which checks both X & Y coordinates.
23
- *
24
- * @param w - image width
25
- * @param h - image width
26
- */
27
- export const borderXY = (w, h) => {
28
- w--;
29
- h--;
30
- return (p) => p[0] === 0 || p[0] === w || p[1] === 0 || p[1] === h;
9
+ const borderXY = (w, h) => {
10
+ w--;
11
+ h--;
12
+ return (p) => p[0] === 0 || p[0] === w || p[1] === 0 || p[1] === h;
13
+ };
14
+ export {
15
+ borderX,
16
+ borderXY,
17
+ borderY
31
18
  };
package/extract.js CHANGED
@@ -1,72 +1,40 @@
1
1
  import { comparator2 } from "@thi.ng/vectors/compare";
2
- /**
3
- * Extracts horizontal line segments (along X-axis) from given point cloud
4
- * (assuming all points are aligned to a grid, e.g. pixel coords). Returns
5
- * object of `{segments, points}`, where `segments` contains all extracted
6
- * segments and `points` all remaining/unmatched points.
7
- *
8
- * @remarks
9
- * The given point array will be sorted (in-place!). Line segments will be as
10
- * long as possible, depending on chosen `maxDist`, which defines max distance
11
- * between consecutive points. If a point is further away than `maxDist` units
12
- * from the previous point (or at a new X coord), the current line segment (if
13
- * any) will be terminated and the new point is potentially becoming the start
14
- * of the next segment.
15
- *
16
- * @param pts
17
- * @param maxDist
18
- */
19
- export const extractSegmentsX = (pts, maxD = 5) => __extract(pts, maxD, 1);
20
- /**
21
- * Similar to {@link extractSegmentsX}, but for extracting vertical line
22
- * segments (along Y-axis).
23
- *
24
- * @param pts
25
- * @param maxDist
26
- */
27
- export const extractSegmentsY = (pts, maxDist = 5) => __extract(pts, maxDist, 0);
28
- /**
29
- * Common implementation for both axis orders.
30
- *
31
- * @param pts
32
- * @param maxD
33
- * @param order
34
- *
35
- * @internal
36
- */
2
+ const extractSegmentsX = (pts, maxD = 5) => __extract(pts, maxD, 1);
3
+ const extractSegmentsY = (pts, maxDist = 5) => __extract(pts, maxDist, 0);
37
4
  const __extract = (pts, maxD, order) => {
38
- if (pts.length < 2)
39
- return { segments: [], points: pts };
40
- const $ = order ? (p) => [p[1], p[0]] : (p) => p;
41
- pts = pts.sort(comparator2(order, order ^ 1));
42
- const segments = [];
43
- const points = [];
44
- let [outer, inner] = $(pts[0]);
45
- let last = 0;
46
- for (let i = 1, n = pts.length - 1; i <= n; i++) {
47
- const p = $(pts[i]);
48
- if (p[0] === outer) {
49
- if (i === n || p[1] - inner > maxD) {
50
- if (i - last > 1) {
51
- segments.push([pts[last], pts[i - 1]]);
52
- }
53
- else {
54
- points.push(pts[last]);
55
- }
56
- last = i;
57
- }
58
- inner = p[1];
59
- }
60
- else {
61
- if (i - last > 1) {
62
- segments.push([pts[last], pts[i - 1]]);
63
- }
64
- else {
65
- points.push(pts[last]);
66
- }
67
- last = i;
68
- [outer, inner] = p;
5
+ if (pts.length < 2)
6
+ return { segments: [], points: pts };
7
+ const $ = order ? (p) => [p[1], p[0]] : (p) => p;
8
+ pts = pts.sort(comparator2(order, order ^ 1));
9
+ const segments = [];
10
+ const points = [];
11
+ let [outer, inner] = $(pts[0]);
12
+ let last = 0;
13
+ for (let i = 1, n = pts.length - 1; i <= n; i++) {
14
+ const p = $(pts[i]);
15
+ if (p[0] === outer) {
16
+ if (i === n || p[1] - inner > maxD) {
17
+ if (i - last > 1) {
18
+ segments.push([pts[last], pts[i - 1]]);
19
+ } else {
20
+ points.push(pts[last]);
69
21
  }
22
+ last = i;
23
+ }
24
+ inner = p[1];
25
+ } else {
26
+ if (i - last > 1) {
27
+ segments.push([pts[last], pts[i - 1]]);
28
+ } else {
29
+ points.push(pts[last]);
30
+ }
31
+ last = i;
32
+ [outer, inner] = p;
70
33
  }
71
- return { segments, points };
34
+ }
35
+ return { segments, points };
36
+ };
37
+ export {
38
+ extractSegmentsX,
39
+ extractSegmentsY
72
40
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/geom-trace-bitmap",
3
- "version": "0.3.40",
3
+ "version": "0.3.42",
4
4
  "description": "Bitmap image to hairline vector and point cloud conversions",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -24,7 +24,9 @@
24
24
  "author": "Karsten Schmidt (https://thi.ng)",
25
25
  "license": "Apache-2.0",
26
26
  "scripts": {
27
- "build": "yarn clean && tsc --declaration",
27
+ "build": "yarn build:esbuild && yarn build:decl",
28
+ "build:decl": "tsc --declaration --emitDeclarationOnly",
29
+ "build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
28
30
  "clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
29
31
  "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
30
32
  "doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
@@ -33,15 +35,16 @@
33
35
  "test": "bun test"
34
36
  },
35
37
  "dependencies": {
36
- "@thi.ng/api": "^8.9.11",
37
- "@thi.ng/errors": "^2.4.5",
38
- "@thi.ng/grid-iterators": "^4.0.35",
39
- "@thi.ng/matrices": "^2.2.12",
40
- "@thi.ng/pixel": "^5.0.3",
41
- "@thi.ng/vectors": "^7.8.8"
38
+ "@thi.ng/api": "^8.9.12",
39
+ "@thi.ng/errors": "^2.4.6",
40
+ "@thi.ng/grid-iterators": "^4.0.36",
41
+ "@thi.ng/matrices": "^2.2.14",
42
+ "@thi.ng/pixel": "^5.0.5",
43
+ "@thi.ng/vectors": "^7.8.10"
42
44
  },
43
45
  "devDependencies": {
44
46
  "@microsoft/api-extractor": "^7.38.3",
47
+ "esbuild": "^0.19.8",
45
48
  "rimraf": "^5.0.5",
46
49
  "tools": "^0.0.1",
47
50
  "typedoc": "^0.25.4",
@@ -98,5 +101,5 @@
98
101
  "status": "alpha",
99
102
  "year": 2022
100
103
  },
101
- "gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
104
+ "gitHead": "22e36fa838e5431d40165384918b395603bbd92f\n"
102
105
  }
package/trace.js CHANGED
@@ -5,139 +5,134 @@ import { rows2d } from "@thi.ng/grid-iterators/rows";
5
5
  import { flipX, ident } from "@thi.ng/grid-iterators/transforms";
6
6
  import { mulV23 } from "@thi.ng/matrices/mulv";
7
7
  import { borderX, borderXY, borderY } from "./border.js";
8
- /**
9
- * Main conversion/extraction function. According to given
10
- * {@link TraceBitmapOpts.flags}, extracts line segments and/or points from
11
- * given pixel buffer and returns object of results. By default _all_ line
12
- * directions and points are processed. If {@link TraceBitmapOpts.mat} is given,
13
- * all coordinates are transformed with that matrix.
14
- *
15
- * ```ts
16
- * traceBitmap({ img: ..., flags: Trace.DIAGONAL })
17
- * // { lines: [...], points: [] }
18
- * ```
19
- *
20
- * @param opts
21
- */
22
- export const traceBitmap = (opts) => {
23
- const mat = opts.mat;
24
- const { width, height } = opts.img;
25
- const lines = [];
26
- const points = [];
27
- for (let d of opts.dir || ["h", "v", "d1", "d2", "p"]) {
28
- if (typeof d !== "string") {
29
- traceLines(opts, d.order, (d.border || borderXY)(width, height), d.tx || ident, lines);
30
- continue;
31
- }
32
- switch (d) {
33
- case "h":
34
- traceLines(opts, rows2d, borderX(width, height), ident, lines);
35
- break;
36
- case "v":
37
- traceLines(opts, columns2d, borderY(width, height), ident, lines);
38
- break;
39
- case "d1":
40
- traceLines(opts, diagonal2d, borderXY(width, height), ident, lines);
41
- break;
42
- case "d2":
43
- traceLines(opts, diagonal2d, borderXY(width, height), flipX, lines);
44
- break;
45
- case "p":
46
- tracePoints(opts, points);
47
- break;
48
- default:
49
- illegalArgs(`invalid trace direction: ${d}`);
50
- }
8
+ const traceBitmap = (opts) => {
9
+ const mat = opts.mat;
10
+ const { width, height } = opts.img;
11
+ const lines = [];
12
+ const points = [];
13
+ for (let d of opts.dir || ["h", "v", "d1", "d2", "p"]) {
14
+ if (typeof d !== "string") {
15
+ traceLines(
16
+ opts,
17
+ d.order,
18
+ (d.border || borderXY)(width, height),
19
+ d.tx || ident,
20
+ lines
21
+ );
22
+ continue;
51
23
  }
52
- if (mat) {
53
- lines.forEach((p) => {
54
- mulV23(null, mat, p[0]);
55
- mulV23(null, mat, p[1]);
56
- });
57
- points.forEach((p) => mulV23(null, mat, p));
24
+ switch (d) {
25
+ case "h":
26
+ traceLines(opts, rows2d, borderX(width, height), ident, lines);
27
+ break;
28
+ case "v":
29
+ traceLines(
30
+ opts,
31
+ columns2d,
32
+ borderY(width, height),
33
+ ident,
34
+ lines
35
+ );
36
+ break;
37
+ case "d1":
38
+ traceLines(
39
+ opts,
40
+ diagonal2d,
41
+ borderXY(width, height),
42
+ ident,
43
+ lines
44
+ );
45
+ break;
46
+ case "d2":
47
+ traceLines(
48
+ opts,
49
+ diagonal2d,
50
+ borderXY(width, height),
51
+ flipX,
52
+ lines
53
+ );
54
+ break;
55
+ case "p":
56
+ tracePoints(opts, points);
57
+ break;
58
+ default:
59
+ illegalArgs(`invalid trace direction: ${d}`);
58
60
  }
59
- return { lines, points };
61
+ }
62
+ if (mat) {
63
+ lines.forEach((p) => {
64
+ mulV23(null, mat, p[0]);
65
+ mulV23(null, mat, p[1]);
66
+ });
67
+ points.forEach((p) => mulV23(null, mat, p));
68
+ }
69
+ return { lines, points };
60
70
  };
61
- /**
62
- * Extracts line segments in the orientation/order of given grid iterator and
63
- * stores results in `acc`.
64
- *
65
- * @param opts
66
- * @param order
67
- * @param border
68
- * @param tx
69
- * @param acc
70
- */
71
- export const traceLines = (opts, order, border, tx, acc = []) => {
72
- let { img, select, clear, last, min, max } = {
73
- clear: 0,
74
- last: true,
75
- min: 2,
76
- max: Infinity,
77
- ...opts,
78
- };
79
- min--;
80
- let curr = [];
81
- let prevBorder = false;
82
- const $record = () => {
83
- acc.push([curr[0], curr[curr.length - 1]]);
84
- for (let q of curr)
85
- img.setAtUnsafe(q[0], q[1], clear);
86
- };
87
- for (let p of order({ cols: img.width, rows: img.height, tx })) {
88
- const c = select(img.getAtUnsafe(p[0], p[1]), p);
89
- const isBorder = border(p);
90
- const n = curr.length;
91
- if (c) {
92
- if (isBorder || n >= max) {
93
- if (n > 0) {
94
- if (prevBorder) {
95
- if (n > min)
96
- $record();
97
- curr = [p];
98
- }
99
- else {
100
- if (n >= min) {
101
- curr.push(p);
102
- $record();
103
- }
104
- curr = [];
105
- }
106
- }
107
- else {
108
- curr.push(p);
109
- }
110
- }
111
- else {
112
- curr.push(p);
113
- }
114
- }
115
- else if (n > 0) {
116
- if (n > min) {
117
- if (last)
118
- curr.push(p);
119
- $record();
71
+ const traceLines = (opts, order, border, tx, acc = []) => {
72
+ let { img, select, clear, last, min, max } = {
73
+ clear: 0,
74
+ last: true,
75
+ min: 2,
76
+ max: Infinity,
77
+ ...opts
78
+ };
79
+ min--;
80
+ let curr = [];
81
+ let prevBorder = false;
82
+ const $record = () => {
83
+ acc.push([curr[0], curr[curr.length - 1]]);
84
+ for (let q of curr)
85
+ img.setAtUnsafe(q[0], q[1], clear);
86
+ };
87
+ for (let p of order({ cols: img.width, rows: img.height, tx })) {
88
+ const c = select(img.getAtUnsafe(p[0], p[1]), p);
89
+ const isBorder = border(p);
90
+ const n = curr.length;
91
+ if (c) {
92
+ if (isBorder || n >= max) {
93
+ if (n > 0) {
94
+ if (prevBorder) {
95
+ if (n > min)
96
+ $record();
97
+ curr = [p];
98
+ } else {
99
+ if (n >= min) {
100
+ curr.push(p);
101
+ $record();
120
102
  }
121
103
  curr = [];
104
+ }
105
+ } else {
106
+ curr.push(p);
122
107
  }
123
- prevBorder = isBorder;
108
+ } else {
109
+ curr.push(p);
110
+ }
111
+ } else if (n > 0) {
112
+ if (n > min) {
113
+ if (last)
114
+ curr.push(p);
115
+ $record();
116
+ }
117
+ curr = [];
124
118
  }
125
- return acc;
119
+ prevBorder = isBorder;
120
+ }
121
+ return acc;
126
122
  };
127
- /**
128
- * Extracts single pixels and stores their coordinates in `acc`.
129
- *
130
- * @param opts
131
- * @param acc
132
- */
133
- export const tracePoints = ({ img, select, clear }, acc = []) => {
134
- if (clear === undefined)
135
- clear = 0;
136
- for (let i = 0, n = img.data.length, w = img.width; i < n; i++) {
137
- if (select(img.data[i], [i % w, (i / w) | 0])) {
138
- acc.push([i % w, (i / w) | 0]);
139
- img.data[i] = clear;
140
- }
123
+ const tracePoints = ({ img, select, clear }, acc = []) => {
124
+ if (clear === void 0)
125
+ clear = 0;
126
+ for (let i = 0, n = img.data.length, w = img.width; i < n; i++) {
127
+ if (select(img.data[i], [i % w, i / w | 0])) {
128
+ acc.push([i % w, i / w | 0]);
129
+ img.data[i] = clear;
141
130
  }
142
- return acc;
131
+ }
132
+ return acc;
133
+ };
134
+ export {
135
+ traceBitmap,
136
+ traceLines,
137
+ tracePoints
143
138
  };