Example #1
0
    def _get_oncoming_vehicles(
            self, frame: Dict[int, ip.AgentState],
            scenario_map: ip.Map) -> List[Tuple[ip.AgentState, float]]:
        oncoming_vehicles = []

        ego_junction_lane = scenario_map.get_lane(self.config.junction_road_id,
                                                  self.config.junction_lane_id)
        lanes_to_cross = self._get_lanes_to_cross(scenario_map)

        agent_lanes = [(i,
                        scenario_map.best_lane_at(s.position, s.heading, True))
                       for i, s in frame.items()]

        for lane_to_cross in lanes_to_cross:
            lane_sequence = self._get_predecessor_lane_sequence(lane_to_cross)
            midline = self.get_lane_path_midline(lane_sequence)
            crossing_point = lane_to_cross.boundary.intersection(
                ego_junction_lane.boundary).centroid
            crossing_lon = midline.project(crossing_point)

            # find agents in lane to cross
            for agent_id, agent_lane in agent_lanes:
                agent_state = frame[agent_id]
                if agent_id != self.agent_id and agent_lane in lane_sequence:
                    agent_lon = midline.project(Point(agent_state.position))
                    dist = crossing_lon - agent_lon
                    if 0 < dist < self.MAX_ONCOMING_VEHICLE_DIST:
                        oncoming_vehicles.append((agent_state, dist))
        return oncoming_vehicles
Example #2
0
 def applicable(state: ip.AgentState, scenario_map: ip.Map) -> bool:
     """ True if in non-outer lane of roundabout and not in junction """
     current_lane = scenario_map.best_lane_at(state.position, state.heading)
     all_lane_ids = [lane.id for lane in current_lane.lane_section.all_lanes if lane != current_lane]
     return (scenario_map.in_roundabout(state.position, state.heading) and
             current_lane.parent_road.junction is None and
             not all([np.abs(current_lane.id) > np.abs(lid) for lid in all_lane_ids]) and  # Not in outer lane
             ip.FollowLane.applicable(state, scenario_map))
Example #3
0
    def get_applicable_actions(agent_state: ip.AgentState, scenario_map: ip.Map, goal: ip.Goal = None) \
            -> List[Type['MacroAction']]:
        """ Return all applicable macro actions.

        Args:
            agent_state: Current state of the examined agent
            scenario_map: The road layout of the scenario
            goal: If given and ahead within current lane boundary, then will always return at least a Continue

        Returns:
            A list of applicable macro action types
        """
        actions = []

        current_lane = scenario_map.best_lane_at(agent_state.position, agent_state.heading)
        if goal is not None:
            goal_point = goal.point_on_lane(current_lane)
            if current_lane.boundary.contains(goal_point) and \
                    current_lane.distance_at(agent_state.position) < current_lane.distance_at(goal_point):
                actions = [Continue]

        for macro_action in ip.util.all_subclasses(MacroAction):
            try:
                if macro_action not in actions and macro_action.applicable(agent_state, scenario_map):
                    actions.append(macro_action)
            except NotImplementedError:
                continue
        return actions
Example #4
0
    def _get_lane_sequence(self, state: ip.AgentState,
                           scenario_map: ip.Map) -> List[ip.Lane]:
        lanes = []
        for position, heading in zip(self._trajectory.path,
                                     self._trajectory.heading):
            possible_lanes = scenario_map.lanes_at(position, heading)
            if not possible_lanes:
                continue

            if len(possible_lanes) > 1:
                lane, min_dist = None, np.inf
                for ll in possible_lanes:
                    final_point = np.array(ll.midline.coords[-1])
                    dist = np.min(
                        np.linalg.norm(self._trajectory.path - final_point,
                                       axis=1))
                    if dist < min_dist:
                        lane, min_dist = ll, dist
            else:
                lane = possible_lanes[0]

            if not lanes:
                lanes.append(lane)
            elif lane != lanes[-1]:
                lanes.append(lane)
        return lanes
