From d5294e111d62b45b1d7bfe6edaa28b2f8fe1d2b3 Mon Sep 17 00:00:00 2001 From: XANTRONIX Industrial Date: Sun, 23 Feb 2025 17:00:19 -0500 Subject: [PATCH] Slowly refactor skew_t.py into reusability --- lib/xmet/skew_t.py | 205 ++++++++------------------------------------- 1 file changed, 36 insertions(+), 169 deletions(-) diff --git a/lib/xmet/skew_t.py b/lib/xmet/skew_t.py index 0c1cffc..87b6c88 100644 --- a/lib/xmet/skew_t.py +++ b/lib/xmet/skew_t.py @@ -1,31 +1,8 @@ -#! /usr/bin/env python3 - import math import cairo -IMAGE_WIDTH = 1366 -IMAGE_HEIGHT = 768 - -GRAPH_HEIGHT = IMAGE_HEIGHT - 64 -GRAPH_WIDTH = (GRAPH_HEIGHT / 10.0) * 18 - -GRAPH_OFFSET_X = (IMAGE_WIDTH - GRAPH_WIDTH) / 2 -GRAPH_OFFSET_Y = 32 - -PRESSURE_MAX = 1050 -PRESSURE_MIN = 100 -PRESSURE_STEP = 50 - -PRESSURE_LOG_MAX = math.log(PRESSURE_MAX) -PRESSURE_LOG_MIN = math.log(PRESSURE_MIN) -PRESSURE_LOG_RANGE = PRESSURE_LOG_MAX - PRESSURE_LOG_MIN - -TEMP_CENTER = 0 # degrees C -TEMP_STEP = 5 -TEMP_STEP_WIDTH = GRAPH_HEIGHT / 10.0 - -ADIABATIC_LAPSE_RATE_DRY = 9.8 / 1000 # degrees C per 1000m -ADIABATIC_LAPSE_RATE_MOIST = 4.0 / 1000 +TEMP_CENTER = 0 # degrees C +TEMP_STEP = 5 def clamp(value, lowest, highest): if value < lowest: @@ -35,160 +12,50 @@ def clamp(value, lowest, highest): return value -def pressure_y(pressure: float) -> float: - if pressure < PRESSURE_MIN: - pressure = PRESSURE_MIN - elif pressure > PRESSURE_MAX: - pressure = PRESSURE_MAX +class SkewT(): + __slots__ = 'width', 'height', 'temp_step_width', - log_p = math.log(pressure) - factor = (PRESSURE_LOG_MAX - log_p) / PRESSURE_LOG_RANGE + ISOTHERM_LINES = ( + (0, 0, 9, 9), (1, 0, 9, 8), (2, 0, 9, 7), (3, 0, 9, 6), + (4, 0, 9, 5), (5, 0, 9, 4), (6, 0, 9, 3), (7, 0, 9, 2), + (8, 0, 9, 1), (9, 0, 9, 0), - return factor * GRAPH_HEIGHT + (-1, 0, 9, 10), (-2, 0, 8, 10), (-3, 0, 7, 10), (-4, 0, 6, 10), + (-5, 0, 5, 10), (-6, 0, 4, 10), (-7, 0, 3, 10), (-8, 0, 2, 10), + (-9, 0, 1, 10), -def graph_to_screen(x, y) -> tuple: - return ( - GRAPH_OFFSET_X + x, - IMAGE_HEIGHT - GRAPH_OFFSET_Y - y + (-9, 1, 0, 10), (-9, 2, -1, 10), (-9, 3, -2, 10), (-9, 4, -3, 10), + (-9, 5, -4, 10), (-9, 6, -5, 10), (-9, 7, -6, 10), (-9, 8, -7, 10), + (-9, 9, -8, 10), ) -def draw_pressure_lines(cr: cairo.Context): - for pressure in range(PRESSURE_MIN, PRESSURE_MAX+1, PRESSURE_STEP): - (x, y) = graph_to_screen(0, pressure_y(pressure)) + def __init__(self, width: float, height: float): + self.width = width + self.height = height - cr.set_source_rgba(0.0, 0.0, 0.0, 0.5) - cr.move_to(x, y) - cr.rel_line_to(GRAPH_WIDTH, 0) - cr.stroke() + self.temp_step_width = self.height / 10.0 -def draw_graph_line(cr: cairo.Context, x1, y1, x2, y2): - (screen_x1, screen_y1) = graph_to_screen(x1, y1) - (screen_x2, screen_y2) = graph_to_screen(x2, y2) + def graph_to_screen(self, x, y) -> tuple: + return (self.width / 2) + x, self.height - y - cr.move_to(screen_x1, screen_y1) - cr.line_to(screen_x2, screen_y2) - cr.stroke() + def draw_pressure_lines(self, cr: cairo.Context): + pass -ISOTHERM_LINES = ( - (0, 0, 9, 9), (1, 0, 9, 8), (2, 0, 9, 7), (3, 0, 9, 6), - (4, 0, 9, 5), (5, 0, 9, 4), (6, 0, 9, 3), (7, 0, 9, 2), - (8, 0, 9, 1), (9, 0, 9, 0), + def draw_isotherms(self, cr: cairo.Context, x: float, y: float): + cr.set_source_rgba(0.1, 0.5, 0.1, 0.8) - (-1, 0, 9, 10), (-2, 0, 8, 10), (-3, 0, 7, 10), (-4, 0, 6, 10), - (-5, 0, 5, 10), (-6, 0, 4, 10), (-7, 0, 3, 10), (-8, 0, 2, 10), - (-9, 0, 1, 10), + for line in self.ISOTHERM_LINES: + x1 = line[0] * self.temp_step_width + y1 = line[1] * self.temp_step_width + x2 = line[2] * self.temp_step_width + y2 = line[3] * self.temp_step_width - (-9, 1, 0, 10), (-9, 2, -1, 10), (-9, 3, -2, 10), - (-9, 4, -3, 10), (-9, 5, -4, 10), (-9, 6, -5, 10), - (-9, 7, -6, 10), (-9, 8, -7, 10), (-9, 9, -8, 10), -) + (screen_x1, screen_y1) = self.graph_to_screen(x1, y1) + (screen_x2, screen_y2) = self.graph_to_screen(x2, y2) -def isotherm_to_graph(x, y) -> tuple: - return ( - GRAPH_WIDTH / 2 + x, - y - ) + cr.move_to(x + screen_x1, y + screen_y1) + cr.line_to(x + screen_x2, y + screen_y2) + cr.stroke() -def draw_isotherms(cr: cairo.Context): - cr.set_source_rgba(0.1, 0.5, 0.1, 0.8) - - for line in ISOTHERM_LINES: - x1 = line[0] * TEMP_STEP_WIDTH - y1 = line[1] * TEMP_STEP_WIDTH - x2 = line[2] * TEMP_STEP_WIDTH - y2 = line[3] * TEMP_STEP_WIDTH - - graph_1 = isotherm_to_graph(x1, y1) - graph_2 = isotherm_to_graph(x2, y2) - - draw_graph_line(cr, graph_1[0], graph_1[1], graph_2[0], graph_2[1]) - -def sample_to_graph(temp: float, pressure: float): - x = (temp / TEMP_STEP) * TEMP_STEP_WIDTH - y = pressure_y(pressure) - - return ( - GRAPH_WIDTH / 2 + x + y, - y - ) - -SAMPLES = ( - ( 101200, -6), - ( 101200, -6), - ( 100000, -12), - ( 99300, -22), - ( 98700, -29), - ( 97500, -39), - ( 95700, -50), - ( 95100, -47), - ( 93900, -43), - ( 92000, -34), - ( 90400, -34), - ( 90000, -34), - ( 89200, -34), - ( 85000, -34), - ( 83700, -34), - ( 82100, -34), - ( 80000, -42), - ( 78600, -46), - ( 77600, -50), - ( 70000, -77), - ( 69100, -80), - ( 60700, -128), - ( 60000, -133), - ( 53100, -186), - ( 50000, -215), - ( 46300, -255), - ( 40200, -337), - ( 40000, -340), - ( 35000, -412), - ( 34900, -413), - ( 30100, -496), - ( 30000, -496), - ( 25700, -565), - ( 25000, -577), - ( 24400, -585), - ( 22100, -510), - ( 21900, -510), - ( 20000, -497), - ( 15000, -466), - ( 10000, -438), - ( 7000, -414), - ( 5000, -393), - ( 3000, -368), - ( 2000, -344), - ( 1500, -337), - ( 1000, -305), - ( 500, -210), - ( 400, -198) -) - -with cairo.SVGSurface('test.svg', IMAGE_WIDTH, IMAGE_HEIGHT) as surface: - cr = cairo.Context(surface) - - cr.rectangle(GRAPH_OFFSET_X, GRAPH_OFFSET_Y, GRAPH_WIDTH, GRAPH_HEIGHT) - cr.stroke() - - draw_pressure_lines(cr) - draw_isotherms(cr) - - cr.set_source_rgb(0, 0, 1) - - first = True - - for sample in SAMPLES: - pressure = sample[0] / 100.0 - temp = sample[1] * 0.1 - - gx, gy = sample_to_graph(temp, pressure) - x, y = graph_to_screen(gx, gy) - - print(f"x {x} y {y} pressure {pressure} temp {temp}") - - if first: - cr.move_to(x, y) - first = False - else: - cr.line_to(x, y) - - cr.stroke() + def draw(self, cr: cairo.Context, x: float, y: float): + self.draw_isotherms(cr, x, y)