Source code for flatland.core.grid.grid_utils

from typing import Tuple, Callable, List, Type

import numpy as np

Vector2D: Type = Tuple[float, float]
IntVector2D: Type = Tuple[int, int]

IntVector2DArray: Type = List[IntVector2D]
IntVector2DArrayArray: Type = List[List[IntVector2D]]

Vector2DArray: Type = List[Vector2D]
Vector2DArrayArray: Type = List[List[Vector2D]]

IntVector2DDistance: Type = Callable[[IntVector2D, IntVector2D], float]


[docs]class Vec2dOperations:
[docs] @staticmethod def is_equal(node_a: Vector2D, node_b: Vector2D) -> bool: """ vector operation : node_a + node_b :param node_a: tuple with coordinate (x,y) or 2d vector :param node_b: tuple with coordinate (x,y) or 2d vector :return: check if node_a and nobe_b are equal """ return node_a[0] == node_b[0] and node_a[1] == node_b[1]
[docs] @staticmethod def subtract(node_a: Vector2D, node_b: Vector2D) -> Vector2D: """ vector operation : node_a - node_b :param node_a: tuple with coordinate (x,y) or 2d vector :param node_b: tuple with coordinate (x,y) or 2d vector :return: tuple with coordinate (x,y) or 2d vector """ return node_a[0] - node_b[0], node_a[1] - node_b[1]
[docs] @staticmethod def add(node_a: Vector2D, node_b: Vector2D) -> Vector2D: """ vector operation : node_a + node_b :param node_a: tuple with coordinate (x,y) or 2d vector :param node_b: tuple with coordinate (x,y) or 2d vector :return: tuple with coordinate (x,y) or 2d vector """ return node_a[0] + node_b[0], node_a[1] + node_b[1]
[docs] @staticmethod def make_orthogonal(node: Vector2D) -> Vector2D: """ vector operation : rotates the 2D vector +90° :param node: tuple with coordinate (x,y) or 2d vector :return: tuple with coordinate (x,y) or 2d vector """ return node[1], -node[0]
[docs] @staticmethod def get_norm(node: Vector2D) -> float: """ calculates the euclidean norm of the 2d vector [see: https://lyfat.wordpress.com/2012/05/22/euclidean-vs-chebyshev-vs-manhattan-distance/] :param node: tuple with coordinate (x,y) or 2d vector :return: tuple with coordinate (x,y) or 2d vector """ return np.sqrt(node[0] * node[0] + node[1] * node[1])
[docs] @staticmethod def get_euclidean_distance(node_a: Vector2D, node_b: Vector2D) -> float: """ calculates the euclidean norm of the 2d vector Parameters ---------- node_a tuple with coordinate (x,y) or 2d vector node_b tuple with coordinate (x,y) or 2d vector Returns ------- float Euclidean distance """ return Vec2dOperations.get_norm(Vec2dOperations.subtract(node_b, node_a))
[docs] @staticmethod def get_manhattan_distance(node_a: Vector2D, node_b: Vector2D) -> float: """ calculates the manhattan distance of the 2d vector [see: https://lyfat.wordpress.com/2012/05/22/euclidean-vs-chebyshev-vs-manhattan-distance/] Parameters ---------- node_a tuple with coordinate (x,y) or 2d vector node_b tuple with coordinate (x,y) or 2d vector Returns ------- float Mahnhattan distance """ delta = (Vec2dOperations.subtract(node_b, node_a)) return np.abs(delta[0]) + np.abs(delta[1])
[docs] @staticmethod def get_chebyshev_distance(node_a: Vector2D, node_b: Vector2D) -> float: """ calculates the chebyshev norm of the 2d vector [see: https://lyfat.wordpress.com/2012/05/22/euclidean-vs-chebyshev-vs-manhattan-distance/] Parameters ---------- node_a tuple with coordinate (x,y) or 2d vector node_b tuple with coordinate (x,y) or 2d vector Returns ------- float the chebyshev distance """ delta = (Vec2dOperations.subtract(node_b, node_a)) return max(np.abs(delta[0]), np.abs(delta[1]))
[docs] @staticmethod def normalize(node: Vector2D) -> Tuple[float, float]: """ normalize the 2d vector = `v/|v|` :param node: tuple with coordinate (x,y) or 2d vector :return: tuple with coordinate (x,y) or 2d vector """ n = Vec2dOperations.get_norm(node) if n > 0.0: n = 1 / n return Vec2dOperations.scale(node, n)
[docs] @staticmethod def scale(node: Vector2D, scale: float) -> Vector2D: """ scales the 2d vector = node * scale :param node: tuple with coordinate (x,y) or 2d vector :param scale: scalar to scale :return: tuple with coordinate (x,y) or 2d vector """ return node[0] * scale, node[1] * scale
[docs] @staticmethod def round(node: Vector2D) -> IntVector2D: """ rounds the x and y coordinate and convert them to an integer values :param node: tuple with coordinate (x,y) or 2d vector :return: tuple with coordinate (x,y) or 2d vector """ return int(np.round(node[0])), int(np.round(node[1]))
[docs] @staticmethod def ceil(node: Vector2D) -> IntVector2D: """ ceiling the x and y coordinate and convert them to an integer values :param node: tuple with coordinate (x,y) or 2d vector :return: tuple with coordinate (x,y) or 2d vector """ return int(np.ceil(node[0])), int(np.ceil(node[1]))
[docs] @staticmethod def floor(node: Vector2D) -> IntVector2D: """ floor the x and y coordinate and convert them to an integer values :param node: tuple with coordinate (x,y) or 2d vector :return: tuple with coordinate (x,y) or 2d vector """ return int(np.floor(node[0])), int(np.floor(node[1]))
[docs] @staticmethod def bound(node: Vector2D, min_value: float, max_value: float) -> Vector2D: """ force the values x and y to be between min_value and max_value :param node: tuple with coordinate (x,y) or 2d vector :param min_value: scalar value :param max_value: scalar value :return: tuple with coordinate (x,y) or 2d vector """ return max(min_value, min(max_value, node[0])), max(min_value, min(max_value, node[1]))
[docs] @staticmethod def rotate(node: Vector2D, rot_in_degree: float) -> Vector2D: """ rotate the 2d vector with given angle in degree :param node: tuple with coordinate (x,y) or 2d vector :param rot_in_degree: angle in degree :return: tuple with coordinate (x,y) or 2d vector """ alpha = rot_in_degree / 180.0 * np.pi x0 = node[0] y0 = node[1] x1 = x0 * np.cos(alpha) - y0 * np.sin(alpha) y1 = x0 * np.sin(alpha) + y0 * np.cos(alpha) return x1, y1
[docs]def position_to_coordinate(depth: int, positions: List[int]): """Converts coordinates to positions:: [ (0,0) (0,1) .. (0,w-1) (1,0) (1,1) (1,w-1) ... (d-1,0) (d-1,1) (d-1,w-1) ] --> [ 0 d .. (w-1)*d 1 d+1 ... d-1 2d-1 w*d-1 ] Parameters ---------- depth : int positions : List[Tuple[int,int]] """ coords = () for p in positions: coords = coords + ((int(p) % depth, int(p) // depth),) # changed x_dim to y_dim return coords
[docs]def coordinate_to_position(depth, coords): """ Converts positions to coordinates:: [ 0 d .. (w-1)*d 1 d+1 ... d-1 2d-1 w*d-1 ] --> [ (0,0) (0,1) .. (0,w-1) (1,0) (1,1) (1,w-1) ... (d-1,0) (d-1,1) (d-1,w-1) ] :param depth: :param coords: :return: """ position = np.empty(len(coords), dtype=int) idx = 0 for t in coords: # Set None type coordinates off the grid if np.isnan(t[0]): position[idx] = -1 else: position[idx] = int(t[1] * depth + t[0]) idx += 1 return position
[docs]def distance_on_rail(pos1, pos2, metric="Euclidean"): if metric == "Euclidean": return np.sqrt(np.power(pos1[0] - pos2[0], 2) + np.power(pos1[1] - pos2[1], 2)) if metric == "Manhattan": return np.abs(pos1[0] - pos2[0]) + np.abs(pos1[1] - pos2[1])