@chrtco/sdk 0.10.54 → 0.10.55

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.
@@ -18817,9 +18817,9 @@ function arcSegmentSvg(token, sweepDeg) {
18817
18817
  const box = segmentBox(sweepDeg);
18818
18818
  const end = sweepDeg + JOINT_OVERLAP_DEG;
18819
18819
  const core = token === "CHBRN" ? OBSCURED_CORE_WIDTH : CORE_WIDTH;
18820
- const R = SECTOR_ARC_RADIUS;
18821
- const outline = annularSectorPath(end, R - OUTLINE_WIDTH / 2, R + OUTLINE_WIDTH / 2, box);
18822
- const inner = annularSectorPath(end, R - core / 2, R + core / 2, box);
18820
+ const R2 = SECTOR_ARC_RADIUS;
18821
+ const outline = annularSectorPath(end, R2 - OUTLINE_WIDTH / 2, R2 + OUTLINE_WIDTH / 2, box);
18822
+ const inner = annularSectorPath(end, R2 - core / 2, R2 + core / 2, box);
18823
18823
  return `<svg xmlns="http://www.w3.org/2000/svg" width="${box.w}" height="${box.h}" viewBox="0 0 ${box.w} ${box.h}"><path d="${outline}" fill="CHBLK"/><path d="${inner}" fill="${token}"/></svg>`;
18824
18824
  }
