Source code for wntr.morph.node

"""
The wntr.morph.node module contains functions to modify node coordinates.
"""
import logging
import copy
import numpy as np
from scipy.spatial.distance import pdist
try:
    import utm
except:
    utm = None

logger = logging.getLogger(__name__)


[docs] def scale_node_coordinates(wn, scale, return_copy=True): """ Scales node coordinates, using 1:scale Parameters ----------- wn: wntr WaterNetworkModel Water network model scale: float Coordinate scale multiplier, in meters return_copy: bool, optional If True, modify and return a copy of the WaterNetworkModel object. If False, modify and return the original WaterNetworkModel object. Returns -------- wntr WaterNetworkModel Water network model with updated node coordinates """ if return_copy: # Get a copy of the WaterNetworkModel wn2 = copy.deepcopy(wn) else: wn2 = wn for name, node in wn2.nodes(): pos = node.coordinates node.coordinates = (pos[0]*scale, pos[1]*scale) for name, link in wn2.links(): if link.vertices: for k in range(len(link.vertices)): vertex = link.vertices[k] link.vertices[k] = (vertex[0]*scale, vertex[1]*scale) return wn2
[docs] def translate_node_coordinates(wn, offset_x, offset_y, return_copy=True): """ Translate node coordinates Parameters ----------- wn: wntr WaterNetworkModel Water network model offset_x: tuple Translation in the x direction, in meters offset_y: float Translation in the y direction, in meters return_copy: bool, optional If True, modify and return a copy of the WaterNetworkModel object. If False, modify and return the original WaterNetworkModel object. Returns -------- wntr WaterNetworkModel Water network model with updated node coordinates """ if return_copy: # Get a copy of the WaterNetworkModel wn2 = copy.deepcopy(wn) else: wn2 = wn for name, node in wn2.nodes(): pos = node.coordinates node.coordinates = (pos[0]+offset_x, pos[1]+offset_y) for name, link in wn2.links(): if link.vertices: for k in range(len(link.vertices)): vertex = link.vertices[k] link.vertices[k] = (vertex[0]+offset_x, vertex[1]+offset_y) return wn2
[docs] def rotate_node_coordinates(wn, theta, return_copy=True): """ Rotate node coordinates counter-clockwise by theta degrees Parameters ----------- wn: wntr WaterNetworkModel Water network model theta: float Node rotation, in degrees return_copy: bool, optional If True, modify and return a copy of the WaterNetworkModel object. If False, modify and return the original WaterNetworkModel object. Returns -------- wntr WaterNetworkModel Water network model with updated node coordinates """ if return_copy: # Get a copy of the WaterNetworkModel wn2 = copy.deepcopy(wn) else: wn2 = wn theta = np.radians(theta) R = np.array([[np.cos(theta),-np.sin(theta)], [np.sin(theta), np.cos(theta)]]) for name, node in wn2.nodes(): pos = node.coordinates node.coordinates = tuple(np.dot(R,pos)) for name, link in wn2.links(): if link.vertices: for k in range(len(link.vertices)): link.vertices[k] = tuple(np.dot(R,link.vertices[k])) return wn2
[docs] def convert_node_coordinates_UTM_to_longlat(wn, zone_number, zone_letter, return_copy=True): """ Convert node coordinates from UTM coordinates to longitude, latitude coordinates Parameters ----------- wn: wntr WaterNetworkModel Water network model zone_number: int Zone number zone_letter: string Zone letter return_copy: bool, optional If True, modify and return a copy of the WaterNetworkModel object. If False, modify and return the original WaterNetworkModel object. Returns -------- wntr WaterNetworkModel Water network model with updated node coordinates (longitude, latitude) """ if utm is None: raise ImportError('utm package is required') if return_copy: # Get a copy of the WaterNetworkModel wn2 = copy.deepcopy(wn) else: wn2 = wn for name, node in wn2.nodes(): pos = node.coordinates lat, long = utm.to_latlon(pos[0], pos[1], zone_number, zone_letter) node.coordinates = (long, lat) for name, link in wn2.links(): if link.vertices: for k in range(len(link.vertices)): vertex = link.vertices[k] lat, long = utm.to_latlon(vertex[0], vertex[1], zone_number, zone_letter) link.vertices[k] = (long, lat) return wn2
[docs] def convert_node_coordinates_longlat_to_UTM(wn, return_copy=True): """ Convert node longitude, latitude coordinates to UTM coordinates Parameters ----------- wn: wntr WaterNetworkModel Water network model return_copy: bool, optional If True, modify and return a copy of the WaterNetworkModel object. If False, modify and return the original WaterNetworkModel object. Returns -------- wntr WaterNetworkModel Water network model with updated node coordinates (easting, northing) """ if utm is None: raise ImportError('utm package is required') if return_copy: # Get a copy of the WaterNetworkModel wn2 = copy.deepcopy(wn) else: wn2 = wn for name, node in wn2.nodes(): pos = node.coordinates longitude = pos[0] latitude = pos[1] utm_coords = utm.from_latlon(latitude, longitude) easting = utm_coords[0] northing = utm_coords[1] node.coordinates = (easting, northing) for name, link in wn2.links(): if link.vertices: for k in range(len(link.vertices)): vertex = link.vertices[k] longitude = vertex[0] latitude = vertex[1] utm_coords = utm.from_latlon(latitude, longitude) easting = utm_coords[0] northing = utm_coords[1] link.vertices[k] = (easting, northing) return wn2
[docs] def convert_node_coordinates_to_UTM(wn, utm_map, return_copy=True): """ Convert node coordinates to UTM coordinates Parameters ----------- wn: wntr WaterNetworkModel Water network model utm_map: dictionary Dictionary containing two node names and their x, y coordinates in UTM easting, northing in the format {'node name 1': (easting, northing), 'node name 2': (easting, northing)} return_copy: bool, optional If True, modify and return a copy of the WaterNetworkModel object. If False, modify and return the original WaterNetworkModel object. Returns -------- wntr WaterNetworkModel Water network model with updated node coordinates (easting, northing) """ wn2 = _convert_with_map(wn, utm_map, 'UTM', return_copy) return wn2
[docs] def convert_node_coordinates_to_longlat(wn, longlat_map, return_copy=True): """ Convert node coordinates to longitude, latitude coordinates Parameters ----------- wn: wntr WaterNetworkModel Water network model longlat_map: dictionary Dictionary containing two node names and their x, y coordinates in longitude, latitude in the format {'node name 1': (longitude, latitude), 'node name 2': (longitude, latitude)} return_copy: bool, optional If True, modify and return a copy of the WaterNetworkModel object. If False, modify and return the original WaterNetworkModel object. Returns -------- wntr WaterNetworkModel Water network model with updated node coordinates (longitude, latitude) """ wn2 = _convert_with_map(wn, longlat_map, 'LONGLAT', return_copy) return wn2
def _convert_with_map(wn, node_map, flag, return_copy): if utm is None: raise ImportError('utm package is required') if not len(node_map.keys()) == 2: raise Exception('map must have exactly 2 entries') if return_copy: # Get a copy of the WaterNetworkModel wn2 = copy.deepcopy(wn) else: wn2 = wn node_names = list(node_map.keys()) A = [] B = [] for node_name, coords in node_map.items(): A.append(np.array(wn2.get_node(node_name).coordinates)) if flag == 'LONGLAT': longitude = coords[0] latitude = coords[1] utm_coords = utm.from_latlon(latitude, longitude) zone_number = utm_coords[2] zone_letter = utm_coords[3] B.append(np.array(utm_coords[0:2])) # B is in UTM coords elif flag == 'UTM': easting = coords[0] northing = coords[1] B.append(np.array(easting, northing)) # B is in UTM coords # Rotate, if needed vect1 = A[1] - A[0] vect2 = B[1] - B[0] vect1_unit = vect1/np.linalg.norm(vect1) vect2_unit = vect2/np.linalg.norm(vect2) dotproduct = np.dot(vect1_unit, vect2_unit) if dotproduct < 1: sign = np.sign(np.cross(vect1_unit, vect2_unit)) angle = np.arccos(dotproduct)*180/np.pi wn2 = rotate_node_coordinates(wn2, sign*angle) A[0] = np.array(wn2.get_node(node_names[0]).coordinates) A[1] = np.array(wn2.get_node(node_names[1]).coordinates) # Compute center points cpA = np.mean(A, axis=0) cpB = np.mean(B, axis=0) # Compute distance to each center point distA = np.mean([pdist([A[0], cpA])[0], pdist([A[1], cpA])[0]]) distB = np.mean([pdist([B[0], cpB])[0], pdist([B[1], cpB])[0]]) # Compute ratio ratio = distB/distA for name, node in wn2.nodes(): pos = node.coordinates (easting, northing) = (np.array(pos) - cpA)*ratio + cpB if flag == 'LONGLAT': lat, long = utm.to_latlon(easting, northing, zone_number, zone_letter) node.coordinates = (long, lat) elif flag == 'UTM': node.coordinates = (easting, northing) for name, link in wn2.links(): if link.vertices: for k in range(len(link.vertices)): pos = link.vertices[k] (easting, northing) = (np.array(pos) - cpA)*ratio + cpB if flag == 'LONGLAT': lat, long = utm.to_latlon(easting, northing, zone_number, zone_letter) link.vertices[k] = (long, lat) elif flag == 'UTM': node.coordinates = (easting, northing) return wn2