Support polygons with holes in the API.

We don't have any of these yet because our landmaps suck, but we'll need
holes in the sea zones to mask islands correctly.
This commit is contained in:
Dan Albert
2022-09-07 14:12:32 -07:00
committed by Raffson
parent b0fd09057c
commit 2dba0f07ad
5 changed files with 59 additions and 47 deletions

View File

@@ -5,7 +5,7 @@ from pydantic import BaseModel, Field
from game import Game
from game.ato import Flight
from game.flightplan import HoldZoneGeometry, IpZoneGeometry, JoinZoneGeometry
from ..leaflet import LeafletPoly, ShapelyUtil
from ..leaflet import LeafletLine, LeafletPoly, ShapelyUtil
class HoldZonesJs(BaseModel):
@@ -14,7 +14,7 @@ class HoldZonesJs(BaseModel):
join_bubble: LeafletPoly = Field(alias="joinBubble")
excluded_zones: list[LeafletPoly] = Field(alias="excludedZones")
permissible_zones: list[LeafletPoly] = Field(alias="permissibleZones")
preferred_lines: list[LeafletPoly] = Field(alias="preferredLines")
preferred_lines: list[LeafletLine] = Field(alias="preferredLines")
class Config:
title = "HoldZones"
@@ -93,7 +93,7 @@ class JoinZonesJs(BaseModel):
ip_bubble: LeafletPoly = Field(alias="ipBubble")
excluded_zones: list[LeafletPoly] = Field(alias="excludedZones")
permissible_zones: list[LeafletPoly] = Field(alias="permissibleZones")
preferred_lines: list[LeafletPoly] = Field(alias="preferredLines")
preferred_lines: list[LeafletLine] = Field(alias="preferredLines")
class Config:
title = "JoinZones"

View File

@@ -20,7 +20,15 @@ class LeafletPoint(BaseModel):
title = "LatLng"
LeafletPoly = list[LeafletPoint]
LeafletLine = list[LeafletPoint]
# Leaflet allows either a single array of latlng to define the boundary, or an array of
# arrays of latlngs, with the first array being the boundary and the rest defining
# holes. To avoid the UI needing to test for which type of polygon we send, we always
# use the array of arrays type, even for geometries without holes.
# https://leafletjs.com/reference.html#polygon
LeafletPoly = list[LeafletLine]
class ShapelyUtil:
@@ -32,10 +40,11 @@ class ShapelyUtil:
def poly_to_leaflet(cls, poly: Polygon, theater: ConflictTheater) -> LeafletPoly:
if poly.is_empty:
return []
return [
cls.latlng_to_leaflet(Point(x, y, theater.terrain).latlng())
for x, y in poly.exterior.coords
]
try:
lines = poly.boundary.geoms
except AttributeError:
lines = [poly.boundary]
return cls.lines_to_leaflet(MultiLineString(lines), theater)
@classmethod
def polys_to_leaflet(
@@ -47,14 +56,17 @@ class ShapelyUtil:
polys = [poly]
return [cls.poly_to_leaflet(poly, theater) for poly in polys]
@staticmethod
def line_to_leaflet(line: LineString, theater: ConflictTheater) -> list[LatLng]:
return [Point(x, y, theater.terrain).latlng() for x, y in line.coords]
@classmethod
def line_to_leaflet(cls, line: LineString, theater: ConflictTheater) -> LeafletLine:
return [
cls.latlng_to_leaflet(Point(x, y, theater.terrain).latlng())
for x, y in line.coords
]
@classmethod
def lines_to_leaflet(
cls, line_string: MultiLineString | LineString, theater: ConflictTheater
) -> list[list[LatLng]]:
) -> list[LeafletLine]:
if isinstance(line_string, MultiLineString):
lines = line_string.geoms
else: