"""Hand-drawn weather icons using the panel's actual 6-color palette (from epd4in0e's getbuffer() quantization palette: black, white, yellow, red, blue, green) instead of relying on font glyph coverage for weather emoji, which turned out to be incomplete (DejaVu Sans has no partly-cloudy glyph) and is monochrome anyway. """ import math BLACK = (0, 0, 0) WHITE = (255, 255, 255) YELLOW = (255, 255, 0) BLUE = (0, 0, 255) # WMO weather code -> (description, icon kind). Not exhaustive, covers the # common cases; unmapped codes fall back to "clear". WMO_CODES = { 0: ("Klarer Himmel", "clear"), 1: ("Überwiegend klar", "clear"), 2: ("Teilweise bewölkt", "partly_cloudy"), 3: ("Bedeckt", "cloudy"), 45: ("Nebel", "fog"), 48: ("Nebel", "fog"), 51: ("Leichter Nieselregen", "rain"), 53: ("Nieselregen", "rain"), 55: ("Starker Nieselregen", "rain"), 61: ("Leichter Regen", "rain"), 63: ("Regen", "rain"), 65: ("Starker Regen", "rain"), 71: ("Leichter Schneefall", "snow"), 73: ("Schneefall", "snow"), 75: ("Starker Schneefall", "snow"), 80: ("Regenschauer", "rain"), 81: ("Regenschauer", "rain"), 82: ("Heftige Regenschauer", "rain"), 85: ("Schneeschauer", "snow"), 86: ("Schneeschauer", "snow"), 95: ("Gewitter", "thunder"), 96: ("Gewitter mit Hagel", "thunder"), 99: ("Gewitter mit Hagel", "thunder"), } def _cloud_shape(draw, cx, cy, w, h, color): draw.rounded_rectangle((cx - w / 2, cy - h * 0.1, cx + w / 2, cy + h * 0.55), radius=h * 0.28, fill=color) draw.ellipse((cx - w * 0.42, cy - h * 0.48, cx - w * 0.02, cy + h * 0.12), fill=color) draw.ellipse((cx - w * 0.18, cy - h * 0.62, cx + w * 0.22, cy + h * 0.02), fill=color) draw.ellipse((cx + w * 0.05, cy - h * 0.42, cx + w * 0.45, cy + h * 0.18), fill=color) def draw_cloud(draw, cx, cy, size, outline=BLACK, fill=WHITE): """Simple line-art cloud: draw the silhouette in `outline`, then a shrunk-down copy in `fill` on top -- fakes an outlined shape without needing real path-offsetting.""" w, h = size, size * 0.7 border = max(2, size * 0.07) _cloud_shape(draw, cx, cy, w, h, outline) _cloud_shape(draw, cx, cy, w - border * 2.4, h - border * 2.4, fill) def draw_sun(draw, cx, cy, r, color=YELLOW, outline=BLACK): ray_w = max(2, int(r * 0.16)) for angle_deg in range(0, 360, 45): rad = math.radians(angle_deg) # Kept within roughly r*1.4 so the whole icon (rays included) stays # inside the nominal size x size box callers lay out around it. inner, outer = r * 1.15, r * 1.4 draw.line( (cx + math.cos(rad) * inner, cy + math.sin(rad) * inner, cx + math.cos(rad) * outer, cy + math.sin(rad) * outer), fill=color, width=ray_w, ) draw.ellipse((cx - r, cy - r, cx + r, cy + r), fill=color, outline=outline, width=max(2, int(r * 0.1))) def _draw_snowflake(draw, cx, cy, r, color): for angle_deg in range(0, 180, 60): rad = math.radians(angle_deg) draw.line( (cx - math.cos(rad) * r, cy - math.sin(rad) * r, cx + math.cos(rad) * r, cy + math.sin(rad) * r), fill=color, width=max(2, int(r * 0.35)), ) def draw_weather_icon(draw, kind: str, cx: float, cy: float, size: float): """Draws into a roughly `size` x `size` box centered on (cx, cy).""" if kind == "clear": draw_sun(draw, cx, cy, size * 0.34) elif kind == "partly_cloudy": draw_sun(draw, cx - size * 0.16, cy - size * 0.18, size * 0.22) draw_cloud(draw, cx + size * 0.08, cy + size * 0.14, size * 0.75) elif kind == "cloudy": draw_cloud(draw, cx, cy, size * 0.9) elif kind == "fog": for i, dy in enumerate((-0.25, -0.05, 0.15, 0.35)): band_w = size * (0.9 - i * 0.12) yy = cy + size * dy draw.line((cx - band_w / 2, yy, cx + band_w / 2, yy), fill=BLACK, width=max(2, int(size * 0.05))) elif kind == "rain": draw_cloud(draw, cx, cy - size * 0.12, size * 0.85) for dx in (-0.28, -0.02, 0.24): x0, y0 = cx + size * dx, cy + size * 0.3 draw.line((x0, y0, x0 - size * 0.08, y0 + size * 0.24), fill=BLUE, width=max(2, int(size * 0.05))) elif kind == "snow": draw_cloud(draw, cx, cy - size * 0.12, size * 0.85) for dx in (-0.28, -0.02, 0.24): _draw_snowflake(draw, cx + size * dx, cy + size * 0.38, size * 0.08, BLUE) elif kind == "thunder": draw_cloud(draw, cx, cy - size * 0.16, size * 0.85) bolt = [ (cx + size * 0.05, cy + size * 0.16), (cx - size * 0.08, cy + size * 0.42), (cx + size * 0.02, cy + size * 0.42), (cx - size * 0.1, cy + size * 0.7), (cx + size * 0.18, cy + size * 0.36), (cx + size * 0.06, cy + size * 0.36), ] draw.polygon(bolt, fill=YELLOW, outline=BLACK) else: draw_sun(draw, cx, cy, size * 0.34)