Skip to content

World

The environment: analytic circular obstacles, recharge places and an optional occupancy grid.

World

World(config)
Source code in src/hivebr/engine/world.py
def __init__(self, config: dict):
    self.config = config
    self.width = float(config["world"]["width"])
    self.height = float(config["world"]["height"])

    self.grid_size = float(
        config["world"].get("grid_size", 1.0)
    )

    self.resolution = float(
        config["world"].get("resolution", 0.1)
    )

    # Raio padrão usado para novos obstáculos adicionados por mouse
    self.default_obstacle_radius = float(
        config["world"].get("default_obstacle_radius", 0.4)
    )

    self.show_origin = bool(
        config["world"].get("show_origin", True)
    )

    self.show_axes = bool(
        config["world"].get("show_axes", True)
    )

    # self.colors = config["colors"] # Removido, vamos usar a property

    self.obstacles = []

    for obs in config["world"].get("obstacles", []):
        self.obstacles.append(
            self._parse_obstacle(obs)
        )

    self.recharge_image = pygame.image.load(assets_dir /"recharge_place.png").convert_alpha()

    self.recharge_places = []

    for rp in config["world"].get("recharge_places", []):
        self.recharge_places.append(
            self._parse_obstacle(rp)
        )

    self.robot_radius = float(config["robot"].get("radius", 0.4))

    self.grid_map = None
    if "map_image" in config["world"]:
        from .occupancy_grid import OccupancyGridMap
        self.grid_map = OccupancyGridMap(
            image_path=config["world"]["map_image"],
            resolution=float(config["world"]["resolution"]),
            robot_radius=self.robot_radius,
            colors=self.colors
        )
        self.width = self.grid_map.width_m
        self.height = self.grid_map.height_m

    self.line_map = None
    if config["world"].get("line_map_image"):
        self.load_line_map(
            config["world"]["line_map_image"],
            float(config["world"].get("resolution", 0.1)),
        )

    self.show_inflation = bool(
        config["world"].get("show_inflation", True)
    )

config instance-attribute

config = config

width instance-attribute

width = float(config['world']['width'])

height instance-attribute

height = float(config['world']['height'])

grid_size instance-attribute

grid_size = float(config['world'].get('grid_size', 1.0))

resolution instance-attribute

resolution = float(config['world'].get('resolution', 0.1))

default_obstacle_radius instance-attribute

default_obstacle_radius = float(
    config["world"].get("default_obstacle_radius", 0.4)
)

show_origin instance-attribute

show_origin = bool(config["world"].get("show_origin", True))

show_axes instance-attribute

show_axes = bool(config['world'].get('show_axes', True))

obstacles instance-attribute

obstacles = []

recharge_image instance-attribute

recharge_image = pygame.image.load(
    assets_dir / "recharge_place.png"
).convert_alpha()

recharge_places instance-attribute

recharge_places = []

robot_radius instance-attribute

robot_radius = float(config['robot'].get('radius', 0.4))

grid_map instance-attribute

grid_map = None

line_map instance-attribute

line_map = None

show_inflation instance-attribute

show_inflation = bool(
    config["world"].get("show_inflation", True)
)

colors property

colors

load_map

load_map(image_path, resolution)

Loads a map dynamically, bypassing YAML configuration.

Source code in src/hivebr/engine/world.py
def load_map(self, image_path: str, resolution: float):
    """
    Loads a map dynamically, bypassing YAML configuration.
    """
    from .occupancy_grid import OccupancyGridMap
    self.grid_map = OccupancyGridMap(
        image_path=image_path,
        resolution=float(resolution),
        robot_radius=self.robot_radius,
        colors=self.colors
    )
    self.width = self.grid_map.width_m
    self.height = self.grid_map.height_m

load_line_map

load_line_map(image_path, resolution)

Carrega dinamicamente uma pista de linha (imagem preto no branco).

Source code in src/hivebr/engine/world.py
def load_line_map(self, image_path: str, resolution: float):
    """Carrega dinamicamente uma pista de linha (imagem preto no branco)."""
    from .line_map import LineTrackMap
    self.line_map = LineTrackMap(
        image_path=image_path,
        resolution=float(resolution),
        colors=self.colors,
    )
    self.width = self.line_map.width_m
    self.height = self.line_map.height_m
    self.resolution = self.line_map.resolution

set_line_map

set_line_map(line_map)

Instala um :class:LineTrackMap já construído (ex.: desenhado na UI).

Source code in src/hivebr/engine/world.py
def set_line_map(self, line_map):
    """Instala um :class:`LineTrackMap` já construído (ex.: desenhado na UI)."""
    self.line_map = line_map
    self.width = line_map.width_m
    self.height = line_map.height_m
    self.resolution = line_map.resolution

draw_line_map

draw_line_map(screen, camera)
Source code in src/hivebr/engine/world.py
def draw_line_map(self, screen, camera):
    if self.line_map is not None:
        self.line_map.draw(screen, camera)

get_position

get_position(obs)
Source code in src/hivebr/engine/world.py
def get_position(self, obs):
    return obs[:2]

obstacle_radius

obstacle_radius(obs)
Source code in src/hivebr/engine/world.py
def obstacle_radius(self, obs):
    return float(obs[2])

clear_obstacles

clear_obstacles()
Source code in src/hivebr/engine/world.py
def clear_obstacles(self):
    self.obstacles.clear()

add_obstacle

add_obstacle(pos, radius=None)
Source code in src/hivebr/engine/world.py
def add_obstacle(self, pos, radius=None):
    if radius is None:
        radius = self.default_obstacle_radius

    self.obstacles.append(
        np.array(
            [float(pos[0]), float(pos[1]), float(radius)],
            dtype=float
        )
    )

