@chrtco/sdk 0.7.5 → 0.7.7

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/dist/index.d.cts CHANGED
@@ -951,6 +951,8 @@ interface NauticalSymbol {
951
951
  description?: string;
952
952
  /** S-52 Presentation Library symbol name */
953
953
  s52PlRef?: string;
954
+ /** S-57 object class (e.g. "LNDMRK") when it can't be derived from s52PlRef's prefix */
955
+ s57Class?: string;
954
956
  /** Grouping key for family clustering */
955
957
  group?: string;
956
958
  /** IDs of related variant symbols */
package/dist/index.d.ts CHANGED
@@ -951,6 +951,8 @@ interface NauticalSymbol {
951
951
  description?: string;
952
952
  /** S-52 Presentation Library symbol name */
953
953
  s52PlRef?: string;
954
+ /** S-57 object class (e.g. "LNDMRK") when it can't be derived from s52PlRef's prefix */
955
+ s57Class?: string;
954
956
  /** Grouping key for family clustering */
955
957
  group?: string;
956
958
  /** IDs of related variant symbols */
package/dist/index.js CHANGED
@@ -3143,18 +3143,37 @@ function depareFillExpression(ct = "DAY") {
3143
3143
  resolveColor("DEPDW", ct)
3144
3144
  ];
3145
3145
  }
3146
- function colourCodeCase(cases, fallback) {
3147
- const colourStr = ["to-string", ["coalesce", ["get", "COLOUR"], ["get", "colour"], ""]];
3146
+ function listAttrString(attr) {
3147
+ return ["to-string", ["coalesce", ["get", attr], ["get", attr.toLowerCase()], ""]];
3148
+ }
3149
+ function listAttrCase(attr, cases, fallback) {
3150
+ const attrStr = listAttrString(attr);
3148
3151
  const expr = ["case"];
3149
3152
  for (const [code, value] of cases) {
3150
- expr.push([">=", ["index-of", `"${code}"`, colourStr], 0], value);
3153
+ expr.push([">=", ["index-of", `"${code}"`, attrStr], 0], value);
3154
+ }
3155
+ for (const [code, value] of cases) {
3156
+ expr.push(["==", attrStr, code], value);
3151
3157
  }
3152
3158
  for (const [code, value] of cases) {
3153
- expr.push(["==", colourStr, code], value);
3159
+ expr.push(["==", attrStr, `[${code}]`], value);
3154
3160
  }
3155
3161
  expr.push(fallback);
3156
3162
  return expr;
3157
3163
  }
3164
+ function listAttrHas(attr, codes) {
3165
+ const attrStr = listAttrString(attr);
3166
+ const clauses = [];
3167
+ for (const code of codes) {
3168
+ clauses.push([">=", ["index-of", `"${code}"`, attrStr], 0]);
3169
+ clauses.push(["==", attrStr, code]);
3170
+ clauses.push(["==", attrStr, `[${code}]`]);
3171
+ }
3172
+ return ["any", ...clauses];
3173
+ }
3174
+ function colourCodeCase(cases, fallback) {
3175
+ return listAttrCase("COLOUR", cases, fallback);
3176
+ }
3158
3177
  function lightColor(props, ct = "DAY") {
3159
3178
  const raw = props.COLOUR ?? props.colour;
3160
3179
  const code = Array.isArray(raw) ? Number(raw[0]) : typeof raw === "string" && raw.startsWith("[") ? Number(JSON.parse(raw)[0]) : Number(raw ?? 0);
@@ -5191,9 +5210,12 @@ var NAUTICAL_SYMBOLS = [
5191
5210
  getSvg: landmarkSpire,
5192
5211
  group: "landmarks",
5193
5212
  description: "Church spire or steeple, conspicuous from seaward. Useful for visual fixing.",
5194
- s52PlRef: "LNDMRK17",
5213
+ // CATLMK 20 alone has no dedicated PL symbol (renders POSGEN01/03); church spires carry
5214
+ // FUNCTN 20/21 and render as the religious-building symbol BUIREL01 (BUIREL13 when conspicuous)
5215
+ s52PlRef: "BUIREL01",
5216
+ s57Class: "LNDMRK",
5195
5217
  attributeKey: "CATLMK",
5196
- attributeValue: 17,
5218
+ attributeValue: 20,
5197
5219
  renderSize: "32x32",
5198
5220
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Spire, building, position circle" }],
5199
5221
  lineStyles: [{ element: "Building outline", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5208,9 +5230,11 @@ var NAUTICAL_SYMBOLS = [
5208
5230
  getSvg: landmarkTower,
5209
5231
  group: "landmarks",
5210
5232
  description: "Tower conspicuous from seaward. General-purpose landmark symbol.",
5211
- s52PlRef: "LNDMRK20",
5233
+ s52PlRef: "TOWERS01",
5234
+ s57Class: "LNDMRK",
5212
5235
  attributeKey: "CATLMK",
5213
- attributeValue: 20,
5236
+ attributeValue: 17,
5237
+ // TOWERS03 = conspicuous variant
5214
5238
  renderSize: "32x32",
5215
5239
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower body, cap, position circle" }],
5216
5240
  lineStyles: [{ element: "Tower outline", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5225,9 +5249,10 @@ var NAUTICAL_SYMBOLS = [
5225
5249
  getSvg: landmarkChimney,
5226
5250
  group: "landmarks",
5227
5251
  description: "Industrial chimney or smokestack visible from the sea.",
5228
- s52PlRef: "LNDMRK01",
5252
+ s52PlRef: "CHIMNY01",
5253
+ s57Class: "LNDMRK",
5229
5254
  attributeKey: "CATLMK",
5230
- attributeValue: 1,
5255
+ attributeValue: 3,
5231
5256
  renderSize: "32x32",
5232
5257
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Chimney body, smoke, position circle" }],
5233
5258
  lineStyles: [{ element: "Body outline", width: 0.8, color: "#000000" }, { element: "Smoke plume", width: 1, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5242,9 +5267,10 @@ var NAUTICAL_SYMBOLS = [
5242
5267
  getSvg: landmarkFlagstaff,
5243
5268
  group: "landmarks",
5244
5269
  description: "Flagstaff or flagpole conspicuous from seaward.",
5245
- s52PlRef: "LNDMRK03",
5270
+ s52PlRef: "FLGSTF01",
5271
+ s57Class: "LNDMRK",
5246
5272
  attributeKey: "CATLMK",
5247
- attributeValue: 3,
5273
+ attributeValue: 5,
5248
5274
  renderSize: "32x32",
5249
5275
  colors: [
5250
5276
  { token: "CHBLK", hex: "#000000", usage: "Pole and position circle" },
@@ -5262,9 +5288,11 @@ var NAUTICAL_SYMBOLS = [
5262
5288
  getSvg: landmarkMonument,
5263
5289
  group: "landmarks",
5264
5290
  description: "Monument or memorial conspicuous from the sea.",
5265
- s52PlRef: "LNDMRK05",
5291
+ s52PlRef: "MONUMT12",
5292
+ s57Class: "LNDMRK",
5266
5293
  attributeKey: "CATLMK",
5267
- attributeValue: 5,
5294
+ attributeValue: 9,
5295
+ // MONUMT02 = non-conspicuous variant
5268
5296
  renderSize: "32x32",
5269
5297
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Monument body, base, position circle" }],
5270
5298
  lineStyles: [{ element: "Body outline", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5279,9 +5307,10 @@ var NAUTICAL_SYMBOLS = [
5279
5307
  getSvg: landmarkWindmill,
5280
5308
  group: "landmarks",
5281
5309
  description: "Traditional windmill with rotating vanes. Conspicuous landmark.",
5282
- s52PlRef: "LNDMRK21",
5310
+ s52PlRef: "WNDMIL12",
5311
+ s57Class: "LNDMRK",
5283
5312
  attributeKey: "CATLMK",
5284
- attributeValue: 7,
5313
+ attributeValue: 18,
5285
5314
  renderSize: "32x32",
5286
5315
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower, vanes, hub, position circle" }],
5287
5316
  lineStyles: [{ element: "Tower", width: 1.5, color: "#000000" }, { element: "Vane arms", width: 1.2, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5296,9 +5325,10 @@ var NAUTICAL_SYMBOLS = [
5296
5325
  getSvg: landmarkWindTurbine,
5297
5326
  group: "landmarks",
5298
5327
  description: "Modern 3-blade wind turbine. Increasingly common offshore landmark.",
5299
- s52PlRef: "LNDMRK22",
5328
+ s52PlRef: "WIMCON11",
5329
+ s57Class: "LNDMRK",
5300
5330
  attributeKey: "CATLMK",
5301
- attributeValue: 26,
5331
+ attributeValue: 19,
5302
5332
  renderSize: "32x32",
5303
5333
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower, blades, hub, position circle" }],
5304
5334
  lineStyles: [{ element: "Tower", width: 1.5, color: "#000000" }, { element: "Blades", width: 1.2, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5313,9 +5343,11 @@ var NAUTICAL_SYMBOLS = [
5313
5343
  getSvg: landmarkDome,
5314
5344
  group: "landmarks",
5315
5345
  description: "Dome or cupola (e.g., observatory, mosque) visible from the sea.",
5316
- s52PlRef: "LNDMRK03",
5346
+ s52PlRef: "DOMES011",
5347
+ s57Class: "LNDMRK",
5317
5348
  attributeKey: "CATLMK",
5318
- attributeValue: 6,
5349
+ attributeValue: 15,
5350
+ // DOMES001 = non-conspicuous variant
5319
5351
  renderSize: "32x32",
5320
5352
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Dome, base, position circle" }],
5321
5353
  lineStyles: [{ element: "Base outline", width: 0.8, color: "#000000" }, { element: "Dome curve", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5330,9 +5362,10 @@ var NAUTICAL_SYMBOLS = [
5330
5362
  getSvg: landmarkRadarScanner,
5331
5363
  group: "landmarks",
5332
5364
  description: "Radar scanner antenna conspicuous from seaward.",
5333
- s52PlRef: "LNDMRK12",
5365
+ s52PlRef: "RASCAN01",
5366
+ s57Class: "LNDMRK",
5334
5367
  attributeKey: "CATLMK",
5335
- attributeValue: 9,
5368
+ attributeValue: 16,
5336
5369
  renderSize: "32x32",
5337
5370
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower, scanner dish, position circle" }],
5338
5371
  lineStyles: [{ element: "Tower", width: 1.5, color: "#000000" }, { element: "Scanner frame", width: 1.5, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5347,9 +5380,10 @@ var NAUTICAL_SYMBOLS = [
5347
5380
  getSvg: landmarkDishAerial,
5348
5381
  group: "landmarks",
5349
5382
  description: "Satellite dish or parabolic antenna visible from the sea.",
5350
- s52PlRef: "LNDMRK12",
5383
+ s52PlRef: "DSHAER01",
5384
+ s57Class: "LNDMRK",
5351
5385
  attributeKey: "CATLMK",
5352
- attributeValue: 12,
5386
+ attributeValue: 4,
5353
5387
  renderSize: "32x32",
5354
5388
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tower, dish, position circle" }],
5355
5389
  lineStyles: [{ element: "Tower", width: 1.5, color: "#000000" }, { element: "Dish curve", width: 1.5, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5364,9 +5398,10 @@ var NAUTICAL_SYMBOLS = [
5364
5398
  getSvg: landmarkWaterTower,
5365
5399
  group: "landmarks",
5366
5400
  description: "Water tower. Elevated tank on supporting structure, conspicuous landmark.",
5367
- s52PlRef: "LNDMRK19",
5368
- attributeKey: "CATLMK",
5369
- attributeValue: 15,
5401
+ s52PlRef: "TOWERS12",
5402
+ s57Class: "SILTNK",
5403
+ attributeKey: "CATSIL",
5404
+ attributeValue: 4,
5370
5405
  renderSize: "32x32",
5371
5406
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Tank, legs, position circle" }],
5372
5407
  lineStyles: [{ element: "Leg outlines", width: 1.2, color: "#000000" }, { element: "Tank outline", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5381,9 +5416,11 @@ var NAUTICAL_SYMBOLS = [
5381
5416
  getSvg: landmarkRadioTvMast,
5382
5417
  group: "landmarks",
5383
5418
  description: "Radio or television transmission mast with horizontal cross-arms.",
5384
- s52PlRef: "LNDMRK10",
5419
+ // Radio/TV masts are CATLMK 7 (mast) + FUNCTN in S-57, so both mast entries share MSTCON04
5420
+ s52PlRef: "MSTCON04",
5421
+ s57Class: "LNDMRK",
5385
5422
  attributeKey: "CATLMK",
5386
- attributeValue: 8,
5423
+ attributeValue: 7,
5387
5424
  renderSize: "32x32",
5388
5425
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Mast, cross-arms, top, position circle" }],
5389
5426
  lineStyles: [{ element: "Main mast", width: 1.5, color: "#000000" }, { element: "Cross-arms", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5398,9 +5435,12 @@ var NAUTICAL_SYMBOLS = [
5398
5435
  getSvg: landmarkCross,
5399
5436
  group: "landmarks",
5400
5437
  description: "Religious cross or calvary conspicuous from seaward.",
5401
- s52PlRef: "LNDMRK05",
5438
+ // The PL has no dedicated symbol for CATLMK 14 (cross/calvary) — S-52 falls back to the
5439
+ // generic position symbol POSGEN01 (POSGEN03 when conspicuous)
5440
+ s52PlRef: "POSGEN01",
5441
+ s57Class: "LNDMRK",
5402
5442
  attributeKey: "CATLMK",
5403
- attributeValue: 10,
5443
+ attributeValue: 14,
5404
5444
  renderSize: "32x32",
5405
5445
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Cross arms and position circle" }],
5406
5446
  lineStyles: [{ element: "Vertical arm", width: 2, color: "#000000" }, { element: "Horizontal arm", width: 2, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5415,9 +5455,11 @@ var NAUTICAL_SYMBOLS = [
5415
5455
  getSvg: landmarkMast,
5416
5456
  group: "landmarks",
5417
5457
  description: "General mast (not radio/TV). Pole with spherical top.",
5418
- s52PlRef: "LNDMRK10",
5458
+ s52PlRef: "MSTCON04",
5459
+ s57Class: "LNDMRK",
5419
5460
  attributeKey: "CATLMK",
5420
- attributeValue: 14,
5461
+ attributeValue: 7,
5462
+ // MSTCON14 = conspicuous variant
5421
5463
  renderSize: "32x32",
5422
5464
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Mast pole, top ball, position circle" }],
5423
5465
  lineStyles: [{ element: "Mast pole", width: 2, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5432,9 +5474,10 @@ var NAUTICAL_SYMBOLS = [
5432
5474
  getSvg: landmarkSilo,
5433
5475
  group: "landmarks",
5434
5476
  description: "Silo, grain elevator, or storage tank conspicuous from the sea.",
5435
- s52PlRef: "LNDMRK17",
5436
- attributeKey: "CATLMK",
5437
- attributeValue: 33,
5477
+ s52PlRef: "SILBUI01",
5478
+ s57Class: "SILTNK",
5479
+ attributeKey: "CATSIL",
5480
+ attributeValue: 1,
5438
5481
  renderSize: "32x32",
5439
5482
  colors: [{ token: "CHBLK", hex: "#000000", usage: "Body, dome top, position circle" }],
5440
5483
  lineStyles: [{ element: "Body outline", width: 0.8, color: "#000000" }, { element: "Dome curve", width: 0.8, color: "#000000" }, { element: "Position circle", width: 0.6, pattern: "2, 2", color: "#000000" }],
@@ -5836,27 +5879,18 @@ function getIconExpression(layerName) {
5836
5879
  ];
5837
5880
  }
5838
5881
  if (layerName === "LNDMRK") {
5839
- return [
5840
- "match",
5841
- ["coalesce", ["get", "CATLMK"], ["get", "catlmk"], 0],
5842
- 1,
5843
- "CAIRNS11",
5844
- // Cairn
5845
- 17,
5846
- "BCNTOW01",
5847
- // Tower
5848
- 18,
5849
- "LNDMRK18",
5882
+ return listAttrCase("CATLMK", [
5883
+ ["18", "LNDMRK18"],
5850
5884
  // Windmill (4-vane)
5851
- 19,
5852
- "LNDMRK19",
5885
+ ["19", "LNDMRK19"],
5853
5886
  // Wind motor / turbine (3-blade)
5854
- 20,
5855
- "BCNTOW01",
5887
+ ["1", "CAIRNS11"],
5888
+ // Cairn
5889
+ ["17", "BCNTOW01"],
5890
+ // Tower
5891
+ ["20", "BCNTOW01"]
5856
5892
  // Spire → tower
5857
- "BCNTOW01"
5858
- // Default: tower
5859
- ];
5893
+ ], "BCNTOW01");
5860
5894
  }
5861
5895
  if (layerName === "DAYMAR") {
5862
5896
  return [
@@ -5996,18 +6030,12 @@ function getIconExpression(layerName) {
5996
6030
  ];
5997
6031
  }
5998
6032
  if (layerName === "LIGHTS") {
5999
- return [
6000
- "match",
6001
- ["coalesce", ["get", "CATLIT"], ["get", "catlit"], 0],
6002
- 8,
6003
- "LIGHTS82",
6004
- // Aero light
6005
- 9,
6006
- "LIGHTS82",
6007
- // Air obstruction light
6008
- "LIGHTS11"
6009
- // Default: major light
6010
- ];
6033
+ return listAttrCase("CATLIT", [
6034
+ ["8", "LIGHTS82"],
6035
+ // Floodlight
6036
+ ["9", "LIGHTS82"]
6037
+ // Strip light
6038
+ ], "LIGHTS11");
6011
6039
  }
6012
6040
  return SYMBOL_MAP[layerName] ?? "";
6013
6041
  }
@@ -6699,6 +6727,11 @@ var LABEL_BEHAVIOR = {
6699
6727
  function getLabelBehavior(layerName) {
6700
6728
  return LABEL_BEHAVIOR[layerName] ?? "feature-band-gated";
6701
6729
  }
6730
+ var LABEL_ANCHOR_FILTER = [
6731
+ "!=",
6732
+ ["get", "_label_anchor"],
6733
+ false
6734
+ ];
6702
6735
  function getLabelConfig(layerName, opts = {}) {
6703
6736
  const ct = opts.colorTable ?? "DAY";
6704
6737
  switch (layerName) {
@@ -7490,6 +7523,18 @@ function preprocessSoundings(fc) {
7490
7523
  }
7491
7524
  return { type: "FeatureCollection", features };
7492
7525
  }
7526
+ function firstListCode(raw) {
7527
+ if (raw == null) return NaN;
7528
+ if (Array.isArray(raw)) return Number(raw[0]);
7529
+ if (typeof raw === "string" && raw.startsWith("[")) {
7530
+ try {
7531
+ const arr = JSON.parse(raw);
7532
+ if (Array.isArray(arr)) return Number(arr[0]);
7533
+ } catch {
7534
+ }
7535
+ }
7536
+ return Number(raw);
7537
+ }
7493
7538
  function preprocessLights(fc) {
7494
7539
  return {
7495
7540
  type: "FeatureCollection",
@@ -7498,7 +7543,7 @@ function preprocessLights(fc) {
7498
7543
  const parts = [];
7499
7544
  const litchr = Number(props.LITCHR);
7500
7545
  if (litchr && LITCHR_ABBR[litchr]) parts.push(LITCHR_ABBR[litchr]);
7501
- const colour = Number(props.COLOUR);
7546
+ const colour = firstListCode(props.COLOUR);
7502
7547
  if (colour && COLOUR_ABBR[colour]) parts.push(COLOUR_ABBR[colour]);
7503
7548
  const sigper = Number(props.SIGPER);
7504
7549
  if (sigper && sigper > 0) parts.push(sigper + "s");
@@ -7572,7 +7617,7 @@ function preprocessNavAids(fc) {
7572
7617
  const match = objnam.match(/(\d+[A-Z]?)\s*$/);
7573
7618
  if (!match) return f;
7574
7619
  const designation = match[1];
7575
- const colourCode = Number(props.COLOUR);
7620
+ const colourCode = firstListCode(props.COLOUR);
7576
7621
  const prefix = NAV_COLOUR_PREFIX[colourCode];
7577
7622
  const label = prefix ? `${prefix} "${designation}"` : `"${designation}"`;
7578
7623
  return {
@@ -8141,6 +8186,18 @@ var S101_FEATURES = [
8141
8186
  isNewInS101: false,
8142
8187
  attributes: ["categoryOfLandmark", "function", "visuallyConspicuous"]
8143
8188
  },
8189
+ {
8190
+ featureClass: "SiloStorageTank",
8191
+ name: "Silo / Storage Tank",
8192
+ s57Equivalent: "SILTNK",
8193
+ section: "E",
8194
+ group: "landmarks",
8195
+ category: "geo",
8196
+ description: "An enclosed structure for storing bulk solids or liquids (silo, grain elevator, water tower, tank). Often conspicuous and useful for position fixing.",
8197
+ portrayalRef: "SILTNK_S101",
8198
+ isNewInS101: false,
8199
+ attributes: ["categoryOfSiloTank", "colour", "visuallyConspicuous"]
8200
+ },
8144
8201
  // ── Section D: Bridges ──
8145
8202
  {
8146
8203
  featureClass: "Bridge",
@@ -9651,23 +9708,30 @@ function buildLayersForClass(objectClass, ct, sourceId = DEFAULT_REGION) {
9651
9708
  }
9652
9709
  if (objectClass === "LNDMRK" && resolved.type === "symbol") {
9653
9710
  const baseFilterParts = layer.filter && layer.filter[0] === "all" ? layer.filter.slice(1) : layer.filter ? [layer.filter] : [];
9654
- const catlmk = ["coalesce", ["get", "CATLMK"], ["get", "catlmk"], 0];
9655
- const isWind = ["any", ["==", catlmk, 18], ["==", catlmk, 19]];
9656
- const isLighthouse = ["==", catlmk, 17];
9711
+ const isWind = listAttrHas("CATLMK", ["18", "19"]);
9712
+ const isLighthouse = listAttrHas("CATLMK", ["17"]);
9657
9713
  const scaminFloor = scaminToMinZoom(entry?.scamin);
9658
9714
  const windLayer = {
9659
9715
  ...layer,
9660
9716
  id: `s52-${objectClass}-wind-symbol`,
9661
- filter: ["all", ...baseFilterParts, isWind]
9717
+ filter: ["all", ...baseFilterParts, isWind],
9718
+ // Explicit, not inherited: turbines share exact coordinates with
9719
+ // their aviation-light LIGHTS feature; without allow-overlap the
9720
+ // turbine icon loses collision to the LIGHTS flare and vanishes.
9721
+ // (The value currently also arrives via the entry-layout
9722
+ // spread-last chain, but that chain is fragile — see s52-lookup
9723
+ // LNDMRK entry — so the intent is pinned here.)
9724
+ layout: { ...layer.layout ?? {}, "icon-allow-overlap": true }
9662
9725
  };
9663
9726
  delete windLayer.minzoom;
9664
9727
  const lighthouseLayer = {
9665
9728
  ...layer,
9666
9729
  id: `s52-${objectClass}-lighthouse-symbol`,
9667
- filter: ["all", ...baseFilterParts, isLighthouse],
9730
+ filter: ["all", ...baseFilterParts, isLighthouse, ["!", isWind]],
9668
9731
  layout: {
9669
9732
  ...layer.layout ?? {},
9670
- "icon-image": "LIGHTHOUSE01"
9733
+ "icon-image": "LIGHTHOUSE01",
9734
+ "icon-allow-overlap": true
9671
9735
  }
9672
9736
  };
9673
9737
  delete lighthouseLayer.minzoom;
@@ -10548,7 +10612,7 @@ function buildLabelLayer2(objectClass, ct, sourceId = DEFAULT_REGION, depthUnits
10548
10612
  delete layer.filter;
10549
10613
  }
10550
10614
  if (getLabelBehavior(objectClass) === "orientation-cross-band") {
10551
- delete layer.filter;
10615
+ layer.filter = LABEL_ANCHOR_FILTER;
10552
10616
  }
10553
10617
  return layer;
10554
10618
  }