예제 #1
0
        def to_scenario_via(
            vias: Tuple[SSVia, ...], sumo_road_network: SumoRoadNetwork
        ) -> Tuple[Via, ...]:
            s_vias = []
            for via in vias:
                lane = sumo_road_network.lane_by_index_on_edge(
                    via.edge_id, via.lane_index
                )
                hit_distance = (
                    via.hit_distance if via.hit_distance > 0 else lane.getWidth() / 2
                )
                via_position = sumo_road_network.world_coord_from_offset(
                    lane,
                    via.lane_offset,
                )

                s_vias.append(
                    Via(
                        lane_id=lane.getID(),
                        lane_index=via.lane_index,
                        edge_id=via.edge_id,
                        position=tuple(via_position),
                        hit_distance=hit_distance,
                        required_speed=via.required_speed,
                    )
                )

            return tuple(s_vias)
예제 #2
0
파일: studio.py 프로젝트: qyshen815/SMARTS
def _build_single_scenario(clean, allow_offset_map, scenario):
    import importlib.resources as pkg_resources

    from smarts.sstudio.sumo2mesh import generate_glb_from_sumo_network

    click.echo(f"build-scenario {scenario}")
    if clean:
        _clean(scenario)

    scenario_root = Path(scenario)
    map_net = str(scenario_root / "map.net.xml")
    if not allow_offset_map:
        SumoRoadNetwork.from_file(map_net, shift_to_origin=True)
    elif os.path.isfile(SumoRoadNetwork.shifted_net_file_path(map_net)):
        click.echo(
            "WARNING: {} already exists.  Remove it if you want to use unshifted/offset map.net.xml instead."
            .format(SumoRoadNetwork.shifted_net_file_name))
    map_glb = scenario_root / "map.glb"
    generate_glb_from_sumo_network(map_net, str(map_glb))

    requirements_txt = scenario_root / "requirements.txt"
    if requirements_txt.exists():
        import zoo.policies

        with pkg_resources.path(zoo.policies, "") as path:
            # Serve policies through the static file server, then kill after
            # we've installed scenario requirements
            pip_index_proc = subprocess.Popen(
                ["twistd", "-n", "web", "--path", path],
                # Hide output to keep display simple
                stdout=subprocess.DEVNULL,
                stderr=subprocess.STDOUT,
            )

            pip_install_cmd = [
                sys.executable,
                "-m",
                "pip",
                "install",
                "-r",
                str(requirements_txt),
            ]

            click.echo(
                f"Installing scenario dependencies via '{' '.join(pip_install_cmd)}'"
            )

            try:
                subprocess.check_call(pip_install_cmd,
                                      stdout=subprocess.DEVNULL)
            finally:
                pip_index_proc.terminate()
                pip_index_proc.wait()

    scenario_py = scenario_root / "scenario.py"
    if scenario_py.exists():
        subprocess.check_call([sys.executable, scenario_py])
예제 #3
0
    def to_geometry(self, road_network: SumoRoadNetwork) -> Polygon:
        def resolve_offset(offset, geometry_length, lane_length,
                           buffer_from_ends):
            if offset == "base" or offset == 0:
                return buffer_from_ends
            # push off of end of lane
            elif offset == "max":
                return lane_length - geometry_length - buffer_from_ends
            elif offset == "random":
                return random.uniform(
                    0, lane_length - geometry_length - buffer_from_ends)
            else:
                return float(offset)

        lane_shapes = []
        edge_id, lane_idx, offset = self.start
        edge = road_network.edge_by_id(edge_id)
        for lane_idx in range(lane_idx, lane_idx + self.n_lanes):
            lane = edge.getLanes()[lane_idx]
            lane_length = lane.getLength()
            geom_length = max(self.length - 1e-6, 1e-6)

            assert lane_length > geom_length  # Geom is too long for lane
            assert geom_length > 0  # Geom length is negative

            lane_shape = SumoRoadNetwork.buffered_lane_or_edge(
                lane, width=lane.getWidth() + 0.3)

            min_cut = resolve_offset(offset, geom_length, lane_length, 1e-6)
            # Second cut takes into account shortening of geometry by `min_cut`.
            max_cut = min(min_cut + geom_length, lane_length - min_cut - 1e-6)

            lane_shape = road_network.split_lane_shape_at_offset(
                Polygon(lane_shape), lane, min_cut)

            if isinstance(lane_shape, GeometryCollection):
                if len(lane_shape) < 2:
                    break
                lane_shape = lane_shape[1]

            lane_shape = road_network.split_lane_shape_at_offset(
                lane_shape,
                lane,
                max_cut,
            )[0]
            lane_shapes.append(lane_shape)

        geom = unary_union(MultiPolygon(lane_shapes))
        return geom
