예제 #1
0
    def __init__(self, map_config: dict = None, random_seed=None):
        """
        Map can be stored and recover to save time when we access the map encountered before
        """
        assert random_seed is None
        # assert random_seed == map_config[
        #     self.SEED
        # ], "Global seed {} should equal to seed in map config {}".format(random_seed, map_config[self.SEED])
        super(BaseMap, self).__init__(config=map_config)
        self.film_size = (get_global_config()["draw_map_resolution"],
                          get_global_config()["draw_map_resolution"])
        self.road_network = RoadNetwork()

        # A flatten representation of blocks, might cause chaos in city-level generation.
        self.blocks = []

        # Generate map and insert blocks
        self.engine = get_engine()
        self._generate()
        assert self.blocks, "The generate methods does not fill blocks!"

        #  a trick to optimize performance
        self.road_network.after_init()
        self.spawn_roads = [Road(FirstPGBlock.NODE_2, FirstPGBlock.NODE_3)]
        self.detach_from_world()
예제 #2
0
    def __init__(self,
                 block_index: int,
                 global_network: RoadNetwork,
                 random_seed,
                 ignore_intersection_checking=False):
        super(BaseBlock, self).__init__(str(block_index) + self.ID,
                                        random_seed,
                                        escape_random_seed_assertion=True)
        # block information
        assert self.ID is not None, "Each Block must has its unique ID When define Block"
        assert len(self.ID) == 1, "Block ID must be a character "

        self.block_index = block_index
        self.ignore_intersection_checking = ignore_intersection_checking

        # each block contains its own road network and a global network
        self._global_network = global_network
        self.block_network = RoadNetwork()

        # a bounding box used to improve efficiency x_min, x_max, y_min, y_max
        self.bounding_box = None

        # used to spawn npc
        self._respawn_roads = []
        self._block_objects = None

        if self.render:
            # render pre-load
            self.road_texture = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sci", "color.jpg"))
            self.road_texture.setMinfilter(
                SamplerState.FT_linear_mipmap_linear)
            self.road_texture.setAnisotropicDegree(8)
            self.road_normal = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sci", "normal.jpg"))
            self.ts_color = TextureStage("color")
            self.ts_normal = TextureStage("normal")
            self.side_texture = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sidewalk", "color.png"))
            self.side_texture.setMinfilter(
                SamplerState.FT_linear_mipmap_linear)
            self.side_texture.setAnisotropicDegree(8)
            self.side_normal = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sidewalk", "normal.png"))
            self.sidewalk = self.loader.loadModel(
                AssetLoader.file_path("models", "box.bam"))
예제 #3
0
def vis_big(debug: bool = False):
    test = TestBlock(debug=debug)

    test.cam.setPos(300, 400, 2000)

    initialize_asset_loader(test)
    set_global_random_seed(4)
    global_network = RoadNetwork()

    big = BIG(2, 3.5, global_network, test.render, test.world)
    test.vis_big(big)
    test.big.block_num = 40
    # big.generate(BigGenerateMethod.BLOCK_NUM, 10)
    test.run()
예제 #4
0
class BaseMap(BaseRunnable):
    """
    Base class for Map generation!
    """
    # only used to save and read maps
    FILE_SUFFIX = ".json"

    # define string in json and config
    SEED = "seed"
    LANE_WIDTH = "lane_width"
    LANE_WIDTH_RAND_RANGE = "lane_width_rand_range"
    LANE_NUM = "lane_num"
    BLOCK_ID = "id"
    BLOCK_SEQUENCE = "block_sequence"
    PRE_BLOCK_SOCKET_INDEX = "pre_block_socket_index"

    # generate_method
    GENERATE_CONFIG = "config"
    GENERATE_TYPE = "type"

    def __init__(self, map_config: dict = None, random_seed=None):
        """
        Map can be stored and recover to save time when we access the map encountered before
        """
        assert random_seed is None
        # assert random_seed == map_config[
        #     self.SEED
        # ], "Global seed {} should equal to seed in map config {}".format(random_seed, map_config[self.SEED])
        super(BaseMap, self).__init__(config=map_config)
        self.film_size = (get_global_config()["draw_map_resolution"],
                          get_global_config()["draw_map_resolution"])
        self.road_network = RoadNetwork()

        # A flatten representation of blocks, might cause chaos in city-level generation.
        self.blocks = []

        # Generate map and insert blocks
        self.engine = get_engine()
        self._generate()
        assert self.blocks, "The generate methods does not fill blocks!"

        #  a trick to optimize performance
        self.road_network.after_init()
        self.spawn_roads = [Road(FirstPGBlock.NODE_2, FirstPGBlock.NODE_3)]
        self.detach_from_world()

    def _generate(self):
        """Key function! Please overwrite it! This func aims at fill the self.road_network adn self.blocks"""
        raise NotImplementedError(
            "Please use child class like PGMap to replace Map!")

    def attach_to_world(self, parent_np=None, physics_world=None):
        parent_node_path, physics_world = self.engine.worldNP or parent_np, self.engine.physics_world or physics_world
        for block in self.blocks:
            block.attach_to_world(parent_node_path, physics_world)

    def detach_from_world(self, physics_world=None):
        for block in self.blocks:
            block.detach_from_world(self.engine.physics_world or physics_world)

    def save_map(self):
        """
        Save the generated map to map file
        """
        assert self.blocks is not None and len(
            self.blocks) > 0, "Please generate Map before saving it"
        map_config = []
        for b in self.blocks:
            assert isinstance(
                b, PGBlock), "None Set can not be saved to json file"
            b_config = b.get_config()
            json_config = b_config.get_serializable_dict()
            json_config[self.BLOCK_ID] = b.ID
            json_config[self.PRE_BLOCK_SOCKET_INDEX] = b.pre_block_socket_index
            map_config.append(json_config)

        saved_data = copy.deepcopy({self.BLOCK_SEQUENCE: map_config})
        return saved_data

    def read_map(self, map_config: dict):
        """
        Load the map from a dict. Note that we don't provide a restore function in the base class.
        """
        self._config[self.SEED] = map_config[self.SEED]
        blocks_config = map_config[self.BLOCK_SEQUENCE]
        for b_id, b in enumerate(blocks_config):
            blocks_config[b_id] = {
                k: np.array(v) if isinstance(v, list) else v
                for k, v in b.items()
            }

        # update the property
        return blocks_config

    @property
    def num_blocks(self):
        return len(self.blocks)

    def destroy(self):
        for block in self.blocks:
            block.destroy()
        super(BaseMap, self).destroy()
예제 #5
0
from pgdrive.component.blocks.first_block import FirstPGBlock
from pgdrive.component.blocks.std_intersection import StdInterSection
from pgdrive.component.blocks.std_t_intersection import StdTInterSection
from pgdrive.component.road.road_network import RoadNetwork
from pgdrive.tests.vis_block.vis_block_base import TestBlock

if __name__ == "__main__":
    test = TestBlock()
    from pgdrive.engine.asset_loader import initialize_asset_loader

    initialize_asset_loader(test)

    global_network = RoadNetwork()
    first = FirstPGBlock(global_network, 3.0, 1, test.render, test.world, 1)

    intersection = StdInterSection(3, first.get_socket(0), global_network, 1)
    print(intersection.construct_block(test.render, test.world))

    id = 4
    for socket_idx in range(intersection.SOCKET_NUM):
        block = StdTInterSection(id, intersection.get_socket(socket_idx),
                                 global_network, id)
        block.construct_block(test.render, test.world)
        id += 1
    test.show_bounding_box(global_network)
    test.run()
