@thi.ng/geom-sdf 0.1.0 → 0.2.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/dist.d.ts CHANGED
@@ -1,10 +1,97 @@
1
1
  import { ReadonlyVec } from "@thi.ng/vectors/api";
2
+ /**
3
+ * Computes signed distance to centered 2D circle of given `radius`.
4
+ *
5
+ * @remarks
6
+ * Ported from code by Inigo Quilez:
7
+ * https://iquilezles.org/articles/distfunctions2d/
8
+ *
9
+ * @param p
10
+ * @param radius
11
+ */
2
12
  export declare const distCircle2: (p: ReadonlyVec, radius: number) => number;
3
- export declare const distBox2: (p: ReadonlyVec, size: ReadonlyVec) => number;
4
- export declare const distPolygon2: (pts: ReadonlyVec[], p: ReadonlyVec) => number;
5
- export declare const distSegment2: (a: ReadonlyVec, b: ReadonlyVec, p: ReadonlyVec) => number;
6
- export declare const distPolyline2: (pts: ReadonlyVec[], p: ReadonlyVec) => number;
13
+ /**
14
+ * Computes signed distance to centered 2D box of given `halfSize`.
15
+ *
16
+ * @remarks
17
+ * Ported from code by Inigo Quilez:
18
+ * https://iquilezles.org/articles/distfunctions2d/
19
+ *
20
+ * @param p
21
+ * @param halfSize
22
+ */
23
+ export declare const distBox2: (p: ReadonlyVec, halfSize: ReadonlyVec) => number;
24
+ /**
25
+ * Computes signed distance to the 2D polygon defined by given point array.
26
+ *
27
+ * @remarks
28
+ * Ported from code by Inigo Quilez:
29
+ * https://iquilezles.org/articles/distfunctions2d/
30
+ *
31
+ * @param p
32
+ * @param pts
33
+ */
34
+ export declare const distPolygon2: (p: ReadonlyVec, pts: ReadonlyVec[]) => number;
35
+ /**
36
+ * Computes distance to 2D line segment defined by endpoints `a` and `b`.
37
+ *
38
+ * @remarks
39
+ * Ported from code by Inigo Quilez:
40
+ * https://iquilezles.org/articles/distfunctions2d/
41
+ *
42
+ * @param p
43
+ * @param a
44
+ * @param b
45
+ */
46
+ export declare const distSegment2: (p: ReadonlyVec, a: ReadonlyVec, b: ReadonlyVec) => number;
47
+ /**
48
+ * Computes distance to 2D polyline defined by given point array (i.e. the union
49
+ * of pairwise results of {@link distSegment2}).
50
+ *
51
+ * @param p
52
+ * @param pts
53
+ */
54
+ export declare const distPolyline2: (p: ReadonlyVec, pts: ReadonlyVec[]) => number;
55
+ /**
56
+ * Computes signed distance to circular arc with given aperture, radius and
57
+ * radius offset (thickness). The aperture is symmetric along the Y-axis and has
58
+ * its origin in +Y.
59
+ *
60
+ * @remarks
61
+ * Ported from code by Inigo Quilez:
62
+ * https://iquilezles.org/articles/distfunctions2d/
63
+ *
64
+ * @param p
65
+ * @param apert - pre-computed vec2 of [sin, cos] of aperture angle
66
+ * @param ra - inner radius
67
+ * @param rb - outer radius offset (thickness)
68
+ */
7
69
  export declare const distArc2: (p: ReadonlyVec, apert: ReadonlyVec, ra: number, rb: number) => number;
70
+ /**
71
+ * Computes (unsigned, by default) distance to given 2D quadratic bezier
72
+ * segment. If `signed` is set to true, points in the curve's interior region
73
+ * will yield negative distances.
74
+ *
75
+ * @remarks
76
+ * Based on code by Inigo Quilez:
77
+ * https://iquilezles.org/articles/distfunctions2d/
78
+ *
79
+ * @param pos
80
+ * @param a
81
+ * @param b
82
+ * @param c
83
+ * @param signed
84
+ */
8
85
  export declare const distQuadratic2: (pos: ReadonlyVec, a: ReadonlyVec, b: ReadonlyVec, c: ReadonlyVec, signed?: boolean) => number;