예제 #4
0
파일: types.py 프로젝트: huzhejie/SMARTS
 def to_edge(self, sumo_road_network: SumoRoadNetwork):
     return sumo_road_network.get_edge_in_junction(
         self.start_edge_id,
         self.start_lane_index,
         self.end_edge_id,
         self.end_lane_index,
     )
예제 #5
0
    def __init__(
        self,
        scenario_root: str,
        route: str = None,
        missions: Dict[str, Mission] = None,
        social_agents: Dict[str, SocialAgent] = None,
        log_dir: str = None,
        surface_patches: list = None,
        traffic_history: str = None,
    ):

        self._logger = logging.getLogger(self.__class__.__name__)
        self._root = scenario_root
        self._route = route
        self._missions = missions or {}
        self._bubbles = Scenario._discover_bubbles(scenario_root)
        self._social_agents = social_agents or {}
        self._surface_patches = surface_patches
        self._log_dir = self._resolve_log_dir(log_dir)
        self._validate_assets_exist()

        if traffic_history:
            self._traffic_history = TrafficHistory(traffic_history)
            default_lane_width = self.traffic_history.lane_width
        else:
            self._traffic_history = None
            default_lane_width = None

        net_file = os.path.join(self._root, "map.net.xml")
        self._road_network = SumoRoadNetwork.from_file(
            net_file, default_lane_width=default_lane_width, lanepoint_spacing=1.0
        )
        self._net_file_hash = file_md5_hash(self._road_network.net_file)
        self._scenario_hash = path2hash(str(Path(self.root_filepath).resolve()))
예제 #6
0
 def _compute_geometry(self):
     return [
         SumoRoadNetwork.buffered_lane_or_edge(
             edge, width=sum([lane.getWidth() for lane in edge.getLanes()])
         )
         for edge in self.edges
     ]
예제 #7
0
파일: scenario.py 프로젝트: zbzhu99/SMARTS
    def __init__(
        self,
        scenario_root: str,
        route: str = None,
        missions: Dict[str, Mission] = None,
        social_agents: Dict[str, SocialAgent] = None,
        log_dir: str = None,
        surface_patches: list = None,
        traffic_history: str = None,
    ):

        self._logger = logging.getLogger(self.__class__.__name__)
        self._root = scenario_root
        self._route = route
        self._missions = missions or {}
        self._bubbles = Scenario._discover_bubbles(scenario_root)
        self._social_agents = social_agents or {}
        self._surface_patches = surface_patches
        self._log_dir = self._resolve_log_dir(log_dir)

        self._validate_assets_exist()
        self._road_network = SumoRoadNetwork.from_file(self.net_filepath)
        self._net_file_hash = file_md5_hash(self.net_filepath)
        self._waypoints = Waypoints(self._road_network, spacing=1.0)
        self._scenario_hash = path2hash(str(
            Path(self.root_filepath).resolve()))
        self._traffic_history_service = Traffic_history_service(
            traffic_history)
예제 #8
0
    def from_file(cls, net_file: str):
        """Constructs a route generator from the given file

        Args:
            net_file: The path to a '\\*.net.xml' file (generally 'map.net.xml')
        """
        # XXX: Spacing is crudely "large enough" so we less likely overlap vehicles
        road_network = SumoRoadNetwork.from_file(net_file, lanepoint_spacing=2.0)
        return cls(road_network)
예제 #9
0
 def map_bounding_box(self):
     # This function returns the following tuple:
     # (bbox length, bbox width, bbox center)
     net_file = os.path.join(self._root, "map.net.xml")
     road_network = SumoRoadNetwork.from_file(net_file)
     # 2D bbox in format (xmin, ymin, xmax, ymax)
     bounding_box = road_network.graph.getBoundary()
     bounding_box_length = bounding_box[2] - bounding_box[0]
     bounding_box_width = bounding_box[3] - bounding_box[1]
     bounding_box_center = [
         (bounding_box[0] + bounding_box[2]) / 2,
         (bounding_box[1] + bounding_box[3]) / 2,
         0,
     ]
     return (bounding_box_length, bounding_box_width, bounding_box_center)
