@chrtco/sdk 0.10.53 → 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.
@@ -34,6 +34,7 @@ __export(browser_exports, {
34
34
  loadSymbolImageSpecs: () => loadSymbolImageSpecs,
35
35
  loadSymbolImages: () => loadSymbolImages,
36
36
  loadThemedBridgeImages: () => loadThemedBridgeImages,
37
+ provideChartLookImages: () => provideChartLookImages,
37
38
  rasterImageSpecs: () => rasterImageSpecs,
38
39
  reloadChrtRasterSymbolImages: () => reloadChrtRasterSymbolImages,
39
40
  reloadS101SymbolImages: () => reloadS101SymbolImages,
@@ -43,7 +44,8 @@ __export(browser_exports, {
43
44
  s101ImageSpecs: () => s101ImageSpecs,
44
45
  s52ImageSpecs: () => s52ImageSpecs,
45
46
  styleImageIds: () => styleImageIds,
46
- symbolImageSpecs: () => symbolImageSpecs
47
+ symbolImageSpecs: () => symbolImageSpecs,
48
+ usChart1ImageSpecs: () => usChart1ImageSpecs
47
49
  });
48
50
  module.exports = __toCommonJS(browser_exports);
49
51
 
@@ -18866,9 +18868,9 @@ function arcSegmentSvg(token, sweepDeg) {
18866
18868
  const box = segmentBox(sweepDeg);
18867
18869
  const end = sweepDeg + JOINT_OVERLAP_DEG;
18868
18870
  const core = token === "CHBRN" ? OBSCURED_CORE_WIDTH : CORE_WIDTH;
18869
- const R = SECTOR_ARC_RADIUS;
18870
- const outline = annularSectorPath(end, R - OUTLINE_WIDTH / 2, R + OUTLINE_WIDTH / 2, box);
18871
- const inner = annularSectorPath(end, R - core / 2, R + core / 2, box);
18871
+ const R2 = SECTOR_ARC_RADIUS;
18872
+ const outline = annularSectorPath(end, R2 - OUTLINE_WIDTH / 2, R2 + OUTLINE_WIDTH / 2, box);
18873
+ const inner = annularSectorPath(end, R2 - core / 2, R2 + core / 2, box);
18872
18874
  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>`;
18873
18875
  }
18874
18876
  function legSvg() {
@@ -19020,17 +19022,17 @@ async function decode(spec) {
19020
19022
  var scratch = null;
19021
19023
  function scratchContext() {
19022
19024
  if (!scratch) {
19023
- const canvas = document.createElement("canvas");
19024
- scratch = canvas.getContext("2d", { willReadFrequently: true });
19025
+ const canvas2 = document.createElement("canvas");
19026
+ scratch = canvas2.getContext("2d", { willReadFrequently: true });
19025
19027
  if (!scratch) throw new Error("symbol-images: no 2d canvas context");
19026
19028
  }
19027
19029
  return scratch;
19028
19030
  }
19029
19031
  function rasterise(src, spec) {
19030
19032
  const ctx = scratchContext();
19031
- const canvas = ctx.canvas;
19032
- canvas.width = spec.width;
19033
- canvas.height = spec.height;
19033
+ const canvas2 = ctx.canvas;
19034
+ canvas2.width = spec.width;
19035
+ canvas2.height = spec.height;
19034
19036
  ctx.drawImage(src.img, 0, -src.y, src.width, src.height);
19035
19037
  return ctx.getImageData(0, 0, spec.width, spec.height);
19036
19038
  }
@@ -19380,13 +19382,13 @@ function decodeSvgToImage(themedSvg, size) {
19380
19382
  }
19381
19383
  async function imageToBitmap(img, size) {
19382
19384
  try {
19383
- const canvas = document.createElement("canvas");
19384
- canvas.width = size.w;
19385
- canvas.height = size.h;
19386
- const ctx = canvas.getContext("2d");
19385
+ const canvas2 = document.createElement("canvas");
19386
+ canvas2.width = size.w;
19387
+ canvas2.height = size.h;
19388
+ const ctx = canvas2.getContext("2d");
19387
19389
  if (!ctx) return null;
19388
19390
  ctx.drawImage(img, 0, 0, size.w, size.h);
19389
- return await createImageBitmap(canvas);
19391
+ return await createImageBitmap(canvas2);
19390
19392
  } catch {
19391
19393
  return null;
19392
19394
  }
@@ -20378,6 +20380,263 @@ function getThemedS101Svg(symbolName, table = "DAY") {
20378
20380
  });
20379
20381
  }
20380
20382
 
20383
+ // src/atlas/look-painter.ts
20384
+ function painter(w, h) {
20385
+ const acc = new Float32Array(w * h * 4);
20386
+ const over = (x, y, c, cov) => {
20387
+ if (x < 0 || y < 0 || x >= w || y >= h || cov <= 0) return;
20388
+ const k = (y * w + x) * 4;
20389
+ const a = c[3] / 255 * Math.min(1, cov);
20390
+ acc[k] = c[0] * a + acc[k] * (1 - a);
20391
+ acc[k + 1] = c[1] * a + acc[k + 1] * (1 - a);
20392
+ acc[k + 2] = c[2] * a + acc[k + 2] * (1 - a);
20393
+ acc[k + 3] = a + acc[k + 3] * (1 - a);
20394
+ };
20395
+ const dot = (cx, cy, r, c) => {
20396
+ for (let y = Math.floor(cy - r - 1); y <= Math.ceil(cy + r + 1); y++) {
20397
+ 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));
20398
+ }
20399
+ };
20400
+ const stroke = (pts, r, c) => {
20401
+ const cov = new Float32Array(w * h);
20402
+ for (let i = 1; i < pts.length; i++) {
20403
+ const [x0, y0] = pts[i - 1];
20404
+ const [x1, y1] = pts[i];
20405
+ const n = Math.max(1, Math.ceil(Math.hypot(x1 - x0, y1 - y0) * 2));
20406
+ for (let t = 0; t <= n; t++) {
20407
+ const cx = x0 + (x1 - x0) * t / n;
20408
+ const cy = y0 + (y1 - y0) * t / n;
20409
+ for (let y = Math.floor(cy - r - 1); y <= Math.ceil(cy + r + 1); y++) {
20410
+ for (let x = Math.floor(cx - r - 1); x <= Math.ceil(cx + r + 1); x++) {
20411
+ if (x < 0 || y < 0 || x >= w || y >= h) continue;
20412
+ const v = Math.max(0, Math.min(1, r + 0.5 - Math.hypot(x + 0.5 - cx, y + 0.5 - cy)));
20413
+ if (v > cov[y * w + x]) cov[y * w + x] = v;
20414
+ }
20415
+ }
20416
+ }
20417
+ }
20418
+ for (let k = 0; k < cov.length; k++) if (cov[k] > 0) over(k % w, Math.floor(k / w), c, cov[k]);
20419
+ };
20420
+ const fill = (pts, c) => {
20421
+ const y0 = Math.max(0, Math.floor(Math.min(...pts.map((p) => p[1]))));
20422
+ const y1 = Math.min(h - 1, Math.ceil(Math.max(...pts.map((p) => p[1]))));
20423
+ const x0 = Math.max(0, Math.floor(Math.min(...pts.map((p) => p[0]))));
20424
+ const x1 = Math.min(w - 1, Math.ceil(Math.max(...pts.map((p) => p[0]))));
20425
+ for (let y = y0; y <= y1; y++) {
20426
+ for (let x = x0; x <= x1; x++) {
20427
+ let inside = 0;
20428
+ for (let sy = 0; sy < 4; sy++) for (let sx = 0; sx < 4; sx++) {
20429
+ const px = x + (sx + 0.5) / 4;
20430
+ const py = y + (sy + 0.5) / 4;
20431
+ let odd = false;
20432
+ for (let i = 0, j = pts.length - 1; i < pts.length; j = i++) {
20433
+ const [xi, yi] = pts[i];
20434
+ const [xj, yj] = pts[j];
20435
+ if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi) odd = !odd;
20436
+ }
20437
+ if (odd) inside++;
20438
+ }
20439
+ over(x, y, c, inside / 16);
20440
+ }
20441
+ }
20442
+ };
20443
+ const data = () => {
20444
+ const out = new Uint8Array(w * h * 4);
20445
+ for (let k = 0; k < w * h; k++) {
20446
+ const a = acc[k * 4 + 3];
20447
+ if (a <= 0) continue;
20448
+ out[k * 4] = Math.round(acc[k * 4] / a);
20449
+ out[k * 4 + 1] = Math.round(acc[k * 4 + 1] / a);
20450
+ out[k * 4 + 2] = Math.round(acc[k * 4 + 2] / a);
20451
+ out[k * 4 + 3] = Math.round(a * 255);
20452
+ }
20453
+ return out;
20454
+ };
20455
+ return { dot, stroke, fill, data };
20456
+ }
20457
+ function turn([x, y], cx, cy, deg) {
20458
+ const r = deg * Math.PI / 180;
20459
+ const dx = x - cx;
20460
+ const dy = y - cy;
20461
+ return [cx + dx * Math.cos(r) - dy * Math.sin(r), cy + dx * Math.sin(r) + dy * Math.cos(r)];
20462
+ }
20463
+
20464
+ // src/atlas/uschart1-marks.ts
20465
+ var CLASSIC_MARK_TONES = {
20466
+ color: { magenta: "#953699", green: "#068b00", ink: "#000000", open: "#ffffff" },
20467
+ // A laser printer's greys: red lighter than green, so a banded mark still
20468
+ // shows its bands. The label (R, G) says which is which, as it always does.
20469
+ mono: { magenta: "#8c8c8c", green: "#4d4d4d", ink: "#000000", open: "#ffffff" }
20470
+ };
20471
+ var PREFIX = { color: "chrt-look-cl-", mono: "chrt-look-cm-" };
20472
+ function classicMarkId(ink, name) {
20473
+ return PREFIX[ink] + name;
20474
+ }
20475
+ function classicMarkInk(id) {
20476
+ for (const ink of ["color", "mono"]) {
20477
+ if (id.startsWith(PREFIX[ink]) && CLASSIC_MARK_NAMES.includes(id.slice(PREFIX[ink].length))) return ink;
20478
+ }
20479
+ return null;
20480
+ }
20481
+ var COLOURS = ["red", "green", "black", "yellow", "white"];
20482
+ var BOARDS = ["triangle-up", "triangle-down", "square", "rhombus"];
20483
+ var paints = COLOURS.flatMap((a) => [
20484
+ a,
20485
+ ...COLOURS.filter((b) => b !== a).flatMap((b) => [`${a}-${b}-h`, `${a}-${b}-v`])
20486
+ ]);
20487
+ var BUOY_NAMES = paints.map((p) => `buoy-${p}`);
20488
+ var BOARD_NAMES = BOARDS.flatMap((s) => paints.map((p) => `board-${s}-${p}`));
20489
+ var CLASSIC_MARK_NAMES = ["flare", "disc", ...BUOY_NAMES, ...BOARD_NAMES];
20490
+ var num = (attr) => ["to-number", ["coalesce", ["get", attr], ["get", attr.toLowerCase()], 0], 0];
20491
+ var LOZENGE_BUOY = ["!", ["in", num("BOYSHP"), ["literal", [7, 8]]]];
20492
+ var DAYBEACON = ["!", ["in", num("BCNSHP"), ["literal", [3, 4, 6]]]];
20493
+ var R = 2;
20494
+ var S = 64 * R;
20495
+ var C0 = S / 2;
20496
+ var BUOY_LENGTH = 12.5;
20497
+ var BUOY_HALF_WIDTH = 3.4;
20498
+ var DISC_RADIUS = 8.5;
20499
+ var BOARD_SIDE = 8;
20500
+ var SB = 96 * R;
20501
+ var CB = SB / 2;
20502
+ var FLARE_SCALE = 0.6;
20503
+ var FLARE_ANCHOR = 18;
20504
+ function paintOf(ink, c) {
20505
+ const t = CLASSIC_MARK_TONES[ink];
20506
+ return c === "red" ? t.magenta : c === "green" ? t.green : c === "black" ? t.ink : t.open;
20507
+ }
20508
+ function circle(cx, cy, r) {
20509
+ return Array.from({ length: 33 }, (_, i) => [cx + r * Math.cos(i / 32 * 2 * Math.PI), cy + r * Math.sin(i / 32 * 2 * Math.PI)]);
20510
+ }
20511
+ function flare(ink) {
20512
+ 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]];
20513
+ const k = 0.9698;
20514
+ const place = ([x, y]) => {
20515
+ const [rx, ry] = turn([(x - 16.3) * 0.9 * FLARE_SCALE, (y - 28) * 0.9 * FLARE_SCALE], 0, 0, 135);
20516
+ return [((rx + 10 - 16.1) * k + 16) * 2 * R, ((ry + 10 - 14.95) * k + 16) * 2 * R];
20517
+ };
20518
+ const t = CLASSIC_MARK_TONES[ink];
20519
+ 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 }] };
20520
+ }
20521
+ function disc(ink) {
20522
+ return { width: S, height: S, pixelRatio: R, ops: [{ fill: circle(C0, C0, DISC_RADIUS * R), c: CLASSIC_MARK_TONES[ink].magenta }] };
20523
+ }
20524
+ function buoy(ink, c1, c2, split) {
20525
+ const ops = [];
20526
+ const t = CLASSIC_MARK_TONES[ink];
20527
+ const L = BUOY_LENGTH;
20528
+ const W = BUOY_HALF_WIDTH;
20529
+ const lean = 45;
20530
+ const at = (a, b) => turn([CB + b * R, CB - a * R], CB, CB, lean);
20531
+ const foot = 1.6;
20532
+ const outline = [at(foot, 0), at(foot + L / 2, -W), at(foot + L, 0), at(foot + L / 2, W)];
20533
+ if (split === null) ops.push({ fill: outline, c: paintOf(ink, c1) });
20534
+ else if (split === "h") {
20535
+ ops.push({ fill: [at(foot, 0), at(foot + L / 2, -W), at(foot + L / 2, W)], c: paintOf(ink, c2) });
20536
+ ops.push({ fill: [at(foot + L / 2, -W), at(foot + L, 0), at(foot + L / 2, W)], c: paintOf(ink, c1) });
20537
+ } else {
20538
+ ops.push({ fill: [at(foot, 0), at(foot + L / 2, -W), at(foot + L, 0)], c: paintOf(ink, c1) });
20539
+ ops.push({ fill: [at(foot, 0), at(foot + L, 0), at(foot + L / 2, W)], c: paintOf(ink, c2) });
20540
+ }
20541
+ ops.push({ stroke: [...outline, outline[0]], r: 0.35 * R, c: t.ink });
20542
+ if (split === "v") ops.push({ stroke: [at(foot, 0), at(foot + L, 0)], r: 0.3 * R, c: t.ink });
20543
+ if (split === "h") ops.push({ stroke: [at(foot + L / 2, -W), at(foot + L / 2, W)], r: 0.3 * R, c: t.ink });
20544
+ const ring = circle(CB, CB, 2 * R);
20545
+ ops.push({ fill: ring, c: t.open });
20546
+ ops.push({ stroke: ring, r: 0.35 * R, c: t.ink });
20547
+ return { width: SB, height: SB, pixelRatio: R, ops };
20548
+ }
20549
+ function boardOutline(shape) {
20550
+ const h = BOARD_SIDE / 2 * R;
20551
+ switch (shape) {
20552
+ case "triangle-up":
20553
+ return [[C0 - h, C0 + h * 0.58], [C0 + h, C0 + h * 0.58], [C0, C0 - h * 1.15]];
20554
+ case "triangle-down":
20555
+ return [[C0 - h, C0 - h * 0.58], [C0, C0 + h * 1.15], [C0 + h, C0 - h * 0.58]];
20556
+ case "square":
20557
+ 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]];
20558
+ case "rhombus":
20559
+ return [[C0, C0 - h * 1.2], [C0 + h * 1.2, C0], [C0, C0 + h * 1.2], [C0 - h * 1.2, C0]];
20560
+ }
20561
+ }
20562
+ function half(pts, axis, first) {
20563
+ const inside = (p) => first ? p[axis] <= C0 : p[axis] >= C0;
20564
+ const out = [];
20565
+ for (let i = 0; i < pts.length; i++) {
20566
+ const a = pts[i];
20567
+ const b = pts[(i + 1) % pts.length];
20568
+ if (inside(a)) out.push(a);
20569
+ if (inside(a) !== inside(b)) {
20570
+ const t = (C0 - a[axis]) / (b[axis] - a[axis]);
20571
+ out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);
20572
+ }
20573
+ }
20574
+ return out;
20575
+ }
20576
+ function chord(pts, axis) {
20577
+ const top = half(pts, axis, true);
20578
+ return top.filter((p) => Math.abs(p[axis] - C0) < 1e-9);
20579
+ }
20580
+ function board(ink, shape, c1, c2, split) {
20581
+ const pts = boardOutline(shape);
20582
+ const ops = [];
20583
+ if (split === null) ops.push({ fill: pts, c: paintOf(ink, c1) });
20584
+ else {
20585
+ const axis = split === "h" ? 1 : 0;
20586
+ ops.push({ fill: half(pts, axis, true), c: paintOf(ink, c1) });
20587
+ ops.push({ fill: half(pts, axis, false), c: paintOf(ink, c2) });
20588
+ }
20589
+ const ink0 = CLASSIC_MARK_TONES[ink].ink;
20590
+ ops.push({ stroke: [...pts, pts[0]], r: 0.45 * R, c: ink0 });
20591
+ if (split !== null) ops.push({ stroke: chord(pts, split === "h" ? 1 : 0), r: 0.3 * R, c: ink0 });
20592
+ return { width: S, height: S, pixelRatio: R, ops };
20593
+ }
20594
+ function classicDrawing(ink, name) {
20595
+ if (name === "flare") return flare(ink);
20596
+ if (name === "disc") return disc(ink);
20597
+ const m = /^(buoy|board-(triangle-up|triangle-down|square|rhombus))-([a-z]+)(?:-([a-z]+)-([hv]))?$/.exec(name);
20598
+ if (!m || !CLASSIC_MARK_NAMES.includes(name)) throw new Error(`classic-marks: no mark ${name}`);
20599
+ const c1 = m[3];
20600
+ const c2 = m[4] ?? m[3];
20601
+ const split = m[5] ?? null;
20602
+ return m[1] === "buoy" ? buoy(ink, c1, c2, split) : board(ink, m[2], c1, c2, split);
20603
+ }
20604
+ function rgba(hex) {
20605
+ return [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16), 255];
20606
+ }
20607
+ function paintDrawing(d) {
20608
+ const p = painter(d.width, d.height);
20609
+ for (const op of d.ops) {
20610
+ if ("fill" in op) p.fill(op.fill, rgba(op.c));
20611
+ else if ("stroke" in op) p.stroke(op.stroke, op.r, rgba(op.c));
20612
+ else p.dot(op.dot[0], op.dot[1], op.r, rgba(op.c));
20613
+ }
20614
+ return p.data();
20615
+ }
20616
+ function drawingSvg(d) {
20617
+ const f = (n) => String(Math.round(n * 100) / 100);
20618
+ const pts = (ps) => ps.map(([x, y]) => `${f(x)},${f(y)}`).join(" ");
20619
+ const body = d.ops.map(
20620
+ (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}"/>`
20621
+ ).join("");
20622
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${d.width}" height="${d.height}" viewBox="0 0 ${d.width} ${d.height}">${body}</svg>`;
20623
+ }
20624
+ function classicMarkSvgs(ink) {
20625
+ return CLASSIC_MARK_NAMES.map((name) => {
20626
+ const d = classicDrawing(ink, name);
20627
+ return { id: classicMarkId(ink, name), svg: drawingSvg(d), width: d.width, height: d.height, pixelRatio: d.pixelRatio };
20628
+ });
20629
+ }
20630
+ function classicMarkImage(id) {
20631
+ const ink = classicMarkInk(id);
20632
+ if (!ink) throw new Error(`classic-marks: no mark ${id}`);
20633
+ const d = classicDrawing(ink, id.slice(PREFIX[ink].length));
20634
+ return { id, width: d.width, height: d.height, pixelRatio: d.pixelRatio, data: paintDrawing(d) };
20635
+ }
20636
+ function classicMarkImages(ink) {
20637
+ return CLASSIC_MARK_NAMES.map((name) => classicMarkImage(classicMarkId(ink, name)));
20638
+ }
20639
+
20381
20640
  // src/atlas/symbol-image-specs.ts
20382
20641
  var SUPERSAMPLE = 2;
20383
20642
  var BASE_PATTERN_GLYPHS = [
@@ -20434,9 +20693,30 @@ function s101ImageSpecs(palette) {
20434
20693
  return [{ id, svg: svg2, ...declared(id, svg2), pixelRatio: SUPERSAMPLE, sdf: false }];
20435
20694
  });
20436
20695
  }
