diff --git a/examples/Simple_Realistic_Railway_Generator.py b/examples/Simple_Realistic_Railway_Generator.py index 3956a8681ad32c91d3e5deaf8afba2e809ca7115..df0b88cb68060816410321d70dd2d6a2222621b1 100644 --- a/examples/Simple_Realistic_Railway_Generator.py +++ b/examples/Simple_Realistic_Railway_Generator.py @@ -6,6 +6,7 @@ import warnings import numpy as np from flatland.core.grid.grid4_utils import mirror +from flatland.core.grid.grid_utils import Vec2dOperations as vec2d from flatland.core.grid.rail_env_grid import RailEnvTransitions from flatland.core.transition_map import GridTransitionMap from flatland.envs.grid4_generators_utils import connect_from_nodes, connect_nodes, connect_rail @@ -13,133 +14,7 @@ from flatland.envs.observations import GlobalObsForRailEnv from flatland.envs.rail_env import RailEnv from flatland.envs.rail_generators import RailGenerator, RailGeneratorProduct from flatland.envs.schedule_generators import sparse_schedule_generator -from flatland.utils.rendertools import RenderTool,AgentRenderVariant - - -class Vec2dOperations: - def subtract_pos(nodeA, nodeB): - """ - vector operation : nodeA - nodeB - - :param nodeA: tuple with coordinate (x,y) or 2d vector - :param nodeB: tuple with coordinate (x,y) or 2d vector - :return: - ------- - tuple with coordinate (x,y) or 2d vector - """ - return (nodeA[0] - nodeB[0], nodeA[1] - nodeB[1]) - - def add_pos(nodeA, nodeB): - """ - vector operation : nodeA + nodeB - - :param nodeA: tuple with coordinate (x,y) or 2d vector - :param nodeB: tuple with coordinate (x,y) or 2d vector - :return: - ------- - tuple with coordinate (x,y) or 2d vector - """ - return (nodeA[0] + nodeB[0], nodeA[1] + nodeB[1]) - - def make_orthogonal_pos(node): - """ - 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]) - - def get_norm_pos(node): - """ - calculates the euclidean norm of the 2d vector - - :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]) - - def normalize_pos(node): - """ - 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_pos(node) - if n > 0.0: - n = 1 / n - return Vec2dOperations.scale_pos(node, n) - - def scale_pos(node, scalar): - """ - 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] * scalar, node[1] * scalar) - - def round_pos(node): - """ - 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]))) - - def ceil_pos(node): - """ - 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]))) - - def bound_pos(node, min_value, max_value): - """ - 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]))) - - def rotate_pos(node, rot_in_degree): - """ - 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) +from flatland.utils.rendertools import RenderTool, AgentRenderVariant class GripMapOp: @@ -245,12 +120,12 @@ def realistic_rail_generator(num_cities=5, for i in range(len(generate_city_locations)): # station main orientation (horizontal or vertical rot_angle = np.random.choice(allowed_rotation_angles) - add_pos_val = Vec2dOperations.scale_pos(Vec2dOperations.rotate_pos((1, 0), rot_angle), + add_pos_val = vec2d.scale_pos(vec2d.rotate_pos((1, 0), rot_angle), (max(1, (intern_city_size - 3) / 2))) - generate_city_locations[i][0] = Vec2dOperations.add_pos(generate_city_locations[i][1], add_pos_val) - add_pos_val = Vec2dOperations.scale_pos(Vec2dOperations.rotate_pos((1, 0), 180 + rot_angle), + generate_city_locations[i][0] = vec2d.add_pos(generate_city_locations[i][1], add_pos_val) + add_pos_val = vec2d.scale_pos(vec2d.rotate_pos((1, 0), 180 + rot_angle), (max(1, (intern_city_size - 3) / 2))) - generate_city_locations[i][1] = Vec2dOperations.add_pos(generate_city_locations[i][1], add_pos_val) + generate_city_locations[i][1] = vec2d.add_pos(generate_city_locations[i][1], add_pos_val) return generate_city_locations def create_stations_from_city_locations(rail_trans, rail_array, generate_city_locations, @@ -271,13 +146,13 @@ def realistic_rail_generator(num_cities=5, org_start_node = generate_city_locations[city_loop][0] org_end_node = generate_city_locations[city_loop][1] - ortho_trans = Vec2dOperations.make_orthogonal_pos( - Vec2dOperations.normalize_pos(Vec2dOperations.subtract_pos(org_start_node, org_end_node))) + ortho_trans = vec2d.make_orthogonal_pos( + vec2d.normalize_pos(vec2d.subtract_pos(org_start_node, org_end_node))) s = (ct - number_of_connecting_tracks / 2.0) - start_node = Vec2dOperations.ceil_pos( - Vec2dOperations.add_pos(org_start_node, Vec2dOperations.scale_pos(ortho_trans, s))) - end_node = Vec2dOperations.ceil_pos( - Vec2dOperations.add_pos(org_end_node, Vec2dOperations.scale_pos(ortho_trans, s))) + start_node = vec2d.ceil_pos( + vec2d.add_pos(org_start_node, vec2d.scale_pos(ortho_trans, s))) + end_node = vec2d.ceil_pos( + vec2d.add_pos(org_end_node, vec2d.scale_pos(ortho_trans, s))) connection = connect_from_nodes(rail_trans, rail_array, start_node, end_node) if len(connection) > 0: @@ -385,7 +260,7 @@ def realistic_rail_generator(num_cities=5, continue ens = e_nodes[city_loop_find_shortest] for en in ens: - d = Vec2dOperations.get_norm_pos(Vec2dOperations.subtract_pos(en, start_node)) + d = vec2d.get_norm_pos(vec2d.subtract_pos(en, start_node)) if d < min_distance: min_distance = d end_node = en @@ -513,8 +388,9 @@ def realistic_rail_generator(num_cities=5, generate_city_locations, intern_max_number_of_station_tracks) # build switches - create_switches_at_stations(width, height, grid_map, station_tracks, nodes_added, - intern_nbr_of_switches_per_station_track) + if True: + create_switches_at_stations(width, height, grid_map, station_tracks, nodes_added, + intern_nbr_of_switches_per_station_track) # ---------------------------------------------------------------------------------- # connect stations @@ -578,7 +454,7 @@ def realistic_rail_generator(num_cities=5, for itrials in range(1000): print(itrials, "generate new city") - np.random.seed(int(time.time())) + np.random.seed(0*int(time.time())) env = RailEnv(width=40 + np.random.choice(100), height=40 + np.random.choice(100), rail_generator=realistic_rail_generator(num_cities=2 + np.random.choice(10), @@ -593,7 +469,7 @@ for itrials in range(1000): print_out_info=False ), schedule_generator=sparse_schedule_generator(), - number_of_agents=1+np.random.choice(10), + number_of_agents=1 + np.random.choice(10), obs_builder_object=GlobalObsForRailEnv()) # reset to initialize agents_static @@ -610,4 +486,5 @@ for itrials in range(1000): "flatland_frame_{:04d}_{:04d}.png".format(itrials, 0) )) + input() env_renderer.close_window() diff --git a/flatland/core/grid/grid_utils.py b/flatland/core/grid/grid_utils.py index f51d285947ae175692ca70e1f03d08b8a22a5a22..b7bf988fb754b30d4784e0feef36176fa5aa28df 100644 --- a/flatland/core/grid/grid_utils.py +++ b/flatland/core/grid/grid_utils.py @@ -1,5 +1,147 @@ +from typing import Tuple + import numpy as np +Vector2D = Tuple[float, float] +IntVector2D = Tuple[int, int] + + +class Vec2dOperations: + + @staticmethod + def subtract_pos(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] + + @staticmethod + def add_pos(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] + + @staticmethod + def make_orthogonal_pos(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] + + @staticmethod + def get_norm_pos(node: Vector2D) -> float: + """ + calculates the euclidean norm of the 2d vector + + :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]) + + @staticmethod + def normalize_pos(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_pos(node) + if n > 0.0: + n = 1 / n + return Vec2dOperations.scale_pos(node, n) + + @staticmethod + def scale_pos(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 + + @staticmethod + def round_pos(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])) + + @staticmethod + def ceil_pos(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])) + + @staticmethod + def bound_pos(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])) + + @staticmethod + def rotate_pos(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 + def position_to_coordinate(depth, positions): """Converts coordinates to positions: