Source code for flametrack.gui.plotting_utils

import numpy as np


[docs] def sort_corner_points( points, experiment_type="Room Corner", direction="clockwise" ) -> list: """ Sort corner points depending on experiment type. - For 'room_corner' (6 points): Sort using angle-based method with defined start point - For 'lateral_flame_spread' (4 points): Sort using center angle """ if experiment_type == "Room Corner": if len(points) != 6: raise ValueError("Room corner expects exactly 6 points.") pts = np.array(points) center = np.mean(pts, axis=0) angles = np.arctan2(pts[:, 1] - center[1], pts[:, 0] - center[0]) sort_order = np.argsort(angles) if direction == "clockwise": sort_order = sort_order[::-1] sorted_pts = pts[sort_order] # Beginne mit dem Punkt ganz links oben top_idx = np.lexsort((sorted_pts[:, 1], sorted_pts[:, 0]))[0] sorted_pts = np.roll(sorted_pts, -top_idx, axis=0) return [tuple(pt) for pt in sorted_pts] if experiment_type == "Lateral Flame Spread": if len(points) != 4: raise ValueError("Lateral flame spread expects exactly 4 points.") pts = np.array(points, dtype=np.float64) # Robust ordering that works for any tilt and aspect ratio: # Split along the dominant axis (wider → left/right pairs; # taller → top/bottom pairs), then sort each pair along the # cross-axis to assign TL/BL (or TL/TR). # # Angle-based methods fail for highly elongated plates where the # two "top" corners are nearly collinear with the two "bottom" # corners relative to the centroid. Sum/diff methods fail for # plates tilted close to 45°. This split-on-dominant-axis # approach is robust for both. x_span = pts[:, 0].max() - pts[:, 0].min() y_span = pts[:, 1].max() - pts[:, 1].min() if x_span >= y_span: # Wider (or square) plate: split into left pair and right pair order = np.argsort(pts[:, 0]) left = pts[order[:2]] right = pts[order[2:]] tl = left[np.argmin(left[:, 1])] bl = left[np.argmax(left[:, 1])] tr = right[np.argmin(right[:, 1])] br = right[np.argmax(right[:, 1])] else: # Taller plate: split into top pair and bottom pair order = np.argsort(pts[:, 1]) top = pts[order[:2]] bot = pts[order[2:]] tl = top[np.argmin(top[:, 0])] tr = top[np.argmax(top[:, 0])] bl = bot[np.argmin(bot[:, 0])] br = bot[np.argmax(bot[:, 0])] return [tuple(tl), tuple(tr), tuple(br), tuple(bl)] raise ValueError(f"Unknown experiment type: {experiment_type}")
[docs] def rotate_points(points, image_shape, rotation_index): """ Converts points from a np.rot90-rotated display frame back to unrotated image coordinates. :param points: Liste von (x, y)-Punkten im rotierten Bild :param image_shape: Form des UNROTIERTEN Bildes als (Höhe, Breite) :param rotation_index: 0 = 0°, 1 = 90° CCW, 2 = 180°, 3 = 270° CCW :return: Punkte im unrotierten Bildkoordinatensystem als Liste von (x, y) """ k = rotation_index % 4 if k == 0: return points img_h, img_w = image_shape[0], image_shape[1] pts = np.array(points, dtype=np.float32) rx, ry = pts[:, 0], pts[:, 1] if k == 1: # 90° CCW: inverse is x = W-1-ry, y = rx x_out, y_out = img_w - 1 - ry, rx elif k == 2: # 180°: inverse is x = W-1-rx, y = H-1-ry x_out, y_out = img_w - 1 - rx, img_h - 1 - ry else: # 270° CCW (= 90° CW): inverse is x = ry, y = H-1-rx x_out, y_out = ry, img_h - 1 - rx result = np.stack([x_out, y_out], axis=1).tolist() return result