20696
+ function usChart1ImageSpecs(palette) {
20697
+ const ink = palette === "EINK_MONO" ? "mono" : "color";
20698
+ return classicMarkSvgs(ink).map((m) => ({ ...m, sdf: false }));
20699
+ }
20437
20700
  function symbolImageSpecs(palette, family) {
20438
- const own = family === "s101" ? s101ImageSpecs(palette) : family === "raster" ? rasterImageSpecs(palette) : family === "chrt" ? chrtImageSpecs(palette) : [];
20439
- return [...s52ImageSpecs(palette), ...basePatternImageSpecs(palette), ...own];
20701
+ return [...s52ImageSpecs(palette), ...basePatternImageSpecs(palette), ...familyOwnImageSpecs(palette, family)];
20702
+ }
20703
+ function familyOwnImageSpecs(palette, family) {
20704
+ switch (family) {
20705
+ case "s52":
20706
+ return [];
20707
+ case "s101":
20708
+ return s101ImageSpecs(palette);
20709
+ case "int1":
20710
+ return rasterImageSpecs(palette);
20711
+ case "uschart1":
20712
+ return [...rasterImageSpecs(palette), ...usChart1ImageSpecs(palette)];
20713
+ case "chrt":
20714
+ return chrtImageSpecs(palette);
20715
+ default: {
20716
+ const unhandled = family;
20717
+ throw new Error(`no symbol family ${String(unhandled)}`);
20718
+ }
20719
+ }
20440
20720
  }