Example #5
0
 def get_possible_args(state: ip.AgentState, scenario_map: ip.Map, goal: ip.Goal = None) -> List[Dict]:
     """ Return empty dictionary if no goal point is provided, otherwise check if goal point in lane and
     return center of goal point as termination point. """
     if goal is not None:
         current_lane = scenario_map.best_lane_at(state.position, state.heading)
         gp = goal.point_on_lane(current_lane)
         if current_lane.boundary.contains(gp):
             return [{"termination_point": np.array(gp.coords)[0]}]
     return [{}]
Example #6
0
    def applicable(state: ip.AgentState, scenario_map: ip.Map) -> bool:
        """ Checks whether the turn maneuver is applicable for an agent.
            Turn is applicable if the agents current lane or next lane is in a junction.

        Args:
            state: Current state of the agent
            scenario_map: local road map

        Returns:
            Boolean indicating whether the maneuver is applicable
        """
        currently_in_junction = scenario_map.junction_at(
            state.position) is not None
        current_lane = scenario_map.best_lane_at(state.position, state.heading)
        next_lanes = current_lane.link.successor
        next_lane_is_junction = (next_lanes is not None and any(
            [ll.parent_road.junction is not None for ll in next_lanes]))
        return currently_in_junction or next_lane_is_junction
Example #7
0
 def applicable(state: ip.AgentState, scenario_map: ip.Map) -> bool:
     """ True if either Turn (in junction) or GiveWay is applicable (ahead of junction) """
     in_junction = scenario_map.junction_at(state.position) is not None
     # Uncomment the following to disallow turns from inner lanes of a roundabout
     # if ContinueNextExit.applicable(state, scenario_map):
     #     return False
     if in_junction:
         return ip.Turn.applicable(state, scenario_map)
     else:
         return ip.GiveWay.applicable(state, scenario_map)
Example #8
0
    def applicable(state: ip.AgentState, scenario_map: ip.Map) -> bool:
        """ Checks whether the follow lane maneuver is applicable for an agent.
            Follow lane is applicable if the agent is in a drivable lane.

        Args:
            state: Current state of the agent
            scenario_map: local road map

        Returns:
            Boolean indicating whether the maneuver is applicable
        """
        return len(scenario_map.lanes_at(state.position,
                                         drivable_only=True)) > 0
Example #9
0
    def _get_target_lane(self, final_point, state: ip.AgentState,
                         current_lane: ip.Lane,
                         scenario_map: ip.Map) -> ip.Lane:
        target_lanes = scenario_map.lanes_at(final_point, drivable_only=True)
        if len(target_lanes) == 1:
            return target_lanes[0]

        distance = -current_lane.distance_at(state.position)
        while distance <= self.TARGET_SWITCH_LENGTH:
            distance += current_lane.length
            for lane in current_lane.lane_section.all_lanes:
                if abs(current_lane.id - lane.id) == 1:
                    if lane in target_lanes:
                        return lane

            successors = current_lane.link.successor
            if successors is None:
                current_lane = None
            elif len(successors) == 1:
                current_lane = current_lane.link.successor[0]
            elif len(successors) > 1:
                next_lanes = [
                    s for s in successors
                    if len(scenario_map.get_adjacent_lanes(s)) > 0
                ]
                if len(next_lanes) == 0:
                    current_lane = None
                elif len(next_lanes) == 1:
                    current_lane = next_lanes[0]
                elif len(next_lanes) > 1 and scenario_map.road_in_roundabout(
                        current_lane.parent_road):
                    for lane in next_lanes:
                        if scenario_map.road_in_roundabout(lane.parent_road):
                            current_lane = lane
                            break
                    else:
                        current_lane = None
        raise RuntimeError(f"Target lane not found at {final_point}!")
Example #10
0
    def get_possible_args(state: ip.AgentState, scenario_map: ip.Map, goal: ip.Goal = None) -> List[Dict]:
        """ Return turn endpoint if approaching junction; if in junction
        return all possible turns within angle threshold"""
        targets = []
        in_junction = scenario_map.junction_at(state.position) is not None

        if in_junction:
            # lanes = scenario_map.lanes_within_angle(state.position, state.heading, Exit.LANE_ANGLE_THRESHOLD,
            #                                         max_distance=0.5)
            # if not lanes:
            lane = scenario_map.best_lane_at(state.position, state.heading, goal=goal)
            targets.append(np.array(lane.midline.coords[-1]))
            # for lane in lanes:
            #     target = np.array(lane.midline.coords[-1])
            #     if not any([np.allclose(p, target, atol=0.25) for p in targets]):
            #         targets.append(target)
        else:
            current_lane = scenario_map.best_lane_at(state.position, state.heading)
            for connecting_lane in current_lane.link.successor:
                if not scenario_map.road_in_roundabout(connecting_lane.parent_road):
                    targets.append(np.array(connecting_lane.midline.coords[-1]))

        return [{"turn_target": t} for t in targets]