예제 #10
0
파일: scenario.py 프로젝트: zbzhu99/SMARTS
    def discover_agent_missions(scenario_root, agents_to_be_briefed):
        """Returns a sequence of {agent_id: mission} mappings.

        If no missions are discovered we generate random ones. If there is only one
        agent to be briefed we return a list of `{agent_id: mission}` cycling through
        each mission. If there are multiple agents to be briefed we assume that each
        one is intended to get its own mission and that `len(agents_to_be_briefed) ==
        len(missions)`. In this case a list of one dictionary is returned.
        """

        net_file = os.path.join(scenario_root, "map.net.xml")
        road_network = SumoRoadNetwork.from_file(net_file)

        missions = []
        missions_file = os.path.join(scenario_root, "missions.pkl")
        if os.path.exists(missions_file):
            with open(missions_file, "rb") as f:
                missions = pickle.load(f)

            missions = [
                Scenario._extract_mission(actor_and_mission.mission,
                                          road_network)
                for actor_and_mission in missions
            ]

        if not missions:
            missions = [None for _ in range(len(agents_to_be_briefed))]

        if len(agents_to_be_briefed) == 1:
            # single-agent, so we cycle through all missions individually.
            return missions
        elif len(agents_to_be_briefed) > 1:
            # multi-agent, so we assume missions "drive" the agents (i.e. one
            # mission per agent) and we will not be cycling through missions.
            assert not missions or len(missions) == len(agents_to_be_briefed), (
                "You must either provide an equal number of missions ({}) to "
                "agents ({}) or provide no missions at all so they can be "
                "randomly generated.".format(len(missions),
                                             len(agents_to_be_briefed)))

        return missions
예제 #11
0
    def is_valid_scenario(scenario_root):
        """Checks if the scenario_root directory matches our expected scenario structure

        >>> Scenario.is_valid_scenario("scenarios/loop")
        True
        >>> Scenario.is_valid_scenario("scenarios/non_existant")
        False
        """
        paths = [
            os.path.join(scenario_root, "map.net.xml"),
        ]

        for f in paths:
            if not os.path.exists(f):
                return False

        # make sure we can load the sumo network
        net_file = os.path.join(scenario_root, "map.net.xml")
        net = SumoRoadNetwork.from_file(net_file)
        if net is None:
            return False

        return True
예제 #12
0
    def to_geometry(self, road_network: SumoRoadNetwork) -> Polygon:
        def resolve_offset(offset, geometry_length, lane_length):
            if offset == "base":
                return 0
            # push off of end of lane
            elif offset == "max":
                return lane_length - geometry_length
            elif offset == "random":
                return random.uniform(0, lane_length - geometry_length)
            else:
                return float(offset)

        def pick_remaining_shape_after_split(geometry_collection, length, lane):
            lane_shape = geometry_collection
            if not isinstance(lane_shape, GeometryCollection):
                return lane_shape

            # For simplicty, we only deal w/ the == 1 or 2 case
            if len(lane_shape) not in {1, 2}:
                return None

            if len(lane_shape) == 1:
                return lane_shape[0]

            expected_bbox_area = lane.getWidth() * length
            keep_index = 0
            if (lane_shape[0].minimum_rotated_rectangle.area - expected_bbox_area) < (
                lane_shape[1].minimum_rotated_rectangle.area - expected_bbox_area
            ):
                # 0 is the discard piece, keep the other
                keep_index = 1
            lane_shape = lane_shape[keep_index]

            return lane_shape

        lane_shapes = []
        edge_id, lane_idx, offset = self.start
        edge = road_network.edge_by_id(edge_id)
        buffer_from_ends = 1e-6
        for lane_idx in range(lane_idx, lane_idx + self.n_lanes):
            lane = edge.getLanes()[lane_idx]
            lane_length = lane.getLength()
            geom_length = self.length

            if geom_length > lane_length:
                logging.debug(
                    f"Geometry is too long={geom_length} with offset={offset} for "
                    f"lane={lane.getID()}, using length={lane_length} instead"
                )
                geom_length = lane_length

            assert geom_length > 0  # Geom length is negative

            lane_shape = SumoRoadNetwork._buffered_lane_or_edge(
                lane, width=lane.getWidth() + 0.3
            )

            lane_offset = resolve_offset(offset, geom_length, lane_length)
            lane_offset += buffer_from_ends
            geom_length = max(geom_length - buffer_from_ends, buffer_from_ends)
            lane_length = max(lane_length - buffer_from_ends, buffer_from_ends)

            min_cut = min(lane_offset, lane_length)
            # Second cut takes into account shortening of geometry by `min_cut`.
            max_cut = min(min_cut + geom_length, lane_length - min_cut)

            lane_shape = road_network.split_lane_shape_at_offset(
                lane_shape, lane, min_cut
            )
            lane_shape = pick_remaining_shape_after_split(lane_shape, min_cut, lane)
            if lane_shape is None:
                continue

            lane_shape = road_network.split_lane_shape_at_offset(
                lane_shape, lane, max_cut,
            )
            lane_shape = pick_remaining_shape_after_split(lane_shape, max_cut, lane)
            if lane_shape is None:
                continue

            lane_shapes.append(lane_shape)

        geom = unary_union(MultiPolygon(lane_shapes))
        return geom
