diff --git a/game/theater/landmap.py b/game/theater/landmap.py index 89dcdcf7..c5b422ad 100644 --- a/game/theater/landmap.py +++ b/game/theater/landmap.py @@ -1,5 +1,6 @@ from dataclasses import dataclass import pickle +from functools import cached_property from typing import Optional, Tuple, Union import logging @@ -13,6 +14,18 @@ class Landmap: exclusion_zones: MultiPolygon sea_zones: MultiPolygon + def __post_init__(self): + if not self.inclusion_zones.is_valid: + raise RuntimeError("Inclusion zones not valid") + if not self.exclusion_zones.is_valid: + raise RuntimeError("Exclusion zones not valid") + if not self.sea_zones.is_valid: + raise RuntimeError("Sea zones not valid") + + @cached_property + def inclusion_zone_only(self) -> MultiPolygon: + return self.inclusion_zones - self.exclusion_zones - self.sea_zones + def load_landmap(filename: str) -> Optional[Landmap]: try: diff --git a/gen/conflictgen.py b/gen/conflictgen.py index d2bedfbe..b050e028 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -93,7 +93,7 @@ class Conflict: line = LineString([p0, p1]) intersection = line.intersection( - theater.landmap.inclusion_zones.boundary) + theater.landmap.inclusion_zone_only.boundary) if intersection.is_empty: # Max extent does not intersect with the boundary of the inclusion # zone, so the full front line is usable. This does assume that the diff --git a/resources/caulandmap.p b/resources/caulandmap.p index 7ceefc71..c5076169 100644 Binary files a/resources/caulandmap.p and b/resources/caulandmap.p differ diff --git a/resources/channellandmap.p b/resources/channellandmap.p index 6ee32087..92864e8c 100644 Binary files a/resources/channellandmap.p and b/resources/channellandmap.p differ diff --git a/resources/gulflandmap.p b/resources/gulflandmap.p index a521f5e5..98fe5bce 100644 Binary files a/resources/gulflandmap.p and b/resources/gulflandmap.p differ diff --git a/resources/nevlandmap.p b/resources/nevlandmap.p index 42e34c37..f8ef5cbb 100644 Binary files a/resources/nevlandmap.p and b/resources/nevlandmap.p differ diff --git a/resources/normandylandmap.p b/resources/normandylandmap.p index 2d7ade8e..20eb8715 100644 Binary files a/resources/normandylandmap.p and b/resources/normandylandmap.p differ diff --git a/resources/syrialandmap.p b/resources/syrialandmap.p index 0d11a3c2..f39fb3bb 100644 Binary files a/resources/syrialandmap.p and b/resources/syrialandmap.p differ diff --git a/resources/tools/generate_landmap.py b/resources/tools/generate_landmap.py index 7e1a9f4b..a23c7fd1 100644 --- a/resources/tools/generate_landmap.py +++ b/resources/tools/generate_landmap.py @@ -1,11 +1,37 @@ import pickle +from functools import singledispatch from dcs.mission import Mission -from shapely import geometry -from shapely.geometry import MultiPolygon +from shapely.geometry import GeometryCollection, MultiPolygon, Polygon +from shapely.ops import unary_union from game.theater.landmap import Landmap + +@singledispatch +def to_multipoly(obj) -> MultiPolygon: + raise NotImplementedError( + f"to_multipoly not implemented for {obj.__class__.__name__}") + + +@to_multipoly.register +def _poly_to_multipoly(obj: Polygon) -> MultiPolygon: + return MultiPolygon([obj]) + + +@to_multipoly.register +def _multipoly_to_multipoly(obj: MultiPolygon) -> MultiPolygon: + return obj + + +@to_multipoly.register +def _geometry_collection_to_multipoly(obj: GeometryCollection) -> MultiPolygon: + if obj.is_empty: + return MultiPolygon() + raise RuntimeError( + f"Not sure how to convert collection to multipoly: {obj.wkt}") + + for terrain in ["cau", "nev", "syria", "channel", "normandy", "gulf"]: print("Terrain " + terrain) m = Mission() @@ -19,19 +45,22 @@ for terrain in ["cau", "nev", "syria", "channel", "normandy", "gulf"]: if terrain == "cau" and inclusion_zones: # legacy - exclusion_zones.append(geometry.Polygon(zone)) + exclusion_zones.append(Polygon(zone)) else: + poly = Polygon(zone) + if not poly.is_valid: + raise RuntimeError(f"{plane_group} is invalid") if plane_group.units[0].type == "F-15C": - exclusion_zones.append(geometry.Polygon(zone)) + exclusion_zones.append(poly) else: - inclusion_zones.append(geometry.Polygon(zone)) + inclusion_zones.append(poly) for ship_group in m.country("USA").ship_group: zone = [(x.position.x, x.position.y) for x in ship_group.points] - seas_zones.append(geometry.Polygon(zone)) + seas_zones.append(Polygon(zone)) with open("../{}landmap.p".format(terrain), "wb") as f: print(len(inclusion_zones), len(exclusion_zones), len(seas_zones)) - pickle.dump(Landmap(MultiPolygon(inclusion_zones), - MultiPolygon(exclusion_zones), - MultiPolygon(seas_zones)), f) + pickle.dump(Landmap(to_multipoly(unary_union(inclusion_zones)), + to_multipoly(unary_union(exclusion_zones)), + to_multipoly(unary_union(seas_zones))), f)