xinjie.wang
update
1d3e2bd
# Project EmbodiedGen
#
# Copyright (c) 2025 Horizon Robotics. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
from __future__ import annotations
import logging
import sys
import warnings
import tyro
from embodied_gen.skills.spatial_computing.api.floorplan_api import (
FloorplanConfig,
FloorplanManager,
)
warnings.filterwarnings("ignore", category=RuntimeWarning)
logging.basicConfig(
format="%(asctime)s - %(levelname)s - %(message)s",
level=logging.INFO,
force=True,
)
logger = logging.getLogger(__name__)
def _get_gpt_client() -> object | None:
"""Lazy-import GPT_CLIENT for semantic --on_instance resolution."""
try:
from embodied_gen.utils.gpt_clients import GPT_CLIENT
return GPT_CLIENT
except Exception:
return None
def entrypoint(cfg: FloorplanConfig) -> None:
"""Main entry point for floorplan visualization and scene manipulation.
Args:
cfg: Configuration object with all parameters.
"""
manager = FloorplanManager(
urdf_path=cfg.urdf_path,
usd_path=cfg.usd_path,
mesh_sample_num=cfg.mesh_sample_num,
ignore_items=cfg.ignore_items,
)
# List instances/rooms and exit if requested
if cfg.list_instances:
names = manager.get_instance_names()
rooms = manager.get_room_names()
logger.info("instance_names:", names)
logger.info("room_names:", rooms)
return
gpt_client = _get_gpt_client()
on_instance = cfg.on_instance
if on_instance is not None:
resolved = manager.resolve_on_instance(
on_instance, gpt_client=gpt_client
)
if resolved is None:
logger.error(
"No object matched \"%s\"。Current scene instance name: %s。",
on_instance,
manager.get_instance_names(),
)
sys.exit(1)
on_instance = resolved
if resolved != cfg.on_instance:
logger.info("\"%s\" -> \"%s\"", cfg.on_instance, resolved)
in_room = cfg.in_room
if in_room is not None:
resolved = manager.resolve_in_room(in_room, gpt_client=gpt_client)
if resolved is None:
logger.error(
"No room matched \"%s\"。Current scene room names: %s。",
in_room,
manager.get_room_names(),
)
sys.exit(1)
in_room = resolved
if resolved != cfg.in_room:
logger.info("\"%s\" -> \"%s\"", cfg.in_room, resolved)
beside_instance = cfg.beside_instance
if beside_instance is not None:
resolved = manager.resolve_beside_instance(
beside_instance, gpt_client=gpt_client, in_room=in_room
)
if resolved is None:
logger.error(
"No object matched \"%s\"。Current scene instance name: %s。",
beside_instance,
manager.get_instance_names(),
)
sys.exit(1)
beside_instance = resolved
if resolved != cfg.beside_instance:
logger.info("\"%s\" -> \"%s\"", cfg.beside_instance, resolved)
# Add asset instance if specified
center = None
if cfg.asset_path is not None:
center = manager.insert_object(
asset_path=cfg.asset_path,
instance_key=cfg.instance_key,
in_room=in_room,
on_instance=on_instance,
beside_instance=beside_instance,
beside_distance=cfg.beside_distance,
rotation_rpy=cfg.rotation_rpy,
n_max_attempt=cfg.max_placement_attempts,
place_strategy=cfg.place_strategy,
)
if center is not None:
logger.info(
f"Successfully placed '{cfg.instance_key}' at "
f"({center[0]:.3f}, {center[1]:.3f}, {center[2]:.3f})"
)
else:
logger.error(
f"❌ Failed to place '{cfg.instance_key}' in the scene."
)
sys.exit(1)
# Generate floorplan visualization
if cfg.output_path is not None:
manager.visualize(output_path=cfg.output_path)
if __name__ == "__main__":
config = tyro.cli(FloorplanConfig)
entrypoint(config)