18825
18825
  function legSvg() {
@@ -18971,17 +18971,17 @@ async function decode(spec) {
18971
18971
  var scratch = null;
18972
18972
  function scratchContext() {
18973
18973
  if (!scratch) {
18974
- const canvas = document.createElement("canvas");
18975
- scratch = canvas.getContext("2d", { willReadFrequently: true });
18974
+ const canvas2 = document.createElement("canvas");
18975
+ scratch = canvas2.getContext("2d", { willReadFrequently: true });
18976
18976
  if (!scratch) throw new Error("symbol-images: no 2d canvas context");
18977
18977
  }
18978
18978
  return scratch;
18979
18979
  }
18980
18980
  function rasterise(src, spec) {
18981
18981
  const ctx = scratchContext();
18982
- const canvas = ctx.canvas;
18983
- canvas.width = spec.width;
18984
- canvas.height = spec.height;
18982
+ const canvas2 = ctx.canvas;
18983
+ canvas2.width = spec.width;
18984
+ canvas2.height = spec.height;
18985
18985
  ctx.drawImage(src.img, 0, -src.y, src.width, src.height);
18986
18986
  return ctx.getImageData(0, 0, spec.width, spec.height);
18987
18987
  }
@@ -19331,13 +19331,13 @@ function decodeSvgToImage(themedSvg, size) {
19331
19331
  }
19332
19332
  async function imageToBitmap(img, size) {
19333
19333
  try {
19334
- const canvas = document.createElement("canvas");
19335
- canvas.width = size.w;
19336
- canvas.height = size.h;
19337
- const ctx = canvas.getContext("2d");
19334
+ const canvas2 = document.createElement("canvas");
19335
+ canvas2.width = size.w;
19336
+ canvas2.height = size.h;
19337
+ const ctx = canvas2.getContext("2d");
19338
19338
  if (!ctx) return null;
19339
19339
  ctx.drawImage(img, 0, 0, size.w, size.h);
19340
- return await createImageBitmap(canvas);
19340
+ return await createImageBitmap(canvas2);
19341
19341
  } catch {
19342
19342
  return null;
19343
19343
  }
@@ -20329,6 +20329,263 @@ function getThemedS101Svg(symbolName, table = "DAY") {
20329
20329
  });
20330
20330
  }
20331
20331
 
20332
+ // src/atlas/look-painter.ts
20333
+ function painter(w, h) {
20334
+ const acc = new Float32Array(w * h * 4);
20335
+ const over = (x, y, c, cov) => {
20336
+ if (x < 0 || y < 0 || x >= w || y >= h || cov <= 0) return;
20337
+ const k = (y * w + x) * 4;
20338
+ const a = c[3] / 255 * Math.min(1, cov);
20339
+ acc[k] = c[0] * a + acc[k] * (1 - a);
20340
+ acc[k + 1] = c[1] * a + acc[k + 1] * (1 - a);
20341
+ acc[k + 2] = c[2] * a + acc[k + 2] * (1 - a);
20342
+ acc[k + 3] = a + acc[k + 3] * (1 - a);
20343
+ };
20344
+ const dot = (cx, cy, r, c) => {
20345
+ for (let y = Math.floor(cy - r - 1); y <= Math.ceil(cy + r + 1); y++) {
20346
+ for (let x = Math.floor(cx - r - 1); x <= Math.ceil(cx + r + 1); x++) over(x, y, c, r + 0.5 - Math.hypot(x + 0.5 - cx, y + 0.5 - cy));
20347
+ }
20348
+ };
20349
+ const stroke = (pts, r, c) => {
20350
+ const cov = new Float32Array(w * h);
20351
+ for (let i = 1; i < pts.length; i++) {
20352
+ const [x0, y0] = pts[i - 1];
20353
+ const [x1, y1] = pts[i];
20354
+ const n = Math.max(1, Math.ceil(Math.hypot(x1 - x0, y1 - y0) * 2));
20355
+ for (let t = 0; t <= n; t++) {
20356
+ const cx = x0 + (x1 - x0) * t / n;
20357
+ const cy = y0 + (y1 - y0) * t / n;
20358
+ for (let y = Math.floor(cy - r - 1); y <= Math.ceil(cy + r + 1); y++) {
20359
+ for (let x = Math.floor(cx - r - 1); x <= Math.ceil(cx + r + 1); x++) {
20360
+ if (x < 0 || y < 0 || x >= w || y >= h) continue;
20361
+ const v = Math.max(0, Math.min(1, r + 0.5 - Math.hypot(x + 0.5 - cx, y + 0.5 - cy)));
20362
+ if (v > cov[y * w + x]) cov[y * w + x] = v;
20363
+ }
20364
+ }
20365
+ }
20366
+ }
20367
+ for (let k = 0; k < cov.length; k++) if (cov[k] > 0) over(k % w, Math.floor(k / w), c, cov[k]);
20368
+ };
20369
+ const fill = (pts, c) => {
20370
+ const y0 = Math.max(0, Math.floor(Math.min(...pts.map((p) => p[1]))));
20371
+ const y1 = Math.min(h - 1, Math.ceil(Math.max(...pts.map((p) => p[1]))));
20372
+ const x0 = Math.max(0, Math.floor(Math.min(...pts.map((p) => p[0]))));
20373
+ const x1 = Math.min(w - 1, Math.ceil(Math.max(...pts.map((p) => p[0]))));
20374
+ for (let y = y0; y <= y1; y++) {
20375
+ for (let x = x0; x <= x1; x++) {
20376
+ let inside = 0;
20377
+ for (let sy = 0; sy < 4; sy++) for (let sx = 0; sx < 4; sx++) {
20378
+ const px = x + (sx + 0.5) / 4;
20379
+ const py = y + (sy + 0.5) / 4;
20380
+ let odd = false;
20381
+ for (let i = 0, j = pts.length - 1; i < pts.length; j = i++) {
20382
+ const [xi, yi] = pts[i];
20383
+ const [xj, yj] = pts[j];
20384
+ if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi) odd = !odd;
20385
+ }
20386
+ if (odd) inside++;
20387
+ }
20388
+ over(x, y, c, inside / 16);
20389
+ }
20390
+ }
20391
+ };
20392
+ const data = () => {
20393
+ const out = new Uint8Array(w * h * 4);
20394
+ for (let k = 0; k < w * h; k++) {
20395
+ const a = acc[k * 4 + 3];
20396
+ if (a <= 0) continue;
20397
+ out[k * 4] = Math.round(acc[k * 4] / a);
20398
+ out[k * 4 + 1] = Math.round(acc[k * 4 + 1] / a);
20399
+ out[k * 4 + 2] = Math.round(acc[k * 4 + 2] / a);
20400
+ out[k * 4 + 3] = Math.round(a * 255);
20401
+ }
20402
+ return out;
20403
+ };
20404
+ return { dot, stroke, fill, data };
20405
+ }
20406
+ function turn([x, y], cx, cy, deg) {
20407
+ const r = deg * Math.PI / 180;
20408
+ const dx = x - cx;
20409
+ const dy = y - cy;
20410
+ return [cx + dx * Math.cos(r) - dy * Math.sin(r), cy + dx * Math.sin(r) + dy * Math.cos(r)];
20411
+ }
20412
+
20413
+ // src/atlas/uschart1-marks.ts
20414
+ var CLASSIC_MARK_TONES = {
20415
+ color: { magenta: "#953699", green: "#068b00", ink: "#000000", open: "#ffffff" },
20416
+ // A laser printer's greys: red lighter than green, so a banded mark still
20417
+ // shows its bands. The label (R, G) says which is which, as it always does.
20418
+ mono: { magenta: "#8c8c8c", green: "#4d4d4d", ink: "#000000", open: "#ffffff" }
20419
+ };
20420
+ var PREFIX = { color: "chrt-look-cl-", mono: "chrt-look-cm-" };
20421
+ function classicMarkId(ink, name) {
20422
+ return PREFIX[ink] + name;
20423
+ }
20424
+ function classicMarkInk(id) {
20425
+ for (const ink of ["color", "mono"]) {
20426
+ if (id.startsWith(PREFIX[ink]) && CLASSIC_MARK_NAMES.includes(id.slice(PREFIX[ink].length))) return ink;
20427
+ }
20428
+ return null;
20429
+ }
20430
+ var COLOURS = ["red", "green", "black", "yellow", "white"];
20431
+ var BOARDS = ["triangle-up", "triangle-down", "square", "rhombus"];
20432
+ var paints = COLOURS.flatMap((a) => [
20433
+ a,
20434
+ ...COLOURS.filter((b) => b !== a).flatMap((b) => [`${a}-${b}-h`, `${a}-${b}-v`])
20435
+ ]);
20436
+ var BUOY_NAMES = paints.map((p) => `buoy-${p}`);
20437
+ var BOARD_NAMES = BOARDS.flatMap((s) => paints.map((p) => `board-${s}-${p}`));
20438
+ var CLASSIC_MARK_NAMES = ["flare", "disc", ...BUOY_NAMES, ...BOARD_NAMES];
20439
+ var num = (attr) => ["to-number", ["coalesce", ["get", attr], ["get", attr.toLowerCase()], 0], 0];
20440
+ var LOZENGE_BUOY = ["!", ["in", num("BOYSHP"), ["literal", [7, 8]]]];
20441
+ var DAYBEACON = ["!", ["in", num("BCNSHP"), ["literal", [3, 4, 6]]]];
20442
+ var R = 2;
20443
+ var S = 64 * R;
20444
+ var C0 = S / 2;
20445
+ var BUOY_LENGTH = 12.5;
20446
+ var BUOY_HALF_WIDTH = 3.4;
20447
+ var DISC_RADIUS = 8.5;
20448
+ var BOARD_SIDE = 8;
20449
+ var SB = 96 * R;
20450
+ var CB = SB / 2;
20451
+ var FLARE_SCALE = 0.6;
20452
+ var FLARE_ANCHOR = 18;
20453
+ function paintOf(ink, c) {
20454
+ const t = CLASSIC_MARK_TONES[ink];
20455
+ return c === "red" ? t.magenta : c === "green" ? t.green : c === "black" ? t.ink : t.open;
20456
+ }
20457
+ function circle(cx, cy, r) {
20458
+ return Array.from({ length: 33 }, (_, i) => [cx + r * Math.cos(i / 32 * 2 * Math.PI), cy + r * Math.sin(i / 32 * 2 * Math.PI)]);
20459
+ }
20460
+ function flare(ink) {
20461
+ const path = [[16.3, 28], [11.8, 7.1], [11.8, 4.9], [12.4, 3.5], [13.2, 3], [14.3, 2.1], [16, 1.9], [17.4, 2.1], [18.5, 2.4], [19.6, 3.2], [20.2, 4.6], [20.4, 5.7], [20.4, 6.9]];
20462
+ const k = 0.9698;
20463
+ const place = ([x, y]) => {
20464
+ const [rx, ry] = turn([(x - 16.3) * 0.9 * FLARE_SCALE, (y - 28) * 0.9 * FLARE_SCALE], 0, 0, 135);
20465
+ return [((rx + 10 - 16.1) * k + 16) * 2 * R, ((ry + 10 - 14.95) * k + 16) * 2 * R];
20466
+ };
20467
+ const t = CLASSIC_MARK_TONES[ink];
20468
+ return { width: S, height: S, pixelRatio: R, ops: [{ fill: path.map(place), c: t.magenta }, { dot: [FLARE_ANCHOR * R, FLARE_ANCHOR * R], r: 2.6 * R, c: t.ink }] };
20469
+ }
20470
+ function disc(ink) {
20471
+ return { width: S, height: S, pixelRatio: R, ops: [{ fill: circle(C0, C0, DISC_RADIUS * R), c: CLASSIC_MARK_TONES[ink].magenta }] };
20472
+ }
20473
+ function buoy(ink, c1, c2, split) {
20474
+ const ops = [];
20475
+ const t = CLASSIC_MARK_TONES[ink];
20476
+ const L = BUOY_LENGTH;
20477
+ const W = BUOY_HALF_WIDTH;
20478
+ const lean = 45;
20479
+ const at = (a, b) => turn([CB + b * R, CB - a * R], CB, CB, lean);
20480
+ const foot = 1.6;
20481
+ const outline = [at(foot, 0), at(foot + L / 2, -W), at(foot + L, 0), at(foot + L / 2, W)];
20482
+ if (split === null) ops.push({ fill: outline, c: paintOf(ink, c1) });
20483
+ else if (split === "h") {
20484
+ ops.push({ fill: [at(foot, 0), at(foot + L / 2, -W), at(foot + L / 2, W)], c: paintOf(ink, c2) });
20485
+ ops.push({ fill: [at(foot + L / 2, -W), at(foot + L, 0), at(foot + L / 2, W)], c: paintOf(ink, c1) });
20486
+ } else {
20487
+ ops.push({ fill: [at(foot, 0), at(foot + L / 2, -W), at(foot + L, 0)], c: paintOf(ink, c1) });
20488
+ ops.push({ fill: [at(foot, 0), at(foot + L, 0), at(foot + L / 2, W)], c: paintOf(ink, c2) });
20489
+ }
20490
+ ops.push({ stroke: [...outline, outline[0]], r: 0.35 * R, c: t.ink });
20491
+ if (split === "v") ops.push({ stroke: [at(foot, 0), at(foot + L, 0)], r: 0.3 * R, c: t.ink });
20492
+ if (split === "h") ops.push({ stroke: [at(foot + L / 2, -W), at(foot + L / 2, W)], r: 0.3 * R, c: t.ink });
20493
+ const ring = circle(CB, CB, 2 * R);
20494
+ ops.push({ fill: ring, c: t.open });
20495
+ ops.push({ stroke: ring, r: 0.35 * R, c: t.ink });
20496
+ return { width: SB, height: SB, pixelRatio: R, ops };
20497
+ }
20498
+ function boardOutline(shape) {
20499
+ const h = BOARD_SIDE / 2 * R;
20500
+ switch (shape) {
20501
+ case "triangle-up":
20502
+ return [[C0 - h, C0 + h * 0.58], [C0 + h, C0 + h * 0.58], [C0, C0 - h * 1.15]];
20503
+ case "triangle-down":
20504
+ return [[C0 - h, C0 - h * 0.58], [C0, C0 + h * 1.15], [C0 + h, C0 - h * 0.58]];
20505
+ case "square":
20506
+ return [[C0 - h * 0.85, C0 - h * 0.85], [C0 + h * 0.85, C0 - h * 0.85], [C0 + h * 0.85, C0 + h * 0.85], [C0 - h * 0.85, C0 + h * 0.85]];
20507
+ case "rhombus":
20508
+ return [[C0, C0 - h * 1.2], [C0 + h * 1.2, C0], [C0, C0 + h * 1.2], [C0 - h * 1.2, C0]];
20509
+ }
20510
+ }
20511
+ function half(pts, axis, first) {
20512
+ const inside = (p) => first ? p[axis] <= C0 : p[axis] >= C0;
20513
+ const out = [];
20514
+ for (let i = 0; i < pts.length; i++) {
20515
+ const a = pts[i];
20516
+ const b = pts[(i + 1) % pts.length];
20517
+ if (inside(a)) out.push(a);
20518
+ if (inside(a) !== inside(b)) {
20519
+ const t = (C0 - a[axis]) / (b[axis] - a[axis]);
20520
+ out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);
20521
+ }
20522
+ }
20523
+ return out;
20524
+ }
20525
+ function chord(pts, axis) {
20526
+ const top = half(pts, axis, true);
20527
+ return top.filter((p) => Math.abs(p[axis] - C0) < 1e-9);
20528
+ }
20529
+ function board(ink, shape, c1, c2, split) {
20530
+ const pts = boardOutline(shape);
20531
+ const ops = [];
20532
+ if (split === null) ops.push({ fill: pts, c: paintOf(ink, c1) });
20533
+ else {
20534
+ const axis = split === "h" ? 1 : 0;
20535
+ ops.push({ fill: half(pts, axis, true), c: paintOf(ink, c1) });
20536
+ ops.push({ fill: half(pts, axis, false), c: paintOf(ink, c2) });
20537
+ }
20538
+ const ink0 = CLASSIC_MARK_TONES[ink].ink;
20539
+ ops.push({ stroke: [...pts, pts[0]], r: 0.45 * R, c: ink0 });
20540
+ if (split !== null) ops.push({ stroke: chord(pts, split === "h" ? 1 : 0), r: 0.3 * R, c: ink0 });
20541
+ return { width: S, height: S, pixelRatio: R, ops };
20542
+ }
20543
+ function classicDrawing(ink, name) {
20544
+ if (name === "flare") return flare(ink);
20545
+ if (name === "disc") return disc(ink);
20546
+ const m = /^(buoy|board-(triangle-up|triangle-down|square|rhombus))-([a-z]+)(?:-([a-z]+)-([hv]))?$/.exec(name);
20547
+ if (!m || !CLASSIC_MARK_NAMES.includes(name)) throw new Error(`classic-marks: no mark ${name}`);
20548
+ const c1 = m[3];
20549
+ const c2 = m[4] ?? m[3];
20550
+ const split = m[5] ?? null;
20551
+ return m[1] === "buoy" ? buoy(ink, c1, c2, split) : board(ink, m[2], c1, c2, split);
20552
+ }
20553
+ function rgba(hex) {
20554
+ return [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16), 255];
20555
+ }
20556
+ function paintDrawing(d) {
20557
+ const p = painter(d.width, d.height);
20558
+ for (const op of d.ops) {
20559
+ if ("fill" in op) p.fill(op.fill, rgba(op.c));
20560
+ else if ("stroke" in op) p.stroke(op.stroke, op.r, rgba(op.c));
20561
+ else p.dot(op.dot[0], op.dot[1], op.r, rgba(op.c));
20562
+ }
20563
+ return p.data();
20564
+ }
20565
+ function drawingSvg(d) {
20566
+ const f = (n) => String(Math.round(n * 100) / 100);
20567
+ const pts = (ps) => ps.map(([x, y]) => `${f(x)},${f(y)}`).join(" ");
20568
+ const body = d.ops.map(
20569
+ (op) => "fill" in op ? `<polygon points="${pts(op.fill)}" fill="${op.c}"/>` : "stroke" in op ? `<polyline points="${pts(op.stroke)}" fill="none" stroke="${op.c}" stroke-width="${f(op.r * 2)}" stroke-linecap="round" stroke-linejoin="round"/>` : `<circle cx="${f(op.dot[0])}" cy="${f(op.dot[1])}" r="${f(op.r)}" fill="${op.c}"/>`
20570
+ ).join("");
20571
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${d.width}" height="${d.height}" viewBox="0 0 ${d.width} ${d.height}">${body}</svg>`;
20572
+ }
20573
+ function classicMarkSvgs(ink) {
20574
+ return CLASSIC_MARK_NAMES.map((name) => {
20575
+ const d = classicDrawing(ink, name);
20576
+ return { id: classicMarkId(ink, name), svg: drawingSvg(d), width: d.width, height: d.height, pixelRatio: d.pixelRatio };
20577
+ });
20578
+ }
20579
+ function classicMarkImage(id) {
20580
+ const ink = classicMarkInk(id);
20581
+ if (!ink) throw new Error(`classic-marks: no mark ${id}`);
20582
+ const d = classicDrawing(ink, id.slice(PREFIX[ink].length));
20583
+ return { id, width: d.width, height: d.height, pixelRatio: d.pixelRatio, data: paintDrawing(d) };
20584
+ }
20585
+ function classicMarkImages(ink) {
20586
+ return CLASSIC_MARK_NAMES.map((name) => classicMarkImage(classicMarkId(ink, name)));
20587
+ }
20588
+
20332
20589
  // src/atlas/symbol-image-specs.ts
