@logomarks/core 0.1.8 → 0.1.11
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 +33 -0
- package/README.md +4 -1
- package/package.json +22 -3
- package/src/batch/args.d.ts +18 -0
- package/src/batch/args.js +44 -0
- package/src/batch/index.d.ts +7 -0
- package/src/batch/index.js +10 -0
- package/src/batch/run.d.ts +53 -0
- package/src/batch/run.js +92 -0
- package/src/batch/slug.d.ts +2 -0
- package/src/batch/slug.js +12 -0
- package/src/batch/source.d.ts +12 -0
- package/src/batch/source.js +23 -0
- package/src/fit/index.d.ts +4 -0
- package/src/fit/index.js +29 -5
- package/src/geometry/index.d.ts +1 -0
- package/src/geometry/index.js +1 -0
- package/src/geometry/mitre.d.ts +8 -0
- package/src/geometry/mitre.js +64 -0
- package/src/geometry/modular.d.ts +1 -1
- package/src/index.d.ts +1 -0
- package/src/index.js +3 -2
- package/src/parts/index.d.ts +2 -0
- package/src/parts/index.js +2 -0
- package/src/parts/pixels.d.ts +11 -0
- package/src/parts/pixels.js +74 -0
- package/src/parts/run.js +4 -2
- package/src/parts/span.d.ts +13 -0
- package/src/parts/span.js +100 -0
- package/src/sdf/fields.js +135 -0
- package/src/sdf/gap.js +42 -0
- package/src/sdf/index.d.ts +56 -0
- package/src/sdf/index.js +12 -0
- package/src/sdf/ops.js +102 -0
- package/src/sdf/trace.js +90 -0
- package/src/skill/bundle.js +1 -1
- package/src/stitch/border.d.ts +2 -0
- package/src/stitch/border.js +40 -0
- package/src/stitch/field.d.ts +14 -0
- package/src/stitch/field.js +207 -0
- package/src/stitch/fill.d.ts +2 -0
- package/src/stitch/fill.js +67 -0
- package/src/stitch/index.d.ts +6 -0
- package/src/stitch/index.js +14 -0
- package/src/stitch/plan.d.ts +46 -0
- package/src/stitch/plan.js +127 -0
- package/src/stitch/regions.d.ts +4 -0
- package/src/stitch/regions.js +54 -0
- package/src/stitch/satin.d.ts +2 -0
- package/src/stitch/satin.js +86 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @logomarks/core/stitch/satin
|
|
3
|
+
*
|
|
4
|
+
* Satin stitch: the narrow parts covered by threads laid side by side
|
|
5
|
+
* straight across them, edge to edge, each following the stroke's local
|
|
6
|
+
* direction. The threads start on the stroke's middle line (the ridge of
|
|
7
|
+
* its distance field), spaced evenly along it, and run both ways along the
|
|
8
|
+
* direction across until the edge. Where the picks along the middle line
|
|
9
|
+
* leave a gap, and where threads fan apart (the outside of a bend, a
|
|
10
|
+
* stroke's end), more threads are laid through what's left bare.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { acrossField, sample, spaced, reach } from './field.js';
|
|
14
|
+
|
|
15
|
+
/** How many times the threads are topped up through what's still bare. */
|
|
16
|
+
const PASSES = 2;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Marks the pixels near a stitch as covered.
|
|
20
|
+
*
|
|
21
|
+
* @param {Uint8Array} covered The coverage, changed in place.
|
|
22
|
+
* @param {number} W The width.
|
|
23
|
+
* @param {number} H The height.
|
|
24
|
+
* @param {number[]} s The stitch: `x0, y0, x1, y1`.
|
|
25
|
+
* @param {number} r How near, in pixels.
|
|
26
|
+
*/
|
|
27
|
+
function cover(covered, W, H, [x0, y0, x1, y1], r) {
|
|
28
|
+
const [dx, dy] = [x1 - x0, y1 - y0];
|
|
29
|
+
const L2 = Math.max(1e-9, dx * dx + dy * dy);
|
|
30
|
+
for (let y = Math.max(0, Math.floor(Math.min(y0, y1) - r)); y <= Math.min(H - 1, Math.ceil(Math.max(y0, y1) + r)); y++) {
|
|
31
|
+
for (let x = Math.max(0, Math.floor(Math.min(x0, x1) - r)); x <= Math.min(W - 1, Math.ceil(Math.max(x0, x1) + r)); x++) {
|
|
32
|
+
const t = Math.max(0, Math.min(1, ((x - x0) * dx + (y - y0) * dy) / L2));
|
|
33
|
+
if ((x - x0 - t * dx) ** 2 + (y - y0 - t * dy) ** 2 <= r * r) covered[y * W + x] = 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The satin stitches over a mask.
|
|
40
|
+
*
|
|
41
|
+
* @param {Uint8Array} mask Where (1 inside: the narrow parts).
|
|
42
|
+
* @param {Float32Array} dist Each ink pixel's distance to the edge of the ink.
|
|
43
|
+
* @param {number} W The raster's width.
|
|
44
|
+
* @param {number} H Its height.
|
|
45
|
+
* @param {object} o How.
|
|
46
|
+
* @param {number} o.spacing The distance between threads, in pixels.
|
|
47
|
+
* @param {number} o.half Half the widest satin, in pixels (a thread reaches no farther from where it starts than about this).
|
|
48
|
+
* @param {number} o.smooth How far the direction is smoothed, in pixels.
|
|
49
|
+
* @returns {number[]} The stitches, flat: `x0, y0, x1, y1` each, in pixel coordinates.
|
|
50
|
+
*/
|
|
51
|
+
export function satinStitches(mask, dist, W, H, { spacing, half, smooth }) {
|
|
52
|
+
const field = acrossField(dist, mask, W, H, Math.max(1, Math.round(smooth)));
|
|
53
|
+
const out = [];
|
|
54
|
+
const covered = new Uint8Array(W * H);
|
|
55
|
+
const lay = (i) => {
|
|
56
|
+
const x = i % W, y = (i - x) / W;
|
|
57
|
+
const [ax, ay] = [Math.cos(field[i]), Math.sin(field[i])];
|
|
58
|
+
const max = Math.min(half * 1.6, dist[i] * 1.8) + 1.5;
|
|
59
|
+
const tp = reach(dist, W, H, x, y, ax, ay, max);
|
|
60
|
+
const tm = reach(dist, W, H, x, y, -ax, -ay, max);
|
|
61
|
+
if (tp + tm < 0.8) return;
|
|
62
|
+
const s = [x - ax * tm, y - ay * tm, x + ax * tp, y + ay * tp];
|
|
63
|
+
out.push(...s);
|
|
64
|
+
cover(covered, W, H, s, spacing * 1.1);
|
|
65
|
+
};
|
|
66
|
+
// the middle line: pixels at least as far from the edge as their neighbours across
|
|
67
|
+
const ridge = [];
|
|
68
|
+
for (let i = 0; i < W * H; i++) {
|
|
69
|
+
if (!mask[i] || dist[i] < 1) continue;
|
|
70
|
+
const x = i % W, y = (i - x) / W;
|
|
71
|
+
const [ax, ay] = [Math.cos(field[i]), Math.sin(field[i])];
|
|
72
|
+
if (dist[i] >= sample(dist, W, H, x + ax, y + ay) - 1e-3 && dist[i] >= sample(dist, W, H, x - ax, y - ay) - 1e-3) ridge.push(i);
|
|
73
|
+
}
|
|
74
|
+
for (const i of spaced(ridge, W, spacing)) lay(i);
|
|
75
|
+
// where the picks along the middle line met from two sides and left a gap, one more thread
|
|
76
|
+
const near = new Uint8Array(W * H);
|
|
77
|
+
for (let k = 0; k < out.length; k += 4) cover(near, W, H, out.slice(k, k + 4), spacing * 0.6);
|
|
78
|
+
for (const i of spaced(ridge.filter((j) => !near[j]), W, spacing * 0.8)) lay(i);
|
|
79
|
+
for (let p = 0; p < PASSES; p++) {
|
|
80
|
+
const bare = [];
|
|
81
|
+
for (let i = 0; i < W * H; i++) if (mask[i] && !covered[i]) bare.push(i);
|
|
82
|
+
if (!bare.length) break;
|
|
83
|
+
for (const i of spaced(bare, W, spacing, (j) => covered[j] === 1)) lay(i);
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|