20441
20721
  var IMAGE_PROPS = /* @__PURE__ */ new Set([
20442
20722
  "icon-image",
@@ -20519,6 +20799,380 @@ async function loadChrtRasterSymbolImages(map, colorTable = "DAY") {
20519
20799
  async function reloadChrtRasterSymbolImages(map, colorTable) {
20520
20800
  await rethemeSymbolImages(map, rasterImageSpecs(colorTable));
20521
20801
  }
20802
+
20803
+ // src/atlas/look-paper.ts
20804
+ var CLASSIC_TONES = {
20805
+ /** Land. */
20806
+ land: "#ebe2c8",
20807
+ /** The blue tint, to the 18 ft curve. */
20808
+ shallow: "#d8f0f5",
20809
+ /** Deep water: the paper. */
20810
+ deep: "#ffffff",
20811
+ /** The foreshore, and salt marsh. */
20812
+ drying: "#c1d1af",
20813
+ /** Magenta: lights, flares, discs, limits, cautions, red aids. */
20814
+ magenta: "#953699",
20815
+ /** Green aids. */
20816
+ green: "#068b00",
20817
+ /** Black: line-work, lettering, soundings, land contours. */
20818
+ ink: "#000000",
20819
+ /** Depth contours and their values. */
20820
+ contour: "#5f5f5f"
20821
+ };
20822
+ var CLASSIC_IMAGE_NAMES = ["hatch", ...CLASSIC_MARK_NAMES];
20823
+ var PREFIX2 = "chrt-look-cl-";
20824
+ var DAY_TO_CLASSIC = {
20825
+ // Land: LANDA, CHRTland's land and its cover but wetland, slopes.
20826
+ "#d4c69d": CLASSIC_TONES.land,
20827
+ "#e6d1a1": CLASSIC_TONES.land,
20828
+ "#bcc5a1": CLASSIC_TONES.land,
20829
+ "#cac6bf": CLASSIC_TONES.land,
20830
+ "#dbd0af": CLASSIC_TONES.land,
20831
+ "#c8b078": CLASSIC_TONES.land,
20832
+ // Marsh.
20833
+ "#b6c0b1": CLASSIC_TONES.drying,
20834
+ // The drying foreshore (DEPIT).
20835
+ "#009678": CLASSIC_TONES.drying,
20836
+ // Inland water and the shallow depth tints (DEPVS, DEPMS, DEPMD) where
20837
+ // other classes use them: lakes, rivers, canals, locks, swept areas.
20838
+ "#7fbfdf": CLASSIC_TONES.shallow,
20839
+ "#a7d4e8": CLASSIC_TONES.shallow,
20840
+ "#cae7f3": CLASSIC_TONES.shallow,
20841
+ "#b9cfdd": CLASSIC_TONES.shallow,
20842
+ // Deep water (DEPDW).
20843
+ "#ecf7fc": CLASSIC_TONES.deep,
20844
+ // Magentas (CHMGD, CHMGF).
20845
+ "#d200d2": CLASSIC_TONES.magenta,
20846
+ "#c545c3": CLASSIC_TONES.magenta,
20847
+ // Brown structures (CHBRN): buildings, bridges, dams, in black.
20848
+ "#ab7948": CLASSIC_TONES.ink,
20849
+ // Black and the near-blacks of the lettering.
20850
+ "#000000": CLASSIC_TONES.ink,
20851
+ "#1a1d23": CLASSIC_TONES.ink,
20852
+ "#4a5560": CLASSIC_TONES.ink,
20853
+ "#5b4f3a": CLASSIC_TONES.ink,
20854
+ "#bfa88a": CLASSIC_TONES.ink,
20855
+ // Depth contours and area outlines.
20856
+ "#555555": CLASSIC_TONES.contour,
20857
+ // CHRTland's contours: black, as the paper chart's.
20858
+ "#958666": CLASSIC_TONES.ink,
20859
+ "#78694b": CLASSIC_TONES.ink
20860
+ };
20861
+ var HATCH_RATIO = 4;
20862
+ function hatch() {
20863
+ const d = 12;
20864
+ const w = d * 2;
20865
+ const half2 = 0.9;
20866
+ const data = new Uint8Array(w * w * 4);
20867
+ for (let y = 0; y < w; y++) {
20868
+ for (let x = 0; x < w; x++) {
20869
+ const t = (x + y + 1) % d;
20870
+ const dist = Math.min(t, d - t) / Math.SQRT2;
20871
+ const cov = Math.max(0, Math.min(1, half2 + 0.5 - dist));
20872
+ data[(y * w + x) * 4 + 3] = Math.round(cov * 255);
20873
+ }
20874
+ }
20875
+ return { size: w, data };
20876
+ }
20877
+ function classicImages() {
20878
+ const h = hatch();
20879
+ return [
20880
+ { name: "hatch", width: h.size, height: h.size, pixelRatio: HATCH_RATIO, data: h.data },
20881
+ ...classicMarkImages("color").map((i) => ({ name: i.id.slice(PREFIX2.length), width: i.width, height: i.height, pixelRatio: i.pixelRatio, data: i.data }))
20882
+ ];
20883
+ }
20884
+
20885
+ // src/atlas/look-wash-tones.ts
20886
+ var WASH_TONES = {
20887
+ paper: [250, 244, 222],
20888
+ land: [165, 186, 118],
20889
+ // A clear light blue against the shore (owner, 2026-11-02): the 1860 sheet's grey-blue read grey-green on the cream.
20890
+ water: [128, 178, 222],
20891
+ flat: [226, 206, 150],
20892
+ town: [186, 72, 52],
20893
+ road: [192, 124, 72]
20894
+ };
20895
+ function washOver(under, tone, a) {
20896
+ const k = Math.max(0, Math.min(1, a));
20897
+ return [0, 1, 2].map((i) => under[i] * (1 - k * (1 - tone[i] / 255)));
20898
+ }
20899
+ function rgbHex(rgb) {
20900
+ return `#${rgb.map((v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0")).join("")}`;
20901
+ }
20902
+ var WASH_TINTS = (() => {
20903
+ const paper = WASH_TONES.paper;
20904
+ const land = washOver(paper, WASH_TONES.land, 0.6);
20905
+ return {
20906
+ paper: rgbHex(paper),
20907
+ land: rgbHex(land),
20908
+ /** Water to the 18 ft curve. */
20909
+ shallow: rgbHex(washOver(paper, WASH_TONES.water, 0.4)),
20910
+ /** A pond or lake. */
20911
+ lake: rgbHex(washOver(paper, WASH_TONES.water, 0.26)),
20912
+ /** Drying flats. */
20913
+ flat: rgbHex(washOver(paper, WASH_TONES.flat, 0.375)),
20914
+ /** A town, laid over the land. */
20915
+ town: rgbHex(washOver(land, WASH_TONES.town, 0.42)),
20916
+ /** A road's core, over the land. */
20917
+ road: rgbHex(washOver(land, WASH_TONES.road, 0.45))
20918
+ };
20919
+ })();
20920
+
20921
+ // src/atlas/chart-look.ts
20922
+ var LOOK_TONES = {
20923
+ // Black on white: the sheet prints in black alone (DeviceGray).
20924
+ engraved: { ink: "#000000", paper: "#ffffff" },
20925
+ // The 1860 sheet's ink, a warm black (#382d20, sampled), on white; the wash,
20926
+ // multiplied over it, tones the paper and colours the land and water
20927
+ // (look-wash-tones.ts WASH_TONES).
20928
+ handcolored: { ink: "#382d20", paper: "#ffffff" }
20929
+ };
20930
+ var LOOK_IMAGE_NAMES = [
20931
+ "stipple-flats",
20932
+ "stipple-1fm",
20933
+ "stipple-2fm",
20934
+ "stipple-3fm",
20935
+ "marsh",
20936
+ "woods",
20937
+ // The Survey's symbols (lookSymbols).
20938
+ "buoy-nun-red",
20939
+ "buoy-nun-green",
20940
+ "buoy-nun-black",
20941
+ "buoy-nun-yellow",
20942
+ "buoy-can-red",
20943
+ "buoy-can-green",
20944
+ "buoy-can-black",
20945
+ "buoy-can-yellow",
20946
+ "buoy-spar-red",
20947
+ "buoy-spar-green",
20948
+ "buoy-spar-black",
20949
+ "buoy-spar-yellow",
20950
+ "buoy-other-red",
20951
+ "buoy-other-green",
20952
+ "buoy-other-black",
20953
+ "buoy-other-yellow",
20954
+ "beacon",
20955
+ "light",
20956
+ "light-major",
20957
+ "lightship",
20958
+ "landmark",
20959
+ "anchor",
20960
+ "fog"
20961
+ ];
20962
+ var IMAGE_PREFIX = { engraved: "chrt-look-en-", handcolored: "chrt-look-hc-", paper: "chrt-look-cl-" };
20963
+ function lookImageId(look, name) {
20964
+ return IMAGE_PREFIX[look] + name;
20965
+ }
20966
+ function imageNames(look) {
20967
+ return look === "paper" ? CLASSIC_IMAGE_NAMES : LOOK_IMAGE_NAMES;
20968
+ }
20969
+ function lookOfImageId(id) {
20970
+ for (const look of Object.keys(IMAGE_PREFIX)) {
20971
+ if (id.startsWith(IMAGE_PREFIX[look]) && imageNames(look).includes(id.slice(IMAGE_PREFIX[look].length))) return look;
20972
+ }
20973
+ return null;
20974
+ }
20975
+ var PAINT = {
20976
+ red: [184, 69, 47, 255],
20977
+ green: [79, 122, 58, 255],
20978
+ yellow: [214, 176, 72, 255],
20979
+ light: [232, 196, 92, 210]
20980
+ };
20981
+ function lookSymbols(look, ink) {
20982
+ const R2 = 2;
20983
+ const S2 = 64 * R2;
20984
+ const c0 = S2 / 2;
20985
+ const out = [];
20986
+ const coloured = look === "handcolored";
20987
+ const tilt = 28;
20988
+ const line = 0.75 * R2;
20989
+ const B = 1.55;
20990
+ const shapes = {
20991
+ nun: [[0, 0], [-3.2, -6], [0, -16], [3.2, -6]],
20992
+ can: [[-3.4, 0], [-3.4, -9], [3.4, -9], [3.4, 0]],
20993
+ spar: [[-0.9, 0], [-0.9, -16], [0.9, -16], [0.9, 0]],
20994
+ 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)])
20995
+ };
20996
+ for (const shape of ["nun", "can", "spar", "other"]) {
20997
+ for (const colour of ["red", "green", "black", "yellow"]) {
20998
+ const p = painter(S2, S2);
20999
+ const pts = shapes[shape].map(([x, y]) => turn([c0 + x * B * R2, c0 + y * B * R2], c0, c0, tilt));
21000
+ const solid = colour === "black" || colour === "green";
21001
+ if (coloured) p.fill(pts, colour === "black" ? ink : PAINT[colour]);
21002
+ else if (solid) p.fill(pts, ink);
21003
+ p.stroke([...pts, pts[0]], line / 2, ink);
21004
+ p.dot(c0, c0, 1.1 * R2, ink);
21005
+ out.push({ name: `buoy-${shape}-${colour}`, data: p.data(), size: S2 });
21006
+ }
21007
+ }
21008
+ {
21009
+ const p = painter(S2, S2);
21010
+ p.stroke([[c0, c0], [c0, c0 - 22 * R2]], 0.6 * R2, ink);
21011
+ p.dot(c0, c0 - 22 * R2, 2.2 * R2, ink);
21012
+ p.dot(c0, c0, 1.2 * R2, ink);
21013
+ out.push({ name: "beacon", data: p.data(), size: S2 });
21014
+ }
21015
+ for (const [name, r, rays] of [["light", 13, 12], ["light-major", 18, 16]]) {
21016
+ const p = painter(S2, S2);
21017
+ if (coloured) p.dot(c0, c0, r * 0.75 * R2, PAINT.light);
21018
+ for (let i = 0; i < rays; i++) {
21019
+ const a = i / rays * 2 * Math.PI;
21020
+ const len = i % 2 === 0 ? r : r * 0.62;
21021
+ 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);
21022
+ }
21023
+ p.dot(c0, c0, 2.8 * R2, ink);
21024
+ out.push({ name, data: p.data(), size: S2 });
21025
+ }
21026
+ {
21027
+ const p = painter(S2, S2);
21028
+ const hull = [[-8, 0], [8, 0], [5.5, 3.2], [-5.5, 3.2]].map(([x, y]) => [c0 + x * R2, c0 + y * R2]);
21029
+ p.fill(hull, coloured ? PAINT.red : ink);
21030
+ p.stroke([...hull, hull[0]], 0.35 * R2, ink);
21031
+ p.stroke([[c0, c0], [c0, c0 - 11 * R2]], 0.45 * R2, ink);
21032
+ for (let i = 0; i < 8; i++) {
21033
+ const a = i / 8 * 2 * Math.PI;
21034
+ 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);
21035
+ }
21036
+ out.push({ name: "lightship", data: p.data(), size: S2 });
21037
+ }
21038
+ {
21039
+ const p = painter(S2, S2);
21040
+ 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)]);
21041
+ p.stroke(ring, 0.45 * R2, ink);
21042
+ p.dot(c0, c0, 1.2 * R2, ink);
21043
+ out.push({ name: "landmark", data: p.data(), size: S2 });
21044
+ }
21045
+ {
21046
+ const p = painter(S2, S2);
21047
+ const y0 = c0 - 7 * R2;
21048
+ p.stroke([[c0, y0], [c0, c0 + 7 * R2]], 0.5 * R2, ink);
21049
+ p.stroke([[c0 - 3.5 * R2, y0 + 2.2 * R2], [c0 + 3.5 * R2, y0 + 2.2 * R2]], 0.45 * R2, ink);
21050
+ 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)]);
21051
+ p.stroke(ring, 0.35 * R2, ink);
21052
+ const arm = Array.from({ length: 13 }, (_, i) => {
21053
+ const a = Math.PI * (0.15 + 0.7 * (i / 12));
21054
+ return [c0 + 5.5 * R2 * Math.cos(a), c0 + 1.5 * R2 + 5.5 * R2 * Math.sin(a)];
21055
+ });
21056
+ p.stroke(arm, 0.5 * R2, ink);
21057
+ p.stroke([arm[0], [arm[0][0] + 1.6 * R2, arm[0][1] - 1.4 * R2]], 0.45 * R2, ink);
21058
+ p.stroke([arm[12], [arm[12][0] - 1.6 * R2, arm[12][1] - 1.4 * R2]], 0.45 * R2, ink);
21059
+ out.push({ name: "anchor", data: p.data(), size: S2 });
21060
+ }
21061
+ {
21062
+ const p = painter(S2, S2);
21063
+ for (const r of [6, 9, 12]) {
21064
+ const arc = Array.from({ length: 13 }, (_, i) => {
21065
+ const a = (-115 + 50 * i / 12) * (Math.PI / 180);
21066
+ return [c0 + r * R2 * Math.cos(a), c0 + r * R2 * Math.sin(a)];
21067
+ });
21068
+ p.stroke(arc, 0.42 * R2, ink);
21069
+ }
21070
+ out.push({ name: "fog", data: p.data(), size: S2 });
21071
+ }
21072
+ return out;
21073
+ }
21074
+ var IMAGE_RATIO = 4;
21075
+ function hash(a, b, seed) {
21076
+ let h = a * 374761393 + b * 668265263 + seed * 2147483647 | 0;
21077
+ h = Math.imul(h ^ h >>> 13, 1274126177);
21078
+ return ((h ^ h >>> 16) >>> 0) / 4294967296;
21079
+ }
21080
+ function canvas(w, h) {
21081
+ const data = new Uint8Array(w * h * 4);
21082
+ const put = (x, y, a) => {
21083
+ const xi = (x % w + w) % w;
21084
+ const yi = (y % h + h) % h;
21085
+ const k = (yi * w + xi) * 4 + 3;
21086
+ data[k] = Math.min(255, Math.max(data[k], Math.round(a * 255)));
21087
+ };
21088
+ const dot = (cx, cy, r, a = 1) => {
21089
+ for (let y = Math.floor(cy - r - 1); y <= Math.ceil(cy + r + 1); y++) {
21090
+ for (let x = Math.floor(cx - r - 1); x <= Math.ceil(cx + r + 1); x++) {
21091
+ const d = Math.hypot(x + 0.5 - cx, y + 0.5 - cy);
21092
+ const cov = Math.max(0, Math.min(1, r + 0.5 - d));
21093
+ if (cov > 0) put(x, y, cov * a);
21094
+ }
21095
+ }
21096
+ };
21097
+ const line = (x0, y0, x1, y1, r) => {
21098
+ const n = Math.max(1, Math.ceil(Math.hypot(x1 - x0, y1 - y0) * 2));
21099
+ for (let i = 0; i <= n; i++) dot(x0 + (x1 - x0) * i / n, y0 + (y1 - y0) * i / n, r);
21100
+ };
21101
+ return { data, dot, line };
21102
+ }
21103
+ function lookImages(look) {
21104
+ if (look === "paper") return classicImages().map((i) => ({ ...i, id: lookImageId("paper", i.name) }));
21105
+ const [ir, ig, ib] = [1, 3, 5].map((i) => parseInt(LOOK_TONES[look].ink.slice(i, i + 2), 16));
21106
+ const finish = (name, w, h, data) => {
21107
+ for (let k = 0; k < data.length; k += 4) {
21108
+ data[k] = ir;
21109
+ data[k + 1] = ig;
21110
+ data[k + 2] = ib;
21111
+ }
21112
+ return { id: lookImageId(look, name), width: w, height: h, pixelRatio: IMAGE_RATIO, data };
21113
+ };
21114
+ const out = [];
21115
+ for (const [id, step, r, seed] of [
21116
+ ["stipple-flats", 5, 0.95, 1],
21117
+ ["stipple-1fm", 6, 0.9, 2],
21118
+ ["stipple-2fm", 8, 0.85, 3],
21119
+ ["stipple-3fm", 11, 0.8, 4]
21120
+ ]) {
21121
+ const n = 8;
21122
+ const w = step * n;
21123
+ const c = canvas(w, w);
21124
+ for (let j = 0; j < n; j++) for (let i = 0; i < n; i++) {
21125
+ 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)));
21126
+ }
21127
+ out.push(finish(id, w, w, c.data));
21128
+ }
21129
+ {
21130
+ const w = 96;
21131
+ const h = 64;
21132
+ const c = canvas(w, h);
21133
+ for (const [x, y] of [[16, 22], [64, 22], [40, 54], [88, 54]]) {
21134
+ c.line(x - 9, y, x + 9, y, 0.55);
21135
+ c.line(x, y, x, y - 9, 0.5);
21136
+ c.line(x - 3, y, x - 7, y - 7, 0.45);
21137
+ c.line(x + 3, y, x + 7, y - 7, 0.45);
21138
+ }
21139
+ out.push(finish("marsh", w, h, c.data));
21140
+ }
21141
+ {
21142
+ const n = 6;
21143
+ const step = 12;
21144
+ const w = n * step;
21145
+ const c = canvas(w, w);
21146
+ for (let j = 0; j < n; j++) for (let i = 0; i < n; i++) {
21147
+ const x = (i + 0.25 + 0.5 * hash(i, j, 31)) * step;
21148
+ const y = (j + 0.25 + 0.5 * hash(j, i, 37)) * step;
21149
+ 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);
21150
+ c.line(x + 1.5, y + 3, x + 3, y + 2.4, 0.55);
21151
+ }
21152
+ out.push(finish("woods", w, w, c.data));
21153
+ }
21154
+ for (const sym of lookSymbols(look, [ir, ig, ib, 255])) {
21155
+ out.push({ id: lookImageId(look, sym.name), width: sym.size, height: sym.size, pixelRatio: 2, data: sym.data });
21156
+ }
21157
+ return out;
21158
+ }
21159
+
21160
+ // src/atlas/chart-look-images-browser.ts
21161
+ var IMAGES = /* @__PURE__ */ new Map();
21162
+ function provideChartLookImages(map) {
21163
+ map.on("styleimagemissing", (e) => {
21164
+ const mark = classicMarkInk(e.id) !== null;
21165
+ const look = mark ? null : lookOfImageId(e.id);
21166
+ if (!mark && look === null || map.hasImage(e.id)) return;
21167
+ if (!IMAGES.has(e.id)) {
21168
+ if (mark) IMAGES.set(e.id, classicMarkImage(e.id));
21169
+ else for (const image2 of lookImages(look)) IMAGES.set(image2.id, image2);
21170
+ }
21171
+ const image = IMAGES.get(e.id);
21172
+ if (!image) return;
21173
+ map.addImage(e.id, { width: image.width, height: image.height, data: new Uint8Array(image.data) }, { pixelRatio: image.pixelRatio });
21174
+ });
21175
+ }
20522
21176
  // Annotate the CommonJS export names for ESM import in node:
20523
21177
  0 && (module.exports = {
20524
21178
  BASE_PATTERN_GLYPHS,
@@ -20535,6 +21189,7 @@ async function reloadChrtRasterSymbolImages(map, colorTable) {
20535
21189
  loadSymbolImageSpecs,
20536
21190
  loadSymbolImages,
20537
21191
  loadThemedBridgeImages,
21192
+ provideChartLookImages,
20538
21193
  rasterImageSpecs,
20539
21194
  reloadChrtRasterSymbolImages,
20540
21195
  reloadS101SymbolImages,
@@ -20544,6 +21199,7 @@ async function reloadChrtRasterSymbolImages(map, colorTable) {
20544
21199
  s101ImageSpecs,
20545
21200
  s52ImageSpecs,
20546
21201
  styleImageIds,
20547
- symbolImageSpecs
21202
+ symbolImageSpecs,
21203
+ usChart1ImageSpecs
20548
21204
  });
20549
21205
  //# sourceMappingURL=browser.cjs.map