Example #11
0
    def play_forward_macro_action(agent_id: int, scenario_map: ip.Map,
                                  frame: Dict[int, ip.AgentState], macro_action: "MacroAction"):
        """ Play forward current frame with the given macro action for the current agent.
        Assumes constant velocity lane follow behaviour for other agents.

        Args:
            agent_id: ID of the ego agent
            scenario_map: The road layout of the current scenario
            frame: The current frame of the environment
            macro_action: The macro action to play forward

        Returns:
            A new frame describing the future state of the environment
        """

        def _lane_at_distance(lane: ip.Lane, ds: float) -> Tuple[Optional[ip.Lane], float]:
            current_lane = lane
            total_length = 0.0
            while True:
                if total_length <= ds < total_length + current_lane.length:
                    return current_lane, ds - total_length
                total_length += current_lane.length
                successor = current_lane.link.successor
                if successor is None:
                    break
                current_lane = successor[0]
            logger.debug(f"No Lane found at distance {ds} for Agent ID{aid}!")
            return None, current_lane.length

        if not macro_action:
            return frame

        trajectory = macro_action.get_trajectory()
        new_frame = {agent_id: trajectory.final_agent_state}
        duration = trajectory.duration
        for aid, agent in frame.items():
            if aid != agent_id:
                state = copy(agent)
                agent_lane = scenario_map.best_lane_at(agent.position, agent.heading)
                if agent_lane is None:
                    continue
                agent_distance = agent_lane.distance_at(agent.position) + duration * agent.speed
                final_lane, distance_in_lane = _lane_at_distance(agent_lane, agent_distance)
                if final_lane is None:
                    continue
                state.position = final_lane.point_at(distance_in_lane)
                state.heading = final_lane.get_heading_at(distance_in_lane)
                new_frame[aid] = state
        return new_frame
Example #12
0
    def check_change_validity(state: ip.AgentState, scenario_map: ip.Map) -> bool:
        """ True if current lane not in junction, or at appropriate distance from a junction """
        in_junction = scenario_map.junction_at(state.position) is not None
        if in_junction:
            return False

        # Disallow lane changes if close to junction as could enter junction boundary by the end of the lane change,
        #  unless currently in a non-junction roundabout lane where we can pass directly straight through the junction
        current_lane = scenario_map.best_lane_at(state.position, state.heading)
        successor = current_lane.link.successor
        if successor is not None:
            successor_distances = [(s.boundary.distance(Point(state.position)), s) for s in successor]
            distance_to_successor, nearest_successor = min(successor_distances, key=lambda x: x[0])

            # All connecting roads are single laned (in total these have 2 lanes including the zero-width center lane)
            #  then check if at least minimum change length available
            if all([len(lane.lane_section.all_lanes) <= 2 for lane in successor]) and \
                    nearest_successor.parent_road.junction is None:
                return distance_to_successor > ip.SwitchLane.MIN_SWITCH_LENGTH
            elif nearest_successor.parent_road.junction is not None:
                return distance_to_successor > ip.SwitchLane.TARGET_SWITCH_LENGTH + state.metadata.length or \
                       scenario_map.road_in_roundabout(current_lane.parent_road)
            return False
        return current_lane.length - current_lane.distance_at(state.position) > ip.SwitchLane.MIN_SWITCH_LENGTH
