@logomarks/core 0.1.5 → 0.1.8

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/src/svg/shape.js CHANGED
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * A mark read back in as a shape: every filled outline unioned, each with its own fill rule. Even-odd outlines
3
- * exclude every ring; non-zero ones test the winding just either side of each ring's edge, so reversed holes, islands
4
- * and same-way overlaps all come out right.
3
+ * exclude every ring; non-zero ones sum the rings' windings (nonzero.js), so reversed holes, islands, same-way
4
+ * overlaps and overlapping subpaths (font glyphs) all come out right.
5
5
  */
6
6
  import { OPS } from '../geometry/booleans.js';
7
- import { signedArea, winding } from '../geometry/polygon.js';
7
+ import { signedArea } from '../geometry/polygon.js';
8
+ import { nonzeroFill } from './nonzero.js';
8
9
  import { rings } from './rings.js';
9
10
  import { parsePath } from './path.js';
10
11
  import { shapes } from './shapes.js';
@@ -17,32 +18,7 @@ import { shapes } from './shapes.js';
17
18
  * @param {import('../geometry/booleans.js').BooleanOps} b The booleans.
18
19
  * @returns {import('../geometry/types.js').Shape} The filled shape.
19
20
  */
20
- function fillOf(rs, evenodd, b) {
21
- if (evenodd) return b.xor(...rs.map((r) => [r]));
22
- const sorted = rs.slice().sort((p, q) => Math.abs(signedArea(q)) - Math.abs(signedArea(p)));
23
- const total = (/** @type {import('../geometry/types.js').Point} */ pt) => rs.reduce((s, r) => s + winding(r, pt), 0);
24
- /** @type {import('../geometry/types.js').Shape} */
25
- let g = [];
26
- for (const r of sorted) {
27
- let k = 0, longest = 0;
28
- r.forEach((p, i) => {
29
- const q = r[(i + 1) % r.length], L = Math.hypot(q[0] - p[0], q[1] - p[1]);
30
- if (L > longest) { k = i; longest = L; }
31
- });
32
- const p = r[k], q = r[(k + 1) % r.length], e = 0.05;
33
- const nx = ((q[1] - p[1]) / longest) * e, ny = ((q[0] - p[0]) / longest) * e;
34
- const m = [(p[0] + q[0]) / 2, (p[1] + q[1]) / 2];
35
- /** @type {import('../geometry/types.js').Point} */
36
- const a = [m[0] - nx, m[1] + ny];
37
- /** @type {import('../geometry/types.js').Point} */
38
- const c = [m[0] + nx, m[1] - ny];
39
- const [inside, outside] = winding(r, a) ? [a, c] : [c, a];
40
- const fi = total(inside) !== 0, fo = total(outside) !== 0;
41
- if (fi && !fo) g = b.union(g, [r]);
42
- else if (!fi && fo) g = b.difference(g, [r]);
43
- }
44
- return g;
45
- }
21
+ const fillOf = (rs, evenodd, b) => (evenodd ? b.xor(...rs.map((r) => [r])) : nonzeroFill(rs, b));
46
22
 
47
23
  /**
48
24
  * Outlines (parsed path data with their fill rules) as one shape.