The Jerusalem PostStudent opens fire outside school in Turkey, eight pupils wounded, NTV reportsDaily MaverickStudent opens fire outside school in Turkey, eight pupils wounded, NTV reportsוואלהבמהלך חג הסוכות תוגבל כניסה למטיילים במשטחי אימונים בדרוםBollywood HungamaEXCLUSIVE: Ajay Devgn-Rohit Jugraj’s horror thriller titled SuryasparshInquirer EntertainmentJopay Paguia ‘respects’ Rochelle Pangilinan, but stands firm on her work ethicInquirerAgusan solon pushes national soil strategy through SUCsХабрКак в игровых студиях принимаются технические решения, когда на кону денюжкиCollider‘Marvel’s Wolverine’ Officially Changes Controversial Gameplay Feature After Fan BacklashSouth China Morning PostCan China’s grain reserves protect food security against El Nino?The South AfricanAircraft crash reported near Morningstar Airfield on the N7RTL BoulevardRekenkamer: Van Weel zette Kamer op verkeerde been over 10.000 onbehandelde aangiftenGhaflaBoundaries And Public Office: Omanga’s School Attire Trend Sparks Debate Online
The Daily Newsstand · Free, Always
Tuesday, September 22, 2026

Написал JavaScript-парсер морских навигационных карт формата S-57: от hex-дампов до рендеринга в браузере

Translate

Год назад мне понадобился JavaScript-инструмент для работы с морскими навигационными картами формата S-57. Я нашёл GDAL — серверная библиотека на C, не для браузера. Нашёл коммерческие SDK — от $10K до $200K в год. Нашёл несколько заброшенных репозиториев 2014 года.

Написал сам. Получился парсер, который работает прямо в браузере: никакого сервера, никаких зависимостей, 127 тестов, открытый код.

В этой статье расскажу, что такое S-57, почему с ним сложно, что я сделал и зачем вообще это нужно.

Что такое S-57 и зачем это кому-то нужно

S-57 (IHO Special Publication No. 57) — международный стандарт для электронных навигационных карт. Используется на каждом коммерческом судне в мире с 1996 года. Гидрографические службы США (NOAA), Великобритании, Норвегии, Японии и других стран публикуют данные именно в этом формате.

Если вы видите электронную карту в системе навигации судна — с большой вероятностью под капотом S-57.

Карты NOAA для US вод доступны бесплатно. Всего их около 1200 штук, они обновляются еженедельно.

Проблема: открытой JavaScript-библиотеки для работы с S-57 фактически не существовало. Все решения — либо серверные (GDAL, OpenCPN), либо платные SDK для enterprise.

Масштаб рынка: maritime navigation software — около $500M, растёт из-за перехода на S-101 (обязателен с 2029 года для всего флота). В JS-экосистеме для этого нет ничего.

Формат данных: почему это сложно

ISO 8211 — бинарный формат 1994 года

S-57 основан на ISO 8211, международном стандарте для обмена данными в полевых условиях. Разработан в эпоху перфокарт, но до сих пор живёт.

Файл состоит из записей (records), каждая запись — из полей, каждое поле — из данных с метаданными. Всё бинарное, с позиционными индексами в начале каждой записи.

Первый сюрприз: два формата бинарной нотации, которые внешне неотличимы. В заголовке записи указан тип, но декодировать его нужно с учётом глобального DDR (Data Descriptive Record) в начале файла. Если перепутать — данные читаются без ошибок, но неверно. Потратил несколько часов на hex-дампы, прежде чем понял.

// DDR tells you how to read each field
// Without it, two identical byte sequences mean different things
const fieldType = ddr.getFieldFormat(fieldTag);
const value = fieldType === 'B' ? readBinary(bytes) : readString(bytes);

Топология: полигоны не хранятся как полигоны

Второй сюрприз — и главная техническая сложность S-57 — это топологическая модель данных.