Example #13
0
 def _get_lanes_to_cross(self, scenario_map: ip.Map) -> List[ip.Lane]:
     ego_road = scenario_map.roads.get(self.config.junction_road_id)
     ego_lane = scenario_map.get_lane(self.config.junction_road_id,
                                      self.config.junction_lane_id)
     ego_incoming_lane = ego_lane.link.predecessor[0]
     lanes = []
     for connection in ego_road.junction.connections:
         for lane_link in connection.lane_links:
             lane = lane_link.to_lane
             same_predecessor = (ego_incoming_lane.id == lane_link.from_id
                                 and ego_incoming_lane.parent_road.id
                                 == connection.incoming_road.id)
             if not (same_predecessor
                     or self._has_priority(ego_road, lane.parent_road)):
                 if ego_lane.midline.intersects(lane.boundary):
                     lanes.append(lane)
     return lanes
Example #14
0
    def play_forward_maneuver(
            agent_id: int,
            scenario_map: ip.Map,
            frame: Dict[int, ip.AgentState],
            maneuver: "Maneuver",
            offset: float = None) -> Dict[int, ip.AgentState]:
        """ Play forward current frame with the given maneuver for the current agent.
        Assumes constant velocity lane follow behaviour for other agents.

        Args:
            agent_id: ID of the ego agent
            scenario_map: The road layout of the current scenario
            frame: The current frame of the environment
            maneuver: The maneuver to play forward
            offset: If not None, then add an extra point at the end of the maneuver's trajectory with distance given
                by this parameter

        Returns:
            A new frame describing the future state of the environment
        """
        if not maneuver:
            return frame

        trajectory = maneuver.trajectory
        if offset is not None:
            trajectory = ip.util.add_offset_point(trajectory, offset)

        new_frame = {agent_id: trajectory.final_agent_state}

        duration = maneuver.trajectory.duration
        for aid, agent in frame.items():
            if aid != agent_id:
                state = copy(agent)
                agent_lane = scenario_map.best_lane_at(agent.position,
                                                       agent.heading)
                if agent_lane is None:
                    continue
                agent_distance = agent_lane.distance_at(
                    agent.position) + duration * agent.speed
                state.position = agent_lane.point_at(agent_distance)
                state.heading = agent_lane.get_heading_at(agent_distance)
                new_frame[aid] = state
        return new_frame
Example #15
0
    def applicable(state: ip.AgentState, scenario_map: ip.Map) -> bool:
        """ Checks whether the switch lane left maneuver is applicable for an agent.
            Switch lane left is applicable if it is legal to switch to a lane left of the current lane.

        Args:
            state: Current state of the agent
            scenario_map: local road map

        Returns:
            Boolean indicating whether the maneuver is applicable
        """
        # TODO: Add check for lane marker
        current_lane = scenario_map.best_lane_at(state.position, state.heading)
        left_lane_id = current_lane.id + (-1 if np.sign(current_lane.id) > 0
                                          else 1)  # Assumes right hand driving
        left_lane = current_lane.lane_section.get_lane(left_lane_id)

        return (left_lane is not None and left_lane_id != 0
                and left_lane.type == ip.LaneTypes.DRIVING
                and (current_lane.id < 0) == (left_lane_id < 0))
Example #16
0
 def _get_lane_sequence(self, state: ip.AgentState,
                        scenario_map: ip.Map) -> List[ip.Lane]:
     junction_lane = scenario_map.get_lane(self.config.junction_road_id,
                                           self.config.junction_lane_id)
     return [junction_lane]
Example #17
0
 def _get_lane_sequence(self, state: ip.AgentState,
                        scenario_map: ip.Map) -> List[ip.Lane]:
     current_lane = scenario_map.best_lane_at(state.position, state.heading)
     target_lane = self._get_target_lane(self.config.termination_point,
                                         state, current_lane, scenario_map)
     return [target_lane]
Example #18
0
 def applicable(state: ip.AgentState, scenario_map: ip.Map) -> bool:
     """ True if vehicle on a lane, and not approaching junction or not in junction"""
     in_junction = scenario_map.best_lane_at(state.position, state.heading).parent_road.junction is not None
     return (ip.FollowLane.applicable(state, scenario_map) and not in_junction and
             not Exit.applicable(state, scenario_map))
Example #19
0
 def _get_lane_sequence(self, state: ip.AgentState,
                        scenario_map: ip.Map) -> List[ip.Lane]:
     current_lane = scenario_map.best_lane_at(state.position, state.heading)
     lane_seq = [current_lane]
     return lane_seq