Initial shitty commit of skew-T chart rendering
This commit is contained in:
parent
2360baeebf
commit
b96bc12660
1 changed files with 194 additions and 0 deletions
194
lib/xmet/skew_t.py
Normal file
194
lib/xmet/skew_t.py
Normal file
|
@ -0,0 +1,194 @@
|
|||
#! /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
|
||||
|
||||
def clamp(value, lowest, highest):
|
||||
if value < lowest:
|
||||
return lowest
|
||||
elif value > highest:
|
||||
return highest
|
||||
|
||||
return value
|
||||
|
||||
def pressure_y(pressure: float) -> float:
|
||||
if pressure < PRESSURE_MIN:
|
||||
pressure = PRESSURE_MIN
|
||||
elif pressure > PRESSURE_MAX:
|
||||
pressure = PRESSURE_MAX
|
||||
|
||||
log_p = math.log(pressure)
|
||||
factor = (PRESSURE_LOG_MAX - log_p) / PRESSURE_LOG_RANGE
|
||||
|
||||
return factor * GRAPH_HEIGHT
|
||||
|
||||
def graph_to_screen(x, y) -> tuple:
|
||||
return (
|
||||
GRAPH_OFFSET_X + x,
|
||||
IMAGE_HEIGHT - GRAPH_OFFSET_Y - y
|
||||
)
|
||||
|
||||
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))
|
||||
|
||||
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()
|
||||
|
||||
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)
|
||||
|
||||
cr.move_to(screen_x1, screen_y1)
|
||||
cr.line_to(screen_x2, screen_y2)
|
||||
cr.stroke()
|
||||
|
||||
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),
|
||||
|
||||
(-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),
|
||||
|
||||
(-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 isotherm_to_graph(x, y) -> tuple:
|
||||
return (
|
||||
GRAPH_WIDTH / 2 + x,
|
||||
y
|
||||
)
|
||||
|
||||
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()
|
Loading…
Add table
Reference in a new issue