86
+ /**
87
+ * Computes signed distance to centered 2D ellipse.
88
+ *
89
+ * @remarks
90
+ * Based on code by Inigo Quilez:
91
+ * https://iquilezles.org/articles/distfunctions2d/
92
+ *
93
+ * @param p
94
+ * @param radii
95
+ */
9
96
  export declare const distEllipse2: ([px, py]: ReadonlyVec, [abx, aby]: ReadonlyVec) => number;
10
97
  //# sourceMappingURL=dist.d.ts.map
package/dist.js CHANGED
@@ -1,4 +1,4 @@
1
- import { SQRT3 } from "@thi.ng/math";
1
+ import { SQRT3 } from "@thi.ng/math/api";
2
2
  import { clamp01 } from "@thi.ng/math/interval";
3
3
  import { abs2 } from "@thi.ng/vectors/abs";
4
4
  import { add2 } from "@thi.ng/vectors/add";
@@ -16,55 +16,135 @@ import { powN2 } from "@thi.ng/vectors/pown";
16
16
  import { sign2 } from "@thi.ng/vectors/sign";
17
17
  import { some3 } from "@thi.ng/vectors/some";
18
18
  import { sub2 } from "@thi.ng/vectors/sub";
19
- const mag2 = (v) => Math.sqrt(magSq2(v));
19
+ const t1 = [];
20
+ const t2 = [];
21
+ const t3 = [];
22
+ const t4 = [];
23
+ const t5 = [];
24
+ const { abs, cos, min, max, sign, sin, sqrt } = Math;
25
+ const mag2 = (v) => sqrt(magSq2(v));
26
+ /**
27
+ * Computes signed distance to centered 2D circle of given `radius`.
28
+ *
29
+ * @remarks
30
+ * Ported from code by Inigo Quilez:
31
+ * https://iquilezles.org/articles/distfunctions2d/
32
+ *
33
+ * @param p
34
+ * @param radius
35
+ */
20
36
  export const distCircle2 = (p, radius) => mag2(p) - radius;