예제 #6
0
class BaseBlock(BaseObject, DrivableAreaProperty):
    """
    Block is a driving area consisting of several roads
    Note: overriding the _sample() function to fill block_network/respawn_roads in subclass
    Call Block.construct_block() to add it to world
    """

    ID = "B"

    def __init__(self,
                 block_index: int,
                 global_network: RoadNetwork,
                 random_seed,
                 ignore_intersection_checking=False):
        super(BaseBlock, self).__init__(str(block_index) + self.ID,
                                        random_seed,
                                        escape_random_seed_assertion=True)
        # block information
        assert self.ID is not None, "Each Block must has its unique ID When define Block"
        assert len(self.ID) == 1, "Block ID must be a character "

        self.block_index = block_index
        self.ignore_intersection_checking = ignore_intersection_checking

        # each block contains its own road network and a global network
        self._global_network = global_network
        self.block_network = RoadNetwork()

        # a bounding box used to improve efficiency x_min, x_max, y_min, y_max
        self.bounding_box = None

        # used to spawn npc
        self._respawn_roads = []
        self._block_objects = None

        if self.render:
            # render pre-load
            self.road_texture = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sci", "color.jpg"))
            self.road_texture.setMinfilter(
                SamplerState.FT_linear_mipmap_linear)
            self.road_texture.setAnisotropicDegree(8)
            self.road_normal = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sci", "normal.jpg"))
            self.ts_color = TextureStage("color")
            self.ts_normal = TextureStage("normal")
            self.side_texture = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sidewalk", "color.png"))
            self.side_texture.setMinfilter(
                SamplerState.FT_linear_mipmap_linear)
            self.side_texture.setAnisotropicDegree(8)
            self.side_normal = self.loader.loadTexture(
                AssetLoader.file_path("textures", "sidewalk", "normal.png"))
            self.sidewalk = self.loader.loadModel(
                AssetLoader.file_path("models", "box.bam"))

    def _sample_topology(self) -> bool:
        """
        Sample a new topology to fill self.block_network
        """
        raise NotImplementedError

    def construct_block(self,
                        root_render_np: NodePath,
                        physics_world: PhysicsWorld,
                        extra_config: Dict = None,
                        no_same_node=True) -> bool:
        """
        Randomly Construct a block, if overlap return False
        """
        self.sample_parameters()
        self.origin = NodePath(self.name)
        self._block_objects = []
        if extra_config:
            assert set(extra_config.keys()).issubset(self.PARAMETER_SPACE.parameters), \
                "Make sure the parameters' name are as same as what defined in pg_space.py"
            raw_config = self.get_config()
            raw_config.update(extra_config)
            self.update_config(raw_config)
        self._clear_topology()
        success = self._sample_topology()
        self._global_network.add(self.block_network, no_same_node)
        self._create_in_world()
        self.attach_to_world(root_render_np, physics_world)
        return success

    def destruct_block(self, physics_world: PhysicsWorld):
        self._clear_topology()
        self.detach_from_world(physics_world)
        self.origin.removeNode()
        self.dynamic_nodes.clear()
        self.static_nodes.clear()
        for obj in self._block_objects:
            obj.destroy()
        self._block_objects = None

    def construct_from_config(self, config: Dict, root_render_np: NodePath,
                              physics_world: PhysicsWorld):
        success = self.construct_block(root_render_np, physics_world, config)
        return success

    def get_respawn_roads(self):
        return self._respawn_roads

    def get_respawn_lanes(self):
        """
        return a 2-dim array [[]] to keep the lane index
        """
        ret = []
        for road in self._respawn_roads:
            lanes = road.get_lanes(self.block_network)
            ret.append(lanes)
        return ret

    def get_intermediate_spawn_lanes(self):
        """Return all lanes that can be used to generate spawn intermediate vehicles."""
        raise NotImplementedError()

    def _add_one_respawn_road(self, respawn_road: Road):
        assert isinstance(respawn_road,
                          Road), "Spawn roads list only accept Road Type"
        self._respawn_roads.append(respawn_road)

    def _clear_topology(self):
        self._global_network -= self.block_network
        self.block_network.graph.clear()
        self.PART_IDX = 0
        self.ROAD_IDX = 0
        self._respawn_roads.clear()

    """------------------------------------- For Render and Physics Calculation ---------------------------------- """

    def _create_in_world(self):
        """
        Create NodePath and Geom node to perform both collision detection and render
        """
        self.lane_line_node_path = NodePath(
            RigidBodyCombiner(self.name + "_lane_line"))
        self.sidewalk_node_path = NodePath(
            RigidBodyCombiner(self.name + "_sidewalk"))
        self.lane_node_path = NodePath(RigidBodyCombiner(self.name + "_lane"))
        self.lane_vis_node_path = NodePath(
            RigidBodyCombiner(self.name + "_lane_vis"))
        graph = self.block_network.graph
        for _from, to_dict in graph.items():
            for _to, lanes in to_dict.items():
                self._add_lane_surface(_from, _to, lanes)
                for _id, l in enumerate(lanes):
                    line_color = l.line_color
                    self._add_lane(l, _id, line_color)
        self.lane_line_node_path.flattenStrong()
        self.lane_line_node_path.node().collect()

        self.sidewalk_node_path.flattenStrong()
        self.sidewalk_node_path.node().collect()
        self.sidewalk_node_path.hide(CamMask.ScreenshotCam)

        # only bodies reparent to this node
        self.lane_node_path.flattenStrong()
        self.lane_node_path.node().collect()

        self.lane_vis_node_path.flattenStrong()
        self.lane_vis_node_path.node().collect()
        self.lane_vis_node_path.hide(CamMask.DepthCam | CamMask.ScreenshotCam)

        self.origin.hide(CamMask.Shadow)

        self.sidewalk_node_path.reparentTo(self.origin)
        self.lane_line_node_path.reparentTo(self.origin)
        self.lane_node_path.reparentTo(self.origin)
        self.lane_vis_node_path.reparentTo(self.origin)

        self.bounding_box = self.block_network.get_bounding_box()

    def _add_pgdrive_lanes(self, lane, lane_id, lane_width, colors, parent_np):
        # for pgdrive structure
        for k, i in enumerate([-1, 1]):
            line_color = colors[k]
            if lane.line_types[k] == LineType.NONE or (lane_id != 0
                                                       and k == 0):
                if isinstance(lane, StraightLane):
                    continue
                elif isinstance(
                        lane, CircularLane) and lane.radius != lane_width / 2:
                    # for ramp render
                    continue
            if lane.line_types[k] == LineType.CONTINUOUS or lane.line_types[
                    k] == LineType.SIDE:
                if isinstance(lane, StraightLane):
                    lane_start = lane.position(0, i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = lane.position(lane.length / 2, i * lane_width / 2)
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k])
                elif isinstance(lane, CircularLane):
                    segment_num = int(
                        lane.length /
                        DrivableAreaProperty.CIRCULAR_SEGMENT_LENGTH)
                    for segment in range(segment_num):
                        lane_start = lane.position(
                            segment *
                            DrivableAreaProperty.CIRCULAR_SEGMENT_LENGTH,
                            i * lane_width / 2)
                        lane_end = lane.position(
                            (segment + 1) *
                            DrivableAreaProperty.CIRCULAR_SEGMENT_LENGTH,
                            i * lane_width / 2)
                        middle = (lane_start + lane_end) / 2

                        self._add_lane_line2bullet(lane_start, lane_end,
                                                   middle, parent_np,
                                                   line_color,
                                                   lane.line_types[k])
                    # for last part
                    lane_start = lane.position(
                        segment_num *
                        DrivableAreaProperty.CIRCULAR_SEGMENT_LENGTH,
                        i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = (lane_start + lane_end) / 2
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k])

                if lane.line_types[k] == LineType.SIDE:
                    radius = lane.radius if isinstance(lane,
                                                       CircularLane) else 0.0
                    segment_num = int(lane.length /
                                      DrivableAreaProperty.SIDEWALK_LENGTH)
                    for segment in range(segment_num):
                        lane_start = lane.position(
                            segment * DrivableAreaProperty.SIDEWALK_LENGTH,
                            i * lane_width / 2)
                        lane_end = lane.position(
                            (segment + 1) *
                            DrivableAreaProperty.SIDEWALK_LENGTH,
                            i * lane_width / 2)
                        middle = (lane_start + lane_end) / 2
                        self._add_sidewalk2bullet(lane_start, lane_end, middle,
                                                  radius, lane.direction)
                    # for last part
                    lane_start = lane.position(
                        segment_num * DrivableAreaProperty.SIDEWALK_LENGTH,
                        i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = (lane_start + lane_end) / 2
                    if norm(lane_start[0] - lane_end[0],
                            lane_start[1] - lane_end[1]) > 1e-1:
                        self._add_sidewalk2bullet(lane_start, lane_end, middle,
                                                  radius, lane.direction)

            elif lane.line_types[k] == LineType.BROKEN:
                straight = True if isinstance(lane, StraightLane) else False
                segment_num = int(lane.length /
                                  (2 * DrivableAreaProperty.STRIPE_LENGTH))
                for segment in range(segment_num):
                    lane_start = lane.position(
                        segment * DrivableAreaProperty.STRIPE_LENGTH * 2,
                        i * lane_width / 2)
                    lane_end = lane.position(
                        segment * DrivableAreaProperty.STRIPE_LENGTH * 2 +
                        DrivableAreaProperty.STRIPE_LENGTH, i * lane_width / 2)
                    middle = lane.position(
                        segment * DrivableAreaProperty.STRIPE_LENGTH * 2 +
                        DrivableAreaProperty.STRIPE_LENGTH / 2,
                        i * lane_width / 2)

                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k], straight)

                lane_start = lane.position(
                    segment_num * DrivableAreaProperty.STRIPE_LENGTH * 2,
                    i * lane_width / 2)
                lane_end = lane.position(
                    lane.length + DrivableAreaProperty.STRIPE_LENGTH,
                    i * lane_width / 2)
                middle = (lane_end[0] + lane_start[0]) / 2, (lane_end[1] +
                                                             lane_start[1]) / 2
                if not straight:
                    self._add_lane_line2bullet(lane_start, lane_end, middle,
                                               parent_np, line_color,
                                               lane.line_types[k], straight)
                if straight:
                    lane_start = lane.position(0, i * lane_width / 2)
                    lane_end = lane.position(lane.length, i * lane_width / 2)
                    middle = lane.position(lane.length / 2, i * lane_width / 2)
                    self._add_box_body(lane_start, lane_end, middle, parent_np,
                                       lane.line_types[k], line_color)

    def _add_lane(self, lane: AbstractLane, lane_id: int, colors: List[Vec4]):
        parent_np = self.lane_line_node_path
        lane_width = lane.width_at(0)
        if isinstance(lane, CircularLane) or isinstance(lane, StraightLane):
            self._add_pgdrive_lanes(lane, lane_id, lane_width, colors,
                                    parent_np)
        elif isinstance(lane, WayPointLane):
            for c, i in enumerate([-1, 1]):
                line_color = colors[c]
                acc_length = 0
                if lane.line_types[c] != LineType.NONE:
                    for segment in lane.segment_property:
                        lane_start = lane.position(acc_length,
                                                   i * lane_width / 2)
                        acc_length += segment["length"]
                        lane_end = lane.position(acc_length,
                                                 i * lane_width / 2)
                        middle = (lane_start + lane_end) / 2
                        self._add_lane_line2bullet(lane_start, lane_end,
                                                   middle, parent_np,
                                                   line_color,
                                                   lane.line_types[c])

    def _add_box_body(self, lane_start, lane_end, middle, parent_np: NodePath,
                      line_type, line_color):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        if LineType.prohibit(line_type):
            node_name = BodyName.White_continuous_line if line_color == LineColor.GREY else BodyName.Yellow_continuous_line
        else:
            node_name = BodyName.Broken_line
        body_node = BulletGhostNode(node_name)
        body_node.set_active(False)
        body_node.setKinematic(False)
        body_node.setStatic(True)
        body_np = parent_np.attachNewNode(body_node)
        shape = BulletBoxShape(
            Vec3(length / 2, DrivableAreaProperty.LANE_LINE_WIDTH / 2,
                 DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT))
        body_np.node().addShape(shape)
        mask = DrivableAreaProperty.CONTINUOUS_COLLISION_MASK if line_type != LineType.BROKEN else DrivableAreaProperty.BROKEN_COLLISION_MASK
        body_np.node().setIntoCollideMask(mask)
        self.static_nodes.append(body_np.node())

        body_np.setPos(
            panda_position(middle,
                           DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT / 2))
        direction_v = lane_end - lane_start
        # theta = -numpy.arctan2(direction_v[1], direction_v[0])
        theta = -math.atan2(direction_v[1], direction_v[0])

        body_np.setQuat(
            LQuaternionf(math.cos(theta / 2), 0, 0, math.sin(theta / 2)))

    def _add_lane_line2bullet(self,
                              lane_start,
                              lane_end,
                              middle,
                              parent_np: NodePath,
                              color: Vec4,
                              line_type: LineType,
                              straight_stripe=False):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        if length <= 0:
            return
        if LineType.prohibit(line_type):
            node_name = BodyName.White_continuous_line if color == LineColor.GREY else BodyName.Yellow_continuous_line
        else:
            node_name = BodyName.Broken_line

        # add bullet body for it
        if straight_stripe:
            body_np = parent_np.attachNewNode(node_name)
        else:
            body_node = BulletGhostNode(node_name)
            body_node.set_active(False)
            body_node.setKinematic(False)
            body_node.setStatic(True)
            body_np = parent_np.attachNewNode(body_node)
            # its scale will change by setScale
            body_height = DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT
            shape = BulletBoxShape(
                Vec3(length / 2 if line_type != LineType.BROKEN else length,
                     DrivableAreaProperty.LANE_LINE_WIDTH / 2, body_height))
            body_np.node().addShape(shape)
            mask = DrivableAreaProperty.CONTINUOUS_COLLISION_MASK if line_type != LineType.BROKEN else DrivableAreaProperty.BROKEN_COLLISION_MASK
            body_np.node().setIntoCollideMask(mask)
            self.static_nodes.append(body_np.node())

        # position and heading
        body_np.setPos(
            panda_position(middle,
                           DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT / 2))
        direction_v = lane_end - lane_start
        # theta = -numpy.arctan2(direction_v[1], direction_v[0])
        theta = -math.atan2(direction_v[1], direction_v[0])
        body_np.setQuat(
            LQuaternionf(math.cos(theta / 2), 0, 0, math.sin(theta / 2)))

        if self.render:
            # For visualization
            lane_line = self.loader.loadModel(
                AssetLoader.file_path("models", "box.bam"))
            lane_line.setScale(length, DrivableAreaProperty.LANE_LINE_WIDTH,
                               DrivableAreaProperty.LANE_LINE_THICKNESS)
            lane_line.setPos(
                Vec3(0, 0 - DrivableAreaProperty.LANE_LINE_GHOST_HEIGHT / 2))
            lane_line.reparentTo(body_np)
            body_np.set_color(color)

    def _add_sidewalk2bullet(self,
                             lane_start,
                             lane_end,
                             middle,
                             radius=0.0,
                             direction=0):
        length = norm(lane_end[0] - lane_start[0], lane_end[1] - lane_start[1])
        body_node = BulletRigidBodyNode(BodyName.Sidewalk)
        body_node.setKinematic(False)
        body_node.setStatic(True)
        side_np = self.sidewalk_node_path.attachNewNode(body_node)
        shape = BulletBoxShape(Vec3(1 / 2, 1 / 2, 1 / 2))
        body_node.addShape(shape)
        body_node.setIntoCollideMask(self.SIDEWALK_COLLISION_MASK)
        self.dynamic_nodes.append(body_node)

        if radius == 0:
            factor = 1
        else:
            if direction == 1:
                factor = (1 - self.SIDEWALK_LINE_DIST / radius)
            else:
                factor = (1 + self.SIDEWALK_WIDTH / radius) * (
                    1 + self.SIDEWALK_LINE_DIST / radius)
        direction_v = lane_end - lane_start
        vertical_v = Vector(
            (-direction_v[1], direction_v[0])) / norm(*direction_v)
        middle += vertical_v * (self.SIDEWALK_WIDTH / 2 +
                                self.SIDEWALK_LINE_DIST)
        side_np.setPos(panda_position(middle, 0))
        theta = -math.atan2(direction_v[1], direction_v[0])
        side_np.setQuat(
            LQuaternionf(math.cos(theta / 2), 0, 0, math.sin(theta / 2)))
        side_np.setScale(
            length * factor, self.SIDEWALK_WIDTH,
            self.SIDEWALK_THICKNESS * (1 + 0.1 * np.random.rand()))
        if self.render:
            side_np.setTexture(self.ts_color, self.side_texture)
            self.sidewalk.instanceTo(side_np)

    def _add_lane_surface(self, from_: str, to_: str, lanes: List):
        """
        Add the land surface to world, this surface will record the lane information, like index
        :param from_: From node
        :param to_: To Node
        :param lanes: All lanes of this road
        """

        if isinstance(lanes[0], StraightLane):
            for index, lane in enumerate(lanes):
                middle = lane.position(lane.length / 2, 0)
                end = lane.position(lane.length, 0)
                direction_v = end - middle
                theta = -math.atan2(direction_v[1], direction_v[0])
                width = lane.width_at(0) + self.SIDEWALK_LINE_DIST * 2
                length = lane.length
                self._add_lane2bullet(middle, width, length, theta, lane,
                                      (from_, to_, index))
        elif isinstance(lanes[0], CircularLane):
            for index, lane in enumerate(lanes):
                segment_num = int(lane.length / self.CIRCULAR_SEGMENT_LENGTH)
                for i in range(segment_num):
                    middle = lane.position(
                        lane.length * (i + .5) / segment_num, 0)
                    end = lane.position(lane.length * (i + 1) / segment_num, 0)
                    direction_v = end - middle
                    theta = -math.atan2(direction_v[1], direction_v[0])
                    width = lane.width_at(0) + self.SIDEWALK_LINE_DIST * 2
                    length = lane.length
                    self._add_lane2bullet(middle, width,
                                          length * 1.3 / segment_num, theta,
                                          lane, (from_, to_, index))
        elif isinstance(lanes[0], WayPointLane):
            for index, lane in enumerate(lanes):
                for segment in lane.segment_property:
                    lane_start = segment["start_point"]
                    lane_end = segment["end_point"]
                    middle = (lane_start + lane_end) / 2
                    direction_v = lane_end - middle
                    theta = -math.atan2(direction_v[1], direction_v[0])
                    width = lane.width_at(0)
                    length = segment["length"]
                    self._add_lane2bullet(middle, width, length, theta, lane,
                                          (from_, to_, index))

    def _add_lane2bullet(self, middle, width, length, theta,
                         lane: Union[StraightLane, CircularLane], lane_index):
        """
        Add lane visualization and body for it
        :param middle: Middle point
        :param width: Lane width
        :param length: Segment length
        :param theta: Rotate theta
        :param lane: Lane info
        :return: None
        """
        length += 0.1
        lane.index = lane_index
        segment_np = NodePath(BaseRigidBodyNode(lane, BodyName.Lane))
        segment_node = segment_np.node()
        segment_node.set_active(False)
        segment_node.setKinematic(False)
        segment_node.setStatic(True)
        shape = BulletBoxShape(Vec3(length / 2, 0.1, width / 2))
        segment_node.addShape(shape)
        self.static_nodes.append(segment_node)
        segment_np.setPos(panda_position(middle, -0.1))
        segment_np.setQuat(
            LQuaternionf(
                math.cos(theta / 2) * math.cos(-math.pi / 4),
                math.cos(theta / 2) * math.sin(-math.pi / 4),
                -math.sin(theta / 2) * math.cos(-math.pi / 4),
                math.sin(theta / 2) * math.cos(-math.pi / 4)))
        segment_np.reparentTo(self.lane_node_path)
        if self.render:
            cm = CardMaker('card')
            cm.setFrame(-length / 2, length / 2, -width / 2, width / 2)
            cm.setHasNormals(True)
            cm.setUvRange((0, 0), (length / 20, width / 10))
            card = self.lane_vis_node_path.attachNewNode(cm.generate())
            card.setPos(panda_position(middle, np.random.rand() * 0.01 - 0.01))

            card.setQuat(
                LQuaternionf(
                    math.cos(theta / 2) * math.cos(-math.pi / 4),
                    math.cos(theta / 2) * math.sin(-math.pi / 4),
                    -math.sin(theta / 2) * math.cos(-math.pi / 4),
                    math.sin(theta / 2) * math.cos(-math.pi / 4)))
            card.setTransparency(TransparencyAttrib.MMultisample)
            card.setTexture(self.ts_color, self.road_texture)

    def add_body(self, physics_body):
        raise DeprecationWarning(
            "Different from common objects like vehicle/traffic sign, Block has several bodies!"
            "Therefore, you should create BulletBody and then add them to self.dynamics_nodes "
            "manually. See in construct() method")
