This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
dcs-maps-coordinates converts coordinates for DCS World maps between
lat/long (WGS84), DCS planar x, y (map-specific), MGRS, and UTM. Every DCS
theatre is a Transverse Mercator projection on WGS84 (k₀ = 0.9996); only three
parameters vary per map (lon_0, x_0, y_0). Conversions are real
projection math (via pyproj), not lookup tables.
poetry install # venv + editable install
poetry run pytest -q # full test suite (needs no game installed)
poetry run pytest tests/test_known_maps.py::<name> # a single test
poetry run dcs-coords maps # list known maps
poetry run dcs-coords calibrate [--write] # add/update a map from a dcs.log
poetry run dcs-coords generate # rebuild exports/ after changing maps.yamlRequires Python ≥ 3.10.
x = North (DCS Lua Vec3.x), y = East (DCS Lua Vec3.z, not
its y). This package ignores altitude. Results are Position(x, y) named
tuples to keep this unambiguous. lat/long is decimal degrees WGS84 (N/E
positive). See the docstring in src/dcs_coords/convert.py.
lat/long is the hub: x,y is per-map, while MGRS/UTM are global. Composed
conversions (xy_to_mgrs, etc.) chain through lat/long — they are thin
compositions, not separate math.
- src/dcs_coords/maps.py — registry. Loads
data/maps.yaml(cached vialru_cache; callreload()after writes). The full PROJ string is built fromPROJ_TEMPLATE+ the three per-map values.maps.yamlstores onlylon_0/x_0/y_0; everything else is fixed in code. - src/dcs_coords/convert.py — the conversions. One
cached
pyproj.Transformerper map (always_xy=Truenormalizes I/O order despite the+axis=neuin the PROJ string). - src/dcs_coords/calibrate.py —
calibrate_from_points()+ thedcs-coordsTyper CLI. Calibration does an integer search overlon_0: the correct meridian makesy − eastingandx − northingconstant (min variance);x_0/y_0are those means. No non-linear solver. Rejects fits with residual > 1 m. - src/dcs_coords/ingest.py —
parse_log()reads thedcs.logproduced by the in-game script (theatre auto-detected fromenv.mission.theatre; only the last theatre block is used) plus CSV/JSON loaders. - src/dcs_coords/export.py — regenerates
exports/maps.{yaml,json,md,py}from the registry (dcs-coords generate). - tools/export_points.lua — in-game grid exporter
(DO SCRIPT trigger → logs
DCSXFORMlines viaenv.info, no game-file edits). - src/dcs_coords/init.py — public API surface
(
__all__). Adding a conversion means adding it inconvert.pyand re-exporting here.
data/maps.yaml is the source of truth for projection params (validated
in-editor by data/maps.schema.json via the # yaml-language-server: modeline
— set_map() re-emits that header on every write so validation survives).
exports/ is generated output — never hand-edit it; run dcs-coords generate. To add a map, prefer the calibration flow
(docs/adding-a-map.md) over editing maps.yaml by hand,
and commit both the YAML change and any saved points.
Keys are the codified env.mission.theatre values (camelCase, no spaces):
Caucasus, PersianGulf, MarianaIslands, SinaiMap, Kola, etc. This same
string is the map_name argument throughout the API.
docs/how-it-works.md (model + calibration internals), docs/adding-a-map.md, docs/exports.md, docs/developing.md.