21
- export const distBox2 = (p, size) => {
22
- const d = sub2(null, abs2([], p), size);
23
- return Math.min(Math.max(d[0], d[1]), 0) + mag2(max2(null, d, ZERO2));
37
+ /**
38
+ * Computes signed distance to centered 2D box of given `halfSize`.
39
+ *
40
+ * @remarks
41
+ * Ported from code by Inigo Quilez:
42
+ * https://iquilezles.org/articles/distfunctions2d/
43
+ *
44
+ * @param p
45
+ * @param halfSize
46
+ */
47
+ export const distBox2 = (p, halfSize) => {
48
+ const d = sub2(null, abs2(t1, p), halfSize);
49
+ return min(max(d[0], d[1]), 0) + mag2(max2(null, d, ZERO2));
24
50
  };
25
- export const distPolygon2 = (pts, p) => {
51
+ /**
52
+ * Computes signed distance to the 2D polygon defined by given point array.
53
+ *
54
+ * @remarks
55
+ * Ported from code by Inigo Quilez:
56
+ * https://iquilezles.org/articles/distfunctions2d/
57
+ *
58
+ * @param p
59
+ * @param pts
60
+ */
61
+ export const distPolygon2 = (p, pts) => {
26
62
  let d = distSq2(p, pts[0]);
27
63
  let s = 1;
28
64
  const py = p[1];
29
- const t1 = [];
30
- const t2 = [];
31
- const t3 = [];
32
65
  for (let n = pts.length, i = 0, j = n - 1; i < n; j = i, i++) {
33
66
  const pi = pts[i];
34
67
  const pj = pts[j];
35
68
  const e = sub2(t1, pj, pi);
36
69
  const w = sub2(t2, p, pi);
37
- d = Math.min(d, distSq2(w, mulN2(t3, e, clamp01(dot2(w, e) / magSq2(e)))));
70
+ d = min(d, distSq2(w, mulN2(t3, e, clamp01(dot2(w, e) / magSq2(e)))));
38
71
  const c = [py >= pi[1], py < pj[1], e[0] * w[1] > e[1] * w[0]];
39
72
  if (every3(c) || !some3(c))
40
73
  s *= -1;
41
74
  }
42
- return s * Math.sqrt(d);
75
+ return s * sqrt(d);
43
76
  };
44
- export const distSegment2 = (a, b, p) => {
45
- const pa = sub2([], p, a);
46
- const ba = sub2([], b, a);
47
- const h = clamp01(dot2(pa, ba) / magSq2(ba));
48
- return mag2(sub2(null, pa, mulN2(null, ba, h)));
77
+ /**
78
+ * Computes distance to 2D line segment defined by endpoints `a` and `b`.
79
+ *
80
+ * @remarks
81
+ * Ported from code by Inigo Quilez:
82
+ * https://iquilezles.org/articles/distfunctions2d/
83
+ *
84
+ * @param p
85
+ * @param a
86
+ * @param b
87
+ */
88
+ export const distSegment2 = (p, a, b) => {
89
+ const pa = sub2(t1, p, a);
90
+ const ba = sub2(t2, b, a);
91
+ return mag2(sub2(null, pa, mulN2(null, ba, clamp01(dot2(pa, ba) / magSq2(ba)))));
49
92
  };
50
- export const distPolyline2 = (pts, p) => {
93
+ /**
94
+ * Computes distance to 2D polyline defined by given point array (i.e. the union
95
+ * of pairwise results of {@link distSegment2}).
96
+ *
97
+ * @param p
98
+ * @param pts
99
+ */
100
+ export const distPolyline2 = (p, pts) => {
51
101
  let d = Infinity;
52
102
  for (let i = 1, n = pts.length; i < n; i++) {
53
- d = Math.min(d, distSegment2(pts[i - 1], pts[i], p));
103
+ d = min(d, distSegment2(p, pts[i - 1], pts[i]));
54
104
  }
55
105
  return d;
56
106
  };
107
+ /**
108
+ * Computes signed distance to circular arc with given aperture, radius and
109
+ * radius offset (thickness). The aperture is symmetric along the Y-axis and has
110
+ * its origin in +Y.
111
+ *
112
+ * @remarks
113
+ * Ported from code by Inigo Quilez:
114
+ * https://iquilezles.org/articles/distfunctions2d/
115
+ *
116
+ * @param p
117
+ * @param apert - pre-computed vec2 of [sin, cos] of aperture angle
118
+ * @param ra - inner radius
119
+ * @param rb - outer radius offset (thickness)
120
+ */
57
121
  export const distArc2 = (p, apert, ra, rb) => {
58
- const q = [Math.abs(p[0]), p[1]];
59
- return ((apert[1] * q[0] > apert[0] * q[1]
60
- ? mag2(maddN2(q, apert, -ra, q))
61
- : Math.abs(mag2(q) - ra)) - rb);
122
+ t1[0] = abs(p[0]);
123
+ t1[1] = p[1];
124
+ return ((apert[1] * t1[0] > apert[0] * t1[1]
125
+ ? mag2(maddN2(t1, apert, -ra, t1))
126
+ : abs(mag2(t1) - ra)) - rb);
62
127
  };
63
- export const distQuadratic2 = (pos, a, b, c, signed = true) => {
64
- const aa = sub2([], b, a);
65
- const bb = add2(null, maddN2([], b, -2, a), c);
66
- const cc = mulN2([], aa, 2);
67
- const dd = sub2([], a, pos);
128
+ /**
129
+ * Computes (unsigned, by default) distance to given 2D quadratic bezier
130
+ * segment. If `signed` is set to true, points in the curve's interior region
131
+ * will yield negative distances.
132
+ *
133
+ * @remarks
134
+ * Based on code by Inigo Quilez:
135
+ * https://iquilezles.org/articles/distfunctions2d/
136
+ *
137
+ * @param pos
138
+ * @param a
139
+ * @param b
140
+ * @param c
141
+ * @param signed
142
+ */
143
+ export const distQuadratic2 = (pos, a, b, c, signed = false) => {
144
+ const aa = sub2(t1, b, a);
145
+ const bb = add2(null, maddN2(t2, b, -2, a), c);
146
+ const cc = mulN2(t3, aa, 2);
147
+ const dd = sub2(t4, a, pos);
68
148
  const kk = 1 / magSq2(bb);
69
149
  const kx = kk * dot2(aa, bb);
70
150
  const ky = (kk * (2 * magSq2(aa) + dot2(dd, bb))) / 3;
@@ -75,38 +155,45 @@ export const distQuadratic2 = (pos, a, b, c, signed = true) => {
75
155
  const q2 = q * q;
76
156
  let h = q2 + 4 * p3;
77
157
  if (h >= 0) {
78
- h = Math.sqrt(h);
158
+ h = sqrt(h);
79
159
  const x = [(h - q) / 2, (-h - q) / 2];
80
- const uv = mul2(null, sign2([], x), powN2([], abs2([], x), 1 / 3));
160
+ const uv = mul2(null, sign2(t1, x), powN2(null, abs2(null, x), 1 / 3));
81
161
  const t = clamp01(uv[0] + uv[1] - kx);
82
- const qq = maddN2(null, maddN2([], bb, t, cc), t, dd);
162
+ const qq = maddN2(null, maddN2(t1, bb, t, cc), t, dd);
83
163
  return (mag2(qq) *
84
- (signed ? Math.sign(cross2(maddN2([], bb, 2 * t, cc), qq)) : 1));
164
+ (signed ? sign(cross2(maddN2(bb, bb, 2 * t, cc), qq)) : 1));
85
165
  }
86
166
  else {
87
- const z = Math.sqrt(-p);
167
+ const z = sqrt(-p);
88
168
  const v = Math.acos(q / (p * z * 2)) / 3;
89
- const m = Math.cos(v);
90
- const n = Math.sin(v) * 1.732050808;
169
+ const m = cos(v);
170
+ const n = sin(v) * SQRT3;
91
171
  const tx = clamp01((m + m) * z - kx);
92
172
  const ty = clamp01((-n - m) * z - kx);
93
- const qx = maddN2(null, maddN2([], bb, tx, cc), tx, dd);
173
+ const qx = maddN2(null, maddN2(t1, bb, tx, cc), tx, dd);
94
174
  const dx = magSq2(qx);
95
- const qy = maddN2(null, maddN2([], bb, ty, cc), ty, dd);
175
+ const qy = maddN2(null, maddN2(t5, bb, ty, cc), ty, dd);
96
176
  const dy = magSq2(qy);
97
- if (dx < dy) {
98
- return (Math.sqrt(dx) *
99
- (signed ? Math.sign(cross2(maddN2([], bb, 2 * tx, cc), qx)) : 1));
100
- }
101
- else {
102
- return (Math.sqrt(dy) *
103
- (signed ? Math.sign(cross2(maddN2([], bb, 2 * ty, cc), qy)) : 1));
104
- }
177
+ return dx < dy
178
+ ? sqrt(dx) *
179
+ (signed ? sign(cross2(maddN2(bb, bb, 2 * tx, cc), qx)) : 1)
180
+ : sqrt(dy) *
181
+ (signed ? sign(cross2(maddN2(bb, bb, 2 * ty, cc), qy)) : 1);
105
182
  }
106
183
  };
184
+ /**
185
+ * Computes signed distance to centered 2D ellipse.
186
+ *
187
+ * @remarks
188
+ * Based on code by Inigo Quilez:
189
+ * https://iquilezles.org/articles/distfunctions2d/
190
+ *
191
+ * @param p
192
+ * @param radii
193
+ */
107
194
  export const distEllipse2 = ([px, py], [abx, aby]) => {
108
- px = Math.abs(px);
109
- py = Math.abs(py);
195
+ px = abs(px);
196
+ py = abs(py);
110
197
  if (px > py) {
111
198
  let t = px;
112
199
  px = py;
@@ -129,22 +216,22 @@ export const distEllipse2 = ([px, py], [abx, aby]) => {
129
216
  let co;
130
217
  if (d < 0) {
131
218
  const h = Math.acos(q / c3) / 3;
132
- const s = Math.cos(h);
133
- const t = Math.sin(h) * SQRT3;
134
- const rx = Math.sqrt(-c * (s + t + 2) + m2);
135
- const ry = Math.sqrt(-c * (s - t + 2) + m2);
136
- co = (ry + Math.sign(l) * rx + Math.abs(g) / (rx * ry) - m) / 2;
219
+ const s = cos(h);
220
+ const t = sin(h) * SQRT3;
221
+ const rx = sqrt(-c * (s + t + 2) + m2);
222
+ const ry = sqrt(-c * (s - t + 2) + m2);
223
+ co = (ry + sign(l) * rx + abs(g) / (rx * ry) - m) / 2;
137
224
  }
138
225
  else {
139
- const h = 2 * m * n * Math.sqrt(d);
140
- const s = Math.sign(q + h) * Math.cbrt(Math.abs(q + h));
141
- const u = Math.sign(q - h) * Math.cbrt(Math.abs(q - h));
226
+ const h = 2 * m * n * sqrt(d);
227
+ const s = sign(q + h) * Math.cbrt(abs(q + h));
228
+ const u = sign(q - h) * Math.cbrt(abs(q - h));
142
229
  const rx = -s - u - c * 4 + 2 * m2;
143
230
  const ry = (s - u) * SQRT3;
144
231
  const rm = Math.hypot(rx, ry);
145
- co = (ry / Math.sqrt(rm - rx) + (2 * g) / rm - m) / 2;
232
+ co = (ry / sqrt(rm - rx) + (2 * g) / rm - m) / 2;
146
233
  }
147
234
  const rx = abx * co;
148
- const ry = aby * Math.sqrt(1 - co * co);
149
- return Math.hypot(rx - px, ry - py) * Math.sign(py - ry);
235
+ const ry = aby * sqrt(1 - co * co);
236
+ return Math.hypot(rx - px, ry - py) * sign(py - ry);
150
237
  };
package/domain.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ import type { ReadonlyVec, Vec } from "@thi.ng/vectors/api";
2
+ /**
3
+ * @remarks
4
+ * Ported from: HG_SDF by Mercury Demogroup
5
+ * https://mercury.sexy/hg_sdf/
6
+ *
7
+ * @param size
8
+ */
9
+ export declare const repeat2: (size: ReadonlyVec) => (p: ReadonlyVec) => Vec;
10
+ /**
11
+ * @remarks
12
+ * Ported from: HG_SDF by Mercury Demogroup
13
+ * https://mercury.sexy/hg_sdf/
14
+ *
15
+ * @param size
16
+ */
17
+ export declare const repeatMirror2: (size: ReadonlyVec) => (p: ReadonlyVec) => Vec;
18
+ /**
19
+ * @remarks
20
+ * Ported from: HG_SDF by Mercury Demogroup
21
+ * https://mercury.sexy/hg_sdf/
22
+ *
23
+ * @param size
24
+ */
25
+ export declare const repeatGrid2: (size: ReadonlyVec) => (p: ReadonlyVec) => ReadonlyVec;
26
+ /**
27
+ * @remarks
28
+ * Ported from: HG_SDF by Mercury Demogroup
29
+ * https://mercury.sexy/hg_sdf/
30
+ *
31
+ * @param n - number of repetition
32
+ */
33
+ export declare const repeatPolar2: (n: number) => (p: ReadonlyVec) => number[];
34
+ //# sourceMappingURL=domain.d.ts.map
package/domain.js ADDED
@@ -0,0 +1,63 @@
1
+ import { cossin } from "@thi.ng/math";
2
+ import { TAU } from "@thi.ng/math/api";
3
+ import { mod } from "@thi.ng/math/prec";
4
+ import { add2 } from "@thi.ng/vectors/add";
5
+ import { div2 } from "@thi.ng/vectors/div";
6
+ import { floor2 } from "@thi.ng/vectors/floor";
7
+ import { mag } from "@thi.ng/vectors/mag";
8
+ import { mod2 } from "@thi.ng/vectors/mod";
9
+ import { modN2 } from "@thi.ng/vectors/modn";
10
+ import { mul2 } from "@thi.ng/vectors/mul";
11
+ import { mulN2 } from "@thi.ng/vectors/muln";
12
+ import { sub2 } from "@thi.ng/vectors/sub";
13
+ import { subN2 } from "@thi.ng/vectors/subn";
14
+ /**
15
+ * @remarks
16
+ * Ported from: HG_SDF by Mercury Demogroup
17
+ * https://mercury.sexy/hg_sdf/
18
+ *
19
+ * @param size
20
+ */
21
+ export const repeat2 = (size) => {
22
+ const s2 = mulN2([], size, 0.5);
23
+ return (p) => sub2(null, mod2(null, add2([], s2, p), size), s2);
24
+ };
25
+ /**
26
+ * @remarks
27
+ * Ported from: HG_SDF by Mercury Demogroup
28
+ * https://mercury.sexy/hg_sdf/
29
+ *
30
+ * @param size
31
+ */
32
+ export const repeatMirror2 = (size) => {
33
+ const c = [];
34
+ const s2 = mulN2([], size, 0.5);
35
+ return (p) => mul2(null, sub2(null, mod2(null, add2([], s2, p), size), s2), subN2(null, mulN2(null, modN2(null, floor2(null, div2(null, add2(c, s2, p), size)), 2), 2), 1));
36
+ };
37
+ /**
38
+ * @remarks
39
+ * Ported from: HG_SDF by Mercury Demogroup
40
+ * https://mercury.sexy/hg_sdf/
41
+ *
42
+ * @param size
43
+ */
44
+ export const repeatGrid2 = (size) => {
45
+ const s2 = mulN2([], size, 0.5);
46
+ const rm = repeatMirror2(size);
47
+ return (p) => {
48
+ p = sub2(null, rm(p), s2);
49
+ return p[0] > p[1] ? [p[1], p[0]] : p;
50
+ };
51
+ };
52
+ /**
53
+ * @remarks
54
+ * Ported from: HG_SDF by Mercury Demogroup
55
+ * https://mercury.sexy/hg_sdf/
56
+ *
57
+ * @param n - number of repetition
58
+ */
59
+ export const repeatPolar2 = (n) => {
60
+ const theta = TAU / n;
61
+ const halfTheta = theta / 2;
62
+ return (p) => cossin(mod(Math.atan2(p[1], p[0]) + halfTheta, theta) - halfTheta, mag(p));
63
+ };
package/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from "./api.js";
2
+ export * from "./as-polygons.js";
2
3
  export * from "./as-sdf.js";
3
4
  export * from "./dist.js";
5
+ export * from "./domain.js";
4
6
  export * from "./ops.js";
5
7
  export * from "./sample.js";
6
8
  export * from "./shapes.js";
package/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from "./api.js";
2
+ export * from "./as-polygons.js";
2
3
  export * from "./as-sdf.js";
3
4
  export * from "./dist.js";
5
+ export * from "./domain.js";
4
6
  export * from "./ops.js";
5
7
  export * from "./sample.js";
6
8
  export * from "./shapes.js";
package/ops.d.ts CHANGED
@@ -1,11 +1,23 @@
1
- import type { SDFn } from "./api.js";
1
+ import type { Fn3, FnN2 } from "@thi.ng/api";
2
+ import type { FieldCoeff, SDFn } from "./api.js";
2
3
  export declare const abs: (sdf: SDFn) => SDFn;
3
4
  export declare const flip: (sdf: SDFn) => SDFn;
4
- export declare const round: (sdf: SDFn, r: number) => SDFn;
5
+ export declare const offset: (sdf: SDFn, r: number | FieldCoeff) => SDFn;
6
+ export declare const defOp: (op: FnN2) => (children: SDFn[]) => SDFn;
5
7
  export declare const union: (children: SDFn[]) => SDFn;
6
- export declare const intersection: (children: SDFn[]) => SDFn;
7
- export declare const difference: (a: SDFn, ...children: SDFn[]) => SDFn;
8
- export declare const smoothUnion: (k: number, a: SDFn, ...children: SDFn[]) => SDFn;
9
- export declare const smoothIntersection: (k: number, a: SDFn, ...children: SDFn[]) => SDFn;
10
- export declare const smoothDifference: (k: number, a: SDFn, ...children: SDFn[]) => SDFn;
8
+ export declare const isec: (children: SDFn[]) => SDFn;
9
+ export declare const diff: (children: SDFn[]) => SDFn;
10
+ export declare const defParamOp: <T = number>(op: Fn3<number, number, T, number>) => (k: T | FieldCoeff<T>, children: SDFn[]) => SDFn;
11
+ export declare const smoothUnion: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
12
+ export declare const smoothIsec: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
13
+ export declare const smoothDiff: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
14
+ export declare const chamferUnion: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
15
+ export declare const chamferIsec: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
16
+ export declare const chamferDiff: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
17
+ export declare const roundUnion: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
18
+ export declare const roundIsec: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
19
+ export declare const roundDiff: (k: number | FieldCoeff<number>, children: SDFn[]) => SDFn;
20
+ export declare const stepUnion: (k: [number, number] | FieldCoeff<[number, number]>, children: SDFn[]) => SDFn;
21
+ export declare const stepIsec: (k: [number, number] | FieldCoeff<[number, number]>, children: SDFn[]) => SDFn;
22
+ export declare const stepDiff: (k: [number, number] | FieldCoeff<[number, number]>, children: SDFn[]) => SDFn;
11
23
  //# sourceMappingURL=ops.d.ts.map
package/ops.js CHANGED
@@ -1,22 +1,74 @@
1
- import { clamp01, mix } from "@thi.ng/math";
2
- export const abs = (sdf) => (p) => Math.abs(sdf(p));
3
- export const flip = (sdf) => (p) => -sdf(p);
4
- export const round = (sdf, r) => (p) => sdf(p) - r;
5
- export const union = (children) => (p) => children.reduce((acc, f) => Math.min(acc, f(p)), Infinity);
6
- export const intersection = (children) => (p) => children.reduce((acc, f) => Math.max(acc, f(p)), -Infinity);
7
- export const difference = (a, ...children) => (p) => children.reduce((acc, f) => Math.max(acc, -f(p)), a(p));
8
- export const smoothUnion = (k, a, ...children) => (p) => children.reduce((acc, f) => {
9
- const d = f(p);
10
- const h = clamp01(0.5 + (0.5 * (d - acc)) / k);
11
- return mix(d, acc, h) - k * h * (1 - h);
12
- }, a(p));
13
- export const smoothIntersection = (k, a, ...children) => (p) => children.reduce((acc, f) => {
14
- const d = f(p);
15
- const h = clamp01(0.5 - (0.5 * (d - acc)) / k);
16
- return mix(d, acc, h) + k * h * (1 - h);
17
- }, a(p));
18
- export const smoothDifference = (k, a, ...children) => (p) => children.reduce((acc, f) => {
19
- const d = f(p);
20
- const h = clamp01(0.5 - (0.5 * (acc + d)) / k);
21
- return mix(acc, -d, h) + k * h * (1 - h);
22
- }, a(p));
1
+ import { isFunction } from "@thi.ng/checks/is-function";
2
+ import { assert } from "@thi.ng/errors/assert";
3
+ import { clamp01, mix, mod, SQRT2_2 } from "@thi.ng/math";
4
+ const __asField = (k) => (isFunction(k) ? k : () => k);
5
+ const __ensureChildren = (children, min = 1) => assert(children.length >= 1, `require at least ${min} SDF(s)`);
6
+ const { min, max } = Math;
7
+ export const abs = (sdf) => (p, minD) => Math.abs(sdf(p, minD));
8
+ export const flip = (sdf) => (p, minD) => -sdf(p, minD);
9
+ export const offset = (sdf, r) => isFunction(r)
10
+ ? (p, minD) => sdf(p, minD) - r(p)
11
+ : (p, minD) => sdf(p, minD) - r;
12
+ export const defOp = (op) => (children) => {
13
+ __ensureChildren(children);
14
+ const n = children.length;
15
+ return (p, minD = Infinity) => {
16
+ let res = children[0](p, minD);
17
+ if (res < minD)
18
+ minD = res;
19
+ for (let i = 1; i < n; i++) {
20
+ const d = children[i](p, minD);
21
+ if (d < minD)
22
+ minD = d;
23
+ res = op(res, d);
24
+ }
25
+ return res;
26
+ };
27
+ };
28
+ export const union = defOp(min);
29
+ export const isec = defOp(max);
30
+ export const diff = defOp((a, b) => max(a, -b));
31
+ export const defParamOp = (op) => (k, children) => {
32
+ __ensureChildren(children);
33
+ const kfield = __asField(k);
34
+ const n = children.length;
35
+ return (p, minD = Infinity) => {
36
+ const $k = kfield(p);
37
+ let res = children[0](p, minD);
38
+ if (res < minD)
39
+ minD = res;
40
+ for (let i = 1; i < n; i++) {
41
+ const d = children[i](p, minD);
42
+ if (d < minD)
43
+ minD = d;
44
+ res = op(res, d, $k);
45
+ }
46
+ return res;
47
+ };
48
+ };
49
+ export const smoothUnion = defParamOp((a, b, k) => {
50
+ const h = clamp01(0.5 + (0.5 * (b - a)) / k);
51
+ return mix(b, a, h) - k * h * (1 - h);
52
+ });
53
+ export const smoothIsec = defParamOp((a, b, k) => {
54
+ const h = clamp01(0.5 - (0.5 * (b - a)) / k);
55
+ return mix(b, a, h) + k * h * (1 - h);
56
+ });
57
+ export const smoothDiff = defParamOp((a, b, k) => {
58
+ const h = clamp01(0.5 - (0.5 * (a + b)) / k);
59
+ return mix(a, -b, h) + k * h * (1 - h);
60
+ });
61
+ export const chamferUnion = defParamOp((a, b, k) => min(min(a, b), (a - k + b) * SQRT2_2));
62
+ export const chamferIsec = defParamOp((a, b, k) => max(max(a, b), (a + k + b) * SQRT2_2));
63
+ export const chamferDiff = defParamOp((a, b, k) => max(max(a, -b), (a + k - b) * SQRT2_2));
64
+ export const roundUnion = defParamOp((a, b, k) => max(k, min(a, b)) - Math.hypot(max(k - a, 0), max(k - b, 0)));
65
+ export const roundIsec = defParamOp((a, b, k) => min(-k, max(a, b)) + Math.hypot(max(k + a, 0), max(k + b, 0)));
66
+ export const roundDiff = defParamOp((a, b, k) => min(-k, max(a, -b)) + Math.hypot(max(k + a, 0), max(k - b, 0)));
67
+ const __steps = (a, b, [r, n]) => {
68
+ const s = r / n;
69
+ const u = b - r;
70
+ return min(min(a, b), 0.5 * (u + a + Math.abs(mod(u - a + s, 2 * s) - s)));
71
+ };
72
+ export const stepUnion = defParamOp(__steps);
73
+ export const stepIsec = defParamOp((a, b, k) => -__steps(-a, -b, k));
74
+ export const stepDiff = defParamOp((a, b, k) => -__steps(-a, b, k));