예제 #13
0
def road_network():
    return SumoRoadNetwork.from_file(
        "scenarios/intersections/4lane_t/map.net.xml")
예제 #14
0
 def _cache_road_network(self):
     if not self._road_network:
         self._road_network = SumoRoadNetwork.from_file(self._road_network_path)
예제 #15
0
def generate_glb_from_sumo_file(sumo_net_file: str, out_glb_file: str):
    """Creates a geometry file from a sumo map file."""
    map_spec = MapSpec(sumo_net_file)
    road_network = SumoRoadNetwork.from_spec(map_spec)
    road_network.to_glb(out_glb_file)
예제 #16
0
    def _discover_social_agents_info(
        scenario,
    ) -> Sequence[Dict[str, SocialAgent]]:
        """Loops through the social agent mission pickles, instantiating corresponding
        implementations for the given types. The output is a list of
        {agent_id: (mission, locator)}, where each dictionary corresponds to the
        social agents to run for a given concrete Scenario (which translates to
        "per episode" when swapping).
        """
        scenario_root = (
            scenario.root_filepath if isinstance(scenario, Scenario) else scenario
        )
        net_file = os.path.join(scenario_root, "map.net.xml")
        road_network = SumoRoadNetwork.from_file(net_file)

        social_agents_path = os.path.join(scenario_root, "social_agents")
        if not os.path.exists(social_agents_path):
            return []

        # [ ( missions_file, agent_actor, Mission ) ]
        agent_bucketer = []

        # like dict.setdefault
        def setdefault(l: Sequence[Any], index: int, default):
            while len(l) < index + 1:
                l.append([])
            return l[index]

        file_match = os.path.join(social_agents_path, "*.pkl")
        for missions_file_path in glob.glob(file_match):
            with open(missions_file_path, "rb") as missions_file:
                count = 0
                missions = pickle.load(missions_file)

            for mission_and_actor in missions:
                # Each pickle file will contain a list of actor/mission pairs. The pairs
                # will most likely be generated in an M:N fashion
                # (i.e. A1: M1, A1: M2, A2: M1, A2: M2). The desired behavior is to have
                # a single pair per concrete Scenario (which would translate to
                # "per episode" when swapping)
                assert isinstance(
                    mission_and_actor.actor, sstudio_types.SocialAgentActor
                )

                actor = mission_and_actor.actor
                extracted_mission = Scenario._extract_mission(
                    mission_and_actor.mission, road_network
                )
                namespace = os.path.basename(missions_file_path)
                namespace = os.path.splitext(namespace)[0]

                setdefault(agent_bucketer, count, []).append(
                    (
                        SocialAgent(
                            id=SocialAgentId.new(actor.name, group=namespace),
                            name=actor.name,
                            is_boid=False,
                            is_boid_keep_alive=False,
                            agent_locator=actor.agent_locator,
                            policy_kwargs=actor.policy_kwargs,
                            initial_speed=actor.initial_speed,
                        ),
                        extracted_mission,
                    )
                )
                count += 1

        social_agents_info = []
        for l in agent_bucketer:
            social_agents_info.append(
                {agent.id: (agent, mission) for agent, mission in l}
            )

        return social_agents_info
예제 #17
0
 def resolve_edge_length(self, edge_id, lane_id):
     if not self._road_network:
         self._road_network = SumoRoadNetwork.from_file(
             self._road_network_path)
     lane = self._road_network.edge_by_id(edge_id).getLanes()[lane_id]
     return lane.getLength()
예제 #18
0
def generate_glb_from_sumo_network(sumo_net_file, out_glb_file):
    road_network = SumoRoadNetwork.from_file(net_file=sumo_net_file)
    glb = road_network.build_glb(scale=1000)
    glb.write_glb(out_glb_file)
예제 #19
0
    def _cache_road_network(self):
        if not self._road_network:
            from smarts.core.sumo_road_network import SumoRoadNetwork

            map_spec = types.MapSpec(self._road_network_path)
            self._road_network = SumoRoadNetwork.from_spec(map_spec)