В обычных форматах (GeoJSON, Shapefile) полигон — это массив координат. В S-57 полигоны хранятся как ориентированные рёбра графа, которые нужно собирать в рантайме.

Структура:

  • Node — точка на карте (может быть связана с несколькими рёбрами)

  • Edge — ребро, соединяющее два узла (может быть частью нескольких объектов)

  • Feature — объект (мель, буй, огонь, береговая линия), ссылается на рёбра через Edge References с направлением (+1 или -1)

Алгоритм сборки полигона:

  1. Найти все Edge References для Feature

  2. Для каждого ребра — взять точки в правильном направлении

  3. Соединить рёбра по shared nodes

  4. Замкнуть контур

function assemblePoly(feature: Feature, edges: Map<string, Edge>): Coordinate[] {
  const rings: Coordinate[][] = [];
  const edgeRefs = feature.attr['FSPT'] as EdgeRef[];
  
  // Sort edges into a closed ring
  let currentRing: Coordinate[] = [];
  let currentEdge = edgeRefs[0];
  
  while (edgeRefs.length > 0) {
    const edge = edges.get(currentEdge.rcid);
    const coords = currentEdge.ornt === 1 
      ? edge.coords 
      : [...edge.coords].reverse();
    
    currentRing.push(...coords.slice(0, -1)); // avoid duplicate node
    
    const nextStart = coords[coords.length - 1];
    currentEdge = edgeRefs.find(e => 
      edgeStartsAt(edges.get(e.rcid), e.ornt, nextStart)
    );
    
    if (!currentEdge || currentRing.length === 0) {
      rings.push([...currentRing, currentRing[0]]); // close
      currentRing = [];
      currentEdge = edgeRefs[0];
    }
  }
  
  return rings.flat();
}

Это медленнее прямой десериализации, но зато: каждое ребро хранится один раз, данные консистентны.

Рендеринг: стандарт IHO S-52

Распарсить данные — полдела. Отобразить их правильно — стандарт IHO S-52 на 400+ страниц с правилами символики, цветов, приоритетов слоёв.

Три цветовые схемы: день (DDAY), сумерки (DUSK), ночь (DNIGHT). Каждая — свой набор цветов для глубин, опасностей, береговой линии.

Что реализовано в парсере:

  • Глубинная зональность с градиентом (безопасные воды — синие, мелководье — зелёное, суша — серая)

  • Секторные навигационные огни (дуги с правильными углами и цветами)

  • Контуры опасностей (пунктирные линии со звёздочками по стандарту)

  • Точечные символы: буи, маяки, вехи

  • Текстовые метки с правилами приоритета

Canvas 2D API, никакого WebGL.

Что получилось в цифрах

  • 5 200 строк TypeScript

  • 127 тестов (парсинг, топология, рендеринг)

  • 0 runtime зависимостей

  • Работает в браузере и Node.js

  • Парсит реальные файлы NOAA (протестировано на 40+ картах)

Демо: можно перетащить .000-файл прямо в браузер и увидеть карту. NOAA публикует их бесплатно на nauticalcharts.noaa.gov.

Почему open source

Я мог бы продавать SDK. Коммерческие аналоги стоят от $10K в год.

Но:

  1. Гидрографические данные NOAA бесплатны по закону. Логично, что инструменты тоже должны быть бесплатными.

  2. Я не морской инженер. Вряд ли смогу строить бизнес на поддержке этой библиотеки правильно.

  3. Следующий стандарт S-101 обязателен к 2029 году. Открытая инфраструктура нужна отрасли.

Написал статью на английском на Reddit (r/sailing, r/OpenSource), получил звёзды от Норвегии, Германии, Канады. Несколько разработчиков уже открыли issues с запросами под конкретные суда.

Что дальше

S-101 — новый стандарт, S-63 (шифрование коммерческих карт), Web Workers для тяжёлых файлов, WebGL для производительности.

Если вы работаете в maritime tech или просто интересно поковыряться — репозиторий на GitHub: github.com/devladpopov/s57-parser

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.