Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sinai terrain export and the fixes needed to do so. #321

Merged
merged 6 commits into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion dcs/mission.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ def loaddict(fname: str, mizfile: zipfile.ZipFile, reserved_files: List[str]) ->
self.terrain = terrain_.Normandy()
elif imp_mission["theatre"] == 'TheChannel':
self.terrain = terrain_.TheChannel()
elif imp_mission["theatre"] == 'SinaiMap':
self.terrain = terrain_.Sinai()
elif imp_mission["theatre"] == 'Syria':
self.terrain = terrain_.Syria()
elif imp_mission["theatre"] == "MarianaIslands":
Expand Down Expand Up @@ -2018,7 +2020,7 @@ def dict(self):
m["trigrules"] = self.triggerrules.trigrules()
m["triggers"] = self.triggers.dict()
m["weather"] = self.weather.dict()
m["theatre"] = self.terrain.name
m["theatre"] = self.terrain.miz_theatre_name
if self.needModules:
m["needModules"] = self.needModules
m["map"] = self.map.dict()
Expand Down
1 change: 1 addition & 0 deletions dcs/terrain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
from dcs.terrain.normandy import Normandy
from dcs.terrain.persiangulf import PersianGulf
from dcs.terrain.thechannel import TheChannel
from dcs.terrain.sinai import Sinai
from dcs.terrain.syria import Syria
from dcs.terrain.marianaislands import MarianaIslands
1 change: 1 addition & 0 deletions dcs/terrain/sinai/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .sinai import Sinai
5,870 changes: 5,870 additions & 0 deletions dcs/terrain/sinai/airports.py

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions dcs/terrain/sinai/projection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# DO NOT EDIT:
# This file is generated by tools/export_map_projection.py.
from dcs.terrain.projections import TransverseMercator

PARAMETERS = TransverseMercator(
central_meridian=33,
false_easting=169221.9999999585,
false_northing=-3325312.9999999693,
scale_factor=0.9996,
)
40 changes: 40 additions & 0 deletions dcs/terrain/sinai/sinai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import dcs.mapping as mapping
from dcs.terrain.terrain import Terrain, MapView
from .airports import ALL_AIRPORTS
from .projection import PARAMETERS


class Sinai(Terrain):
center = {"lat": 31.0, "long": 32.0}
temperature = [
(2, 8),
(3, 11),
(6, 15),
(10, 21),
(15, 27),
(18, 32),
(22, 35),
(22, 35),
(19, 32),
(14, 26),
(7, 17),
(4, 10)
]
assert len(temperature) == 12

def __init__(self):
bounds = mapping.Rectangle(-450000, -280000, 500000, 560000, self)
super().__init__(
"Sinai",
PARAMETERS,
bounds,
map_view_default=MapView(bounds.center(), self, 1000000)
)
self.bullseye_blue = {"x": 0, "y": 0}
self.bullseye_red = {"x": 0, "y": 0}

self.airports = {a.name: a(self) for a in ALL_AIRPORTS}

@property
def miz_theatre_name(self) -> str:
return "SinaiMap"
8 changes: 7 additions & 1 deletion dcs/terrain/terrain.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class RunwayApproach:

@staticmethod
def from_lua(name: str, beacons: Dict[str, List[RunwayBeacon]]) -> RunwayApproach:
return RunwayApproach(name, int(name.rstrip("LR")) * 10, beacons.get(name, []))
return RunwayApproach(name, int(name.rstrip("LCR")) * 10, beacons.get(name, []))


@dataclass(frozen=True)
Expand Down Expand Up @@ -531,6 +531,12 @@ def __setstate__(self, state: Dict[str, Any]) -> None:
CRS("WGS84"), self.projection_parameters.to_crs()
)

@property
def miz_theatre_name(self) -> str:
# Sinai uses a different name for the "theatre" field (SinaiMap) than it does in
# the mods directory on disk (Sinai).
return self.name

def weather(self, dt: datetime, weather_: weather.Weather):
# check if there might be the season for thunderstorms
if 4 < dt.month < 11:
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
'dcs/terrain/normandy',
'dcs/terrain/persiangulf',
'dcs/terrain/projections',
'dcs/terrain/sinai',
'dcs/terrain/syria',
'dcs/terrain/thechannel',
],
Expand Down
86 changes: 42 additions & 44 deletions tools/export_map_projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from dcs.terrain.nevada import Nevada
from dcs.terrain.normandy import Normandy
from dcs.terrain.persiangulf import PersianGulf
from dcs.terrain.sinai import Sinai
from dcs.terrain.syria import Syria
from dcs.terrain.terrain import Terrain
from dcs.terrain.thechannel import TheChannel
Expand All @@ -55,7 +56,7 @@
EXPORT_LUA = THIS_DIR / "coord_export.lua"
DCS_SAVED_GAMES = Path.home() / "Saved Games/DCS"
SRC_ROOT = THIS_DIR.parent
EXPORT_DIR = SRC_ROOT / "dcs/terrain/projections"
EXPORT_DIR = SRC_ROOT / "dcs/terrain"