예제 #7
0
    def __init__(self,
                 global_network: RoadNetwork,
                 lane_width: float,
                 lane_num: int,
                 render_root_np: NodePath,
                 physics_world: PhysicsWorld,
                 length: float = 50,
                 ignore_intersection_checking=False):
        place_holder = PGBlockSocket(Road(Decoration.start, Decoration.end),
                                     Road(Decoration.start, Decoration.end))
        super(FirstPGBlock, self).__init__(
            0,
            place_holder,
            global_network,
            random_seed=0,
            ignore_intersection_checking=ignore_intersection_checking)
        assert length > self.ENTRANCE_LENGTH, (length, self.ENTRANCE_LENGTH)
        self._block_objects = []
        basic_lane = StraightLane(
            [0, lane_width * (lane_num - 1)],
            [self.ENTRANCE_LENGTH, lane_width * (lane_num - 1)],
            line_types=(LineType.BROKEN, LineType.SIDE),
            width=lane_width)
        ego_v_spawn_road = Road(self.NODE_1, self.NODE_2)
        CreateRoadFrom(
            basic_lane,
            lane_num,
            ego_v_spawn_road,
            self.block_network,
            self._global_network,
            ignore_intersection_checking=self.ignore_intersection_checking)
        CreateAdverseRoad(
            ego_v_spawn_road,
            self.block_network,
            self._global_network,
            ignore_intersection_checking=self.ignore_intersection_checking)

        next_lane = ExtendStraightLane(basic_lane,
                                       length - self.ENTRANCE_LENGTH,
                                       [LineType.BROKEN, LineType.SIDE])
        other_v_spawn_road = Road(self.NODE_2, self.NODE_3)
        CreateRoadFrom(
            next_lane,
            lane_num,
            other_v_spawn_road,
            self.block_network,
            self._global_network,
            ignore_intersection_checking=self.ignore_intersection_checking)
        CreateAdverseRoad(
            other_v_spawn_road,
            self.block_network,
            self._global_network,
            ignore_intersection_checking=self.ignore_intersection_checking)

        self._create_in_world()

        # global_network += self.block_network
        global_network.add(self.block_network)

        socket = self.create_socket_from_positive_road(other_v_spawn_road)
        socket.set_index(self.name, 0)

        self.add_sockets(socket)
        self.attach_to_world(render_root_np, physics_world)
        self._respawn_roads = [other_v_spawn_road]