@thi.ng/geom-clip-line 2.3.49 → 2.3.50

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
@@ -65,7 +65,7 @@ For Node.js REPL:
65
65
  const geomClipLine = await import("@thi.ng/geom-clip-line");
66
66
  ```
67
67
 
68
- Package sizes (brotli'd, pre-treeshake): ESM: 755 bytes
68
+ Package sizes (brotli'd, pre-treeshake): ESM: 761 bytes
69
69
 
70
70
  ## Dependencies
71
71
 
package/clip-poly.js CHANGED
@@ -2,91 +2,70 @@ import { intersectLinePolylineAll } from "@thi.ng/geom-isec/line-poly";
2
2
  import { pointInPolygon2 } from "@thi.ng/geom-isec/point";
3
3
  import { intersectRayPolylineAll } from "@thi.ng/geom-isec/ray-poly";
4
4
  import { direction2 } from "@thi.ng/vectors/direction";
5
- /**
6
- * Computes all intersection points of the **infinite** line defined by `a`, `b`
7
- * with the given polygon. Returns an array of segments where the line is inside
8
- * the polygon.
9
- *
10
- * @remarks
11
- * "Infinite" here means the line extends indefinitely on either side and
12
- * intersections are found also outside the segment a..b. If only intra-segment
13
- * intersections are desired, use {@link clipLineSegmentPoly} instead.
14
- *
15
- * @param a
16
- * @param b
17
- * @param poly
18
- */
19
- export const clipLinePoly = (a, b, poly) => {
20
- const isecs = intersectRayPolylineAll(a, direction2([], a, b), poly, true).isec;
21
- return isecs ? collectSegments(isecs) : undefined;
5
+ const clipLinePoly = (a, b, poly) => {
6
+ const isecs = intersectRayPolylineAll(
7
+ a,
8
+ direction2([], a, b),
9
+ poly,
10
+ true
11
+ ).isec;
12
+ return isecs ? collectSegments(isecs) : void 0;
22
13
  };
23
- /**
24
- * Similar to {@link clipLinePoly}, but only considers intersections within the
25
- * given line segment.
26
- *
27
- * @param a
28
- * @param b
29
- * @param poly
30
- */
31
- export const clipLineSegmentPoly = (a, b, poly) => {
32
- const isecs = intersectLinePolylineAll(a, b, poly, true).isec;
33
- const isAInside = pointInPolygon2(a, poly);
14
+ const clipLineSegmentPoly = (a, b, poly) => {
15
+ const isecs = intersectLinePolylineAll(a, b, poly, true).isec;
16
+ const isAInside = pointInPolygon2(a, poly);
17
+ const isBInside = pointInPolygon2(b, poly);
18
+ if (!isecs) {
19
+ return isAInside && isBInside ? [[a, b]] : void 0;
20
+ }
21
+ isAInside && isecs.unshift(a);
22
+ isBInside && isecs.push(b);
23
+ return collectSegments(isecs);
24
+ };
25
+ const clipPolylinePoly = (pts, poly) => {
26
+ let res = [];
27
+ if (pts.length < 2)
28
+ return res;
29
+ let isAInside = pointInPolygon2(pts[0], poly);
30
+ for (let i = 0, n = pts.length - 1; i < n; i++) {
31
+ const a = pts[i];
32
+ const b = pts[i + 1];
34
33
  const isBInside = pointInPolygon2(b, poly);
34
+ const isecs = intersectLinePolylineAll(a, b, poly, true).isec;
35
35
  if (!isecs) {
36
- return isAInside && isBInside ? [[a, b]] : undefined;
36
+ if (isAInside && isBInside) {
37
+ if (res.length)
38
+ res[res.length - 1].push(b);
39
+ else
40
+ res.push([a, b]);
41
+ }
42
+ } else {
43
+ isAInside && isecs.unshift(a);
44
+ isBInside && isecs.push(b);
45
+ const [first, ...segments] = collectSegments(isecs);
46
+ if (isAInside) {
47
+ if (res.length)
48
+ res[res.length - 1].push(first[1]);
49
+ else
50
+ res.push(first);
51
+ } else {
52
+ res.push(first);
53
+ }
54
+ res.push(...segments);
37
55
  }
38
- isAInside && isecs.unshift(a);
39
- isBInside && isecs.push(b);
40
- return collectSegments(isecs);
41
- };
42
- /**
43
- * Similar to {@link clipLineSegmentPoly}, but for polylines. Returns array of
44
- * new vertex chunks where the given polyline is inside the given bounding poly.
45
- *
46
- * @param pts
47
- * @param poly
48
- */
49
- export const clipPolylinePoly = (pts, poly) => {
50
- let res = [];
51
- if (pts.length < 2)
52
- return res;
53
- let isAInside = pointInPolygon2(pts[0], poly);
54
- for (let i = 0, n = pts.length - 1; i < n; i++) {
55
- const a = pts[i];
56
- const b = pts[i + 1];
57
- const isBInside = pointInPolygon2(b, poly);
58
- const isecs = intersectLinePolylineAll(a, b, poly, true).isec;
59
- if (!isecs) {
60
- if (isAInside && isBInside) {
61
- if (res.length)
62
- res[res.length - 1].push(b);
63
- else
64
- res.push([a, b]);
65
- }
66
- }
67
- else {
68
- isAInside && isecs.unshift(a);
69
- isBInside && isecs.push(b);
70
- const [first, ...segments] = collectSegments(isecs);
71
- if (isAInside) {
72
- if (res.length)
73
- res[res.length - 1].push(first[1]);
74
- else
75
- res.push(first);
76
- }
77
- else {
78
- res.push(first);
79
- }
80
- res.push(...segments);
81
- }
82
- isAInside = isBInside;
83
- }
84
- return res;
56
+ isAInside = isBInside;
57
+ }
58
+ return res;
85
59
  };
86
60
  const collectSegments = (isecs) => {
87
- const segments = [];
88
- for (let i = 0, n = isecs.length - 1; i < n; i += 2) {
89
- segments.push([isecs[i], isecs[i + 1]]);
90
- }
91
- return segments;
61
+ const segments = [];
62
+ for (let i = 0, n = isecs.length - 1; i < n; i += 2) {
63
+ segments.push([isecs[i], isecs[i + 1]]);
64
+ }
65
+ return segments;
66
+ };
67
+ export {
68
+ clipLinePoly,
69
+ clipLineSegmentPoly,
70
+ clipPolylinePoly
92
71
  };
package/clip-with.js CHANGED
@@ -1,68 +1,31 @@
1
- /**
2
- * Segments given polyline based on given predicate and `step` size. Returns
3
- * array of segmented vertex chunks.
4
- *
5
- * @remarks
6
- * Vertices are processed pairwise using given `step` size (default: 1). As long
7
- * as the predicate is true, vertices are collected into the current chunk. If
8
- * the predicate returns false, the current chunk is terminated and depending on
9
- * `keepLast`, the current vertex (i.e. for which the predicate failed) is still
10
- * added or not. If `keepLast` is false and the current chunk only included one
11
- * other vertex, that entire chunk will be discarded.
12
- *
13
- * @example
14
- * ```ts
15
- * const pts = [[0, 0], [1, 0], [1, 1], [2, 1], [3, 1], [4, 0], [5, 0]];
16
- *
17
- * // isolate horizontal chunks
18
- * clipPolylineWith((a, b) => a[1] == b[1], pts)
19
- * // [
20
- * // [[0, 0], [1, 0]],
21
- * // [[1, 1], [2, 1], [3, 1]],
22
- * // [[4, 0], [5, 0]]
23
- * // ]
24
- *
25
- * // isolate sloped chunks
26
- * clipPolylineWith((a, b) => a[1] != b[1], pts)
27
- * // [
28
- * // [[1, 0], [1, 1]],
29
- * // [[3, 1], [4, 0]]
30
- * // ]
31
- * ```
32
- *
33
- * @param pred
34
- * @param pts
35
- * @param step
36
- * @param keepLast
37
- */
38
- export const clipPolylineWith = (pred, pts, step = 1, keepLast = true) => {
39
- const segs = [];
40
- let last = -1;
41
- const $terminate = (i) => {
42
- if (last !== -1) {
43
- if (keepLast) {
44
- segs[segs.length - 1].push(pts[i]);
45
- }
46
- else if (segs[segs.length - 1].length < 2) {
47
- segs.pop();
48
- }
49
- }
50
- last = -1;
51
- };
52
- for (let i = 0, n = pts.length - step; i < n; i++) {
53
- if (pred(pts[i], pts[i + step])) {
54
- if (last === -1) {
55
- segs.push([pts[i]]);
56
- last = i;
57
- }
58
- else {
59
- segs[segs.length - 1].push(pts[i]);
60
- }
61
- }
62
- else {
63
- $terminate(i);
64
- }
1
+ const clipPolylineWith = (pred, pts, step = 1, keepLast = true) => {
2
+ const segs = [];
3
+ let last = -1;
4
+ const $terminate = (i) => {
5
+ if (last !== -1) {
6
+ if (keepLast) {
7
+ segs[segs.length - 1].push(pts[i]);
8
+ } else if (segs[segs.length - 1].length < 2) {
9
+ segs.pop();
10
+ }
65
11
  }
66
- $terminate(pts.length - step);
67
- return segs;
12
+ last = -1;
13
+ };
14
+ for (let i = 0, n = pts.length - step; i < n; i++) {
15
+ if (pred(pts[i], pts[i + step])) {
16
+ if (last === -1) {
17
+ segs.push([pts[i]]);
18
+ last = i;
19
+ } else {
20
+ segs[segs.length - 1].push(pts[i]);
21
+ }
22
+ } else {
23
+ $terminate(i);
24
+ }
25
+ }
26
+ $terminate(pts.length - step);
27
+ return segs;
28
+ };
29
+ export {
30
+ clipPolylineWith
68
31
  };
package/liang-barsky.js CHANGED
@@ -1,84 +1,59 @@
1
- /**
2
- * Performs Liang-Barsky clipping of the line segment with endpoints `a`, `b`
3
- * against the clipping rect defined by `min` and `max`. The optional `ca` and
4
- * `cb` vectors can be given to store the result (clipped points). If omitted
5
- * creates new vectors. Returns a tuple of `[ca, cb, a, b]`, where the latter
6
- * two values represent the normalized distances of the clipped points relative
7
- * to original given line segment. Returns `undefined` iff the line lies
8
- * completely outside the rect.
9
- *
10
- * - https://en.wikipedia.org/wiki/Liang%E2%80%93Barsky_algorithm
11
- * - https://github.com/thi-ng/c-thing/blob/develop/src/geom/clip/liangbarsky.c
12
- *
13
- * @param a - line endpoint
14
- * @param b - line endpoint
15
- * @param min - bbox min
16
- * @param max - bbox max
17
- * @param ca - result A
18
- * @param cb - result B
19
- */
20
- export const liangBarsky2 = (a, b, min, max, ca = [], cb = []) => {
21
- const res = liangBarsky2Raw(a[0], a[1], b[0], b[1], min[0], min[1], max[0], max[1]);
22
- if (!res)
23
- return;
24
- ca[0] = res[0];
25
- ca[1] = res[1];
26
- cb[0] = res[2];
27
- cb[1] = res[3];
28
- return [ca, cb, res[4], res[5]];
1
+ const liangBarsky2 = (a, b, min, max, ca = [], cb = []) => {
2
+ const res = liangBarsky2Raw(
3
+ a[0],
4
+ a[1],
5
+ b[0],
6
+ b[1],
7
+ min[0],
8
+ min[1],
9
+ max[0],
10
+ max[1]
11
+ );
12
+ if (!res)
13
+ return;
14
+ ca[0] = res[0];
15
+ ca[1] = res[1];
16
+ cb[0] = res[2];
17
+ cb[1] = res[3];
18
+ return [ca, cb, res[4], res[5]];
29
19
  };
30
- /**
31
- * Same as {@link liangBarsky2} but for non-vector arguments.
32
- *
33
- * @param ax -
34
- * @param ay -
35
- * @param bx -
36
- * @param by -
37
- * @param minx -
38
- * @param miny -
39
- * @param maxx -
40
- * @param maxy -
41
- */
42
- export const liangBarsky2Raw = (ax, ay, bx, by, minx, miny, maxx, maxy) => {
43
- const dx = bx - ax;
44
- const dy = by - ay;
45
- let alpha = 0;
46
- let beta = 1;
47
- const clip = (p, q) => {
48
- if (p < 0) {
49
- const r = q / p;
50
- if (r > beta) {
51
- return false;
52
- }
53
- if (r > alpha) {
54
- alpha = r;
55
- }
56
- }
57
- else if (p > 0) {
58
- const r = q / p;
59
- if (r < alpha) {
60
- return false;
61
- }
62
- if (r < beta) {
63
- beta = r;
64
- }
65
- }
66
- else if (q < 0) {
67
- return false;
68
- }
69
- return true;
70
- };
71
- return clip(-dx, ax - minx) &&
72
- clip(dx, maxx - ax) &&
73
- clip(-dy, ay - miny) &&
74
- clip(dy, maxy - ay)
75
- ? [
76
- alpha * dx + ax,
77
- alpha * dy + ay,
78
- beta * dx + ax,
79
- beta * dy + ay,
80
- alpha,
81
- beta,
82
- ]
83
- : undefined;
20
+ const liangBarsky2Raw = (ax, ay, bx, by, minx, miny, maxx, maxy) => {
21
+ const dx = bx - ax;
22
+ const dy = by - ay;
23
+ let alpha = 0;
24
+ let beta = 1;
25
+ const clip = (p, q) => {
26
+ if (p < 0) {
27
+ const r = q / p;
28
+ if (r > beta) {
29
+ return false;
30
+ }
31
+ if (r > alpha) {
32
+ alpha = r;
33
+ }
34
+ } else if (p > 0) {
35
+ const r = q / p;
36
+ if (r < alpha) {
37
+ return false;
38
+ }
39
+ if (r < beta) {
40
+ beta = r;
41
+ }
42
+ } else if (q < 0) {
43
+ return false;
44
+ }
45
+ return true;
46
+ };
47
+ return clip(-dx, ax - minx) && clip(dx, maxx - ax) && clip(-dy, ay - miny) && clip(dy, maxy - ay) ? [
48
+ alpha * dx + ax,
49
+ alpha * dy + ay,
50
+ beta * dx + ax,
51
+ beta * dy + ay,
52
+ alpha,
53
+ beta
54
+ ] : void 0;
55
+ };
56
+ export {
57
+ liangBarsky2,
58
+ liangBarsky2Raw
84
59
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/geom-clip-line",
3
- "version": "2.3.49",
3
+ "version": "2.3.50",
4
4
  "description": "2D line clipping (Liang-Barsky)",
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,12 +35,13 @@
33
35
  "test": "bun test"
34
36
  },
35
37
  "dependencies": {
36
- "@thi.ng/api": "^8.9.11",
37
- "@thi.ng/geom-isec": "^2.1.91",
38
- "@thi.ng/vectors": "^7.8.8"
38
+ "@thi.ng/api": "^8.9.12",
39
+ "@thi.ng/geom-isec": "^2.1.92",
40
+ "@thi.ng/vectors": "^7.8.9"
39
41
  },
40
42
  "devDependencies": {
41
43
  "@microsoft/api-extractor": "^7.38.3",
44
+ "esbuild": "^0.19.8",
42
45
  "rimraf": "^5.0.5",
43
46
  "tools": "^0.0.1",
44
47
  "typedoc": "^0.25.4",
@@ -85,5 +88,5 @@
85
88
  ],
86
89
  "year": 2013
87
90
  },
88
- "gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
91
+ "gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
89
92
  }