diff --git a/src/c3nav/mapdata/render/engines/opengl.py b/src/c3nav/mapdata/render/engines/opengl.py index 4290f37e..d15a2dd8 100644 --- a/src/c3nav/mapdata/render/engines/opengl.py +++ b/src/c3nav/mapdata/render/engines/opengl.py @@ -1,11 +1,13 @@ import io from collections import deque +from itertools import chain from typing import Union import ModernGL import numpy as np from PIL import Image -from shapely.geometry import MultiPolygon, Polygon +from shapely.geometry import CAP_STYLE, JOIN_STYLE, LinearRing, LineString, MultiLineString, MultiPolygon, Polygon +from shapely.ops import unary_union from trimesh.creation import triangulate_polygon from c3nav.mapdata.render.engines.base import RenderEngine @@ -73,6 +75,23 @@ class OpenGLEngine(RenderEngine): if fill is not None: self.vertices.append(self._create_geometry(geometry, self.hex_to_rgb(fill.color))) + if stroke is not None and stroke.color.startswith('#'): + if isinstance(geometry, MultiLineString): + lines = (geometry, ) + elif isinstance(geometry, (LinearRing, LineString)): + lines = (geometry, ) + elif isinstance(geometry, (Polygon, MultiPolygon)): + lines = tuple(chain(*((polygon.exterior, *polygon.interiors) + for polygon in assert_multipolygon(geometry)))) + else: + raise ValueError('Unknown geometry for add_geometry!') + + self.vertices.append(self._create_geometry( + unary_union(lines).buffer(max(stroke.width, (stroke.min_px or 0) / self.scale)/2, + cap_style=CAP_STYLE.flat, join_style=JOIN_STYLE.mitre), + self.hex_to_rgb(stroke.color) + )) + def get_png(self) -> bytes: if self.vertices: vbo = self.ctx.buffer(np.hstack(self.vertices).astype(np.float32).tobytes())