20333
20590
  var SUPERSAMPLE = 2;
20334
20591
  var BASE_PATTERN_GLYPHS = [
@@ -20385,9 +20642,30 @@ function s101ImageSpecs(palette) {
20385
20642
  return [{ id, svg: svg2, ...declared(id, svg2), pixelRatio: SUPERSAMPLE, sdf: false }];
20386
20643
  });
20387
20644
  }
20645
+ function usChart1ImageSpecs(palette) {
20646
+ const ink = palette === "EINK_MONO" ? "mono" : "color";
20647
+ return classicMarkSvgs(ink).map((m) => ({ ...m, sdf: false }));
20648
+ }
20388
20649
  function symbolImageSpecs(palette, family) {
20389
- const own = family === "s101" ? s101ImageSpecs(palette) : family === "raster" ? rasterImageSpecs(palette) : family === "chrt" ? chrtImageSpecs(palette) : [];
20390
- return [...s52ImageSpecs(palette), ...basePatternImageSpecs(palette), ...own];
20650
+ return [...s52ImageSpecs(palette), ...basePatternImageSpecs(palette), ...familyOwnImageSpecs(palette, family)];
20651
+ }
20652
+ function familyOwnImageSpecs(palette, family) {
20653
+ switch (family) {
20654
+ case "s52":
20655
+ return [];
20656
+ case "s101":
20657
+ return s101ImageSpecs(palette);
20658
+ case "int1":
20659
+ return rasterImageSpecs(palette);
20660
+ case "uschart1":
20661
+ return [...rasterImageSpecs(palette), ...usChart1ImageSpecs(palette)];
20662
+ case "chrt":
20663
+ return chrtImageSpecs(palette);
20664
+ default: {
20665
+ const unhandled = family;
20666
+ throw new Error(`no symbol family ${String(unhandled)}`);
20667
+ }
20668
+ }
20391
20669
  }
20392
20670
  var IMAGE_PROPS = /* @__PURE__ */ new Set([
20393
20671
  "icon-image",
@@ -20470,6 +20748,380 @@ async function loadChrtRasterSymbolImages(map, colorTable = "DAY") {
20470
20748
  async function reloadChrtRasterSymbolImages(map, colorTable) {
20471
20749
  await rethemeSymbolImages(map, rasterImageSpecs(colorTable));
20472
20750
  }
20751
+
20752
+ // src/atlas/look-paper.ts
20753
+ var CLASSIC_TONES = {
20754
+ /** Land. */
20755
+ land: "#ebe2c8",
20756
+ /** The blue tint, to the 18 ft curve. */
20757
+ shallow: "#d8f0f5",
20758
+ /** Deep water: the paper. */
20759
+ deep: "#ffffff",
20760
+ /** The foreshore, and salt marsh. */
20761
+ drying: "#c1d1af",
20762
+ /** Magenta: lights, flares, discs, limits, cautions, red aids. */
20763
+ magenta: "#953699",
20764
+ /** Green aids. */
20765
+ green: "#068b00",
20766
+ /** Black: line-work, lettering, soundings, land contours. */
20767
+ ink: "#000000",
20768
+ /** Depth contours and their values. */
20769
+ contour: "#5f5f5f"
20770
+ };
20771
+ var CLASSIC_IMAGE_NAMES = ["hatch", ...CLASSIC_MARK_NAMES];
20772
+ var PREFIX2 = "chrt-look-cl-";
20773
+ var DAY_TO_CLASSIC = {
20774
+ // Land: LANDA, CHRTland's land and its cover but wetland, slopes.
20775
+ "#d4c69d": CLASSIC_TONES.land,
20776
+ "#e6d1a1": CLASSIC_TONES.land,
20777
+ "#bcc5a1": CLASSIC_TONES.land,
20778
+ "#cac6bf": CLASSIC_TONES.land,
20779
+ "#dbd0af": CLASSIC_TONES.land,
20780
+ "#c8b078": CLASSIC_TONES.land,
20781
+ // Marsh.
20782
+ "#b6c0b1": CLASSIC_TONES.drying,
20783
+ // The drying foreshore (DEPIT).
20784
+ "#009678": CLASSIC_TONES.drying,
20785
+ // Inland water and the shallow depth tints (DEPVS, DEPMS, DEPMD) where
20786
+ // other classes use them: lakes, rivers, canals, locks, swept areas.
20787
+ "#7fbfdf": CLASSIC_TONES.shallow,
20788
+ "#a7d4e8": CLASSIC_TONES.shallow,
20789
+ "#cae7f3": CLASSIC_TONES.shallow,
20790
+ "#b9cfdd": CLASSIC_TONES.shallow,
20791
+ // Deep water (DEPDW).
20792
+ "#ecf7fc": CLASSIC_TONES.deep,
20793
+ // Magentas (CHMGD, CHMGF).
20794
+ "#d200d2": CLASSIC_TONES.magenta,
20795
+ "#c545c3": CLASSIC_TONES.magenta,
20796
+ // Brown structures (CHBRN): buildings, bridges, dams, in black.
20797
+ "#ab7948": CLASSIC_TONES.ink,
20798
+ // Black and the near-blacks of the lettering.
20799
+ "#000000": CLASSIC_TONES.ink,
20800
+ "#1a1d23": CLASSIC_TONES.ink,
20801
+ "#4a5560": CLASSIC_TONES.ink,
20802
+ "#5b4f3a": CLASSIC_TONES.ink,
20803
+ "#bfa88a": CLASSIC_TONES.ink,
20804
+ // Depth contours and area outlines.
20805
+ "#555555": CLASSIC_TONES.contour,
20806
+ // CHRTland's contours: black, as the paper chart's.
20807
+ "#958666": CLASSIC_TONES.ink,
20808
+ "#78694b": CLASSIC_TONES.ink
20809
+ };
20810
+ var HATCH_RATIO = 4;
20811
+ function hatch() {
20812
+ const d = 12;
20813
+ const w = d * 2;
20814
+ const half2 = 0.9;
20815
+ const data = new Uint8Array(w * w * 4);
20816
+ for (let y = 0; y < w; y++) {
20817
+ for (let x = 0; x < w; x++) {
20818
+ const t = (x + y + 1) % d;
20819
+ const dist = Math.min(t, d - t) / Math.SQRT2;
20820
+ const cov = Math.max(0, Math.min(1, half2 + 0.5 - dist));
20821
+ data[(y * w + x) * 4 + 3] = Math.round(cov * 255);
20822
+ }
20823
+ }
20824
+ return { size: w, data };
20825
+ }
20826
+ function classicImages() {
20827
+ const h = hatch();
20828
+ return [
20829
+ { name: "hatch", width: h.size, height: h.size, pixelRatio: HATCH_RATIO, data: h.data },
20830
+ ...classicMarkImages("color").map((i) => ({ name: i.id.slice(PREFIX2.length), width: i.width, height: i.height, pixelRatio: i.pixelRatio, data: i.data }))
20831
+ ];
20832
+ }
20833
+
20834
+ // src/atlas/look-wash-tones.ts
20835
+ var WASH_TONES = {
20836
+ paper: [250, 244, 222],
20837
+ land: [165, 186, 118],
20838
+ // A clear light blue against the shore (owner, 2026-11-02): the 1860 sheet's grey-blue read grey-green on the cream.
20839
+ water: [128, 178, 222],
20840
+ flat: [226, 206, 150],
20841
+ town: [186, 72, 52],
20842
+ road: [192, 124, 72]
20843
+ };
20844
+ function washOver(under, tone, a) {
20845
+ const k = Math.max(0, Math.min(1, a));
20846
+ return [0, 1, 2].map((i) => under[i] * (1 - k * (1 - tone[i] / 255)));
20847
+ }
20848
+ function rgbHex(rgb) {
20849
+ return `#${rgb.map((v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0")).join("")}`;
20850
+ }
20851
+ var WASH_TINTS = (() => {
20852
+ const paper = WASH_TONES.paper;
20853
+ const land = washOver(paper, WASH_TONES.land, 0.6);
20854
+ return {
20855
+ paper: rgbHex(paper),
20856
+ land: rgbHex(land),
20857
+ /** Water to the 18 ft curve. */
20858
+ shallow: rgbHex(washOver(paper, WASH_TONES.water, 0.4)),
20859
+ /** A pond or lake. */
20860
+ lake: rgbHex(washOver(paper, WASH_TONES.water, 0.26)),
20861
+ /** Drying flats. */
20862
+ flat: rgbHex(washOver(paper, WASH_TONES.flat, 0.375)),
20863
+ /** A town, laid over the land. */
20864
+ town: rgbHex(washOver(land, WASH_TONES.town, 0.42)),
20865
+ /** A road's core, over the land. */
20866
+ road: rgbHex(washOver(land, WASH_TONES.road, 0.45))
20867
+ };
20868
+ })();
20869
+
20870
+ // src/atlas/chart-look.ts
20871
+ var LOOK_TONES = {
20872
+ // Black on white: the sheet prints in black alone (DeviceGray).
20873
+ engraved: { ink: "#000000", paper: "#ffffff" },
20874
+ // The 1860 sheet's ink, a warm black (#382d20, sampled), on white; the wash,
20875
+ // multiplied over it, tones the paper and colours the land and water
20876
+ // (look-wash-tones.ts WASH_TONES).
20877
+ handcolored: { ink: "#382d20", paper: "#ffffff" }
20878
+ };
20879
+ var LOOK_IMAGE_NAMES = [
20880
+ "stipple-flats",
20881
+ "stipple-1fm",
20882
+ "stipple-2fm",
20883
+ "stipple-3fm",
20884
+ "marsh",
20885
+ "woods",
20886
+ // The Survey's symbols (lookSymbols).
20887
+ "buoy-nun-red",
20888
+ "buoy-nun-green",
20889
+ "buoy-nun-black",
20890
+ "buoy-nun-yellow",
20891
+ "buoy-can-red",
20892
+ "buoy-can-green",
20893
+ "buoy-can-black",
20894
+ "buoy-can-yellow",
20895
+ "buoy-spar-red",
20896
+ "buoy-spar-green",
20897
+ "buoy-spar-black",
20898
+ "buoy-spar-yellow",
20899
+ "buoy-other-red",
20900
+ "buoy-other-green",
20901
+ "buoy-other-black",
20902
+ "buoy-other-yellow",
20903
+ "beacon",
20904
+ "light",
20905
+ "light-major",
20906
+ "lightship",
20907
+ "landmark",
20908
+ "anchor",
20909
+ "fog"
20910
+ ];
20911
+ var IMAGE_PREFIX = { engraved: "chrt-look-en-", handcolored: "chrt-look-hc-", paper: "chrt-look-cl-" };
20912
+ function lookImageId(look, name) {
20913
+ return IMAGE_PREFIX[look] + name;
20914
+ }
20915
+ function imageNames(look) {
20916
+ return look === "paper" ? CLASSIC_IMAGE_NAMES : LOOK_IMAGE_NAMES;
20917
+ }
20918
+ function lookOfImageId(id) {
20919
+ for (const look of Object.keys(IMAGE_PREFIX)) {
20920
+ if (id.startsWith(IMAGE_PREFIX[look]) && imageNames(look).includes(id.slice(IMAGE_PREFIX[look].length))) return look;
20921
+ }
20922
+ return null;
20923
+ }
20924
+ var PAINT = {
20925
+ red: [184, 69, 47, 255],
20926
+ green: [79, 122, 58, 255],
20927
+ yellow: [214, 176, 72, 255],
20928
+ light: [232, 196, 92, 210]
20929
+ };
20930
+ function lookSymbols(look, ink) {
20931
+ const R2 = 2;
20932
+ const S2 = 64 * R2;
20933
+ const c0 = S2 / 2;
20934
+ const out = [];
20935
+ const coloured = look === "handcolored";
20936
+ const tilt = 28;
20937
+ const line = 0.75 * R2;
20938
+ const B = 1.55;
20939
+ const shapes = {
20940
+ nun: [[0, 0], [-3.2, -6], [0, -16], [3.2, -6]],
20941
+ can: [[-3.4, 0], [-3.4, -9], [3.4, -9], [3.4, 0]],
20942
+ spar: [[-0.9, 0], [-0.9, -16], [0.9, -16], [0.9, 0]],
20943
+ other: Array.from({ length: 20 }, (_, i) => [4.2 * Math.sin(i / 20 * 2 * Math.PI), -5 - 4.6 * Math.cos(i / 20 * 2 * Math.PI)])
20944
+ };
20945
+ for (const shape of ["nun", "can", "spar", "other"]) {
20946
+ for (const colour of ["red", "green", "black", "yellow"]) {
20947
+ const p = painter(S2, S2);
20948
+ const pts = shapes[shape].map(([x, y]) => turn([c0 + x * B * R2, c0 + y * B * R2], c0, c0, tilt));
20949
+ const solid = colour === "black" || colour === "green";
20950
+ if (coloured) p.fill(pts, colour === "black" ? ink : PAINT[colour]);
20951
+ else if (solid) p.fill(pts, ink);
20952
+ p.stroke([...pts, pts[0]], line / 2, ink);
20953
+ p.dot(c0, c0, 1.1 * R2, ink);
20954
+ out.push({ name: `buoy-${shape}-${colour}`, data: p.data(), size: S2 });
20955
+ }
20956
+ }
20957
+ {
20958
+ const p = painter(S2, S2);
20959
+ p.stroke([[c0, c0], [c0, c0 - 22 * R2]], 0.6 * R2, ink);
20960
+ p.dot(c0, c0 - 22 * R2, 2.2 * R2, ink);
20961
+ p.dot(c0, c0, 1.2 * R2, ink);
20962
+ out.push({ name: "beacon", data: p.data(), size: S2 });
20963
+ }
20964
+ for (const [name, r, rays] of [["light", 13, 12], ["light-major", 18, 16]]) {
20965
+ const p = painter(S2, S2);
20966
+ if (coloured) p.dot(c0, c0, r * 0.75 * R2, PAINT.light);
20967
+ for (let i = 0; i < rays; i++) {
20968
+ const a = i / rays * 2 * Math.PI;
20969
+ const len = i % 2 === 0 ? r : r * 0.62;
20970
+ p.stroke([[c0 + Math.cos(a) * 3 * R2, c0 + Math.sin(a) * 3 * R2], [c0 + Math.cos(a) * len * R2, c0 + Math.sin(a) * len * R2]], 0.38 * R2, ink);
20971
+ }
20972
+ p.dot(c0, c0, 2.8 * R2, ink);
20973
+ out.push({ name, data: p.data(), size: S2 });
20974
+ }
20975
+ {
20976
+ const p = painter(S2, S2);
20977
+ const hull = [[-8, 0], [8, 0], [5.5, 3.2], [-5.5, 3.2]].map(([x, y]) => [c0 + x * R2, c0 + y * R2]);
20978
+ p.fill(hull, coloured ? PAINT.red : ink);
20979
+ p.stroke([...hull, hull[0]], 0.35 * R2, ink);
20980
+ p.stroke([[c0, c0], [c0, c0 - 11 * R2]], 0.45 * R2, ink);
20981
+ for (let i = 0; i < 8; i++) {
20982
+ const a = i / 8 * 2 * Math.PI;
20983
+ p.stroke([[c0, c0 - 11 * R2], [c0 + Math.cos(a) * 3.6 * R2, c0 - 11 * R2 + Math.sin(a) * 3.6 * R2]], 0.28 * R2, ink);
20984
+ }
20985
+ out.push({ name: "lightship", data: p.data(), size: S2 });
20986
+ }
20987
+ {
20988
+ const p = painter(S2, S2);
20989
+ const ring = Array.from({ length: 33 }, (_, i) => [c0 + 4.6 * R2 * Math.cos(i / 32 * 2 * Math.PI), c0 + 4.6 * R2 * Math.sin(i / 32 * 2 * Math.PI)]);
20990
+ p.stroke(ring, 0.45 * R2, ink);
20991
+ p.dot(c0, c0, 1.2 * R2, ink);
20992
+ out.push({ name: "landmark", data: p.data(), size: S2 });
20993
+ }
20994
+ {
20995
+ const p = painter(S2, S2);
20996
+ const y0 = c0 - 7 * R2;
20997
+ p.stroke([[c0, y0], [c0, c0 + 7 * R2]], 0.5 * R2, ink);
20998
+ p.stroke([[c0 - 3.5 * R2, y0 + 2.2 * R2], [c0 + 3.5 * R2, y0 + 2.2 * R2]], 0.45 * R2, ink);
20999
+ const ring = Array.from({ length: 17 }, (_, i) => [c0 + 1.3 * R2 * Math.cos(i / 16 * 2 * Math.PI), y0 - 1.3 * R2 + 1.3 * R2 * Math.sin(i / 16 * 2 * Math.PI)]);
21000
+ p.stroke(ring, 0.35 * R2, ink);
21001
+ const arm = Array.from({ length: 13 }, (_, i) => {
21002
+ const a = Math.PI * (0.15 + 0.7 * (i / 12));
21003
+ return [c0 + 5.5 * R2 * Math.cos(a), c0 + 1.5 * R2 + 5.5 * R2 * Math.sin(a)];
21004
+ });
21005
+ p.stroke(arm, 0.5 * R2, ink);
21006
+ p.stroke([arm[0], [arm[0][0] + 1.6 * R2, arm[0][1] - 1.4 * R2]], 0.45 * R2, ink);
21007
+ p.stroke([arm[12], [arm[12][0] - 1.6 * R2, arm[12][1] - 1.4 * R2]], 0.45 * R2, ink);
21008
+ out.push({ name: "anchor", data: p.data(), size: S2 });
21009
+ }
21010
+ {
21011
+ const p = painter(S2, S2);
21012
+ for (const r of [6, 9, 12]) {
21013
+ const arc = Array.from({ length: 13 }, (_, i) => {
21014
+ const a = (-115 + 50 * i / 12) * (Math.PI / 180);
21015
+ return [c0 + r * R2 * Math.cos(a), c0 + r * R2 * Math.sin(a)];
21016
+ });
21017
+ p.stroke(arc, 0.42 * R2, ink);
21018
+ }
21019
+ out.push({ name: "fog", data: p.data(), size: S2 });
21020
+ }
21021
+ return out;
21022
+ }
21023
+ var IMAGE_RATIO = 4;
21024
+ function hash(a, b, seed) {
21025
+ let h = a * 374761393 + b * 668265263 + seed * 2147483647 | 0;
21026
+ h = Math.imul(h ^ h >>> 13, 1274126177);
21027
+ return ((h ^ h >>> 16) >>> 0) / 4294967296;
21028
+ }
21029
+ function canvas(w, h) {
21030
+ const data = new Uint8Array(w * h * 4);
21031
+ const put = (x, y, a) => {
21032
+ const xi = (x % w + w) % w;
21033
+ const yi = (y % h + h) % h;
21034
+ const k = (yi * w + xi) * 4 + 3;
21035
+ data[k] = Math.min(255, Math.max(data[k], Math.round(a * 255)));
21036
+ };
21037
+ const dot = (cx, cy, r, a = 1) => {
21038
+ for (let y = Math.floor(cy - r - 1); y <= Math.ceil(cy + r + 1); y++) {
21039
+ for (let x = Math.floor(cx - r - 1); x <= Math.ceil(cx + r + 1); x++) {
21040
+ const d = Math.hypot(x + 0.5 - cx, y + 0.5 - cy);
21041
+ const cov = Math.max(0, Math.min(1, r + 0.5 - d));
21042
+ if (cov > 0) put(x, y, cov * a);
21043
+ }
21044
+ }
21045
+ };
21046
+ const line = (x0, y0, x1, y1, r) => {
21047
+ const n = Math.max(1, Math.ceil(Math.hypot(x1 - x0, y1 - y0) * 2));
21048
+ for (let i = 0; i <= n; i++) dot(x0 + (x1 - x0) * i / n, y0 + (y1 - y0) * i / n, r);
21049
+ };
21050
+ return { data, dot, line };
21051
+ }
21052
+ function lookImages(look) {
21053
+ if (look === "paper") return classicImages().map((i) => ({ ...i, id: lookImageId("paper", i.name) }));
21054
+ const [ir, ig, ib] = [1, 3, 5].map((i) => parseInt(LOOK_TONES[look].ink.slice(i, i + 2), 16));
21055
+ const finish = (name, w, h, data) => {
21056
+ for (let k = 0; k < data.length; k += 4) {
21057
+ data[k] = ir;
21058
+ data[k + 1] = ig;
21059
+ data[k + 2] = ib;
21060
+ }
21061
+ return { id: lookImageId(look, name), width: w, height: h, pixelRatio: IMAGE_RATIO, data };
21062
+ };
21063
+ const out = [];
21064
+ for (const [id, step, r, seed] of [
21065
+ ["stipple-flats", 5, 0.95, 1],
21066
+ ["stipple-1fm", 6, 0.9, 2],
21067
+ ["stipple-2fm", 8, 0.85, 3],
21068
+ ["stipple-3fm", 11, 0.8, 4]
21069
+ ]) {
21070
+ const n = 8;
21071
+ const w = step * n;
21072
+ const c = canvas(w, w);
21073
+ for (let j = 0; j < n; j++) for (let i = 0; i < n; i++) {
21074
+ c.dot((i + 0.2 + 0.6 * hash(i, j, seed)) * step, (j + 0.2 + 0.6 * hash(j, i, seed + 7)) * step, r * (0.8 + 0.4 * hash(i, j, seed + 3)));
21075
+ }
21076
+ out.push(finish(id, w, w, c.data));
21077
+ }
21078
+ {
21079
+ const w = 96;
21080
+ const h = 64;
21081
+ const c = canvas(w, h);
21082
+ for (const [x, y] of [[16, 22], [64, 22], [40, 54], [88, 54]]) {
21083
+ c.line(x - 9, y, x + 9, y, 0.55);
21084
+ c.line(x, y, x, y - 9, 0.5);
21085
+ c.line(x - 3, y, x - 7, y - 7, 0.45);
21086
+ c.line(x + 3, y, x + 7, y - 7, 0.45);
21087
+ }
21088
+ out.push(finish("marsh", w, h, c.data));
21089
+ }
21090
+ {
21091
+ const n = 6;
21092
+ const step = 12;
21093
+ const w = n * step;
21094
+ const c = canvas(w, w);
21095
+ for (let j = 0; j < n; j++) for (let i = 0; i < n; i++) {
21096
+ const x = (i + 0.25 + 0.5 * hash(i, j, 31)) * step;
21097
+ const y = (j + 0.25 + 0.5 * hash(j, i, 37)) * step;
21098
+ for (let a = 0; a < 2 * Math.PI; a += 0.25) c.dot(x + 2.4 * Math.cos(a), y + 2.4 * Math.sin(a), 0.4);
21099
+ c.line(x + 1.5, y + 3, x + 3, y + 2.4, 0.55);
21100
+ }
21101
+ out.push(finish("woods", w, w, c.data));
21102
+ }
21103
+ for (const sym of lookSymbols(look, [ir, ig, ib, 255])) {
21104
+ out.push({ id: lookImageId(look, sym.name), width: sym.size, height: sym.size, pixelRatio: 2, data: sym.data });
21105
+ }
21106
+ return out;
21107
+ }
21108
+
21109
+ // src/atlas/chart-look-images-browser.ts
21110
+ var IMAGES = /* @__PURE__ */ new Map();
21111
+ function provideChartLookImages(map) {
21112
+ map.on("styleimagemissing", (e) => {
21113
+ const mark = classicMarkInk(e.id) !== null;
21114
+ const look = mark ? null : lookOfImageId(e.id);
21115
+ if (!mark && look === null || map.hasImage(e.id)) return;
21116
+ if (!IMAGES.has(e.id)) {
21117
+ if (mark) IMAGES.set(e.id, classicMarkImage(e.id));
21118
+ else for (const image2 of lookImages(look)) IMAGES.set(image2.id, image2);
21119
+ }
21120
+ const image = IMAGES.get(e.id);
21121
+ if (!image) return;
21122
+ map.addImage(e.id, { width: image.width, height: image.height, data: new Uint8Array(image.data) }, { pixelRatio: image.pixelRatio });
21123
+ });
21124
+ }
20473
21125
  export {
20474
21126
  BASE_PATTERN_GLYPHS,
20475
21127
  basePatternImageSpecs,
@@ -20485,6 +21137,7 @@ export {
20485
21137
  loadSymbolImageSpecs,
20486
21138
  loadSymbolImages,
20487
21139
  loadThemedBridgeImages,
21140
+ provideChartLookImages,
20488
21141
  rasterImageSpecs,
20489
21142
  reloadChrtRasterSymbolImages,
20490
21143
  reloadS101SymbolImages,
@@ -20494,6 +21147,7 @@ export {
20494
21147
  s101ImageSpecs,
20495
21148
  s52ImageSpecs,
20496
21149
  styleImageIds,
20497
- symbolImageSpecs
21150
+ symbolImageSpecs,
21151
+ usChart1ImageSpecs
20498
21152
  };
20499
21153
  //# sourceMappingURL=browser.js.map