Source code for swmmio.graphics.utils

# UTILITY/HELPER FUNCTIONS FOR DRAWING
import pandas as pd
import math
import os
from PIL import Image


[docs]def save_image(img, img_path, antialias=True, auto_open=False): # get the size from the Image object imgSize = (img.getbbox()[2], img.getbbox()[3]) if antialias: size = (int(imgSize[0] * 0.5), int(imgSize[1] * 0.5)) img.thumbnail(size, Image.LANCZOS) img.save(img_path) if auto_open: os.startfile(img_path)
[docs]def px_to_irl_coords(df, px_width=4096.0, bbox=None, shift_ratio=None): """ given a dataframe with element id (as index) and X1, Y1 columns (and optionally X2, Y2 columns), return a dataframe with the coords as pixel locations based on the targetImgW. """ df = df.loc[pd.notnull(df.coords)] if not bbox: xs = [xy[0] for verts in df.coords.tolist() for xy in verts] ys = [xy[1] for verts in df.coords.tolist() for xy in verts] xmin, ymin, xmax, ymax = (min(xs), min(ys), max(xs), max(ys)) bbox = [(xmin, ymin), (xmax, ymax)] else: df = clip_to_box(df, bbox) # clip if necessary xmin = float(bbox[0][0]) ymin = float(bbox[0][1]) # find the actual dimensions, use to find scale factor height = bbox[1][1] - bbox[0][1] width = bbox[1][0] - bbox[0][0] if not shift_ratio: # to scale down from coordinate to pixels shift_ratio = float(px_width / width) def shft_coords(row): # parse through coords (nodes, or link) and adjust for pixel space return [(int((xy[0] - xmin) * shift_ratio), int((height - xy[1] + ymin) * shift_ratio)) for xy in row.coords] # insert new column with the shifted coordinates draw_coords = df.apply(lambda row: shft_coords(row), axis=1) if not (draw_coords.empty and df.empty): df = df.assign(draw_coords=draw_coords) return df, bbox, int(height * shift_ratio), int(width * shift_ratio), shift_ratio
[docs]def circle_bbox(coordinates, radius=5): """the bounding box of a circle given as centriod coordinate and radius""" x = coordinates[0] y = coordinates[1] r = radius return (x - r, y - r, x + r, y + r)
[docs]def clip_to_box(df, bbox): """clip a dataframe with a coords column to a bounding box""" def any_xy_in_box(row, bbox): # because im confused with list comprehensions rn return any([point_in_box(bbox, pt) for pt in row]) coords = df.coords.tolist() result = [any_xy_in_box(p, bbox) for p in coords] return df.loc[result]
[docs]def angle_bw_points(xy1, xy2): dx, dy = (xy2[0] - xy1[0]), (xy2[1] - xy1[1]) angle = (math.atan(float(dx) / float(dy)) * 180 / math.pi) if angle < 0: angle = 270 - angle else: angle = 90 - angle # angle in radians return angle
[docs]def midpoint(xy1, xy2): dx, dy = (xy2[0] + xy1[0]), (xy2[1] + xy1[1]) midpt = (int(dx / 2), int(dy / 2.0)) # angle in radians return midpt
[docs]def point_in_box(bbox, point): """check if a point falls with in a bounding box, bbox""" LB = bbox[0] RU = bbox[1] x = point[0] y = point[1] if x < LB[0] or x > RU[0]: return False elif y < LB[1] or y > RU[1]: return False else: return True
[docs]def length_bw_coords(upstreamXY, downstreamXY): # return the distance (units based on input) between two points x1 = float(upstreamXY[0]) x2 = float(downstreamXY[0]) y1 = float(upstreamXY[1]) y2 = float(downstreamXY[1]) return math.hypot(x2 - x1, y2 - y1)
[docs]def rotate_coord_about_point(xy, radians, origin=(0, 0)): """Rotate a point around a given origin https://gist.github.com/LyleScott/e36e08bfb23b1f87af68c9051f985302 """ x, y = xy offset_x, offset_y = origin adjusted_x = (x - offset_x) adjusted_y = (y - offset_y) cos_rad = math.cos(radians) sin_rad = math.sin(radians) qx = offset_x + cos_rad * adjusted_x + sin_rad * adjusted_y qy = offset_y + -sin_rad * adjusted_x + cos_rad * adjusted_y return qx, qy