# srmp API Reference (condensed)

class Pose:
    p: NDArray  # [x, y, z]
    q: NDArray  # [w, x, y, z] quaternion
    def __init__(self, p=None, q=None)
    def __mul__(self, other: Pose) -> Pose
    def inv(self) -> Pose

class GoalType:
    JOINTS: int
    POSE: int

class GoalConstraint:
    def __init__(self, type: int, data: List)  # data is [goal_array]

class Trajectory:
    positions: List[List[float]]
    velocities: List[List[float]]
    times: List[float]

class PlannerInterface:
    # Robot management
    def add_robot(self, robot: str, name=None, planned=True) -> None  # preferred: loads from registry
    def add_articulation(self, name, end_effector, urdf_path, srdf_path="", planned=True) -> None  # manual URDF
    def remove_articulation(self, name) -> None
    def set_base_pose(self, name, pose: Pose) -> None
    # Scene objects
    def add_box(self, name, size, pose=Pose()) -> None
    def add_sphere(self, name, radius, pose=Pose()) -> None
    def add_cylinder(self, name, radius, height, pose=Pose()) -> None
    def add_mesh(self, name, mesh_path="", scale=..., pose=..., convex=False, vertices=None, triangles=None) -> None
    def add_point_cloud(self, name, vertices, resolution=0.01) -> None
    def remove_object(self, name) -> None
    # Queries
    def get_articulation_names(self) -> List[str]
    def get_object_names(self) -> List[str]
    def get_active_joint_names(self, name) -> List[str]
    def get_link_names(self, name) -> List[str]
    def get_link_index(self, name, link_name) -> int
    def has_articulation(self, name) -> bool
    def has_object(self, name) -> bool
    # Kinematics
    def compute_fk(self, name, qpos) -> Pose
    def compute_ik(self, name, ee_pose, init_state) -> Tuple[bool, List[float]]
    def get_link_pose(self, name, link_name) -> Pose
    def set_qpos(self, name, qpos) -> None
    # Collision
    def is_state_colliding(self, name="") -> bool
    def distance_to_collision(self) -> float
    def set_allowed_collision(self, name1, name2, allowed) -> None
    # Attachment
    def attach_object(self, name, art_name, link_id, touch_links=None) -> None
    def detach_object(self, name, also_remove=False) -> bool
    # Planning
    def make_planner(self, articulation_names: List[str], planner_context: Dict[str, str]) -> None
    def plan(self, start, goal_constraint) -> Trajectory
    def plan_multi(self, start_states, goal_constraints) -> Dict[str, Trajectory]
    def reset(self, reset_robots=True) -> None

class ViserPlannerInterface(PlannerInterface):
    def __init__(self, port=8080, share=False)
    def visualize(self, open_browser=True, add_grid=True) -> None
    def animate_trajectory(self, trajectories, dt=0.05, robot_name=None) -> None
    def stop(self) -> None

# Robot Registry
srmp.robots.list_available()  # {'remote': [...], 'local': [...]}
srmp.robots.download(name)
srmp.robots.get(name)  # returns RobotInfo with .urdf_path, .srdf_path, .end_effector