ARG_TO_TERRAIN_MAP = {
Expand All @@ -65,24 +66,11 @@
"normandy": Normandy(),
"persiangulf": PersianGulf(),
"thechannel": TheChannel(),
"sinai": Sinai(),
"syria": Syria(),
"marianaislands": MarianaIslands(),
}

# https://gisgeography.com/central-meridian/
# UTM zones determined by guess and check. There are only a handful in the region for
# each map and getting the wrong one will be flagged with errors when processing.
CENTRAL_MERIDIANS = {
"caucasus": 33,
"falklands": -57,
"nevada": -117,
"normandy": -3,
"persiangulf": 57,
"thechannel": 3,
"syria": 39,
"marianaislands": 147,
}


@dataclass(frozen=True)
class Coordinates:
Expand Down Expand Up @@ -143,9 +131,12 @@ def test_for_errors(
if not math.isclose(x, coords.x) or not math.isclose(z, coords.z):
error_x = x - coords.x
error_z = z - coords.z
error_pct_x = error_x / coords.x * 100
error_pct_z = error_z / coords.z * 100
print(f"{name} has error of {error_pct_x}% {error_pct_z}%")
try:
error_pct_x = error_x / coords.x * 100
error_pct_z = error_z / coords.z * 100
except ZeroDivisionError as ex:
raise RuntimeError(f"Unexpected 0 coordinate in {name}")
logging.debug(f"{name} has error of {error_pct_x}% {error_pct_z}%")
errors = True

lat, lon = x_z_to_lat_lon.transform(coords.x, coords.z)
Expand All @@ -156,7 +147,7 @@ def test_for_errors(
error_lon = lon - coords.longitude
error_pct_lon = error_lat / coords.latitude * 100
error_pct_lat = error_lon / coords.longitude * 100
print(f"{name} has error of {error_pct_lat}% {error_pct_lon}%")
logging.debug(f"{name} has error of {error_pct_lat}% {error_pct_lon}%")
errors = True

return errors
Expand All @@ -173,6 +164,9 @@ def test_parameters(
for name, coords in airbases.items():
if name == "zero":
continue
if name in {"Raj al Issa East", "Raj al Issa West"}:
# https://forum.dcs.world/topic/299885-raj-al-issa-west-east-markers/
continue
if test_for_errors(name, lat_lon_to_x_z, x_z_to_lat_lon, coords):
errors = True
return errors
Expand All @@ -186,30 +180,34 @@ def compute_tmerc_parameters(
airbases = load_coordinate_data(data)
wgs84 = CRS("WGS84")

# Creates a transformer with 0 for the false easting and northing, but otherwise has
# the correct parameters. We'll use this to transform the zero point from the
# mission to calculate the error from the actual zero point to determine the correct
# false easting and northing.
bad = TransverseMercator(
central_meridian=CENTRAL_MERIDIANS[terrain],
false_easting=0,
false_northing=0,
scale_factor=0.9996,
).to_crs()
zero_finder = Transformer.from_crs(wgs84, bad)
z, x = zero_finder.transform(airbases["zero"].latitude, airbases["zero"].longitude)

parameters = TransverseMercator(
central_meridian=CENTRAL_MERIDIANS[terrain],
false_easting=-x,
false_northing=-z,
scale_factor=0.9996,
)
# UTM has a central meridian every 6 degrees from 177W to 177E.
# https://gisgeography.com/central-meridian/
for central_meridian in range(-177, 177 + 1, 6):
# Creates a transformer with 0 for the false easting and northing, but otherwise has
# the correct parameters. We'll use this to transform the zero point from the
# mission to calculate the error from the actual zero point to determine the correct
# false easting and northing.
bad = TransverseMercator(
central_meridian=central_meridian,
false_easting=0,
false_northing=0,
scale_factor=0.9996,
).to_crs()
zero_finder = Transformer.from_crs(wgs84, bad)
z, x = zero_finder.transform(
airbases["zero"].latitude, airbases["zero"].longitude
)

if test_parameters(airbases, parameters):
sys.exit("Found errors in projection parameters. Quitting.")
parameters = TransverseMercator(
central_meridian=central_meridian,
false_easting=-x,
false_northing=-z,
scale_factor=0.9996,
)

return parameters
if not test_parameters(airbases, parameters):
return parameters
sys.exit("Found errors in projection parameters. Quitting.")


def replace_mission_scripting_file(install_dir: Path) -> Path:
Expand Down Expand Up @@ -275,12 +273,12 @@ def main() -> None:
mission = create_mission(terrain)
with mission_scripting(args.dcs):
input(
f"Created {mission} and replaced MissionScript.lua. Open DCS and load the "
"mission. Once the mission starts running, close it and press enter."
f"Created {mission} and replaced MissionScripting.lua. Open DCS and load "
"the mission. Once the mission starts running, close it and press enter."
)
coords_path = DCS_SAVED_GAMES / "coords.json"
parameters = compute_tmerc_parameters(coords_path, args.map)
out_file = EXPORT_DIR / f"{args.map}.py"
out_file = EXPORT_DIR / args.map / "projection.py"
out_file.write_text(
textwrap.dedent(
f"""\
Expand Down