Одна из самых предметных частей проекта началась с обычной строки судового донесения:

река, 612 километр

Для человека, который работает с флотом, это понятное положение. Для цифровой карты это пока не координата.

Почему одного километра недостаточно

Одинаковые или близкие значения километров встречаются на разных участках водных путей. Чтобы определить место, нужны дополнительные признаки:

  • атлас или том ЕГС;
  • участок пути;
  • название реки, канала, озера или водохранилища;
  • ближайший шлюз;
  • порт или реперная точка;
  • направление и предыдущее положение судна.

Особенно сложны переходы между разными типами водных объектов. В одном рейсе судно может последовательно пройти реку, водохранилище, канал и озеро. Предыдущий контекст помогает, но не должен блокировать явный переход на другую водную систему.

Сначала предметная область, потом алгоритм

Значительная часть работы состояла не в программировании. Приходилось открывать атласы ЕГС и вручную проверять:

  • к какому тому относится участок;
  • какой диапазон километров в нём используется;
  • где находятся шлюзы;
  • как проходят границы участков;
  • к какому месту относится подпись из донесения;
  • совпадает ли расчётная точка с цифровой картой.

Пока эти связи не понятны человеку, формализовать их в коде невозможно. Бумажный документ содержит предметную логику, а не только строки для переноса в таблицу.

Импорт существующих справочников

Часть данных уже существовала в табличных материалах:

  • атласы;
  • участки пути;
  • километры;
  • шлюзы;
  • реперные точки;
  • порты;
  • моря и морские районы.

Их можно было импортировать, но импорт не отменял проверку. Для некоторых километров были заданы географические границы. Ориентировочную точку можно было получить как центр такой области.

Это не GPS-координата. Результат должен храниться как расчётный и иметь соответствующее обозначение точности.

Когда точной точки нет

Не каждый километр имел готовую координату. Тогда использовался каскад вариантов:

  1. точное совпадение с импортированной точкой;
  2. интерполяция между соседними километрами одного участка;
  3. ближайшая точка того же атласа и водной системы;
  4. известный шлюз, порт или реперная точка;
  5. локальный справочник алиасов;
  6. водная геометрия цифровой карты;
  7. ручная проверка.

Интерполяция допустима только внутри понятного участка. Нельзя брать две формально соседние записи, если между ними меняется водная система или километраж относится к другому тому.

Алиасы реальных мест

Путевые донесения редко используют идеальные официальные названия. В них встречаются сокращения, местные ориентиры, номера стоянок, падежные формы, варианты написания и опечатки.

Для этого появился справочник географических алиасов. После ручного уточнения место сохраняется как известное соответствие, и следующая такая формулировка уже не требует повторного разбора.

Исправление одной записи превращается в правило для будущих данных.

Открытая карта — тоже не источник истины

Открытые картографические данные помогают получить геометрию рек, озёр, каналов, портов и акваторий. Но общий картографический слой не является готовой моделью судового хода.

В нём могут встречаться неоднозначные названия, крупные полигоны без нужной детализации, объекты с одинаковыми именами и неполные данные отдельных районов.

Поэтому картографический слой используется как часть каскада, а не как единственный справочник.

Что получилось в итоге

Из бумажных и табличных источников сложилась связанная модель:

атлас
→ участок пути
→ километровая точка
→ шлюз или ориентир
→ географическая область
→ расчётная координата

Она нужна не только карте. Это часть НСИ судового приложения: экипаж выбирает атлас, участок и километр из справочника, а берег получает структурированные значения вместо попытки распознать их из свободного текста.

Оцифровка отраслевого документа оказалась не сканированием и не переносом таблицы в базу. Сначала потребовалось понять его терминологию, связи, диапазоны и границы применимости, а затем явно отделить расчётную точность от подтверждённого положения.