From 7a34c3743540e15ca76161a5b1262d9ae9fa885d Mon Sep 17 00:00:00 2001 From: Jeremy Collins Date: Mon, 3 Aug 2026 06:46:42 -0400 Subject: [PATCH 1/3] s57: add the attribute catalogue and the decode catalog.zig holds the S-57 edition 3.1 attribute catalogue as data: 186 attribute labels and 102 enum tables with 1112 values. The source is Appendix A, Chapter 2 (November 2000). A code that the source does not confirm is omitted. An omitted code passes through the report unchanged. decode.zig reads the catalogue and adds the print rules the catalogue does not contain: chart abbreviations for light characteristics (LITCHR 4 prints as Q), units for plain numbers, signal sequences, SCAMIN as '1:30,000 and larger', SORIND as 'Chart 12283 (US)', and S-57 dates. A '--MMDD' date prints as a yearly date. Unknown values stay unchanged. --- src/s57/catalog.zig | 1360 +++++++++++++++++++++++++++++++++++++++++++ src/s57/decode.zig | 275 +++++++++ src/s57/s57.zig | 5 + 3 files changed, 1640 insertions(+) create mode 100644 src/s57/catalog.zig create mode 100644 src/s57/decode.zig diff --git a/src/s57/catalog.zig b/src/s57/catalog.zig new file mode 100644 index 00000000..f51ba38f --- /dev/null +++ b/src/s57/catalog.zig @@ -0,0 +1,1360 @@ +//! The IHO S-57 (edition 3.1) attribute catalogue, as data. +//! +//! Transcribed from IHO S-57 Appendix A, Chapter 2 "Attributes" (edition 3.1, +//! November 2000, iho.int). Any code whose meaning could not be confirmed +//! against the standard is omitted, so unknown codes pass through raw instead +//! of risking a wrong decode. + +pub const AttrName = struct { acronym: []const u8, name: []const u8 }; + +/// Attribute acronym -> the label a mariner reads. +pub const attribute_names = [_]AttrName{ + .{ .acronym = "AGENCY", .name = "Agency" }, + .{ .acronym = "BCNSHP", .name = "Beacon shape" }, + .{ .acronym = "BOYSHP", .name = "Buoy shape" }, + .{ .acronym = "BUISHP", .name = "Building shape" }, + .{ .acronym = "BURDEP", .name = "Buried depth" }, + .{ .acronym = "CALSGN", .name = "Call sign" }, + .{ .acronym = "CATACH", .name = "Category" }, + .{ .acronym = "CATAIR", .name = "Category" }, + .{ .acronym = "CATBRG", .name = "Category" }, + .{ .acronym = "CATBUA", .name = "Category" }, + .{ .acronym = "CATCAM", .name = "Category" }, + .{ .acronym = "CATCAN", .name = "Category" }, + .{ .acronym = "CATCBL", .name = "Category" }, + .{ .acronym = "CATCHP", .name = "Category" }, + .{ .acronym = "CATCOA", .name = "Category" }, + .{ .acronym = "CATCON", .name = "Category" }, + .{ .acronym = "CATCOV", .name = "Category" }, + .{ .acronym = "CATCRN", .name = "Category" }, + .{ .acronym = "CATCTR", .name = "Category" }, + .{ .acronym = "CATDAM", .name = "Category" }, + .{ .acronym = "CATDIS", .name = "Category" }, + .{ .acronym = "CATDOC", .name = "Category" }, + .{ .acronym = "CATDPG", .name = "Category" }, + .{ .acronym = "CATFIF", .name = "Category" }, + .{ .acronym = "CATFNC", .name = "Category" }, + .{ .acronym = "CATFOG", .name = "Category" }, + .{ .acronym = "CATFOR", .name = "Category" }, + .{ .acronym = "CATFRY", .name = "Category" }, + .{ .acronym = "CATGAT", .name = "Category" }, + .{ .acronym = "CATHLK", .name = "Category" }, + .{ .acronym = "CATICE", .name = "Category" }, + .{ .acronym = "CATINB", .name = "Category" }, + .{ .acronym = "CATLAM", .name = "Category" }, + .{ .acronym = "CATLIT", .name = "Category" }, + .{ .acronym = "CATLMK", .name = "Category" }, + .{ .acronym = "CATLND", .name = "Category" }, + .{ .acronym = "CATMFA", .name = "Category" }, + .{ .acronym = "CATMOR", .name = "Category" }, + .{ .acronym = "CATMPA", .name = "Category" }, + .{ .acronym = "CATNAV", .name = "Category" }, + .{ .acronym = "CATOBS", .name = "Category" }, + .{ .acronym = "CATOFP", .name = "Category" }, + .{ .acronym = "CATOLB", .name = "Category" }, + .{ .acronym = "CATPIL", .name = "Category" }, + .{ .acronym = "CATPIP", .name = "Category" }, + .{ .acronym = "CATPLE", .name = "Category" }, + .{ .acronym = "CATPRA", .name = "Category" }, + .{ .acronym = "CATPYL", .name = "Category" }, + .{ .acronym = "CATQUA", .name = "Category" }, + .{ .acronym = "CATRAS", .name = "Category" }, + .{ .acronym = "CATREA", .name = "Category" }, + .{ .acronym = "CATROD", .name = "Category" }, + .{ .acronym = "CATROS", .name = "Category" }, + .{ .acronym = "CATRSC", .name = "Category" }, + .{ .acronym = "CATRTB", .name = "Category" }, + .{ .acronym = "CATRUN", .name = "Category" }, + .{ .acronym = "CATSCF", .name = "Category" }, + .{ .acronym = "CATSEA", .name = "Category" }, + .{ .acronym = "CATSIL", .name = "Category" }, + .{ .acronym = "CATSIT", .name = "Category" }, + .{ .acronym = "CATSIW", .name = "Category" }, + .{ .acronym = "CATSLC", .name = "Category" }, + .{ .acronym = "CATSLO", .name = "Category" }, + .{ .acronym = "CATSPM", .name = "Category" }, + .{ .acronym = "CATTRK", .name = "Category" }, + .{ .acronym = "CATTSS", .name = "Category" }, + .{ .acronym = "CATVEG", .name = "Category" }, + .{ .acronym = "CATWAT", .name = "Category" }, + .{ .acronym = "CATWED", .name = "Category" }, + .{ .acronym = "CATWRK", .name = "Category" }, + .{ .acronym = "CATZOC", .name = "Category" }, + .{ .acronym = "CAT_TS", .name = "Category" }, + .{ .acronym = "COLOUR", .name = "Colour" }, + .{ .acronym = "COLPAT", .name = "Colour pattern" }, + .{ .acronym = "COMCHA", .name = "Communication channel" }, + .{ .acronym = "CONDTN", .name = "Condition" }, + .{ .acronym = "CONRAD", .name = "Radar conspicuous" }, + .{ .acronym = "CONVIS", .name = "Visually conspicuous" }, + .{ .acronym = "CPDATE", .name = "Compilation date" }, + .{ .acronym = "CSCALE", .name = "Compilation scale" }, + .{ .acronym = "CURVEL", .name = "Current velocity" }, + .{ .acronym = "DATEND", .name = "End date" }, + .{ .acronym = "DATSTA", .name = "Start date" }, + .{ .acronym = "DRVAL1", .name = "Depth range minimum" }, + .{ .acronym = "DRVAL2", .name = "Depth range maximum" }, + .{ .acronym = "DUNITS", .name = "Depth units" }, + .{ .acronym = "ELEVAT", .name = "Elevation" }, + .{ .acronym = "ESTRNG", .name = "Estimated range" }, + .{ .acronym = "EXCLIT", .name = "Light exhibition" }, + .{ .acronym = "EXPSOU", .name = "Exposition of sounding" }, + .{ .acronym = "FUNCTN", .name = "Function" }, + .{ .acronym = "HEIGHT", .name = "Height" }, + .{ .acronym = "HORACC", .name = "Horizontal accuracy" }, + .{ .acronym = "HORCLR", .name = "Horizontal clearance" }, + .{ .acronym = "HORDAT", .name = "Horizontal datum" }, + .{ .acronym = "HORLEN", .name = "Length" }, + .{ .acronym = "HORWID", .name = "Width" }, + .{ .acronym = "HUNITS", .name = "Height units" }, + .{ .acronym = "ICEFAC", .name = "Ice factor" }, + .{ .acronym = "INFORM", .name = "Information" }, + .{ .acronym = "JRSDTN", .name = "Jurisdiction" }, + .{ .acronym = "LIFCAP", .name = "Lifting capacity" }, + .{ .acronym = "LITCHR", .name = "Light characteristic" }, + .{ .acronym = "LITVIS", .name = "Light visibility" }, + .{ .acronym = "MARSYS", .name = "Buoyage system" }, + .{ .acronym = "MLTYLT", .name = "Number of lights" }, + .{ .acronym = "NATCON", .name = "Construction" }, + .{ .acronym = "NATION", .name = "Nationality" }, + .{ .acronym = "NATQUA", .name = "Surface qualifier" }, + .{ .acronym = "NATSUR", .name = "Surface" }, + .{ .acronym = "NINFOM", .name = "Information (national)" }, + .{ .acronym = "NMDATE", .name = "Notice to Mariners date" }, + .{ .acronym = "NOBJNM", .name = "Name (national)" }, + .{ .acronym = "NPLDST", .name = "Pilot district (national)" }, + .{ .acronym = "NTXTDS", .name = "Description (national)" }, + .{ .acronym = "OBJNAM", .name = "Name" }, + .{ .acronym = "ORIENT", .name = "Orientation" }, + .{ .acronym = "PEREND", .name = "Period end" }, + .{ .acronym = "PERSTA", .name = "Period start" }, + .{ .acronym = "PICREP", .name = "Picture" }, + .{ .acronym = "PILDST", .name = "Pilot district" }, + .{ .acronym = "POSACC", .name = "Positional accuracy" }, + .{ .acronym = "PRCTRY", .name = "Producing country" }, + .{ .acronym = "PRODCT", .name = "Product" }, + .{ .acronym = "PUBREF", .name = "Publication reference" }, + .{ .acronym = "PUNITS", .name = "Position units" }, + .{ .acronym = "QUAPOS", .name = "Position quality" }, + .{ .acronym = "QUASOU", .name = "Sounding quality" }, + .{ .acronym = "RADIUS", .name = "Radius" }, + .{ .acronym = "RADWAL", .name = "Radar wavelength" }, + .{ .acronym = "RECDAT", .name = "Recording date" }, + .{ .acronym = "RECIND", .name = "Recording indication" }, + .{ .acronym = "RESTRN", .name = "Restriction" }, + .{ .acronym = "RYRMGV", .name = "Reference year" }, + .{ .acronym = "SCAMAX", .name = "Maximum scale" }, + .{ .acronym = "SCAMIN", .name = "Minimum scale" }, + .{ .acronym = "SCVAL1", .name = "Scale value 1" }, + .{ .acronym = "SCVAL2", .name = "Scale value 2" }, + .{ .acronym = "SDISMN", .name = "Minimum sounding distance" }, + .{ .acronym = "SDISMX", .name = "Maximum sounding distance" }, + .{ .acronym = "SECTR1", .name = "Sector limit 1" }, + .{ .acronym = "SECTR2", .name = "Sector limit 2" }, + .{ .acronym = "SHIPAM", .name = "Shift parameters" }, + .{ .acronym = "SIGFRQ", .name = "Signal frequency" }, + .{ .acronym = "SIGGEN", .name = "Signal generation" }, + .{ .acronym = "SIGGRP", .name = "Signal group" }, + .{ .acronym = "SIGPER", .name = "Signal period" }, + .{ .acronym = "SIGSEQ", .name = "Signal sequence" }, + .{ .acronym = "SORDAT", .name = "Source date" }, + .{ .acronym = "SORIND", .name = "Source" }, + .{ .acronym = "SOUACC", .name = "Sounding accuracy" }, + .{ .acronym = "STATUS", .name = "Status" }, + .{ .acronym = "SURATH", .name = "Survey authority" }, + .{ .acronym = "SUREND", .name = "Survey end" }, + .{ .acronym = "SURSTA", .name = "Survey start" }, + .{ .acronym = "SURTYP", .name = "Survey type" }, + .{ .acronym = "TECSOU", .name = "Sounding technique" }, + .{ .acronym = "TIMEND", .name = "End time" }, + .{ .acronym = "TIMSTA", .name = "Start time" }, + .{ .acronym = "TOPSHP", .name = "Topmark shape" }, + .{ .acronym = "TRAFIC", .name = "Traffic flow" }, + .{ .acronym = "TS_TSP", .name = "Tidal stream panel" }, + .{ .acronym = "TS_TSV", .name = "Tidal stream time series" }, + .{ .acronym = "TXTDSC", .name = "Description" }, + .{ .acronym = "T_ACWL", .name = "Water level accuracy" }, + .{ .acronym = "T_HWLW", .name = "High and low waters" }, + .{ .acronym = "T_MTOD", .name = "Tidal prediction method" }, + .{ .acronym = "T_THDF", .name = "Time and height differences" }, + .{ .acronym = "T_TINT", .name = "Time interval" }, + .{ .acronym = "T_TSVL", .name = "Tide time series" }, + .{ .acronym = "T_VAHC", .name = "Harmonic constituents" }, + .{ .acronym = "VALACM", .name = "Annual magnetic change" }, + .{ .acronym = "VALDCO", .name = "Depth contour" }, + .{ .acronym = "VALLMA", .name = "Local magnetic anomaly" }, + .{ .acronym = "VALMAG", .name = "Magnetic variation" }, + .{ .acronym = "VALMXR", .name = "Maximum range" }, + .{ .acronym = "VALNMR", .name = "Nominal range" }, + .{ .acronym = "VALSOU", .name = "Depth" }, + .{ .acronym = "VERACC", .name = "Vertical accuracy" }, + .{ .acronym = "VERCCL", .name = "Vertical clearance (closed)" }, + .{ .acronym = "VERCLR", .name = "Vertical clearance" }, + .{ .acronym = "VERCOP", .name = "Vertical clearance (open)" }, + .{ .acronym = "VERCSA", .name = "Safe vertical clearance" }, + .{ .acronym = "VERDAT", .name = "Vertical datum" }, + .{ .acronym = "VERLEN", .name = "Vertical length" }, + .{ .acronym = "WATLEV", .name = "Water level effect" }, +}; + +pub const EnumValue = struct { acronym: []const u8, code: u16, value: []const u8 }; + +/// Every enumerated/list attribute's official values, one entry per code. +pub const enum_values = [_]EnumValue{ + .{ .acronym = "BCNSHP", .code = 1, .value = "stake, pole, perch, post" }, + .{ .acronym = "BCNSHP", .code = 2, .value = "withy" }, + .{ .acronym = "BCNSHP", .code = 3, .value = "beacon tower" }, + .{ .acronym = "BCNSHP", .code = 4, .value = "lattice beacon" }, + .{ .acronym = "BCNSHP", .code = 5, .value = "pile beacon" }, + .{ .acronym = "BCNSHP", .code = 6, .value = "cairn" }, + .{ .acronym = "BCNSHP", .code = 7, .value = "buoyant beacon" }, + .{ .acronym = "BOYSHP", .code = 1, .value = "conical (nun, ogival)" }, + .{ .acronym = "BOYSHP", .code = 2, .value = "can (cylindrical)" }, + .{ .acronym = "BOYSHP", .code = 3, .value = "spherical" }, + .{ .acronym = "BOYSHP", .code = 4, .value = "pillar" }, + .{ .acronym = "BOYSHP", .code = 5, .value = "spar (spindle)" }, + .{ .acronym = "BOYSHP", .code = 6, .value = "barrel (tun)" }, + .{ .acronym = "BOYSHP", .code = 7, .value = "super-buoy" }, + .{ .acronym = "BOYSHP", .code = 8, .value = "ice buoy" }, + .{ .acronym = "BUISHP", .code = 1, .value = "no specific shape" }, + .{ .acronym = "BUISHP", .code = 2, .value = "tower" }, + .{ .acronym = "BUISHP", .code = 3, .value = "spire" }, + .{ .acronym = "BUISHP", .code = 4, .value = "cupola (dome)" }, + .{ .acronym = "BUISHP", .code = 5, .value = "high-rise building" }, + .{ .acronym = "BUISHP", .code = 6, .value = "pyramid" }, + .{ .acronym = "BUISHP", .code = 7, .value = "cylindrical" }, + .{ .acronym = "BUISHP", .code = 8, .value = "spherical" }, + .{ .acronym = "BUISHP", .code = 9, .value = "cubic" }, + .{ .acronym = "CATACH", .code = 1, .value = "unrestricted anchorage" }, + .{ .acronym = "CATACH", .code = 2, .value = "deep water anchorage" }, + .{ .acronym = "CATACH", .code = 3, .value = "tanker anchorage" }, + .{ .acronym = "CATACH", .code = 4, .value = "explosives anchorage" }, + .{ .acronym = "CATACH", .code = 5, .value = "quarantine anchorage" }, + .{ .acronym = "CATACH", .code = 6, .value = "sea-plane anchorage" }, + .{ .acronym = "CATACH", .code = 7, .value = "small craft anchorage" }, + .{ .acronym = "CATACH", .code = 8, .value = "small craft mooring area" }, + .{ .acronym = "CATACH", .code = 9, .value = "anchorage for periods up to 24 hours" }, + .{ .acronym = "CATACH", .code = 10, .value = "anchorage for a limited period of time" }, + .{ .acronym = "CATAIR", .code = 1, .value = "military aeroplane airport" }, + .{ .acronym = "CATAIR", .code = 2, .value = "civil aeroplane airport" }, + .{ .acronym = "CATAIR", .code = 3, .value = "military heliport" }, + .{ .acronym = "CATAIR", .code = 4, .value = "civil heliport" }, + .{ .acronym = "CATAIR", .code = 5, .value = "glider airfield" }, + .{ .acronym = "CATAIR", .code = 6, .value = "small planes airfield" }, + .{ .acronym = "CATAIR", .code = 7, .value = "helicopter platform" }, + .{ .acronym = "CATAIR", .code = 8, .value = "emergency airfield" }, + .{ .acronym = "CATBRG", .code = 1, .value = "fixed bridge" }, + .{ .acronym = "CATBRG", .code = 2, .value = "opening bridge" }, + .{ .acronym = "CATBRG", .code = 3, .value = "swing bridge" }, + .{ .acronym = "CATBRG", .code = 4, .value = "lifting bridge" }, + .{ .acronym = "CATBRG", .code = 5, .value = "bascule bridge" }, + .{ .acronym = "CATBRG", .code = 6, .value = "pontoon bridge" }, + .{ .acronym = "CATBRG", .code = 7, .value = "draw bridge" }, + .{ .acronym = "CATBRG", .code = 8, .value = "transporter bridge" }, + .{ .acronym = "CATBRG", .code = 9, .value = "footbridge" }, + .{ .acronym = "CATBRG", .code = 10, .value = "viaduct" }, + .{ .acronym = "CATBRG", .code = 11, .value = "aqueduct" }, + .{ .acronym = "CATBRG", .code = 12, .value = "suspension bridge" }, + .{ .acronym = "CATBUA", .code = 1, .value = "urban area" }, + .{ .acronym = "CATBUA", .code = 2, .value = "settlement" }, + .{ .acronym = "CATBUA", .code = 3, .value = "village" }, + .{ .acronym = "CATBUA", .code = 4, .value = "town" }, + .{ .acronym = "CATBUA", .code = 5, .value = "city" }, + .{ .acronym = "CATBUA", .code = 6, .value = "holiday village" }, + .{ .acronym = "CATCAM", .code = 1, .value = "north cardinal mark" }, + .{ .acronym = "CATCAM", .code = 2, .value = "east cardinal mark" }, + .{ .acronym = "CATCAM", .code = 3, .value = "south cardinal mark" }, + .{ .acronym = "CATCAM", .code = 4, .value = "west cardinal mark" }, + .{ .acronym = "CATCAN", .code = 1, .value = "transportation" }, + .{ .acronym = "CATCAN", .code = 2, .value = "drainage" }, + .{ .acronym = "CATCAN", .code = 3, .value = "irrigation" }, + .{ .acronym = "CATCBL", .code = 1, .value = "power line" }, + .{ .acronym = "CATCBL", .code = 2, .value = "telephone/telegraph" }, + .{ .acronym = "CATCBL", .code = 3, .value = "transmission line" }, + .{ .acronym = "CATCBL", .code = 4, .value = "telephone" }, + .{ .acronym = "CATCBL", .code = 5, .value = "telegraph" }, + .{ .acronym = "CATCBL", .code = 6, .value = "mooring cable/chain" }, + .{ .acronym = "CATCHP", .code = 1, .value = "custom" }, + .{ .acronym = "CATCOA", .code = 1, .value = "steep coast" }, + .{ .acronym = "CATCOA", .code = 2, .value = "flat coast" }, + .{ .acronym = "CATCOA", .code = 3, .value = "sandy shore" }, + .{ .acronym = "CATCOA", .code = 4, .value = "stony shore" }, + .{ .acronym = "CATCOA", .code = 5, .value = "shingly shore" }, + .{ .acronym = "CATCOA", .code = 6, .value = "glacier (seaward end)" }, + .{ .acronym = "CATCOA", .code = 7, .value = "mangrove" }, + .{ .acronym = "CATCOA", .code = 8, .value = "marshy shore" }, + .{ .acronym = "CATCOA", .code = 9, .value = "coral reef" }, + .{ .acronym = "CATCOA", .code = 10, .value = "ice coast" }, + .{ .acronym = "CATCOA", .code = 11, .value = "shelly shore" }, + .{ .acronym = "CATCON", .code = 1, .value = "aerial cableway (telepheric)" }, + .{ .acronym = "CATCON", .code = 2, .value = "belt conveyor" }, + .{ .acronym = "CATCOV", .code = 1, .value = "coverage available" }, + .{ .acronym = "CATCOV", .code = 2, .value = "no coverage available" }, + .{ .acronym = "CATCRN", .code = 1, .value = "crane without specific construction" }, + .{ .acronym = "CATCRN", .code = 2, .value = "container crane/gantry" }, + .{ .acronym = "CATCRN", .code = 3, .value = "sheerlegs" }, + .{ .acronym = "CATCRN", .code = 4, .value = "travelling crane" }, + .{ .acronym = "CATCRN", .code = 5, .value = "A-frame" }, + .{ .acronym = "CATCTR", .code = 1, .value = "triangulation point" }, + .{ .acronym = "CATCTR", .code = 2, .value = "observation spot" }, + .{ .acronym = "CATCTR", .code = 3, .value = "fixed point" }, + .{ .acronym = "CATCTR", .code = 4, .value = "bench-mark" }, + .{ .acronym = "CATCTR", .code = 5, .value = "boundary mark" }, + .{ .acronym = "CATCTR", .code = 6, .value = "horizontal control, main station" }, + .{ .acronym = "CATCTR", .code = 7, .value = "horizontal control, secondary station" }, + .{ .acronym = "CATDAM", .code = 1, .value = "weir" }, + .{ .acronym = "CATDAM", .code = 2, .value = "dam" }, + .{ .acronym = "CATDAM", .code = 3, .value = "flood barrage" }, + .{ .acronym = "CATDIS", .code = 1, .value = "distance mark not physically installed" }, + .{ .acronym = "CATDIS", .code = 2, .value = "visible mark, pole" }, + .{ .acronym = "CATDIS", .code = 3, .value = "visible mark, board" }, + .{ .acronym = "CATDIS", .code = 4, .value = "visible mark, unknown shape" }, + .{ .acronym = "CATDOC", .code = 1, .value = "tidal" }, + .{ .acronym = "CATDOC", .code = 2, .value = "non-tidal (wet dock)" }, + .{ .acronym = "CATDPG", .code = 1, .value = "general dumping ground" }, + .{ .acronym = "CATDPG", .code = 2, .value = "chemical waste dumping ground" }, + .{ .acronym = "CATDPG", .code = 3, .value = "nuclear waste dumping ground" }, + .{ .acronym = "CATDPG", .code = 4, .value = "explosives dumping ground" }, + .{ .acronym = "CATDPG", .code = 5, .value = "spoil ground" }, + .{ .acronym = "CATDPG", .code = 6, .value = "vessel dumping ground" }, + .{ .acronym = "CATFIF", .code = 1, .value = "fishing stake" }, + .{ .acronym = "CATFIF", .code = 2, .value = "fish trap" }, + .{ .acronym = "CATFIF", .code = 3, .value = "fish weir" }, + .{ .acronym = "CATFIF", .code = 4, .value = "tunny net" }, + .{ .acronym = "CATFNC", .code = 1, .value = "fence" }, + .{ .acronym = "CATFNC", .code = 2, .value = "muir" }, + .{ .acronym = "CATFNC", .code = 3, .value = "hedge" }, + .{ .acronym = "CATFNC", .code = 4, .value = "wall" }, + .{ .acronym = "CATFOG", .code = 1, .value = "explosive" }, + .{ .acronym = "CATFOG", .code = 2, .value = "diaphone" }, + .{ .acronym = "CATFOG", .code = 3, .value = "siren" }, + .{ .acronym = "CATFOG", .code = 4, .value = "nautophone" }, + .{ .acronym = "CATFOG", .code = 5, .value = "reed" }, + .{ .acronym = "CATFOG", .code = 6, .value = "tyfon" }, + .{ .acronym = "CATFOG", .code = 7, .value = "bell" }, + .{ .acronym = "CATFOG", .code = 8, .value = "whistle" }, + .{ .acronym = "CATFOG", .code = 9, .value = "gong" }, + .{ .acronym = "CATFOG", .code = 10, .value = "horn" }, + .{ .acronym = "CATFOR", .code = 1, .value = "castle" }, + .{ .acronym = "CATFOR", .code = 2, .value = "fort" }, + .{ .acronym = "CATFOR", .code = 3, .value = "battery" }, + .{ .acronym = "CATFOR", .code = 4, .value = "blockhouse" }, + .{ .acronym = "CATFOR", .code = 5, .value = "Martello tower" }, + .{ .acronym = "CATFOR", .code = 6, .value = "redoubt" }, + .{ .acronym = "CATFRY", .code = 1, .value = "'free-moving' ferry" }, + .{ .acronym = "CATFRY", .code = 2, .value = "cable ferry" }, + .{ .acronym = "CATFRY", .code = 3, .value = "ice ferry" }, + .{ .acronym = "CATGAT", .code = 1, .value = "gate in general" }, + .{ .acronym = "CATGAT", .code = 2, .value = "flood barrage gate" }, + .{ .acronym = "CATGAT", .code = 3, .value = "caisson" }, + .{ .acronym = "CATGAT", .code = 4, .value = "lock gate" }, + .{ .acronym = "CATGAT", .code = 5, .value = "dyke gate" }, + .{ .acronym = "CATGAT", .code = 6, .value = "sluice" }, + .{ .acronym = "CATHLK", .code = 1, .value = "floating restaurant" }, + .{ .acronym = "CATHLK", .code = 2, .value = "historic ship" }, + .{ .acronym = "CATHLK", .code = 3, .value = "museum" }, + .{ .acronym = "CATHLK", .code = 4, .value = "accommodation" }, + .{ .acronym = "CATHLK", .code = 5, .value = "floating breakwater" }, + .{ .acronym = "CATICE", .code = 1, .value = "fast ice" }, + .{ .acronym = "CATICE", .code = 2, .value = "sea ice" }, + .{ .acronym = "CATICE", .code = 3, .value = "growler area" }, + .{ .acronym = "CATICE", .code = 4, .value = "pancake ice" }, + .{ .acronym = "CATICE", .code = 5, .value = "glacier" }, + .{ .acronym = "CATICE", .code = 6, .value = "ice peak" }, + .{ .acronym = "CATICE", .code = 7, .value = "pack ice" }, + .{ .acronym = "CATICE", .code = 8, .value = "polar ice" }, + .{ .acronym = "CATINB", .code = 1, .value = "catenary anchor leg mooring (CALM)" }, + .{ .acronym = "CATINB", .code = 2, .value = "single buoy mooring (SBM or SPM)" }, + .{ .acronym = "CATLAM", .code = 1, .value = "port-hand lateral mark" }, + .{ .acronym = "CATLAM", .code = 2, .value = "starboard-hand lateral mark" }, + .{ .acronym = "CATLAM", .code = 3, .value = "preferred channel to starboard lateral mark" }, + .{ .acronym = "CATLAM", .code = 4, .value = "preferred channel to port lateral mark" }, + .{ .acronym = "CATLIT", .code = 1, .value = "directional function" }, + .{ .acronym = "CATLIT", .code = 2, .value = "rear/upper light" }, + .{ .acronym = "CATLIT", .code = 3, .value = "front/lower light" }, + .{ .acronym = "CATLIT", .code = 4, .value = "leading light" }, + .{ .acronym = "CATLIT", .code = 5, .value = "aero light" }, + .{ .acronym = "CATLIT", .code = 6, .value = "air obstruction light" }, + .{ .acronym = "CATLIT", .code = 7, .value = "fog detector light" }, + .{ .acronym = "CATLIT", .code = 8, .value = "flood light" }, + .{ .acronym = "CATLIT", .code = 9, .value = "strip light" }, + .{ .acronym = "CATLIT", .code = 10, .value = "subsidiary light" }, + .{ .acronym = "CATLIT", .code = 11, .value = "spotlight" }, + .{ .acronym = "CATLIT", .code = 12, .value = "front" }, + .{ .acronym = "CATLIT", .code = 13, .value = "rear" }, + .{ .acronym = "CATLIT", .code = 14, .value = "lower" }, + .{ .acronym = "CATLIT", .code = 15, .value = "upper" }, + .{ .acronym = "CATLIT", .code = 16, .value = "moiré effect" }, + .{ .acronym = "CATLIT", .code = 17, .value = "emergency" }, + .{ .acronym = "CATLIT", .code = 18, .value = "bearing light" }, + .{ .acronym = "CATLIT", .code = 19, .value = "horizontally disposed" }, + .{ .acronym = "CATLIT", .code = 20, .value = "vertically disposed" }, + .{ .acronym = "CATLMK", .code = 1, .value = "cairn" }, + .{ .acronym = "CATLMK", .code = 2, .value = "cemetery" }, + .{ .acronym = "CATLMK", .code = 3, .value = "chimney" }, + .{ .acronym = "CATLMK", .code = 4, .value = "dish aerial" }, + .{ .acronym = "CATLMK", .code = 5, .value = "flagstaff (flagpole)" }, + .{ .acronym = "CATLMK", .code = 6, .value = "flare stack" }, + .{ .acronym = "CATLMK", .code = 7, .value = "mast" }, + .{ .acronym = "CATLMK", .code = 8, .value = "windsock" }, + .{ .acronym = "CATLMK", .code = 9, .value = "monument" }, + .{ .acronym = "CATLMK", .code = 10, .value = "column (pillar)" }, + .{ .acronym = "CATLMK", .code = 11, .value = "memorial plaque" }, + .{ .acronym = "CATLMK", .code = 12, .value = "obelisk" }, + .{ .acronym = "CATLMK", .code = 13, .value = "statue" }, + .{ .acronym = "CATLMK", .code = 14, .value = "cross" }, + .{ .acronym = "CATLMK", .code = 15, .value = "dome" }, + .{ .acronym = "CATLMK", .code = 16, .value = "radar scanner" }, + .{ .acronym = "CATLMK", .code = 17, .value = "tower" }, + .{ .acronym = "CATLMK", .code = 18, .value = "windmill" }, + .{ .acronym = "CATLMK", .code = 19, .value = "windmotor" }, + .{ .acronym = "CATLMK", .code = 20, .value = "spire/minaret" }, + .{ .acronym = "CATLMK", .code = 21, .value = "large rock or boulder on land" }, + .{ .acronym = "CATLND", .code = 1, .value = "fen" }, + .{ .acronym = "CATLND", .code = 2, .value = "marsh" }, + .{ .acronym = "CATLND", .code = 3, .value = "moor/bog" }, + .{ .acronym = "CATLND", .code = 4, .value = "heathland" }, + .{ .acronym = "CATLND", .code = 5, .value = "mountain range" }, + .{ .acronym = "CATLND", .code = 6, .value = "lowlands" }, + .{ .acronym = "CATLND", .code = 7, .value = "canyon lands" }, + .{ .acronym = "CATLND", .code = 8, .value = "paddy field" }, + .{ .acronym = "CATLND", .code = 9, .value = "agricultural land" }, + .{ .acronym = "CATLND", .code = 10, .value = "savanna/grassland" }, + .{ .acronym = "CATLND", .code = 11, .value = "parkland" }, + .{ .acronym = "CATLND", .code = 12, .value = "swamp" }, + .{ .acronym = "CATLND", .code = 13, .value = "landslide" }, + .{ .acronym = "CATLND", .code = 14, .value = "lava flow" }, + .{ .acronym = "CATLND", .code = 15, .value = "salt pan" }, + .{ .acronym = "CATLND", .code = 16, .value = "moraine" }, + .{ .acronym = "CATLND", .code = 17, .value = "crater" }, + .{ .acronym = "CATLND", .code = 18, .value = "cave" }, + .{ .acronym = "CATLND", .code = 19, .value = "rock column or pinnacle" }, + .{ .acronym = "CATLND", .code = 20, .value = "cay" }, + .{ .acronym = "CATMFA", .code = 1, .value = "crustaceans" }, + .{ .acronym = "CATMFA", .code = 2, .value = "oysters/mussels" }, + .{ .acronym = "CATMFA", .code = 3, .value = "fish" }, + .{ .acronym = "CATMFA", .code = 4, .value = "seaweed" }, + .{ .acronym = "CATMFA", .code = 5, .value = "pearl culture farm" }, + .{ .acronym = "CATMOR", .code = 1, .value = "dolphin" }, + .{ .acronym = "CATMOR", .code = 2, .value = "deviation dolphin" }, + .{ .acronym = "CATMOR", .code = 3, .value = "bollard" }, + .{ .acronym = "CATMOR", .code = 4, .value = "tie-up wall" }, + .{ .acronym = "CATMOR", .code = 5, .value = "post or pile" }, + .{ .acronym = "CATMOR", .code = 6, .value = "chain/wire/cable" }, + .{ .acronym = "CATMOR", .code = 7, .value = "mooring buoy" }, + .{ .acronym = "CATMPA", .code = 1, .value = "practice area in general" }, + .{ .acronym = "CATMPA", .code = 2, .value = "torpedo exercise area" }, + .{ .acronym = "CATMPA", .code = 3, .value = "submarine exercise area" }, + .{ .acronym = "CATMPA", .code = 4, .value = "firing danger area" }, + .{ .acronym = "CATMPA", .code = 5, .value = "mine-laying practice area" }, + .{ .acronym = "CATMPA", .code = 6, .value = "small arms firing range" }, + .{ .acronym = "CATNAV", .code = 1, .value = "clearing line" }, + .{ .acronym = "CATNAV", .code = 2, .value = "transit line" }, + .{ .acronym = "CATNAV", .code = 3, .value = "leading line bearing a recommended track" }, + .{ .acronym = "CATOBS", .code = 1, .value = "snag/stump" }, + .{ .acronym = "CATOBS", .code = 2, .value = "wellhead" }, + .{ .acronym = "CATOBS", .code = 3, .value = "diffuser" }, + .{ .acronym = "CATOBS", .code = 4, .value = "crib" }, + .{ .acronym = "CATOBS", .code = 5, .value = "fish haven" }, + .{ .acronym = "CATOBS", .code = 6, .value = "foul area" }, + .{ .acronym = "CATOBS", .code = 7, .value = "foul ground" }, + .{ .acronym = "CATOBS", .code = 8, .value = "ice boom" }, + .{ .acronym = "CATOBS", .code = 9, .value = "ground tackle" }, + .{ .acronym = "CATOBS", .code = 10, .value = "boom" }, + .{ .acronym = "CATOFP", .code = 1, .value = "oil derrick/rig" }, + .{ .acronym = "CATOFP", .code = 2, .value = "production platform" }, + .{ .acronym = "CATOFP", .code = 3, .value = "observation/research platform" }, + .{ .acronym = "CATOFP", .code = 4, .value = "articulated loading platform (ALP)" }, + .{ .acronym = "CATOFP", .code = 5, .value = "single anchor leg mooring (SALM)" }, + .{ .acronym = "CATOFP", .code = 6, .value = "mooring tower" }, + .{ .acronym = "CATOFP", .code = 7, .value = "artificial island" }, + .{ + .acronym = "CATOFP", + .code = 8, + .value = "floating production, storage and off-loading vessel (FPSO)", + }, + .{ .acronym = "CATOFP", .code = 9, .value = "accommodation platform" }, + .{ + .acronym = "CATOFP", + .code = 10, + .value = "navigation, communication and control buoy (NCCB)", + }, + .{ .acronym = "CATOLB", .code = 1, .value = "oil retention (high pressure pipe)" }, + .{ .acronym = "CATOLB", .code = 2, .value = "floating oil barrier" }, + .{ .acronym = "CATPIL", .code = 1, .value = "boarding by pilot-cruising vessel" }, + .{ .acronym = "CATPIL", .code = 2, .value = "boarding by helicopter" }, + .{ .acronym = "CATPIL", .code = 3, .value = "pilot comes out from shore" }, + .{ .acronym = "CATPIP", .code = 1, .value = "pipeline in general" }, + .{ .acronym = "CATPIP", .code = 2, .value = "outfall pipe" }, + .{ .acronym = "CATPIP", .code = 3, .value = "intake pipe" }, + .{ .acronym = "CATPIP", .code = 4, .value = "sewer" }, + .{ .acronym = "CATPIP", .code = 5, .value = "bubbler system" }, + .{ .acronym = "CATPIP", .code = 6, .value = "supply pipe" }, + .{ .acronym = "CATPLE", .code = 1, .value = "stake" }, + .{ .acronym = "CATPLE", .code = 2, .value = "snag" }, + .{ .acronym = "CATPLE", .code = 3, .value = "post" }, + .{ .acronym = "CATPLE", .code = 4, .value = "tripodal" }, + .{ .acronym = "CATPRA", .code = 1, .value = "quarry" }, + .{ .acronym = "CATPRA", .code = 2, .value = "mine" }, + .{ .acronym = "CATPRA", .code = 3, .value = "stockpile" }, + .{ .acronym = "CATPRA", .code = 4, .value = "power station area" }, + .{ .acronym = "CATPRA", .code = 5, .value = "refinery area" }, + .{ .acronym = "CATPRA", .code = 6, .value = "timber yard" }, + .{ .acronym = "CATPRA", .code = 7, .value = "factory area" }, + .{ .acronym = "CATPRA", .code = 8, .value = "tank farm" }, + .{ .acronym = "CATPRA", .code = 9, .value = "wind farm" }, + .{ .acronym = "CATPRA", .code = 10, .value = "slag heap/spoil heap" }, + .{ .acronym = "CATPYL", .code = 1, .value = "power transmission pylon/pole" }, + .{ .acronym = "CATPYL", .code = 2, .value = "telephone/telegraph pylon/pole" }, + .{ .acronym = "CATPYL", .code = 3, .value = "aerial cableway/sky pylon" }, + .{ .acronym = "CATPYL", .code = 4, .value = "bridge pylon/tower" }, + .{ .acronym = "CATPYL", .code = 5, .value = "bridge pier" }, + .{ .acronym = "CATQUA", .code = 1, .value = "data quality A" }, + .{ .acronym = "CATQUA", .code = 2, .value = "data quality B" }, + .{ .acronym = "CATQUA", .code = 3, .value = "data quality C" }, + .{ .acronym = "CATQUA", .code = 4, .value = "data quality D" }, + .{ .acronym = "CATQUA", .code = 5, .value = "data quality E" }, + .{ .acronym = "CATQUA", .code = 6, .value = "quality not evaluated" }, + .{ .acronym = "CATRAS", .code = 1, .value = "radar surveillance station" }, + .{ .acronym = "CATRAS", .code = 2, .value = "coast radar station" }, + .{ .acronym = "CATREA", .code = 1, .value = "offshore safety zone" }, + .{ .acronym = "CATREA", .code = 2, .value = "anchoring prohibition area" }, + .{ .acronym = "CATREA", .code = 3, .value = "fishing prohibition area" }, + .{ .acronym = "CATREA", .code = 4, .value = "nature reserve" }, + .{ .acronym = "CATREA", .code = 5, .value = "bird sanctuary" }, + .{ .acronym = "CATREA", .code = 6, .value = "game reserve" }, + .{ .acronym = "CATREA", .code = 7, .value = "seal sanctuary" }, + .{ .acronym = "CATREA", .code = 8, .value = "degaussing range" }, + .{ .acronym = "CATREA", .code = 9, .value = "military area" }, + .{ .acronym = "CATREA", .code = 10, .value = "historic wreck area" }, + .{ .acronym = "CATREA", .code = 11, .value = "inshore traffic zone" }, + .{ .acronym = "CATREA", .code = 12, .value = "navigational aid safety zone" }, + .{ .acronym = "CATREA", .code = 13, .value = "danger of stranding area" }, + .{ .acronym = "CATREA", .code = 14, .value = "minefield" }, + .{ .acronym = "CATREA", .code = 15, .value = "diving prohibition area" }, + .{ .acronym = "CATREA", .code = 16, .value = "area to be avoided" }, + .{ .acronym = "CATREA", .code = 17, .value = "prohibited area" }, + .{ .acronym = "CATREA", .code = 18, .value = "swimming area" }, + .{ .acronym = "CATREA", .code = 19, .value = "waiting area" }, + .{ .acronym = "CATREA", .code = 20, .value = "research area" }, + .{ .acronym = "CATREA", .code = 21, .value = "dredging area" }, + .{ .acronym = "CATREA", .code = 22, .value = "fish sanctuary" }, + .{ .acronym = "CATREA", .code = 23, .value = "ecological reserve" }, + .{ .acronym = "CATREA", .code = 24, .value = "no wake area" }, + .{ .acronym = "CATREA", .code = 25, .value = "swinging area" }, + .{ .acronym = "CATREA", .code = 26, .value = "water skiing area" }, + .{ .acronym = "CATROD", .code = 1, .value = "motorway" }, + .{ .acronym = "CATROD", .code = 2, .value = "major road" }, + .{ .acronym = "CATROD", .code = 3, .value = "minor road" }, + .{ .acronym = "CATROD", .code = 4, .value = "track/path" }, + .{ .acronym = "CATROD", .code = 5, .value = "major street" }, + .{ .acronym = "CATROD", .code = 6, .value = "minor street" }, + .{ .acronym = "CATROD", .code = 7, .value = "crossing" }, + .{ + .acronym = "CATROS", + .code = 1, + .value = "circular (non-directional) marine or aero-marine radiobeacon", + }, + .{ .acronym = "CATROS", .code = 2, .value = "directional radiobeacon" }, + .{ .acronym = "CATROS", .code = 3, .value = "rotating-pattern radiobeacon" }, + .{ .acronym = "CATROS", .code = 4, .value = "Consol beacon" }, + .{ .acronym = "CATROS", .code = 5, .value = "radio direction-finding station" }, + .{ .acronym = "CATROS", .code = 6, .value = "coast radio station providing QTG service" }, + .{ .acronym = "CATROS", .code = 7, .value = "aeronautical radiobeacon" }, + .{ .acronym = "CATROS", .code = 8, .value = "Decca" }, + .{ .acronym = "CATROS", .code = 9, .value = "Loran C" }, + .{ .acronym = "CATROS", .code = 10, .value = "Differential GPS" }, + .{ .acronym = "CATROS", .code = 11, .value = "Toran" }, + .{ .acronym = "CATROS", .code = 12, .value = "Omega" }, + .{ .acronym = "CATROS", .code = 13, .value = "Syledis" }, + .{ .acronym = "CATROS", .code = 14, .value = "Chaika (Chayka)" }, + .{ .acronym = "CATRSC", .code = 1, .value = "rescue station with lifeboat" }, + .{ .acronym = "CATRSC", .code = 2, .value = "rescue station with rocket" }, + .{ .acronym = "CATRSC", .code = 3, .value = "rescue station with lifeboat and rocket" }, + .{ .acronym = "CATRSC", .code = 4, .value = "refuge for shipwrecked mariners" }, + .{ .acronym = "CATRSC", .code = 5, .value = "refuge for intertidal area walkers" }, + .{ .acronym = "CATRSC", .code = 6, .value = "lifeboat lying at a mooring" }, + .{ .acronym = "CATRSC", .code = 7, .value = "aid radio station" }, + .{ .acronym = "CATRSC", .code = 8, .value = "first aid equipment" }, + .{ .acronym = "CATRTB", .code = 1, .value = "ramark, radar beacon transmitting continuously" }, + .{ .acronym = "CATRTB", .code = 2, .value = "racon, radar transponder beacon" }, + .{ .acronym = "CATRTB", .code = 3, .value = "leading racon/radar transponder beacon" }, + .{ .acronym = "CATRUN", .code = 1, .value = "aeroplane runway" }, + .{ .acronym = "CATRUN", .code = 2, .value = "helicopter landing pad" }, + .{ .acronym = "CATSCF", .code = 1, .value = "visitor's berth" }, + .{ .acronym = "CATSCF", .code = 2, .value = "nautical club" }, + .{ .acronym = "CATSCF", .code = 3, .value = "boat hoist" }, + .{ .acronym = "CATSCF", .code = 4, .value = "sailmaker" }, + .{ .acronym = "CATSCF", .code = 5, .value = "boatyard" }, + .{ .acronym = "CATSCF", .code = 6, .value = "public inn" }, + .{ .acronym = "CATSCF", .code = 7, .value = "restaurant" }, + .{ .acronym = "CATSCF", .code = 8, .value = "chandler" }, + .{ .acronym = "CATSCF", .code = 9, .value = "provisions" }, + .{ .acronym = "CATSCF", .code = 10, .value = "doctor" }, + .{ .acronym = "CATSCF", .code = 11, .value = "pharmacy" }, + .{ .acronym = "CATSCF", .code = 12, .value = "water tap" }, + .{ .acronym = "CATSCF", .code = 13, .value = "fuel station" }, + .{ .acronym = "CATSCF", .code = 14, .value = "electricity" }, + .{ .acronym = "CATSCF", .code = 15, .value = "bottle gas" }, + .{ .acronym = "CATSCF", .code = 16, .value = "showers" }, + .{ .acronym = "CATSCF", .code = 17, .value = "launderette" }, + .{ .acronym = "CATSCF", .code = 18, .value = "public toilets" }, + .{ .acronym = "CATSCF", .code = 19, .value = "post box" }, + .{ .acronym = "CATSCF", .code = 20, .value = "public telephone" }, + .{ .acronym = "CATSCF", .code = 21, .value = "refuse bin" }, + .{ .acronym = "CATSCF", .code = 22, .value = "car park" }, + .{ .acronym = "CATSCF", .code = 23, .value = "parking for boats and trailers" }, + .{ .acronym = "CATSCF", .code = 24, .value = "caravan site" }, + .{ .acronym = "CATSCF", .code = 25, .value = "camping site" }, + .{ .acronym = "CATSCF", .code = 26, .value = "sewerage pump-out station" }, + .{ .acronym = "CATSCF", .code = 27, .value = "emergency telephone" }, + .{ .acronym = "CATSCF", .code = 28, .value = "landing/launching place for boats" }, + .{ .acronym = "CATSCF", .code = 29, .value = "visitors mooring" }, + .{ .acronym = "CATSCF", .code = 30, .value = "scrubbing berth" }, + .{ .acronym = "CATSCF", .code = 31, .value = "picnic area" }, + .{ .acronym = "CATSCF", .code = 32, .value = "mechanics workshop" }, + .{ .acronym = "CATSCF", .code = 33, .value = "guard and/or security service" }, + .{ .acronym = "CATSEA", .code = 1, .value = "sea area in general" }, + .{ .acronym = "CATSEA", .code = 2, .value = "gat" }, + .{ .acronym = "CATSEA", .code = 3, .value = "bank" }, + .{ .acronym = "CATSEA", .code = 4, .value = "deep" }, + .{ .acronym = "CATSEA", .code = 5, .value = "bay" }, + .{ .acronym = "CATSEA", .code = 6, .value = "trench" }, + .{ .acronym = "CATSEA", .code = 7, .value = "basin" }, + .{ .acronym = "CATSEA", .code = 8, .value = "mud flats" }, + .{ .acronym = "CATSEA", .code = 9, .value = "reef" }, + .{ .acronym = "CATSEA", .code = 10, .value = "ledge" }, + .{ .acronym = "CATSEA", .code = 11, .value = "canyon" }, + .{ .acronym = "CATSEA", .code = 12, .value = "narrows" }, + .{ .acronym = "CATSEA", .code = 13, .value = "shoal" }, + .{ .acronym = "CATSEA", .code = 14, .value = "knoll" }, + .{ .acronym = "CATSEA", .code = 15, .value = "ridge" }, + .{ .acronym = "CATSEA", .code = 16, .value = "seamount" }, + .{ .acronym = "CATSEA", .code = 17, .value = "pinnacle" }, + .{ .acronym = "CATSEA", .code = 18, .value = "abyssal plain" }, + .{ .acronym = "CATSEA", .code = 19, .value = "plateau" }, + .{ .acronym = "CATSEA", .code = 20, .value = "spur" }, + .{ .acronym = "CATSEA", .code = 21, .value = "shelf" }, + .{ .acronym = "CATSEA", .code = 22, .value = "trough" }, + .{ .acronym = "CATSEA", .code = 23, .value = "saddle" }, + .{ .acronym = "CATSEA", .code = 24, .value = "abyssal hills" }, + .{ .acronym = "CATSEA", .code = 25, .value = "apron" }, + .{ .acronym = "CATSEA", .code = 26, .value = "archipelagic apron" }, + .{ .acronym = "CATSEA", .code = 27, .value = "borderland" }, + .{ .acronym = "CATSEA", .code = 28, .value = "continental margin" }, + .{ .acronym = "CATSEA", .code = 29, .value = "continental rise" }, + .{ .acronym = "CATSEA", .code = 30, .value = "escarpment" }, + .{ .acronym = "CATSEA", .code = 31, .value = "fan" }, + .{ .acronym = "CATSEA", .code = 32, .value = "fracture zone" }, + .{ .acronym = "CATSEA", .code = 33, .value = "gap" }, + .{ .acronym = "CATSEA", .code = 34, .value = "guyot" }, + .{ .acronym = "CATSEA", .code = 35, .value = "hill" }, + .{ .acronym = "CATSEA", .code = 36, .value = "hole" }, + .{ .acronym = "CATSEA", .code = 37, .value = "levee" }, + .{ .acronym = "CATSEA", .code = 38, .value = "median valley" }, + .{ .acronym = "CATSEA", .code = 39, .value = "moat" }, + .{ .acronym = "CATSEA", .code = 40, .value = "mountains" }, + .{ .acronym = "CATSEA", .code = 41, .value = "peak" }, + .{ .acronym = "CATSEA", .code = 42, .value = "province" }, + .{ .acronym = "CATSEA", .code = 43, .value = "rise" }, + .{ .acronym = "CATSEA", .code = 44, .value = "sea channel" }, + .{ .acronym = "CATSEA", .code = 45, .value = "seamount chain" }, + .{ .acronym = "CATSEA", .code = 46, .value = "shelf-edge" }, + .{ .acronym = "CATSEA", .code = 47, .value = "sill" }, + .{ .acronym = "CATSEA", .code = 48, .value = "slope" }, + .{ .acronym = "CATSEA", .code = 49, .value = "terrace" }, + .{ .acronym = "CATSEA", .code = 50, .value = "valley" }, + .{ .acronym = "CATSEA", .code = 51, .value = "canal" }, + .{ .acronym = "CATSEA", .code = 52, .value = "lake" }, + .{ .acronym = "CATSEA", .code = 53, .value = "river" }, + .{ .acronym = "CATSEA", .code = 54, .value = "reach" }, + .{ .acronym = "CATSIL", .code = 1, .value = "silo in general" }, + .{ .acronym = "CATSIL", .code = 2, .value = "tank in general" }, + .{ .acronym = "CATSIL", .code = 3, .value = "grain elevator" }, + .{ .acronym = "CATSIL", .code = 4, .value = "water tower" }, + .{ .acronym = "CATSIT", .code = 1, .value = "port control" }, + .{ .acronym = "CATSIT", .code = 2, .value = "port entry and departure" }, + .{ .acronym = "CATSIT", .code = 3, .value = "International Port Traffic" }, + .{ .acronym = "CATSIT", .code = 4, .value = "berthing" }, + .{ .acronym = "CATSIT", .code = 5, .value = "dock" }, + .{ .acronym = "CATSIT", .code = 6, .value = "lock" }, + .{ .acronym = "CATSIT", .code = 7, .value = "flood barrage" }, + .{ .acronym = "CATSIT", .code = 8, .value = "bridge passage" }, + .{ .acronym = "CATSIT", .code = 9, .value = "dredging" }, + .{ .acronym = "CATSIT", .code = 10, .value = "traffic control light" }, + .{ .acronym = "CATSIW", .code = 1, .value = "danger" }, + .{ .acronym = "CATSIW", .code = 2, .value = "maritime obstruction" }, + .{ .acronym = "CATSIW", .code = 3, .value = "cable" }, + .{ .acronym = "CATSIW", .code = 4, .value = "military practice" }, + .{ .acronym = "CATSIW", .code = 5, .value = "distress" }, + .{ .acronym = "CATSIW", .code = 6, .value = "weather" }, + .{ .acronym = "CATSIW", .code = 7, .value = "storm" }, + .{ .acronym = "CATSIW", .code = 8, .value = "ice" }, + .{ .acronym = "CATSIW", .code = 9, .value = "time" }, + .{ .acronym = "CATSIW", .code = 10, .value = "tide" }, + .{ .acronym = "CATSIW", .code = 11, .value = "tidal stream" }, + .{ .acronym = "CATSIW", .code = 12, .value = "tide gauge" }, + .{ .acronym = "CATSIW", .code = 13, .value = "tide scale" }, + .{ .acronym = "CATSIW", .code = 14, .value = "diving" }, + .{ .acronym = "CATSIW", .code = 15, .value = "water level gauge" }, + .{ .acronym = "CATSLC", .code = 1, .value = "breakwater" }, + .{ .acronym = "CATSLC", .code = 2, .value = "groyne (groin)" }, + .{ .acronym = "CATSLC", .code = 3, .value = "mole" }, + .{ .acronym = "CATSLC", .code = 4, .value = "pier (jetty)" }, + .{ .acronym = "CATSLC", .code = 5, .value = "promenade pier" }, + .{ .acronym = "CATSLC", .code = 6, .value = "wharf (quay)" }, + .{ .acronym = "CATSLC", .code = 7, .value = "training wall" }, + .{ .acronym = "CATSLC", .code = 8, .value = "rip rap" }, + .{ .acronym = "CATSLC", .code = 9, .value = "revetment" }, + .{ .acronym = "CATSLC", .code = 10, .value = "sea wall" }, + .{ .acronym = "CATSLC", .code = 11, .value = "landing steps" }, + .{ .acronym = "CATSLC", .code = 12, .value = "ramp" }, + .{ .acronym = "CATSLC", .code = 13, .value = "slipway" }, + .{ .acronym = "CATSLC", .code = 14, .value = "fender" }, + .{ .acronym = "CATSLC", .code = 15, .value = "solid face wharf" }, + .{ .acronym = "CATSLC", .code = 16, .value = "open face wharf" }, + .{ .acronym = "CATSLC", .code = 17, .value = "log ramp" }, + .{ .acronym = "CATSLO", .code = 1, .value = "cutting" }, + .{ .acronym = "CATSLO", .code = 2, .value = "embankment" }, + .{ .acronym = "CATSLO", .code = 3, .value = "dune" }, + .{ .acronym = "CATSLO", .code = 4, .value = "hill" }, + .{ .acronym = "CATSLO", .code = 5, .value = "pingo" }, + .{ .acronym = "CATSLO", .code = 6, .value = "cliff" }, + .{ .acronym = "CATSLO", .code = 7, .value = "scree" }, + .{ .acronym = "CATSPM", .code = 1, .value = "firing danger area mark" }, + .{ .acronym = "CATSPM", .code = 2, .value = "target mark" }, + .{ .acronym = "CATSPM", .code = 3, .value = "marker ship mark" }, + .{ .acronym = "CATSPM", .code = 4, .value = "degaussing range mark" }, + .{ .acronym = "CATSPM", .code = 5, .value = "barge mark" }, + .{ .acronym = "CATSPM", .code = 6, .value = "cable mark" }, + .{ .acronym = "CATSPM", .code = 7, .value = "spoil ground mark" }, + .{ .acronym = "CATSPM", .code = 8, .value = "outfall mark" }, + .{ .acronym = "CATSPM", .code = 9, .value = "ODAS (Ocean-Data-Acquisition-System)" }, + .{ .acronym = "CATSPM", .code = 10, .value = "recording mark" }, + .{ .acronym = "CATSPM", .code = 11, .value = "seaplane anchorage mark" }, + .{ .acronym = "CATSPM", .code = 12, .value = "recreation zone mark" }, + .{ .acronym = "CATSPM", .code = 13, .value = "private mark" }, + .{ .acronym = "CATSPM", .code = 14, .value = "mooring mark" }, + .{ .acronym = "CATSPM", .code = 15, .value = "LANBY (Large Automatic Navigational Buoy)" }, + .{ .acronym = "CATSPM", .code = 16, .value = "leading mark" }, + .{ .acronym = "CATSPM", .code = 17, .value = "measured distance mark" }, + .{ .acronym = "CATSPM", .code = 18, .value = "notice mark" }, + .{ .acronym = "CATSPM", .code = 19, .value = "TSS mark (Traffic Separation Scheme)" }, + .{ .acronym = "CATSPM", .code = 20, .value = "anchoring prohibited mark" }, + .{ .acronym = "CATSPM", .code = 21, .value = "berthing prohibited mark" }, + .{ .acronym = "CATSPM", .code = 22, .value = "overtaking prohibited mark" }, + .{ .acronym = "CATSPM", .code = 23, .value = "two-way traffic prohibited mark" }, + .{ .acronym = "CATSPM", .code = 24, .value = "'reduced wake' mark" }, + .{ .acronym = "CATSPM", .code = 25, .value = "speed limit mark" }, + .{ .acronym = "CATSPM", .code = 26, .value = "stop mark" }, + .{ .acronym = "CATSPM", .code = 27, .value = "general warning mark" }, + .{ .acronym = "CATSPM", .code = 28, .value = "'sound ship's siren' mark" }, + .{ .acronym = "CATSPM", .code = 29, .value = "restricted vertical clearance mark" }, + .{ .acronym = "CATSPM", .code = 30, .value = "maximum vessel's draught mark" }, + .{ .acronym = "CATSPM", .code = 31, .value = "restricted horizontal clearance mark" }, + .{ .acronym = "CATSPM", .code = 32, .value = "strong current warning mark" }, + .{ .acronym = "CATSPM", .code = 33, .value = "berthing permitted mark" }, + .{ .acronym = "CATSPM", .code = 34, .value = "overhead power cable mark" }, + .{ .acronym = "CATSPM", .code = 35, .value = "'channel edge gradient' mark" }, + .{ .acronym = "CATSPM", .code = 36, .value = "telephone mark" }, + .{ .acronym = "CATSPM", .code = 37, .value = "ferry crossing mark" }, + .{ .acronym = "CATSPM", .code = 38, .value = "marine traffic lights" }, + .{ .acronym = "CATSPM", .code = 39, .value = "pipeline mark" }, + .{ .acronym = "CATSPM", .code = 40, .value = "anchorage mark" }, + .{ .acronym = "CATSPM", .code = 41, .value = "clearing mark" }, + .{ .acronym = "CATSPM", .code = 42, .value = "control mark" }, + .{ .acronym = "CATSPM", .code = 43, .value = "diving mark" }, + .{ .acronym = "CATSPM", .code = 44, .value = "refuge beacon" }, + .{ .acronym = "CATSPM", .code = 45, .value = "foul ground mark" }, + .{ .acronym = "CATSPM", .code = 46, .value = "yachting mark" }, + .{ .acronym = "CATSPM", .code = 47, .value = "heliport mark" }, + .{ .acronym = "CATSPM", .code = 48, .value = "GPS mark" }, + .{ .acronym = "CATSPM", .code = 49, .value = "seaplane landing mark" }, + .{ .acronym = "CATSPM", .code = 50, .value = "entry prohibited mark" }, + .{ .acronym = "CATSPM", .code = 51, .value = "work in progress mark" }, + .{ .acronym = "CATSPM", .code = 52, .value = "mark with unknown purpose" }, + .{ .acronym = "CATSPM", .code = 53, .value = "wellhead mark" }, + .{ .acronym = "CATSPM", .code = 54, .value = "channel separation mark" }, + .{ .acronym = "CATSPM", .code = 55, .value = "marine farm mark" }, + .{ .acronym = "CATSPM", .code = 56, .value = "artificial reef mark" }, + .{ .acronym = "CATTRK", .code = 1, .value = "based on a system of fixed marks" }, + .{ .acronym = "CATTRK", .code = 2, .value = "not based on a system of fixed marks" }, + .{ .acronym = "CATTSS", .code = 1, .value = "IMO - adopted" }, + .{ .acronym = "CATTSS", .code = 2, .value = "not IMO - adopted" }, + .{ .acronym = "CATVEG", .code = 1, .value = "grass" }, + .{ .acronym = "CATVEG", .code = 2, .value = "paddy field" }, + .{ .acronym = "CATVEG", .code = 3, .value = "bush" }, + .{ .acronym = "CATVEG", .code = 4, .value = "deciduous wood" }, + .{ .acronym = "CATVEG", .code = 5, .value = "coniferous wood" }, + .{ .acronym = "CATVEG", .code = 6, .value = "wood in general (inc mixed wood)" }, + .{ .acronym = "CATVEG", .code = 7, .value = "mangroves" }, + .{ .acronym = "CATVEG", .code = 8, .value = "park" }, + .{ .acronym = "CATVEG", .code = 9, .value = "parkland" }, + .{ .acronym = "CATVEG", .code = 10, .value = "mixed crops" }, + .{ .acronym = "CATVEG", .code = 11, .value = "reed" }, + .{ .acronym = "CATVEG", .code = 12, .value = "moss" }, + .{ .acronym = "CATVEG", .code = 13, .value = "tree in general" }, + .{ .acronym = "CATVEG", .code = 14, .value = "evergreen tree" }, + .{ .acronym = "CATVEG", .code = 15, .value = "coniferous tree" }, + .{ .acronym = "CATVEG", .code = 16, .value = "palm tree" }, + .{ .acronym = "CATVEG", .code = 17, .value = "nipa palm tree" }, + .{ .acronym = "CATVEG", .code = 18, .value = "casuarina tree" }, + .{ .acronym = "CATVEG", .code = 19, .value = "eucalypt tree" }, + .{ .acronym = "CATVEG", .code = 20, .value = "deciduous tree" }, + .{ .acronym = "CATVEG", .code = 21, .value = "mangrove tree" }, + .{ .acronym = "CATVEG", .code = 22, .value = "filao tree" }, + .{ .acronym = "CATWAT", .code = 1, .value = "breakers" }, + .{ .acronym = "CATWAT", .code = 2, .value = "eddies" }, + .{ .acronym = "CATWAT", .code = 3, .value = "overfalls" }, + .{ .acronym = "CATWAT", .code = 4, .value = "tide rips" }, + .{ .acronym = "CATWAT", .code = 5, .value = "bombora" }, + .{ .acronym = "CATWED", .code = 1, .value = "kelp" }, + .{ .acronym = "CATWED", .code = 2, .value = "sea weed" }, + .{ .acronym = "CATWED", .code = 3, .value = "sea grass" }, + .{ .acronym = "CATWED", .code = 4, .value = "saragasso" }, + .{ .acronym = "CATWRK", .code = 1, .value = "non-dangerous wreck" }, + .{ .acronym = "CATWRK", .code = 2, .value = "dangerous wreck" }, + .{ .acronym = "CATWRK", .code = 3, .value = "distributed remains of wreck" }, + .{ .acronym = "CATWRK", .code = 4, .value = "wreck showing mast/masts" }, + .{ + .acronym = "CATWRK", + .code = 5, + .value = "wreck showing any portion of hull or superstructure", + }, + .{ .acronym = "CATZOC", .code = 1, .value = "zone of confidence A1" }, + .{ .acronym = "CATZOC", .code = 2, .value = "zone of confidence A2" }, + .{ .acronym = "CATZOC", .code = 3, .value = "zone of confidence B" }, + .{ .acronym = "CATZOC", .code = 4, .value = "zone of confidence C" }, + .{ .acronym = "CATZOC", .code = 5, .value = "zone of confidence D" }, + .{ .acronym = "CATZOC", .code = 6, .value = "zone of confidence U (data not assessed)" }, + .{ .acronym = "CAT_TS", .code = 1, .value = "flood stream" }, + .{ .acronym = "CAT_TS", .code = 2, .value = "ebb stream" }, + .{ .acronym = "CAT_TS", .code = 3, .value = "other tidal flow" }, + .{ .acronym = "COLOUR", .code = 1, .value = "White" }, + .{ .acronym = "COLOUR", .code = 2, .value = "Black" }, + .{ .acronym = "COLOUR", .code = 3, .value = "Red" }, + .{ .acronym = "COLOUR", .code = 4, .value = "Green" }, + .{ .acronym = "COLOUR", .code = 5, .value = "Blue" }, + .{ .acronym = "COLOUR", .code = 6, .value = "Yellow" }, + .{ .acronym = "COLOUR", .code = 7, .value = "Grey" }, + .{ .acronym = "COLOUR", .code = 8, .value = "Brown" }, + .{ .acronym = "COLOUR", .code = 9, .value = "Amber" }, + .{ .acronym = "COLOUR", .code = 10, .value = "Violet" }, + .{ .acronym = "COLOUR", .code = 11, .value = "Orange" }, + .{ .acronym = "COLOUR", .code = 12, .value = "Magenta" }, + .{ .acronym = "COLOUR", .code = 13, .value = "Pink" }, + .{ .acronym = "COLPAT", .code = 1, .value = "horizontal stripes" }, + .{ .acronym = "COLPAT", .code = 2, .value = "vertical stripes" }, + .{ .acronym = "COLPAT", .code = 3, .value = "diagonal stripes" }, + .{ .acronym = "COLPAT", .code = 4, .value = "squared" }, + .{ .acronym = "COLPAT", .code = 5, .value = "stripes (direction unknown)" }, + .{ .acronym = "COLPAT", .code = 6, .value = "border stripe" }, + .{ .acronym = "CONDTN", .code = 1, .value = "under construction" }, + .{ .acronym = "CONDTN", .code = 2, .value = "ruined" }, + .{ .acronym = "CONDTN", .code = 3, .value = "under reclamation" }, + .{ .acronym = "CONDTN", .code = 4, .value = "wingless" }, + .{ .acronym = "CONDTN", .code = 5, .value = "planned construction" }, + .{ .acronym = "CONRAD", .code = 1, .value = "radar conspicuous" }, + .{ .acronym = "CONRAD", .code = 2, .value = "not radar conspicuous" }, + .{ .acronym = "CONRAD", .code = 3, .value = "radar conspicuous (has radar reflector)" }, + .{ .acronym = "CONVIS", .code = 1, .value = "visually conspicuous" }, + .{ .acronym = "CONVIS", .code = 2, .value = "not visually conspicuous" }, + .{ .acronym = "DUNITS", .code = 1, .value = "metres" }, + .{ .acronym = "DUNITS", .code = 2, .value = "fathoms and feet" }, + .{ .acronym = "DUNITS", .code = 3, .value = "feet" }, + .{ .acronym = "DUNITS", .code = 4, .value = "fathoms and fractions" }, + .{ .acronym = "EXCLIT", .code = 1, .value = "light shown without change of character" }, + .{ .acronym = "EXCLIT", .code = 2, .value = "daytime light" }, + .{ .acronym = "EXCLIT", .code = 3, .value = "fog light" }, + .{ .acronym = "EXCLIT", .code = 4, .value = "night light" }, + .{ + .acronym = "EXPSOU", + .code = 1, + .value = "within the range of depth of the surrounding depth area", + }, + .{ + .acronym = "EXPSOU", + .code = 2, + .value = "shoaler than the range of depth of the surrounding depth area", + }, + .{ + .acronym = "EXPSOU", + .code = 3, + .value = "deeper than the range of depth of the surrounding depth area", + }, + .{ .acronym = "FUNCTN", .code = 1, .value = "no function/service of major interest" }, + .{ .acronym = "FUNCTN", .code = 2, .value = "harbour-master's office" }, + .{ .acronym = "FUNCTN", .code = 3, .value = "custom office" }, + .{ .acronym = "FUNCTN", .code = 4, .value = "health office" }, + .{ .acronym = "FUNCTN", .code = 5, .value = "hospital" }, + .{ .acronym = "FUNCTN", .code = 6, .value = "post office" }, + .{ .acronym = "FUNCTN", .code = 7, .value = "hotel" }, + .{ .acronym = "FUNCTN", .code = 8, .value = "railway station" }, + .{ .acronym = "FUNCTN", .code = 9, .value = "police station" }, + .{ .acronym = "FUNCTN", .code = 10, .value = "water-police station" }, + .{ .acronym = "FUNCTN", .code = 11, .value = "pilot office" }, + .{ .acronym = "FUNCTN", .code = 12, .value = "pilot lookout" }, + .{ .acronym = "FUNCTN", .code = 13, .value = "bank office" }, + .{ .acronym = "FUNCTN", .code = 14, .value = "headquarters for district control" }, + .{ .acronym = "FUNCTN", .code = 15, .value = "transit shed/warehouse" }, + .{ .acronym = "FUNCTN", .code = 16, .value = "factory" }, + .{ .acronym = "FUNCTN", .code = 17, .value = "power station" }, + .{ .acronym = "FUNCTN", .code = 18, .value = "administrative" }, + .{ .acronym = "FUNCTN", .code = 19, .value = "educational facility" }, + .{ .acronym = "FUNCTN", .code = 20, .value = "church" }, + .{ .acronym = "FUNCTN", .code = 21, .value = "chapel" }, + .{ .acronym = "FUNCTN", .code = 22, .value = "temple" }, + .{ .acronym = "FUNCTN", .code = 23, .value = "pagoda" }, + .{ .acronym = "FUNCTN", .code = 24, .value = "shinto shrine" }, + .{ .acronym = "FUNCTN", .code = 25, .value = "buddhist temple" }, + .{ .acronym = "FUNCTN", .code = 26, .value = "mosque" }, + .{ .acronym = "FUNCTN", .code = 27, .value = "marabout" }, + .{ .acronym = "FUNCTN", .code = 28, .value = "lookout" }, + .{ .acronym = "FUNCTN", .code = 29, .value = "communication" }, + .{ .acronym = "FUNCTN", .code = 30, .value = "television" }, + .{ .acronym = "FUNCTN", .code = 31, .value = "radio" }, + .{ .acronym = "FUNCTN", .code = 32, .value = "radar" }, + .{ .acronym = "FUNCTN", .code = 33, .value = "light support" }, + .{ .acronym = "FUNCTN", .code = 34, .value = "microwave" }, + .{ .acronym = "FUNCTN", .code = 35, .value = "cooling" }, + .{ .acronym = "FUNCTN", .code = 36, .value = "observation" }, + .{ .acronym = "FUNCTN", .code = 37, .value = "timeball" }, + .{ .acronym = "FUNCTN", .code = 38, .value = "clock" }, + .{ .acronym = "FUNCTN", .code = 39, .value = "control" }, + .{ .acronym = "FUNCTN", .code = 40, .value = "airship mooring" }, + .{ .acronym = "FUNCTN", .code = 41, .value = "stadium" }, + .{ .acronym = "FUNCTN", .code = 42, .value = "bus station" }, + .{ .acronym = "HORDAT", .code = 1, .value = "WGS 72" }, + .{ .acronym = "HORDAT", .code = 2, .value = "WGS 84" }, + .{ .acronym = "HORDAT", .code = 3, .value = "European 1950" }, + .{ .acronym = "HORDAT", .code = 4, .value = "Potsdam Datum" }, + .{ .acronym = "HORDAT", .code = 5, .value = "Adindan" }, + .{ .acronym = "HORDAT", .code = 6, .value = "Afgooye" }, + .{ .acronym = "HORDAT", .code = 7, .value = "Ain el Abd 1970" }, + .{ .acronym = "HORDAT", .code = 8, .value = "Anna 1 Astro 1965" }, + .{ .acronym = "HORDAT", .code = 9, .value = "Antigua Island Astro 1943" }, + .{ .acronym = "HORDAT", .code = 10, .value = "Arc 1950" }, + .{ .acronym = "HORDAT", .code = 11, .value = "Arc 1960" }, + .{ .acronym = "HORDAT", .code = 12, .value = "Ascension Island 1958" }, + .{ .acronym = "HORDAT", .code = 13, .value = "Astro beacon \"E\" 1945" }, + .{ .acronym = "HORDAT", .code = 14, .value = "Astro DOS 71/4" }, + .{ .acronym = "HORDAT", .code = 15, .value = "Astro Tern Island (FRIG) 1961" }, + .{ .acronym = "HORDAT", .code = 16, .value = "Astronomical Station 1952" }, + .{ .acronym = "HORDAT", .code = 17, .value = "Australian Geodetic 1966" }, + .{ .acronym = "HORDAT", .code = 18, .value = "Australian Geodetic 1984" }, + .{ .acronym = "HORDAT", .code = 19, .value = "Ayabelle Lighthouse" }, + .{ .acronym = "HORDAT", .code = 20, .value = "Bellevue (IGN)" }, + .{ .acronym = "HORDAT", .code = 21, .value = "Bermuda 1957" }, + .{ .acronym = "HORDAT", .code = 22, .value = "Bissau" }, + .{ .acronym = "HORDAT", .code = 23, .value = "Bogota Observatory" }, + .{ .acronym = "HORDAT", .code = 24, .value = "Bukit Rimpah" }, + .{ .acronym = "HORDAT", .code = 25, .value = "Camp Area Astro" }, + .{ .acronym = "HORDAT", .code = 26, .value = "Campo Inchauspe 1969" }, + .{ .acronym = "HORDAT", .code = 27, .value = "Canton Astro 1966" }, + .{ .acronym = "HORDAT", .code = 28, .value = "Cape" }, + .{ .acronym = "HORDAT", .code = 29, .value = "Cape Canaveral" }, + .{ .acronym = "HORDAT", .code = 30, .value = "Carthage" }, + .{ .acronym = "HORDAT", .code = 31, .value = "Chatam Island Astro 1971" }, + .{ .acronym = "HORDAT", .code = 32, .value = "Chua Astro" }, + .{ .acronym = "HORDAT", .code = 33, .value = "Corrego Alegre" }, + .{ .acronym = "HORDAT", .code = 34, .value = "Dabola" }, + .{ .acronym = "HORDAT", .code = 35, .value = "Djakarta (Batavia)" }, + .{ .acronym = "HORDAT", .code = 36, .value = "DOS 1968" }, + .{ .acronym = "HORDAT", .code = 37, .value = "Easter Island 1967" }, + .{ .acronym = "HORDAT", .code = 38, .value = "European 1979" }, + .{ .acronym = "HORDAT", .code = 39, .value = "Fort Thomas 1955" }, + .{ .acronym = "HORDAT", .code = 40, .value = "Gan 1970" }, + .{ .acronym = "HORDAT", .code = 41, .value = "Geodetic Datum 1949" }, + .{ .acronym = "HORDAT", .code = 42, .value = "Graciosa Base SW 1948" }, + .{ .acronym = "HORDAT", .code = 43, .value = "Guam 1963" }, + .{ .acronym = "HORDAT", .code = 44, .value = "Gunung Segara" }, + .{ .acronym = "HORDAT", .code = 45, .value = "GUX 1 Astro" }, + .{ .acronym = "HORDAT", .code = 46, .value = "Herat North" }, + .{ .acronym = "HORDAT", .code = 47, .value = "Hjorsey 1955" }, + .{ .acronym = "HORDAT", .code = 48, .value = "Hong Kong 1963" }, + .{ .acronym = "HORDAT", .code = 49, .value = "Hu-Tzu-Shan" }, + .{ .acronym = "HORDAT", .code = 50, .value = "Indian" }, + .{ .acronym = "HORDAT", .code = 51, .value = "Indian 1954" }, + .{ .acronym = "HORDAT", .code = 52, .value = "Indian 1975" }, + .{ .acronym = "HORDAT", .code = 53, .value = "Ireland 1965" }, + .{ .acronym = "HORDAT", .code = 54, .value = "ISTS 061 Astro 1968" }, + .{ .acronym = "HORDAT", .code = 55, .value = "ISTS 073 Astro 1969" }, + .{ .acronym = "HORDAT", .code = 56, .value = "Johnston Island 1961" }, + .{ .acronym = "HORDAT", .code = 57, .value = "Kandawala" }, + .{ .acronym = "HORDAT", .code = 58, .value = "Kerguelen Island 1949" }, + .{ .acronym = "HORDAT", .code = 59, .value = "Kertau 1948" }, + .{ .acronym = "HORDAT", .code = 60, .value = "Kusaie Astro 1951" }, + .{ .acronym = "HORDAT", .code = 61, .value = "L. C. 5 Astro 1961" }, + .{ .acronym = "HORDAT", .code = 62, .value = "Leigon" }, + .{ .acronym = "HORDAT", .code = 63, .value = "Liberia 1964" }, + .{ .acronym = "HORDAT", .code = 64, .value = "Luzon" }, + .{ .acronym = "HORDAT", .code = 65, .value = "Mahe 1971" }, + .{ .acronym = "HORDAT", .code = 66, .value = "Massawa" }, + .{ .acronym = "HORDAT", .code = 67, .value = "Merchich" }, + .{ .acronym = "HORDAT", .code = 68, .value = "Midway Astro 1961" }, + .{ .acronym = "HORDAT", .code = 69, .value = "Minna" }, + .{ .acronym = "HORDAT", .code = 70, .value = "Montserrat Island Astro 1958" }, + .{ .acronym = "HORDAT", .code = 71, .value = "M'Poraloko" }, + .{ .acronym = "HORDAT", .code = 72, .value = "Nahrwan" }, + .{ .acronym = "HORDAT", .code = 73, .value = "Naparima, BWI" }, + .{ .acronym = "HORDAT", .code = 74, .value = "North American 1927" }, + .{ .acronym = "HORDAT", .code = 75, .value = "North American 1983" }, + .{ .acronym = "HORDAT", .code = 76, .value = "Observatorio Meteorologico 1939" }, + .{ .acronym = "HORDAT", .code = 77, .value = "Old Egyptian 1907" }, + .{ .acronym = "HORDAT", .code = 78, .value = "Old Hawaiian" }, + .{ .acronym = "HORDAT", .code = 79, .value = "Oman" }, + .{ .acronym = "HORDAT", .code = 80, .value = "Ordnance Survey of Great Britain 1936" }, + .{ .acronym = "HORDAT", .code = 81, .value = "Pico de las Nieves" }, + .{ .acronym = "HORDAT", .code = 82, .value = "Pitcairn Astro 1967" }, + .{ .acronym = "HORDAT", .code = 83, .value = "Point 58" }, + .{ .acronym = "HORDAT", .code = 84, .value = "Pointe Noire 1948" }, + .{ .acronym = "HORDAT", .code = 85, .value = "Porto Santo 1936" }, + .{ .acronym = "HORDAT", .code = 86, .value = "Provisional South American 1956" }, + .{ + .acronym = "HORDAT", + .code = 87, + .value = "Provisional South Chilean 1963 (also known as Hito XVIII 1963)", + }, + .{ .acronym = "HORDAT", .code = 88, .value = "Puerto Rico" }, + .{ .acronym = "HORDAT", .code = 89, .value = "Qatar national" }, + .{ .acronym = "HORDAT", .code = 90, .value = "Qornoq" }, + .{ .acronym = "HORDAT", .code = 91, .value = "Reunion" }, + .{ .acronym = "HORDAT", .code = 92, .value = "Rome 1940" }, + .{ .acronym = "HORDAT", .code = 93, .value = "Santo (DOS) 1965" }, + .{ .acronym = "HORDAT", .code = 94, .value = "Sao Braz" }, + .{ .acronym = "HORDAT", .code = 95, .value = "Sapper Hill 1943" }, + .{ .acronym = "HORDAT", .code = 96, .value = "Schwarzeck" }, + .{ .acronym = "HORDAT", .code = 97, .value = "Selvagem Grande 1938" }, + .{ .acronym = "HORDAT", .code = 98, .value = "South American 1969" }, + .{ .acronym = "HORDAT", .code = 99, .value = "South Asia" }, + .{ .acronym = "HORDAT", .code = 100, .value = "Tananarive Observatory 1925" }, + .{ .acronym = "HORDAT", .code = 101, .value = "Timbalai 1948" }, + .{ .acronym = "HORDAT", .code = 102, .value = "Tokyo" }, + .{ .acronym = "HORDAT", .code = 103, .value = "Tristan Astro 1968" }, + .{ .acronym = "HORDAT", .code = 104, .value = "Viti Levu 1916" }, + .{ .acronym = "HORDAT", .code = 105, .value = "Wake-Eniwetok 1960" }, + .{ .acronym = "HORDAT", .code = 106, .value = "Wake Island Astro 1952" }, + .{ .acronym = "HORDAT", .code = 107, .value = "Yacare" }, + .{ .acronym = "HORDAT", .code = 108, .value = "Zanderij" }, + .{ .acronym = "HORDAT", .code = 109, .value = "American Samoa 1962" }, + .{ .acronym = "HORDAT", .code = 110, .value = "Deception Island" }, + .{ .acronym = "HORDAT", .code = 111, .value = "Indian 1960" }, + .{ .acronym = "HORDAT", .code = 112, .value = "Indonesian 1974" }, + .{ .acronym = "HORDAT", .code = 113, .value = "North Sahara 1959" }, + .{ .acronym = "HORDAT", .code = 114, .value = "Pulkovo 1942" }, + .{ .acronym = "HORDAT", .code = 115, .value = "S-42 (Pulkovo 1942)" }, + .{ .acronym = "HORDAT", .code = 116, .value = "S-JYSK" }, + .{ .acronym = "HORDAT", .code = 117, .value = "Voirol 1950" }, + .{ .acronym = "HORDAT", .code = 118, .value = "Average Terrestrial System 1977" }, + .{ .acronym = "HORDAT", .code = 119, .value = "Compensation Géodésique du Québec 1977" }, + .{ .acronym = "HORDAT", .code = 120, .value = "Finnish (KKJ)" }, + .{ .acronym = "HORDAT", .code = 121, .value = "Ordnance Survey of Ireland" }, + .{ .acronym = "HORDAT", .code = 122, .value = "Revised Kertau" }, + .{ .acronym = "HORDAT", .code = 123, .value = "Revised Nahrwan" }, + .{ .acronym = "HORDAT", .code = 124, .value = "GGRS 76 (Greece)" }, + .{ .acronym = "HORDAT", .code = 125, .value = "Nouvelle Triangulation de France" }, + .{ .acronym = "HORDAT", .code = 126, .value = "RT 90 (Sweden)" }, + .{ .acronym = "HORDAT", .code = 127, .value = "Geocentric Datum of Australia (GDA)" }, + .{ .acronym = "HORDAT", .code = 128, .value = "BJZ54 (A954 Beijing Coordinates)" }, + .{ .acronym = "HORDAT", .code = 129, .value = "Modified BJZ54" }, + .{ .acronym = "HORDAT", .code = 130, .value = "GDZ80" }, + .{ .acronym = "HORDAT", .code = 131, .value = "Local datum" }, + .{ .acronym = "HUNITS", .code = 1, .value = "metres" }, + .{ .acronym = "HUNITS", .code = 2, .value = "feet" }, + .{ .acronym = "JRSDTN", .code = 1, .value = "international" }, + .{ .acronym = "JRSDTN", .code = 2, .value = "national" }, + .{ .acronym = "JRSDTN", .code = 3, .value = "national sub-division" }, + .{ .acronym = "LITCHR", .code = 1, .value = "Fixed" }, + .{ .acronym = "LITCHR", .code = 2, .value = "Flashing" }, + .{ .acronym = "LITCHR", .code = 3, .value = "Long-flashing" }, + .{ .acronym = "LITCHR", .code = 4, .value = "Quick-flashing" }, + .{ .acronym = "LITCHR", .code = 5, .value = "Very quick-flashing" }, + .{ .acronym = "LITCHR", .code = 6, .value = "Ultra quick-flashing" }, + .{ .acronym = "LITCHR", .code = 7, .value = "Isophased" }, + .{ .acronym = "LITCHR", .code = 8, .value = "Occulting" }, + .{ .acronym = "LITCHR", .code = 9, .value = "Interrupted quick-flashing" }, + .{ .acronym = "LITCHR", .code = 10, .value = "Interrupted very quick-flashing" }, + .{ .acronym = "LITCHR", .code = 11, .value = "Interrupted ultra quick-flashing" }, + .{ .acronym = "LITCHR", .code = 12, .value = "Morse" }, + .{ .acronym = "LITCHR", .code = 13, .value = "Fixed/flash" }, + .{ .acronym = "LITCHR", .code = 14, .value = "Flash/long-flash" }, + .{ .acronym = "LITCHR", .code = 15, .value = "Occulting/flash" }, + .{ .acronym = "LITCHR", .code = 16, .value = "Fixed/long-flash" }, + .{ .acronym = "LITCHR", .code = 17, .value = "Occulting alternating" }, + .{ .acronym = "LITCHR", .code = 18, .value = "Long-flash alternating" }, + .{ .acronym = "LITCHR", .code = 19, .value = "Flash alternating" }, + .{ .acronym = "LITCHR", .code = 20, .value = "Group alternating" }, + .{ .acronym = "LITCHR", .code = 21, .value = "2 fixed (vertical)" }, + .{ .acronym = "LITCHR", .code = 22, .value = "2 fixed (horizontal)" }, + .{ .acronym = "LITCHR", .code = 23, .value = "3 fixed (vertical)" }, + .{ .acronym = "LITCHR", .code = 24, .value = "3 fixed (horizontal)" }, + .{ .acronym = "LITCHR", .code = 25, .value = "Quick-flash plus long-flash" }, + .{ .acronym = "LITCHR", .code = 26, .value = "Very quick-flash plus long-flash" }, + .{ .acronym = "LITCHR", .code = 27, .value = "Ultra quick-flash plus long-flash" }, + .{ .acronym = "LITCHR", .code = 28, .value = "Alternating" }, + .{ .acronym = "LITCHR", .code = 29, .value = "Fixed and alternating flashing" }, + .{ .acronym = "LITVIS", .code = 1, .value = "high intensity" }, + .{ .acronym = "LITVIS", .code = 2, .value = "low intensity" }, + .{ .acronym = "LITVIS", .code = 3, .value = "faint" }, + .{ .acronym = "LITVIS", .code = 4, .value = "intensified" }, + .{ .acronym = "LITVIS", .code = 5, .value = "unintensified" }, + .{ .acronym = "LITVIS", .code = 6, .value = "visibility deliberately restricted" }, + .{ .acronym = "LITVIS", .code = 7, .value = "obscured" }, + .{ .acronym = "LITVIS", .code = 8, .value = "partially obscured" }, + .{ .acronym = "MARSYS", .code = 1, .value = "IALA A" }, + .{ .acronym = "MARSYS", .code = 2, .value = "IALA B" }, + .{ .acronym = "MARSYS", .code = 3, .value = "modified US" }, + .{ .acronym = "MARSYS", .code = 4, .value = "old US" }, + .{ .acronym = "MARSYS", .code = 5, .value = "US intracoastal waterway" }, + .{ .acronym = "MARSYS", .code = 6, .value = "US uniform state" }, + .{ .acronym = "MARSYS", .code = 7, .value = "US western rivers" }, + .{ .acronym = "MARSYS", .code = 8, .value = "SIGNI" }, + .{ .acronym = "MARSYS", .code = 9, .value = "no system" }, + .{ .acronym = "MARSYS", .code = 10, .value = "other system" }, + .{ .acronym = "NATCON", .code = 1, .value = "masonry" }, + .{ .acronym = "NATCON", .code = 2, .value = "concreted" }, + .{ .acronym = "NATCON", .code = 3, .value = "loose boulders" }, + .{ .acronym = "NATCON", .code = 4, .value = "hard surfaced" }, + .{ .acronym = "NATCON", .code = 5, .value = "unsurfaced" }, + .{ .acronym = "NATCON", .code = 6, .value = "wooden" }, + .{ .acronym = "NATCON", .code = 7, .value = "metal" }, + .{ .acronym = "NATCON", .code = 8, .value = "glass reinforced plastic (GRP)" }, + .{ .acronym = "NATCON", .code = 9, .value = "painted" }, + .{ .acronym = "NATQUA", .code = 1, .value = "fine" }, + .{ .acronym = "NATQUA", .code = 2, .value = "medium" }, + .{ .acronym = "NATQUA", .code = 3, .value = "coarse" }, + .{ .acronym = "NATQUA", .code = 4, .value = "broken" }, + .{ .acronym = "NATQUA", .code = 5, .value = "sticky" }, + .{ .acronym = "NATQUA", .code = 6, .value = "soft" }, + .{ .acronym = "NATQUA", .code = 7, .value = "stiff" }, + .{ .acronym = "NATQUA", .code = 8, .value = "volcanic" }, + .{ .acronym = "NATQUA", .code = 9, .value = "calcareous" }, + .{ .acronym = "NATQUA", .code = 10, .value = "hard" }, + .{ .acronym = "NATSUR", .code = 1, .value = "mud" }, + .{ .acronym = "NATSUR", .code = 2, .value = "clay" }, + .{ .acronym = "NATSUR", .code = 3, .value = "silt" }, + .{ .acronym = "NATSUR", .code = 4, .value = "sand" }, + .{ .acronym = "NATSUR", .code = 5, .value = "stone" }, + .{ .acronym = "NATSUR", .code = 6, .value = "gravel" }, + .{ .acronym = "NATSUR", .code = 7, .value = "pebbles" }, + .{ .acronym = "NATSUR", .code = 8, .value = "cobbles" }, + .{ .acronym = "NATSUR", .code = 9, .value = "rock" }, + .{ .acronym = "NATSUR", .code = 10, .value = "marsh" }, + .{ .acronym = "NATSUR", .code = 11, .value = "lava" }, + .{ .acronym = "NATSUR", .code = 12, .value = "snow" }, + .{ .acronym = "NATSUR", .code = 13, .value = "ice" }, + .{ .acronym = "NATSUR", .code = 14, .value = "coral" }, + .{ .acronym = "NATSUR", .code = 15, .value = "swamp" }, + .{ .acronym = "NATSUR", .code = 16, .value = "bog/moor" }, + .{ .acronym = "NATSUR", .code = 17, .value = "shells" }, + .{ .acronym = "NATSUR", .code = 18, .value = "boulder" }, + .{ .acronym = "PRODCT", .code = 1, .value = "oil" }, + .{ .acronym = "PRODCT", .code = 2, .value = "gas" }, + .{ .acronym = "PRODCT", .code = 3, .value = "water" }, + .{ .acronym = "PRODCT", .code = 4, .value = "stone" }, + .{ .acronym = "PRODCT", .code = 5, .value = "coal" }, + .{ .acronym = "PRODCT", .code = 6, .value = "ore" }, + .{ .acronym = "PRODCT", .code = 7, .value = "chemicals" }, + .{ .acronym = "PRODCT", .code = 8, .value = "drinking water" }, + .{ .acronym = "PRODCT", .code = 9, .value = "milk" }, + .{ .acronym = "PRODCT", .code = 10, .value = "bauxite" }, + .{ .acronym = "PRODCT", .code = 11, .value = "coke" }, + .{ .acronym = "PRODCT", .code = 12, .value = "iron ingots" }, + .{ .acronym = "PRODCT", .code = 13, .value = "salt" }, + .{ .acronym = "PRODCT", .code = 14, .value = "sand" }, + .{ .acronym = "PRODCT", .code = 15, .value = "timber" }, + .{ .acronym = "PRODCT", .code = 16, .value = "sawdust/wood chips" }, + .{ .acronym = "PRODCT", .code = 17, .value = "scrap metal" }, + .{ .acronym = "PRODCT", .code = 18, .value = "liquified natural gas (LNG)" }, + .{ .acronym = "PRODCT", .code = 19, .value = "liquified petroleum gas (LPG)" }, + .{ .acronym = "PRODCT", .code = 20, .value = "wine" }, + .{ .acronym = "PRODCT", .code = 21, .value = "cement" }, + .{ .acronym = "PRODCT", .code = 22, .value = "grain" }, + .{ .acronym = "PUNITS", .code = 1, .value = "metres" }, + .{ .acronym = "PUNITS", .code = 2, .value = "degrees of arc" }, + .{ .acronym = "PUNITS", .code = 3, .value = "millimeters" }, + .{ .acronym = "PUNITS", .code = 4, .value = "feet" }, + .{ .acronym = "PUNITS", .code = 5, .value = "cables" }, + .{ .acronym = "QUAPOS", .code = 1, .value = "surveyed" }, + .{ .acronym = "QUAPOS", .code = 2, .value = "unsurveyed" }, + .{ .acronym = "QUAPOS", .code = 3, .value = "inadequately surveyed" }, + .{ .acronym = "QUAPOS", .code = 4, .value = "approximate" }, + .{ .acronym = "QUAPOS", .code = 5, .value = "position doubtful" }, + .{ .acronym = "QUAPOS", .code = 6, .value = "unreliable" }, + .{ .acronym = "QUAPOS", .code = 7, .value = "reported (not surveyed)" }, + .{ .acronym = "QUAPOS", .code = 8, .value = "reported (not confirmed)" }, + .{ .acronym = "QUAPOS", .code = 9, .value = "estimated" }, + .{ .acronym = "QUAPOS", .code = 10, .value = "precisely known" }, + .{ .acronym = "QUAPOS", .code = 11, .value = "calculated" }, + .{ .acronym = "QUASOU", .code = 1, .value = "depth known" }, + .{ .acronym = "QUASOU", .code = 2, .value = "depth unknown" }, + .{ .acronym = "QUASOU", .code = 3, .value = "doubtful sounding" }, + .{ .acronym = "QUASOU", .code = 4, .value = "unreliable sounding" }, + .{ .acronym = "QUASOU", .code = 5, .value = "no bottom found at value shown" }, + .{ .acronym = "QUASOU", .code = 6, .value = "least depth known" }, + .{ + .acronym = "QUASOU", + .code = 7, + .value = "least depth unknown, safe clearance at value shown", + }, + .{ .acronym = "QUASOU", .code = 8, .value = "value reported (not surveyed)" }, + .{ .acronym = "QUASOU", .code = 9, .value = "value reported (not confirmed)" }, + .{ .acronym = "QUASOU", .code = 10, .value = "maintained depth" }, + .{ .acronym = "QUASOU", .code = 11, .value = "not regularly maintained" }, + .{ .acronym = "RESTRN", .code = 1, .value = "anchoring prohibited" }, + .{ .acronym = "RESTRN", .code = 2, .value = "anchoring restricted" }, + .{ .acronym = "RESTRN", .code = 3, .value = "fishing prohibited" }, + .{ .acronym = "RESTRN", .code = 4, .value = "fishing restricted" }, + .{ .acronym = "RESTRN", .code = 5, .value = "trawling prohibited" }, + .{ .acronym = "RESTRN", .code = 6, .value = "trawling restricted" }, + .{ .acronym = "RESTRN", .code = 7, .value = "entry prohibited" }, + .{ .acronym = "RESTRN", .code = 8, .value = "entry restricted" }, + .{ .acronym = "RESTRN", .code = 9, .value = "dredging prohibited" }, + .{ .acronym = "RESTRN", .code = 10, .value = "dredging restricted" }, + .{ .acronym = "RESTRN", .code = 11, .value = "diving prohibited" }, + .{ .acronym = "RESTRN", .code = 12, .value = "diving restricted" }, + .{ .acronym = "RESTRN", .code = 13, .value = "no wake" }, + .{ .acronym = "RESTRN", .code = 14, .value = "area to be avoided" }, + .{ .acronym = "RESTRN", .code = 15, .value = "construction prohibited" }, + .{ .acronym = "RESTRN", .code = 16, .value = "discharging prohibited" }, + .{ .acronym = "RESTRN", .code = 17, .value = "discharging restricted" }, + .{ + .acronym = "RESTRN", + .code = 18, + .value = "industrial or mineral exploration/development prohibited", + }, + .{ + .acronym = "RESTRN", + .code = 19, + .value = "industrial or mineral exploration/development restricted", + }, + .{ .acronym = "RESTRN", .code = 20, .value = "drilling prohibited" }, + .{ .acronym = "RESTRN", .code = 21, .value = "drilling restricted" }, + .{ .acronym = "RESTRN", .code = 22, .value = "removal of historical artifacts prohibited" }, + .{ .acronym = "RESTRN", .code = 23, .value = "cargo transhipment (lightering) prohibited" }, + .{ .acronym = "RESTRN", .code = 24, .value = "dragging prohibited" }, + .{ .acronym = "RESTRN", .code = 25, .value = "stopping prohibited" }, + .{ .acronym = "RESTRN", .code = 26, .value = "landing prohibited" }, + .{ .acronym = "RESTRN", .code = 27, .value = "speed restricted" }, + .{ .acronym = "SIGGEN", .code = 1, .value = "automatically" }, + .{ .acronym = "SIGGEN", .code = 2, .value = "by wave action" }, + .{ .acronym = "SIGGEN", .code = 3, .value = "by hand" }, + .{ .acronym = "SIGGEN", .code = 4, .value = "by wind" }, + .{ .acronym = "STATUS", .code = 1, .value = "permanent" }, + .{ .acronym = "STATUS", .code = 2, .value = "occasional" }, + .{ .acronym = "STATUS", .code = 3, .value = "recommended" }, + .{ .acronym = "STATUS", .code = 4, .value = "not in use" }, + .{ .acronym = "STATUS", .code = 5, .value = "periodic/intermittent" }, + .{ .acronym = "STATUS", .code = 6, .value = "reserved" }, + .{ .acronym = "STATUS", .code = 7, .value = "temporary" }, + .{ .acronym = "STATUS", .code = 8, .value = "private" }, + .{ .acronym = "STATUS", .code = 9, .value = "mandatory" }, + .{ .acronym = "STATUS", .code = 10, .value = "destroyed/ruined" }, + .{ .acronym = "STATUS", .code = 11, .value = "extinguished" }, + .{ .acronym = "STATUS", .code = 12, .value = "illuminated" }, + .{ .acronym = "STATUS", .code = 13, .value = "historic" }, + .{ .acronym = "STATUS", .code = 14, .value = "public" }, + .{ .acronym = "STATUS", .code = 15, .value = "synchronized" }, + .{ .acronym = "STATUS", .code = 16, .value = "watched" }, + .{ .acronym = "STATUS", .code = 17, .value = "un-watched" }, + .{ .acronym = "STATUS", .code = 18, .value = "existence doubtful" }, + .{ .acronym = "SURTYP", .code = 1, .value = "reconnaissance/sketch survey" }, + .{ .acronym = "SURTYP", .code = 2, .value = "controlled survey" }, + .{ .acronym = "SURTYP", .code = 3, .value = "unsurveyed" }, + .{ .acronym = "SURTYP", .code = 4, .value = "examination survey" }, + .{ .acronym = "SURTYP", .code = 5, .value = "passage survey" }, + .{ .acronym = "SURTYP", .code = 6, .value = "remotely sensed" }, + .{ .acronym = "TECSOU", .code = 1, .value = "found by echo-sounder" }, + .{ .acronym = "TECSOU", .code = 2, .value = "found by side scan sonar" }, + .{ .acronym = "TECSOU", .code = 3, .value = "found by multi-beam" }, + .{ .acronym = "TECSOU", .code = 4, .value = "found by diver" }, + .{ .acronym = "TECSOU", .code = 5, .value = "found by lead-line" }, + .{ .acronym = "TECSOU", .code = 6, .value = "swept by wire-drag" }, + .{ .acronym = "TECSOU", .code = 7, .value = "found by laser" }, + .{ .acronym = "TECSOU", .code = 8, .value = "swept by vertical acoustic system" }, + .{ .acronym = "TECSOU", .code = 9, .value = "found by electromagnetic sensor" }, + .{ .acronym = "TECSOU", .code = 10, .value = "photogrammetry" }, + .{ .acronym = "TECSOU", .code = 11, .value = "satellite imagery" }, + .{ .acronym = "TECSOU", .code = 12, .value = "found by levelling" }, + .{ .acronym = "TECSOU", .code = 13, .value = "swept by side-scan sonar" }, + .{ .acronym = "TECSOU", .code = 14, .value = "computer generated" }, + .{ .acronym = "TOPSHP", .code = 1, .value = "cone, point up" }, + .{ .acronym = "TOPSHP", .code = 2, .value = "cone, point down" }, + .{ .acronym = "TOPSHP", .code = 3, .value = "sphere" }, + .{ .acronym = "TOPSHP", .code = 4, .value = "2 spheres" }, + .{ .acronym = "TOPSHP", .code = 5, .value = "cylinder (can)" }, + .{ .acronym = "TOPSHP", .code = 6, .value = "board" }, + .{ .acronym = "TOPSHP", .code = 7, .value = "x-shape (St. Andrew's cross)" }, + .{ .acronym = "TOPSHP", .code = 8, .value = "upright cross (St George's cross)" }, + .{ .acronym = "TOPSHP", .code = 9, .value = "cube, point up" }, + .{ .acronym = "TOPSHP", .code = 10, .value = "2 cones, point to point" }, + .{ .acronym = "TOPSHP", .code = 11, .value = "2 cones, base to base" }, + .{ .acronym = "TOPSHP", .code = 12, .value = "rhombus (diamond)" }, + .{ .acronym = "TOPSHP", .code = 13, .value = "2 cones (points upward)" }, + .{ .acronym = "TOPSHP", .code = 14, .value = "2 cones (points downward)" }, + .{ .acronym = "TOPSHP", .code = 15, .value = "besom, point up (broom or perch)" }, + .{ .acronym = "TOPSHP", .code = 16, .value = "besom, point down (broom or perch)" }, + .{ .acronym = "TOPSHP", .code = 17, .value = "flag" }, + .{ .acronym = "TOPSHP", .code = 18, .value = "sphere over rhombus" }, + .{ .acronym = "TOPSHP", .code = 19, .value = "square" }, + .{ .acronym = "TOPSHP", .code = 20, .value = "rectangle, horizontal" }, + .{ .acronym = "TOPSHP", .code = 21, .value = "rectangle, vertical" }, + .{ .acronym = "TOPSHP", .code = 22, .value = "trapezium, up" }, + .{ .acronym = "TOPSHP", .code = 23, .value = "trapezium, down" }, + .{ .acronym = "TOPSHP", .code = 24, .value = "triangle, point up" }, + .{ .acronym = "TOPSHP", .code = 25, .value = "triangle, point down" }, + .{ .acronym = "TOPSHP", .code = 26, .value = "circle" }, + .{ .acronym = "TOPSHP", .code = 27, .value = "two upright crosses (one over the other)" }, + .{ .acronym = "TOPSHP", .code = 28, .value = "T-shape" }, + .{ .acronym = "TOPSHP", .code = 29, .value = "triangle pointing up over a circle" }, + .{ .acronym = "TOPSHP", .code = 30, .value = "upright cross over a circle" }, + .{ .acronym = "TOPSHP", .code = 31, .value = "rhombus over a circle" }, + .{ .acronym = "TOPSHP", .code = 32, .value = "circle over a triangle pointing up" }, + .{ .acronym = "TOPSHP", .code = 33, .value = "other shape (see INFORM)" }, + .{ .acronym = "TRAFIC", .code = 1, .value = "inbound" }, + .{ .acronym = "TRAFIC", .code = 2, .value = "outbound" }, + .{ .acronym = "TRAFIC", .code = 3, .value = "one-way" }, + .{ .acronym = "TRAFIC", .code = 4, .value = "two-way" }, + .{ .acronym = "T_ACWL", .code = 1, .value = "better than 0.1 m and 10 minutes" }, + .{ .acronym = "T_ACWL", .code = 2, .value = "worse than 0.1 m or 10 minutes" }, + .{ .acronym = "T_MTOD", .code = 1, .value = "simplified harmonic method of tidal prediction" }, + .{ .acronym = "T_MTOD", .code = 2, .value = "full harmonic method of tidal prediction" }, + .{ .acronym = "T_MTOD", .code = 3, .value = "time and height difference non-harmonic method" }, + .{ .acronym = "VERDAT", .code = 1, .value = "mean low water springs" }, + .{ .acronym = "VERDAT", .code = 2, .value = "mean lower low water springs" }, + .{ .acronym = "VERDAT", .code = 3, .value = "mean sea level" }, + .{ .acronym = "VERDAT", .code = 4, .value = "lowest low water" }, + .{ .acronym = "VERDAT", .code = 5, .value = "mean low water" }, + .{ .acronym = "VERDAT", .code = 6, .value = "lowest low water springs" }, + .{ .acronym = "VERDAT", .code = 7, .value = "approximate mean low water springs" }, + .{ .acronym = "VERDAT", .code = 8, .value = "indian spring low water" }, + .{ .acronym = "VERDAT", .code = 9, .value = "low water springs" }, + .{ .acronym = "VERDAT", .code = 10, .value = "approximate lowest astronomical tide" }, + .{ .acronym = "VERDAT", .code = 11, .value = "nearly lowest low water" }, + .{ .acronym = "VERDAT", .code = 12, .value = "mean lower low water" }, + .{ .acronym = "VERDAT", .code = 13, .value = "low water" }, + .{ .acronym = "VERDAT", .code = 14, .value = "approximate mean low water" }, + .{ .acronym = "VERDAT", .code = 15, .value = "approximate mean lower low water" }, + .{ .acronym = "VERDAT", .code = 16, .value = "mean high water" }, + .{ .acronym = "VERDAT", .code = 17, .value = "mean high water springs" }, + .{ .acronym = "VERDAT", .code = 18, .value = "high water" }, + .{ .acronym = "VERDAT", .code = 19, .value = "approximate mean sea level" }, + .{ .acronym = "VERDAT", .code = 20, .value = "high water springs" }, + .{ .acronym = "VERDAT", .code = 21, .value = "mean higher high water" }, + .{ .acronym = "VERDAT", .code = 22, .value = "equinoctial spring low water" }, + .{ .acronym = "VERDAT", .code = 23, .value = "lowest astronomical tide" }, + .{ .acronym = "VERDAT", .code = 24, .value = "local datum" }, + .{ .acronym = "VERDAT", .code = 25, .value = "International Great Lakes Datum 1985" }, + .{ .acronym = "VERDAT", .code = 26, .value = "mean water level" }, + .{ .acronym = "VERDAT", .code = 27, .value = "lower low water large tide" }, + .{ .acronym = "VERDAT", .code = 28, .value = "higher high water large tide" }, + .{ .acronym = "VERDAT", .code = 29, .value = "nearly highest high water" }, + .{ .acronym = "VERDAT", .code = 30, .value = "highest astronomical tide (HAT)" }, + .{ .acronym = "WATLEV", .code = 1, .value = "partly submerged at high water" }, + .{ .acronym = "WATLEV", .code = 2, .value = "always dry" }, + .{ .acronym = "WATLEV", .code = 3, .value = "always under water/submerged" }, + .{ .acronym = "WATLEV", .code = 4, .value = "covers and uncovers" }, + .{ .acronym = "WATLEV", .code = 5, .value = "awash" }, + .{ .acronym = "WATLEV", .code = 6, .value = "subject to inundation or flooding" }, + .{ .acronym = "WATLEV", .code = 7, .value = "floating" }, +}; diff --git a/src/s57/decode.zig b/src/s57/decode.zig new file mode 100644 index 00000000..99a8d48f --- /dev/null +++ b/src/s57/decode.zig @@ -0,0 +1,275 @@ +//! S-57 decode for the pick report. +//! +//! The cell stores acronyms and enum codes. This module translates them: +//! COLOUR 4 becomes "Green", and a LIGHTS object gets its characteristic +//! "Q G 1s". Every shell reads the same decode. +//! +//! The decode is conservative. An acronym or a code that the catalogue +//! does not contain passes through unchanged. +//! +//! catalog.zig holds the S-57 attribute catalogue as data. This file holds +//! the chart shorthand (the chart prints "Fl(2) G 6s"; the catalogue does +//! not) and the value print rules. + +const std = @import("std"); +const catalog = @import("catalog.zig"); + +// ---- catalogue lookups ------------------------------------------------------ + +/// The label a mariner reads for an attribute acronym, or the acronym itself. +pub fn attrName(acronym: []const u8) []const u8 { + for (catalog.attribute_names) |e| { + if (std.mem.eql(u8, e.acronym, acronym)) return e.name; + } + return acronym; +} + +fn enumValue(acronym: []const u8, code: u16) ?[]const u8 { + for (catalog.enum_values) |e| { + if (e.code == code and std.mem.eql(u8, e.acronym, acronym)) return e.value; + } + return null; +} + +// ---- portrayal shorthand ---------------------------------------------------- + +/// The chart's abbreviation for a light character (LITCHR). The catalogue +/// says "quick-flashing"; the chart prints "Q". +const litchr_abbrev = [_]struct { code: u16, abbr: []const u8 }{ + .{ .code = 1, .abbr = "F" }, .{ .code = 2, .abbr = "Fl" }, + .{ .code = 3, .abbr = "LFl" }, .{ .code = 4, .abbr = "Q" }, + .{ .code = 5, .abbr = "VQ" }, .{ .code = 6, .abbr = "UQ" }, + .{ .code = 7, .abbr = "Iso" }, .{ .code = 8, .abbr = "Oc" }, + .{ .code = 9, .abbr = "IQ" }, .{ .code = 10, .abbr = "IVQ" }, + .{ .code = 11, .abbr = "IUQ" }, .{ .code = 12, .abbr = "Mo" }, + .{ .code = 13, .abbr = "FFl" }, .{ .code = 25, .abbr = "Q+LFl" }, + .{ .code = 26, .abbr = "VQ+LFl" }, .{ .code = 28, .abbr = "Al" }, +}; + +/// The chart's letter for a light colour (COLOUR). +const colour_abbrev = [_]struct { code: u16, abbr: []const u8 }{ + .{ .code = 1, .abbr = "W" }, .{ .code = 3, .abbr = "R" }, + .{ .code = 4, .abbr = "G" }, .{ .code = 5, .abbr = "Bu" }, + .{ .code = 6, .abbr = "Y" }, .{ .code = 9, .abbr = "Am" }, + .{ .code = 10, .abbr = "Vi" }, .{ .code = 11, .abbr = "Or" }, +}; + +fn abbrevOf(comptime table: anytype, code: u16) ?[]const u8 { + for (table) |e| if (e.code == code) return e.abbr; + return null; +} + +// ---- value decoding --------------------------------------------------------- + +/// The separator for a decoded value list. COLOUR joins with "over": the +/// list gives the order of the bands on the mark. +fn listSeparator(acronym: []const u8) []const u8 { + return if (std.mem.eql(u8, acronym, "COLOUR")) " over " else ", "; +} + +/// Decode one attribute value. The caller owns the returned slice's arena. +/// Returns null when the tables cannot read the value; the caller keeps the +/// raw text. +pub fn decodeValue(a: std.mem.Allocator, acronym: []const u8, raw: []const u8) ?[]const u8 { + if (raw.len == 0) return null; + if (std.mem.eql(u8, acronym, "SIGPER")) return withUnit(a, raw, "s"); + if (std.mem.eql(u8, acronym, "HEIGHT") or std.mem.eql(u8, acronym, "ELEVAT") or + std.mem.eql(u8, acronym, "VERCLR") or std.mem.eql(u8, acronym, "HORCLR") or + std.mem.eql(u8, acronym, "VERLEN")) + return withUnit(a, raw, "m"); // heights stay metric: the chart's rule + if (std.mem.eql(u8, acronym, "VALNMR")) return withUnit(a, raw, "M"); + if (std.mem.eql(u8, acronym, "SECTR1") or std.mem.eql(u8, acronym, "SECTR2") or + std.mem.eql(u8, acronym, "ORIENT")) + return withUnit(a, raw, "°"); + if (std.mem.eql(u8, acronym, "SIGSEQ")) return sequence(a, raw); + if (std.mem.eql(u8, acronym, "SCAMIN")) return scamin(a, raw); + if (std.mem.eql(u8, acronym, "SORIND")) return sorind(a, raw); + if (std.mem.eql(u8, acronym, "SORDAT") or std.mem.eql(u8, acronym, "RECDAT") or + std.mem.eql(u8, acronym, "PEREND") or std.mem.eql(u8, acronym, "PERSTA") or + std.mem.eql(u8, acronym, "DATSTA") or std.mem.eql(u8, acronym, "DATEND")) + return date(a, raw); + return decodeEnumList(a, acronym, raw); +} + +/// Decode a comma list such as "3,1": each code through the catalogue, +/// joined by the attribute's separator. Returns null when no code in the +/// list is known. +fn decodeEnumList(a: std.mem.Allocator, acronym: []const u8, raw: []const u8) ?[]const u8 { + var parts = std.ArrayList([]const u8).empty; + var any = false; + var it = std.mem.splitScalar(u8, raw, ','); + while (it.next()) |part| { + const p = std.mem.trim(u8, part, " "); + const code = std.fmt.parseInt(u16, p, 10) catch { + parts.append(a, p) catch return null; + continue; + }; + if (enumValue(acronym, code)) |v| { + parts.append(a, v) catch return null; + any = true; + } else { + parts.append(a, p) catch return null; + } + } + if (!any or parts.items.len == 0) return null; + return std.mem.join(a, listSeparator(acronym), parts.items) catch null; +} + +/// Append a unit to a plain number. A value that already contains text +/// stays unchanged, so a formatted value does not get a second unit. +fn withUnit(a: std.mem.Allocator, raw: []const u8, unit: []const u8) ?[]const u8 { + _ = std.fmt.parseFloat(f64, raw) catch return null; + return std.fmt.allocPrint(a, "{s} {s}", .{ raw, unit }) catch null; +} + +/// Print a signal sequence: "00.3+(00.7)" becomes "0.3 s on, 0.7 s off". +/// Times in brackets are eclipse. +fn sequence(a: std.mem.Allocator, raw: []const u8) ?[]const u8 { + var on = std.ArrayList([]const u8).empty; + var off = std.ArrayList([]const u8).empty; + var it = std.mem.splitScalar(u8, raw, '+'); + while (it.next()) |part| { + const s = std.mem.trim(u8, part, " "); + const dark = s.len >= 2 and s[0] == '(' and s[s.len - 1] == ')'; + const num_text = if (dark) s[1 .. s.len - 1] else s; + const n = std.fmt.parseFloat(f64, num_text) catch return null; + const printed = std.fmt.allocPrint(a, "{d}", .{n}) catch return null; + (if (dark) &off else &on).append(a, printed) catch return null; + } + if (on.items.len == 0 or off.items.len == 0) return null; + const on_s = std.mem.join(a, " + ", on.items) catch return null; + const off_s = std.mem.join(a, " + ", off.items) catch return null; + return std.fmt.allocPrint(a, "{s} s on, {s} s off", .{ on_s, off_s }) catch null; +} + +/// Print SCAMIN, the smallest scale the object shows at: 29999 becomes +/// "1:30,000 and larger". +fn scamin(a: std.mem.Allocator, raw: []const u8) ?[]const u8 { + const v = std.fmt.parseInt(i64, raw, 10) catch return null; + if (v <= 0) return null; + const denom: i64 = if (@rem(v + 1, 1000) == 0) v + 1 else v; + return std.fmt.allocPrint(a, "1:{s} and larger", .{grouped(a, denom) orelse return null}) catch null; +} + +/// Group digits: 30000 becomes "30,000". +fn grouped(a: std.mem.Allocator, v: i64) ?[]const u8 { + var buf: [24]u8 = undefined; + const digits = std.fmt.bufPrint(&buf, "{d}", .{v}) catch return null; + var out = std.ArrayList(u8).empty; + for (digits, 0..) |c, i| { + const remaining = digits.len - i; + if (i != 0 and remaining % 3 == 0) out.append(a, ',') catch return null; + out.append(a, c) catch return null; + } + return out.items; +} + +/// Print SORIND (country, authority, type, source): "US,US,graph,Chart +/// 12283" becomes "Chart 12283 (US)". Any other shape stays unchanged. +fn sorind(a: std.mem.Allocator, raw: []const u8) ?[]const u8 { + var parts: [8][]const u8 = undefined; + var n: usize = 0; + var it = std.mem.splitScalar(u8, raw, ','); + while (it.next()) |p| : (n += 1) { + if (n >= parts.len) return null; + parts[n] = std.mem.trim(u8, p, " "); + } + if (n != 4 or parts[3].len == 0) return null; + return std.fmt.allocPrint(a, "{s} ({s})", .{ parts[3], parts[0] }) catch null; +} + +/// Print an S-57 date (yyyymmdd, yyyymm, or yyyy). A season date "--MMDD" +/// repeats every year and prints as one. +fn date(a: std.mem.Allocator, raw: []const u8) ?[]const u8 { + const months = [_][]const u8{ "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + if (std.mem.startsWith(u8, raw, "--") and raw.len >= 6) { + const m = std.fmt.parseInt(u8, raw[2..4], 10) catch return null; + const d = std.fmt.parseInt(u8, raw[4..6], 10) catch return null; + if (m < 1 or m > 12 or d < 1 or d > 31) return null; + return std.fmt.allocPrint(a, "{d} {s} each year", .{ d, months[m] }) catch null; + } + if (raw.len < 4) return null; + const year = std.fmt.parseInt(u16, raw[0..4], 10) catch return null; + var mon: []const u8 = ""; + if (raw.len >= 6) { + const m = std.fmt.parseInt(u8, raw[4..6], 10) catch 0; + if (m >= 1 and m <= 12) mon = months[m]; + } + if (raw.len >= 8 and mon.len > 0) { + const d = std.fmt.parseInt(u8, raw[6..8], 10) catch 0; + if (d >= 1 and d <= 31) + return std.fmt.allocPrint(a, "{d} {s} {d}", .{ d, mon, year }) catch null; + } + if (mon.len > 0) return std.fmt.allocPrint(a, "{s} {d}", .{ mon, year }) catch null; + return std.fmt.allocPrint(a, "{d}", .{year}) catch null; +} + +// ---- the light's signature -------------------------------------------------- + +/// The light's characteristic as the chart prints it: "Fl(2) G 6s 7m 5M", +/// built from the parts the object carries. Returns null when LITCHR is +/// absent or unknown. +pub fn lightSignature(a: std.mem.Allocator, attrs: *const std.json.ObjectMap) ?[]const u8 { + const chr_raw = strAttr(attrs, "LITCHR") orelse return null; + const chr = std.fmt.parseInt(u16, chr_raw, 10) catch return null; + const abbr = abbrevOf(litchr_abbrev, chr) orelse return null; + var out = std.ArrayList(u8).empty; + out.appendSlice(a, abbr) catch return null; + if (strAttr(attrs, "SIGGRP")) |grp| { + if (grp.len > 0 and !std.mem.eql(u8, grp, "(1)") and !std.mem.eql(u8, grp, "()")) + out.appendSlice(a, grp) catch return null; + } + if (strAttr(attrs, "COLOUR")) |col_raw| { + if (std.fmt.parseInt(u16, col_raw, 10) catch null) |col| { + if (abbrevOf(colour_abbrev, col)) |letter| { + out.append(a, ' ') catch return null; + out.appendSlice(a, letter) catch return null; + } + } + } + appendNumUnit(a, &out, attrs, "SIGPER", "s"); + appendNumUnit(a, &out, attrs, "HEIGHT", "m"); + appendNumUnit(a, &out, attrs, "VALNMR", "M"); + return out.items; +} + +fn appendNumUnit(a: std.mem.Allocator, out: *std.ArrayList(u8), attrs: *const std.json.ObjectMap, acronym: []const u8, unit: []const u8) void { + const raw = strAttr(attrs, acronym) orelse return; + const n = std.fmt.parseFloat(f64, raw) catch return; + const printed = std.fmt.allocPrint(a, " {d}{s}", .{ n, unit }) catch return; + out.appendSlice(a, printed) catch {}; +} + +/// A top-level scalar attribute as text, whatever JSON type the cell used. +fn strAttr(attrs: *const std.json.ObjectMap, name: []const u8) ?[]const u8 { + const v = attrs.get(name) orelse return null; + return switch (v) { + .string => |s| s, + else => null, + }; +} + +// ---- tests ------------------------------------------------------------------ + +test "decodeValue reads the catalogue and the print forms" { + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const a = arena.allocator(); + try std.testing.expectEqualStrings("1 s", decodeValue(a, "SIGPER", "1").?); + try std.testing.expectEqualStrings("0.3 s on, 0.7 s off", decodeValue(a, "SIGSEQ", "00.3+(00.7)").?); + try std.testing.expectEqualStrings("1:30,000 and larger", decodeValue(a, "SCAMIN", "29999").?); + try std.testing.expectEqualStrings("Chart 12283 (US)", decodeValue(a, "SORIND", "US,US,graph,Chart 12283").?); + try std.testing.expectEqualStrings("6 Jan 2001", decodeValue(a, "SORDAT", "20010106").?); + try std.testing.expectEqualStrings("15 Jun each year", decodeValue(a, "PERSTA", "--0615").?); + // Unknown codes pass through as raw (null): never invent a meaning. + try std.testing.expect(decodeValue(a, "NOSUCH", "7") == null); +} + +test "the signature is the chart's shorthand" { + var arena = std.heap.ArenaAllocator.init(std.testing.allocator); + defer arena.deinit(); + const a = arena.allocator(); + const parsed = try std.json.parseFromSlice(std.json.Value, a, "{\"LITCHR\":\"4\",\"COLOUR\":\"4\",\"SIGPER\":\"1\",\"SIGGRP\":\"(1)\"}", .{}); + const sig = lightSignature(a, &parsed.value.object).?; + try std.testing.expectEqualStrings("Q G 1s", sig); +} diff --git a/src/s57/s57.zig b/src/s57/s57.zig index b62e9118..00a3a71e 100644 --- a/src/s57/s57.zig +++ b/src/s57/s57.zig @@ -14,6 +14,10 @@ const Allocator = std.mem.Allocator; /// that want the raw records. It is its own module (`@import("iso8211")`), so a /// caller can depend on the 8211 layer without pulling in S-57 semantics. pub const iso8211 = @import("iso8211"); +/// The IHO attribute catalogue as data, and the mariner's decode over it — +/// the pick report's language, served to every shell from here. +pub const catalog = @import("catalog.zig"); +pub const decode = @import("decode.zig"); const iso = iso8211; // Geographic coordinate stored in S-57's native integer ×1e7 units (lon ±1.8e9, @@ -2473,4 +2477,5 @@ test "pointInRings: inside, outside, and inside a hole" { test { _ = iso8211; + _ = decode; } From fb216524d49b2daf2ff001576d0dda1e56d6d61d Mon Sep 17 00:00:00 2001 From: Jeremy Collins Date: Mon, 3 Aug 2026 09:29:33 -0400 Subject: [PATCH 2/3] s57: generate the S-101 vocabulary from the Feature Catalogue The tool 'tile57 fcattrs' reads the vendored S-101 Feature Catalogue XML and writes catalog_s101.zig: 221 attribute labels and 1022 listed values, keyed by S-101 attribute code. The decode reads S-57 acronyms from the S-57 catalogue and S-101 codes from this file. The two catalogues stay separate. S-101 changed attributes that it took from S-57: CATTRK became the boolean basedOnFixedMarks, BUISHP keeps five shapes, CATCOA drops its shore types. 104 S-57 codes are absent or different in the Feature Catalogue. A decode of an S-57 code through the S-101 tables would give a wrong value. Regenerate with: tile57 fcattrs --- src/s57/catalog_s101.zig | 1260 ++++++++++++++++++++++++++++++++++++++ src/s57/decode.zig | 13 +- src/s57/s57.zig | 1 + tools/fcattrs.zig | 181 ++++++ tools/main.zig | 5 + 5 files changed, 1459 insertions(+), 1 deletion(-) create mode 100644 src/s57/catalog_s101.zig create mode 100644 tools/fcattrs.zig diff --git a/src/s57/catalog_s101.zig b/src/s57/catalog_s101.zig new file mode 100644 index 00000000..70477664 --- /dev/null +++ b/src/s57/catalog_s101.zig @@ -0,0 +1,1260 @@ +//! The S-101 Feature Catalogue's simple attributes, as data. +//! +//! GENERATED by `tile57 fcattrs` from the vendored Feature Catalogue — +//! do not edit by hand; regenerate instead. Keys are S-101 attribute +//! codes; the S-57 catalogue is its own authority in catalog.zig. A +//! code the catalogue does not list stays undecoded and passes +//! through a report raw. + +const catalog = @import("catalog.zig"); + +/// S-101 attribute code -> the label a mariner reads. +pub const attribute_names = [_]catalog.AttrName{ + .{ .acronym = "basedOnFixedMarks", .name = "Based On Fixed Marks" }, + .{ .acronym = "beaconShape", .name = "Beacon Shape" }, + .{ .acronym = "buildingShape", .name = "Building Shape" }, + .{ .acronym = "buoyShape", .name = "Buoy Shape" }, + .{ .acronym = "buriedDepth", .name = "Buried Depth" }, + .{ .acronym = "callSign", .name = "Call Sign" }, + .{ .acronym = "categoryOfAirportAirfield", .name = "Category of Airport/Airfield" }, + .{ .acronym = "categoryOfAnchorage", .name = "Category of Anchorage" }, + .{ .acronym = "categoryOfBridge", .name = "Category of Bridge" }, + .{ .acronym = "categoryOfBuiltUpArea", .name = "Category of Built-Up Area" }, + .{ .acronym = "categoryOfCable", .name = "Category of Cable" }, + .{ .acronym = "categoryOfCanal", .name = "Category of Canal" }, + .{ .acronym = "categoryOfCardinalMark", .name = "Category of Cardinal Mark" }, + .{ .acronym = "categoryOfCheckpoint", .name = "Category of Checkpoint" }, + .{ .acronym = "categoryOfCoastline", .name = "Category of Coastline" }, + .{ .acronym = "categoryOfConveyor", .name = "Category of Conveyor" }, + .{ .acronym = "categoryOfCrane", .name = "Category of Crane" }, + .{ .acronym = "categoryOfDam", .name = "Category of Dam" }, + .{ .acronym = "categoryOfDock", .name = "Category of Dock" }, + .{ .acronym = "categoryOfDumpingGround", .name = "Category of Dumping Ground" }, + .{ .acronym = "categoryOfFence", .name = "Category of Fence" }, + .{ .acronym = "categoryOfFerry", .name = "Category of Ferry" }, + .{ .acronym = "categoryOfFishingFacility", .name = "Category of Fishing Facility" }, + .{ .acronym = "categoryOfFogSignal", .name = "Category of Fog Signal" }, + .{ .acronym = "categoryOfFortifiedStructure", .name = "Category of Fortified Structure" }, + .{ .acronym = "categoryOfGate", .name = "Category of Gate" }, + .{ .acronym = "categoryOfHarbourFacility", .name = "Category of Harbour Facility" }, + .{ .acronym = "categoryOfHulk", .name = "Category of Hulk" }, + .{ .acronym = "categoryOfIce", .name = "Category of Ice" }, + .{ .acronym = "categoryOfInstallationBuoy", .name = "Category of Installation Buoy" }, + .{ .acronym = "categoryOfLandRegion", .name = "Category of Land Region" }, + .{ .acronym = "categoryOfLandmark", .name = "Category of Landmark" }, + .{ .acronym = "categoryOfLateralMark", .name = "Category of Lateral Mark" }, + .{ .acronym = "categoryOfLight", .name = "Category of Light" }, + .{ .acronym = "categoryOfMarineFarmCulture", .name = "Category of Marine Farm/Culture" }, + .{ .acronym = "categoryOfMilitaryPracticeArea", .name = "Category of Military Practice Area" }, + .{ .acronym = "categoryOfMooringWarpingFacility", .name = "Category of Mooring/Warping Facility" }, + .{ .acronym = "categoryOfNavigationLine", .name = "Category of Navigation Line" }, + .{ .acronym = "categoryOfObstruction", .name = "Category of Obstruction" }, + .{ .acronym = "categoryOfOffshorePlatform", .name = "Category of Offshore Platform" }, + .{ .acronym = "categoryOfOffshoreProductionArea", .name = "Category of Offshore Production Area" }, + .{ .acronym = "categoryOfOilBarrier", .name = "Category of Oil Barrier" }, + .{ .acronym = "categoryOfPile", .name = "Category of Pile" }, + .{ .acronym = "categoryOfPilotBoardingPlace", .name = "Category of Pilot Boarding Place" }, + .{ .acronym = "categoryOfPipelinePipe", .name = "Category of Pipeline/Pipe" }, + .{ .acronym = "categoryOfPreference", .name = "Category of Preference" }, + .{ .acronym = "categoryOfProductionArea", .name = "Category of Production Area" }, + .{ .acronym = "categoryOfPylon", .name = "Category of Pylon" }, + .{ .acronym = "categoryOfRadarStation", .name = "Category of Radar Station" }, + .{ .acronym = "categoryOfRadarTransponderBeacon", .name = "Category of Radar Transponder Beacon" }, + .{ .acronym = "categoryOfRadioStation", .name = "Category of Radio Station" }, + .{ .acronym = "categoryOfRescueStation", .name = "Category of Rescue Station" }, + .{ .acronym = "categoryOfRestrictedArea", .name = "Category of Restricted Area" }, + .{ .acronym = "categoryOfRoad", .name = "Category of Road" }, + .{ .acronym = "categoryOfRunway", .name = "Category of Runway" }, + .{ .acronym = "categoryOfSchedule", .name = "Category of Schedule" }, + .{ .acronym = "categoryOfSeaArea", .name = "Category of Sea Area" }, + .{ .acronym = "categoryOfShorelineConstruction", .name = "Category of Shoreline Construction" }, + .{ .acronym = "categoryOfSignalStationTraffic", .name = "Category of Signal Station, Traffic" }, + .{ .acronym = "categoryOfSignalStationWarning", .name = "Category of Signal Station, Warning" }, + .{ .acronym = "categoryOfSiloTank", .name = "Category of Silo/Tank" }, + .{ .acronym = "categoryOfSlope", .name = "Category of Slope" }, + .{ .acronym = "categoryOfSmallCraftFacility", .name = "Category of Small Craft Facility" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .name = "Category of Special Purpose Mark" }, + .{ .acronym = "categoryOfTemporalVariation", .name = "Category of Temporal Variation" }, + .{ .acronym = "categoryOfTidalStream", .name = "Category of Tidal Stream" }, + .{ .acronym = "categoryOfVegetation", .name = "Category of Vegetation" }, + .{ .acronym = "categoryOfWaterTurbulence", .name = "Category of Water Turbulence" }, + .{ .acronym = "categoryOfWeedKelp", .name = "Category of Weed/Kelp" }, + .{ .acronym = "categoryOfWreck", .name = "Category of Wreck" }, + .{ .acronym = "categoryOfZoneOfConfidenceInData", .name = "Category of Zone of Confidence In Data" }, + .{ .acronym = "colour", .name = "Colour" }, + .{ .acronym = "colourPattern", .name = "Colour Pattern" }, + .{ .acronym = "communicationChannel", .name = "Communication Channel" }, + .{ .acronym = "condition", .name = "Condition" }, + .{ .acronym = "contactInstructions", .name = "Contact Instructions" }, + .{ .acronym = "dataAssessment", .name = "Data Assessment" }, + .{ .acronym = "dateDisused", .name = "Date Disused" }, + .{ .acronym = "dateEnd", .name = "Date End" }, + .{ .acronym = "dateFixed", .name = "Date Fixed" }, + .{ .acronym = "dateStart", .name = "Date Start" }, + .{ .acronym = "dateVariable", .name = "Date Variable" }, + .{ .acronym = "dayOfWeek", .name = "Day of Week" }, + .{ .acronym = "dayOfWeekIsRange", .name = "Day of Week is Range" }, + .{ .acronym = "defaultClearanceDepth", .name = "Default Clearance Depth" }, + .{ .acronym = "depthRangeMaximumValue", .name = "Depth Range Maximum Value" }, + .{ .acronym = "depthRangeMinimumValue", .name = "Depth Range Minimum Value" }, + .{ .acronym = "destination", .name = "Destination" }, + .{ .acronym = "displayName", .name = "Display Name" }, + .{ .acronym = "displayUncertainties", .name = "Display Uncertainties" }, + .{ .acronym = "distanceMarkVisible", .name = "Distance Mark Visible" }, + .{ .acronym = "distanceUnitOfMeasurement", .name = "Distance Unit of Measurement" }, + .{ .acronym = "dredgedDate", .name = "Dredged Date" }, + .{ .acronym = "elevation", .name = "Elevation" }, + .{ .acronym = "estimatedRangeOfTransmission", .name = "Estimated Range of Transmission" }, + .{ .acronym = "exhibitionConditionOfLight", .name = "Exhibition Condition of Light" }, + .{ .acronym = "expositionOfSounding", .name = "Exposition of Sounding" }, + .{ .acronym = "fileLocator", .name = "File Locator" }, + .{ .acronym = "fileReference", .name = "File Reference" }, + .{ .acronym = "flareBearing", .name = "Flare Bearing" }, + .{ .acronym = "flareStack", .name = "Flare Stack" }, + .{ .acronym = "frequencyShoreStationReceives", .name = "Frequency Shore Station Receives" }, + .{ .acronym = "frequencyShoreStationTransmits", .name = "Frequency Shore Station Transmits" }, + .{ .acronym = "fullSeafloorCoverageAchieved", .name = "Full Seafloor Coverage Achieved" }, + .{ .acronym = "function", .name = "Function" }, + .{ .acronym = "headline", .name = "Headline" }, + .{ .acronym = "height", .name = "Height" }, + .{ .acronym = "horizontalClearanceLength", .name = "Horizontal Clearance Length" }, + .{ .acronym = "horizontalClearanceValue", .name = "Horizontal Clearance Value" }, + .{ .acronym = "horizontalClearanceWidth", .name = "Horizontal Clearance Width" }, + .{ .acronym = "horizontalDistanceUncertainty", .name = "Horizontal Distance Uncertainty" }, + .{ .acronym = "horizontalLength", .name = "Horizontal Length" }, + .{ .acronym = "horizontalWidth", .name = "Horizontal Width" }, + .{ .acronym = "iceFactor", .name = "Ice Factor" }, + .{ .acronym = "iMOAdopted", .name = "IMO Adopted" }, + .{ .acronym = "inDispute", .name = "In Dispute" }, + .{ .acronym = "inTheWater", .name = "In the Water" }, + .{ .acronym = "isMRCC", .name = "Is MRCC" }, + .{ .acronym = "jurisdiction", .name = "Jurisdiction" }, + .{ .acronym = "language", .name = "Language" }, + .{ .acronym = "leastDepthOfDetectedFeaturesMeasured", .name = "Least Depth of Detected Features Measured" }, + .{ .acronym = "liftingCapacity", .name = "Lifting Capacity" }, + .{ .acronym = "lightCharacteristic", .name = "Light Characteristic" }, + .{ .acronym = "lightVisibility", .name = "Light Visibility" }, + .{ .acronym = "lineSpacingMaximum", .name = "Line Spacing Maximum" }, + .{ .acronym = "lineSpacingMinimum", .name = "Line Spacing Minimum" }, + .{ .acronym = "linkage", .name = "Linkage" }, + .{ .acronym = "magneticAnomalyValue", .name = "Magnetic Anomaly Value" }, + .{ .acronym = "referenceDirection", .name = "Reference Direction" }, + .{ .acronym = "majorLight", .name = "Major Light" }, + .{ .acronym = "marksNavigationalSystemOf", .name = "Marks Navigational - System Of" }, + .{ .acronym = "maximumDisplayScale", .name = "Maximum Display Scale" }, + .{ .acronym = "maximumPermittedDraught", .name = "Maximum Permitted Draught" }, + .{ .acronym = "measuredDistance", .name = "Measured Distance" }, + .{ .acronym = "measurementDistanceMaximum", .name = "Measurement Distance Maximum" }, + .{ .acronym = "measurementDistanceMinimum", .name = "Measurement Distance Minimum" }, + .{ .acronym = "minimumDisplayScale", .name = "Minimum Display Scale" }, + .{ .acronym = "mMSICode", .name = "MMSI Code" }, + .{ .acronym = "moireEffect", .name = "Moire Effect" }, + .{ .acronym = "multiplicityKnown", .name = "Multiplicity Known" }, + .{ .acronym = "name", .name = "Name" }, + .{ .acronym = "nameOfResource", .name = "Name of Resource" }, + .{ .acronym = "nationality", .name = "Nationality" }, + .{ .acronym = "natureOfConstruction", .name = "Nature of Construction" }, + .{ .acronym = "natureOfSurface", .name = "Nature of Surface" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .name = "Nature of Surface - Qualifying Terms" }, + .{ .acronym = "numberOfFeatures", .name = "Number of Features" }, + .{ .acronym = "orientationUncertainty", .name = "Orientation Uncertainty" }, + .{ .acronym = "orientationValue", .name = "Orientation Value" }, + .{ .acronym = "pictorialRepresentation", .name = "Pictorial Representation" }, + .{ .acronym = "pilotMovement", .name = "Pilot Movement" }, + .{ .acronym = "product", .name = "Product" }, + .{ .acronym = "qualityOfHorizontalMeasurement", .name = "Quality of Horizontal Measurement" }, + .{ .acronym = "qualityOfVerticalMeasurement", .name = "Quality of Vertical Measurement" }, + .{ .acronym = "radarBand", .name = "Radar Band" }, + .{ .acronym = "radarConspicuous", .name = "Radar Conspicuous" }, + .{ .acronym = "radius", .name = "Radius" }, + .{ .acronym = "referenceLocation", .name = "Reference Location" }, + .{ .acronym = "referenceTide", .name = "Reference Tide" }, + .{ .acronym = "referenceTideType", .name = "Reference Tide Type" }, + .{ .acronym = "referenceYearForMagneticVariation", .name = "Reference Year for Magnetic Variation" }, + .{ .acronym = "regulationCitation", .name = "Regulation Citation" }, + .{ .acronym = "reportedDate", .name = "Reported Date" }, + .{ .acronym = "restriction", .name = "Restriction" }, + .{ .acronym = "scaleMinimum", .name = "Scale Minimum" }, + .{ .acronym = "scaleValueMaximum", .name = "Scale Value Maximum" }, + .{ .acronym = "scaleValueMinimum", .name = "Scale Value Minimum" }, + .{ .acronym = "sectorBearing", .name = "Sector Bearing" }, + .{ .acronym = "sectorExtension", .name = "Sector Extension" }, + .{ .acronym = "sectorLineLength", .name = "Sector Line Length" }, + .{ .acronym = "signalDuration", .name = "Signal Duration" }, + .{ .acronym = "signalFrequency", .name = "Signal Frequency" }, + .{ .acronym = "signalGeneration", .name = "Signal Generation" }, + .{ .acronym = "signalGroup", .name = "Signal Group" }, + .{ .acronym = "signalPeriod", .name = "Signal Period" }, + .{ .acronym = "signalStatus", .name = "Signal Status" }, + .{ .acronym = "significantFeaturesDetected", .name = "Significant Features Detected" }, + .{ .acronym = "sizeOfFeaturesDetected", .name = "Size of Features Detected" }, + .{ .acronym = "source", .name = "Source" }, + .{ .acronym = "speedLimit", .name = "Speed Limit" }, + .{ .acronym = "speedMaximum", .name = "Speed Maximum" }, + .{ .acronym = "speedMinimum", .name = "Speed Minimum" }, + .{ .acronym = "stationName", .name = "Station Name" }, + .{ .acronym = "stationNumber", .name = "Station Number" }, + .{ .acronym = "status", .name = "Status" }, + .{ .acronym = "streamDepth", .name = "Stream Depth" }, + .{ .acronym = "surroundingDepth", .name = "Surrounding Depth" }, + .{ .acronym = "surveyAuthority", .name = "Survey Authority" }, + .{ .acronym = "surveyType", .name = "Survey Type" }, + .{ .acronym = "sweptDate", .name = "Swept Date" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .name = "Technique of Vertical Measurement" }, + .{ .acronym = "telecommunicationIdentifier", .name = "Telecommunication Identifier" }, + .{ .acronym = "telecommunicationService", .name = "Telecommunication Service" }, + .{ .acronym = "text", .name = "Text" }, + .{ .acronym = "textOffsetMm", .name = "Text Offset Mm" }, + .{ .acronym = "textType", .name = "Text Type" }, + .{ .acronym = "timeOfDayEnd", .name = "Time of Day End" }, + .{ .acronym = "timeOfDayStart", .name = "Time of Day Start" }, + .{ .acronym = "timeRelativeToTide", .name = "Time Relative to Tide" }, + .{ .acronym = "topmarkDaymarkShape", .name = "Topmark/Daymark Shape" }, + .{ .acronym = "trafficFlow", .name = "Traffic Flow" }, + .{ .acronym = "uncertaintyFixed", .name = "Uncertainty Fixed" }, + .{ .acronym = "uncertaintyVariableFactor", .name = "Uncertainty Variable Factor" }, + .{ .acronym = "underlyingLayer", .name = "Underlying Layer" }, + .{ .acronym = "valueOfAnnualChangeInMagneticVariation", .name = "Value of Annual Change in Magnetic Variation" }, + .{ .acronym = "valueOfDepthContour", .name = "Value of Depth Contour" }, + .{ .acronym = "valueOfMagneticVariation", .name = "Value of Magnetic Variation" }, + .{ .acronym = "valueOfMaximumRange", .name = "Value of Maximum Range" }, + .{ .acronym = "valueOfNominalRange", .name = "Value of Nominal Range" }, + .{ .acronym = "valueOfSounding", .name = "Value of Sounding" }, + .{ .acronym = "verticalClearanceValue", .name = "Vertical Clearance Value" }, + .{ .acronym = "verticalDatum", .name = "Vertical Datum" }, + .{ .acronym = "verticalLength", .name = "Vertical Length" }, + .{ .acronym = "vesselClass", .name = "Vessel Class" }, + .{ .acronym = "virtualAISAidToNavigationType", .name = "Virtual AIS Aid to Navigation Type" }, + .{ .acronym = "visualProminence", .name = "Visual Prominence" }, + .{ .acronym = "waterLevelEffect", .name = "Water Level Effect" }, + .{ .acronym = "waterwayDistance", .name = "Waterway Distance" }, + .{ .acronym = "waveLengthValue", .name = "Wave Length Value" }, + .{ .acronym = "categoryOfCargo", .name = "Category of Cargo" }, + .{ .acronym = "minimumBerthDepth", .name = "Minimum Berth Depth" }, +}; + +/// Every enumerated S-101 attribute's listed values, one per code. +pub const enum_values = [_]catalog.EnumValue{ + .{ .acronym = "beaconShape", .code = 1, .value = "stake, pole, perch, post" }, + .{ .acronym = "beaconShape", .code = 2, .value = "withy" }, + .{ .acronym = "beaconShape", .code = 3, .value = "beacon tower" }, + .{ .acronym = "beaconShape", .code = 5, .value = "pile beacon" }, + .{ .acronym = "beaconShape", .code = 6, .value = "cairn" }, + .{ .acronym = "beaconShape", .code = 7, .value = "buoyant beacon" }, + .{ .acronym = "buildingShape", .code = 5, .value = "high-rise building" }, + .{ .acronym = "buildingShape", .code = 6, .value = "pyramid" }, + .{ .acronym = "buildingShape", .code = 7, .value = "cylindrical" }, + .{ .acronym = "buildingShape", .code = 8, .value = "spherical" }, + .{ .acronym = "buildingShape", .code = 9, .value = "cubic" }, + .{ .acronym = "buoyShape", .code = 1, .value = "conical" }, + .{ .acronym = "buoyShape", .code = 2, .value = "can" }, + .{ .acronym = "buoyShape", .code = 3, .value = "spherical" }, + .{ .acronym = "buoyShape", .code = 4, .value = "pillar" }, + .{ .acronym = "buoyShape", .code = 5, .value = "spar" }, + .{ .acronym = "buoyShape", .code = 6, .value = "barrel" }, + .{ .acronym = "buoyShape", .code = 7, .value = "superbuoy" }, + .{ .acronym = "buoyShape", .code = 8, .value = "ice buoy" }, + .{ .acronym = "categoryOfAirportAirfield", .code = 1, .value = "military aeroplane airport" }, + .{ .acronym = "categoryOfAirportAirfield", .code = 2, .value = "civil aeroplane airport" }, + .{ .acronym = "categoryOfAirportAirfield", .code = 3, .value = "military heliport" }, + .{ .acronym = "categoryOfAirportAirfield", .code = 4, .value = "civil heliport" }, + .{ .acronym = "categoryOfAirportAirfield", .code = 5, .value = "glider airfield" }, + .{ .acronym = "categoryOfAirportAirfield", .code = 6, .value = "small planes airfield" }, + .{ .acronym = "categoryOfAirportAirfield", .code = 8, .value = "emergency airfield" }, + .{ .acronym = "categoryOfAirportAirfield", .code = 9, .value = "search and rescue airfield" }, + .{ .acronym = "categoryOfAnchorage", .code = 1, .value = "unrestricted anchorage" }, + .{ .acronym = "categoryOfAnchorage", .code = 2, .value = "deep water anchorage" }, + .{ .acronym = "categoryOfAnchorage", .code = 3, .value = "tanker anchorage" }, + .{ .acronym = "categoryOfAnchorage", .code = 4, .value = "explosives anchorage" }, + .{ .acronym = "categoryOfAnchorage", .code = 5, .value = "quarantine anchorage" }, + .{ .acronym = "categoryOfAnchorage", .code = 6, .value = "seaplane anchorage" }, + .{ .acronym = "categoryOfAnchorage", .code = 7, .value = "small craft anchorage" }, + .{ .acronym = "categoryOfAnchorage", .code = 8, .value = "small craft mooring area" }, + .{ .acronym = "categoryOfAnchorage", .code = 9, .value = "anchorage for periods up to 24 hours" }, + .{ .acronym = "categoryOfAnchorage", .code = 10, .value = "anchorage for a limited period of time" }, + .{ .acronym = "categoryOfAnchorage", .code = 14, .value = "waiting anchorage" }, + .{ .acronym = "categoryOfAnchorage", .code = 15, .value = "reported anchorage" }, + .{ .acronym = "categoryOfBridge", .code = 1, .value = "fixed bridge" }, + .{ .acronym = "categoryOfBridge", .code = 2, .value = "opening bridge" }, + .{ .acronym = "categoryOfBridge", .code = 3, .value = "swing bridge" }, + .{ .acronym = "categoryOfBridge", .code = 4, .value = "lifting bridge" }, + .{ .acronym = "categoryOfBridge", .code = 5, .value = "bascule bridge" }, + .{ .acronym = "categoryOfBridge", .code = 6, .value = "pontoon bridge" }, + .{ .acronym = "categoryOfBridge", .code = 7, .value = "drawbridge" }, + .{ .acronym = "categoryOfBridge", .code = 8, .value = "transporter bridge" }, + .{ .acronym = "categoryOfBridge", .code = 9, .value = "footbridge" }, + .{ .acronym = "categoryOfBridge", .code = 10, .value = "viaduct" }, + .{ .acronym = "categoryOfBridge", .code = 11, .value = "aqueduct" }, + .{ .acronym = "categoryOfBridge", .code = 12, .value = "suspension bridge" }, + .{ .acronym = "categoryOfBuiltUpArea", .code = 1, .value = "urban area" }, + .{ .acronym = "categoryOfBuiltUpArea", .code = 2, .value = "settlement" }, + .{ .acronym = "categoryOfBuiltUpArea", .code = 3, .value = "village" }, + .{ .acronym = "categoryOfBuiltUpArea", .code = 4, .value = "town" }, + .{ .acronym = "categoryOfBuiltUpArea", .code = 5, .value = "city" }, + .{ .acronym = "categoryOfBuiltUpArea", .code = 6, .value = "holiday village" }, + .{ .acronym = "categoryOfCable", .code = 1, .value = "power line" }, + .{ .acronym = "categoryOfCable", .code = 3, .value = "transmission line" }, + .{ .acronym = "categoryOfCable", .code = 4, .value = "telephone" }, + .{ .acronym = "categoryOfCable", .code = 5, .value = "telegraph" }, + .{ .acronym = "categoryOfCable", .code = 6, .value = "mooring cable" }, + .{ .acronym = "categoryOfCable", .code = 7, .value = "ferry" }, + .{ .acronym = "categoryOfCable", .code = 8, .value = "fibre optic cable" }, + .{ .acronym = "categoryOfCanal", .code = 1, .value = "transportation" }, + .{ .acronym = "categoryOfCanal", .code = 2, .value = "drainage" }, + .{ .acronym = "categoryOfCanal", .code = 3, .value = "irrigation" }, + .{ .acronym = "categoryOfCardinalMark", .code = 1, .value = "north cardinal mark" }, + .{ .acronym = "categoryOfCardinalMark", .code = 2, .value = "east cardinal mark" }, + .{ .acronym = "categoryOfCardinalMark", .code = 3, .value = "south cardinal mark" }, + .{ .acronym = "categoryOfCardinalMark", .code = 4, .value = "west cardinal mark" }, + .{ .acronym = "categoryOfCheckpoint", .code = 1, .value = "custom" }, + .{ .acronym = "categoryOfCoastline", .code = 1, .value = "steep coast" }, + .{ .acronym = "categoryOfCoastline", .code = 2, .value = "flat coast" }, + .{ .acronym = "categoryOfCoastline", .code = 6, .value = "glacier, seaward end" }, + .{ .acronym = "categoryOfCoastline", .code = 7, .value = "mangrove" }, + .{ .acronym = "categoryOfCoastline", .code = 8, .value = "marshy shore" }, + .{ .acronym = "categoryOfCoastline", .code = 10, .value = "ice coast" }, + .{ .acronym = "categoryOfConveyor", .code = 1, .value = "aerial cableway" }, + .{ .acronym = "categoryOfConveyor", .code = 2, .value = "belt conveyor" }, + .{ .acronym = "categoryOfConveyor", .code = 3, .value = "flume" }, + .{ .acronym = "categoryOfConveyor", .code = 4, .value = "lift/elevator" }, + .{ .acronym = "categoryOfCrane", .code = 2, .value = "container crane/gantry" }, + .{ .acronym = "categoryOfCrane", .code = 3, .value = "sheerlegs" }, + .{ .acronym = "categoryOfCrane", .code = 4, .value = "travelling crane" }, + .{ .acronym = "categoryOfCrane", .code = 5, .value = "a-frame" }, + .{ .acronym = "categoryOfCrane", .code = 6, .value = "goliath crane" }, + .{ .acronym = "categoryOfDam", .code = 1, .value = "weir" }, + .{ .acronym = "categoryOfDam", .code = 2, .value = "dam" }, + .{ .acronym = "categoryOfDam", .code = 3, .value = "flood barrage" }, + .{ .acronym = "categoryOfDock", .code = 1, .value = "tidal" }, + .{ .acronym = "categoryOfDock", .code = 2, .value = "wet dock" }, + .{ .acronym = "categoryOfDumpingGround", .code = 2, .value = "chemical waste dumping ground" }, + .{ .acronym = "categoryOfDumpingGround", .code = 3, .value = "nuclear waste dumping ground" }, + .{ .acronym = "categoryOfDumpingGround", .code = 4, .value = "explosives dumping ground" }, + .{ .acronym = "categoryOfDumpingGround", .code = 5, .value = "spoil ground" }, + .{ .acronym = "categoryOfDumpingGround", .code = 6, .value = "vessel dumping ground" }, + .{ .acronym = "categoryOfFence", .code = 1, .value = "fence" }, + .{ .acronym = "categoryOfFence", .code = 3, .value = "hedge" }, + .{ .acronym = "categoryOfFence", .code = 4, .value = "wall" }, + .{ .acronym = "categoryOfFerry", .code = 1, .value = "free moving ferry" }, + .{ .acronym = "categoryOfFerry", .code = 2, .value = "cable ferry" }, + .{ .acronym = "categoryOfFerry", .code = 3, .value = "ice ferry" }, + .{ .acronym = "categoryOfFerry", .code = 5, .value = "high speed ferry" }, + .{ .acronym = "categoryOfFishingFacility", .code = 1, .value = "fishing stake" }, + .{ .acronym = "categoryOfFishingFacility", .code = 2, .value = "fish trap" }, + .{ .acronym = "categoryOfFishingFacility", .code = 3, .value = "fish weir" }, + .{ .acronym = "categoryOfFishingFacility", .code = 4, .value = "tunny net" }, + .{ .acronym = "categoryOfFogSignal", .code = 1, .value = "explosive" }, + .{ .acronym = "categoryOfFogSignal", .code = 2, .value = "diaphone" }, + .{ .acronym = "categoryOfFogSignal", .code = 3, .value = "siren" }, + .{ .acronym = "categoryOfFogSignal", .code = 4, .value = "nautophone" }, + .{ .acronym = "categoryOfFogSignal", .code = 5, .value = "reed" }, + .{ .acronym = "categoryOfFogSignal", .code = 6, .value = "tyfon" }, + .{ .acronym = "categoryOfFogSignal", .code = 7, .value = "bell" }, + .{ .acronym = "categoryOfFogSignal", .code = 8, .value = "whistle" }, + .{ .acronym = "categoryOfFogSignal", .code = 9, .value = "gong" }, + .{ .acronym = "categoryOfFogSignal", .code = 10, .value = "horn" }, + .{ .acronym = "categoryOfFortifiedStructure", .code = 1, .value = "castle" }, + .{ .acronym = "categoryOfFortifiedStructure", .code = 2, .value = "fort" }, + .{ .acronym = "categoryOfFortifiedStructure", .code = 3, .value = "battery" }, + .{ .acronym = "categoryOfFortifiedStructure", .code = 4, .value = "blockhouse" }, + .{ .acronym = "categoryOfFortifiedStructure", .code = 5, .value = "fortified tower" }, + .{ .acronym = "categoryOfFortifiedStructure", .code = 6, .value = "redoubt" }, + .{ .acronym = "categoryOfFortifiedStructure", .code = 8, .value = "fortified submarine shelter" }, + .{ .acronym = "categoryOfFortifiedStructure", .code = 9, .value = "rampart" }, + .{ .acronym = "categoryOfGate", .code = 2, .value = "flood barrage gate" }, + .{ .acronym = "categoryOfGate", .code = 3, .value = "caisson" }, + .{ .acronym = "categoryOfGate", .code = 4, .value = "lock gate" }, + .{ .acronym = "categoryOfGate", .code = 5, .value = "dyke gate" }, + .{ .acronym = "categoryOfGate", .code = 6, .value = "sluice" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 1, .value = "roro terminal" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 3, .value = "ferry terminal" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 4, .value = "fishing harbour" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 5, .value = "yacht harbour/marina" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 6, .value = "naval base" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 7, .value = "tanker terminal" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 8, .value = "passenger terminal" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 9, .value = "shipyard" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 10, .value = "container terminal" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 11, .value = "bulk terminal" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 12, .value = "ship lift" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 13, .value = "straddle carrier" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 14, .value = "service harbour" }, + .{ .acronym = "categoryOfHarbourFacility", .code = 15, .value = "pilotage service" }, + .{ .acronym = "categoryOfHulk", .code = 1, .value = "floating restaurant" }, + .{ .acronym = "categoryOfHulk", .code = 2, .value = "historic ship" }, + .{ .acronym = "categoryOfHulk", .code = 3, .value = "floating museum" }, + .{ .acronym = "categoryOfHulk", .code = 4, .value = "floating accommodation" }, + .{ .acronym = "categoryOfHulk", .code = 5, .value = "floating breakwater" }, + .{ .acronym = "categoryOfHulk", .code = 6, .value = "casino" }, + .{ .acronym = "categoryOfHulk", .code = 7, .value = "training vessel" }, + .{ .acronym = "categoryOfIce", .code = 1, .value = "fast ice" }, + .{ .acronym = "categoryOfIce", .code = 5, .value = "glacier" }, + .{ .acronym = "categoryOfIce", .code = 8, .value = "polar ice" }, + .{ .acronym = "categoryOfInstallationBuoy", .code = 1, .value = "catenary anchor leg mooring" }, + .{ .acronym = "categoryOfInstallationBuoy", .code = 2, .value = "single buoy mooring" }, + .{ .acronym = "categoryOfLandRegion", .code = 1, .value = "fen" }, + .{ .acronym = "categoryOfLandRegion", .code = 2, .value = "marsh" }, + .{ .acronym = "categoryOfLandRegion", .code = 3, .value = "bog" }, + .{ .acronym = "categoryOfLandRegion", .code = 4, .value = "heathland" }, + .{ .acronym = "categoryOfLandRegion", .code = 5, .value = "mountain range" }, + .{ .acronym = "categoryOfLandRegion", .code = 6, .value = "lowlands" }, + .{ .acronym = "categoryOfLandRegion", .code = 7, .value = "canyon lands" }, + .{ .acronym = "categoryOfLandRegion", .code = 8, .value = "paddy field" }, + .{ .acronym = "categoryOfLandRegion", .code = 9, .value = "agricultural land" }, + .{ .acronym = "categoryOfLandRegion", .code = 10, .value = "savanna/grassland" }, + .{ .acronym = "categoryOfLandRegion", .code = 11, .value = "parkland" }, + .{ .acronym = "categoryOfLandRegion", .code = 12, .value = "swamp" }, + .{ .acronym = "categoryOfLandRegion", .code = 13, .value = "landslide" }, + .{ .acronym = "categoryOfLandRegion", .code = 14, .value = "lava flow" }, + .{ .acronym = "categoryOfLandRegion", .code = 15, .value = "salt pan" }, + .{ .acronym = "categoryOfLandRegion", .code = 16, .value = "moraine" }, + .{ .acronym = "categoryOfLandRegion", .code = 17, .value = "crater" }, + .{ .acronym = "categoryOfLandRegion", .code = 18, .value = "cave" }, + .{ .acronym = "categoryOfLandRegion", .code = 19, .value = "rock column or pinnacle" }, + .{ .acronym = "categoryOfLandRegion", .code = 20, .value = "cay" }, + .{ .acronym = "categoryOfLandRegion", .code = 21, .value = "wadi" }, + .{ .acronym = "categoryOfLandmark", .code = 1, .value = "cairn" }, + .{ .acronym = "categoryOfLandmark", .code = 2, .value = "cemetery" }, + .{ .acronym = "categoryOfLandmark", .code = 3, .value = "chimney" }, + .{ .acronym = "categoryOfLandmark", .code = 4, .value = "dish aerial" }, + .{ .acronym = "categoryOfLandmark", .code = 5, .value = "flagstaff" }, + .{ .acronym = "categoryOfLandmark", .code = 6, .value = "flare stack" }, + .{ .acronym = "categoryOfLandmark", .code = 7, .value = "mast" }, + .{ .acronym = "categoryOfLandmark", .code = 8, .value = "windsock" }, + .{ .acronym = "categoryOfLandmark", .code = 9, .value = "monument" }, + .{ .acronym = "categoryOfLandmark", .code = 10, .value = "column/pillar" }, + .{ .acronym = "categoryOfLandmark", .code = 11, .value = "memorial plaque" }, + .{ .acronym = "categoryOfLandmark", .code = 12, .value = "obelisk" }, + .{ .acronym = "categoryOfLandmark", .code = 13, .value = "statue" }, + .{ .acronym = "categoryOfLandmark", .code = 14, .value = "cross" }, + .{ .acronym = "categoryOfLandmark", .code = 15, .value = "dome" }, + .{ .acronym = "categoryOfLandmark", .code = 16, .value = "radar scanner" }, + .{ .acronym = "categoryOfLandmark", .code = 17, .value = "tower" }, + .{ .acronym = "categoryOfLandmark", .code = 18, .value = "windmill" }, + .{ .acronym = "categoryOfLandmark", .code = 20, .value = "spire/minaret" }, + .{ .acronym = "categoryOfLandmark", .code = 21, .value = "large rock or boulder on land" }, + .{ .acronym = "categoryOfLandmark", .code = 22, .value = "triangulation mark" }, + .{ .acronym = "categoryOfLandmark", .code = 23, .value = "boundary mark" }, + .{ .acronym = "categoryOfLandmark", .code = 24, .value = "observation wheel" }, + .{ .acronym = "categoryOfLandmark", .code = 25, .value = "torii" }, + .{ .acronym = "categoryOfLandmark", .code = 26, .value = "bridge" }, + .{ .acronym = "categoryOfLandmark", .code = 27, .value = "dam" }, + .{ .acronym = "categoryOfLateralMark", .code = 1, .value = "port-hand lateral mark" }, + .{ .acronym = "categoryOfLateralMark", .code = 2, .value = "starboard-hand lateral mark" }, + .{ .acronym = "categoryOfLateralMark", .code = 3, .value = "preferred channel to starboard lateral mark" }, + .{ .acronym = "categoryOfLateralMark", .code = 4, .value = "preferred channel to port lateral mark" }, + .{ .acronym = "categoryOfLight", .code = 4, .value = "leading light" }, + .{ .acronym = "categoryOfLight", .code = 5, .value = "aero light" }, + .{ .acronym = "categoryOfLight", .code = 8, .value = "flood light" }, + .{ .acronym = "categoryOfLight", .code = 9, .value = "strip light" }, + .{ .acronym = "categoryOfLight", .code = 10, .value = "subsidiary light" }, + .{ .acronym = "categoryOfLight", .code = 11, .value = "spotlight" }, + .{ .acronym = "categoryOfLight", .code = 12, .value = "front" }, + .{ .acronym = "categoryOfLight", .code = 13, .value = "rear" }, + .{ .acronym = "categoryOfLight", .code = 14, .value = "lower" }, + .{ .acronym = "categoryOfLight", .code = 15, .value = "upper" }, + .{ .acronym = "categoryOfLight", .code = 17, .value = "emergency" }, + .{ .acronym = "categoryOfLight", .code = 18, .value = "bearing light" }, + .{ .acronym = "categoryOfLight", .code = 19, .value = "horizontally disposed" }, + .{ .acronym = "categoryOfLight", .code = 20, .value = "vertically disposed" }, + .{ .acronym = "categoryOfMarineFarmCulture", .code = 1, .value = "crustaceans" }, + .{ .acronym = "categoryOfMarineFarmCulture", .code = 2, .value = "edible bivalve molluscs" }, + .{ .acronym = "categoryOfMarineFarmCulture", .code = 3, .value = "fish" }, + .{ .acronym = "categoryOfMarineFarmCulture", .code = 4, .value = "seaweed" }, + .{ .acronym = "categoryOfMarineFarmCulture", .code = 5, .value = "pearl culture farm" }, + .{ .acronym = "categoryOfMilitaryPracticeArea", .code = 2, .value = "torpedo exercise area" }, + .{ .acronym = "categoryOfMilitaryPracticeArea", .code = 3, .value = "submarine exercise area" }, + .{ .acronym = "categoryOfMilitaryPracticeArea", .code = 4, .value = "firing danger area" }, + .{ .acronym = "categoryOfMilitaryPracticeArea", .code = 5, .value = "mine-laying practice area" }, + .{ .acronym = "categoryOfMilitaryPracticeArea", .code = 6, .value = "small arms firing range" }, + .{ .acronym = "categoryOfMooringWarpingFacility", .code = 1, .value = "dolphin" }, + .{ .acronym = "categoryOfMooringWarpingFacility", .code = 2, .value = "deviation dolphin" }, + .{ .acronym = "categoryOfMooringWarpingFacility", .code = 3, .value = "bollard" }, + .{ .acronym = "categoryOfMooringWarpingFacility", .code = 4, .value = "tie-up wall" }, + .{ .acronym = "categoryOfMooringWarpingFacility", .code = 5, .value = "post or pile" }, + .{ .acronym = "categoryOfMooringWarpingFacility", .code = 6, .value = "mooring cable" }, + .{ .acronym = "categoryOfMooringWarpingFacility", .code = 7, .value = "mooring buoy" }, + .{ .acronym = "categoryOfNavigationLine", .code = 1, .value = "clearing line" }, + .{ .acronym = "categoryOfNavigationLine", .code = 2, .value = "transit line" }, + .{ .acronym = "categoryOfNavigationLine", .code = 3, .value = "leading line bearing a recommended track" }, + .{ .acronym = "categoryOfObstruction", .code = 1, .value = "snag/stump" }, + .{ .acronym = "categoryOfObstruction", .code = 2, .value = "wellhead" }, + .{ .acronym = "categoryOfObstruction", .code = 3, .value = "diffuser" }, + .{ .acronym = "categoryOfObstruction", .code = 4, .value = "crib" }, + .{ .acronym = "categoryOfObstruction", .code = 5, .value = "fish haven" }, + .{ .acronym = "categoryOfObstruction", .code = 6, .value = "foul area" }, + .{ .acronym = "categoryOfObstruction", .code = 8, .value = "ice boom" }, + .{ .acronym = "categoryOfObstruction", .code = 9, .value = "ground tackle" }, + .{ .acronym = "categoryOfObstruction", .code = 10, .value = "boom" }, + .{ .acronym = "categoryOfObstruction", .code = 12, .value = "wave energy device" }, + .{ .acronym = "categoryOfObstruction", .code = 13, .value = "subsurface ocean data acquisition system" }, + .{ .acronym = "categoryOfObstruction", .code = 14, .value = "artificial reef" }, + .{ .acronym = "categoryOfObstruction", .code = 15, .value = "template" }, + .{ .acronym = "categoryOfObstruction", .code = 16, .value = "manifold" }, + .{ .acronym = "categoryOfObstruction", .code = 17, .value = "submerged pingo" }, + .{ .acronym = "categoryOfObstruction", .code = 18, .value = "remains of platform" }, + .{ .acronym = "categoryOfObstruction", .code = 19, .value = "scientific instrument" }, + .{ .acronym = "categoryOfObstruction", .code = 20, .value = "underwater turbine" }, + .{ .acronym = "categoryOfObstruction", .code = 21, .value = "active submarine volcano" }, + .{ .acronym = "categoryOfObstruction", .code = 22, .value = "shark net" }, + .{ .acronym = "categoryOfObstruction", .code = 23, .value = "mangrove" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 1, .value = "oil rig" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 2, .value = "production platform" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 3, .value = "observation/research platform" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 4, .value = "articulated loading platform" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 5, .value = "single anchor leg mooring" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 6, .value = "mooring tower" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 7, .value = "artificial island" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 8, .value = "floating production, storage and off-loading vessel" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 9, .value = "accommodation platform" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 10, .value = "navigation, communication and control buoy" }, + .{ .acronym = "categoryOfOffshorePlatform", .code = 11, .value = "floating oil tank" }, + .{ .acronym = "categoryOfOffshoreProductionArea", .code = 1, .value = "wind farm" }, + .{ .acronym = "categoryOfOffshoreProductionArea", .code = 2, .value = "wave farm" }, + .{ .acronym = "categoryOfOffshoreProductionArea", .code = 3, .value = "current farm" }, + .{ .acronym = "categoryOfOffshoreProductionArea", .code = 4, .value = "tank farm" }, + .{ .acronym = "categoryOfOffshoreProductionArea", .code = 5, .value = "seabed material extraction area" }, + .{ .acronym = "categoryOfOffshoreProductionArea", .code = 6, .value = "solar farm" }, + .{ .acronym = "categoryOfOilBarrier", .code = 1, .value = "oil retention (high pressure pipe)" }, + .{ .acronym = "categoryOfOilBarrier", .code = 2, .value = "floating oil barrier" }, + .{ .acronym = "categoryOfPile", .code = 1, .value = "stake" }, + .{ .acronym = "categoryOfPile", .code = 3, .value = "post" }, + .{ .acronym = "categoryOfPile", .code = 4, .value = "tripodal" }, + .{ .acronym = "categoryOfPile", .code = 5, .value = "piling" }, + .{ .acronym = "categoryOfPile", .code = 6, .value = "area of piles" }, + .{ .acronym = "categoryOfPile", .code = 7, .value = "pipe" }, + .{ .acronym = "categoryOfPilotBoardingPlace", .code = 1, .value = "boarding by pilot-cruising vessel" }, + .{ .acronym = "categoryOfPilotBoardingPlace", .code = 2, .value = "boarding by helicopter" }, + .{ .acronym = "categoryOfPilotBoardingPlace", .code = 3, .value = "pilot comes out from shore" }, + .{ .acronym = "categoryOfPipelinePipe", .code = 2, .value = "outfall pipe" }, + .{ .acronym = "categoryOfPipelinePipe", .code = 3, .value = "intake pipe" }, + .{ .acronym = "categoryOfPipelinePipe", .code = 4, .value = "sewer" }, + .{ .acronym = "categoryOfPipelinePipe", .code = 5, .value = "bubbler system" }, + .{ .acronym = "categoryOfPipelinePipe", .code = 6, .value = "supply pipe" }, + .{ .acronym = "categoryOfPipelinePipe", .code = 7, .value = "bubble curtain" }, + .{ .acronym = "categoryOfPreference", .code = 1, .value = "primary" }, + .{ .acronym = "categoryOfPreference", .code = 2, .value = "alternate" }, + .{ .acronym = "categoryOfProductionArea", .code = 1, .value = "quarry" }, + .{ .acronym = "categoryOfProductionArea", .code = 2, .value = "mine" }, + .{ .acronym = "categoryOfProductionArea", .code = 3, .value = "stockpile" }, + .{ .acronym = "categoryOfProductionArea", .code = 4, .value = "power station area" }, + .{ .acronym = "categoryOfProductionArea", .code = 5, .value = "refinery area" }, + .{ .acronym = "categoryOfProductionArea", .code = 6, .value = "timber yard" }, + .{ .acronym = "categoryOfProductionArea", .code = 7, .value = "factory area" }, + .{ .acronym = "categoryOfProductionArea", .code = 8, .value = "tank farm" }, + .{ .acronym = "categoryOfProductionArea", .code = 9, .value = "wind farm" }, + .{ .acronym = "categoryOfProductionArea", .code = 10, .value = "slag heap/spoil heap" }, + .{ .acronym = "categoryOfProductionArea", .code = 11, .value = "production plant" }, + .{ .acronym = "categoryOfProductionArea", .code = 12, .value = "solar farm" }, + .{ .acronym = "categoryOfPylon", .code = 1, .value = "power transmission pylon/pole" }, + .{ .acronym = "categoryOfPylon", .code = 2, .value = "telephone/telegraph pylon/pole" }, + .{ .acronym = "categoryOfPylon", .code = 3, .value = "aerial cableway pylon" }, + .{ .acronym = "categoryOfPylon", .code = 4, .value = "bridge pylon/tower" }, + .{ .acronym = "categoryOfPylon", .code = 5, .value = "bridge pier" }, + .{ .acronym = "categoryOfPylon", .code = 6, .value = "pipeline pylon" }, + .{ .acronym = "categoryOfRadarStation", .code = 1, .value = "radar surveillance station" }, + .{ .acronym = "categoryOfRadarStation", .code = 2, .value = "coast radar station" }, + .{ .acronym = "categoryOfRadarTransponderBeacon", .code = 1, .value = "ramark, radar beacon transmitting continuously" }, + .{ .acronym = "categoryOfRadarTransponderBeacon", .code = 2, .value = "racon, radar transponder beacon" }, + .{ .acronym = "categoryOfRadarTransponderBeacon", .code = 3, .value = "leading racon/radar transponder beacon" }, + .{ .acronym = "categoryOfRadioStation", .code = 5, .value = "radio direction-finding station" }, + .{ .acronym = "categoryOfRadioStation", .code = 10, .value = "differential GNSS" }, + .{ .acronym = "categoryOfRadioStation", .code = 11, .value = "toran" }, + .{ .acronym = "categoryOfRadioStation", .code = 14, .value = "chaika" }, + .{ .acronym = "categoryOfRadioStation", .code = 19, .value = "radio telephone station" }, + .{ .acronym = "categoryOfRadioStation", .code = 20, .value = "AIS base station" }, + .{ .acronym = "categoryOfRescueStation", .code = 1, .value = "rescue station with lifeboat" }, + .{ .acronym = "categoryOfRescueStation", .code = 2, .value = "rescue station with rocket" }, + .{ .acronym = "categoryOfRescueStation", .code = 4, .value = "refuge for shipwrecked mariners" }, + .{ .acronym = "categoryOfRescueStation", .code = 5, .value = "refuge for intertidal area walkers" }, + .{ .acronym = "categoryOfRescueStation", .code = 6, .value = "lifeboat lying at a mooring" }, + .{ .acronym = "categoryOfRescueStation", .code = 7, .value = "aid radio station" }, + .{ .acronym = "categoryOfRescueStation", .code = 8, .value = "first aid equipment" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 1, .value = "offshore safety zone" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 4, .value = "nature reserve" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 5, .value = "bird sanctuary" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 6, .value = "game reserve" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 7, .value = "seal sanctuary" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 8, .value = "degaussing range" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 9, .value = "military area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 10, .value = "historic wreck area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 12, .value = "navigational aid safety zone" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 14, .value = "minefield" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 18, .value = "swimming area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 19, .value = "waiting area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 20, .value = "research area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 21, .value = "dredging area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 22, .value = "fish sanctuary" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 23, .value = "ecological reserve" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 24, .value = "no wake area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 25, .value = "swinging area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 27, .value = "environmentally sensitive sea area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 28, .value = "particularly sensitive sea area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 29, .value = "disengagement area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 30, .value = "port security area" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 31, .value = "coral sanctuary" }, + .{ .acronym = "categoryOfRestrictedArea", .code = 32, .value = "recreation area" }, + .{ .acronym = "categoryOfRoad", .code = 1, .value = "motorway" }, + .{ .acronym = "categoryOfRoad", .code = 2, .value = "major road" }, + .{ .acronym = "categoryOfRoad", .code = 3, .value = "minor road" }, + .{ .acronym = "categoryOfRoad", .code = 4, .value = "track/path" }, + .{ .acronym = "categoryOfRoad", .code = 5, .value = "major street" }, + .{ .acronym = "categoryOfRoad", .code = 6, .value = "minor street" }, + .{ .acronym = "categoryOfRunway", .code = 1, .value = "aeroplane runway" }, + .{ .acronym = "categoryOfRunway", .code = 2, .value = "helicopter landing pad" }, + .{ .acronym = "categoryOfSchedule", .code = 1, .value = "normal operation" }, + .{ .acronym = "categoryOfSchedule", .code = 2, .value = "closure" }, + .{ .acronym = "categoryOfSchedule", .code = 3, .value = "unmanned operation" }, + .{ .acronym = "categoryOfSeaArea", .code = 2, .value = "gat" }, + .{ .acronym = "categoryOfSeaArea", .code = 3, .value = "bank" }, + .{ .acronym = "categoryOfSeaArea", .code = 4, .value = "deep" }, + .{ .acronym = "categoryOfSeaArea", .code = 5, .value = "bay" }, + .{ .acronym = "categoryOfSeaArea", .code = 6, .value = "trench" }, + .{ .acronym = "categoryOfSeaArea", .code = 7, .value = "basin" }, + .{ .acronym = "categoryOfSeaArea", .code = 8, .value = "mud flats" }, + .{ .acronym = "categoryOfSeaArea", .code = 9, .value = "reef" }, + .{ .acronym = "categoryOfSeaArea", .code = 10, .value = "ledge" }, + .{ .acronym = "categoryOfSeaArea", .code = 11, .value = "canyon" }, + .{ .acronym = "categoryOfSeaArea", .code = 12, .value = "narrows" }, + .{ .acronym = "categoryOfSeaArea", .code = 13, .value = "shoal" }, + .{ .acronym = "categoryOfSeaArea", .code = 14, .value = "knoll" }, + .{ .acronym = "categoryOfSeaArea", .code = 15, .value = "ridge" }, + .{ .acronym = "categoryOfSeaArea", .code = 16, .value = "seamount" }, + .{ .acronym = "categoryOfSeaArea", .code = 17, .value = "pinnacle" }, + .{ .acronym = "categoryOfSeaArea", .code = 18, .value = "abyssal plain" }, + .{ .acronym = "categoryOfSeaArea", .code = 19, .value = "plateau" }, + .{ .acronym = "categoryOfSeaArea", .code = 20, .value = "spur" }, + .{ .acronym = "categoryOfSeaArea", .code = 21, .value = "shelf" }, + .{ .acronym = "categoryOfSeaArea", .code = 22, .value = "trough" }, + .{ .acronym = "categoryOfSeaArea", .code = 23, .value = "saddle" }, + .{ .acronym = "categoryOfSeaArea", .code = 24, .value = "abyssal hills" }, + .{ .acronym = "categoryOfSeaArea", .code = 25, .value = "apron" }, + .{ .acronym = "categoryOfSeaArea", .code = 26, .value = "archipelagic apron" }, + .{ .acronym = "categoryOfSeaArea", .code = 27, .value = "borderland" }, + .{ .acronym = "categoryOfSeaArea", .code = 28, .value = "continental margin" }, + .{ .acronym = "categoryOfSeaArea", .code = 29, .value = "continental rise" }, + .{ .acronym = "categoryOfSeaArea", .code = 30, .value = "escarpment" }, + .{ .acronym = "categoryOfSeaArea", .code = 31, .value = "fan" }, + .{ .acronym = "categoryOfSeaArea", .code = 32, .value = "fracture zone" }, + .{ .acronym = "categoryOfSeaArea", .code = 33, .value = "gap" }, + .{ .acronym = "categoryOfSeaArea", .code = 34, .value = "guyot" }, + .{ .acronym = "categoryOfSeaArea", .code = 35, .value = "hill" }, + .{ .acronym = "categoryOfSeaArea", .code = 36, .value = "hole" }, + .{ .acronym = "categoryOfSeaArea", .code = 37, .value = "levee" }, + .{ .acronym = "categoryOfSeaArea", .code = 38, .value = "median valley" }, + .{ .acronym = "categoryOfSeaArea", .code = 39, .value = "moat" }, + .{ .acronym = "categoryOfSeaArea", .code = 40, .value = "mountains" }, + .{ .acronym = "categoryOfSeaArea", .code = 41, .value = "peak" }, + .{ .acronym = "categoryOfSeaArea", .code = 42, .value = "province" }, + .{ .acronym = "categoryOfSeaArea", .code = 43, .value = "rise" }, + .{ .acronym = "categoryOfSeaArea", .code = 44, .value = "sea channel" }, + .{ .acronym = "categoryOfSeaArea", .code = 45, .value = "seamount chain" }, + .{ .acronym = "categoryOfSeaArea", .code = 46, .value = "shelf-edge" }, + .{ .acronym = "categoryOfSeaArea", .code = 47, .value = "sill" }, + .{ .acronym = "categoryOfSeaArea", .code = 48, .value = "slope" }, + .{ .acronym = "categoryOfSeaArea", .code = 49, .value = "terrace" }, + .{ .acronym = "categoryOfSeaArea", .code = 50, .value = "valley" }, + .{ .acronym = "categoryOfSeaArea", .code = 51, .value = "canal" }, + .{ .acronym = "categoryOfSeaArea", .code = 52, .value = "lake" }, + .{ .acronym = "categoryOfSeaArea", .code = 53, .value = "river" }, + .{ .acronym = "categoryOfSeaArea", .code = 54, .value = "reach" }, + .{ .acronym = "categoryOfSeaArea", .code = 55, .value = "intertidal cay" }, + .{ .acronym = "categoryOfSeaArea", .code = 56, .value = "submarine volcano" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 1, .value = "breakwater" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 2, .value = "groyne" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 3, .value = "mole" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 4, .value = "pier (jetty)" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 5, .value = "promenade pier" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 6, .value = "wharf" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 7, .value = "training wall" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 8, .value = "rip rap" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 9, .value = "revetment" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 10, .value = "sea wall" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 11, .value = "landing steps" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 12, .value = "ramp" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 13, .value = "slipway" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 14, .value = "fender" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 15, .value = "solid face wharf" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 16, .value = "open face wharf" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 17, .value = "log ramp" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 20, .value = "swimming facility" }, + .{ .acronym = "categoryOfShorelineConstruction", .code = 22, .value = "quay" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 1, .value = "port control" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 2, .value = "port entry and departure" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 3, .value = "international port traffic" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 4, .value = "berthing" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 5, .value = "dock" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 6, .value = "lock" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 7, .value = "flood barrage station" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 8, .value = "bridge passage" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 9, .value = "dredging" }, + .{ .acronym = "categoryOfSignalStationTraffic", .code = 10, .value = "traffic control light" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 1, .value = "danger" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 2, .value = "maritime obstruction" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 3, .value = "cable" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 4, .value = "military practice" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 5, .value = "distress" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 6, .value = "weather" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 7, .value = "storm" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 8, .value = "ice warning" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 9, .value = "time" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 10, .value = "tide" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 11, .value = "tidal stream" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 12, .value = "tide gauge" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 13, .value = "tide scale" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 14, .value = "diving" }, + .{ .acronym = "categoryOfSignalStationWarning", .code = 15, .value = "water level gauge" }, + .{ .acronym = "categoryOfSiloTank", .code = 1, .value = "silo in general" }, + .{ .acronym = "categoryOfSiloTank", .code = 2, .value = "tank in general" }, + .{ .acronym = "categoryOfSiloTank", .code = 3, .value = "grain elevator" }, + .{ .acronym = "categoryOfSiloTank", .code = 4, .value = "water tower" }, + .{ .acronym = "categoryOfSlope", .code = 1, .value = "cutting" }, + .{ .acronym = "categoryOfSlope", .code = 2, .value = "embankment" }, + .{ .acronym = "categoryOfSlope", .code = 3, .value = "dune" }, + .{ .acronym = "categoryOfSlope", .code = 4, .value = "hill" }, + .{ .acronym = "categoryOfSlope", .code = 5, .value = "pingo" }, + .{ .acronym = "categoryOfSlope", .code = 6, .value = "cliff" }, + .{ .acronym = "categoryOfSlope", .code = 7, .value = "scree" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 1, .value = "visitors berth" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 2, .value = "nautical club" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 3, .value = "boat hoist" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 4, .value = "sailmaker" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 5, .value = "boatyard" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 6, .value = "public inn" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 7, .value = "restaurant" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 8, .value = "chandler" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 9, .value = "provisions" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 10, .value = "doctor" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 11, .value = "pharmacy" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 12, .value = "water tap" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 13, .value = "fuel station" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 14, .value = "electricity outlet" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 15, .value = "bottle gas" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 16, .value = "showers" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 17, .value = "launderette" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 18, .value = "public toilets" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 19, .value = "post box" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 20, .value = "public telephone" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 21, .value = "refuse bin" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 22, .value = "car park" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 23, .value = "parking for boats and trailers" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 24, .value = "caravan site" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 25, .value = "camping site" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 26, .value = "sewage pump-out station" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 27, .value = "emergency telephone" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 28, .value = "landing/launching place for boats" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 29, .value = "visitors mooring" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 30, .value = "scrubbing berth" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 31, .value = "picnic area" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 32, .value = "mechanics workshop" }, + .{ .acronym = "categoryOfSmallCraftFacility", .code = 33, .value = "guard and/or security service" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 1, .value = "firing danger mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 2, .value = "target mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 3, .value = "marker ship mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 4, .value = "degaussing range mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 5, .value = "barge mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 6, .value = "cable mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 7, .value = "spoil ground mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 8, .value = "outfall mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 9, .value = "ODAS" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 10, .value = "recording mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 11, .value = "seaplane anchorage mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 12, .value = "recreation zone mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 14, .value = "mooring mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 15, .value = "LANBY" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 16, .value = "leading mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 17, .value = "measured distance mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 18, .value = "notice mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 19, .value = "TSS mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 20, .value = "anchoring prohibited mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 21, .value = "berthing prohibited mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 22, .value = "overtaking prohibited mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 23, .value = "two-way traffic prohibited mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 24, .value = "reduced wake mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 25, .value = "speed limit mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 26, .value = "stop mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 27, .value = "general warning mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 28, .value = "sound ship's siren mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 29, .value = "restricted vertical clearance mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 30, .value = "maximum vessel's draught mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 31, .value = "restricted horizontal clearance mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 32, .value = "strong current warning mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 33, .value = "berthing permitted mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 34, .value = "overhead power cable mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 35, .value = "channel edge gradient mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 36, .value = "telephone mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 37, .value = "ferry crossing mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 39, .value = "pipeline mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 40, .value = "anchorage mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 41, .value = "clearing mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 42, .value = "control mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 43, .value = "diving mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 44, .value = "refuge beacon" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 45, .value = "foul ground mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 46, .value = "yachting mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 47, .value = "heliport mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 48, .value = "GNSS mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 49, .value = "seaplane landing mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 50, .value = "entry prohibited mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 51, .value = "work in progress mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 52, .value = "mark with unknown purpose" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 53, .value = "wellhead mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 54, .value = "channel separation mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 55, .value = "marine farm mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 56, .value = "artificial reef mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 57, .value = "ice mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 58, .value = "nature reserve mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 59, .value = "fish aggregating device" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 60, .value = "wreck mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 61, .value = "customs mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 62, .value = "causeway mark" }, + .{ .acronym = "categoryOfSpecialPurposeMark", .code = 63, .value = "wave recorder" }, + .{ .acronym = "categoryOfTemporalVariation", .code = 1, .value = "extreme event" }, + .{ .acronym = "categoryOfTemporalVariation", .code = 2, .value = "likely to change and significant shoaling expected" }, + .{ .acronym = "categoryOfTemporalVariation", .code = 3, .value = "likely to change but significant shoaling not expected" }, + .{ .acronym = "categoryOfTemporalVariation", .code = 4, .value = "likely to change" }, + .{ .acronym = "categoryOfTemporalVariation", .code = 5, .value = "unlikely to change" }, + .{ .acronym = "categoryOfTemporalVariation", .code = 6, .value = "unassessed" }, + .{ .acronym = "categoryOfTidalStream", .code = 1, .value = "flood stream" }, + .{ .acronym = "categoryOfTidalStream", .code = 2, .value = "ebb stream" }, + .{ .acronym = "categoryOfTidalStream", .code = 3, .value = "other tidal flow" }, + .{ .acronym = "categoryOfVegetation", .code = 3, .value = "bush" }, + .{ .acronym = "categoryOfVegetation", .code = 4, .value = "deciduous wood" }, + .{ .acronym = "categoryOfVegetation", .code = 5, .value = "coniferous wood" }, + .{ .acronym = "categoryOfVegetation", .code = 6, .value = "wood in general (inc mixed wood)" }, + .{ .acronym = "categoryOfVegetation", .code = 11, .value = "reed" }, + .{ .acronym = "categoryOfVegetation", .code = 13, .value = "tree in general" }, + .{ .acronym = "categoryOfVegetation", .code = 14, .value = "evergreen tree" }, + .{ .acronym = "categoryOfVegetation", .code = 15, .value = "coniferous tree" }, + .{ .acronym = "categoryOfVegetation", .code = 16, .value = "palm tree" }, + .{ .acronym = "categoryOfVegetation", .code = 17, .value = "nipa palm tree" }, + .{ .acronym = "categoryOfVegetation", .code = 18, .value = "casuarina tree" }, + .{ .acronym = "categoryOfVegetation", .code = 19, .value = "eucalypt tree" }, + .{ .acronym = "categoryOfVegetation", .code = 20, .value = "deciduous tree" }, + .{ .acronym = "categoryOfVegetation", .code = 22, .value = "filao tree" }, + .{ .acronym = "categoryOfWaterTurbulence", .code = 1, .value = "breakers" }, + .{ .acronym = "categoryOfWaterTurbulence", .code = 2, .value = "eddies" }, + .{ .acronym = "categoryOfWaterTurbulence", .code = 3, .value = "overfalls" }, + .{ .acronym = "categoryOfWaterTurbulence", .code = 4, .value = "tide rips" }, + .{ .acronym = "categoryOfWaterTurbulence", .code = 5, .value = "bombora" }, + .{ .acronym = "categoryOfWeedKelp", .code = 1, .value = "kelp" }, + .{ .acronym = "categoryOfWeedKelp", .code = 2, .value = "seaweed" }, + .{ .acronym = "categoryOfWeedKelp", .code = 4, .value = "sargasso" }, + .{ .acronym = "categoryOfWreck", .code = 1, .value = "non-dangerous wreck" }, + .{ .acronym = "categoryOfWreck", .code = 2, .value = "dangerous wreck" }, + .{ .acronym = "categoryOfWreck", .code = 3, .value = "distributed remains of wreck" }, + .{ .acronym = "categoryOfWreck", .code = 4, .value = "wreck showing mast/masts" }, + .{ .acronym = "categoryOfWreck", .code = 5, .value = "wreck showing any portion of hull or superstructure" }, + .{ .acronym = "categoryOfZoneOfConfidenceInData", .code = 1, .value = "zone of confidence a1" }, + .{ .acronym = "categoryOfZoneOfConfidenceInData", .code = 2, .value = "zone of confidence a2" }, + .{ .acronym = "categoryOfZoneOfConfidenceInData", .code = 3, .value = "zone of confidence b" }, + .{ .acronym = "categoryOfZoneOfConfidenceInData", .code = 4, .value = "zone of confidence c" }, + .{ .acronym = "categoryOfZoneOfConfidenceInData", .code = 5, .value = "zone of confidence d" }, + .{ .acronym = "categoryOfZoneOfConfidenceInData", .code = 6, .value = "zone of confidence u" }, + .{ .acronym = "colour", .code = 1, .value = "white" }, + .{ .acronym = "colour", .code = 2, .value = "black" }, + .{ .acronym = "colour", .code = 3, .value = "red" }, + .{ .acronym = "colour", .code = 4, .value = "green" }, + .{ .acronym = "colour", .code = 5, .value = "blue" }, + .{ .acronym = "colour", .code = 6, .value = "yellow" }, + .{ .acronym = "colour", .code = 7, .value = "grey" }, + .{ .acronym = "colour", .code = 8, .value = "brown" }, + .{ .acronym = "colour", .code = 9, .value = "amber" }, + .{ .acronym = "colour", .code = 10, .value = "violet" }, + .{ .acronym = "colour", .code = 11, .value = "orange" }, + .{ .acronym = "colour", .code = 12, .value = "magenta" }, + .{ .acronym = "colour", .code = 13, .value = "pink" }, + .{ .acronym = "colourPattern", .code = 1, .value = "horizontal stripes" }, + .{ .acronym = "colourPattern", .code = 2, .value = "vertical stripes" }, + .{ .acronym = "colourPattern", .code = 3, .value = "diagonal stripes" }, + .{ .acronym = "colourPattern", .code = 4, .value = "squared" }, + .{ .acronym = "colourPattern", .code = 5, .value = "stripes (direction unknown)" }, + .{ .acronym = "colourPattern", .code = 6, .value = "border stripe" }, + .{ .acronym = "condition", .code = 1, .value = "under construction" }, + .{ .acronym = "condition", .code = 2, .value = "ruined" }, + .{ .acronym = "condition", .code = 3, .value = "under reclamation" }, + .{ .acronym = "condition", .code = 4, .value = "wingless" }, + .{ .acronym = "condition", .code = 5, .value = "planned construction" }, + .{ .acronym = "dataAssessment", .code = 1, .value = "assessed" }, + .{ .acronym = "dataAssessment", .code = 2, .value = "assessed (oceanic)" }, + .{ .acronym = "dataAssessment", .code = 3, .value = "unassessed" }, + .{ .acronym = "dayOfWeek", .code = 1, .value = "sunday" }, + .{ .acronym = "dayOfWeek", .code = 2, .value = "monday" }, + .{ .acronym = "dayOfWeek", .code = 3, .value = "tuesday" }, + .{ .acronym = "dayOfWeek", .code = 4, .value = "wednesday" }, + .{ .acronym = "dayOfWeek", .code = 5, .value = "thursday" }, + .{ .acronym = "dayOfWeek", .code = 6, .value = "friday" }, + .{ .acronym = "dayOfWeek", .code = 7, .value = "saturday" }, + .{ .acronym = "distanceUnitOfMeasurement", .code = 1, .value = "metres" }, + .{ .acronym = "distanceUnitOfMeasurement", .code = 2, .value = "yards" }, + .{ .acronym = "distanceUnitOfMeasurement", .code = 3, .value = "kilometres" }, + .{ .acronym = "distanceUnitOfMeasurement", .code = 4, .value = "statute miles" }, + .{ .acronym = "distanceUnitOfMeasurement", .code = 5, .value = "nautical miles" }, + .{ .acronym = "exhibitionConditionOfLight", .code = 1, .value = "light shown without change of character" }, + .{ .acronym = "exhibitionConditionOfLight", .code = 2, .value = "daytime light" }, + .{ .acronym = "exhibitionConditionOfLight", .code = 3, .value = "fog light" }, + .{ .acronym = "exhibitionConditionOfLight", .code = 4, .value = "night light" }, + .{ .acronym = "expositionOfSounding", .code = 1, .value = "within the range of depth of the surrounding depth area" }, + .{ .acronym = "expositionOfSounding", .code = 2, .value = "shoaler than the range of depth of the surrounding depth area" }, + .{ .acronym = "expositionOfSounding", .code = 3, .value = "deeper than the range of depth of the surrounding depth area" }, + .{ .acronym = "function", .code = 2, .value = "harbour-masters office" }, + .{ .acronym = "function", .code = 3, .value = "customs office" }, + .{ .acronym = "function", .code = 4, .value = "health office" }, + .{ .acronym = "function", .code = 5, .value = "hospital" }, + .{ .acronym = "function", .code = 6, .value = "post office" }, + .{ .acronym = "function", .code = 7, .value = "hotel" }, + .{ .acronym = "function", .code = 8, .value = "railway station" }, + .{ .acronym = "function", .code = 9, .value = "police station" }, + .{ .acronym = "function", .code = 10, .value = "water-police station" }, + .{ .acronym = "function", .code = 11, .value = "pilot office" }, + .{ .acronym = "function", .code = 12, .value = "pilot lookout" }, + .{ .acronym = "function", .code = 13, .value = "bank office" }, + .{ .acronym = "function", .code = 14, .value = "headquarters for district control" }, + .{ .acronym = "function", .code = 15, .value = "transit shed/warehouse" }, + .{ .acronym = "function", .code = 16, .value = "factory" }, + .{ .acronym = "function", .code = 17, .value = "power station" }, + .{ .acronym = "function", .code = 18, .value = "administrative" }, + .{ .acronym = "function", .code = 19, .value = "educational facility" }, + .{ .acronym = "function", .code = 20, .value = "church" }, + .{ .acronym = "function", .code = 21, .value = "chapel" }, + .{ .acronym = "function", .code = 22, .value = "temple" }, + .{ .acronym = "function", .code = 23, .value = "pagoda" }, + .{ .acronym = "function", .code = 24, .value = "shinto shrine" }, + .{ .acronym = "function", .code = 25, .value = "buddhist temple" }, + .{ .acronym = "function", .code = 26, .value = "mosque" }, + .{ .acronym = "function", .code = 27, .value = "marabout" }, + .{ .acronym = "function", .code = 28, .value = "lookout" }, + .{ .acronym = "function", .code = 29, .value = "communication" }, + .{ .acronym = "function", .code = 30, .value = "television" }, + .{ .acronym = "function", .code = 31, .value = "radio" }, + .{ .acronym = "function", .code = 32, .value = "radar" }, + .{ .acronym = "function", .code = 33, .value = "light support" }, + .{ .acronym = "function", .code = 34, .value = "microwave" }, + .{ .acronym = "function", .code = 35, .value = "cooling" }, + .{ .acronym = "function", .code = 36, .value = "observation" }, + .{ .acronym = "function", .code = 37, .value = "timeball" }, + .{ .acronym = "function", .code = 38, .value = "clock" }, + .{ .acronym = "function", .code = 39, .value = "control" }, + .{ .acronym = "function", .code = 40, .value = "airship mooring" }, + .{ .acronym = "function", .code = 41, .value = "stadium" }, + .{ .acronym = "function", .code = 42, .value = "bus station" }, + .{ .acronym = "function", .code = 44, .value = "sea rescue control" }, + .{ .acronym = "function", .code = 45, .value = "observatory" }, + .{ .acronym = "function", .code = 46, .value = "ore crusher" }, + .{ .acronym = "function", .code = 47, .value = "boathouse" }, + .{ .acronym = "function", .code = 48, .value = "pumping station" }, + .{ .acronym = "jurisdiction", .code = 1, .value = "international" }, + .{ .acronym = "jurisdiction", .code = 2, .value = "national" }, + .{ .acronym = "jurisdiction", .code = 3, .value = "national sub-division" }, + .{ .acronym = "lightCharacteristic", .code = 1, .value = "fixed" }, + .{ .acronym = "lightCharacteristic", .code = 2, .value = "flashing" }, + .{ .acronym = "lightCharacteristic", .code = 3, .value = "long-flashing" }, + .{ .acronym = "lightCharacteristic", .code = 4, .value = "quick-flashing" }, + .{ .acronym = "lightCharacteristic", .code = 5, .value = "very quick-flashing" }, + .{ .acronym = "lightCharacteristic", .code = 6, .value = "continuous ultra quick-flashing" }, + .{ .acronym = "lightCharacteristic", .code = 7, .value = "isophased" }, + .{ .acronym = "lightCharacteristic", .code = 8, .value = "occulting" }, + .{ .acronym = "lightCharacteristic", .code = 11, .value = "interrupted ultra quick-flashing" }, + .{ .acronym = "lightCharacteristic", .code = 12, .value = "morse" }, + .{ .acronym = "lightCharacteristic", .code = 13, .value = "fixed and flash" }, + .{ .acronym = "lightCharacteristic", .code = 14, .value = "flash and long-flash" }, + .{ .acronym = "lightCharacteristic", .code = 15, .value = "occulting and flash" }, + .{ .acronym = "lightCharacteristic", .code = 16, .value = "fixed and long-flash" }, + .{ .acronym = "lightCharacteristic", .code = 17, .value = "occulting alternating" }, + .{ .acronym = "lightCharacteristic", .code = 18, .value = "long-flash alternating" }, + .{ .acronym = "lightCharacteristic", .code = 19, .value = "flash alternating" }, + .{ .acronym = "lightCharacteristic", .code = 25, .value = "quick-flash plus long-flash" }, + .{ .acronym = "lightCharacteristic", .code = 26, .value = "very quick-flash plus long-flash" }, + .{ .acronym = "lightCharacteristic", .code = 27, .value = "ultra quick-flash plus long-flash" }, + .{ .acronym = "lightCharacteristic", .code = 28, .value = "alternating" }, + .{ .acronym = "lightCharacteristic", .code = 29, .value = "fixed and alternating flashing" }, + .{ .acronym = "lightVisibility", .code = 1, .value = "high intensity" }, + .{ .acronym = "lightVisibility", .code = 2, .value = "low intensity" }, + .{ .acronym = "lightVisibility", .code = 3, .value = "faint" }, + .{ .acronym = "lightVisibility", .code = 4, .value = "intensified" }, + .{ .acronym = "lightVisibility", .code = 5, .value = "unintensified" }, + .{ .acronym = "lightVisibility", .code = 6, .value = "visibility deliberately restricted" }, + .{ .acronym = "lightVisibility", .code = 7, .value = "obscured" }, + .{ .acronym = "lightVisibility", .code = 8, .value = "partially obscured" }, + .{ .acronym = "lightVisibility", .code = 9, .value = "visible in line of range" }, + .{ .acronym = "referenceDirection", .code = 5, .value = "east" }, + .{ .acronym = "referenceDirection", .code = 13, .value = "west" }, + .{ .acronym = "marksNavigationalSystemOf", .code = 1, .value = "IALA a" }, + .{ .acronym = "marksNavigationalSystemOf", .code = 2, .value = "IALA b" }, + .{ .acronym = "marksNavigationalSystemOf", .code = 9, .value = "no system" }, + .{ .acronym = "marksNavigationalSystemOf", .code = 11, .value = "CEVNI" }, + .{ .acronym = "natureOfConstruction", .code = 1, .value = "masonry" }, + .{ .acronym = "natureOfConstruction", .code = 2, .value = "concreted" }, + .{ .acronym = "natureOfConstruction", .code = 3, .value = "loose boulders" }, + .{ .acronym = "natureOfConstruction", .code = 4, .value = "hard surfaced" }, + .{ .acronym = "natureOfConstruction", .code = 5, .value = "unsurfaced" }, + .{ .acronym = "natureOfConstruction", .code = 6, .value = "wooden" }, + .{ .acronym = "natureOfConstruction", .code = 7, .value = "metal" }, + .{ .acronym = "natureOfConstruction", .code = 8, .value = "glass reinforced plastic" }, + .{ .acronym = "natureOfConstruction", .code = 11, .value = "latticed" }, + .{ .acronym = "natureOfConstruction", .code = 12, .value = "glass" }, + .{ .acronym = "natureOfSurface", .code = 1, .value = "mud" }, + .{ .acronym = "natureOfSurface", .code = 2, .value = "clay" }, + .{ .acronym = "natureOfSurface", .code = 3, .value = "silt" }, + .{ .acronym = "natureOfSurface", .code = 4, .value = "sand" }, + .{ .acronym = "natureOfSurface", .code = 5, .value = "stone" }, + .{ .acronym = "natureOfSurface", .code = 6, .value = "gravel" }, + .{ .acronym = "natureOfSurface", .code = 7, .value = "pebbles" }, + .{ .acronym = "natureOfSurface", .code = 8, .value = "cobbles" }, + .{ .acronym = "natureOfSurface", .code = 9, .value = "rock" }, + .{ .acronym = "natureOfSurface", .code = 11, .value = "lava" }, + .{ .acronym = "natureOfSurface", .code = 14, .value = "coral" }, + .{ .acronym = "natureOfSurface", .code = 17, .value = "shells" }, + .{ .acronym = "natureOfSurface", .code = 18, .value = "boulder" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 1, .value = "fine" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 2, .value = "medium" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 3, .value = "coarse" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 4, .value = "broken" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 5, .value = "sticky" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 6, .value = "soft" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 7, .value = "stiff" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 8, .value = "volcanic" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 9, .value = "calcareous" }, + .{ .acronym = "natureOfSurfaceQualifyingTerms", .code = 10, .value = "hard" }, + .{ .acronym = "pilotMovement", .code = 1, .value = "embarkation" }, + .{ .acronym = "pilotMovement", .code = 2, .value = "disembarkation" }, + .{ .acronym = "pilotMovement", .code = 3, .value = "pilot change" }, + .{ .acronym = "product", .code = 1, .value = "oil" }, + .{ .acronym = "product", .code = 2, .value = "gas" }, + .{ .acronym = "product", .code = 3, .value = "water" }, + .{ .acronym = "product", .code = 4, .value = "stone" }, + .{ .acronym = "product", .code = 5, .value = "coal" }, + .{ .acronym = "product", .code = 6, .value = "ore" }, + .{ .acronym = "product", .code = 7, .value = "chemicals" }, + .{ .acronym = "product", .code = 8, .value = "drinking water" }, + .{ .acronym = "product", .code = 9, .value = "milk" }, + .{ .acronym = "product", .code = 10, .value = "bauxite" }, + .{ .acronym = "product", .code = 11, .value = "coke" }, + .{ .acronym = "product", .code = 12, .value = "iron ingots" }, + .{ .acronym = "product", .code = 13, .value = "salt" }, + .{ .acronym = "product", .code = 14, .value = "sand" }, + .{ .acronym = "product", .code = 15, .value = "timber" }, + .{ .acronym = "product", .code = 16, .value = "sawdust/wood chips" }, + .{ .acronym = "product", .code = 17, .value = "scrap metal" }, + .{ .acronym = "product", .code = 18, .value = "liquefied natural gas" }, + .{ .acronym = "product", .code = 19, .value = "liquefied petroleum gas" }, + .{ .acronym = "product", .code = 20, .value = "wine" }, + .{ .acronym = "product", .code = 21, .value = "cement" }, + .{ .acronym = "product", .code = 22, .value = "grain" }, + .{ .acronym = "product", .code = 23, .value = "electricity" }, + .{ .acronym = "product", .code = 24, .value = "ice" }, + .{ .acronym = "product", .code = 25, .value = "clay" }, + .{ .acronym = "qualityOfHorizontalMeasurement", .code = 4, .value = "approximate" }, + .{ .acronym = "qualityOfHorizontalMeasurement", .code = 5, .value = "position doubtful" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 1, .value = "depth known" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 2, .value = "depth or least depth unknown" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 3, .value = "doubtful sounding" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 4, .value = "unreliable sounding" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 6, .value = "least depth known" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 7, .value = "least depth unknown, safe clearance at value shown" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 8, .value = "value reported (not surveyed)" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 9, .value = "value reported (not confirmed)" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 10, .value = "maintained depth" }, + .{ .acronym = "qualityOfVerticalMeasurement", .code = 11, .value = "not regularly maintained" }, + .{ .acronym = "referenceTide", .code = 1, .value = "high water" }, + .{ .acronym = "referenceTide", .code = 2, .value = "low water" }, + .{ .acronym = "referenceTideType", .code = 1, .value = "springs" }, + .{ .acronym = "referenceTideType", .code = 2, .value = "neaps" }, + .{ .acronym = "referenceTideType", .code = 3, .value = "mean" }, + .{ .acronym = "restriction", .code = 1, .value = "anchoring prohibited" }, + .{ .acronym = "restriction", .code = 2, .value = "anchoring restricted" }, + .{ .acronym = "restriction", .code = 3, .value = "fishing prohibited" }, + .{ .acronym = "restriction", .code = 4, .value = "fishing restricted" }, + .{ .acronym = "restriction", .code = 5, .value = "trawling prohibited" }, + .{ .acronym = "restriction", .code = 6, .value = "trawling restricted" }, + .{ .acronym = "restriction", .code = 7, .value = "entry prohibited" }, + .{ .acronym = "restriction", .code = 8, .value = "entry restricted" }, + .{ .acronym = "restriction", .code = 9, .value = "dredging prohibited" }, + .{ .acronym = "restriction", .code = 10, .value = "dredging restricted" }, + .{ .acronym = "restriction", .code = 11, .value = "diving prohibited" }, + .{ .acronym = "restriction", .code = 12, .value = "diving restricted" }, + .{ .acronym = "restriction", .code = 13, .value = "no wake" }, + .{ .acronym = "restriction", .code = 14, .value = "area to be avoided" }, + .{ .acronym = "restriction", .code = 15, .value = "construction prohibited" }, + .{ .acronym = "restriction", .code = 16, .value = "discharging prohibited" }, + .{ .acronym = "restriction", .code = 17, .value = "discharging restricted" }, + .{ .acronym = "restriction", .code = 18, .value = "industrial or mineral exploration/development prohibited" }, + .{ .acronym = "restriction", .code = 19, .value = "industrial or mineral exploration/development restricted" }, + .{ .acronym = "restriction", .code = 20, .value = "drilling prohibited" }, + .{ .acronym = "restriction", .code = 21, .value = "drilling restricted" }, + .{ .acronym = "restriction", .code = 22, .value = "removal of historical artefacts prohibited" }, + .{ .acronym = "restriction", .code = 23, .value = "cargo transhipment (lightening) prohibited" }, + .{ .acronym = "restriction", .code = 24, .value = "dragging prohibited" }, + .{ .acronym = "restriction", .code = 25, .value = "stopping prohibited" }, + .{ .acronym = "restriction", .code = 26, .value = "landing prohibited" }, + .{ .acronym = "restriction", .code = 27, .value = "speed restricted" }, + .{ .acronym = "restriction", .code = 39, .value = "swimming prohibited" }, + .{ .acronym = "signalGeneration", .code = 1, .value = "automatically" }, + .{ .acronym = "signalGeneration", .code = 2, .value = "by wave action" }, + .{ .acronym = "signalGeneration", .code = 3, .value = "by hand" }, + .{ .acronym = "signalGeneration", .code = 4, .value = "by wind" }, + .{ .acronym = "signalGeneration", .code = 5, .value = "radio activated" }, + .{ .acronym = "signalGeneration", .code = 6, .value = "call activated" }, + .{ .acronym = "signalStatus", .code = 1, .value = "lit/sound" }, + .{ .acronym = "signalStatus", .code = 2, .value = "eclipsed/silent" }, + .{ .acronym = "status", .code = 1, .value = "permanent" }, + .{ .acronym = "status", .code = 2, .value = "occasional" }, + .{ .acronym = "status", .code = 3, .value = "recommended" }, + .{ .acronym = "status", .code = 4, .value = "not in use" }, + .{ .acronym = "status", .code = 5, .value = "periodic/intermittent" }, + .{ .acronym = "status", .code = 6, .value = "reserved" }, + .{ .acronym = "status", .code = 7, .value = "temporary" }, + .{ .acronym = "status", .code = 8, .value = "private" }, + .{ .acronym = "status", .code = 9, .value = "mandatory" }, + .{ .acronym = "status", .code = 11, .value = "extinguished" }, + .{ .acronym = "status", .code = 12, .value = "illuminated" }, + .{ .acronym = "status", .code = 13, .value = "historic" }, + .{ .acronym = "status", .code = 14, .value = "public" }, + .{ .acronym = "status", .code = 15, .value = "synchronized" }, + .{ .acronym = "status", .code = 16, .value = "watched" }, + .{ .acronym = "status", .code = 17, .value = "unwatched" }, + .{ .acronym = "status", .code = 18, .value = "existence doubtful" }, + .{ .acronym = "status", .code = 28, .value = "buoyed" }, + .{ .acronym = "surveyType", .code = 1, .value = "reconnaissance/sketch survey" }, + .{ .acronym = "surveyType", .code = 2, .value = "controlled survey" }, + .{ .acronym = "surveyType", .code = 4, .value = "examination survey" }, + .{ .acronym = "surveyType", .code = 5, .value = "passage survey" }, + .{ .acronym = "surveyType", .code = 6, .value = "remotely sensed" }, + .{ .acronym = "surveyType", .code = 7, .value = "full coverage" }, + .{ .acronym = "surveyType", .code = 8, .value = "systematic survey" }, + .{ .acronym = "surveyType", .code = 9, .value = "non-systematic survey" }, + .{ .acronym = "surveyType", .code = 10, .value = "inadequately surveyed" }, + .{ .acronym = "surveyType", .code = 11, .value = "spot-sounding survey" }, + .{ .acronym = "surveyType", .code = 12, .value = "acoustically swept survey" }, + .{ .acronym = "surveyType", .code = 13, .value = "mechanically swept survey" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 1, .value = "found by echo sounder" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 2, .value = "found by side scan sonar" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 3, .value = "found by multi beam" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 4, .value = "found by diver" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 5, .value = "found by lead line" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 6, .value = "swept by wire-drag" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 8, .value = "swept by vertical acoustic system" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 9, .value = "found by electromagnetic sensor" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 10, .value = "photogrammetry" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 11, .value = "satellite imagery" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 12, .value = "found by levelling" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 13, .value = "swept by side scan sonar" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 15, .value = "found by LIDAR" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 16, .value = "synthetic aperture radar" }, + .{ .acronym = "techniqueOfVerticalMeasurement", .code = 17, .value = "hyperspectral imagery" }, + .{ .acronym = "telecommunicationService", .code = 1, .value = "voice" }, + .{ .acronym = "telecommunicationService", .code = 2, .value = "facsimile" }, + .{ .acronym = "telecommunicationService", .code = 3, .value = "SMS" }, + .{ .acronym = "telecommunicationService", .code = 4, .value = "data" }, + .{ .acronym = "telecommunicationService", .code = 5, .value = "streamed data" }, + .{ .acronym = "telecommunicationService", .code = 6, .value = "telex" }, + .{ .acronym = "telecommunicationService", .code = 7, .value = "telegraph" }, + .{ .acronym = "telecommunicationService", .code = 8, .value = "email" }, + .{ .acronym = "textType", .code = 1, .value = "name" }, + .{ .acronym = "textType", .code = 2, .value = "light characteristic" }, + .{ .acronym = "topmarkDaymarkShape", .code = 1, .value = "cone (point up)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 2, .value = "cone (point down)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 3, .value = "sphere" }, + .{ .acronym = "topmarkDaymarkShape", .code = 4, .value = "2 spheres" }, + .{ .acronym = "topmarkDaymarkShape", .code = 5, .value = "cylinder" }, + .{ .acronym = "topmarkDaymarkShape", .code = 6, .value = "board" }, + .{ .acronym = "topmarkDaymarkShape", .code = 7, .value = "x-shaped" }, + .{ .acronym = "topmarkDaymarkShape", .code = 8, .value = "upright cross" }, + .{ .acronym = "topmarkDaymarkShape", .code = 9, .value = "cube (point up)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 10, .value = "2 cones (point to point)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 11, .value = "2 cones (base to base)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 12, .value = "rhombus" }, + .{ .acronym = "topmarkDaymarkShape", .code = 13, .value = "2 cones (points upward)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 14, .value = "2 cones (points downward)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 15, .value = "besom (point up)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 16, .value = "besom (point down)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 17, .value = "flag" }, + .{ .acronym = "topmarkDaymarkShape", .code = 18, .value = "sphere over a rhombus" }, + .{ .acronym = "topmarkDaymarkShape", .code = 19, .value = "square" }, + .{ .acronym = "topmarkDaymarkShape", .code = 20, .value = "rectangle (horizontal)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 21, .value = "rectangle (vertical)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 22, .value = "trapezium (up)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 23, .value = "trapezium (down)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 24, .value = "triangle (point up)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 25, .value = "triangle (point down)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 26, .value = "circle" }, + .{ .acronym = "topmarkDaymarkShape", .code = 27, .value = "two upright crosses (one over the other)" }, + .{ .acronym = "topmarkDaymarkShape", .code = 28, .value = "t-shape" }, + .{ .acronym = "topmarkDaymarkShape", .code = 29, .value = "triangle pointing up over a circle" }, + .{ .acronym = "topmarkDaymarkShape", .code = 30, .value = "upright cross over a circle" }, + .{ .acronym = "topmarkDaymarkShape", .code = 31, .value = "rhombus over a circle" }, + .{ .acronym = "topmarkDaymarkShape", .code = 32, .value = "circle over a triangle pointing up" }, + .{ .acronym = "topmarkDaymarkShape", .code = 33, .value = "other shape (see shape information)" }, + .{ .acronym = "trafficFlow", .code = 1, .value = "inbound" }, + .{ .acronym = "trafficFlow", .code = 2, .value = "outbound" }, + .{ .acronym = "trafficFlow", .code = 3, .value = "one-way" }, + .{ .acronym = "trafficFlow", .code = 4, .value = "two-way" }, + .{ .acronym = "verticalDatum", .code = 1, .value = "mean low water springs" }, + .{ .acronym = "verticalDatum", .code = 2, .value = "mean lower low water springs" }, + .{ .acronym = "verticalDatum", .code = 3, .value = "mean sea level" }, + .{ .acronym = "verticalDatum", .code = 4, .value = "lowest low water" }, + .{ .acronym = "verticalDatum", .code = 5, .value = "mean low water" }, + .{ .acronym = "verticalDatum", .code = 6, .value = "lowest low water springs" }, + .{ .acronym = "verticalDatum", .code = 7, .value = "approximate mean low water springs" }, + .{ .acronym = "verticalDatum", .code = 8, .value = "indian spring low water" }, + .{ .acronym = "verticalDatum", .code = 9, .value = "low water springs" }, + .{ .acronym = "verticalDatum", .code = 10, .value = "approximate lowest astronomical tide" }, + .{ .acronym = "verticalDatum", .code = 11, .value = "nearly lowest low water" }, + .{ .acronym = "verticalDatum", .code = 12, .value = "mean lower low water" }, + .{ .acronym = "verticalDatum", .code = 13, .value = "low water" }, + .{ .acronym = "verticalDatum", .code = 14, .value = "approximate mean low water" }, + .{ .acronym = "verticalDatum", .code = 15, .value = "approximate mean lower low water" }, + .{ .acronym = "verticalDatum", .code = 16, .value = "mean high water" }, + .{ .acronym = "verticalDatum", .code = 17, .value = "mean high water springs" }, + .{ .acronym = "verticalDatum", .code = 18, .value = "high water" }, + .{ .acronym = "verticalDatum", .code = 19, .value = "approximate mean sea level" }, + .{ .acronym = "verticalDatum", .code = 20, .value = "high water springs" }, + .{ .acronym = "verticalDatum", .code = 21, .value = "mean higher high water" }, + .{ .acronym = "verticalDatum", .code = 22, .value = "equinoctial spring low water" }, + .{ .acronym = "verticalDatum", .code = 23, .value = "lowest astronomical tide" }, + .{ .acronym = "verticalDatum", .code = 24, .value = "local datum" }, + .{ .acronym = "verticalDatum", .code = 25, .value = "international great lakes datum 1985" }, + .{ .acronym = "verticalDatum", .code = 26, .value = "mean water level" }, + .{ .acronym = "verticalDatum", .code = 27, .value = "lower low water large tide" }, + .{ .acronym = "verticalDatum", .code = 28, .value = "higher high water large tide" }, + .{ .acronym = "verticalDatum", .code = 29, .value = "nearly highest high water" }, + .{ .acronym = "verticalDatum", .code = 30, .value = "highest astronomical tide" }, + .{ .acronym = "verticalDatum", .code = 44, .value = "baltic sea chart datum 2000" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 1, .value = "north cardinal" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 2, .value = "east cardinal" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 3, .value = "south cardinal" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 4, .value = "west cardinal" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 5, .value = "port lateral" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 6, .value = "starboard lateral" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 7, .value = "preferred channel to port" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 8, .value = "preferred channel to starboard" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 9, .value = "isolated danger" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 10, .value = "safe water" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 11, .value = "special purpose" }, + .{ .acronym = "virtualAISAidToNavigationType", .code = 12, .value = "emergency wreck marking" }, + .{ .acronym = "visualProminence", .code = 1, .value = "visually conspicuous" }, + .{ .acronym = "visualProminence", .code = 2, .value = "not visually conspicuous" }, + .{ .acronym = "visualProminence", .code = 3, .value = "prominent" }, + .{ .acronym = "waterLevelEffect", .code = 1, .value = "partly submerged at high water" }, + .{ .acronym = "waterLevelEffect", .code = 2, .value = "always dry" }, + .{ .acronym = "waterLevelEffect", .code = 3, .value = "always under water/submerged" }, + .{ .acronym = "waterLevelEffect", .code = 4, .value = "covers and uncovers" }, + .{ .acronym = "waterLevelEffect", .code = 5, .value = "awash" }, + .{ .acronym = "waterLevelEffect", .code = 6, .value = "subject to inundation or flooding" }, + .{ .acronym = "waterLevelEffect", .code = 7, .value = "floating" }, + .{ .acronym = "categoryOfCargo", .code = 1, .value = "bulk" }, + .{ .acronym = "categoryOfCargo", .code = 2, .value = "container" }, + .{ .acronym = "categoryOfCargo", .code = 3, .value = "general" }, + .{ .acronym = "categoryOfCargo", .code = 4, .value = "liquid" }, + .{ .acronym = "categoryOfCargo", .code = 5, .value = "passenger" }, + .{ .acronym = "categoryOfCargo", .code = 6, .value = "livestock" }, + .{ .acronym = "categoryOfCargo", .code = 7, .value = "dangerous or hazardous" }, + .{ .acronym = "categoryOfCargo", .code = 8, .value = "heavy lift" }, + .{ .acronym = "categoryOfCargo", .code = 9, .value = "ballast" }, + .{ .acronym = "categoryOfCargo", .code = 10, .value = "dry bulk cargo" }, + .{ .acronym = "categoryOfCargo", .code = 11, .value = "liquid bulk cargo" }, + .{ .acronym = "categoryOfCargo", .code = 12, .value = "reefer container cargo" }, + .{ .acronym = "categoryOfCargo", .code = 13, .value = "ro-ro cargo" }, + .{ .acronym = "categoryOfCargo", .code = 14, .value = "project cargo" }, + .{ .acronym = "categoryOfCargo", .code = 15, .value = "break bulk cargo" }, +}; diff --git a/src/s57/decode.zig b/src/s57/decode.zig index 99a8d48f..27798398 100644 --- a/src/s57/decode.zig +++ b/src/s57/decode.zig @@ -13,14 +13,22 @@ const std = @import("std"); const catalog = @import("catalog.zig"); +const catalog_s101 = @import("catalog_s101.zig"); // ---- catalogue lookups ------------------------------------------------------ -/// The label a mariner reads for an attribute acronym, or the acronym itself. +/// The label for an attribute, or the attribute itself when no catalogue +/// contains it. S-57 acronyms read the S-57 catalogue. S-101 codes read +/// the generated Feature Catalogue tables. The two stay separate: S-101 +/// changed attributes that it took from S-57, so an S-57 code must not +/// read the S-101 tables. pub fn attrName(acronym: []const u8) []const u8 { for (catalog.attribute_names) |e| { if (std.mem.eql(u8, e.acronym, acronym)) return e.name; } + for (catalog_s101.attribute_names) |e| { + if (std.mem.eql(u8, e.acronym, acronym)) return e.name; + } return acronym; } @@ -28,6 +36,9 @@ fn enumValue(acronym: []const u8, code: u16) ?[]const u8 { for (catalog.enum_values) |e| { if (e.code == code and std.mem.eql(u8, e.acronym, acronym)) return e.value; } + for (catalog_s101.enum_values) |e| { + if (e.code == code and std.mem.eql(u8, e.acronym, acronym)) return e.value; + } return null; } diff --git a/src/s57/s57.zig b/src/s57/s57.zig index 00a3a71e..ec7de7c1 100644 --- a/src/s57/s57.zig +++ b/src/s57/s57.zig @@ -17,6 +17,7 @@ pub const iso8211 = @import("iso8211"); /// The IHO attribute catalogue as data, and the mariner's decode over it — /// the pick report's language, served to every shell from here. pub const catalog = @import("catalog.zig"); +pub const catalog_s101 = @import("catalog_s101.zig"); pub const decode = @import("decode.zig"); const iso = iso8211; diff --git a/tools/fcattrs.zig b/tools/fcattrs.zig new file mode 100644 index 00000000..27d47ffc --- /dev/null +++ b/tools/fcattrs.zig @@ -0,0 +1,181 @@ +const std = @import("std"); + +// Emit src/s57/catalog_s101.zig from the vendored S-101 Feature Catalogue +// XML: every simple attribute's label and, for enumeration types, its +// listed values, keyed by the S-101 code (beaconShape). The tool does not +// emit enum values under the S-57 aliases. S-101 changed attributes that +// it took from S-57 (CATTRK became a boolean; BUISHP keeps five shapes), +// so an S-57 code must not read the S-101 tables. catalog.zig stays the +// authority for S-57 acronyms. The scan uses the FC's fixed element order +// instead of an XML parser. A malformed block is skipped whole. +pub fn run(io: std.Io, a: std.mem.Allocator, args: []const [:0]const u8) !void { + if (args.len < 3) { + std.debug.print("usage: tile57 fcattrs [> catalog.zig]\n", .{}); + return; + } + const xml = try std.Io.Dir.cwd().readFileAlloc(io, args[2], a, .unlimited); + + var out = std.ArrayList(u8).empty; + try out.appendSlice(a, + \\//! The S-101 Feature Catalogue's simple attributes, as data. + \\//! + \\//! GENERATED by `tile57 fcattrs` from the vendored Feature Catalogue — + \\//! do not edit by hand; regenerate instead. Keys are S-101 attribute + \\//! codes; the S-57 catalogue is its own authority in catalog.zig. A + \\//! code the catalogue does not list stays undecoded and passes + \\//! through a report raw. + \\ + \\const catalog = @import("catalog.zig"); + \\ + \\/// S-101 attribute code -> the label a mariner reads. + \\pub const attribute_names = [_]catalog.AttrName{ + \\ + ); + + var enums = std.ArrayList(u8).empty; + var n_attrs: usize = 0; + var n_vals: usize = 0; + + var rest: []const u8 = xml; + while (indexAfter(rest, "")) |start| { + const end = std.mem.indexOf(u8, rest[start..], "") orelse break; + const block = rest[start .. start + end]; + rest = rest[start + end ..]; + + // The attribute's own name/code/alias come before its listed values. + const head = block[0 .. std.mem.indexOf(u8, block, "") orelse block.len]; + const name = element(head, "S100FC:name") orelse continue; + const code = element(head, "S100FC:code") orelse continue; + const alias = element(head, "S100FC:alias"); + + _ = alias; + try emitName(a, &out, code, name); + n_attrs += 1; + + // Every listed value: label, then its own code. definitionReference + // carries an unrelated sourceIdentifier, so the label anchors the + // scan and the code is taken from between the two. + var vals: []const u8 = block[head.len..]; + while (indexAfter(vals, "")) |vs| { + const ve = std.mem.indexOf(u8, vals[vs..], "") orelse break; + const vblock = vals[vs .. vs + ve]; + vals = vals[vs + ve ..]; + const label = element(vblock, "S100FC:label") orelse continue; + const vcode_text = element(vblock, "S100FC:code") orelse continue; + const vcode = std.fmt.parseInt(u16, vcode_text, 10) catch continue; + try emitValue(a, &enums, code, vcode, label); + n_vals += 1; + } + } + + try out.appendSlice(a, + \\}; + \\ + \\/// Every enumerated S-101 attribute's listed values, one per code. + \\pub const enum_values = [_]catalog.EnumValue{ + \\ + ); + try out.appendSlice(a, enums.items); + try out.appendSlice(a, "};\n"); + + std.debug.print("fcattrs: {d} attribute names, {d} enum values\n", .{ n_attrs, n_vals }); + std.Io.File.stdout().writeStreamingAll(io, out.items) catch {}; +} + +fn indexAfter(hay: []const u8, needle: []const u8) ?usize { + const at = std.mem.indexOf(u8, hay, needle) orelse return null; + return at + needle.len; +} + +/// The text of `text`, trimmed, or null. +fn element(block: []const u8, comptime tag: []const u8) ?[]const u8 { + const open = "<" ++ tag ++ ">"; + const close = ""; + const at = indexAfter(block, open) orelse return null; + const end = std.mem.indexOf(u8, block[at..], close) orelse return null; + return std.mem.trim(u8, block[at .. at + end], " \t\r\n"); +} + +fn emitName(a: std.mem.Allocator, out: *std.ArrayList(u8), key: []const u8, name: []const u8) !void { + try out.appendSlice(a, " .{ .acronym = \""); + try appendEscaped(a, out, key); + try out.appendSlice(a, "\", .name = \""); + try appendEscaped(a, out, name); + try out.appendSlice(a, "\" },\n"); +} + +fn emitValue(a: std.mem.Allocator, out: *std.ArrayList(u8), key: []const u8, code: u16, label: []const u8) !void { + var buf: [16]u8 = undefined; + try out.appendSlice(a, " .{ .acronym = \""); + try appendEscaped(a, out, key); + try out.appendSlice(a, "\", .code = "); + try out.appendSlice(a, std.fmt.bufPrint(&buf, "{d}", .{code}) catch unreachable); + try out.appendSlice(a, ", .value = \""); + try appendLoweredEscaped(a, out, label); + try out.appendSlice(a, "\" },\n"); +} + +/// XML entities unescaped, string quoting escaped. +fn appendEscaped(a: std.mem.Allocator, out: *std.ArrayList(u8), s: []const u8) !void { + var i: usize = 0; + while (i < s.len) : (i += 1) { + if (try appendEntity(a, out, s, &i)) continue; + switch (s[i]) { + '"' => try out.appendSlice(a, "\\\""), + '\\' => try out.appendSlice(a, "\\\\"), + else => try out.append(a, s[i]), + } + } +} + +/// Lowercase the label. A word in ALL CAPS is an initialism (IALA, ODAS, +/// TSS) and keeps its case. +fn appendLoweredEscaped(a: std.mem.Allocator, out: *std.ArrayList(u8), s: []const u8) !void { + var i: usize = 0; + while (i < s.len) { + // find the current word's extent + var j = i; + while (j < s.len and s[j] != ' ') : (j += 1) {} + const word = s[i..j]; + var caps: usize = 0; + var letters: usize = 0; + for (word) |c| { + if (std.ascii.isAlphabetic(c)) { + letters += 1; + if (std.ascii.isUpper(c)) caps += 1; + } + } + const initialism = letters >= 2 and caps == letters; + var k: usize = i; + while (k < j) : (k += 1) { + var ch = s[k]; + if (!initialism) ch = std.ascii.toLower(ch); + if (try appendEntity(a, out, s, &k)) continue; + switch (ch) { + '"' => try out.appendSlice(a, "\\\""), + '\\' => try out.appendSlice(a, "\\\\"), + else => try out.append(a, ch), + } + } + if (j < s.len) try out.append(a, ' '); + i = j + 1; + } +} + +/// Consume an XML entity at s[i.*] if present, appending its character. +fn appendEntity(a: std.mem.Allocator, out: *std.ArrayList(u8), s: []const u8, i: *usize) !bool { + const rest = s[i.*..]; + const map = [_]struct { ent: []const u8, ch: []const u8 }{ + .{ .ent = "&", .ch = "&" }, .{ .ent = "<", .ch = "<" }, + .{ .ent = ">", .ch = ">" }, .{ .ent = """, .ch = "\\\"" }, + .{ .ent = "'", .ch = "'" }, + }; + for (map) |m| { + if (std.mem.startsWith(u8, rest, m.ent)) { + try out.appendSlice(a, m.ch); + i.* += m.ent.len - 1; + return true; + } + } + return false; +} diff --git a/tools/main.zig b/tools/main.zig index b66505fb..fe2e1912 100644 --- a/tools/main.zig +++ b/tools/main.zig @@ -35,6 +35,7 @@ const ascii = @import("ascii.zig"); const explore = @import("explore.zig"); const cells = @import("cells.zig"); const catalog = @import("catalog.zig"); +const fcattrs = @import("fcattrs.zig"); const features = @import("features.zig"); const inspect = @import("inspect.zig"); const zoomsizes = @import("zoomsizes.zig"); @@ -116,6 +117,10 @@ pub fn main(init: std.process.Init) !void { return cells.run(io, arena, args); } + if (std.mem.eql(u8, sub, "fcattrs")) { + return fcattrs.run(io, arena, args); + } + if (std.mem.eql(u8, sub, "catalog")) { return catalog.run(io, arena, args); } From 17e367e7e2a91dafa5a62e57cf185caa13095de4 Mon Sep 17 00:00:00 2001 From: Jeremy Collins Date: Mon, 3 Aug 2026 12:31:01 -0400 Subject: [PATCH 3/3] s57: compose the pick report in the engine tile57_s57_report turns one queried feature into the report JSON that a shell renders. The input is the class, the cell name, and the attribute JSON from the query callback. The output contains: a title with the object's key fact (a light's characteristic, a depth area's range, a wreck's least depth), a subtitle, a chip name, notes from INFORM, the rows decoded and sorted into reading order, a one-line provenance footnote, and an 'empty' field when there is nothing to read. fcattrs now also collects the Feature Catalogue's feature types. Class names did not change in S-101, so the S-57 alias maps safely: HULKES reads as Hulk. The meta and collection classes that S-101 does not contain are in a small table in decode.zig. --- include/tile57.h | 15 ++ src/capi.zig | 12 ++ src/s57/catalog_s101.zig | 340 ++++++++++++++++++++++++++++++++++ src/s57/decode.zig | 381 +++++++++++++++++++++++++++++++++++++++ src/s57/s57.zig | 4 +- tools/fcattrs.zig | 55 ++++++ 6 files changed, 805 insertions(+), 2 deletions(-) diff --git a/include/tile57.h b/include/tile57.h index 4b78eeb6..f583d253 100644 --- a/include/tile57.h +++ b/include/tile57.h @@ -377,6 +377,21 @@ typedef struct { tile57_status tile57_chart_query(tile57_chart *chart, double lon, double lat, double zoom, const tile57_query_cb *cb, tile57_error *err); +/* The decoded pick report for one queried feature. Compose it from the class, + * the cell name, and the attribute JSON of a query callback. *out is JSON + * (free with tile57_free): + * {"title","subtitle","chip","notes":[...], + * "rows":[{"label","value","depth","file","picture"}...], + * "footnote","empty":"none"|"source"} + * The title is the object's key fact (a light's characteristic, a depth + * area's range). The rows are decoded through the S-57 and S-101 catalogues. + * A value that no catalogue contains passes through unchanged. The "empty" + * field appears only when there is nothing to read. */ +tile57_status tile57_s57_report(const char *cls, size_t cls_len, + const char *cell, size_t cell_len, + const char *attrs, size_t attrs_len, + uint8_t **out, size_t *out_len, tile57_error *err); + /* ---- mariner settings ------------------------------------------------------ * * The mariner's S-52 display options: shared by the view renderers below diff --git a/src/capi.zig b/src/capi.zig index 71fed25a..a117c644 100644 --- a/src/capi.zig +++ b/src/capi.zig @@ -559,6 +559,18 @@ export fn tile57_chart_tile(handle: ?*Chart, z: u8, x: u32, y: u32, out: ?*?[*]u return exportOut(err, o, n, bytes); } +/// The decoded pick report for one queried feature, as JSON: title, rows, +/// notes and provenance, composed from the class, the cell name and the +/// attribute payload of a query callback. See tile57.h. +export fn tile57_s57_report(cls: ?[*]const u8, cls_len: usize, cell: ?[*]const u8, cell_len: usize, attrs: ?[*]const u8, attrs_len: usize, out: ?*?[*]u8, out_len: ?*usize, err: ?*CError) callconv(.c) c_int { + const o, const n = bytesOut(out, out_len) catch return failWith(err, .badarg, bad_out); + const c = cls orelse return failWith(err, .badarg, "cls must not be null"); + const ch = cell orelse return failWith(err, .badarg, "cell must not be null"); + const s = attrs orelse return failWith(err, .badarg, "attrs must not be null"); + const bytes = s57.decode.report(gpa, c[0..cls_len], ch[0..cell_len], s[0..attrs_len]) catch |e| return fail(err, e); + return exportOut(err, o, n, bytes); +} + const CQueryCb = @import("render").query.QueryCb; /// Cursor object-query at (lon,lat) for the view `zoom` (web-mercator): invokes diff --git a/src/s57/catalog_s101.zig b/src/s57/catalog_s101.zig index 70477664..588c7679 100644 --- a/src/s57/catalog_s101.zig +++ b/src/s57/catalog_s101.zig @@ -1258,3 +1258,343 @@ pub const enum_values = [_]catalog.EnumValue{ .{ .acronym = "categoryOfCargo", .code = 14, .value = "project cargo" }, .{ .acronym = "categoryOfCargo", .code = 15, .value = "break bulk cargo" }, }; + +/// Object class (S-57 acronym or S-101 code) -> the chart's name. +pub const class_names = [_]catalog.AttrName{ + .{ .acronym = "QualityOfNonBathymetricData", .name = "Quality of Non-Bathymetric Data" }, + .{ .acronym = "M_ACCY", .name = "Quality of Non-Bathymetric Data" }, + .{ .acronym = "DataCoverage", .name = "Data Coverage" }, + .{ .acronym = "M_COVR", .name = "Data Coverage" }, + .{ .acronym = "NavigationalSystemOfMarks", .name = "Navigational System of Marks" }, + .{ .acronym = "LocalDirectionOfBuoyage", .name = "Local Direction of Buoyage" }, + .{ .acronym = "QualityOfBathymetricData", .name = "Quality of Bathymetric Data" }, + .{ .acronym = "M_QUAL", .name = "Quality of Bathymetric Data" }, + .{ .acronym = "SoundingDatum", .name = "Sounding Datum" }, + .{ .acronym = "M_SDAT", .name = "Sounding Datum" }, + .{ .acronym = "VerticalDatumOfData", .name = "Vertical Datum of Data" }, + .{ .acronym = "M_VDAT", .name = "Vertical Datum of Data" }, + .{ .acronym = "QualityOfSurvey", .name = "Quality of Survey" }, + .{ .acronym = "M_SREL", .name = "Quality of Survey" }, + .{ .acronym = "UpdateInformation", .name = "Update Information" }, + .{ .acronym = "MagneticVariation", .name = "Magnetic Variation" }, + .{ .acronym = "MAGVAR", .name = "Magnetic Variation" }, + .{ .acronym = "LocalMagneticAnomaly", .name = "Local Magnetic Anomaly" }, + .{ .acronym = "LOCMAG", .name = "Local Magnetic Anomaly" }, + .{ .acronym = "Coastline", .name = "Coastline" }, + .{ .acronym = "COALNE", .name = "Coastline" }, + .{ .acronym = "LandArea", .name = "Land Area" }, + .{ .acronym = "LNDARE", .name = "Land Area" }, + .{ .acronym = "IslandGroup", .name = "Island Group" }, + .{ .acronym = "LandElevation", .name = "Land Elevation" }, + .{ .acronym = "LNDELV", .name = "Land Elevation" }, + .{ .acronym = "River", .name = "River" }, + .{ .acronym = "RIVERS", .name = "River" }, + .{ .acronym = "Rapids", .name = "Rapids" }, + .{ .acronym = "RAPIDS", .name = "Rapids" }, + .{ .acronym = "Waterfall", .name = "Waterfall" }, + .{ .acronym = "WATFAL", .name = "Waterfall" }, + .{ .acronym = "Lake", .name = "Lake" }, + .{ .acronym = "LAKARE", .name = "Lake" }, + .{ .acronym = "LandRegion", .name = "Land Region" }, + .{ .acronym = "LNDRGN", .name = "Land Region" }, + .{ .acronym = "Vegetation", .name = "Vegetation" }, + .{ .acronym = "VEGATN", .name = "Vegetation" }, + .{ .acronym = "IceArea", .name = "Ice Area" }, + .{ .acronym = "ICEARE", .name = "Ice Area" }, + .{ .acronym = "SlopingGround", .name = "Sloping Ground" }, + .{ .acronym = "SLOGRD", .name = "Sloping Ground" }, + .{ .acronym = "SlopeTopline", .name = "Slope Topline" }, + .{ .acronym = "SLOTOP", .name = "Slope Topline" }, + .{ .acronym = "Tideway", .name = "Tideway" }, + .{ .acronym = "TIDEWY", .name = "Tideway" }, + .{ .acronym = "BuiltUpArea", .name = "Built-Up Area" }, + .{ .acronym = "BUAARE", .name = "Built-Up Area" }, + .{ .acronym = "Building", .name = "Building" }, + .{ .acronym = "BUISGL", .name = "Building" }, + .{ .acronym = "AirportAirfield", .name = "Airport/Airfield" }, + .{ .acronym = "AIRARE", .name = "Airport/Airfield" }, + .{ .acronym = "Runway", .name = "Runway" }, + .{ .acronym = "RUNWAY", .name = "Runway" }, + .{ .acronym = "Bridge", .name = "Bridge" }, + .{ .acronym = "SpanFixed", .name = "Span Fixed" }, + .{ .acronym = "SpanOpening", .name = "Span Opening" }, + .{ .acronym = "Conveyor", .name = "Conveyor" }, + .{ .acronym = "CONVYR", .name = "Conveyor" }, + .{ .acronym = "CableOverhead", .name = "Cable Overhead" }, + .{ .acronym = "CBLOHD", .name = "Cable Overhead" }, + .{ .acronym = "PipelineOverhead", .name = "Pipeline Overhead" }, + .{ .acronym = "PIPOHD", .name = "Pipeline Overhead" }, + .{ .acronym = "PylonBridgeSupport", .name = "Pylon/Bridge Support" }, + .{ .acronym = "PYLONS", .name = "Pylon/Bridge Support" }, + .{ .acronym = "FenceWall", .name = "Fence/Wall" }, + .{ .acronym = "FNCLNE", .name = "Fence/Wall" }, + .{ .acronym = "Railway", .name = "Railway" }, + .{ .acronym = "RAILWY", .name = "Railway" }, + .{ .acronym = "Road", .name = "Road" }, + .{ .acronym = "ROADWY", .name = "Road" }, + .{ .acronym = "Tunnel", .name = "Tunnel" }, + .{ .acronym = "TUNNEL", .name = "Tunnel" }, + .{ .acronym = "Landmark", .name = "Landmark" }, + .{ .acronym = "LNDMRK", .name = "Landmark" }, + .{ .acronym = "SiloTank", .name = "Silo/Tank" }, + .{ .acronym = "SILTNK", .name = "Silo/Tank" }, + .{ .acronym = "WindTurbine", .name = "Wind Turbine" }, + .{ .acronym = "FortifiedStructure", .name = "Fortified Structure" }, + .{ .acronym = "FORSTC", .name = "Fortified Structure" }, + .{ .acronym = "ProductionStorageArea", .name = "Production/Storage Area" }, + .{ .acronym = "PRDARE", .name = "Production/Storage Area" }, + .{ .acronym = "Checkpoint", .name = "Checkpoint" }, + .{ .acronym = "CHKPNT", .name = "Checkpoint" }, + .{ .acronym = "Hulk", .name = "Hulk" }, + .{ .acronym = "HULKES", .name = "Hulk" }, + .{ .acronym = "Pile", .name = "Pile" }, + .{ .acronym = "PILPNT", .name = "Pile" }, + .{ .acronym = "Dyke", .name = "Dyke" }, + .{ .acronym = "DYKCON", .name = "Dyke" }, + .{ .acronym = "ShorelineConstruction", .name = "Shoreline Construction" }, + .{ .acronym = "SLCONS", .name = "Shoreline Construction" }, + .{ .acronym = "Causeway", .name = "Causeway" }, + .{ .acronym = "CAUSWY", .name = "Causeway" }, + .{ .acronym = "Canal", .name = "Canal" }, + .{ .acronym = "CANALS", .name = "Canal" }, + .{ .acronym = "DistanceMark", .name = "Distance Mark" }, + .{ .acronym = "DISMAR", .name = "Distance Mark" }, + .{ .acronym = "Gate", .name = "Gate" }, + .{ .acronym = "GATCON", .name = "Gate" }, + .{ .acronym = "Dam", .name = "Dam" }, + .{ .acronym = "DAMCON", .name = "Dam" }, + .{ .acronym = "Crane", .name = "Crane" }, + .{ .acronym = "CRANES", .name = "Crane" }, + .{ .acronym = "Berth", .name = "Berth" }, + .{ .acronym = "BERTHS", .name = "Berth" }, + .{ .acronym = "MooringWarpingFacility", .name = "Mooring/Warping Facility" }, + .{ .acronym = "MORFAC", .name = "Mooring/Warping Facility" }, + .{ .acronym = "DryDock", .name = "Dry Dock" }, + .{ .acronym = "DRYDOC", .name = "Dry Dock" }, + .{ .acronym = "FloatingDock", .name = "Floating Dock" }, + .{ .acronym = "FLODOC", .name = "Floating Dock" }, + .{ .acronym = "Pontoon", .name = "Pontoon" }, + .{ .acronym = "PONTON", .name = "Pontoon" }, + .{ .acronym = "DockArea", .name = "Dock Area" }, + .{ .acronym = "DOCARE", .name = "Dock Area" }, + .{ .acronym = "Gridiron", .name = "Gridiron" }, + .{ .acronym = "GRIDRN", .name = "Gridiron" }, + .{ .acronym = "LockBasin", .name = "Lock Basin" }, + .{ .acronym = "LOKBSN", .name = "Lock Basin" }, + .{ .acronym = "MooringTrot", .name = "Mooring Trot" }, + .{ .acronym = "SeaAreaNamedWaterArea", .name = "Sea Area/Named Water Area" }, + .{ .acronym = "SEAARE", .name = "Sea Area/Named Water Area" }, + .{ .acronym = "TidalStreamFloodEbb", .name = "Tidal Stream - Flood/Ebb" }, + .{ .acronym = "TS_FEB", .name = "Tidal Stream - Flood/Ebb" }, + .{ .acronym = "CurrentNonGravitational", .name = "Current - Non-Gravitational" }, + .{ .acronym = "CURENT", .name = "Current - Non-Gravitational" }, + .{ .acronym = "WaterTurbulence", .name = "Water Turbulence" }, + .{ .acronym = "WATTUR", .name = "Water Turbulence" }, + .{ .acronym = "TidalStreamPanelData", .name = "Tidal Stream Panel Data" }, + .{ .acronym = "TS_PAD", .name = "Tidal Stream Panel Data" }, + .{ .acronym = "Sounding", .name = "Sounding" }, + .{ .acronym = "SOUNDG", .name = "Sounding" }, + .{ .acronym = "DredgedArea", .name = "Dredged Area" }, + .{ .acronym = "DRGARE", .name = "Dredged Area" }, + .{ .acronym = "SweptArea", .name = "Swept Area" }, + .{ .acronym = "SWPARE", .name = "Swept Area" }, + .{ .acronym = "DepthContour", .name = "Depth Contour" }, + .{ .acronym = "DEPCNT", .name = "Depth Contour" }, + .{ .acronym = "DepthArea", .name = "Depth Area" }, + .{ .acronym = "DEPARE", .name = "Depth Area" }, + .{ .acronym = "DepthNoBottomFound", .name = "Depth - No Bottom Found" }, + .{ .acronym = "UnsurveyedArea", .name = "Unsurveyed Area" }, + .{ .acronym = "UNSARE", .name = "Unsurveyed Area" }, + .{ .acronym = "SeabedArea", .name = "Seabed Area" }, + .{ .acronym = "SBDARE", .name = "Seabed Area" }, + .{ .acronym = "WeedKelp", .name = "Weed/Kelp" }, + .{ .acronym = "WEDKLP", .name = "Weed/Kelp" }, + .{ .acronym = "Seagrass", .name = "Seagrass" }, + .{ .acronym = "Sandwave", .name = "Sandwave" }, + .{ .acronym = "SNDWAV", .name = "Sandwave" }, + .{ .acronym = "Spring", .name = "Spring" }, + .{ .acronym = "SPRING", .name = "Spring" }, + .{ .acronym = "UnderwaterAwashRock", .name = "Underwater/Awash Rock" }, + .{ .acronym = "UWTROC", .name = "Underwater/Awash Rock" }, + .{ .acronym = "Wreck", .name = "Wreck" }, + .{ .acronym = "WRECKS", .name = "Wreck" }, + .{ .acronym = "Obstruction", .name = "Obstruction" }, + .{ .acronym = "OBSTRN", .name = "Obstruction" }, + .{ .acronym = "FoulGround", .name = "Foul Ground" }, + .{ .acronym = "DiscolouredWater", .name = "Discoloured Water" }, + .{ .acronym = "FishingFacility", .name = "Fishing Facility" }, + .{ .acronym = "FSHFAC", .name = "Fishing Facility" }, + .{ .acronym = "MarineFarmCulture", .name = "Marine Farm/Culture" }, + .{ .acronym = "MARCUL", .name = "Marine Farm/Culture" }, + .{ .acronym = "OffshorePlatform", .name = "Offshore Platform" }, + .{ .acronym = "OFSPLF", .name = "Offshore Platform" }, + .{ .acronym = "CableSubmarine", .name = "Cable Submarine" }, + .{ .acronym = "CBLSUB", .name = "Cable Submarine" }, + .{ .acronym = "CableArea", .name = "Cable Area" }, + .{ .acronym = "CBLARE", .name = "Cable Area" }, + .{ .acronym = "PipelineSubmarineOnLand", .name = "Pipeline Submarine/On Land" }, + .{ .acronym = "PIPSOL", .name = "Pipeline Submarine/On Land" }, + .{ .acronym = "SubmarinePipelineArea", .name = "Submarine Pipeline Area" }, + .{ .acronym = "PIPARE", .name = "Submarine Pipeline Area" }, + .{ .acronym = "OffshoreProductionArea", .name = "Offshore Production Area" }, + .{ .acronym = "OSPARE", .name = "Offshore Production Area" }, + .{ .acronym = "NavigationLine", .name = "Navigation Line" }, + .{ .acronym = "NAVLNE", .name = "Navigation Line" }, + .{ .acronym = "RecommendedTrack", .name = "Recommended Track" }, + .{ .acronym = "RECTRC", .name = "Recommended Track" }, + .{ .acronym = "RangeSystem", .name = "Range System" }, + .{ .acronym = "Fairway", .name = "Fairway" }, + .{ .acronym = "FAIRWY", .name = "Fairway" }, + .{ .acronym = "FairwaySystem", .name = "Fairway System" }, + .{ .acronym = "RecommendedRouteCentreline", .name = "Recommended Route Centreline" }, + .{ .acronym = "RCRTCL", .name = "Recommended Route Centreline" }, + .{ .acronym = "TwoWayRoutePart", .name = "Two-Way Route Part" }, + .{ .acronym = "TWRTPT", .name = "Two-Way Route Part" }, + .{ .acronym = "TwoWayRoute", .name = "Two-Way Route" }, + .{ .acronym = "RecommendedTrafficLanePart", .name = "Recommended Traffic Lane Part" }, + .{ .acronym = "RCTLPT", .name = "Recommended Traffic Lane Part" }, + .{ .acronym = "DeepWaterRouteCentreline", .name = "Deep Water Route Centreline" }, + .{ .acronym = "DWRTCL", .name = "Deep Water Route Centreline" }, + .{ .acronym = "DeepWaterRoutePart", .name = "Deep Water Route Part" }, + .{ .acronym = "DWRTPT", .name = "Deep Water Route Part" }, + .{ .acronym = "DeepWaterRoute", .name = "Deep Water Route" }, + .{ .acronym = "InshoreTrafficZone", .name = "Inshore Traffic Zone" }, + .{ .acronym = "ISTZNE", .name = "Inshore Traffic Zone" }, + .{ .acronym = "PrecautionaryArea", .name = "Precautionary Area" }, + .{ .acronym = "PRCARE", .name = "Precautionary Area" }, + .{ .acronym = "TrafficSeparationSchemeLanePart", .name = "Traffic Separation Scheme Lane Part" }, + .{ .acronym = "TSSLPT", .name = "Traffic Separation Scheme Lane Part" }, + .{ .acronym = "SeparationZoneOrLine", .name = "Separation Zone or Line" }, + .{ .acronym = "TSELNE", .name = "Separation Zone or Line" }, + .{ .acronym = "TrafficSeparationSchemeBoundary", .name = "Traffic Separation Scheme Boundary" }, + .{ .acronym = "TSSBND", .name = "Traffic Separation Scheme Boundary" }, + .{ .acronym = "TrafficSeparationSchemeCrossing", .name = "Traffic Separation Scheme Crossing" }, + .{ .acronym = "TSSCRS", .name = "Traffic Separation Scheme Crossing" }, + .{ .acronym = "TrafficSeparationSchemeRoundabout", .name = "Traffic Separation Scheme Roundabout" }, + .{ .acronym = "TSSRON", .name = "Traffic Separation Scheme Roundabout" }, + .{ .acronym = "TrafficSeparationScheme", .name = "Traffic Separation Scheme" }, + .{ .acronym = "ArchipelagicSeaLaneArea", .name = "Archipelagic Sea Lane Area" }, + .{ .acronym = "ARCSLN", .name = "Archipelagic Sea Lane Area" }, + .{ .acronym = "ArchipelagicSeaLaneAxis", .name = "Archipelagic Sea Lane Axis" }, + .{ .acronym = "ASLXIS", .name = "Archipelagic Sea Lane Axis" }, + .{ .acronym = "ArchipelagicSeaLane", .name = "Archipelagic Sea Lane" }, + .{ .acronym = "RadioCallingInPoint", .name = "Radio Calling-In Point" }, + .{ .acronym = "RDOCAL", .name = "Radio Calling-In Point" }, + .{ .acronym = "FerryRoute", .name = "Ferry Route" }, + .{ .acronym = "FERYRT", .name = "Ferry Route" }, + .{ .acronym = "RadarLine", .name = "Radar Line" }, + .{ .acronym = "RADLNE", .name = "Radar Line" }, + .{ .acronym = "RadarRange", .name = "Radar Range" }, + .{ .acronym = "RADRNG", .name = "Radar Range" }, + .{ .acronym = "RadarStation", .name = "Radar Station" }, + .{ .acronym = "RADSTA", .name = "Radar Station" }, + .{ .acronym = "AnchorageArea", .name = "Anchorage Area" }, + .{ .acronym = "ACHARE", .name = "Anchorage Area" }, + .{ .acronym = "AnchorBerth", .name = "Anchor Berth" }, + .{ .acronym = "ACHBRT", .name = "Anchor Berth" }, + .{ .acronym = "SeaplaneLandingArea", .name = "Seaplane Landing Area" }, + .{ .acronym = "SPLARE", .name = "Seaplane Landing Area" }, + .{ .acronym = "DumpingGround", .name = "Dumping Ground" }, + .{ .acronym = "DMPGRD", .name = "Dumping Ground" }, + .{ .acronym = "MilitaryPracticeArea", .name = "Military Practice Area" }, + .{ .acronym = "MIPARE", .name = "Military Practice Area" }, + .{ .acronym = "AdministrationArea", .name = "Administration Area" }, + .{ .acronym = "CargoTranshipmentArea", .name = "Cargo Transhipment Area" }, + .{ .acronym = "CTSARE", .name = "Cargo Transhipment Area" }, + .{ .acronym = "CautionArea", .name = "Caution Area" }, + .{ .acronym = "InformationArea", .name = "Information Area" }, + .{ .acronym = "M_NPUB", .name = "Information Area" }, + .{ .acronym = "ContiguousZone", .name = "Contiguous Zone" }, + .{ .acronym = "CONZNE", .name = "Contiguous Zone" }, + .{ .acronym = "ContinentalShelfArea", .name = "Continental Shelf Area" }, + .{ .acronym = "COSARE", .name = "Continental Shelf Area" }, + .{ .acronym = "CustomZone", .name = "Custom Zone" }, + .{ .acronym = "CUSZNE", .name = "Custom Zone" }, + .{ .acronym = "ExclusiveEconomicZone", .name = "Exclusive Economic Zone" }, + .{ .acronym = "EXEZNE", .name = "Exclusive Economic Zone" }, + .{ .acronym = "FisheryZone", .name = "Fishery Zone" }, + .{ .acronym = "FSHZNE", .name = "Fishery Zone" }, + .{ .acronym = "FishingGround", .name = "Fishing Ground" }, + .{ .acronym = "FSHGRD", .name = "Fishing Ground" }, + .{ .acronym = "FreePortArea", .name = "Free Port Area" }, + .{ .acronym = "FRPARE", .name = "Free Port Area" }, + .{ .acronym = "HarbourAreaAdministrative", .name = "Harbour Area (Administrative)" }, + .{ .acronym = "HRBARE", .name = "Harbour Area (Administrative)" }, + .{ .acronym = "LogPond", .name = "Log Pond" }, + .{ .acronym = "LOGPON", .name = "Log Pond" }, + .{ .acronym = "OilBarrier", .name = "Oil Barrier" }, + .{ .acronym = "OILBAR", .name = "Oil Barrier" }, + .{ .acronym = "StraightTerritorialSeaBaseline", .name = "Straight Territorial Sea Baseline" }, + .{ .acronym = "STSLNE", .name = "Straight Territorial Sea Baseline" }, + .{ .acronym = "TerritorialSeaArea", .name = "Territorial Sea Area" }, + .{ .acronym = "TESARE", .name = "Territorial Sea Area" }, + .{ .acronym = "SubmarineTransitLane", .name = "Submarine Transit Lane" }, + .{ .acronym = "SUBTLN", .name = "Submarine Transit Lane" }, + .{ .acronym = "PilotageDistrict", .name = "Pilotage District" }, + .{ .acronym = "CollisionRegulationsLimit", .name = "Collision Regulations Limit" }, + .{ .acronym = "MarinePollutionRegulationsArea", .name = "Marine Pollution Regulations Area" }, + .{ .acronym = "RestrictedAreaNavigational", .name = "Restricted Area Navigational" }, + .{ .acronym = "RestrictedAreaRegulatory", .name = "Restricted Area Regulatory" }, + .{ .acronym = "LightAllAround", .name = "Light All Around" }, + .{ .acronym = "LightSectored", .name = "Light Sectored" }, + .{ .acronym = "LightFogDetector", .name = "Light Fog Detector" }, + .{ .acronym = "LightAirObstruction", .name = "Light Air Obstruction" }, + .{ .acronym = "BuoyLateral", .name = "Buoy Lateral" }, + .{ .acronym = "BOYLAT", .name = "Buoy Lateral" }, + .{ .acronym = "BuoyCardinal", .name = "Buoy Cardinal" }, + .{ .acronym = "BOYCAR", .name = "Buoy Cardinal" }, + .{ .acronym = "BuoyIsolatedDanger", .name = "Buoy Isolated Danger" }, + .{ .acronym = "BOYISD", .name = "Buoy Isolated Danger" }, + .{ .acronym = "BuoySafeWater", .name = "Buoy Safe Water" }, + .{ .acronym = "BOYSAW", .name = "Buoy Safe Water" }, + .{ .acronym = "BuoySpecialPurposeGeneral", .name = "Buoy Special Purpose/General" }, + .{ .acronym = "BOYSPP", .name = "Buoy Special Purpose/General" }, + .{ .acronym = "BuoyEmergencyWreckMarking", .name = "Buoy Emergency Wreck Marking" }, + .{ .acronym = "BuoyInstallation", .name = "Buoy Installation" }, + .{ .acronym = "BOYINB", .name = "Buoy Installation" }, + .{ .acronym = "BeaconLateral", .name = "Beacon Lateral" }, + .{ .acronym = "BCNLAT", .name = "Beacon Lateral" }, + .{ .acronym = "BeaconCardinal", .name = "Beacon Cardinal" }, + .{ .acronym = "BCNCAR", .name = "Beacon Cardinal" }, + .{ .acronym = "BeaconIsolatedDanger", .name = "Beacon Isolated Danger" }, + .{ .acronym = "BCNISD", .name = "Beacon Isolated Danger" }, + .{ .acronym = "BeaconSafeWater", .name = "Beacon Safe Water" }, + .{ .acronym = "BCNSAW", .name = "Beacon Safe Water" }, + .{ .acronym = "BeaconSpecialPurposeGeneral", .name = "Beacon Special Purpose/General" }, + .{ .acronym = "BCNSPP", .name = "Beacon Special Purpose/General" }, + .{ .acronym = "Daymark", .name = "Daymark" }, + .{ .acronym = "DAYMAR", .name = "Daymark" }, + .{ .acronym = "LightFloat", .name = "Light Float" }, + .{ .acronym = "LITFLT", .name = "Light Float" }, + .{ .acronym = "LightVessel", .name = "Light Vessel" }, + .{ .acronym = "LITVES", .name = "Light Vessel" }, + .{ .acronym = "Retroreflector", .name = "Retroreflector" }, + .{ .acronym = "RETRFL", .name = "Retroreflector" }, + .{ .acronym = "RadarReflector", .name = "Radar Reflector" }, + .{ .acronym = "RADRFL", .name = "Radar Reflector" }, + .{ .acronym = "FogSignal", .name = "Fog Signal" }, + .{ .acronym = "FOGSIG", .name = "Fog Signal" }, + .{ .acronym = "PhysicalAISAidToNavigation", .name = "Physical AIS Aid to Navigation" }, + .{ .acronym = "VirtualAISAidToNavigation", .name = "Virtual AIS Aid to Navigation" }, + .{ .acronym = "NEWOBJ", .name = "Virtual AIS Aid to Navigation" }, + .{ .acronym = "RadioStation", .name = "Radio Station" }, + .{ .acronym = "RDOSTA", .name = "Radio Station" }, + .{ .acronym = "RadarTransponderBeacon", .name = "Radar Transponder Beacon" }, + .{ .acronym = "RTPBCN", .name = "Radar Transponder Beacon" }, + .{ .acronym = "PilotBoardingPlace", .name = "Pilot Boarding Place" }, + .{ .acronym = "PILBOP", .name = "Pilot Boarding Place" }, + .{ .acronym = "VesselTrafficServiceArea", .name = "Vessel Traffic Service Area" }, + .{ .acronym = "CoastGuardStation", .name = "Coast Guard Station" }, + .{ .acronym = "CGUSTA", .name = "Coast Guard Station" }, + .{ .acronym = "SignalStationWarning", .name = "Signal Station Warning" }, + .{ .acronym = "SISTAW", .name = "Signal Station Warning" }, + .{ .acronym = "SignalStationTraffic", .name = "Signal Station Traffic" }, + .{ .acronym = "SISTAT", .name = "Signal Station Traffic" }, + .{ .acronym = "RescueStation", .name = "Rescue Station" }, + .{ .acronym = "RSCSTA", .name = "Rescue Station" }, + .{ .acronym = "HarbourFacility", .name = "Harbour Facility" }, + .{ .acronym = "HRBFAC", .name = "Harbour Facility" }, + .{ .acronym = "SmallCraftFacility", .name = "Small Craft Facility" }, + .{ .acronym = "SMCFAC", .name = "Small Craft Facility" }, + .{ .acronym = "TextPlacement", .name = "Text Placement" }, +}; diff --git a/src/s57/decode.zig b/src/s57/decode.zig index 27798398..69b922af 100644 --- a/src/s57/decode.zig +++ b/src/s57/decode.zig @@ -284,3 +284,384 @@ test "the signature is the chart's shorthand" { const sig = lightSignature(a, &parsed.value.object).?; try std.testing.expectEqualStrings("Q G 1s", sig); } + +// ---- the report ------------------------------------------------------------- + +/// Classes the generated table cannot name: the S-57 meta and collection +/// objects that S-101 does not contain, and the classes whose S-57 alias +/// is claimed by more than one S-101 feature. +const class_leftovers = [_]catalog.AttrName{ + .{ .acronym = "ADMARE", .name = "Administration area" }, + .{ .acronym = "BRIDGE", .name = "Bridge" }, + .{ .acronym = "CTNARE", .name = "Caution area" }, + .{ .acronym = "LIGHTS", .name = "Light" }, + .{ .acronym = "RESARE", .name = "Restricted area" }, + .{ .acronym = "M_NPUB", .name = "Nautical publication note" }, + .{ .acronym = "M_COVR", .name = "Chart coverage" }, + .{ .acronym = "M_QUAL", .name = "Data quality" }, + .{ .acronym = "M_NSYS", .name = "Buoyage system" }, + .{ .acronym = "M_ACCY", .name = "Data accuracy" }, + .{ .acronym = "M_SREL", .name = "Survey reliability" }, + .{ .acronym = "M_CSCL", .name = "Compilation scale" }, + .{ .acronym = "C_AGGR", .name = "Aggregation" }, + .{ .acronym = "C_ASSO", .name = "Association" }, +}; + +/// The chart's name for an object class, or the class itself. +pub fn className(cls: []const u8) []const u8 { + for (class_leftovers) |e| if (std.mem.eql(u8, e.acronym, cls)) return e.name; + for (catalog_s101.class_names) |e| if (std.mem.eql(u8, e.acronym, cls)) return e.name; + return cls; +} + +/// One attribute of the payload, flattened. A complex attribute becomes a +/// heading with its parts indented under it. +const Row = struct { name: []const u8, value: []const u8, depth: u8 }; + +fn flatten(a: std.mem.Allocator, rows: *std.ArrayList(Row), v: std.json.Value, name: ?[]const u8, depth: u8) !void { + switch (v) { + .object => |obj| { + if (name) |n| try rows.append(a, .{ .name = n, .value = "", .depth = depth }); + // Alphabetical order first; the reading order sorts the top + // level after. + var keys = std.ArrayList([]const u8).empty; + var it = obj.iterator(); + while (it.next()) |e| try keys.append(a, e.key_ptr.*); + std.mem.sort([]const u8, keys.items, {}, struct { + fn lt(_: void, x: []const u8, y: []const u8) bool { + return std.mem.lessThan(u8, x, y); + } + }.lt); + for (keys.items) |k| { + try flatten(a, rows, obj.get(k).?, k, if (name == null) depth else depth + 1); + } + }, + .array => |arr| { + if (name) |n| try rows.append(a, .{ .name = n, .value = "", .depth = depth }); + for (arr.items) |item| try flatten(a, rows, item, null, depth + 1); + }, + .string => |s| try rows.append(a, .{ .name = name orelse "", .value = s, .depth = depth }), + .integer => |i| try rows.append(a, .{ .name = name orelse "", .value = try std.fmt.allocPrint(a, "{d}", .{i}), .depth = depth }), + .float => |f| try rows.append(a, .{ .name = name orelse "", .value = try std.fmt.allocPrint(a, "{d}", .{f}), .depth = depth }), + .bool => |b| try rows.append(a, .{ .name = name orelse "", .value = if (b) "true" else "false", .depth = depth }), + else => {}, + } +} + +/// The reading order of the top-level rows: the name first, then the +/// signal, then the shape, then the depths, then the rest in cell order. +const reading_order = [_][]const u8{ + "OBJNAM", "NOBJNM", + "LITCHR", "COLOUR", + "SIGPER", "SIGSEQ", + "SIGGRP", "EXCLIT", + "SECTR1", "SECTR2", + "HEIGHT", "VALNMR", + "CATLAM", "CATCAM", + "CATLIT", "CATWRK", + "CATOBS", "BOYSHP", + "BCNSHP", "TOPSHP", + "COLPAT", "VALSOU", + "DRVAL1", "DRVAL2", + "WATLEV", "NATSUR", +}; + +fn readingRank(name: []const u8) usize { + for (reading_order, 0..) |n, i| if (std.mem.eql(u8, n, name)) return i; + return reading_order.len; +} + +const RowGroup = enum { note, source, detail }; + +fn groupOf(name: []const u8) RowGroup { + const notes = [_][]const u8{ "INFORM", "NINFOM" }; + const source = [_][]const u8{ "SCAMIN", "SORDAT", "SORIND", "RECDAT", "RECIND" }; + for (notes) |n| if (std.mem.eql(u8, n, name)) return .note; + for (source) |n| if (std.mem.eql(u8, n, name)) return .source; + return .detail; +} + +fn isFileRef(name: []const u8, value: []const u8) bool { + if (value.len == 0) return false; + const refs = [_][]const u8{ "TXTDSC", "NTXTDS", "PICREP", "fileReference" }; + for (refs) |n| if (std.mem.eql(u8, n, name)) return true; + return false; +} + +fn isPicture(value: []const u8) bool { + const exts = [_][]const u8{ ".tif", ".tiff", ".jpg", ".jpeg", ".png", ".TIF", ".TIFF", ".JPG", ".JPEG", ".PNG" }; + for (exts) |e| if (std.mem.endsWith(u8, value, e)) return true; + return false; +} + +/// A top-level scalar's text from the flattened rows. +fn rowValue(rows: []const Row, name: []const u8) ?[]const u8 { + for (rows) |r| { + if (r.depth == 0 and r.value.len > 0 and std.mem.eql(u8, r.name, name)) return r.value; + } + return null; +} + +fn decodedOrNull(a: std.mem.Allocator, rows: []const Row, name: []const u8) ?[]const u8 { + const raw = rowValue(rows, name) orelse return null; + return decodeValue(a, name, raw); +} + +const Header = struct { title: []const u8, subtitle: ?[]const u8 }; + +/// The title and subtitle for a feature. A class with a rule leads with +/// its key fact: a light's characteristic, a wreck's least depth, a depth +/// area's range. Other classes lead with the name or the class. +fn header(a: std.mem.Allocator, cls: []const u8, rows: []const Row) Header { + const name = className(cls); + if (std.mem.eql(u8, cls, "LIGHTS")) { + if (lightSignatureRows(a, rows)) |sig| { + var phrase: []const u8 = name; + if (decodedOrNull(a, rows, "LITCHR")) |chr| { + if (decodedOrNull(a, rows, "COLOUR")) |col| { + phrase = std.fmt.allocPrint(a, "{s} — {s} {s}", .{ name, lowered(a, chr), lowered(a, col) }) catch name; + } + } + return .{ .title = sig, .subtitle = phrase }; + } + } + if (std.mem.eql(u8, cls, "WRECKS")) { + if (rowValue(rows, "VALSOU")) |sou| { + const v = decodeValue(a, "VALSOU", sou) orelse sou; + return .{ + .title = std.fmt.allocPrint(a, "Wreck, {s}", .{v}) catch name, + .subtitle = if (decodedOrNull(a, rows, "CATWRK")) |c| + std.fmt.allocPrint(a, "Wreck — {s}", .{c}) catch name + else + name, + }; + } + } + if (std.mem.eql(u8, cls, "DEPARE") or std.mem.eql(u8, cls, "DRGARE")) { + if (rowValue(rows, "DRVAL1")) |d1| if (rowValue(rows, "DRVAL2")) |d2| { + return .{ .title = std.fmt.allocPrint(a, "{s}–{s}", .{ d1, d2 }) catch name, .subtitle = name }; + }; + } + const phrase = markPhrase(a, cls, rows) orelse areaPhrase(a, rows); + if (rowValue(rows, "OBJNAM")) |objnam| { + return .{ .title = objnam, .subtitle = phrase orelse name }; + } + return .{ .title = name, .subtitle = phrase }; +} + +/// A mark's subtitle from shape, colour and category: "Buoy, lateral — +/// green can · port hand". +fn markPhrase(a: std.mem.Allocator, cls: []const u8, rows: []const Row) ?[]const u8 { + const marky = std.mem.startsWith(u8, cls, "BOY") or std.mem.startsWith(u8, cls, "BCN") or + std.mem.eql(u8, cls, "TOPMAR") or std.mem.eql(u8, cls, "DAYMAR"); + if (!marky) return null; + const name = className(cls); + const col = decodedOrNull(a, rows, "COLOUR"); + const shp = decodedOrNull(a, rows, "BOYSHP") orelse decodedOrNull(a, rows, "BCNSHP") orelse decodedOrNull(a, rows, "TOPSHP"); + const cat = decodedOrNull(a, rows, "CATLAM") orelse decodedOrNull(a, rows, "CATCAM"); + var lead: ?[]const u8 = null; + if (col != null and shp != null) { + lead = std.fmt.allocPrint(a, "{s} {s}", .{ lowered(a, col.?), shp.? }) catch null; + } else if (col) |c| { + lead = lowered(a, c); + } else if (shp) |sh| { + lead = sh; + } + if (lead != null and cat != null) + return std.fmt.allocPrint(a, "{s} — {s} · {s}", .{ name, lead.?, cat.? }) catch null; + if (lead) |l| return std.fmt.allocPrint(a, "{s} — {s}", .{ name, l }) catch null; + if (cat) |c| return std.fmt.allocPrint(a, "{s} — {s}", .{ name, c }) catch null; + return null; +} + +/// An area's subtitle: its category, or its restriction. +fn areaPhrase(a: std.mem.Allocator, rows: []const Row) ?[]const u8 { + return decodedOrNull(a, rows, "CATREA") orelse decodedOrNull(a, rows, "RESTRN"); +} + +fn lowered(a: std.mem.Allocator, s: []const u8) []const u8 { + const out = a.dupe(u8, s) catch return s; + for (out) |*c| c.* = std.ascii.toLower(c.*); + return out; +} + +/// The light's characteristic from flattened rows. The ObjectMap variant +/// serves callers that hold parsed JSON. +fn lightSignatureRows(a: std.mem.Allocator, rows: []const Row) ?[]const u8 { + const chr_raw = rowValue(rows, "LITCHR") orelse return null; + const chr = std.fmt.parseInt(u16, chr_raw, 10) catch return null; + const abbr = abbrevOf(litchr_abbrev, chr) orelse return null; + var out = std.ArrayList(u8).empty; + out.appendSlice(a, abbr) catch return null; + if (rowValue(rows, "SIGGRP")) |grp| { + if (!std.mem.eql(u8, grp, "(1)") and !std.mem.eql(u8, grp, "()")) + out.appendSlice(a, grp) catch return null; + } + if (rowValue(rows, "COLOUR")) |col_raw| { + if (std.fmt.parseInt(u16, col_raw, 10) catch null) |col| { + if (abbrevOf(colour_abbrev, col)) |letter| { + out.append(a, ' ') catch return null; + out.appendSlice(a, letter) catch return null; + } + } + } + appendNumUnitRows(a, &out, rows, "SIGPER", "s"); + appendNumUnitRows(a, &out, rows, "HEIGHT", "m"); + appendNumUnitRows(a, &out, rows, "VALNMR", "M"); + return out.items; +} + +fn appendNumUnitRows(a: std.mem.Allocator, out: *std.ArrayList(u8), rows: []const Row, name: []const u8, unit: []const u8) void { + const raw = rowValue(rows, name) orelse return; + const n = std.fmt.parseFloat(f64, raw) catch return; + const printed = std.fmt.allocPrint(a, " {d}{s}", .{ n, unit }) catch return; + out.appendSlice(a, printed) catch {}; +} + +/// The chip: the short name for a list row. +fn chipTitle(a: std.mem.Allocator, cls: []const u8, rows: []const Row) []const u8 { + if (std.mem.eql(u8, cls, "LIGHTS")) { + if (lightSignatureRows(a, rows)) |sig| return sig; + } + if (std.mem.eql(u8, cls, "M_NPUB")) return "Chart notes"; + return className(cls); +} + +/// The report a shell renders for one picked feature, as JSON: +/// {"title","subtitle","chip","notes":[…],"rows":[{"label","value","depth", +/// "file","picture"}…],"footnote","empty":"none"|"source"}. The "empty" +/// field appears only when there is nothing to read. The caller frees the +/// bytes. +pub fn report(alloc: std.mem.Allocator, cls: []const u8, cell: []const u8, s57_json: []const u8) ![]u8 { + var arena = std.heap.ArenaAllocator.init(alloc); + defer arena.deinit(); + const a = arena.allocator(); + + var rows = std.ArrayList(Row).empty; + if (std.json.parseFromSlice(std.json.Value, a, s57_json, .{})) |parsed| { + try flatten(a, &rows, parsed.value, null, 0); + } else |_| {} + + // Sort the top-level blocks into reading order. Sub-rows stay under + // their parents. The sort is stable for rows the order does not name. + var blocks = std.ArrayList([]const Row).empty; + { + var i: usize = 0; + while (i < rows.items.len) { + var j = i + 1; + while (j < rows.items.len and rows.items[j].depth > 0) : (j += 1) {} + try blocks.append(a, rows.items[i..j]); + i = j; + } + std.mem.sort([]const Row, blocks.items, {}, struct { + fn lt(_: void, x: []const Row, y: []const Row) bool { + return readingRank(x[0].name) < readingRank(y[0].name); + } + }.lt); + } + + const hdr = header(a, cls, rows.items); + + var aw: std.Io.Writer.Allocating = .init(alloc); + defer aw.deinit(); + var stringify: std.json.Stringify = .{ .writer = &aw.writer }; + const js = &stringify; + + try js.beginObject(); + try js.objectField("title"); + try js.write(hdr.title); + if (hdr.subtitle) |sub| { + try js.objectField("subtitle"); + try js.write(sub); + } + try js.objectField("chip"); + try js.write(chipTitle(a, cls, rows.items)); + + try js.objectField("notes"); + try js.beginArray(); + for (rows.items) |r| { + if (r.depth == 0 and groupOf(r.name) == .note and r.value.len > 0) try js.write(r.value); + } + try js.endArray(); + + var n_detail: usize = 0; + try js.objectField("rows"); + try js.beginArray(); + for (blocks.items) |block| { + if (groupOf(block[0].name) != .detail) continue; + for (block) |r| { + n_detail += 1; + try js.beginObject(); + try js.objectField("label"); + try js.write(attrName(r.name)); + try js.objectField("value"); + try js.write(decodeValue(a, r.name, r.value) orelse r.value); + if (r.depth > 0) { + try js.objectField("depth"); + try js.write(r.depth); + } + if (isFileRef(r.name, r.value)) { + try js.objectField("file"); + try js.write(true); + if (isPicture(r.value)) { + try js.objectField("picture"); + try js.write(true); + } + } + try js.endObject(); + } + } + try js.endArray(); + + // The provenance as one line: the cell, the source, the source date, + // and the charted scale range. + var foot = std.ArrayList(u8).empty; + try foot.appendSlice(a, cell); + const source_attrs = [_][]const u8{ "SORIND", "SORDAT", "SCAMIN" }; + for (source_attrs) |sn| { + if (rowValue(rows.items, sn)) |raw| { + try foot.appendSlice(a, " · "); + try foot.appendSlice(a, decodeValue(a, sn, raw) orelse raw); + } + } + try js.objectField("footnote"); + try js.write(foot.items); + + var n_notes: usize = 0; + for (rows.items) |r| { + if (r.depth == 0 and groupOf(r.name) == .note and r.value.len > 0) n_notes += 1; + } + if (n_detail == 0 and n_notes == 0) { + try js.objectField("empty"); + try js.write(if (rows.items.len == 0) "none" else "source"); + } + try js.endObject(); + + return aw.toOwnedSlice(); +} + +test "report composes the page" { + const a = std.testing.allocator; + const json = + \\{"COLOUR":"4","LITCHR":"4","SIGPER":"1","SIGGRP":"(1)","SIGSEQ":"00.3+(00.7)", + \\"EXCLIT":"4","SCAMIN":"29999","SORDAT":"20010106","SORIND":"US,US,graph,Chart 12283", + \\"INFORM":"Seasonal aid"} + ; + const out = try report(a, "LIGHTS", "US5MD1MC", json); + defer a.free(out); + try std.testing.expect(std.mem.indexOf(u8, out, "\"title\":\"Q G 1s\"") != null); + try std.testing.expect(std.mem.indexOf(u8, out, "Seasonal aid") != null); + try std.testing.expect(std.mem.indexOf(u8, out, "Quick-flashing") != null); + try std.testing.expect(std.mem.indexOf(u8, out, "1:30,000 and larger") != null); + try std.testing.expect(std.mem.indexOf(u8, out, "Chart 12283 (US)") != null); +} + +test "report marks an empty body" { + const a = std.testing.allocator; + const out = try report(a, "SLCONS", "C", "{\"SORDAT\":\"20010106\"}"); + defer a.free(out); + try std.testing.expect(std.mem.indexOf(u8, out, "\"empty\":\"source\"") != null); + const none = try report(a, "LNDARE", "C", "{}"); + defer a.free(none); + try std.testing.expect(std.mem.indexOf(u8, none, "\"empty\":\"none\"") != null); +} diff --git a/src/s57/s57.zig b/src/s57/s57.zig index ec7de7c1..20098956 100644 --- a/src/s57/s57.zig +++ b/src/s57/s57.zig @@ -14,8 +14,8 @@ const Allocator = std.mem.Allocator; /// that want the raw records. It is its own module (`@import("iso8211")`), so a /// caller can depend on the 8211 layer without pulling in S-57 semantics. pub const iso8211 = @import("iso8211"); -/// The IHO attribute catalogue as data, and the mariner's decode over it — -/// the pick report's language, served to every shell from here. +/// The attribute catalogues as data, and the pick-report decode over +/// them. Every shell reads the same decode. pub const catalog = @import("catalog.zig"); pub const catalog_s101 = @import("catalog_s101.zig"); pub const decode = @import("decode.zig"); diff --git a/tools/fcattrs.zig b/tools/fcattrs.zig index 27d47ffc..0dfe15dd 100644 --- a/tools/fcattrs.zig +++ b/tools/fcattrs.zig @@ -78,10 +78,65 @@ pub fn run(io: std.Io, a: std.mem.Allocator, args: []const [:0]const u8) !void { try out.appendSlice(a, enums.items); try out.appendSlice(a, "};\n"); + // Feature types: the object-class names. Emit the S-101 code always. + // Emit the S-57 alias only when exactly one feature type claims it and + // it has the shape of an S-57 acronym. S-101 splits some S-57 classes + // into several features (CTNARE becomes Caution Area and Discoloured + // Water), and an alias with several claims does not name one class. + try out.appendSlice(a, + \\ + \\/// Object class (S-57 acronym or S-101 code) -> the chart's name. + \\pub const class_names = [_]catalog.AttrName{ + \\ + ); + var n_classes: usize = 0; + // First pass: count the claims on each alias. + var claims = std.StringHashMap(usize).init(a); + var crest: []const u8 = xml; + while (indexAfter(crest, "") orelse break; + const head = crest[start .. start + (std.mem.indexOf(u8, crest[start .. start + end], "") orelse break; + const block = frest[start .. start + end]; + frest = frest[start + end ..]; + const head = block[0 .. std.mem.indexOf(u8, block, "