diff --git a/lib/xmet/hodograph.py b/lib/xmet/hodograph.py index 7b8cbfc..7b66cd9 100644 --- a/lib/xmet/hodograph.py +++ b/lib/xmet/hodograph.py @@ -6,11 +6,11 @@ from typing import Iterable from xmet.igra import IGRAReader from xmet.sounding import Sounding, SoundingSample -WIND_SPEED_MAX = 90 # knots -WIND_SPEED_MIN = 10 -WIND_SPEED_STEP = 10 +WIND_SPEED_MAX = 100 # knots +WIND_SPEED_MIN = 10 +WIND_SPEED_STEP = 10 -WIND_DIR_STEP = 45 # degrees +WIND_DIR_STEP = 90 # degrees PRESSURE_MIN = 100 @@ -24,28 +24,40 @@ class Hodograph(): def __init__(self, width, height): self.width = min(width, height) self.height = min(width, height) - self.radius = min(width, height) / 2 + self.radius = min(width, height) * 1.2 def sample_to_screen(self, wind_speed: dir, wind_dir: float) -> tuple: r = self.radius * min(wind_speed, WIND_SPEED_MAX) / WIND_SPEED_MAX return ( - self.width / 2 + r * math.cos(radians(wind_dir)), - self.height / 2 + r * math.sin(radians(wind_dir)) + 0.1 * self.width + r * math.cos(radians(wind_dir)), + 0.9 * self.height + r * math.sin(radians(wind_dir)) ) def draw_speed_lines(self, cr: cairo.Context, x, y): + cr.save() + + cr.set_source_rgb(0.5, 0.5, 0.5) + cr.set_line_width(0.5) + cr.set_dash([5, 5], 1) + for speed in range(WIND_SPEED_MIN, WIND_SPEED_MAX+1, WIND_SPEED_STEP): - cr.arc(x + self.width / 2, - y + self.height / 2, + cr.arc(x + 0.1 * self.width, + y + 0.9 * self.height, self.radius * min(speed, WIND_SPEED_MAX) / WIND_SPEED_MAX, 0, 2*math.pi) cr.stroke() + cr.restore() + def draw_direction_lines(self, cr: cairo.Context, x, y): - for angle in range(0, 360+1, WIND_DIR_STEP): + cr.save() + + cr.set_source_rgb(0.5, 0.5, 0.5) + + for angle in range(0, 360+1, WIND_DIR_STEP): sx1, sy1 = self.sample_to_screen(WIND_SPEED_MAX, angle) sx2, sy2 = self.sample_to_screen(WIND_SPEED_MAX, angle + 180) @@ -53,6 +65,8 @@ class Hodograph(): cr.line_to(x + sx2, y + sy2) cr.stroke() + cr.restore() + def draw_direction_legends(self, cr: cairo.Context, x, y): cr.save() @@ -67,8 +81,8 @@ class Hodograph(): extents = cr.text_extents(text) r = self.radius + ((extents.width + extents.height) / 2) - sx = self.width / 2 + r * math.cos(radians(angle)) - sy = self.height / 2 + r * math.sin(radians(angle)) + sx = 0.1 * self.width + r * math.cos(radians(angle)) + sy = 0.9 * self.height + r * math.sin(radians(angle)) cr.move_to(x + sx - extents.width / 2, y + sy + extents.height / 2) cr.show_text(text) @@ -80,7 +94,7 @@ class Hodograph(): cr.save() x_offset_scale = 0.01190476 - y_offset_scale = 0.02380952 + y_offset_scale = 0.01 x_offset = x_offset_scale * self.radius y_offset = y_offset_scale * self.radius @@ -157,27 +171,51 @@ class Hodograph(): def draw_height_legends(self, cr: cairo.Context, x, y): width = 0.02380952 * self.width interval = 0.05952380 * self.width - offset = 0 + offset = 0.75 * self.width + + cr.save() + cr.set_source_rgb(1, 1, 1) + + cr.rectangle(offset + x - width / 2, + y + width, + interval * 4, + width * 3) + + cr.fill() + + cr.set_source_rgb(0.8, 0.8, 0.8) + cr.rectangle(offset + x - width / 2, + y + width, + interval * 4, + width * 3) + cr.stroke() + cr.restore() for height in self.COLORS: color = self.COLORS[height] cr.save() cr.set_source_rgb(*color) - cr.rectangle(offset + x, y, width, width) + cr.rectangle(offset + x, y + width * 1.5, width, width) cr.fill() cr.restore() - cr.rectangle(offset + x, y, width, width) + cr.rectangle(offset + x, y + width * 1.5, width, width) cr.stroke() - cr.move_to(offset + x, y + 2*width) + cr.move_to(offset + x, y + 3.5*width) cr.show_text("%dkm" % (height / 1000)) cr.stroke() offset += interval def draw(self, cr: cairo.Context, x, y, samples: Iterable[SoundingSample]): + cr.rectangle(x, y, self.width, self.height) + cr.clip() + + cr.rectangle(x, y, self.width, self.height) + cr.stroke() + self.draw_speed_lines(cr, x, y) self.draw_direction_lines(cr, x, y) @@ -186,3 +224,5 @@ class Hodograph(): self.draw_speed_legends(cr, x, y) self.draw_direction_legends(cr, x, y) self.draw_height_legends(cr, x, y) + + cr.reset_clip()