distance_to_nearest_obstacle

distance_to_nearest_obstacle(position)
Source code in src/hivebr/engine/world.py
def distance_to_nearest_obstacle(self, position):
    if not self.obstacles:
        return float("inf")

    distances = []

    for obs in self.obstacles:
        center = self.get_position(obs)
        radius = self.obstacle_radius(obs)

        distance = np.linalg.norm(position - center) - radius
        distances.append(distance)

    return float(min(distances))

draw_grid

draw_grid(screen, camera)
Source code in src/hivebr/engine/world.py
def draw_grid(self, screen, camera):
    step_px = self.grid_size * camera.scale

    if step_px < 8:
        return

    bottom_left = camera.screen_to_world(
        0,
        camera.viewport_height
    )

    top_right = camera.screen_to_world(
        camera.viewport_width,
        0
    )

    min_x, min_y = bottom_left
    max_x, max_y = top_right

    start_x = math.floor(min_x / self.grid_size) * self.grid_size
    end_x = math.ceil(max_x / self.grid_size) * self.grid_size

    start_y = math.floor(min_y / self.grid_size) * self.grid_size
    end_y = math.ceil(max_y / self.grid_size) * self.grid_size

    color = tuple(self.colors["grid"])

    x = start_x
    while x <= end_x:
        pygame.draw.line(
            screen,
            color,
            camera.world_to_screen(x, min_y),
            camera.world_to_screen(x, max_y)
        )

        x += self.grid_size

    y = start_y
    while y <= end_y:
        pygame.draw.line(
            screen,
            color,
            camera.world_to_screen(min_x, y),
            camera.world_to_screen(max_x, y)
        )

        y += self.grid_size

draw_origin

draw_origin(screen, camera)
Source code in src/hivebr/engine/world.py
def draw_origin(self, screen, camera):
    if not self.show_origin:
        return

    origin = camera.world_to_screen(0.0, 0.0)

    red = tuple(self.colors["red"])
    # white = tuple(self.colors["black"])

    # pygame.draw.circle(
    #     screen,
    #     white,
    #     origin,
    #     3
    # )

    pygame.draw.line(
        screen,
        red,
        (origin[0] - 10, origin[1]),
        (origin[0] + 10, origin[1]),
        2
    )

    pygame.draw.line(
        screen,
        red,
        (origin[0], origin[1] - 10),
        (origin[0], origin[1] + 10),
        2
    )

draw_axes

draw_axes(screen, camera)
Source code in src/hivebr/engine/world.py
def draw_axes(self, screen, camera):
    if not self.show_axes:
        return

    red = tuple(self.colors["red"])
    green = tuple(self.colors["green"])

    origin = camera.world_to_screen(0.0, 0.0)
    x_tip = camera.world_to_screen(camera.margin_x, 0.0)
    y_tip = camera.world_to_screen(0.0, camera.margin_y)

    pygame.draw.line(
        screen,
        red,
        origin,
        x_tip,
        2
    )

    pygame.draw.line(
        screen,
        green,
        origin,
        y_tip,
        2
    )

draw_recharge_places

draw_recharge_places(screen, camera)
Source code in src/hivebr/engine/world.py
def draw_recharge_places(self, screen, camera):
    # Obter tamanho original da imagem para manter proporção
    orig_w, orig_h = self.recharge_image.get_size()
    aspect_ratio = orig_h / orig_w

    for rp in self.recharge_places:
        center = self.get_position(rp)
        screen_pos = camera.world_to_screen(center[0], center[1])

        # Escala baseada no zoom da câmera. 
        # Define uma largura base de 32 pixels
        base_width = 16
        scaled_width = int(base_width * camera.zoom)
        scaled_height = int(scaled_width * aspect_ratio)

        img = pygame.transform.smoothscale(self.recharge_image, (scaled_width, scaled_height))
        rect = img.get_rect(center=screen_pos)
        screen.blit(img, rect)

get_recharge_place

get_recharge_place(id)
Source code in src/hivebr/engine/world.py
def get_recharge_place(self, id):
    if 0 <= id < len(self.recharge_places):
        return self.get_position(self.recharge_places[id])
    return None

draw_obstacles

draw_obstacles(screen, camera)
Source code in src/hivebr/engine/world.py
def draw_obstacles(self, screen, camera):
    color = tuple(self.colors["obstacle"])

    for obs in self.obstacles:
        center = self.get_position(obs)
        radius = self.obstacle_radius(obs)

        pygame.draw.circle(
            screen,
            color,
            camera.world_to_screen(center[0], center[1]),
            max(2, int(radius * camera.scale))
        )

        # =========================
        # Círculo transparente
        # =========================
        radius_px = max(5, int((self.robot_radius + radius) * camera.scale))

        circle_surface = pygame.Surface(
            (radius_px * 2, radius_px * 2),
            pygame.SRCALPHA
        )

        color2 = (*color, 120)

        pygame.draw.circle(
            circle_surface,
            color2,
            (radius_px, radius_px),
            radius_px
        )

        screen_pos = camera.world_to_screen(center[0], center[1])

        screen.blit(
            circle_surface,
            (screen_pos[0] - radius_px,
            screen_pos[1] - radius_px)
        )

set_grid_map

set_grid_map(grid_map)
Source code in src/hivebr/engine/world.py
def set_grid_map(self, grid_map):
    self.grid_map = grid_map
    self.width = self.grid_map.width_m
    self.height = self.grid_map.height_m