robolib.entities

entites.py Helpers to make various entities, like cubes, robots, meshes Import level: 3

 1"""
 2entites.py Helpers to make various entities, like cubes, robots, meshes
 3Import level: 3
 4"""
 5from pathlib import Path
 6from typing import Any
 7import numpy as np
 8from microecs import World, EntityId, ComponentType
 9from robolib.utils import RlModelWithTexture, get_project_root, make_radius, ecs_data_as_np
10from robolib.components import HasModel, HasPose, HasFPV
11
12def make_nonserializable_data(components: list[ComponentType], data: dict[str, Any]) -> dict[str, np.ndarray]:
13    """
14    Given the serializable data (e.g. from entity_to_dict()), create the live non-serializable (e.g. gpu model).
15    This is the missing link that allows us to spawn new entities (via world.add_entity).
16    """
17    res = {}
18    for component in components:
19        if component == HasModel:
20            model = RlModelWithTexture.from_path(data["model_path"], data["texture_path"])
21            top_left, bottom_right = model.bbox
22            res["model"] = np.array([model], "object")
23            res["model_bbox"] = np.float32([top_left, bottom_right])
24            res["model_radius"] = np.float32([make_radius(size=bottom_right - top_left)])
25        elif component == HasPose:
26            res["candidate_pose"] = data["pose"].copy()
27        elif component == HasFPV:
28            res["fpv_camera"] = np.array([None], "object")
29            res["fpv_data"] = np.array([None], "object")
30            res["fpv_texture"] = np.array([None], "object")
31    return res
32
33def add_entity(world: World, components: list[ComponentType], **kwargs) -> EntityId:
34    """calls world.make_entity() but only after calling make_nonserializable_data. Bridges robosim with microecs"""
35    for key in ("model_path", "texture_path"): # store portable, root-relative strings
36        if kwargs.get(key) is not None:
37            p = Path(kwargs[key])
38            kwargs[key] = str(p.relative_to(get_project_root()) if p.is_absolute() else p)
39    kwargs = {**kwargs, **make_nonserializable_data(components, kwargs)}
40    field_dtype = {name: dt for c in components
41                    for name, dt in zip(world.component_to_field_names[c], world.component_to_dtypes[c])}
42    entity_data = {k: ecs_data_as_np(v, dtype=field_dtype[k]) for k, v in kwargs.items()}
43    return world.add_entity(components, **entity_data)
def make_nonserializable_data( components: list[type[microecs.component.Component]], data: dict[str, typing.Any]) -> dict[str, numpy.ndarray]:
13def make_nonserializable_data(components: list[ComponentType], data: dict[str, Any]) -> dict[str, np.ndarray]:
14    """
15    Given the serializable data (e.g. from entity_to_dict()), create the live non-serializable (e.g. gpu model).
16    This is the missing link that allows us to spawn new entities (via world.add_entity).
17    """
18    res = {}
19    for component in components:
20        if component == HasModel:
21            model = RlModelWithTexture.from_path(data["model_path"], data["texture_path"])
22            top_left, bottom_right = model.bbox
23            res["model"] = np.array([model], "object")
24            res["model_bbox"] = np.float32([top_left, bottom_right])
25            res["model_radius"] = np.float32([make_radius(size=bottom_right - top_left)])
26        elif component == HasPose:
27            res["candidate_pose"] = data["pose"].copy()
28        elif component == HasFPV:
29            res["fpv_camera"] = np.array([None], "object")
30            res["fpv_data"] = np.array([None], "object")
31            res["fpv_texture"] = np.array([None], "object")
32    return res

Given the serializable data (e.g. from entity_to_dict()), create the live non-serializable (e.g. gpu model). This is the missing link that allows us to spawn new entities (via world.add_entity).

def add_entity( world: microecs.world.World, components: list[type[microecs.component.Component]], **kwargs) -> int:
34def add_entity(world: World, components: list[ComponentType], **kwargs) -> EntityId:
35    """calls world.make_entity() but only after calling make_nonserializable_data. Bridges robosim with microecs"""
36    for key in ("model_path", "texture_path"): # store portable, root-relative strings
37        if kwargs.get(key) is not None:
38            p = Path(kwargs[key])
39            kwargs[key] = str(p.relative_to(get_project_root()) if p.is_absolute() else p)
40    kwargs = {**kwargs, **make_nonserializable_data(components, kwargs)}
41    field_dtype = {name: dt for c in components
42                    for name, dt in zip(world.component_to_field_names[c], world.component_to_dtypes[c])}
43    entity_data = {k: ecs_data_as_np(v, dtype=field_dtype[k]) for k, v in kwargs.items()}
44    return world.add_entity(components, **entity_data)

calls world.make_entity() but only after calling make_nonserializable_data. Bridges robosim with microecs