@logomarks/core 0.1.11 → 0.2.0
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 +22 -0
- package/README.md +7 -0
- package/package.json +47 -4
- package/src/font/glyphs.d.ts +31 -0
- package/src/font/glyphs.js +228 -0
- package/src/font/index.d.ts +10 -0
- package/src/font/index.js +10 -0
- package/src/font/measure.d.ts +16 -0
- package/src/font/measure.js +201 -0
- package/src/font/moves.d.ts +42 -0
- package/src/font/moves.js +263 -0
- package/src/forms/discs.d.ts +20 -0
- package/src/forms/discs.js +114 -0
- package/src/forms/emblems.d.ts +22 -0
- package/src/forms/emblems.js +109 -0
- package/src/forms/flow.d.ts +21 -0
- package/src/forms/flow.js +80 -0
- package/src/forms/folds.d.ts +18 -0
- package/src/forms/folds.js +147 -0
- package/src/forms/geo.d.ts +46 -0
- package/src/forms/geo.js +233 -0
- package/src/forms/hooks.d.ts +40 -0
- package/src/forms/hooks.js +204 -0
- package/src/forms/index.d.ts +22 -0
- package/src/forms/index.js +24 -0
- package/src/forms/jog.d.ts +33 -0
- package/src/forms/jog.js +162 -0
- package/src/forms/lines.d.ts +32 -0
- package/src/forms/lines.js +233 -0
- package/src/forms/ref.d.ts +41 -0
- package/src/forms/ref.js +246 -0
- package/src/forms/shatter.d.ts +40 -0
- package/src/forms/shatter.js +341 -0
- package/src/forms/slats.d.ts +35 -0
- package/src/forms/slats.js +78 -0
- package/src/forms/swash.d.ts +23 -0
- package/src/forms/swash.js +74 -0
- package/src/forms/tech.d.ts +40 -0
- package/src/forms/tech.js +293 -0
- package/src/forms/tracks.d.ts +36 -0
- package/src/forms/tracks.js +121 -0
- package/src/index.js +2 -1
- package/src/iso/index.d.ts +5 -0
- package/src/iso/index.js +13 -0
- package/src/iso/objects.d.ts +168 -0
- package/src/iso/objects.js +1042 -0
- package/src/iso/planes.d.ts +27 -0
- package/src/iso/planes.js +138 -0
- package/src/iso/voxels.d.ts +43 -0
- package/src/iso/voxels.js +255 -0
- package/src/letters/blackletter.d.ts +31 -0
- package/src/letters/blackletter.js +199 -0
- package/src/letters/dotstroke.d.ts +16 -0
- package/src/letters/dotstroke.js +77 -0
- package/src/letters/echo.d.ts +42 -0
- package/src/letters/echo.js +246 -0
- package/src/letters/frame.d.ts +6 -0
- package/src/letters/frame.js +14 -0
- package/src/letters/index.d.ts +16 -0
- package/src/letters/index.js +18 -0
- package/src/letters/inktrap.d.ts +66 -0
- package/src/letters/inktrap.js +244 -0
- package/src/letters/mono.d.ts +145 -0
- package/src/letters/mono.js +684 -0
- package/src/letters/pillar.d.ts +31 -0
- package/src/letters/pillar.js +257 -0
- package/src/letters/serif.d.ts +109 -0
- package/src/letters/serif.js +666 -0
- package/src/letters/stair.d.ts +8 -0
- package/src/letters/stair.js +43 -0
- package/src/letters/stem.d.ts +29 -0
- package/src/letters/stem.js +205 -0
- package/src/objects/animals.d.ts +105 -0
- package/src/objects/animals.js +469 -0
- package/src/objects/bio.d.ts +14 -0
- package/src/objects/bio.js +76 -0
- package/src/objects/devglyphs.d.ts +34 -0
- package/src/objects/devglyphs.js +226 -0
- package/src/objects/devices.d.ts +31 -0
- package/src/objects/devices.js +114 -0
- package/src/objects/faces.d.ts +94 -0
- package/src/objects/faces.js +344 -0
- package/src/objects/food.d.ts +12 -0
- package/src/objects/food.js +74 -0
- package/src/objects/index.d.ts +13 -0
- package/src/objects/index.js +18 -0
- package/src/objects/rosettes.d.ts +14 -0
- package/src/objects/rosettes.js +64 -0
- package/src/objects/sport.d.ts +8 -0
- package/src/objects/sport.js +37 -0
- package/src/objects/weapons.d.ts +31 -0
- package/src/objects/weapons.js +179 -0
- package/src/pixels/dither.d.ts +78 -0
- package/src/pixels/dither.js +399 -0
- package/src/pixels/emote.d.ts +6 -0
- package/src/pixels/emote.js +76 -0
- package/src/pixels/index.d.ts +7 -0
- package/src/pixels/index.js +8 -0
- package/src/sdf/index.d.ts +2 -0
- package/src/sdf/index.js +2 -0
- package/src/sdf/y2k.d.ts +12 -0
- package/src/sdf/y2k.js +80 -0
- package/src/util/vec.d.ts +14 -0
- package/src/util/vec.js +61 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bold tech parts: split sparkles, the folded ribbon (Folio), beads on a lattice, slashes, lens gaps, keyed chevrons and
|
|
3
|
+
* the Kerf tile. Angles are degrees, 0 right, 90 down. From the Logomarks tools (techparts.mjs, batch 213, "Bold · Tech",
|
|
4
|
+
* and its editions in batches 220 and 227).
|
|
5
|
+
*/
|
|
6
|
+
import { C, D, I, U, bar, circle, grow, poly, rad, rr, sample } from '../geometry/index.js';
|
|
7
|
+
import { sub, add, mul } from '../util/vec.js';
|
|
8
|
+
|
|
9
|
+
// A rectangle from its corners, box(x0, y0, x1, y1): the tech marks draw their bars with it.
|
|
10
|
+
export { box } from '../util/vec.js';
|
|
11
|
+
|
|
12
|
+
/** @typedef {import('../geometry/types.js').Point} Point */
|
|
13
|
+
/** @typedef {import('../geometry/types.js').Polygon} Polygon */
|
|
14
|
+
/** @typedef {import('../geometry/types.js').Shape} Shape */
|
|
15
|
+
/** @typedef {import('../geometry/types.js').Geom} Geom */
|
|
16
|
+
|
|
17
|
+
/** Far enough to run a half plane off any canvas. */
|
|
18
|
+
const BIG = 3000;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A 2D vector at unit length.
|
|
22
|
+
*
|
|
23
|
+
* @param {readonly number[]} a The vector.
|
|
24
|
+
* @returns {Point} It, unit.
|
|
25
|
+
*/
|
|
26
|
+
const norm = (a) => { const l = Math.hypot(...a); return [a[0] / l, a[1] / l]; };
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A 2D vector turned a quarter (to its left on screen, y down).
|
|
30
|
+
*
|
|
31
|
+
* @param {readonly number[]} a The vector.
|
|
32
|
+
* @returns {Point} It, turned.
|
|
33
|
+
*/
|
|
34
|
+
const perp = (a) => [-a[1], a[0]];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The dot product in 2D.
|
|
38
|
+
*
|
|
39
|
+
* @param {readonly number[]} a One vector.
|
|
40
|
+
* @param {readonly number[]} b The other.
|
|
41
|
+
* @returns {number} a · b.
|
|
42
|
+
*/
|
|
43
|
+
const dot2 = (a, b) => a[0] * b[0] + a[1] * b[1];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The cross product in 2D (its z).
|
|
47
|
+
*
|
|
48
|
+
* @param {readonly number[]} a One vector.
|
|
49
|
+
* @param {readonly number[]} b The other.
|
|
50
|
+
* @returns {number} a × b.
|
|
51
|
+
*/
|
|
52
|
+
const cross2 = (a, b) => a[0] * b[1] - a[1] * b[0];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The half plane left of the directed line through p along d (left: the side `perp(d)` points to).
|
|
56
|
+
*
|
|
57
|
+
* @param {readonly number[]} p A point on the line.
|
|
58
|
+
* @param {readonly number[]} d Its direction.
|
|
59
|
+
* @returns {Polygon} The half plane.
|
|
60
|
+
*/
|
|
61
|
+
const half = (p, d) => {
|
|
62
|
+
const u = norm(d), n = perp(u);
|
|
63
|
+
return poly([add(p, mul(u, -BIG)), add(p, mul(u, BIG)), add(add(p, mul(u, BIG)), mul(n, BIG)), add(add(p, mul(u, -BIG)), mul(n, BIG))]);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The half plane on the side of the line (p, d) that holds the point q.
|
|
68
|
+
*
|
|
69
|
+
* @param {readonly number[]} p A point on the line.
|
|
70
|
+
* @param {readonly number[]} d Its direction.
|
|
71
|
+
* @param {readonly number[]} q The point to keep.
|
|
72
|
+
* @returns {Polygon} The half plane.
|
|
73
|
+
*/
|
|
74
|
+
const halfWith = (p, d, q) => (cross2(norm(d), sub(q, p)) * cross2(norm(d), perp(norm(d))) > 0 ? half(p, d) : half(p, mul(d, -1)));
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* A parallelogram: its bottom edge from (x, yb) w long, its top edge h higher and shifted dx right.
|
|
78
|
+
*
|
|
79
|
+
* @param {number} x The bottom edge's left end.
|
|
80
|
+
* @param {number} yb The bottom edge's height.
|
|
81
|
+
* @param {number} w The width.
|
|
82
|
+
* @param {number} h The height.
|
|
83
|
+
* @param {number} dx The top edge's shift.
|
|
84
|
+
* @returns {Polygon} The parallelogram.
|
|
85
|
+
*/
|
|
86
|
+
export const para = (x, yb, w, h, dx) => poly([[x, yb], [x + w, yb], [x + w + dx, yb - h], [x + dx, yb - h]]);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Points of the circle through a, m and b, from a through m to b.
|
|
90
|
+
*
|
|
91
|
+
* @param {readonly number[]} a The start.
|
|
92
|
+
* @param {readonly number[]} m A point on the way.
|
|
93
|
+
* @param {readonly number[]} b The end.
|
|
94
|
+
* @param {number} [n=60] Steps.
|
|
95
|
+
* @returns {Point[]} The arc.
|
|
96
|
+
*/
|
|
97
|
+
export const arc3 = (a, m, b, n = 60) => {
|
|
98
|
+
const ax = a[0], ay = a[1], bx = m[0], by = m[1], cx = b[0], cy = b[1];
|
|
99
|
+
const d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
|
|
100
|
+
const ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
|
|
101
|
+
const uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
|
|
102
|
+
const r = Math.hypot(ax - ux, ay - uy), t = (p) => Math.atan2(p[1] - uy, p[0] - ux); let t0 = t(a), t1 = t(m), t2 = t(b);
|
|
103
|
+
const ccw = (x, y) => ((y - x) % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI); // sweep from x to y anticlockwise (in y-down terms, increasing angle)
|
|
104
|
+
const s = ccw(t0, t1) < ccw(t0, t2) ? ccw(t0, t2) : ccw(t0, t2) - 2 * Math.PI;
|
|
105
|
+
return sample((u) => [ux + r * Math.cos(t0 + s * u), uy + r * Math.sin(t0 + s * u)], 0, 1, n);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The point at radius r and angle deg from a centre.
|
|
110
|
+
*
|
|
111
|
+
* @param {number} r The radius.
|
|
112
|
+
* @param {number} deg The angle.
|
|
113
|
+
* @param {readonly number[]} [c=[C, C]] The centre.
|
|
114
|
+
* @returns {Point} The point.
|
|
115
|
+
*/
|
|
116
|
+
const at = (r, deg, c = [C, C]) => [c[0] + r * Math.cos(rad(deg)), c[1] + r * Math.sin(rad(deg))];
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* A concave star about the canvas centre: n tips at radius R (`tips` scales single tips), each side a quadratic curve
|
|
120
|
+
* pulled in towards a control point at radius rc on the mid angle (rc 0 pulls every side to the centre), so the sides meet
|
|
121
|
+
* the tips without crossing.
|
|
122
|
+
*
|
|
123
|
+
* @param {number} n The tips.
|
|
124
|
+
* @param {number} R Their radius.
|
|
125
|
+
* @param {number} [rc=0] The sides' control radius.
|
|
126
|
+
* @param {number} [deg=-90] The first tip's angle.
|
|
127
|
+
* @param {readonly number[]} [tips=[]] Per-tip radius factors.
|
|
128
|
+
* @returns {Polygon} The star.
|
|
129
|
+
*/
|
|
130
|
+
export const star = (n, R, rc = 0, deg = -90, tips = []) => {
|
|
131
|
+
const pts = [];
|
|
132
|
+
for (let i = 0; i < n; i++) {
|
|
133
|
+
const a = deg + (i * 360) / n, b = a + 360 / n, p0 = at(R * (tips[i] ?? 1), a), p1 = at(rc, a + 180 / n), p2 = at(R * (tips[(i + 1) % n] ?? 1), b);
|
|
134
|
+
pts.push(...sample((t) => [(1 - t) ** 2 * p0[0] + 2 * t * (1 - t) * p1[0] + t * t * p2[0], (1 - t) ** 2 * p0[1] + 2 * t * (1 - t) * p1[1] + t * t * p2[1]], 0, 1, 64).slice(0, -1));
|
|
135
|
+
}
|
|
136
|
+
return poly(pts);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A gap g wide across a star's arm at angle deg, d from the centre.
|
|
141
|
+
*
|
|
142
|
+
* @param {number} deg The arm's angle.
|
|
143
|
+
* @param {number} d The distance from the centre.
|
|
144
|
+
* @param {number} g The gap.
|
|
145
|
+
* @returns {Polygon} The cut.
|
|
146
|
+
*/
|
|
147
|
+
export const armCut = (deg, d, g) => {
|
|
148
|
+
const p = at(d, deg), u = [Math.cos(rad(deg)), Math.sin(rad(deg))], n = perp(u);
|
|
149
|
+
return bar(add(p, mul(n, -400)), add(p, mul(n, 400)), g);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* A ribbon B wide along the polyline pts, drawn as outlines t wide. Each turn is a fold: the crease runs through the
|
|
154
|
+
* corner along the bisector of the two directions (so the outer corner is cut on it), and each later facet lies over the
|
|
155
|
+
* one before, hiding its lines. Ends are cut square. Every facet's outline is drawn t/2 inside it, and the silhouette's
|
|
156
|
+
* another t/2, so shared folds and the outer edge are all t wide.
|
|
157
|
+
*
|
|
158
|
+
* @param {readonly Point[]} pts The ribbon's centreline.
|
|
159
|
+
* @param {number} B Its width.
|
|
160
|
+
* @param {number} t The outline's width.
|
|
161
|
+
* @returns {Shape} The ribbon's lines.
|
|
162
|
+
*/
|
|
163
|
+
export const ribbon = (pts, B, t) => {
|
|
164
|
+
const n = pts.length - 1, v = [...Array(n)].map((_, i) => norm(sub(pts[i + 1], pts[i])));
|
|
165
|
+
const crease = (k) => (k === 0 ? perp(v[0]) : k === n ? perp(v[n - 1]) : (Math.hypot(...add(v[k - 1], v[k])) < 1e-6 ? perp(v[k]) : add(v[k - 1], v[k])));
|
|
166
|
+
const facets = v.map((u, i) => {
|
|
167
|
+
const a = pts[i], b = pts[i + 1], nn = perp(u);
|
|
168
|
+
const strip = poly([add(add(a, mul(u, -BIG)), mul(nn, -B / 2)), add(add(a, mul(u, BIG)), mul(nn, -B / 2)), add(add(a, mul(u, BIG)), mul(nn, B / 2)), add(add(a, mul(u, -BIG)), mul(nn, B / 2))]);
|
|
169
|
+
return I(strip, halfWith(a, crease(i), b), halfWith(b, crease(i + 1), a));
|
|
170
|
+
});
|
|
171
|
+
const vis = facets.map((f, i) => (i < n - 1 ? D(f, ...facets.slice(i + 1)) : f)); // what each facet shows under the later ones
|
|
172
|
+
const all = U(...facets), ring = (s, w) => D(s, grow(s, -w)); // a line w wide just inside the outline (sharp corners kept)
|
|
173
|
+
return U(ring(all, t / 2), ...vis.map((s) => ring(s, t / 2)));
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Equal discs on a lattice of pitch p, the gap g between neighbours: cells as [col, row] in pitch units.
|
|
178
|
+
*
|
|
179
|
+
* @param {readonly (readonly number[])[]} cells The lattice points.
|
|
180
|
+
* @param {number} g The gap.
|
|
181
|
+
* @param {number} [p=130] The pitch.
|
|
182
|
+
* @returns {Shape} The beads.
|
|
183
|
+
*/
|
|
184
|
+
export const beads = (cells, g, p = 130) => U(...cells.map(([x, y]) => circle(x * p, y * p, (p - g) / 2, 160)));
|
|
185
|
+
|
|
186
|
+
/** √3 / 2: a hexagonal lattice's row pitch, in pitch units. */
|
|
187
|
+
export const H3 = Math.sqrt(3) / 2;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* A bar w wide leaning `lean`° right of upright, its centreline through (x, ym), cut flat at y0 and y1.
|
|
191
|
+
*
|
|
192
|
+
* @param {number} x The centreline's x at ym.
|
|
193
|
+
* @param {number} ym The height it passes x at.
|
|
194
|
+
* @param {number} w The width (square to the bar).
|
|
195
|
+
* @param {number} lean The lean, degrees.
|
|
196
|
+
* @param {number} y0 The top cut.
|
|
197
|
+
* @param {number} y1 The bottom cut.
|
|
198
|
+
* @returns {Polygon} The slash.
|
|
199
|
+
*/
|
|
200
|
+
export const slash = (x, ym, w, lean, y0, y1) => {
|
|
201
|
+
const t = Math.tan(rad(lean)), xa = (y) => x + (ym - y) * t, hw = w / 2 / Math.cos(rad(lean));
|
|
202
|
+
return poly([[xa(y1) - hw, y1], [xa(y1) + hw, y1], [xa(y0) + hw, y0], [xa(y0) - hw, y0]]);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The lens marks' disc: radius 224, centred, 720 points.
|
|
207
|
+
*
|
|
208
|
+
* @returns {Polygon} The disc.
|
|
209
|
+
*/
|
|
210
|
+
export const DISC = () => circle(C, C, 224, 720);
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* A lens gap from p to q: two arcs bowing w apart at the middle and meeting at p and q (run it on past the rim).
|
|
214
|
+
*
|
|
215
|
+
* @param {readonly number[]} p One end.
|
|
216
|
+
* @param {readonly number[]} q The other.
|
|
217
|
+
* @param {number} w Its width at the middle.
|
|
218
|
+
* @returns {Polygon} The gap.
|
|
219
|
+
*/
|
|
220
|
+
export const lensGap = (p, q, w) => {
|
|
221
|
+
const m = mul(add(p, q), 0.5), n = perp(norm(sub(q, p)));
|
|
222
|
+
return poly([...arc3(p, add(m, mul(n, w / 2)), q, 60), ...arc3(q, add(m, mul(n, -w / 2)), p, 60).slice(1, -1)]);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* A chevron: outer apex P, arms running out along A and B (directions from P), w wide inward; long, so a box clips the
|
|
227
|
+
* ends.
|
|
228
|
+
*
|
|
229
|
+
* @param {readonly number[]} P The apex.
|
|
230
|
+
* @param {readonly number[]} A One arm's direction.
|
|
231
|
+
* @param {readonly number[]} B The other's.
|
|
232
|
+
* @param {number} w The width.
|
|
233
|
+
* @param {number} [L=1400] The arms' length.
|
|
234
|
+
* @returns {Polygon} The chevron.
|
|
235
|
+
*/
|
|
236
|
+
export const techChevron = (P, A, B, w, L = 1400) => {
|
|
237
|
+
const u1 = norm(A), u2 = norm(B), bis = norm(add(u1, u2)), th = Math.acos(dot2(u1, u2));
|
|
238
|
+
const side = (u, o) => { const n = perp(u); return dot2(n, o) > 0 ? n : mul(n, -1); }, n1 = side(u1, u2), n2 = side(u2, u1);
|
|
239
|
+
const Q = add(P, mul(bis, w / Math.sin(th / 2)));
|
|
240
|
+
return poly([P, add(P, mul(u1, L)), add(add(P, mul(u1, L)), mul(n1, w)), Q, add(add(P, mul(u2, L)), mul(n2, w)), add(P, mul(u2, L))]);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* A slab w wide from a to b whose b end is cut to a 90° point (two 45° chamfers): the key of a Keyed letter.
|
|
245
|
+
*
|
|
246
|
+
* @param {readonly number[]} a The square end.
|
|
247
|
+
* @param {readonly number[]} b The point.
|
|
248
|
+
* @param {number} w The width.
|
|
249
|
+
* @returns {Polygon} The slab.
|
|
250
|
+
*/
|
|
251
|
+
export const pointed = (a, b, w) => {
|
|
252
|
+
const u = norm(sub(b, a)), n = perp(u), h = w / 2, back = add(b, mul(u, -h));
|
|
253
|
+
return poly([add(a, mul(n, h)), add(back, mul(n, h)), b, add(back, mul(n, -h)), add(a, mul(n, -h))]);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Two Keyed slabs parted: the notched slab loses the key grown by g, so the gap is even round the point.
|
|
258
|
+
*
|
|
259
|
+
* @param {Geom} notched The slab the key goes into.
|
|
260
|
+
* @param {Geom} key The key.
|
|
261
|
+
* @param {number} g The gap.
|
|
262
|
+
* @returns {Shape} Both.
|
|
263
|
+
*/
|
|
264
|
+
export const keyed = (notched, key, g) => U(D(notched, grow(key, g)), key);
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* The Kerf tile: a 448 square from the origin, its corners rounded 78 (about 17%: a rounded square, never a squircle).
|
|
268
|
+
*
|
|
269
|
+
* @returns {Polygon} The tile.
|
|
270
|
+
*/
|
|
271
|
+
export const TILE = () => rr(0, 0, 448, 448, 78);
|
|
272
|
+
|
|
273
|
+
/** The folded ribbon letters' width. */
|
|
274
|
+
export const RB = 124;
|
|
275
|
+
|
|
276
|
+
/** The folded ribbon letters' outline width once fitted. */
|
|
277
|
+
export const RT = 24;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* A folded ribbon letter along pts, RB wide, its outline RT wide once fitted.
|
|
281
|
+
*
|
|
282
|
+
* @param {readonly Point[]} pts The centreline.
|
|
283
|
+
* @returns {(g: number) => Shape} The build of the gap.
|
|
284
|
+
*/
|
|
285
|
+
export const rib = (pts) => (g) => ribbon(pts, RB, (g * RT) / 22);
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* The four-point star both sparkles break: radius 224, its sides pulled to a control point 40 out, so the arms stay
|
|
289
|
+
* chunky.
|
|
290
|
+
*
|
|
291
|
+
* @returns {Polygon} The star.
|
|
292
|
+
*/
|
|
293
|
+
export const SPARK = () => star(4, 224, 40);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Point, Ring, Polygon, Shape, Geom } from '../geometry/types.js';
|
|
2
|
+
|
|
3
|
+
/** The source-unit helpers trackKit(K) returns. */
|
|
4
|
+
export interface TrackKit {
|
|
5
|
+
/** A solid built in source units, drawn K larger. */
|
|
6
|
+
S(g: Geom): Geom;
|
|
7
|
+
/** A loop's centreline: a region's boundary, corners rounded r1 (inner) and r2 (outer), resampled evenly. */
|
|
8
|
+
ring(region: Geom, r1?: number, r2?: number): Point[];
|
|
9
|
+
/** A solid cut a house gap clear of tracks. */
|
|
10
|
+
off(sol: Geom, ...tracks: Geom[]): Shape;
|
|
11
|
+
/** A solid kept only outside a loop's centreline, a gap clear of its outer track. */
|
|
12
|
+
out(sol: Geom, o: Point[]): Shape;
|
|
13
|
+
/** A solid kept only inside a loop's centreline, a gap clear of the inner track. */
|
|
14
|
+
within(sol: Geom, o: Point[]): Shape;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Source units to drawing units, for the fixed-K editions (1.6). */
|
|
18
|
+
export const TRACK_K: number;
|
|
19
|
+
/** A closed ring resampled every `step` along its length. */
|
|
20
|
+
export function evenRing(o: readonly Point[], step?: number): Point[];
|
|
21
|
+
/** The source-unit helpers at a fixed K. */
|
|
22
|
+
export function trackKit(K?: number): TrackKit;
|
|
23
|
+
/** A closed region from a radius function round (cx, cy), every 2 degrees. */
|
|
24
|
+
export function radial(cx: number, cy: number, f: (a: number) => number): Polygon;
|
|
25
|
+
/** A drop pointing up: a disc of radius r at (x, y), its point h above the centre. */
|
|
26
|
+
export function drop(x: number, y: number, r: number, h: number): Shape;
|
|
27
|
+
/** A shape's area: outer rings less their holes. */
|
|
28
|
+
export function sArea(s: Shape): number;
|
|
29
|
+
/** Whether a point lies inside a ring (even-odd). */
|
|
30
|
+
export function inRing(r: readonly Point[], p: readonly number[]): boolean;
|
|
31
|
+
/** A ring's box centre. */
|
|
32
|
+
export function mid(r: Ring): Point;
|
|
33
|
+
/** The largest outer ring of a shape, its closing point dropped. */
|
|
34
|
+
export function largest(s: Shape): Point[];
|
|
35
|
+
/** A cut shape's parts, less any piece under `min`. */
|
|
36
|
+
export function parts2(s: Shape, min?: number): Shape;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Track editions: a mark redrawn as two-track loops (the kit's trackLoop with the house Duo, the gap between the tracks)
|
|
3
|
+
* round its solid parts. A source is drawn in source units and scaled K into drawing units; trackKit(K) gives the
|
|
4
|
+
* source-unit helpers at a fixed K, and the rest split a live source into its parts.
|
|
5
|
+
* From the Logomarks tools (trackparts.mjs, the helpers every Track edition generator had copied; shared since Drop 35).
|
|
6
|
+
*/
|
|
7
|
+
import { U, D, I, poly, circle, grow, scale, soften, area, bbox } from '../geometry/index.js';
|
|
8
|
+
import { inside } from '../objects/animals.js';
|
|
9
|
+
|
|
10
|
+
/** Source units to drawing units, for the editions drawn at a fixed K. */
|
|
11
|
+
export const TRACK_K = 1.6;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A closed ring resampled every `step` along its length (soften()'s rings crowd points at the arcs, and two points a
|
|
15
|
+
* hair apart turn a track's offset normals: the loop frays).
|
|
16
|
+
*
|
|
17
|
+
* @param {readonly import('../geometry/types.js').Point[]} o The ring (open: its first point not repeated).
|
|
18
|
+
* @param {number} [step=6] The spacing.
|
|
19
|
+
* @returns {import('../geometry/types.js').Point[]} The resampled ring.
|
|
20
|
+
*/
|
|
21
|
+
export function evenRing(o, step = 6) {
|
|
22
|
+
const n = o.length, seg = o.map((p, i) => Math.hypot(o[(i + 1) % n][0] - p[0], o[(i + 1) % n][1] - p[1])), L = seg.reduce((a, b) => a + b, 0), m = Math.round(L / step), out = [];
|
|
23
|
+
let i = 0, acc = 0;
|
|
24
|
+
for (let k = 0; k < m; k++) { const d = (k * L) / m; while (acc + seg[i] < d) acc += seg[i++]; const t = seg[i] ? (d - acc) / seg[i] : 0, a = o[i], b = o[(i + 1) % n]; out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]); }
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The source-unit helpers at a fixed K:
|
|
30
|
+
*
|
|
31
|
+
* - `S(g)`: a solid built in source units, drawn K larger;
|
|
32
|
+
* - `ring(region, r1, r2)`: a loop's centreline, the boundary of a region drawn in source units, its inner corners
|
|
33
|
+
* rounded r1 and outer r2 (drawing units, 60 or more): the largest ring, its closing point dropped, resampled evenly;
|
|
34
|
+
* - `off(sol, ...tracks)`: a solid (source units) cut a house gap clear of tracks (drawing units);
|
|
35
|
+
* - `out(sol, o)`: a solid (source units) kept only outside a loop's centreline o, a gap clear of its outer track;
|
|
36
|
+
* - `within(sol, o)`: a solid (source units) kept only inside a loop's centreline o, a gap clear of the inner track.
|
|
37
|
+
*
|
|
38
|
+
* @param {number} [K=TRACK_K] Source units to drawing units.
|
|
39
|
+
* @returns {{ S: (g: import('../geometry/types.js').Geom) => import('../geometry/types.js').Geom, ring: (region: import('../geometry/types.js').Geom, r1?: number, r2?: number) => import('../geometry/types.js').Point[], off: (sol: import('../geometry/types.js').Geom, ...tracks: import('../geometry/types.js').Geom[]) => import('../geometry/types.js').Shape, out: (sol: import('../geometry/types.js').Geom, o: import('../geometry/types.js').Point[]) => import('../geometry/types.js').Shape, within: (sol: import('../geometry/types.js').Geom, o: import('../geometry/types.js').Point[]) => import('../geometry/types.js').Shape }}
|
|
40
|
+
* The helpers.
|
|
41
|
+
*/
|
|
42
|
+
export const trackKit = (K = TRACK_K) => {
|
|
43
|
+
const S = (g) => scale(g, K, 0, 0);
|
|
44
|
+
const ring = (region, r1 = 64, r2 = 64) => {
|
|
45
|
+
const g = soften(S(region), r1, r2), area = (r) => Math.abs(r.reduce((s, p, i) => { const q = r[(i + 1) % r.length]; return s + p[0] * q[1] - q[0] * p[1]; }, 0));
|
|
46
|
+
let best = null; for (const pg of g) if (!best || area(pg[0]) > area(best)) best = pg[0];
|
|
47
|
+
const o = best.slice(); if (Math.hypot(o[0][0] - o.at(-1)[0], o[0][1] - o.at(-1)[1]) < 0.01) o.pop(); return evenRing(o);
|
|
48
|
+
};
|
|
49
|
+
const off = (sol, ...trs) => D(S(sol), grow(U(...trs), 22));
|
|
50
|
+
const out = (sol, o) => D(S(sol), grow(poly(o), 37 + 22));
|
|
51
|
+
const within = (sol, o) => I(S(sol), inside(o));
|
|
52
|
+
return { S, ring, off, out, within };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A closed region from a radius function round (cx, cy), sampled every 2 degrees.
|
|
57
|
+
*
|
|
58
|
+
* @param {number} cx The centre.
|
|
59
|
+
* @param {number} cy The centre.
|
|
60
|
+
* @param {(a: number) => number} f The radius at the angle a (radians).
|
|
61
|
+
* @returns {import('../geometry/types.js').Polygon} The region.
|
|
62
|
+
*/
|
|
63
|
+
export const radial = (cx, cy, f) => poly(Array.from({ length: 180 }, (_, i) => { const a = (i * 2 * Math.PI) / 180, r = f(a); return [cx + r * Math.cos(a), cy + r * Math.sin(a)]; }));
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* A drop pointing up: a disc of radius r at (x, y) and its point h above the centre.
|
|
67
|
+
*
|
|
68
|
+
* @param {number} x The disc's centre.
|
|
69
|
+
* @param {number} y The disc's centre.
|
|
70
|
+
* @param {number} r Its radius.
|
|
71
|
+
* @param {number} h How far above the centre the point is.
|
|
72
|
+
* @returns {import('../geometry/types.js').Shape} The drop.
|
|
73
|
+
*/
|
|
74
|
+
export const drop = (x, y, r, h) => { const t = Math.asin(r / h); return U(circle(x, y, r), poly([[x, y - h], [x + r * Math.cos(t), y - r * Math.sin(t)], [x - r * Math.cos(t), y - r * Math.sin(t)]])); };
|
|
75
|
+
|
|
76
|
+
/* ---------- splitting a live source ---------- */
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* A shape's area: its outer rings less their holes.
|
|
80
|
+
*
|
|
81
|
+
* @param {import('../geometry/types.js').Shape} s The shape.
|
|
82
|
+
* @returns {number} The area.
|
|
83
|
+
*/
|
|
84
|
+
export const sArea = (s) => s.reduce((t, pg) => t + area(pg[0]) - pg.slice(1).reduce((h, r) => h + area(r), 0), 0);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Whether a point lies inside a ring (even-odd).
|
|
88
|
+
*
|
|
89
|
+
* @param {readonly import('../geometry/types.js').Point[]} r The ring.
|
|
90
|
+
* @param {readonly number[]} p The point.
|
|
91
|
+
* @returns {boolean} True inside.
|
|
92
|
+
*/
|
|
93
|
+
export const inRing = (r, [px, py]) => { let c = false; for (let i = 0, j = r.length - 1; i < r.length; j = i++) { const [a, b] = [r[i], r[j]]; if ((a[1] > py) !== (b[1] > py) && px < ((b[0] - a[0]) * (py - a[1])) / (b[1] - a[1]) + a[0]) c = !c; } return c; };
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* A ring's box centre.
|
|
97
|
+
*
|
|
98
|
+
* @param {import('../geometry/types.js').Ring} r The ring.
|
|
99
|
+
* @returns {import('../geometry/types.js').Point} The centre of its box.
|
|
100
|
+
*/
|
|
101
|
+
export const mid = (r) => { const [x0, y0, x1, y1] = bbox([[r]]); return [(x0 + x1) / 2, (y0 + y1) / 2]; };
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The largest outer ring of a shape, its closing point dropped.
|
|
105
|
+
*
|
|
106
|
+
* @param {import('../geometry/types.js').Shape} s The shape.
|
|
107
|
+
* @returns {import('../geometry/types.js').Point[]} The ring.
|
|
108
|
+
*/
|
|
109
|
+
export const largest = (s) => {
|
|
110
|
+
let best = null; for (const pg of s) if (!best || area(pg[0]) > area(best)) best = pg[0];
|
|
111
|
+
const o = best.slice(); if (Math.hypot(o[0][0] - o.at(-1)[0], o[0][1] - o.at(-1)[1]) < 0.01) o.pop(); return o;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A cut shape's parts, less any piece under `min` (drawing units): a limb's stub left between two cuts.
|
|
116
|
+
*
|
|
117
|
+
* @param {import('../geometry/types.js').Shape} s The cut shape.
|
|
118
|
+
* @param {number} [min=1000] The smallest piece kept.
|
|
119
|
+
* @returns {import('../geometry/types.js').Shape} The parts.
|
|
120
|
+
*/
|
|
121
|
+
export const parts2 = (s, min = 1000) => s.filter((pg) => area(pg[0]) >= min);
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @logomarks/core: geometry, SVG reading, fitting, analysis, similarity, shape edits and stitch plans for logomarks
|
|
3
3
|
* on a 512 grid. Each area is also its own subpath (`/geometry`, `/svg`, `/fit`, `/raster`, `/analyse`, `/similar`, `/edit`, `/stitch`,
|
|
4
|
-
* and `/parts` for the industry-symbol parts, which needs Node for its batch writer).
|
|
4
|
+
* and `/parts` for the industry-symbol parts, which needs Node for its batch writer). The parts subpaths (`/iso`, `/letters`,
|
|
5
|
+
* `/font`, `/pixels`, `/objects`, `/forms`) and `/batch` are imported on their own: their names would clash here.
|
|
5
6
|
*/
|
|
6
7
|
export * from './geometry/index.js';
|
|
7
8
|
export { parsePath, bezierAt, arcOf, arcAt, attr, shapes, viewBox, body, outlinePoints, bounds, rings, filledShape } from './svg/index.js';
|
package/src/iso/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @logomarks/core/iso
|
|
3
|
+
*
|
|
4
|
+
* Iso parts on top of the parts' solid engine (`scene()` in /parts): iso objects (cylinders, frustums, lathes, roofs,
|
|
5
|
+
* shops with their trade feature, openings cut on the fitted faces, cut-outs square to the viewer drawn by isoFlat(),
|
|
6
|
+
* tipped slabs), flat planes hinged and folded into a scene (planeScene(), iso or oblique), and voxels (sprites and
|
|
7
|
+
* plans as boxes, a pixel sprite with one step of depth, slabs with square gaps, corner monograms). x runs to the front
|
|
8
|
+
* right, y to the front left, z up. The 2D outline helpers here (rect, rr, disc, circ, ell, lens, rot, stroke, band)
|
|
9
|
+
* return point lists for flat() and cuts, not kit shapes.
|
|
10
|
+
*/
|
|
11
|
+
export * from './objects.js';
|
|
12
|
+
export * from './planes.js';
|
|
13
|
+
export * from './voxels.js';
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { Point, Point3, Shape } from '../geometry/types.js';
|
|
2
|
+
import type { FittedProjection, Piece } from '../parts/iso.js';
|
|
3
|
+
|
|
4
|
+
export { cross3 } from '../util/vec.js';
|
|
5
|
+
|
|
6
|
+
/** A part: one convex piece, or a list of pieces drawn as one solid. */
|
|
7
|
+
export type Part = Piece | Piece[];
|
|
8
|
+
/** 2D points on a face or a plane. */
|
|
9
|
+
type Pts = readonly (readonly number[])[];
|
|
10
|
+
/** A cut-out square to the viewer, from flat(): its outlines and holes on the facing plane and its depth. */
|
|
11
|
+
export interface Flat {
|
|
12
|
+
outer: number[][][];
|
|
13
|
+
holes: number[][][];
|
|
14
|
+
back: number[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The projection scene() fits round these parts. */
|
|
18
|
+
export function fitOf(parts: readonly Part[]): FittedProjection;
|
|
19
|
+
/** The house gap in model units for these parts. */
|
|
20
|
+
export function gapIn(parts: readonly Part[], g: number): number;
|
|
21
|
+
/** 2D points on the face of axis ax at at, as 3D points. */
|
|
22
|
+
export function onFace(ax: 'x' | 'y' | 'z', at: number, pts: Pts): Point3[];
|
|
23
|
+
/** 2D points on the plane o + a·u + b·v, as 3D points. */
|
|
24
|
+
export function onPlane(o: readonly number[], u: readonly number[], v: readonly number[], pts: Pts): Point3[];
|
|
25
|
+
/** Rectangles [a0, b0, a1, b1] on a face, as 3D quads. */
|
|
26
|
+
export function quads(ax: 'x' | 'y' | 'z', at: number, rects: Pts): Point3[][];
|
|
27
|
+
/** A disc of radius r at (a, b) on a face. */
|
|
28
|
+
export function discOn(ax: 'x' | 'y' | 'z', at: number, a: number, b: number, r: number, n?: number): Point3[];
|
|
29
|
+
/** A 2D shape as 3D outlines on the +x or +y face, f model units a canvas unit, centred on (ca, cb). */
|
|
30
|
+
export function shapeOn(ax: 'x' | 'y', at: number, shape: Shape, f: number, ca: number, cb: number): Point3[][];
|
|
31
|
+
/** Iso parts drawn, the 3D outlines in holes cut through them and those in keep put back. */
|
|
32
|
+
export function isoCut(parts: readonly Part[], g: number, holes?: readonly Pts[], keep?: readonly Pts[]): Shape;
|
|
33
|
+
/** A cylinder along x. */
|
|
34
|
+
export function cylX(cy: number, cz: number, r: number, x0: number, x1: number, n?: number): Piece;
|
|
35
|
+
/** A cylinder along y. */
|
|
36
|
+
export function cylY(cx: number, cz: number, r: number, y0: number, y1: number, n?: number): Piece;
|
|
37
|
+
/** An upright frustum, radius r0 at z0 to r1 at z1, n sides turned deg. */
|
|
38
|
+
export function frustum(cx: number, cy: number, r0: number, r1: number, z0: number, z1: number, n?: number, deg?: number): Piece;
|
|
39
|
+
/** A slab hinged on a line along y, leaning back by deg. */
|
|
40
|
+
export function leaning(x: number, z: number, y0: number, y1: number, h: number, t: number, deg: number): Piece;
|
|
41
|
+
/** A flap hinged on the edge p0–p1, folded out along out by deg. */
|
|
42
|
+
export function flap(p0: readonly number[], p1: readonly number[], out: readonly number[], deg: number, L: number, t: number): Piece;
|
|
43
|
+
/** A square-section bar between two 3D points. */
|
|
44
|
+
export function rod(a: readonly number[], b: readonly number[], w: number): Piece;
|
|
45
|
+
/** A round bar between two 3D points, one smooth side. */
|
|
46
|
+
export function tube(a: readonly number[], b: readonly number[], r: number, n?: number): Piece;
|
|
47
|
+
/** A vehicle's wheels on its +y side at y = W. */
|
|
48
|
+
export function wheels(xs: readonly number[], W: number, r?: number, z?: number): Piece[];
|
|
49
|
+
/** A rectangle on the tangent plane at the front of an upright cylinder. */
|
|
50
|
+
export function cylFront(cx: number, cy: number, r: number, w: number, z0: number, z1: number): Point3[];
|
|
51
|
+
/** A ball as one part: rings of frustums, squashed and cut between two latitudes. */
|
|
52
|
+
export function ball(cx: number, cy: number, cz: number, r: number, o?: { squash?: number; rings?: number; from?: number; to?: number }): Piece[];
|
|
53
|
+
/** A band along an arc in a side profile (x, z), pushed along y. */
|
|
54
|
+
export function arcSide(cx: number, cz: number, r0: number, r1: number, a0: number, a1: number, y0: number, y1: number, n?: number): Piece[];
|
|
55
|
+
/** A band along an arc in a front profile (y, z), pushed along x. */
|
|
56
|
+
export function arcFront(cy: number, cz: number, r0: number, r1: number, a0: number, a1: number, x0: number, x1: number, n?: number): Piece[];
|
|
57
|
+
/** A gable roof, its ridge along y. */
|
|
58
|
+
export function roofY(x0: number, x1: number, y0: number, y1: number, z0: number, rise: number): Piece;
|
|
59
|
+
/** A gable roof, its ridge along x. */
|
|
60
|
+
export function roofX(x0: number, x1: number, y0: number, y1: number, z0: number, rise: number): Piece;
|
|
61
|
+
/** A shop block with its shopfront cuts and its roof's centre. */
|
|
62
|
+
export function shop(W: number, D: number, H: number, o?: { win?: boolean; door?: number | null; dh?: number }): { parts: Piece[]; cuts: Point3[][]; c: Point3 };
|
|
63
|
+
/** A flat convex profile standing on the roof facing +y. */
|
|
64
|
+
export function sign(pts: Pts, yc: number, t?: number): Piece;
|
|
65
|
+
/** A disc on edge facing +y. */
|
|
66
|
+
export function discY(x: number, z: number, r: number, yc: number, t?: number): Piece;
|
|
67
|
+
/** A disc on edge facing +x. */
|
|
68
|
+
export function discX(y: number, z: number, r: number, xc: number, t?: number): Piece;
|
|
69
|
+
/** 3D points scaled about o by k. */
|
|
70
|
+
export function sc3(pts: Pts, o: readonly number[], k: number): number[][];
|
|
71
|
+
/** A part scaled about o by k. */
|
|
72
|
+
export function scalePart<T extends Part>(part: T, o: readonly number[], k: number): T;
|
|
73
|
+
/** A shop with its trade feature, as a build (g) => shape. */
|
|
74
|
+
export function shopMark(size: readonly number[], feat: (c: number[], W: number, D: number, H: number, k: number) => unknown[], o?: { win?: boolean; door?: number | null; dh?: number; big?: number }): (g: number) => Shape;
|
|
75
|
+
/** A box tapering from w × d at z0 to W × D at z1. */
|
|
76
|
+
export function taper(cx: number, cy: number, w: number, d: number, W: number, D: number, z0: number, z1: number): Piece;
|
|
77
|
+
/** An open box's floor and walls. */
|
|
78
|
+
export function tray(x0: number, y0: number, x1: number, y1: number, h: number, t: number, z0?: number): Piece[];
|
|
79
|
+
/** The facing plane's right-hand axis, along (1, −1, 0). */
|
|
80
|
+
export const FU: Point3;
|
|
81
|
+
/** The facing plane's normal, along (1, 1, 0). */
|
|
82
|
+
export const FN: Point3;
|
|
83
|
+
/** 2D points on the facing plane through o, pushed s towards the viewer. */
|
|
84
|
+
export function onFacing(o: readonly number[], pts: Pts, s?: number): Point3[];
|
|
85
|
+
/** A convex profile on the facing plane, t deep. */
|
|
86
|
+
export function facing(o: readonly number[], pts: Pts, t: number, smooth?: boolean): Piece;
|
|
87
|
+
/** An annulus band on the facing plane, t deep, as convex pieces. */
|
|
88
|
+
export function facingArc(o: readonly number[], c: readonly number[], r0: number, r1: number, a0: number, a1: number, t: number, n?: number): Piece[];
|
|
89
|
+
/** A lathe through a [radius, height] profile. */
|
|
90
|
+
export function lathe(cx: number, cy: number, prof: Pts, n?: number): Piece[];
|
|
91
|
+
/** A cut-out square to the viewer, for isoFlat(). */
|
|
92
|
+
export function flat(o: readonly number[], outer: readonly Pts[], t: number, holes?: readonly Pts[]): Flat;
|
|
93
|
+
/** A 2D outline turned anticlockwise. */
|
|
94
|
+
export function ccw<T extends Pts>(pts: T): T;
|
|
95
|
+
/** flat() with every outline and hole turned anticlockwise. */
|
|
96
|
+
export function flatCcw(o: readonly number[], outer: readonly Pts[], t: number, holes?: readonly Pts[]): Flat;
|
|
97
|
+
/** A flat() scaled about o by k. */
|
|
98
|
+
export function scaleFlat(f: Flat, o: readonly number[], k: number): Flat;
|
|
99
|
+
/** A 2D shape swept along the screen vector v. */
|
|
100
|
+
export function sweep(sh: Shape, v: readonly number[]): Shape;
|
|
101
|
+
/** isoCut() with flat() cut-outs in front of the parts. */
|
|
102
|
+
export function isoFlat(parts: readonly Part[], g: number, flats: readonly Flat[], holes?: readonly Pts[], keep?: readonly Pts[]): Shape;
|
|
103
|
+
/** Points round an ellipse from d0 to d1 degrees (2D, both ends). */
|
|
104
|
+
export function arcPts(a: number, b: number, ra: number, rb: number, d0: number, d1: number, n?: number): Point[];
|
|
105
|
+
/** A slot w wide along p–q, as a quad. */
|
|
106
|
+
export function slot2(p: readonly number[], q: readonly number[], w: number): Point[];
|
|
107
|
+
/** A ring of gap w wide at radius r, as small quads. */
|
|
108
|
+
export function ring2(a: number, b: number, r: number, w: number, n?: number): Point[][];
|
|
109
|
+
/** A part re-aimed: each point to T + x·e1 + y·e2 + z·e3. */
|
|
110
|
+
export function turned<T extends Part>(part: T, T: readonly number[], e1: readonly number[], e2: readonly number[], e3: readonly number[]): T;
|
|
111
|
+
/** A capsule's lathe profile. */
|
|
112
|
+
export function capsule(r: number, L: number, both?: boolean): number[][];
|
|
113
|
+
/** A part built up z turned so its z axis runs from a towards b. */
|
|
114
|
+
export function aimed<T extends Part>(part: T, a: readonly number[], b: readonly number[]): T;
|
|
115
|
+
/** A round pole from a to b. */
|
|
116
|
+
export function pole(a: readonly number[], b: readonly number[], r: number): Piece;
|
|
117
|
+
/** A lathe laid along the horizontal unit vector u, its middle at c. */
|
|
118
|
+
export function lying<T extends Part>(part: T, c: readonly number[], u: readonly number[], len: number): T;
|
|
119
|
+
/** The gap in model units for parts plus flat() cut-outs. */
|
|
120
|
+
export function gapWith(parts: readonly Part[], flats: readonly Flat[], g: number): number;
|
|
121
|
+
/** A circle as n 2D points. */
|
|
122
|
+
export function circ(a: number, b: number, r: number, n?: number): Point[];
|
|
123
|
+
/** A quad along an arm at d degrees from r0 to r1. */
|
|
124
|
+
export function arm(cx: number, cy: number, d: number, r0: number, r1: number, w: number, w1?: number): Point[];
|
|
125
|
+
/** 2D points turned deg anticlockwise about c. */
|
|
126
|
+
export function rot(pts: Pts, deg: number, c?: readonly number[]): Point[];
|
|
127
|
+
/** An ellipse as 2D points, turned deg. */
|
|
128
|
+
export function ell(a: number, b: number, ra: number, rb: number, deg?: number, n?: number): Point[];
|
|
129
|
+
/** The facing plane's vertical foreshortening, √(2/3). */
|
|
130
|
+
export const SQ: number;
|
|
131
|
+
/** A circle on the facing plane that projects round. */
|
|
132
|
+
export function rnd(a: number, b: number, r: number, n?: number): Point[];
|
|
133
|
+
/** A disc's outline as 2D points. */
|
|
134
|
+
export function disc(a: number, b: number, r: number, n?: number): Point[];
|
|
135
|
+
/** A rectangle with rounded corners, as 2D points. */
|
|
136
|
+
export function rr(a0: number, b0: number, a1: number, b1: number, r: number, n?: number): Point[];
|
|
137
|
+
/** An almond from p to q, w wide. */
|
|
138
|
+
export function lens(p: readonly number[], q: readonly number[], w: number, n?: number): Point[];
|
|
139
|
+
/** A slot along a polyline, one quad a segment. */
|
|
140
|
+
export function path2(pts: Pts, w: number): Point[][];
|
|
141
|
+
/** 2D outlines as cuts on the front face of a flat(). */
|
|
142
|
+
export function flatCuts(o: readonly number[], t: number, list: readonly Pts[]): Point3[][];
|
|
143
|
+
/** A roof feature of flat() cut-outs, as shopMark()'s feat. */
|
|
144
|
+
export function roofFlats(fn: (o: number[], k: number) => { flats: Flat[]; cuts?: unknown[]; keep?: unknown[] }): (c: number[], W: number, D: number, H: number, k: number) => unknown[];
|
|
145
|
+
/** A spiral slot as 2D quads. */
|
|
146
|
+
export function spiral(a: number, b: number, r0: number, r1: number, turns: number, w: number, n?: number): Point[][];
|
|
147
|
+
/** Pieces whose side faces merge into one surface. */
|
|
148
|
+
export function smooth(ps: readonly Piece[]): Piece[];
|
|
149
|
+
/** A flame outline, about its foot. */
|
|
150
|
+
export function flame(a: number, b: number, h: number): Point[];
|
|
151
|
+
/** A thick 2D stroke as convex pieces. */
|
|
152
|
+
export function stroke(pts: Pts, w: number): Point[][];
|
|
153
|
+
/** An annulus band as convex 2D quads. */
|
|
154
|
+
export function band(a: number, b: number, r0: number, r1: number, d0: number, d1: number, n?: number): Point[][];
|
|
155
|
+
/** 2D points moved by (da, db). */
|
|
156
|
+
export function mv(pts: Pts, da: number, db: number): Point[];
|
|
157
|
+
/** A rectangle a0–a1 × b0–b1, as four 2D points. */
|
|
158
|
+
export function rect(a0: number, b0: number, a1: number, b1: number): Point[];
|
|
159
|
+
/** A kit glyph on a plane: its outlines to cut and counters to keep. */
|
|
160
|
+
export function glyphOn(k: string, o: readonly number[], u: readonly number[], v: readonly number[], h: number, T?: number): { cut: Point3[][]; keep: Point3[][] };
|
|
161
|
+
/** A 3D point moved by k times v. */
|
|
162
|
+
export function add3(p: readonly number[], v: readonly number[], k?: number): number[];
|
|
163
|
+
/** A ring of gap round a 3D outline, measured on the canvas. */
|
|
164
|
+
export function ringIn(parts: readonly Part[], s: Shape, q: Pts, g: number): Shape;
|
|
165
|
+
/** Keys tiling a 3D outline, cut as islands a canvas gap apart. */
|
|
166
|
+
export function keysIn(parts: readonly Part[], s: Shape, area: Pts, keys: readonly Pts[], g: number): Shape;
|
|
167
|
+
/** A slab tipped back by deg from upright. */
|
|
168
|
+
export function slab(o: readonly number[], deg: number, outline: Pts, t: number, o2?: { dir?: 'x' | 'y'; smooth?: boolean }): { part: Piece; on: (pts: Pts) => number[][]; n: Point3 };
|