From ad912caa11d150161589449771586e3e8301a928 Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Tue, 18 Aug 2026 19:18:28 +0200 Subject: [PATCH 1/8] Multi team sim initial --- .../launch/mujoco_simulation.launch.py | 34 ++----- .../bitbots_mujoco_sim/joint.py | 2 +- .../bitbots_mujoco_sim/robot.py | 4 +- .../bitbots_mujoco_sim/simulation.py | 24 ++--- .../bitbots_mujoco_sim/world.py | 99 +++++++++++++++++++ 5 files changed, 118 insertions(+), 45 deletions(-) create mode 100644 src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py diff --git a/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py b/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py index 39a73f5326..9f93d35ca4 100644 --- a/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py +++ b/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py @@ -3,6 +3,7 @@ import yaml from ament_index_python.packages import get_package_share_directory +from bitbots_mujoco_sim.world import generate_world_xml, parse_num_robots from launch import LaunchDescription from launch.actions import ( DeclareLaunchArgument, @@ -88,32 +89,10 @@ def generate_domain_bridge_config(robot_domain: int, output_dir: Path) -> Path: return config_path -def generate_world_xml(num_robots: int, package_share: str, robot_type: str) -> Path: - """Generate MuJoCo world XML with the correct number of robots.""" - template_path = Path(package_share) / "xml" / "kid_field.xml" - output_path = Path(package_share) / "xml" / "generated_world.xml" - offset = 4 * ( - 1 / num_robots - ) # this makes the offset be the default value when there are 4 robots and increse the less robots there are - - with open(template_path) as f: - template = f.read() - - # Replace placeholder with actual robot count - world_xml = ( - template.replace("{{NUM_ROBOTS}}", str(num_robots)) - .replace("{{OFFSET}}", str(offset)) - .replace("{{ROBOT_TYPE}}", robot_type) - ) - - with open(output_path, "w") as f: - f.write(world_xml) - return output_path - - def launch_setup(context): """Dynamically set up launches based on num_robots.""" - num_robots = int(LaunchConfiguration("num_robots").perform(context)) + num_robots_spec = LaunchConfiguration("num_robots").perform(context) + num_robots = sum(parse_num_robots(num_robots_spec)) # total robots across all teams robot_type = str(LaunchConfiguration("robot_type").perform(context)) package_share = get_package_share_directory("bitbots_mujoco_sim") bridge_config_dir = Path(package_share) / "config" / "domain_bridges" @@ -125,7 +104,7 @@ def launch_setup(context): if value: # Only pass if not empty string teamplayer_args.append(f"{arg_name}:={value}") - world_file = generate_world_xml(num_robots, package_share, robot_type) + world_file = generate_world_xml(num_robots_spec, package_share, robot_type) actions = [] @@ -189,7 +168,10 @@ def generate_launch_description(): DeclareLaunchArgument( "num_robots", default_value="1", - description="Number of robots in the simulation", + description=( + "Robot setup in the simulation. Either a single number for one team " + "(e.g. '3') or a colon separated team setup (e.g. '2:2' for a 2 vs 2)." + ), ), DeclareLaunchArgument( "robot_type", diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/joint.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/joint.py index d5e13e3978..cc730afebb 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/joint.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/joint.py @@ -16,7 +16,7 @@ def __init__( self.ros_name: str = ros_name self.name: str = name if name is not None else ros_name self.joint_instance: int = model.joint(self.name) - self.actuator_instance: int = model.actuator(self.name.replace("_joint_", "_")) + self.actuator_instance: int = model.actuator(self.name.replace("_joint", "")) aid = self.actuator_instance.id self._default_kp: float = float(model.actuator_gainprm[aid, 0]) diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/robot.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/robot.py index e7f51d2a7c..e1eed6e19b 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/robot.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/robot.py @@ -96,7 +96,9 @@ def quaternion_noisy_sensor(base_name: str, ros_name: str) -> QuaternionNoisySen ) def _get_name(self, base_name: str) -> str: - return f"robot_{base_name}_{self.index}" + # Each robot is attached with a unique "robot__" prefix in the world XML, + # so its element names are the prefix followed by the bare model element name. + return f"robot_{self.index}_{base_name}" @property def domain(self) -> int: diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py index 476d9e1489..d91f92b5aa 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py @@ -1,3 +1,4 @@ +import re import time from collections.abc import Callable from pathlib import Path @@ -16,6 +17,7 @@ from bitbots_msgs.msg import JointCommand from bitbots_msgs.srv import MoveBall, SimulatorPush from bitbots_mujoco_sim.robot import Robot +from bitbots_mujoco_sim.world import generate_world_xml BALL_JOINT_NAME = "ball-root" @@ -147,7 +149,7 @@ def _apply_home_keyframe(self) -> None: for robot_sim in self.robots: # Set z spawn height from keyframe while preserving x/y placement and orientation if home_z is not None: - freejoint_name = f"robot_floating_base_joint_{robot_sim.robot.index}" + freejoint_name = f"robot_{robot_sim.robot.index}_floating_base_joint" freejoint_id = mujoco.mj_name2id(self.model, mujoco.mjtObj.mjOBJ_JOINT, freejoint_name) if freejoint_id >= 0: self.data.qpos[self.model.joint(freejoint_id).qposadr[0] + 2] = home_z @@ -163,25 +165,13 @@ def _apply_home_keyframe(self) -> None: mujoco.mj_forward(self.model, self.data) def _generate_default_world(self) -> str: - template_path = Path(self.package_path) / "xml" / "kid_field.xml" - output_path = Path(self.package_path) / "xml" / "generated_world.xml" - with open(template_path) as f: - template = f.read() - world_xml = ( - template.replace("{{NUM_ROBOTS}}", "1").replace("{{OFFSET}}", "6.0").replace("{{ROBOT_TYPE}}", "piplus") - ) - with open(output_path, "w") as f: - f.write(world_xml) - return str(output_path) + return str(generate_world_xml("1", self.package_path, "piplus")) def _find_robot_indices(self) -> list[int]: - """Find all robot instances by looking for bodies named 'robot_base_link_X'.""" + """Find all robot instances by looking for bodies named 'robot__base_link'.""" body_names = [self.model.body(i).name for i in range(self.model.nbody)] - return sorted( - int(name.split("_")[-1]) - for name in body_names - if name.startswith("robot_base_link_") and name.split("_")[-1].isdigit() - ) + pattern = re.compile(r"^robot_(\d+)_base_link$") + return sorted(int(match.group(1)) for name in body_names if (match := pattern.match(name))) def _key_callback(self, key: int) -> None: # Exceptions in this callback completly deadlock the process. diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py new file mode 100644 index 0000000000..5afeb31640 --- /dev/null +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py @@ -0,0 +1,99 @@ +"""Utilities for generating the MuJoCo world XML with a configurable robot setup. + +The ``kid_field.xml`` template positions robots with a single ```` +element that clones one robot with a uniform offset. That is not flexible enough +to place robots for a team versus team setup. Instead of encoding the placement +in the template, we parse the template, drop the ```` element and +insert one ```` per robot so that every robot can be positioned +individually. +""" + +import xml.etree.ElementTree as ET +from pathlib import Path + +# Robots of a team are lined up parallel to the goal line, offset from the field +# center along the y-axis. The value mirrors the sideline offset that was +# previously baked into the single-team template. +TEAM_LINE_Y = 3.25 +# Distance between adjacent robots within a single team row, along the x-axis. +ROBOT_ROW_SPACING = 1.0 +# Yaw (rotation about z) that makes a robot on the negative-y line face the field +# center. Robots on the positive-y line face the opposite direction. +FACING_YAW = 1.57 + + +def parse_num_robots(num_robots: str | int) -> list[int]: + """Parse a ``num_robots`` specification into per-team robot counts. + + Accepts either a single number (e.g. ``"3"`` -> a single team of three + robots) or a colon separated team setup (e.g. ``"2:2"`` -> two teams of two + robots each). Returns the robot count of every team in order. + """ + teams = [int(part) for part in str(num_robots).split(":")] + if any(count < 0 for count in teams) or sum(teams) < 1: + raise ValueError(f"Invalid num_robots specification: {num_robots!r}") + return teams + + +def compute_robot_poses(teams: list[int]) -> list[tuple[float, float, float]]: + """Compute the ``(x, y, yaw)`` placement for every robot. + + Robots of a team are spread along the x-axis and centered on x=0. With more + than one team the teams are distributed across the width of the field along + the y-axis and turned to face each other. The returned poses are ordered team + by team, matching the order of ``teams``. + """ + poses: list[tuple[float, float, float]] = [] + num_teams = len(teams) + for team_index, count in enumerate(teams): + if num_teams == 1: + y = -TEAM_LINE_Y + else: + # Distribute the teams evenly between the two team lines. + fraction = team_index / (num_teams - 1) + y = -TEAM_LINE_Y + fraction * (2 * TEAM_LINE_Y) + # Robots on (or below) the center line face +y, the others face -y. + yaw = FACING_YAW if y <= 0 else -FACING_YAW + for robot_in_team in range(count): + x = (robot_in_team - (count - 1) / 2.0) * ROBOT_ROW_SPACING + poses.append((x, y, yaw)) + return poses + + +def _find_replicate(root: ET.Element) -> tuple[ET.Element, ET.Element]: + """Return the ```` element and its parent from the world tree.""" + for parent in root.iter(): + for child in parent: + if child.tag == "replicate": + return parent, child + raise ValueError("No element found in world template") + + +def generate_world_xml(num_robots: str | int, package_share: str, robot_type: str) -> Path: + """Generate the MuJoCo world XML positioning every robot individually. + + The ```` element of the template is replaced by one ```` per + robot, each attaching the robot model at its computed pose. Every robot gets a + unique attach prefix (``robot__``) so that the resulting body names stay + unique and can be discovered by the simulation. + + Returns the path of the generated world file. + """ + template_path = Path(package_share) / "xml" / "kid_field.xml" + output_path = Path(package_share) / "xml" / "generated_world.xml" + + poses = compute_robot_poses(parse_num_robots(num_robots)) + + tree = ET.parse(template_path) + replicate_parent, replicate = _find_replicate(tree.getroot()) + insert_index = list(replicate_parent).index(replicate) + replicate_parent.remove(replicate) + + for robot_index, (x, y, yaw) in enumerate(poses): + frame = ET.Element("frame", {"pos": f"{x} {y} 0.0", "euler": f"0 0 {yaw}"}) + ET.SubElement(frame, "attach", {"model": robot_type, "prefix": f"robot_{robot_index}_"}) + replicate_parent.insert(insert_index, frame) + insert_index += 1 + + tree.write(output_path, encoding="unicode", xml_declaration=False) + return output_path From 3e967be5c1d52b5defc373644920953f79c5f018 Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Thu, 20 Aug 2026 17:33:58 +0200 Subject: [PATCH 2/8] Move game_settings determination into mujoco_simulation.launch.py --- .gitignore | 1 + .../launch/mujoco_simulation.launch.py | 62 ++++++++++++++++++- .../bitbots_bringup/launch/teamplayer.launch | 12 ++++ .../config/sim_game_settings_11.yaml | 5 -- .../config/sim_game_settings_12.yaml | 5 -- .../config/sim_game_settings_13.yaml | 5 -- .../config/sim_game_settings_14.yaml | 5 -- .../launch/parameter_blackboard.launch.py | 43 ++++++++++--- 8 files changed, 107 insertions(+), 31 deletions(-) delete mode 100644 src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_11.yaml delete mode 100644 src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_12.yaml delete mode 100644 src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_13.yaml delete mode 100644 src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_14.yaml diff --git a/.gitignore b/.gitignore index 64ba98fc85..5b6f1d5bac 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ .idea/workspace.xml .idea/tasks.xml .idea/* +.junie/ **/.idea/ **/cmake-build-debug/ diff --git a/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py b/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py index 9f93d35ca4..1513bc61b3 100644 --- a/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py +++ b/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py @@ -35,6 +35,52 @@ ("tts", "Whether to speak"), ] +# Role assigned to a robot based on its position within a team (0-based). A team +# has at most 3 offense, 3 defense and 1 goalie players (7 players total). Roles +# are filled in this fixed order, and the position_number within each of the +# offense/defense groups is assigned in the order the robots appear (0, 1, 2). +TEAM_ROLE_ORDER = ["offense", "goalie", "defense", "defense", "defense", "offense", "offense"] +# team_id used for the first team. Every additional team increments from here. +# The value stays within the allowed team_id range (see game_settings_options.yaml). +BASE_TEAM_ID = 6 + + +def compute_game_settings(teams: list[int]) -> list[dict]: + """Compute the per-robot game settings for a team setup. + + Given the per-team robot counts (e.g. ``[2, 2]`` for a 2 vs 2), this returns + one dict of game settings per robot, ordered team by team. ``bot_id`` is unique + within a team (1-based) while ``team_id``/``team_color`` identify the team, so + any team layout works without hand-maintained per-robot config files. + + Roles are assigned per team following ``TEAM_ROLE_ORDER`` and the + ``position_number`` is counted separately per role group so that it is never + duplicated within a team (e.g. the three offense players get positions 0, 1, 2). + """ + settings: list[dict] = [] + for team_index, count in enumerate(teams): + if count > len(TEAM_ROLE_ORDER): + raise ValueError( + f"Team {team_index} has {count} robots, but at most {len(TEAM_ROLE_ORDER)} players per team are supported" + ) + # Count how many robots of each role were already assigned within this team + # to derive a unique position_number per role group. + role_position_counters: dict[str, int] = {} + for robot_in_team in range(count): + role = TEAM_ROLE_ORDER[robot_in_team] + position_number = role_position_counters.get(role, 0) + role_position_counters[role] = position_number + 1 + settings.append( + { + "bot_id": robot_in_team + 1, + "team_id": BASE_TEAM_ID + team_index, + "team_color": team_index % 2, + "role": role, + "position_number": position_number, + } + ) + return settings + def generate_domain_bridge_config(robot_domain: int, output_dir: Path) -> Path: """Generate domain bridge config file for a single robot. @@ -106,6 +152,11 @@ def launch_setup(context): world_file = generate_world_xml(num_robots_spec, package_share, robot_type) + # Compute individual game settings for every robot so that each robot gets its + # own team affiliation, bot id and role instead of relying on hand-written + # per-domain config files. Ordered the same as the robot domains below. + game_settings = compute_game_settings(parse_num_robots(num_robots_spec)) + actions = [] actions.append( @@ -122,7 +173,8 @@ def launch_setup(context): ), ) - for robot_domain in range(11, num_robots + 11): # 11 is the standart starting id for our robots + # 11 is the standard starting id for our robots + for robot_index, robot_domain in enumerate(range(11, num_robots + 11)): config_file = generate_domain_bridge_config(robot_domain, bridge_config_dir) actions.append( LogInfo(msg=f"Starting domain bridge for robot{robot_domain} (domain {robot_domain})"), @@ -138,6 +190,11 @@ def launch_setup(context): ), ) + # Pass this robot's individual game settings down to the teamplayer stack, + # where parameter_blackboard.launch.py applies them on top of the shared + # game_settings.yaml defaults. + robot_game_settings_args = [f"{key}:={value}" for key, value in game_settings[robot_index].items()] + actions.append( TimerAction( period=3.0, @@ -150,7 +207,8 @@ def launch_setup(context): "bitbots_bringup", "teamplayer.launch", ] - + teamplayer_args, + + teamplayer_args + + robot_game_settings_args, output="screen", additional_env={"ROS_DOMAIN_ID": str(robot_domain)}, ), diff --git a/src/bitbots_misc/bitbots_bringup/launch/teamplayer.launch b/src/bitbots_misc/bitbots_bringup/launch/teamplayer.launch index 4ee7d0a9e4..040cdf246e 100644 --- a/src/bitbots_misc/bitbots_bringup/launch/teamplayer.launch +++ b/src/bitbots_misc/bitbots_bringup/launch/teamplayer.launch @@ -19,11 +19,23 @@ + + + + + + + + + + + + diff --git a/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_11.yaml b/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_11.yaml deleted file mode 100644 index f8649a5159..0000000000 --- a/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_11.yaml +++ /dev/null @@ -1,5 +0,0 @@ -parameter_blackboard: - ros__parameters: - bot_id: 1 - position_number: 0 - role: offense diff --git a/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_12.yaml b/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_12.yaml deleted file mode 100644 index 437d64089b..0000000000 --- a/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_12.yaml +++ /dev/null @@ -1,5 +0,0 @@ -parameter_blackboard: - ros__parameters: - bot_id: 2 - position_number: 0 - role: goalie diff --git a/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_13.yaml b/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_13.yaml deleted file mode 100644 index 32505c3bab..0000000000 --- a/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_13.yaml +++ /dev/null @@ -1,5 +0,0 @@ -parameter_blackboard: - ros__parameters: - bot_id: 3 - position_number: 0 - role: defense diff --git a/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_14.yaml b/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_14.yaml deleted file mode 100644 index 7116cb8607..0000000000 --- a/src/bitbots_misc/bitbots_parameter_blackboard/config/sim_game_settings_14.yaml +++ /dev/null @@ -1,5 +0,0 @@ -parameter_blackboard: - ros__parameters: - bot_id: 4 - position_number: 1 - role: defense diff --git a/src/bitbots_misc/bitbots_parameter_blackboard/launch/parameter_blackboard.launch.py b/src/bitbots_misc/bitbots_parameter_blackboard/launch/parameter_blackboard.launch.py index 2cacbbe705..ec1daf7afd 100644 --- a/src/bitbots_misc/bitbots_parameter_blackboard/launch/parameter_blackboard.launch.py +++ b/src/bitbots_misc/bitbots_parameter_blackboard/launch/parameter_blackboard.launch.py @@ -1,7 +1,5 @@ from __future__ import annotations -import os - from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, OpaqueFunction @@ -10,6 +8,18 @@ from launch_ros.actions import Node from launch_ros.parameter_descriptions import ParameterFile +# Per-robot game settings that may be provided as launch arguments (e.g. by the +# multi-robot simulation launch) to override the shared ``game_settings.yaml`` +# defaults. Each entry maps the launch argument name to the type its value should +# be cast to before it is passed to the parameter blackboard. +GAME_SETTING_OVERRIDES = { + "bot_id": int, + "team_id": int, + "team_color": int, + "role": str, + "position_number": int, +} + def generate_launch_description() -> LaunchDescription: package_name = "bitbots_parameter_blackboard" @@ -28,13 +38,17 @@ def create_node(context, *args, **kwargs): ParameterFile(PathJoinSubstitution([package_share, "config", "game_settings.yaml"])), ] - robot_domain = os.environ.get("ROS_DOMAIN_ID") - if in_sim and robot_domain is not None: - parameters.append( - ParameterFile( - PathJoinSubstitution([package_share, "config", f"sim_game_settings_{int(robot_domain)}.yaml"]) - ) - ) + # Per-robot game settings can be injected as launch arguments. They are + # applied after ``game_settings.yaml`` so that explicitly provided values + # win over the shared defaults. Unset arguments (empty string) are ignored + # and keep the shared default. + overrides = {} + for arg_name, cast in GAME_SETTING_OVERRIDES.items(): + value = LaunchConfiguration(arg_name).perform(context) + if value != "": + overrides[arg_name] = cast(value) + if overrides: + parameters.append(overrides) return [ Node( @@ -55,6 +69,17 @@ def create_node(context, *args, **kwargs): default_value=PythonExpression(["'hsl_kid' if '", sim, "' == 'true' else 'labor'"]), description="Field name to load parameters for.", ), + *[ + DeclareLaunchArgument( + arg_name, + default_value="", + description=( + f"Per-robot override for the '{arg_name}' game setting. " + "Leave empty to use the shared game_settings.yaml default." + ), + ) + for arg_name in GAME_SETTING_OVERRIDES + ], IncludeLaunchDescription( AnyLaunchDescriptionSource( PathJoinSubstitution([get_package_share_directory("bitbots_utils"), "launch", "welcome.launch"]) From 9ea9474220aa98157e82f4ccc3c765f1b624f755 Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Thu, 20 Aug 2026 18:51:03 +0200 Subject: [PATCH 3/8] Position robots among the side lines --- .../launch/mujoco_simulation.launch.py | 48 +------ .../bitbots_mujoco_sim/world.py | 127 +++++++++++++++--- 2 files changed, 106 insertions(+), 69 deletions(-) diff --git a/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py b/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py index 1513bc61b3..523eb80b07 100644 --- a/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py +++ b/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py @@ -3,7 +3,7 @@ import yaml from ament_index_python.packages import get_package_share_directory -from bitbots_mujoco_sim.world import generate_world_xml, parse_num_robots +from bitbots_mujoco_sim.world import compute_game_settings, generate_world_xml, parse_num_robots from launch import LaunchDescription from launch.actions import ( DeclareLaunchArgument, @@ -35,52 +35,6 @@ ("tts", "Whether to speak"), ] -# Role assigned to a robot based on its position within a team (0-based). A team -# has at most 3 offense, 3 defense and 1 goalie players (7 players total). Roles -# are filled in this fixed order, and the position_number within each of the -# offense/defense groups is assigned in the order the robots appear (0, 1, 2). -TEAM_ROLE_ORDER = ["offense", "goalie", "defense", "defense", "defense", "offense", "offense"] -# team_id used for the first team. Every additional team increments from here. -# The value stays within the allowed team_id range (see game_settings_options.yaml). -BASE_TEAM_ID = 6 - - -def compute_game_settings(teams: list[int]) -> list[dict]: - """Compute the per-robot game settings for a team setup. - - Given the per-team robot counts (e.g. ``[2, 2]`` for a 2 vs 2), this returns - one dict of game settings per robot, ordered team by team. ``bot_id`` is unique - within a team (1-based) while ``team_id``/``team_color`` identify the team, so - any team layout works without hand-maintained per-robot config files. - - Roles are assigned per team following ``TEAM_ROLE_ORDER`` and the - ``position_number`` is counted separately per role group so that it is never - duplicated within a team (e.g. the three offense players get positions 0, 1, 2). - """ - settings: list[dict] = [] - for team_index, count in enumerate(teams): - if count > len(TEAM_ROLE_ORDER): - raise ValueError( - f"Team {team_index} has {count} robots, but at most {len(TEAM_ROLE_ORDER)} players per team are supported" - ) - # Count how many robots of each role were already assigned within this team - # to derive a unique position_number per role group. - role_position_counters: dict[str, int] = {} - for robot_in_team in range(count): - role = TEAM_ROLE_ORDER[robot_in_team] - position_number = role_position_counters.get(role, 0) - role_position_counters[role] = position_number + 1 - settings.append( - { - "bot_id": robot_in_team + 1, - "team_id": BASE_TEAM_ID + team_index, - "team_color": team_index % 2, - "role": role, - "position_number": position_number, - } - ) - return settings - def generate_domain_bridge_config(robot_domain: int, output_dir: Path) -> Path: """Generate domain bridge config file for a single robot. diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py index 5afeb31640..945f02afe8 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py @@ -11,16 +11,47 @@ import xml.etree.ElementTree as ET from pathlib import Path -# Robots of a team are lined up parallel to the goal line, offset from the field -# center along the y-axis. The value mirrors the sideline offset that was -# previously baked into the single-team template. -TEAM_LINE_Y = 3.25 -# Distance between adjacent robots within a single team row, along the x-axis. -ROBOT_ROW_SPACING = 1.0 -# Yaw (rotation about z) that makes a robot on the negative-y line face the field -# center. Robots on the positive-y line face the opposite direction. +# Sideline offset from the field center along the y-axis. +SIDELINE_Y = 3.25 +# Backward compatibility alias +TEAM_LINE_Y = SIDELINE_Y + +# Half dimensions of the field (length 9m -> half length 4.5m). +HALF_FIELD_LENGTH = 4.5 + +# Yaw (rotation about z) to make a robot face inward towards the field center. +# A robot on the negative-y sideline faces +y; on the positive-y sideline it faces -y. FACING_YAW = 1.57 +# Role assigned to a robot based on its position within a team (0-based). A team +# has at most 3 offense, 3 defense and 1 goalie players (7 players total). Roles +# are filled in this fixed order, and the position_number within each of the +# offense/defense groups is assigned in the order the robots appear (0, 1, 2). +TEAM_ROLE_ORDER = ["offense", "goalie", "defense", "defense", "defense", "offense", "offense"] + +# Default team ID for the first team. Additional teams increment from here. +BASE_TEAM_ID = 6 + +# Fixed placement along the sideline for team 0 (defending x in [-4.5, 0], facing +x). +# Offense is placed at the front (near x=0), goalie at the back (near x=-4.5), and +# defenders in the middle. Position 1 (left) goes to the left sideline (+y), +# position 2 (right) goes to the right sideline (-y), and center (position 0) +# positions are distributed across sides (offense/goalie right, defense left). +# All positions leave >= 0.5m space from the borders of the half (-4.5 and 0.0). +# Formatted as: (role, position_number) -> (x_pos, side) where side is "left" or "right". +_ROLE_PLACEMENTS_TEAM_0: dict[tuple[str, int], tuple[float, str]] = { + # Offense (front): position 0 = center (right side), 1 = left, 2 = right + ("offense", 0): (-0.6, "right"), + ("offense", 1): (-0.6, "left"), + ("offense", 2): (-1.2, "right"), + # Goalie (back): position 0 = right side + ("goalie", 0): (-3.9, "right"), + # Defense (middle): position 0 = center (left side), 1 = left, 2 = right + ("defense", 0): (-2.6, "left"), + ("defense", 1): (-2.3, "left"), + ("defense", 2): (-2.0, "right"), +} + def parse_num_robots(num_robots: str | int) -> list[int]: """Parse a ``num_robots`` specification into per-team robot counts. @@ -35,28 +66,80 @@ def parse_num_robots(num_robots: str | int) -> list[int]: return teams +def compute_game_settings(teams: list[int]) -> list[dict]: + """Compute the per-robot game settings for a team setup. + + Given the per-team robot counts (e.g. ``[2, 2]`` for a 2 vs 2), this returns + one dict of game settings per robot, ordered team by team. ``bot_id`` is unique + within a team (1-based) while ``team_id``/``team_color`` identify the team, so + any team layout works without hand-maintained per-robot config files. + + Roles are assigned per team following ``TEAM_ROLE_ORDER`` and the + ``position_number`` is counted separately per role group so that it is never + duplicated within a team (e.g. the three offense players get positions 0, 1, 2). + """ + settings: list[dict] = [] + for team_index, count in enumerate(teams): + if count > len(TEAM_ROLE_ORDER): + raise ValueError( + f"Team {team_index} has {count} robots, but at most {len(TEAM_ROLE_ORDER)} players per team are supported" + ) + role_position_counters: dict[str, int] = {} + for robot_in_team in range(count): + role = TEAM_ROLE_ORDER[robot_in_team] + position_number = role_position_counters.get(role, 0) + role_position_counters[role] = position_number + 1 + settings.append( + { + "bot_id": robot_in_team + 1, + "team_id": BASE_TEAM_ID + team_index, + "team_color": team_index % 2, + "role": role, + "position_number": position_number, + } + ) + return settings + + def compute_robot_poses(teams: list[int]) -> list[tuple[float, float, float]]: """Compute the ``(x, y, yaw)`` placement for every robot. - Robots of a team are spread along the x-axis and centered on x=0. With more - than one team the teams are distributed across the width of the field along - the y-axis and turned to face each other. The returned poses are ordered team - by team, matching the order of ``teams``. + Robots are positioned on the sidelines of their own half. Offense players are + placed to the front (near midfield), the goalie to the back (near goal line), + and defenders in the middle. Role position 1 is left and position 2 is right + (relative to local team orientation), while position 0 is placed on the side. + All positions keep at least 0.5m clearance from the borders of the half. + + For team 0 (defending negative x half, facing +x), left is +y and right is -y. + For team 1 (defending positive x half, facing -x), poses are mirrored across + the field origin (left is -y and right is +y). """ poses: list[tuple[float, float, float]] = [] - num_teams = len(teams) + game_settings = compute_game_settings(teams) + for team_index, count in enumerate(teams): - if num_teams == 1: - y = -TEAM_LINE_Y - else: - # Distribute the teams evenly between the two team lines. - fraction = team_index / (num_teams - 1) - y = -TEAM_LINE_Y + fraction * (2 * TEAM_LINE_Y) - # Robots on (or below) the center line face +y, the others face -y. - yaw = FACING_YAW if y <= 0 else -FACING_YAW + # Determine team offset in the flat game_settings list + team_start = sum(teams[:team_index]) for robot_in_team in range(count): - x = (robot_in_team - (count - 1) / 2.0) * ROBOT_ROW_SPACING + setting = game_settings[team_start + robot_in_team] + role = setting["role"] + pos_num = setting["position_number"] + + x_base, side = _ROLE_PLACEMENTS_TEAM_0[(role, pos_num)] + + if team_index % 2 == 0: + # Team 0: defending -x half, facing +x + x = x_base + y = SIDELINE_Y if side == "left" else -SIDELINE_Y + else: + # Team 1: defending +x half, facing -x (mirrored across origin) + x = -x_base + y = -SIDELINE_Y if side == "left" else SIDELINE_Y + + # Facing angle: turn towards field center (y = 0) + yaw = FACING_YAW if y < 0 else -FACING_YAW poses.append((x, y, yaw)) + return poses From b84004f936b3b88d633666b39edc5dbecaf1160f Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Thu, 20 Aug 2026 20:11:03 +0200 Subject: [PATCH 4/8] Fix parameters not being loaded correctly --- .../bitbots_parameter_blackboard/config/game_settings.yaml | 2 +- .../launch/parameter_blackboard.launch.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitbots_misc/bitbots_parameter_blackboard/config/game_settings.yaml b/src/bitbots_misc/bitbots_parameter_blackboard/config/game_settings.yaml index 851517592b..36f1533679 100644 --- a/src/bitbots_misc/bitbots_parameter_blackboard/config/game_settings.yaml +++ b/src/bitbots_misc/bitbots_parameter_blackboard/config/game_settings.yaml @@ -1,4 +1,4 @@ -parameter_blackboard: +/parameter_blackboard: ros__parameters: bot_id: 1 monitoring_host_ip: 0.0.0.0 diff --git a/src/bitbots_misc/bitbots_parameter_blackboard/launch/parameter_blackboard.launch.py b/src/bitbots_misc/bitbots_parameter_blackboard/launch/parameter_blackboard.launch.py index ec1daf7afd..7428401792 100644 --- a/src/bitbots_misc/bitbots_parameter_blackboard/launch/parameter_blackboard.launch.py +++ b/src/bitbots_misc/bitbots_parameter_blackboard/launch/parameter_blackboard.launch.py @@ -57,6 +57,7 @@ def create_node(context, *args, **kwargs): name="parameter_blackboard", arguments=["--ros-args", "--log-level", "WARN"], parameters=parameters, + namespace="/", ) ] From b09a3ca84b6ee8a1ce14e2c3a9d544f63afa3368 Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Thu, 20 Aug 2026 22:25:59 +0200 Subject: [PATCH 5/8] Small temporary changes --- pixi.lock | 91 +++++++++++-------- pixi.toml | 1 + .../launch/mujoco_simulation.launch.py | 45 +++++---- .../launch/simulator_teamplayer.launch | 3 +- .../bitbots_mujoco_sim/simulation.py | 2 +- 5 files changed, 84 insertions(+), 58 deletions(-) diff --git a/pixi.lock b/pixi.lock index d0e75f9beb..a5e309688c 100644 --- a/pixi.lock +++ b/pixi.lock @@ -554,6 +554,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pep517-0.13.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.12-unix_hf108a03_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/playsound-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda @@ -1005,7 +1006,7 @@ environments: - conda: https://data.bit-bots.de/conda-misc/output/noarch/bitbots_model_2026_07_02_flo_yoeo_rf_detr_wm_torso_extension-1.1.0-h4616a5c_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/readline-8.3-h4616a5c_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/tts-supertonic-1.0.0-h4616a5c_1.conda - - conda_source: bitbots_rust_nav[146a3083] @ src/bitbots_navigation/bitbots_rust_nav + - conda_source: bitbots_rust_nav[5e7b7ba8] @ src/bitbots_navigation/bitbots_rust_nav - pypi: https://files.pythonhosted.org/packages/05/98/716a473cfb24750858ddd5d14e6527539dd206583a46408d08eeb2844a75/trimesh-4.12.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/de/0880cf8af64b225bc8fde0924f76ea5e6cd8d8dc50c6dd61232beb54327f/mjviser-0.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl @@ -1543,6 +1544,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pep517-0.13.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.12-unix_hf108a03_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/playsound-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda @@ -1994,7 +1996,7 @@ environments: - conda: https://data.bit-bots.de/conda-misc/output/noarch/bitbots_model_2026_07_02_flo_yoeo_rf_detr_wm_torso_extension-1.1.0-h4616a5c_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/readline-8.3-h4616a5c_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/tts-supertonic-1.0.0-h4616a5c_1.conda - - conda_source: bitbots_rust_nav[36aa2fce] @ src/bitbots_navigation/bitbots_rust_nav + - conda_source: bitbots_rust_nav[a130a192] @ src/bitbots_navigation/bitbots_rust_nav - pypi: https://files.pythonhosted.org/packages/05/98/716a473cfb24750858ddd5d14e6527539dd206583a46408d08eeb2844a75/trimesh-4.12.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/de/0880cf8af64b225bc8fde0924f76ea5e6cd8d8dc50c6dd61232beb54327f/mjviser-0.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl @@ -2061,6 +2063,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.12-unix_hf108a03_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.6.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-3.0-pyhcf101f3_0.conda @@ -2121,6 +2124,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.12-unix_hf108a03_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.6.0-pyha770c72_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-3.0-pyhcf101f3_0.conda @@ -2675,6 +2679,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pep517-0.13.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.12-unix_hf108a03_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/playsound-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda @@ -3129,7 +3134,7 @@ environments: - conda: https://data.bit-bots.de/conda-misc/output/noarch/bitbots_model_2026_07_02_flo_yoeo_rf_detr_wm_torso_extension-1.1.0-h4616a5c_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/readline-8.3-h4616a5c_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/tts-supertonic-1.0.0-h4616a5c_1.conda - - conda_source: bitbots_rust_nav[146a3083] @ src/bitbots_navigation/bitbots_rust_nav + - conda_source: bitbots_rust_nav[5e7b7ba8] @ src/bitbots_navigation/bitbots_rust_nav - pypi: https://files.pythonhosted.org/packages/05/98/716a473cfb24750858ddd5d14e6527539dd206583a46408d08eeb2844a75/trimesh-4.12.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/de/0880cf8af64b225bc8fde0924f76ea5e6cd8d8dc50c6dd61232beb54327f/mjviser-0.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl @@ -3668,6 +3673,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/pathspec-1.1.1-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pep517-0.13.0-pyhd8ed1ab_0.tar.bz2 - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.12-unix_hf108a03_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/playsound-1.3.0-pyhd8ed1ab_1.conda - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda @@ -4122,7 +4128,7 @@ environments: - conda: https://data.bit-bots.de/conda-misc/output/noarch/bitbots_model_2026_07_02_flo_yoeo_rf_detr_wm_torso_extension-1.1.0-h4616a5c_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/readline-8.3-h4616a5c_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/tts-supertonic-1.0.0-h4616a5c_1.conda - - conda_source: bitbots_rust_nav[36aa2fce] @ src/bitbots_navigation/bitbots_rust_nav + - conda_source: bitbots_rust_nav[a130a192] @ src/bitbots_navigation/bitbots_rust_nav - pypi: https://files.pythonhosted.org/packages/05/98/716a473cfb24750858ddd5d14e6527539dd206583a46408d08eeb2844a75/trimesh-4.12.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/de/0880cf8af64b225bc8fde0924f76ea5e6cd8d8dc50c6dd61232beb54327f/mjviser-0.0.12-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/15/efef5a2f204a64bdb5571e6161d49f7ef0fffdbca953a615efbec045f60f/zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl @@ -4184,7 +4190,7 @@ packages: license: MIT AND Apache-2.0 license_family: Apache purls: - - pkg:pypi/aiohttp?source=compressed-mapping + - pkg:pypi/aiohttp?source=hash-mapping run_exports: {} size: 1078273 timestamp: 1780913823270 @@ -4328,7 +4334,7 @@ packages: - zstd >=1.5.7,<1.6.0a0 license: BSD-3-Clause AND MIT AND EPL-2.0 purls: - - pkg:pypi/backports-zstd?source=compressed-mapping + - pkg:pypi/backports-zstd?source=hash-mapping run_exports: {} size: 239892 timestamp: 1781450817988 @@ -8772,8 +8778,7 @@ packages: - tornado >=5 license: PSF-2.0 license_family: PSF - purls: - - pkg:pypi/matplotlib?source=compressed-mapping + purls: [] run_exports: {} size: 14887 timestamp: 1782829550796 @@ -8805,7 +8810,7 @@ packages: license: PSF-2.0 license_family: PSF purls: - - pkg:pypi/matplotlib?source=compressed-mapping + - pkg:pypi/matplotlib?source=hash-mapping run_exports: {} size: 8877024 timestamp: 1782829532714 @@ -8878,7 +8883,7 @@ packages: license: Apache-2.0 license_family: APACHE purls: - - pkg:pypi/msgpack?source=compressed-mapping + - pkg:pypi/msgpack?source=hash-mapping run_exports: {} size: 112800 timestamp: 1782460774570 @@ -10590,7 +10595,7 @@ packages: license: Apache-2.0 license_family: Apache purls: - - pkg:pypi/tornado?source=compressed-mapping + - pkg:pypi/tornado?source=hash-mapping run_exports: {} size: 864705 timestamp: 1781006801632 @@ -10853,7 +10858,7 @@ packages: license: BSD-2-Clause license_family: BSD purls: - - pkg:pypi/wrapt?source=compressed-mapping + - pkg:pypi/wrapt?source=hash-mapping run_exports: {} size: 115842 timestamp: 1782133640094 @@ -17853,7 +17858,7 @@ packages: license: BSD-2-Clause license_family: BSD purls: - - pkg:pypi/wrapt?source=compressed-mapping + - pkg:pypi/wrapt?source=hash-mapping run_exports: {} size: 115536 timestamp: 1782133697736 @@ -18530,7 +18535,7 @@ packages: license: PSF-2.0 license_family: PSF purls: - - pkg:pypi/aiohappyeyeballs?source=compressed-mapping + - pkg:pypi/aiohappyeyeballs?source=hash-mapping run_exports: {} size: 24690 timestamp: 1782986823268 @@ -18569,7 +18574,7 @@ packages: license: Apache-2.0 license_family: APACHE purls: - - pkg:pypi/argcomplete?source=compressed-mapping + - pkg:pypi/argcomplete?source=hash-mapping run_exports: {} size: 46445 timestamp: 1782888485558 @@ -18690,7 +18695,7 @@ packages: - python >=3.10 license: ISC purls: - - pkg:pypi/certifi?source=compressed-mapping + - pkg:pypi/certifi?source=hash-mapping run_exports: {} size: 133877 timestamp: 1781719949728 @@ -18728,7 +18733,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/click?source=compressed-mapping + - pkg:pypi/click?source=hash-mapping run_exports: {} size: 104999 timestamp: 1779900548735 @@ -18874,7 +18879,7 @@ packages: license: Apache-2.0 license_family: APACHE purls: - - pkg:pypi/colcon-output?source=compressed-mapping + - pkg:pypi/colcon-output?source=hash-mapping run_exports: {} size: 21527 timestamp: 1782140571074 @@ -19099,7 +19104,7 @@ packages: license: Apache-2.0 license_family: APACHE purls: - - pkg:pypi/distlib?source=compressed-mapping + - pkg:pypi/distlib?source=hash-mapping run_exports: {} size: 303705 timestamp: 1781320269259 @@ -19219,7 +19224,7 @@ packages: - python >=3.10 license: Unlicense purls: - - pkg:pypi/filelock?source=compressed-mapping + - pkg:pypi/filelock?source=hash-mapping run_exports: {} size: 38993 timestamp: 1783063554943 @@ -19394,7 +19399,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/fsspec?source=compressed-mapping + - pkg:pypi/fsspec?source=hash-mapping run_exports: {} size: 149709 timestamp: 1781615868173 @@ -19459,7 +19464,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/hpack?source=compressed-mapping + - pkg:pypi/hpack?source=hash-mapping run_exports: {} size: 32884 timestamp: 1782283986153 @@ -19510,7 +19515,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/idna?source=compressed-mapping + - pkg:pypi/idna?source=hash-mapping run_exports: {} size: 163869 timestamp: 1781620148226 @@ -19536,7 +19541,7 @@ packages: license: Apache-2.0 license_family: APACHE purls: - - pkg:pypi/importlib-metadata?source=compressed-mapping + - pkg:pypi/importlib-metadata?source=hash-mapping run_exports: {} size: 34766 timestamp: 1779714582554 @@ -19600,7 +19605,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/ipython?source=compressed-mapping + - pkg:pypi/ipython?source=hash-mapping run_exports: {} size: 658801 timestamp: 1782482716877 @@ -19651,7 +19656,7 @@ packages: - python license: Apache-2.0 AND MIT purls: - - pkg:pypi/jedi?source=compressed-mapping + - pkg:pypi/jedi?source=hash-mapping run_exports: {} size: 2715215 timestamp: 1782251948616 @@ -19994,6 +19999,18 @@ packages: run_exports: {} size: 53561 timestamp: 1733302019362 +- conda: https://conda.anaconda.org/conda-forge/noarch/pixi-pycharm-0.0.12-unix_hf108a03_0.conda + sha256: 66cd439b83657c2728d0e45e4e40d140eb33dd22b61b045b23f922cae51bb503 + md5: a92eadbeec2c489f209382433acf14a5 + depends: + - __unix + - python >=3.8 + license: BSD-3-Clause + license_family: BSD + purls: [] + run_exports: {} + size: 7177 + timestamp: 1783850404460 - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda sha256: 9e5e1fd3506ccfc4d444fc4d2d39b0ed097d5d0e3bd3d4bdf6bcc81aaf66860d md5: 2c5ef45db85d34799771629bd5860fd7 @@ -20003,7 +20020,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/platformdirs?source=compressed-mapping + - pkg:pypi/platformdirs?source=hash-mapping run_exports: {} size: 26308 timestamp: 1779972894916 @@ -20163,7 +20180,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/pycparser?source=compressed-mapping + - pkg:pypi/pycparser?source=hash-mapping run_exports: {} size: 55886 timestamp: 1779293633166 @@ -20406,7 +20423,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/python-discovery?source=compressed-mapping + - pkg:pypi/python-discovery?source=hash-mapping run_exports: {} size: 35514 timestamp: 1781257630962 @@ -20449,7 +20466,7 @@ packages: license: Apache-2.0 license_family: APACHE purls: - - pkg:pypi/requests?source=compressed-mapping + - pkg:pypi/requests?source=hash-mapping run_exports: {} size: 68709 timestamp: 1778851103479 @@ -20880,7 +20897,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/traitlets?source=compressed-mapping + - pkg:pypi/traitlets?source=hash-mapping run_exports: {} size: 115158 timestamp: 1780507822178 @@ -20922,7 +20939,7 @@ packages: - python license: PSF-2.0 purls: - - pkg:pypi/typing-extensions?source=compressed-mapping + - pkg:pypi/typing-extensions?source=hash-mapping run_exports: {} size: 52631 timestamp: 1783002732887 @@ -20999,7 +21016,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/wcwidth?source=compressed-mapping + - pkg:pypi/wcwidth?source=hash-mapping run_exports: {} size: 132415 timestamp: 1782771807703 @@ -21027,7 +21044,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/wslink?source=compressed-mapping + - pkg:pypi/wslink?source=hash-mapping run_exports: {} size: 36803 timestamp: 1778826669944 @@ -21040,7 +21057,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/zipp?source=compressed-mapping + - pkg:pypi/zipp?source=hash-mapping run_exports: {} size: 24190 timestamp: 1779159948016 @@ -37248,7 +37265,7 @@ packages: license: LicenseRef-openrail size: 244991335 timestamp: 1771976595791 -- conda_source: bitbots_rust_nav[146a3083] @ src/bitbots_navigation/bitbots_rust_nav +- conda_source: bitbots_rust_nav[5e7b7ba8] @ src/bitbots_navigation/bitbots_rust_nav variants: c_stdlib: sysroot c_stdlib_version: '2.28' @@ -37317,7 +37334,7 @@ packages: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - conda: https://data.bit-bots.de/conda-misc/output/noarch/readline-8.3-h4616a5c_1.conda -- conda_source: bitbots_rust_nav[36aa2fce] @ src/bitbots_navigation/bitbots_rust_nav +- conda_source: bitbots_rust_nav[a130a192] @ src/bitbots_navigation/bitbots_rust_nav variants: c_stdlib: sysroot c_stdlib_version: '2.28' diff --git a/pixi.toml b/pixi.toml index aa19965ac0..e8b00055eb 100644 --- a/pixi.toml +++ b/pixi.toml @@ -45,6 +45,7 @@ python = "==3.12.1, <3.13" # Patches readline = ">=8.2.999" # This is needed because we want to install an empty readline package from our models channel that leads to the system version being used. Otherwise we might have a mismatch between bash (often accessed globally ignoring the env) and readline (provided by the env) breaking everything. +pixi-pycharm = ">=0.0.12,<0.0.13" [feature.ros.dependencies] # Misc dependencies for our ROS 2 packages diff --git a/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py b/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py index a07cc32c51..23b7a219a8 100644 --- a/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py +++ b/src/bitbots_misc/bitbots_bringup/launch/mujoco_simulation.launch.py @@ -95,6 +95,7 @@ def launch_setup(context): num_robots = sum(parse_num_robots(num_robots_spec)) # total robots across all teams robot_type = str(LaunchConfiguration("robot_type").perform(context)) use_web = LaunchConfiguration("web").perform(context).lower() == "true" + start_teamplayer = LaunchConfiguration("teamplayer").perform(context).lower() == "true" package_share = get_package_share_directory("bitbots_mujoco_sim") bridge_config_dir = Path(package_share) / "config" / "domain_bridges" @@ -150,26 +151,27 @@ def launch_setup(context): # game_settings.yaml defaults. robot_game_settings_args = [f"{key}:={value}" for key, value in game_settings[robot_index].items()] - actions.append( - TimerAction( - period=3.0, - actions=[ - LogInfo(msg=f"Launching teamplayer stack for robot{robot_domain} in domain {robot_domain}"), - ExecuteProcess( - cmd=[ - "ros2", - "launch", - "bitbots_bringup", - "teamplayer.launch", - ] - + teamplayer_args - + robot_game_settings_args, - output="screen", - additional_env={"ROS_DOMAIN_ID": str(robot_domain)}, - ), - ], + if start_teamplayer: + actions.append( + TimerAction( + period=3.0, + actions=[ + LogInfo(msg=f"Launching teamplayer stack for robot{robot_domain} in domain {robot_domain}"), + ExecuteProcess( + cmd=[ + "ros2", + "launch", + "bitbots_bringup", + "teamplayer.launch", + ] + + teamplayer_args + + robot_game_settings_args, + output="screen", + additional_env={"ROS_DOMAIN_ID": str(robot_domain)}, + ), + ], + ) ) - ) return actions @@ -178,6 +180,11 @@ def generate_launch_description(): """Launch MuJoCo simulation with domain bridge for multi-robot support.""" declared_args = [ + DeclareLaunchArgument( + "teamplayer", + default_value="true", + description="Whether to launch the teamplayer software stack for the simulated robots", + ), DeclareLaunchArgument( "num_robots", default_value="1", diff --git a/src/bitbots_misc/bitbots_bringup/launch/simulator_teamplayer.launch b/src/bitbots_misc/bitbots_bringup/launch/simulator_teamplayer.launch index e29c13aab2..5f9ab475fd 100644 --- a/src/bitbots_misc/bitbots_bringup/launch/simulator_teamplayer.launch +++ b/src/bitbots_misc/bitbots_bringup/launch/simulator_teamplayer.launch @@ -1,5 +1,6 @@ + @@ -20,7 +21,7 @@ - + diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py index a8dae6583b..e79911b434 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py @@ -281,7 +281,7 @@ def _add_field_textures(self, server) -> None: 2 * half_x, 2 * half_y, # Lift slightly above the plane to avoid z-fighting with the grid. - position=(float(pos[0]), float(pos[1]), float(pos[2]) + 0.001), + position=(float(pos[0]), float(pos[1]), float(pos[2]) + 0.010), cast_shadow=False, ) From 6aea40e36ff8a47f0e29b61a39b793a07af0feaa Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Thu, 20 Aug 2026 22:27:10 +0200 Subject: [PATCH 6/8] Properly distribute robots --- .../bitbots_mujoco_sim/world.py | 115 ++++++++++++------ 1 file changed, 79 insertions(+), 36 deletions(-) diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py index 945f02afe8..609c64acc8 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py @@ -19,6 +19,9 @@ # Half dimensions of the field (length 9m -> half length 4.5m). HALF_FIELD_LENGTH = 4.5 +# Clearance from the borders of the half (goal line at -4.5m/4.5m and midfield at 0.0m). +BORDER_CLEARANCE = 0.5 + # Yaw (rotation about z) to make a robot face inward towards the field center. # A robot on the negative-y sideline faces +y; on the positive-y sideline it faces -y. FACING_YAW = 1.57 @@ -32,26 +35,6 @@ # Default team ID for the first team. Additional teams increment from here. BASE_TEAM_ID = 6 -# Fixed placement along the sideline for team 0 (defending x in [-4.5, 0], facing +x). -# Offense is placed at the front (near x=0), goalie at the back (near x=-4.5), and -# defenders in the middle. Position 1 (left) goes to the left sideline (+y), -# position 2 (right) goes to the right sideline (-y), and center (position 0) -# positions are distributed across sides (offense/goalie right, defense left). -# All positions leave >= 0.5m space from the borders of the half (-4.5 and 0.0). -# Formatted as: (role, position_number) -> (x_pos, side) where side is "left" or "right". -_ROLE_PLACEMENTS_TEAM_0: dict[tuple[str, int], tuple[float, str]] = { - # Offense (front): position 0 = center (right side), 1 = left, 2 = right - ("offense", 0): (-0.6, "right"), - ("offense", 1): (-0.6, "left"), - ("offense", 2): (-1.2, "right"), - # Goalie (back): position 0 = right side - ("goalie", 0): (-3.9, "right"), - # Defense (middle): position 0 = center (left side), 1 = left, 2 = right - ("defense", 0): (-2.6, "left"), - ("defense", 1): (-2.3, "left"), - ("defense", 2): (-2.0, "right"), -} - def parse_num_robots(num_robots: str | int) -> list[int]: """Parse a ``num_robots`` specification into per-team robot counts. @@ -104,11 +87,14 @@ def compute_game_settings(teams: list[int]) -> list[dict]: def compute_robot_poses(teams: list[int]) -> list[tuple[float, float, float]]: """Compute the ``(x, y, yaw)`` placement for every robot. - Robots are positioned on the sidelines of their own half. Offense players are - placed to the front (near midfield), the goalie to the back (near goal line), - and defenders in the middle. Role position 1 is left and position 2 is right - (relative to local team orientation), while position 0 is placed on the side. - All positions keep at least 0.5m clearance from the borders of the half. + Robots are dynamically distributed evenly along the available sideline space + of their own half, keeping at least 0.5m clearance from borders. + - Position 1 is placed on the left sideline, position 2 on the right sideline. + - Unassigned / center positions are balanced across both sides so player + counts per sideline are as even as possible. + - On each sideline, robots are sorted from back to front according to role: + goalie at the back, offense at the front, with center defense/offense + positioned in front of side defense/offense. For team 0 (defending negative x half, facing +x), left is +y and right is -y. For team 1 (defending positive x half, facing -x), poses are mirrored across @@ -117,28 +103,85 @@ def compute_robot_poses(teams: list[int]) -> list[tuple[float, float, float]]: poses: list[tuple[float, float, float]] = [] game_settings = compute_game_settings(teams) + x_min = -(HALF_FIELD_LENGTH - BORDER_CLEARANCE) + x_max = -BORDER_CLEARANCE + + def compute_x_positions(k: int) -> list[float]: + if k <= 0: + return [] + if k == 1: + return [(x_min + x_max) / 2.0] + return [x_min + i * (x_max - x_min) / (k - 1) for i in range(k)] + + def role_sort_key(item: tuple[int, dict]) -> int: + _idx, setting = item + role = setting["role"] + pos = setting["position_number"] + if role == "goalie": + return 0 + elif role == "defense": + return 2 if pos == 0 else 1 + elif role == "offense": + return 4 if pos == 0 else 3 + return 0 + for team_index, count in enumerate(teams): - # Determine team offset in the flat game_settings list team_start = sum(teams[:team_index]) - for robot_in_team in range(count): - setting = game_settings[team_start + robot_in_team] - role = setting["role"] + team_settings = game_settings[team_start : team_start + count] + team_robots = list(enumerate(team_settings)) + + left_robots: list[tuple[int, dict]] = [] + right_robots: list[tuple[int, dict]] = [] + unassigned_robots: list[tuple[int, dict]] = [] + + for idx, setting in team_robots: pos_num = setting["position_number"] + if pos_num == 1: + left_robots.append((idx, setting)) + elif pos_num == 2: + right_robots.append((idx, setting)) + else: + unassigned_robots.append((idx, setting)) + + # Fill up unassigned so that left and right are about even + for idx, setting in unassigned_robots: + if len(left_robots) < len(right_robots): + left_robots.append((idx, setting)) + elif len(right_robots) < len(left_robots): + right_robots.append((idx, setting)) + else: + right_robots.append((idx, setting)) - x_base, side = _ROLE_PLACEMENTS_TEAM_0[(role, pos_num)] + # Sort according to role from back to front + left_robots.sort(key=role_sort_key) + right_robots.sort(key=role_sort_key) + left_x = compute_x_positions(len(left_robots)) + right_x = compute_x_positions(len(right_robots)) + + team_poses: list[tuple[float, float, float]] = [None] * count # type: ignore[list-item] + + for (idx, _setting), x_base in zip(left_robots, left_x): if team_index % 2 == 0: - # Team 0: defending -x half, facing +x x = x_base - y = SIDELINE_Y if side == "left" else -SIDELINE_Y + y = SIDELINE_Y else: - # Team 1: defending +x half, facing -x (mirrored across origin) x = -x_base - y = -SIDELINE_Y if side == "left" else SIDELINE_Y + y = -SIDELINE_Y + yaw = FACING_YAW if y < 0 else -FACING_YAW + team_poses[idx] = (x, y, yaw) - # Facing angle: turn towards field center (y = 0) + for (idx, _setting), x_base in zip(right_robots, right_x): + if team_index % 2 == 0: + x = x_base + y = -SIDELINE_Y + else: + x = -x_base + y = SIDELINE_Y yaw = FACING_YAW if y < 0 else -FACING_YAW - poses.append((x, y, yaw)) + team_poses[idx] = (x, y, yaw) + + poses.extend(team_poses) return poses From f7525b4677d4a32ae6c5067eeafbee884710abdf Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Fri, 21 Aug 2026 15:54:44 +0200 Subject: [PATCH 7/8] Add Jersey --- .../bitbots_mujoco_sim/simulation.py | 12 ++ .../bitbots_mujoco_sim/world.py | 105 +++++++++++++++++- .../bitbots_mujoco_sim/package.xml | 1 + .../bitbots_mujoco_sim/xml/pi_plus.xml | 19 ++++ 4 files changed, 131 insertions(+), 6 deletions(-) diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py index e79911b434..dee9702dcf 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/simulation.py @@ -71,6 +71,7 @@ def __init__(self): self._rng = np.random.default_rng() self.model: mujoco.MjModel = mujoco.MjModel.from_xml_path(world_file) + self._apply_jersey_overrides() self.data: mujoco.MjData = mujoco.MjData(self.model) self.robots: list[RobotSimulation] = [ RobotSimulation( @@ -123,6 +124,17 @@ def __init__(self): {"frequency": 32, "handler": lambda: self.publish(lambda robot: robot.publish_camera_event())}, ] + def _apply_jersey_overrides(self) -> None: + """Replace default robot materials with dynamically generated jersey overrides if present.""" + for geom_id in range(self.model.ngeom): + cur_mat_id = self.model.geom_matid[geom_id] + if cur_mat_id >= 0: + cur_mat_name = mujoco.mj_id2name(self.model, mujoco.mjtObj.mjOBJ_MATERIAL, cur_mat_id) + override_mat_name = f"{cur_mat_name}_override" + override_mat_id = mujoco.mj_name2id(self.model, mujoco.mjtObj.mjOBJ_MATERIAL, override_mat_name) + if override_mat_id != -1: + self.model.geom_matid[geom_id] = override_mat_id + def _apply_home_keyframe(self) -> None: """Apply the 'home' keyframe joint values to all robots, leaving freejoints untouched. diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py index 609c64acc8..6e89546927 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/bitbots_mujoco_sim/world.py @@ -8,9 +8,12 @@ individually. """ +import tempfile import xml.etree.ElementTree as ET from pathlib import Path +from PIL import Image, ImageDraw, ImageFont + # Sideline offset from the field center along the y-axis. SIDELINE_Y = 3.25 # Backward compatibility alias @@ -35,6 +38,67 @@ # Default team ID for the first team. Additional teams increment from here. BASE_TEAM_ID = 6 +# RGB color palettes for teams and goalies. +DEFAULT_TEAM_COLORS: list[tuple[int, int, int]] = [ + (0, 70, 200), # Team 0: Blue + (200, 30, 30), # Team 1: Red +] + +DEFAULT_GOALIE_COLORS: list[tuple[int, int, int]] = [ + (230, 190, 20), # Goalie 0: Yellow + (30, 180, 60), # Goalie 1: Green +] + +# Directory where generated jersey textures are cached to avoid re-generating. +JERSEY_CACHE_DIR: Path = Path(tempfile.gettempdir()) / "bitbots_mujoco_sim_jerseys" + + +def get_robot_jersey_color( + team_color: int, + is_goalie: bool = False, +) -> tuple[int, int, int]: + """Return the RGB jersey color for a robot based on its team and role.""" + if is_goalie: + return DEFAULT_GOALIE_COLORS[team_color % len(DEFAULT_GOALIE_COLORS)] + return DEFAULT_TEAM_COLORS[team_color % len(DEFAULT_TEAM_COLORS)] + + +def get_jersey_texture( + color: tuple[int, int, int], + number: int | str, + cache_dir: Path = JERSEY_CACHE_DIR, + size: int = 256, +) -> Path: + """Generate and cache a jersey texture image with the specified color and number. + + The texture is cached in ``cache_dir`` (placed in a temporary directory without + automatic deletion) and reused across simulation launches for performance. + """ + hex_color = f"{color[0]:02x}{color[1]:02x}{color[2]:02x}" + output_path = cache_dir / f"jersey_{hex_color}_{number}.png" + + if output_path.exists(): + return output_path + + output_path.parent.mkdir(parents=True, exist_ok=True) + img = Image.new("RGB", (size, size), color=color) + draw = ImageDraw.Draw(img) + + # Choose contrasting text color based on background luminance + r, g, b = color + luminance = 0.299 * r + 0.587 * g + 0.114 * b + text_color = (0, 0, 0) if luminance > 140 else (255, 255, 255) + + font_size = int(size * 0.6) + try: + font = ImageFont.load_default(size=font_size) + except TypeError: + font = ImageFont.load_default() + + draw.text((size // 2, size // 2), str(number), fill=text_color, font=font, anchor="mm") + img.save(output_path) + return output_path + def parse_num_robots(num_robots: str | int) -> list[int]: """Parse a ``num_robots`` specification into per-team robot counts. @@ -161,7 +225,7 @@ def role_sort_key(item: tuple[int, dict]) -> int: team_poses: list[tuple[float, float, float]] = [None] * count # type: ignore[list-item] - for (idx, _setting), x_base in zip(left_robots, left_x): + for (idx, _setting), x_base in zip(left_robots, left_x, strict=True): if team_index % 2 == 0: x = x_base y = SIDELINE_Y @@ -171,7 +235,7 @@ def role_sort_key(item: tuple[int, dict]) -> int: yaw = FACING_YAW if y < 0 else -FACING_YAW team_poses[idx] = (x, y, yaw) - for (idx, _setting), x_base in zip(right_robots, right_x): + for (idx, _setting), x_base in zip(right_robots, right_x, strict=True): if team_index % 2 == 0: x = x_base y = -SIDELINE_Y @@ -195,7 +259,11 @@ def _find_replicate(root: ET.Element) -> tuple[ET.Element, ET.Element]: raise ValueError("No element found in world template") -def generate_world_xml(num_robots: str | int, package_share: str, robot_type: str) -> Path: +def generate_world_xml( + num_robots: str | int, + package_share: str, + robot_type: str, +) -> Path: """Generate the MuJoCo world XML positioning every robot individually. The ```` element of the template is replaced by one ```` per @@ -203,19 +271,44 @@ def generate_world_xml(num_robots: str | int, package_share: str, robot_type: st unique attach prefix (``robot__``) so that the resulting body names stay unique and can be discovered by the simulation. + Additionally, per-robot jersey textures and materials are dynamically generated, + cached in a temporary directory, and registered in the model assets so that each + robot displays its team/goalie color and player number in both the visualizer and + camera images. + Returns the path of the generated world file. """ template_path = Path(package_share) / "xml" / "kid_field.xml" output_path = Path(package_share) / "xml" / "generated_world.xml" - poses = compute_robot_poses(parse_num_robots(num_robots)) + teams = parse_num_robots(num_robots) + poses = compute_robot_poses(teams) + game_settings = compute_game_settings(teams) tree = ET.parse(template_path) - replicate_parent, replicate = _find_replicate(tree.getroot()) + root = tree.getroot() + + asset = root.find("asset") + if asset is None: + asset = ET.SubElement(root, "asset") + + replicate_parent, replicate = _find_replicate(root) insert_index = list(replicate_parent).index(replicate) replicate_parent.remove(replicate) - for robot_index, (x, y, yaw) in enumerate(poses): + for robot_index, ((x, y, yaw), setting) in enumerate(zip(poses, game_settings, strict=False)): + is_goalie = setting["role"] == "goalie" + color = get_robot_jersey_color( + setting["team_color"], + is_goalie=is_goalie, + ) + texture_path = get_jersey_texture(color, setting["bot_id"]) + + tex_name = f"robot_{robot_index}_jersey_override" + mat_name = f"robot_{robot_index}_jersey_override" + ET.SubElement(asset, "texture", {"name": tex_name, "type": "2d", "file": str(texture_path)}) + ET.SubElement(asset, "material", {"name": mat_name, "texture": tex_name}) + frame = ET.Element("frame", {"pos": f"{x} {y} 0.0", "euler": f"0 0 {yaw}"}) ET.SubElement(frame, "attach", {"model": robot_type, "prefix": f"robot_{robot_index}_"}) replicate_parent.insert(insert_index, frame) diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/package.xml b/src/bitbots_simulation/bitbots_mujoco_sim/package.xml index bac09bcd52..fb8bf7f8ad 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/package.xml +++ b/src/bitbots_simulation/bitbots_mujoco_sim/package.xml @@ -25,6 +25,7 @@ ament_index_python python3-numpy python3-mujoco + python3-pil ament_cmake_mypy diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/xml/pi_plus.xml b/src/bitbots_simulation/bitbots_mujoco_sim/xml/pi_plus.xml index 0b23002a53..f2be7755f6 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/xml/pi_plus.xml +++ b/src/bitbots_simulation/bitbots_mujoco_sim/xml/pi_plus.xml @@ -33,6 +33,24 @@ + + + @@ -83,6 +101,7 @@ + From 79d812a5f3e8048f86e7f6aa4490e3e8c6679591 Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Fri, 21 Aug 2026 17:19:35 +0200 Subject: [PATCH 8/8] Update trikot --- .../bitbots_mujoco_sim/setup.py | 1 + .../xml/assets/meshes/trikot.OBJ | 2907 +++++++++++++++++ .../bitbots_mujoco_sim/xml/pi_plus.xml | 19 +- 3 files changed, 2910 insertions(+), 17 deletions(-) create mode 100644 src/bitbots_simulation/bitbots_mujoco_sim/xml/assets/meshes/trikot.OBJ diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/setup.py b/src/bitbots_simulation/bitbots_mujoco_sim/setup.py index cc6a68f7fb..55fc050e38 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/setup.py +++ b/src/bitbots_simulation/bitbots_mujoco_sim/setup.py @@ -18,6 +18,7 @@ ("share/" + package_name + "/xml/assets/ball", glob.glob("xml/assets/ball/*.png")), ("share/" + package_name + "/xml/assets/backgrounds", glob.glob("xml/assets/backgrounds/*.png")), ("share/" + package_name + "/xml/assets/meshes", glob.glob("xml/assets/meshes/*.STL")), + ("share/" + package_name + "/xml/assets/meshes", glob.glob("xml/assets/meshes/*.OBJ")), ], install_requires=["setuptools"], zip_safe=True, diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/xml/assets/meshes/trikot.OBJ b/src/bitbots_simulation/bitbots_mujoco_sim/xml/assets/meshes/trikot.OBJ new file mode 100644 index 0000000000..3210a4881c --- /dev/null +++ b/src/bitbots_simulation/bitbots_mujoco_sim/xml/assets/meshes/trikot.OBJ @@ -0,0 +1,2907 @@ +# Blender 5.2.0 LTS +# www.blender.org +o trikot +v -0.100364 -0.029143 0.119311 +v -0.100005 -0.033130 0.117705 +v -0.096356 -0.049371 0.021315 +v -0.089777 -0.065005 0.023542 +v -0.092059 -0.061179 0.023085 +v -0.091810 -0.065008 0.119484 +v -0.095953 -0.052744 0.127291 +v -0.092249 -0.062300 0.132576 +v -0.096356 0.049461 0.021315 +v -0.089777 0.065095 0.023542 +v -0.092059 0.061268 0.023085 +v -0.091810 0.065098 0.119484 +v 0.064588 -0.090934 0.139733 +v 0.064751 -0.089858 0.147428 +v 0.055512 -0.091096 0.160713 +v 0.064668 -0.088482 0.154134 +v 0.068246 -0.083737 0.160842 +v 0.061043 -0.088243 0.160724 +v 0.069059 -0.088403 0.138326 +v 0.074770 -0.084183 0.141280 +v 0.075202 -0.078298 0.160654 +v 0.072308 -0.083247 0.154291 +v 0.076467 -0.082924 0.140857 +v 0.059498 -0.092757 0.147082 +v 0.059539 -0.091374 0.153890 +v 0.043215 -0.095969 0.160661 +v 0.079323 -0.080942 0.056850 +v 0.064739 -0.087514 0.042753 +v 0.057141 -0.090451 0.041412 +v 0.056570 -0.088853 0.034500 +v 0.059496 -0.090849 0.047950 +v 0.069183 -0.086168 0.048064 +v 0.035654 -0.095688 0.036773 +v 0.036907 -0.097160 0.043228 +v 0.079142 -0.079421 0.042614 +v 0.078603 -0.077446 0.031002 +v 0.043992 -0.095196 0.042689 +v 0.000176 -0.098428 0.033324 +v 0.000176 -0.094604 0.024044 +v 0.014424 -0.098241 0.034660 +v 0.026488 -0.091017 0.177528 +v 0.027842 -0.095108 0.171176 +v 0.064588 0.091024 0.139733 +v 0.064751 0.089948 0.147428 +v 0.055512 0.091186 0.160713 +v 0.064668 0.088572 0.154134 +v 0.068246 0.083827 0.160842 +v 0.061043 0.088333 0.160724 +v 0.069059 0.088493 0.138326 +v 0.074770 0.084273 0.141280 +v 0.075202 0.078387 0.160654 +v 0.072308 0.083337 0.154291 +v 0.076467 0.083014 0.140857 +v 0.059498 0.092847 0.147082 +v 0.059539 0.091464 0.153890 +v 0.043215 0.096059 0.160661 +v 0.087156 -0.074012 0.049195 +v 0.090657 -0.070318 0.048843 +v 0.083324 -0.076907 0.046441 +v 0.091017 -0.070799 0.068026 +v 0.097569 -0.056131 0.021371 +v 0.084983 -0.072867 0.029162 +v 0.077210 -0.084074 0.098295 +v 0.083771 -0.078680 0.098181 +v 0.090603 -0.069729 0.126802 +v 0.087139 -0.074159 0.126918 +v 0.079323 0.081032 0.056850 +v 0.064739 0.087604 0.042753 +v 0.057141 0.090541 0.041412 +v 0.056570 0.088943 0.034500 +v 0.059496 0.090939 0.047950 +v 0.069183 0.086258 0.048064 +v 0.035654 0.095778 0.036773 +v 0.036907 0.097250 0.043228 +v 0.079142 0.079511 0.042614 +v 0.078603 0.077536 0.031002 +v 0.043992 0.095285 0.042689 +v 0.000176 0.098518 0.033324 +v 0.000176 0.094694 0.024044 +v 0.080754 -0.075898 0.154163 +v 0.079121 -0.074580 0.160585 +v 0.084389 -0.071849 0.154072 +v 0.082651 -0.070597 0.160495 +v 0.087643 -0.067436 0.153971 +v 0.014424 0.098331 0.034660 +v 0.085804 -0.066260 0.160391 +v 0.026488 0.091107 0.177528 +v 0.027842 0.095198 0.171176 +v 0.098728 0.056194 0.044296 +v 0.096361 0.061495 0.044656 +v 0.087156 0.074102 0.049195 +v 0.090657 0.070408 0.048843 +v 0.083324 0.076997 0.046441 +v 0.091017 0.070889 0.068026 +v 0.097569 0.056221 0.021371 +v 0.084983 0.072957 0.029162 +v 0.103064 0.039296 0.103246 +v 0.077210 0.084164 0.098295 +v 0.083771 0.078770 0.098181 +v 0.102353 0.038428 0.126291 +v 0.090603 0.069819 0.126802 +v 0.087139 0.074249 0.126918 +v 0.080754 0.075988 0.154163 +v 0.079121 0.074670 0.160585 +v 0.084389 0.071938 0.154072 +v 0.082651 0.070687 0.160495 +v 0.087643 0.067525 0.153971 +v 0.085804 0.066350 0.160391 +v 0.090525 0.062659 0.153862 +v 0.088589 0.061569 0.160279 +v 0.093043 0.057250 0.153753 +v 0.091017 0.056256 0.160163 +v 0.095207 0.051208 0.153647 +v 0.093099 0.050322 0.160050 +v 0.097025 0.044443 0.153550 +v 0.094844 0.043677 0.159946 +v 0.098506 0.036865 0.153466 +v 0.096695 0.032711 0.160102 +v 0.085664 0.072921 0.146797 +v 0.091972 0.063547 0.146583 +v 0.094571 0.058073 0.146474 +v 0.096809 0.051953 0.146371 +v 0.101490 0.037918 0.137364 +v 0.097969 0.052608 0.137538 +v 0.095669 0.058775 0.137643 +v 0.093003 0.064279 0.137753 +v 0.086555 0.073678 0.137976 +v 0.090525 -0.062569 0.153862 +v 0.088589 -0.061479 0.160279 +v 0.093043 -0.057160 0.153753 +v 0.091017 -0.056166 0.160163 +v 0.095207 -0.051118 0.153647 +v 0.093099 -0.050232 0.160050 +v 0.096695 -0.032621 0.160102 +v 0.085664 -0.072832 0.146797 +v 0.091972 -0.063457 0.146583 +v 0.094571 -0.057983 0.146474 +v 0.096809 -0.051863 0.146371 +v 0.100228 -0.037322 0.146195 +v 0.101490 -0.037828 0.137364 +v 0.099908 -0.045597 0.137444 +v 0.097969 -0.052519 0.137538 +v 0.095669 -0.058685 0.137643 +v 0.093003 -0.064189 0.137753 +v 0.086555 -0.073588 0.137976 +v 0.085802 -0.033454 0.177333 +v 0.093209 -0.035401 0.166385 +v 0.089167 -0.020871 0.174834 +v 0.085802 0.033544 0.177333 +v 0.094519 0.022074 0.166767 +v 0.098155 0.019004 0.159735 +v 0.089167 0.020961 0.174834 +v 0.067617 -0.071566 0.178183 +v 0.068867 -0.075740 0.172901 +v 0.072748 -0.066461 0.178090 +v 0.074291 -0.070830 0.172599 +v 0.076974 -0.072914 0.166721 +v 0.076877 -0.060827 0.177915 +v 0.079277 -0.056535 0.177795 +v 0.081355 -0.051739 0.177669 +v 0.083799 -0.043884 0.177540 +v 0.077553 -0.067090 0.172502 +v 0.080454 -0.063011 0.172385 +v 0.083006 -0.058507 0.172256 +v 0.085221 -0.053490 0.172123 +v 0.087113 -0.047874 0.171991 +v 0.080383 -0.069032 0.166627 +v 0.067617 0.071656 0.178183 +v 0.068867 0.075830 0.172901 +v 0.072748 0.066551 0.178090 +v 0.074291 0.070920 0.172599 +v 0.076974 0.073004 0.166721 +v 0.076877 0.060917 0.177915 +v 0.079277 0.056625 0.177795 +v 0.081355 0.051829 0.177669 +v 0.083799 0.043974 0.177540 +v 0.077553 0.067180 0.172502 +v 0.080454 0.063101 0.172385 +v 0.083006 0.058597 0.172256 +v 0.085221 0.053580 0.172123 +v 0.087113 0.047964 0.171991 +v 0.080383 0.069122 0.166627 +v 0.090419 0.049249 0.166142 +v 0.059947 0.082320 0.172745 +v 0.062027 0.084856 0.166874 +v 0.049575 0.087688 0.172688 +v 0.054045 0.089115 0.166818 +v 0.052558 0.081875 0.178261 +v 0.089401 0.067529 0.021400 +v 0.041857 0.089250 0.023258 +v 0.055153 0.084779 0.021459 +v 0.090419 -0.049159 0.166142 +v 0.059947 -0.082230 0.172745 +v 0.062027 -0.084766 0.166874 +v 0.049575 -0.087598 0.172688 +v 0.054045 -0.089025 0.166818 +v 0.099764 0.029059 0.152995 +v 0.104510 0.020188 0.126182 +v 0.103495 0.019874 0.138161 +v 0.101391 0.019475 0.150060 +v 0.052558 -0.081785 0.178261 +v 0.089401 -0.067439 0.021400 +v 0.041857 -0.089160 0.023258 +v 0.055153 -0.084689 0.021459 +v 0.099764 -0.028969 0.152995 +v 0.103495 -0.019784 0.138161 +v 0.102561 -0.019587 0.144545 +v 0.101391 -0.019385 0.150060 +v 0.105262 -0.020611 0.103132 +v -0.100426 0.000045 0.148353 +v -0.097678 -0.031148 0.153446 +v -0.098272 -0.035177 0.145831 +v -0.099667 -0.018014 0.149357 +v -0.098742 -0.017720 0.154576 +v -0.097258 -0.020457 0.159464 +v -0.095614 -0.033722 0.159506 +v -0.069949 -0.075476 0.172238 +v -0.077397 -0.071757 0.166440 +v -0.084820 -0.041468 0.177129 +v -0.070641 -0.069207 0.177817 +v -0.076544 -0.067554 0.172571 +v -0.080906 -0.061137 0.172090 +v -0.083400 -0.056301 0.171952 +v -0.088449 -0.042542 0.171374 +v -0.092688 -0.036739 0.165702 +v -0.088350 -0.052443 0.165944 +v -0.090325 -0.046500 0.165812 +v -0.094225 -0.040971 0.159601 +v -0.092525 -0.047610 0.159712 +v -0.090515 -0.053689 0.159832 +v -0.088191 -0.059261 0.159957 +v -0.085555 -0.064375 0.160079 +v -0.082603 -0.069084 0.160195 +v -0.079335 -0.073439 0.160297 +v -0.088779 -0.016181 0.176463 +v -0.091527 -0.016499 0.172394 +v -0.093591 -0.020073 0.168394 +v -0.095870 -0.017125 0.163842 +v -0.095104 -0.025380 0.163900 +v -0.070080 -0.079425 0.166579 +v -0.065936 -0.082869 0.166611 +v -0.061807 -0.082041 0.172518 +v -0.061438 -0.086040 0.166622 +v -0.051282 -0.091504 0.166603 +v -0.045576 -0.093771 0.166582 +v -0.041335 -0.091956 0.172437 +v -0.039420 -0.095710 0.166560 +v -0.029688 -0.098079 0.166303 +v -0.032171 -0.093764 0.173252 +v -0.037008 -0.089161 0.177929 +v -0.030894 -0.090797 0.177705 +v -0.063548 -0.075911 0.178024 +v -0.055181 -0.081711 0.178044 +v -0.045281 -0.086435 0.178042 +v -0.067592 -0.084803 0.160478 +v -0.057968 -0.090995 0.160508 +v -0.052547 -0.093636 0.160506 +v 0.000174 -0.094464 0.176432 +v 0.000176 -0.093954 0.022693 +v 0.000176 -0.099255 0.035545 +v -0.045060 -0.097365 0.049619 +v -0.040446 -0.097160 0.043092 +v -0.047255 -0.095298 0.043083 +v -0.054611 -0.091289 0.037356 +v -0.079136 -0.079982 0.046671 +v -0.073395 -0.084605 0.050020 +v -0.065983 -0.090932 0.067125 +v -0.079749 -0.081545 0.068482 +v -0.033391 -0.098799 0.043569 +v -0.068592 -0.085882 0.040964 +v -0.089166 -0.069604 0.045116 +v -0.086204 -0.073364 0.045607 +v -0.082866 -0.076777 0.046127 +v -0.083413 -0.078138 0.068216 +v -0.079990 -0.081974 0.098024 +v -0.077212 -0.078902 0.153957 +v -0.079104 -0.080824 0.137889 +v -0.082773 -0.076767 0.137780 +v -0.086085 -0.072393 0.137662 +v -0.090077 -0.065911 0.136840 +v -0.090913 -0.061490 0.146249 +v -0.093229 -0.055787 0.146131 +v -0.095224 -0.049539 0.146019 +v -0.096903 -0.042688 0.145918 +v -0.095827 -0.041850 0.153197 +v -0.094128 -0.048609 0.153301 +v -0.092114 -0.054790 0.153415 +v -0.089782 -0.060447 0.153534 +v -0.084153 -0.070401 0.153766 +v -0.011905 -0.095137 0.025655 +v -0.011684 -0.097612 0.031585 +v -0.035494 -0.094552 0.030997 +v -0.020492 -0.093250 0.176669 +v -0.025481 -0.097187 0.169351 +v -0.070642 -0.088135 0.138073 +v -0.073363 -0.085471 0.142250 +v -0.069916 -0.087382 0.146845 +v -0.073251 -0.085012 0.145439 +v -0.059945 -0.093625 0.146948 +v -0.060560 -0.094319 0.138215 +v -0.097678 0.031238 0.153446 +v -0.098272 0.035267 0.145831 +v -0.099667 0.018104 0.149357 +v -0.098742 0.017810 0.154576 +v -0.097258 0.020547 0.159464 +v -0.095614 0.033812 0.159506 +v -0.069949 0.075565 0.172238 +v -0.077397 0.071847 0.166440 +v -0.084820 0.041558 0.177129 +v -0.070641 0.069296 0.177817 +v -0.076544 0.067644 0.172571 +v -0.080906 0.061227 0.172090 +v -0.083400 0.056391 0.171952 +v -0.088449 0.042632 0.171374 +v -0.092688 0.036829 0.165702 +v -0.088350 0.052532 0.165944 +v -0.090325 0.046590 0.165812 +v -0.094225 0.041061 0.159601 +v -0.092525 0.047700 0.159712 +v -0.090515 0.053779 0.159832 +v -0.088191 0.059351 0.159957 +v -0.085555 0.064465 0.160079 +v -0.082603 0.069174 0.160195 +v -0.079335 0.073529 0.160297 +v -0.088779 0.016270 0.176463 +v -0.091527 0.016589 0.172394 +v -0.093591 0.020163 0.168394 +v -0.095870 0.017215 0.163842 +v -0.095104 0.025470 0.163900 +v -0.070080 0.079514 0.166579 +v -0.065936 0.082959 0.166611 +v -0.061807 0.082131 0.172518 +v -0.061438 0.086130 0.166622 +v -0.051282 0.091594 0.166603 +v -0.045576 0.093861 0.166582 +v -0.041335 0.092046 0.172437 +v -0.039420 0.095800 0.166560 +v -0.029688 0.098169 0.166303 +v -0.032171 0.093854 0.173252 +v -0.037008 0.089251 0.177929 +v -0.030894 0.090887 0.177705 +v -0.063548 0.076001 0.178024 +v -0.055181 0.081801 0.178044 +v -0.045281 0.086525 0.178042 +v -0.067592 0.084892 0.160478 +v -0.057968 0.091085 0.160508 +v -0.052547 0.093726 0.160506 +v 0.000174 0.094554 0.176432 +v 0.000176 0.094044 0.022693 +v 0.000176 0.099345 0.035545 +v -0.045060 0.097454 0.049619 +v -0.040446 0.097250 0.043092 +v -0.047255 0.095388 0.043083 +v -0.054611 0.091379 0.037356 +v -0.079136 0.080072 0.046671 +v -0.073395 0.084695 0.050020 +v -0.065983 0.091022 0.067125 +v -0.079749 0.081635 0.068482 +v -0.033391 0.098888 0.043569 +v -0.068592 0.085972 0.040964 +v -0.089166 0.069694 0.045116 +v -0.086204 0.073454 0.045607 +v -0.082866 0.076866 0.046127 +v -0.083413 0.078228 0.068216 +v -0.079990 0.082064 0.098024 +v -0.077212 0.078992 0.153957 +v -0.079104 0.080914 0.137889 +v -0.082773 0.076857 0.137780 +v -0.086085 0.072483 0.137662 +v -0.090077 0.066001 0.136840 +v -0.090913 0.061580 0.146249 +v -0.093229 0.055877 0.146131 +v -0.096903 0.042778 0.145918 +v -0.095827 0.041940 0.153197 +v -0.094128 0.048699 0.153301 +v -0.092114 0.054880 0.153415 +v -0.089782 0.060536 0.153534 +v -0.084153 0.070491 0.153766 +v -0.011905 0.095227 0.025655 +v -0.011684 0.097702 0.031585 +v -0.035494 0.094642 0.030997 +v -0.020492 0.093340 0.176669 +v -0.025481 0.097277 0.169351 +v -0.070642 0.088224 0.138073 +v -0.073363 0.085561 0.142250 +v -0.069916 0.087472 0.146845 +v -0.073251 0.085102 0.145439 +v -0.059945 0.093714 0.146948 +v -0.060560 0.094409 0.138215 +v -0.059090 0.092629 0.154142 +v -0.068910 0.086378 0.154079 +v -0.060962 0.094782 0.127232 +v -0.066256 0.091878 0.127149 +v -0.016949 0.101198 0.044253 +v -0.075923 0.085574 0.098165 +v -0.059090 -0.092539 0.154142 +v -0.068910 -0.086288 0.154079 +v -0.060962 -0.094693 0.127232 +v -0.066256 -0.091788 0.127149 +v -0.016949 -0.101108 0.044253 +v -0.075923 -0.085485 0.098165 +v 0.027151 0.087267 0.181587 +v -0.081427 0.039811 0.181587 +v -0.035992 0.086066 0.181587 +v 0.050464 0.079394 0.181587 +v -0.068298 0.066994 0.181587 +v 0.064215 0.070283 0.181587 +v 0.073846 0.059024 0.181587 +v 0.039703 0.083871 0.181587 +v -0.052909 0.079362 0.181587 +v -0.073772 0.059582 0.181587 +v 0.069958 0.064570 0.181587 +v 0.076590 0.053692 0.181587 +v -0.084523 0.015859 0.181587 +v -0.061249 0.073738 0.181587 +v 0.027151 -0.087178 0.181587 +v -0.081427 -0.039721 0.181587 +v -0.078243 0.050434 0.181587 +v -0.018911 0.089164 0.181587 +v -0.035992 -0.085976 0.181587 +v 0.050464 -0.079305 0.181587 +v -0.068298 -0.066904 0.181587 +v 0.080005 0.043038 0.181587 +v 0.064215 -0.070193 0.181587 +v 0.000175 0.090013 0.181587 +v 0.073846 -0.058934 0.181587 +v -0.013935 0.103634 0.158615 +v -0.021239 0.103634 0.156710 +v -0.026857 0.103634 0.153933 +v 0.010083 0.103634 0.158895 +v 0.000174 0.103634 0.159991 +v -0.029417 0.103634 0.152232 +v 0.027929 0.103634 0.151774 +v 0.021475 0.103634 0.155527 +v -0.036282 0.103634 0.145398 +v -0.039851 0.103634 0.138429 +v 0.030034 0.103634 0.150054 +v -0.041566 0.103634 0.131559 +v 0.034838 0.103634 0.144768 +v 0.040582 0.103634 0.131151 +v 0.038650 0.103634 0.137495 +v -0.029321 0.103634 0.064346 +v -0.035138 0.103634 0.072191 +v -0.040922 0.103634 0.089954 +v -0.042610 0.103634 0.107293 +v 0.040032 0.103634 0.090996 +v 0.039133 0.103634 0.086883 +v 0.033942 0.103634 0.073725 +v 0.031228 0.103634 0.069658 +v 0.024922 0.103634 0.062834 +v 0.013204 0.103634 0.055597 +v 0.000358 0.103634 0.052673 +v -0.007837 0.103634 0.053031 +v -0.015906 0.103634 0.055284 +v -0.021825 0.103634 0.058231 +v 0.041769 0.103634 0.112755 +v -0.039521 0.103634 0.083806 +v 0.039703 -0.083781 0.181587 +v -0.052909 -0.079273 0.181587 +v -0.073772 -0.059493 0.181587 +v 0.083210 -0.017051 0.181587 +v 0.069958 -0.064480 0.181587 +v 0.076590 -0.053602 0.181587 +v -0.084523 -0.015769 0.181587 +v -0.061249 -0.073648 0.181587 +v -0.078243 -0.050345 0.181587 +v -0.018911 -0.089075 0.181587 +v 0.080005 -0.042948 0.181587 +v 0.000175 -0.089923 0.181587 +v -0.013935 -0.103544 0.158615 +v -0.021239 -0.103544 0.156710 +v -0.026857 -0.103544 0.153933 +v 0.010083 -0.103544 0.158895 +v 0.000174 -0.103544 0.159991 +v -0.029417 -0.103544 0.152232 +v 0.027929 -0.103544 0.151774 +v 0.021475 -0.103544 0.155527 +v -0.036282 -0.103544 0.145398 +v -0.039851 -0.103544 0.138429 +v 0.030034 -0.103544 0.150054 +v -0.041566 -0.103544 0.131559 +v 0.034838 -0.103544 0.144768 +v 0.040582 -0.103544 0.131151 +v 0.038650 -0.103544 0.137495 +v -0.029321 -0.103544 0.064346 +v -0.035138 -0.103544 0.072191 +v -0.040922 -0.103544 0.089954 +v -0.042610 -0.103544 0.107293 +v -0.100362 0.016755 0.021323 +v -0.092881 0.059107 0.021394 +v 0.078028 0.075240 0.021421 +v 0.040032 -0.103544 0.090996 +v -0.083760 0.070719 0.021414 +v 0.039133 -0.103544 0.086883 +v 0.102798 0.038350 0.021360 +v 0.033942 -0.103544 0.073725 +v 0.031228 -0.103544 0.069658 +v 0.085980 0.070342 0.021413 +v -0.086942 0.067681 0.021409 +v -0.002824 0.093341 0.021452 +v 0.024922 -0.103544 0.062834 +v 0.013204 -0.103544 0.055597 +v 0.000358 -0.103544 0.052673 +v -0.007837 -0.103544 0.053031 +v -0.015906 -0.103544 0.055284 +v -0.034080 0.090615 0.021447 +v -0.021825 -0.103544 0.058231 +v 0.041769 -0.103544 0.112755 +v -0.097451 0.044597 0.021370 +v 0.022315 0.091807 0.021449 +v -0.039521 -0.103544 0.083806 +v -0.092881 -0.059017 0.021394 +v 0.078028 -0.075151 0.021421 +v -0.083760 -0.070629 0.021414 +v 0.085980 -0.070252 0.021413 +v -0.086942 -0.067592 0.021409 +v 0.095168 0.060572 0.021397 +v -0.002824 -0.093252 0.021452 +v -0.034080 -0.090526 0.021447 +v -0.056559 0.084819 0.021438 +v -0.099424 -0.029980 0.021346 +v -0.089300 0.065094 0.021404 +v 0.099635 0.051109 0.021381 +v 0.022315 -0.091717 0.021449 +v 0.092429 0.064299 0.021403 +v -0.076867 0.075398 0.021422 +v 0.105481 -0.009928 0.021312 +v 0.095168 -0.060483 0.021397 +v -0.056559 -0.084730 0.021438 +v -0.089300 -0.065004 0.021404 +v 0.092429 -0.064209 0.021403 +v -0.076867 -0.075308 0.021422 +v 0.101300 -0.045290 0.021371 +vn -0.9826 -0.1798 0.0474 +vn 0.8625 0.3871 0.3260 +vn 0.5907 -0.7447 0.3106 +vn 0.7709 0.5528 0.3163 +vn -0.1138 0.9446 -0.3080 +vn -0.7973 -0.0000 0.6036 +vn 0.5139 0.8569 -0.0410 +vn 0.1490 0.1043 0.9833 +vn -0.2813 -0.6966 0.6600 +vn -0.9894 -0.1450 -0.0032 +vn -0.6538 0.7558 0.0363 +vn -0.8099 -0.4057 0.4236 +vn -0.2106 -0.9612 -0.1783 +vn -0.4603 -0.6620 0.5915 +vn -0.8120 -0.5016 0.2985 +vn 0.5884 -0.4096 0.6971 +vn -0.4057 -0.9084 0.1013 +vn -0.5215 0.8358 -0.1717 +vn -0.6641 0.6617 0.3479 +vn -0.4266 0.6131 0.6649 +vn 0.8908 0.3061 0.3357 +vn 0.9032 0.1417 0.4052 +vn 0.4348 0.8981 -0.0654 +vn -0.8120 0.5016 0.2985 +vn -0.4322 -0.8047 0.4069 +vn 0.4411 -0.6276 0.6415 +vn -0.5521 -0.8146 -0.1779 +vn 0.5083 0.7103 0.4869 +vn -0.3155 0.9414 -0.1190 +vn -0.0208 -0.9687 -0.2472 +vn -0.8733 -0.2064 0.4414 +vn 0.8761 0.4813 -0.0285 +vn 0.9021 -0.0000 0.4315 +vn -0.4015 0.8659 -0.2985 +vn -0.7736 -0.6238 -0.1111 +vn 0.6558 -0.5637 0.5021 +vn -0.6223 -0.7565 0.2009 +vn 0.6592 0.5618 0.4999 +vn -0.6825 0.7153 -0.1498 +vn 0.1697 0.9201 0.3529 +vn 0.9823 -0.1156 0.1471 +vn -0.9349 -0.2349 0.2662 +vn -0.8339 -0.5196 -0.1859 +vn -0.9168 0.3171 0.2426 +vn -0.6538 -0.7558 0.0363 +vn 0.4378 0.8500 0.2930 +vn 0.4378 -0.8500 0.2930 +vn -0.5590 0.6725 0.4850 +vn -0.3805 -0.7763 0.5026 +vn -0.8873 -0.3637 0.2836 +vn 0.0743 -0.7305 0.6789 +vn -0.7928 0.6090 0.0220 +vn 0.8905 -0.3131 0.3300 +vn -0.2575 0.9428 -0.2116 +vn -0.7588 0.4832 0.4368 +vn 0.3770 0.7345 0.5643 +vn 0.6976 0.2358 0.6766 +vn 0.9735 -0.1094 0.2009 +vn -0.6611 0.4020 0.6336 +vn 0.5916 -0.5676 0.5725 +vn 0.0496 -0.8132 -0.5799 +vn -0.1678 -0.7199 0.6735 +vn 0.2633 -0.9093 0.3222 +vn 0.4908 -0.8713 -0.0079 +vn 0.0478 -0.9235 -0.3806 +vn -0.5147 0.8057 0.2931 +vn 0.7882 0.5762 0.2160 +vn 0.8143 -0.2622 0.5179 +vn -0.1188 0.8384 0.5319 +vn 0.4671 -0.8671 0.1734 +vn 0.8143 0.2622 0.5179 +vn -0.9298 -0.0837 0.3585 +vn -0.9349 0.2309 0.2697 +vn 0.0001 0.0271 0.9996 +vn 0.7291 0.6496 0.2156 +vn -0.4193 -0.9070 -0.0408 +vn 0.0478 0.9235 -0.3806 +vn 0.4566 0.6423 0.6156 +vn 0.2812 -0.6759 0.6812 +vn -0.8871 -0.4571 0.0648 +vn -0.6953 -0.7030 -0.1497 +vn -0.5124 0.7253 0.4598 +vn -0.1431 0.8457 0.5141 +vn -0.5373 -0.6429 0.5459 +vn 0.5907 0.7447 0.3106 +vn -0.9298 0.0837 0.3585 +vn -0.9966 0.0819 0.0045 +vn -0.6287 -0.5907 0.5058 +vn -0.1431 -0.8457 0.5141 +vn 0.9925 0.1172 0.0351 +vn 0.0087 -0.0127 0.9999 +vn -0.6809 0.7211 0.1278 +vn -0.4015 -0.8659 -0.2985 +vn -0.2315 -0.9084 0.3483 +vn 0.2578 0.9143 -0.3123 +vn -0.0198 -0.8956 -0.4444 +vn 0.5396 0.7957 0.2751 +vn 0.8547 0.1102 0.5073 +vn 0.4762 0.8602 0.1824 +vn 0.8949 -0.4220 0.1448 +vn 0.5135 -0.5035 0.6949 +vn -0.7635 -0.4814 0.4305 +vn 0.7345 -0.3025 0.6075 +vn -0.5669 0.5817 0.5833 +vn -0.5669 -0.5817 0.5833 +vn -0.8339 0.5196 -0.1859 +vn -0.1270 0.7001 0.7026 +vn 0.6820 -0.7142 0.1573 +vn 0.8402 -0.4925 0.2271 +vn -0.5585 0.8052 -0.1992 +vn -0.9941 -0.0926 0.0574 +vn -0.2575 -0.9428 -0.2116 +vn 0.2580 0.9507 -0.1722 +vn -0.7487 -0.6051 0.2708 +vn -0.8897 0.1194 0.4406 +vn -0.8533 0.5181 0.0582 +vn 0.3677 -0.8830 -0.2917 +vn 0.8054 -0.1341 0.5774 +vn -0.7227 0.6769 -0.1394 +vn 0.0001 -0.0271 0.9996 +vn -0.5147 -0.8057 0.2931 +vn 0.0496 0.8132 -0.5799 +vn 0.5872 0.8088 0.0321 +vn 0.0794 -0.0084 0.9968 +vn 0.8837 0.4068 0.2314 +vn -0.1138 -0.9446 -0.3080 +vn -0.8838 0.2856 0.3707 +vn 0.6486 0.4565 0.6091 +vn 0.3811 -0.9243 -0.0224 +vn 0.2418 0.7333 0.6355 +vn 0.7879 -0.6155 0.0168 +vn -0.1902 -0.7909 0.5817 +vn 0.4348 -0.8981 -0.0654 +vn 0.6579 -0.4506 0.6034 +vn 0.7879 0.6155 0.0168 +vn -0.7176 -0.3531 0.6003 +vn -0.1087 0.9188 -0.3795 +vn 0.2071 -0.7303 0.6510 +vn 0.9281 -0.3438 0.1427 +vn -0.8215 0.2806 0.4965 +vn 0.5884 0.4096 0.6971 +vn 0.9460 -0.3238 0.0126 +vn 0.6189 0.6440 0.4497 +vn -0.6027 0.7219 0.3400 +vn 0.7709 -0.5528 0.3163 +vn -0.2106 0.9612 -0.1783 +vn -0.6143 -0.7891 -0.0007 +vn 0.5396 -0.7957 0.2751 +vn 0.8625 -0.3871 0.3260 +vn -0.9840 -0.1777 0.0096 +vn -0.8916 -0.0000 0.4528 +vn 0.0863 0.9961 -0.0181 +vn 0.9169 -0.0231 0.3984 +vn 0.5234 -0.8210 -0.2281 +vn 0.3034 -0.9524 -0.0308 +vn -0.9552 -0.0000 0.2960 +vn -0.2575 -0.9372 -0.2351 +vn 0.5010 0.5036 0.7038 +vn -0.2315 0.9084 0.3483 +vn 0.6248 -0.7606 -0.1763 +vn -0.9215 -0.3719 0.1121 +vn 0.9210 -0.3886 -0.0270 +vn -0.2462 0.7715 0.5867 +vn 0.0430 -0.0895 0.9951 +vn 0.8178 0.5577 0.1417 +vn -0.0106 0.9700 -0.2428 +vn 0.2580 -0.9507 -0.1722 +vn -0.2849 -0.9082 0.3067 +vn -0.3415 0.8629 0.3726 +vn 0.7097 0.1225 0.6938 +vn 0.7032 0.3761 0.6033 +vn 0.7020 0.7034 -0.1113 +vn -0.7329 0.2197 0.6439 +vn -0.7615 -0.0984 0.6406 +vn -0.7329 -0.2197 0.6439 +vn -0.1188 -0.8384 0.5319 +vn -0.6074 -0.7926 -0.0527 +vn 0.8785 -0.0232 0.4772 +vn 0.5083 -0.7103 0.4869 +vn -0.7985 -0.6019 0.0075 +vn -0.4797 0.8758 -0.0527 +vn 0.5121 0.8316 -0.2148 +vn 0.2812 0.6759 0.6812 +vn 0.0706 0.7485 0.6594 +vn 0.3770 -0.7345 0.5643 +vn -0.9103 0.3657 0.1937 +vn -0.4057 0.9084 0.1008 +vn 0.9298 0.3375 0.1471 +vn 0.9691 0.2313 0.0861 +vn 0.9558 0.2914 0.0405 +vn -0.3701 0.9111 0.1814 +vn -0.9377 0.3391 0.0760 +vn -0.8476 0.5046 0.1641 +vn 0.4103 -0.7753 0.4802 +vn 0.2399 0.8867 0.3953 +vn 0.2384 0.7246 0.6466 +vn 0.4881 0.8564 -0.1683 +vn 0.4746 0.8619 -0.1786 +vn 0.3882 0.8814 -0.2691 +vn -0.9739 -0.2261 -0.0206 +vn -0.8577 -0.5138 -0.0182 +vn -0.8533 -0.5181 0.0582 +vn -0.5491 -0.8242 0.1380 +vn -0.5215 -0.8358 -0.1717 +vn -0.6003 -0.7994 0.0264 +vn -0.5147 -0.8345 0.1966 +vn -0.1088 -0.9023 0.4172 +vn -0.0269 -0.8726 0.4877 +vn -0.7917 -0.2674 0.5492 +vn -0.7615 0.0984 0.6406 +vn -0.8288 -0.0000 0.5595 +vn -0.7692 -0.0000 0.6390 +vn -0.7660 0.2759 0.5806 +vn 0.6248 0.7606 -0.1763 +vn 0.7097 -0.1225 0.6938 +vn 0.7499 -0.0000 0.6616 +vn 0.6453 0.0344 0.7631 +vn 0.1407 -0.9635 -0.2277 +vn 0.9000 0.4354 0.0230 +vn 0.7896 0.6102 -0.0647 +vn 0.8746 0.4829 -0.0437 +vn -0.2813 0.6966 0.6600 +vn 0.8043 -0.5913 -0.0592 +vn -0.9363 -0.3018 0.1795 +vn 0.7281 -0.6826 -0.0629 +vn -0.1978 0.8629 0.4651 +vn -0.3882 -0.9110 -0.1392 +vn -0.3155 -0.9414 -0.1190 +vn 0.9898 0.1166 0.0824 +vn 0.9711 0.1451 0.1895 +vn 0.9498 0.2526 0.1848 +vn 0.4333 -0.8702 -0.2345 +vn 0.4881 -0.8564 -0.1683 +vn 0.4746 -0.8619 -0.1786 +vn 0.9456 0.0628 0.3193 +vn 0.9484 -0.0000 0.3172 +vn 0.9847 -0.0000 0.1741 +vn -0.9565 0.2379 0.1687 +vn -0.9838 0.1792 0.0069 +vn -0.9628 0.2699 0.0102 +vn -0.9265 0.3761 0.0077 +vn 0.8214 -0.4710 0.3215 +vn 0.5015 -0.8096 0.3052 +vn 0.4233 -0.8221 0.3806 +vn 0.6878 -0.6005 0.4078 +vn 0.6123 -0.6486 0.4521 +vn 0.7148 -0.6267 0.3104 +vn -0.7928 -0.6090 0.0220 +vn 0.6878 0.6005 0.4078 +vn -0.6143 0.7891 -0.0007 +vn 0.8240 -0.5514 0.1305 +vn 0.9068 -0.4214 0.0056 +vn 0.6338 0.3263 0.7013 +vn -0.8099 0.4057 0.4236 +vn 0.9370 -0.3494 0.0076 +vn 0.2622 -0.7849 0.5614 +vn -0.0733 0.8412 -0.5357 +vn -0.0314 0.9006 -0.4335 +vn -0.6568 -0.4850 0.5774 +vn -0.6611 -0.4020 0.6336 +vn 0.7258 0.6753 0.1313 +vn 0.6349 0.7712 0.0469 +vn 0.6349 -0.7712 0.0469 +vn 0.7258 -0.6753 0.1313 +vn 0.2352 0.7936 0.5612 +vn 0.5947 -0.7936 -0.1285 +vn 0.6285 -0.7756 -0.0591 +vn -0.8873 0.3637 0.2836 +vn 0.8949 0.4220 0.1448 +vn 0.9164 0.3241 0.2349 +vn 0.6857 -0.2198 0.6939 +vn 0.6285 0.7756 -0.0591 +vn 0.5432 0.8232 -0.1653 +vn -0.5216 -0.8299 0.1980 +vn -0.7659 0.6216 0.1645 +vn 0.9587 0.2840 -0.0135 +vn 0.2578 -0.9143 -0.3123 +vn -0.8577 0.5138 -0.0182 +vn -0.9739 0.2261 -0.0206 +vn -0.7985 0.6019 0.0075 +vn -0.8733 0.2064 0.4414 +vn -0.8278 0.1152 0.5491 +vn -0.6711 -0.6334 0.3852 +vn 0.1407 0.9635 -0.2277 +vn -0.1988 -0.9381 -0.2836 +vn -0.5702 -0.7233 -0.3894 +vn -0.2307 -0.9111 -0.3415 +vn -0.9985 -0.0399 0.0380 +vn -0.0333 0.7499 0.6607 +vn -0.5125 -0.5357 0.6711 +vn -0.5280 0.5383 0.6569 +vn 0.9164 -0.3241 0.2349 +vn 0.8837 -0.4068 0.2314 +vn 0.5542 0.8140 0.1739 +vn 0.7587 0.2414 0.6050 +vn 0.4312 0.8133 0.3908 +vn 0.5015 0.8096 0.3052 +vn -0.1087 -0.9188 -0.3795 +vn -0.0733 -0.8412 -0.5357 +vn 0.3677 0.8830 -0.2917 +vn 0.9587 -0.2840 -0.0135 +vn -0.1978 -0.8629 0.4651 +vn -0.3805 0.7763 0.5026 +vn 0.1378 -0.8739 0.4662 +vn -0.9168 -0.3171 0.2426 +vn 0.1378 0.8739 0.4662 +vn -0.4059 0.8332 0.3756 +vn -0.5077 0.7873 0.3500 +vn -0.9103 -0.3657 0.1937 +vn -0.9046 -0.4110 0.1127 +vn -0.8494 -0.5027 0.1607 +vn 0.2399 -0.8867 0.3953 +vn 0.2384 -0.7246 0.6466 +vn 0.1542 0.9156 -0.3714 +vn 0.1572 0.7333 -0.6615 +vn -0.7659 -0.6216 0.1645 +vn -0.9485 0.1784 0.2618 +vn -0.9709 0.1718 0.1666 +vn 0.8177 0.3317 0.4705 +vn 0.5542 -0.8140 0.1739 +vn -0.0471 0.8744 0.4829 +vn -0.1104 0.9023 0.4167 +vn 0.8062 -0.3582 0.4709 +vn -0.5216 0.8299 0.1980 +vn 0.1542 -0.9156 -0.3714 +vn 0.1572 -0.7333 -0.6615 +vn 0.4261 -0.8972 0.1164 +vn 0.4856 -0.8708 -0.0762 +vn 0.3124 -0.7939 0.5217 +vn 0.2708 -0.8676 0.4171 +vn -0.0333 -0.7499 0.6607 +vn 0.1490 -0.1043 0.9833 +vn -0.7179 0.3509 0.6012 +vn -0.6568 0.4850 0.5774 +vn 0.9388 -0.1846 0.2908 +vn 0.9587 -0.2233 0.1761 +vn 0.0794 0.0084 0.9968 +vn 0.4103 0.7753 0.4802 +vn -0.1988 0.9381 -0.2836 +vn -0.5702 0.7233 -0.3894 +vn -0.2466 0.9039 -0.3496 +vn 0.9333 -0.1829 0.3090 +vn 0.8918 -0.1833 0.4137 +vn -0.6308 -0.7036 0.3273 +vn -0.8838 -0.2856 0.3707 +vn 0.0087 0.0127 0.9999 +vn 0.3029 -0.9124 0.2752 +vn 0.3772 0.9048 0.1977 +vn -0.8189 0.5739 0.0016 +vn -0.7089 -0.7027 -0.0609 +vn -0.7417 -0.6706 0.0139 +vn -0.8961 -0.4435 0.0170 +vn -0.6816 -0.7314 0.0207 +vn -0.6287 0.5907 0.5058 +vn -0.9526 -0.1706 0.2520 +vn -0.9852 -0.1075 0.1337 +vn 0.9808 -0.1947 0.0112 +vn 0.2633 0.9093 0.3222 +vn 0.3124 0.7939 0.5217 +vn 0.2758 0.8772 0.3930 +vn 0.7424 0.5298 0.4100 +vn 0.7105 0.4908 0.5044 +vn 0.7771 0.4270 0.4623 +vn 0.7424 -0.5298 0.4100 +vn 0.7105 -0.4908 0.5044 +vn 0.7630 -0.4515 0.4626 +vn 0.8345 -0.0227 0.5505 +vn 0.8031 0.5904 -0.0796 +vn -0.8897 -0.1194 0.4406 +vn -0.8278 -0.1152 0.5491 +vn -0.2575 0.9372 -0.2351 +vn -0.3882 0.9110 -0.1392 +vn -0.5124 -0.7253 0.4598 +vn -0.5331 -0.7550 0.3819 +vn 0.9328 0.1300 0.3360 +vn 0.0554 -0.0011 0.9985 +vn -0.5477 -0.0806 0.8328 +vn -0.4603 0.6620 0.5915 +vn -0.7661 0.5679 0.3010 +vn -0.6452 0.7614 -0.0629 +vn -0.5147 0.8345 0.1966 +vn -0.5655 0.8240 -0.0365 +vn -0.5429 0.8333 0.1045 +vn -0.3691 -0.9100 0.1890 +vn 0.6344 -0.3350 0.6967 +vn -0.4096 -0.6073 0.6808 +vn -0.8388 -0.2683 0.4738 +vn -0.8189 -0.5739 0.0016 +vn -0.7417 0.6706 0.0139 +vn -0.6816 0.7314 0.0207 +vn -0.7089 0.7027 -0.0609 +vn -0.8961 0.4435 0.0170 +vn -0.9393 -0.3429 -0.0073 +vn 0.0430 0.0895 0.9951 +vn 0.5767 0.5690 0.5862 +vn 0.4261 0.8972 0.1164 +vn 0.4856 0.8708 -0.0762 +vn -0.9847 -0.0000 0.1745 +vn 0.7148 0.6267 0.3104 +vn 0.8214 0.4710 0.3215 +vn -0.9877 -0.1563 -0.0111 +vn -0.9791 -0.2036 -0.0028 +vn -0.9686 -0.2362 0.0781 +vn -0.9828 -0.1786 0.0463 +vn -0.9924 -0.1109 0.0531 +vn 0.8577 0.3926 0.3320 +vn 0.6336 -0.7233 0.2745 +vn 0.6575 -0.6874 0.3083 +vn 0.7657 0.5572 0.3213 +vn -0.1205 0.9464 -0.2995 +vn 0.4565 0.8892 0.0295 +vn 0.4908 0.8713 -0.0079 +vn 0.4890 0.8720 -0.0209 +vn -0.2722 -0.6869 0.6738 +vn -0.6537 0.7559 0.0364 +vn -0.6534 0.7549 0.0555 +vn -0.8178 -0.3904 0.4229 +vn -0.8584 -0.3496 0.3754 +vn -0.8095 -0.4072 0.4231 +vn -0.1272 -0.9687 -0.2132 +vn -0.1022 -0.9734 -0.2053 +vn -0.2111 -0.9609 -0.1794 +vn -0.2227 -0.9608 -0.1651 +vn -0.1557 -0.9692 -0.1908 +vn -0.8531 -0.4328 0.2912 +vn -0.8427 -0.4705 0.2619 +vn 0.5853 -0.4102 0.6994 +vn -0.4057 -0.9084 0.1008 +vn -0.6711 0.6334 0.3852 +vn -0.4096 0.6073 0.6808 +vn 0.9113 0.2341 0.3387 +vn 0.9117 0.2402 0.3334 +vn 0.8905 0.3131 0.3300 +vn 0.8961 0.1448 0.4196 +vn 0.3091 0.9207 -0.2384 +vn 0.3139 0.9375 -0.1505 +vn 0.3320 0.9342 -0.1310 +vn 0.4094 0.9080 -0.0895 +vn 0.4324 0.8914 -0.1358 +vn 0.3196 0.9319 -0.1718 +vn -0.8427 0.4705 0.2619 +vn -0.8531 0.4328 0.2912 +vn -0.4059 -0.8332 0.3756 +vn 0.4566 -0.6423 0.6156 +vn 0.4073 -0.6301 0.6612 +vn 0.3965 -0.5985 0.6961 +vn -0.5502 -0.8109 -0.1995 +vn -0.5585 -0.8052 -0.1992 +vn 0.5613 0.7027 0.4371 +vn 0.5471 0.7103 0.4429 +vn -0.0134 -0.9372 -0.3486 +vn 0.0538 -0.9685 -0.2431 +vn 0.0551 -0.9687 -0.2421 +vn -0.0390 -0.9590 -0.2809 +vn -0.0586 -0.9760 -0.2100 +vn -0.0106 -0.9700 -0.2428 +vn -0.4108 0.8596 -0.3039 +vn -0.7291 -0.6648 -0.1626 +vn -0.7227 -0.6769 -0.1394 +vn 0.6592 -0.5618 0.4999 +vn -0.6503 -0.7273 0.2193 +vn -0.7061 -0.6885 0.1655 +vn -0.6809 -0.7211 0.1278 +vn 0.6558 0.5637 0.5021 +vn -0.6953 0.7030 -0.1497 +vn -0.6286 0.7597 -0.1663 +vn 0.9823 -0.1155 0.1472 +vn -0.9349 -0.2309 0.2697 +vn -0.8345 -0.4995 -0.2328 +vn -0.6534 -0.7549 0.0555 +vn -0.6537 -0.7559 0.0364 +vn 0.4606 0.8410 0.2839 +vn 0.4606 -0.8410 0.2839 +vn -0.5622 0.6720 0.4820 +vn -0.5373 0.6429 0.5459 +vn -0.3780 -0.7780 0.5018 +vn -0.3681 -0.7787 0.5080 +vn -0.3709 -0.7777 0.5075 +vn -0.9145 -0.2970 0.2749 +vn -0.9148 -0.2929 0.2783 +vn -0.8879 -0.3600 0.2864 +vn 0.0706 -0.7485 0.6594 +vn 0.8908 -0.3061 0.3357 +vn -0.7426 0.5483 0.3845 +vn -0.7712 0.4730 0.4260 +vn -0.7635 0.4814 0.4305 +vn 0.6857 0.2198 0.6939 +vn 0.9725 -0.1009 0.2100 +vn -0.6733 0.3664 0.6422 +vn 0.5767 -0.5690 0.5862 +vn -0.1086 -0.7402 0.6635 +vn -0.1270 -0.7001 0.7026 +vn 0.2167 -0.8949 0.3901 +vn 0.2263 -0.8929 0.3893 +vn 0.4565 -0.8892 0.0295 +vn 0.5139 -0.8569 -0.0410 +vn 0.4890 -0.8720 -0.0209 +vn 0.0665 -0.8991 -0.4328 +vn 0.0710 -0.9106 -0.4072 +vn 0.0450 -0.9363 -0.3483 +vn -0.0078 -0.9245 -0.3810 +vn -0.0106 -0.9229 -0.3848 +vn -0.5190 0.8052 0.2868 +vn 0.8402 0.4925 0.2271 +vn 0.8173 0.5457 0.1850 +vn -0.1330 0.8067 0.5758 +vn 0.4762 -0.8602 0.1824 +vn -0.9205 -0.1718 0.3511 +vn -0.9114 -0.0817 0.4034 +vn -0.9198 -0.1374 0.3675 +vn -0.9421 -0.1356 0.3068 +vn -0.9539 -0.0922 0.2857 +vn -0.9349 0.2349 0.2662 +vn 0.6932 0.7087 0.1308 +vn 0.6144 0.7701 0.1716 +vn 0.6820 0.7142 0.1573 +vn 0.6470 0.7404 0.1825 +vn -0.4184 -0.9081 0.0180 +vn -0.4232 -0.9048 0.0462 +vn -0.4797 -0.8758 -0.0527 +vn -0.4550 -0.8903 -0.0148 +vn 0.0710 0.9106 -0.4072 +vn 0.0665 0.8990 -0.4328 +vn -0.0106 0.9229 -0.3848 +vn 0.0450 0.9363 -0.3483 +vn -0.0078 0.9245 -0.3810 +vn 0.4411 0.6276 0.6415 +vn 0.3965 0.5985 0.6961 +vn 0.4073 0.6301 0.6612 +vn -0.6825 -0.7153 -0.1498 +vn -0.6286 -0.7597 -0.1663 +vn -0.5622 -0.6720 0.4820 +vn -0.5590 -0.6725 0.4850 +vn 0.6575 0.6874 0.3083 +vn 0.6336 0.7233 0.2745 +vn -0.9198 0.1374 0.3675 +vn -0.9205 0.1718 0.3511 +vn -0.9539 0.0922 0.2857 +vn -0.9421 0.1356 0.3068 +vn -0.9114 0.0817 0.4034 +vn -0.9946 0.1040 0.0012 +vn -0.9991 0.0418 0.0050 +vn -0.6160 -0.6071 0.5019 +vn 0.9964 -0.0000 0.0844 +vn 0.9987 -0.0102 0.0506 +vn 0.9993 0.0366 0.0075 +vn 0.9988 0.0367 -0.0324 +vn 0.9985 0.0555 -0.0039 +vn -0.7061 0.6885 0.1655 +vn -0.6503 0.7273 0.2193 +vn -0.6223 0.7565 0.2009 +vn -0.4108 -0.8596 -0.3039 +vn -0.1793 -0.9144 0.3629 +vn -0.2129 -0.9122 0.3501 +vn 0.2630 0.9104 -0.3193 +vn 0.2754 0.9091 -0.3126 +vn 0.2396 0.9355 -0.2598 +vn -0.0314 -0.9006 -0.4335 +vn 0.8014 0.1423 0.5809 +vn 0.8214 0.1085 0.5599 +vn 0.8323 0.1379 0.5369 +vn 0.4671 0.8671 0.1734 +vn 0.8923 -0.4293 0.1398 +vn 0.5010 -0.5036 0.7038 +vn -0.7426 -0.5483 0.3845 +vn -0.7588 -0.4832 0.4368 +vn -0.7712 -0.4730 0.4260 +vn 0.7032 -0.3761 0.6033 +vn 0.6995 -0.3790 0.6059 +vn 0.7346 -0.3083 0.6044 +vn -0.8345 0.4995 -0.2328 +vn -0.1086 0.7402 0.6635 +vn -0.1678 0.7199 0.6735 +vn 0.6144 -0.7701 0.1716 +vn 0.6932 -0.7087 0.1308 +vn 0.7291 -0.6496 0.2156 +vn 0.6470 -0.7404 0.1825 +vn 0.7882 -0.5762 0.2160 +vn 0.8173 -0.5457 0.1850 +vn -0.5502 0.8109 -0.1995 +vn -0.5521 0.8146 -0.1779 +vn 0.2505 0.9520 -0.1761 +vn 0.2037 0.9607 -0.1883 +vn -0.7661 -0.5679 0.3010 +vn 0.7566 -0.2253 0.6139 +vn 0.7587 -0.2414 0.6050 +vn 0.8391 -0.1792 0.5137 +vn 0.8150 -0.1048 0.5700 +vn 0.8076 -0.1437 0.5719 +vn -0.7291 0.6648 -0.1626 +vn -0.7736 0.6238 -0.1111 +vn -0.5190 -0.8052 0.2868 +vn 0.4857 0.8731 -0.0412 +vn 0.3811 0.9243 -0.0224 +vn 0.5954 0.8034 -0.0033 +vn 0.6346 0.7724 -0.0260 +vn 0.8818 0.4142 0.2258 +vn -0.1205 -0.9464 -0.2995 +vn -0.8838 0.2849 0.3712 +vn -0.9028 0.2250 0.3665 +vn -0.9017 0.2140 0.3756 +vn 0.6579 0.4506 0.6034 +vn 0.4857 -0.8731 -0.0412 +vn 0.6346 -0.7724 -0.0260 +vn 0.5872 -0.8088 0.0321 +vn 0.5954 -0.8034 -0.0033 +vn -0.2462 -0.7715 0.5867 +vn -0.2076 -0.7959 0.5687 +vn 0.3091 -0.9207 -0.2384 +vn 0.4324 -0.8914 -0.1358 +vn 0.3196 -0.9319 -0.1718 +vn 0.3320 -0.9342 -0.1310 +vn 0.3139 -0.9375 -0.1505 +vn 0.4094 -0.9080 -0.0895 +vn 0.6486 -0.4565 0.6091 +vn -0.7179 -0.3509 0.6012 +vn -0.1132 0.9094 -0.4002 +vn 0.9298 -0.3375 0.1471 +vn -0.8388 0.2683 0.4738 +vn 0.5853 0.4102 0.6994 +vn 0.6123 0.6486 0.4521 +vn -0.6308 0.7036 0.3273 +vn 0.7657 -0.5572 0.3213 +vn -0.1022 0.9734 -0.2053 +vn -0.2111 0.9609 -0.1794 +vn -0.1272 0.9687 -0.2132 +vn -0.2227 0.9608 -0.1651 +vn -0.1557 0.9692 -0.1908 +vn 0.8577 -0.3926 0.3320 +vn -0.8918 -0.0090 0.4523 +vn -0.8918 0.0090 0.4523 +vn 0.9248 -0.0413 0.3781 +vn 0.5121 -0.8316 -0.2148 +vn -0.9553 -0.0097 0.2955 +vn -0.9553 0.0097 0.2955 +vn 0.5135 0.5035 0.6949 +vn -0.2129 0.9122 0.3501 +vn -0.1793 0.9144 0.3629 +vn -0.9494 -0.3015 0.0885 +vn -0.9440 -0.3189 0.0849 +vn -0.1902 0.7909 0.5817 +vn -0.2076 0.7959 0.5687 +vn 0.8213 0.5610 0.1038 +vn 0.7866 0.6130 0.0732 +vn 0.8240 0.5514 0.1305 +vn -0.0134 0.9372 -0.3486 +vn -0.0390 0.9590 -0.2809 +vn -0.0586 0.9760 -0.2100 +vn -0.0208 0.9687 -0.2472 +vn 0.0551 0.9687 -0.2421 +vn 0.0538 0.9685 -0.2431 +vn 0.2037 -0.9607 -0.1883 +vn 0.2505 -0.9520 -0.1761 +vn -0.4200 -0.8622 0.2832 +vn -0.3579 -0.9096 0.2112 +vn -0.2923 -0.9102 0.2936 +vn -0.3415 -0.8629 0.3726 +vn -0.2808 -0.9129 0.2963 +vn -0.2849 0.9082 0.3067 +vn -0.2923 0.9102 0.2936 +vn -0.2808 0.9129 0.2963 +vn -0.3579 0.9096 0.2112 +vn -0.4200 0.8622 0.2832 +vn 0.7345 0.3025 0.6075 +vn 0.7346 0.3083 0.6044 +vn 0.6995 0.3790 0.6059 +vn 0.7281 0.6826 -0.0629 +vn 0.6833 0.7228 -0.1034 +vn 0.6912 0.6787 -0.2482 +vn -0.7713 -0.1042 0.6279 +vn -0.1330 -0.8067 0.5758 +vn -0.6452 -0.7614 -0.0629 +vn 0.8841 -0.0217 0.4667 +vn 0.5471 -0.7103 0.4429 +vn 0.5613 -0.7027 0.4371 +vn -0.7974 -0.6035 0.0059 +vn -0.7862 -0.6179 0.0102 +vn -0.4232 0.9048 0.0462 +vn -0.4193 0.9070 -0.0408 +vn -0.4184 0.9081 0.0180 +vn -0.4550 0.8903 -0.0148 +vn 0.5234 0.8210 -0.2281 +vn 0.0743 0.7305 0.6789 +vn -0.9091 0.3707 0.1900 +vn -0.4057 0.9084 0.1013 +vn 0.9281 0.3438 0.1427 +vn 0.9733 0.2295 -0.0058 +vn 0.9705 0.2407 -0.0150 +vn 0.9262 0.3741 -0.0464 +vn 0.9132 0.4045 0.0488 +vn 0.9442 0.3291 0.0167 +vn 0.9337 0.3496 -0.0768 +vn -0.3691 0.9100 0.1890 +vn -0.8494 0.5027 0.1607 +vn -0.8546 0.4786 0.2012 +vn 0.3981 -0.7746 0.4915 +vn 0.3832 0.9033 -0.1930 +vn 0.4333 0.8702 -0.2345 +vn -0.5429 -0.8333 0.1045 +vn -0.6530 -0.7572 -0.0163 +vn -0.6725 -0.7319 -0.1101 +vn -0.5664 -0.8221 -0.0587 +vn -0.5151 -0.8570 -0.0146 +vn -0.4810 -0.8754 0.0473 +vn -0.5655 -0.8240 -0.0365 +vn -0.5222 -0.8495 0.0745 +vn -0.1104 -0.9023 0.4167 +vn -0.0471 -0.8744 0.4829 +vn -0.0458 -0.8749 0.4821 +vn -0.7660 -0.2759 0.5806 +vn -0.7713 0.1042 0.6279 +vn -0.7917 0.2674 0.5492 +vn 0.7312 -0.0607 0.6794 +vn 0.6748 -0.0835 0.7332 +vn 0.5880 -0.0033 0.8088 +vn 0.1361 -0.9622 -0.2358 +vn 0.1398 -0.9592 -0.2459 +vn 0.8896 0.4564 0.0200 +vn 0.9035 0.4283 0.0142 +vn 0.9097 0.4105 -0.0630 +vn -0.2722 0.6869 0.6738 +vn -0.9565 -0.2379 0.1687 +vn -0.9571 -0.2320 0.1737 +vn -0.9373 -0.2959 0.1840 +vn 0.7020 -0.7034 -0.1113 +vn 0.6912 -0.6787 -0.2482 +vn 0.6833 -0.7228 -0.1034 +vn -0.2659 0.8494 0.4559 +vn -0.2108 0.8536 0.4765 +vn -0.1630 0.8632 0.4778 +vn -0.4098 -0.9069 -0.0975 +vn -0.4127 -0.9060 -0.0941 +vn -0.4100 -0.9077 -0.0894 +vn -0.3855 -0.9091 -0.1580 +vn 0.9897 0.1138 0.0868 +vn 0.9779 0.1120 0.1766 +vn 0.9779 0.1163 0.1739 +vn 0.9638 0.1862 0.1908 +vn 0.9583 0.2277 0.1726 +vn 0.3832 -0.9033 -0.1930 +vn 0.3882 -0.8814 -0.2691 +vn 0.9303 0.0896 0.3557 +vn -0.9355 0.3014 0.1845 +vn -0.9532 0.2649 0.1458 +vn -0.9755 0.2197 0.0075 +vn -0.9406 0.3386 0.0244 +vn -0.9400 0.3412 0.0060 +vn 0.8162 -0.4761 0.3272 +vn 0.4886 -0.7907 0.3689 +vn 0.4312 -0.8133 0.3908 +vn 0.6921 -0.5979 0.4045 +vn 0.6189 -0.6440 0.4497 +vn 0.7098 -0.6301 0.3148 +vn 0.6921 0.5979 0.4045 +vn 0.7866 -0.6130 0.0732 +vn 0.8213 -0.5610 0.1038 +vn 0.8178 -0.5577 0.1417 +vn 0.9000 -0.4354 0.0230 +vn 0.8755 -0.4832 -0.0045 +vn 0.6344 0.3350 0.6967 +vn -0.8095 0.4072 0.4231 +vn -0.8584 0.3496 0.3754 +vn -0.8178 0.3904 0.4229 +vn 0.9456 -0.3254 0.0069 +vn 0.9629 -0.2696 0.0108 +vn -0.0198 0.8956 -0.4444 +vn -0.6733 -0.3664 0.6422 +vn 0.6588 0.7516 0.0318 +vn 0.6886 0.7214 0.0736 +vn 0.7604 0.6493 0.0130 +vn 0.6717 0.7401 -0.0312 +vn 0.6721 0.7398 -0.0318 +vn 0.6717 -0.7401 -0.0312 +vn 0.6886 -0.7214 0.0736 +vn 0.6721 -0.7398 -0.0318 +vn 0.7604 -0.6493 0.0130 +vn 0.6588 -0.7516 0.0318 +vn 0.5748 -0.8129 -0.0941 +vn 0.5212 -0.8479 -0.0972 +vn 0.5432 -0.8232 -0.1653 +vn -0.8879 0.3600 0.2864 +vn -0.9148 0.2929 0.2783 +vn -0.9145 0.2970 0.2749 +vn 0.8923 0.4293 0.1398 +vn 0.9154 0.3308 0.2295 +vn 0.6976 -0.2358 0.6766 +vn 0.5212 0.8479 -0.0972 +vn 0.5748 0.8129 -0.0941 +vn 0.5947 0.7936 -0.1285 +vn -0.5283 -0.8280 0.1877 +vn -0.7614 0.6259 0.1688 +vn 0.2396 -0.9355 -0.2598 +vn 0.2754 -0.9091 -0.3126 +vn 0.2630 -0.9104 -0.3193 +vn -0.7862 0.6179 0.0102 +vn -0.7974 0.6035 0.0059 +vn -0.8362 0.0806 0.5424 +vn -0.8410 0.1304 0.5251 +vn -0.8126 0.1584 0.5609 +vn -0.6641 -0.6617 0.3479 +vn 0.1398 0.9592 -0.2459 +vn 0.1361 0.9622 -0.2358 +vn -0.2341 -0.9086 -0.3458 +vn -0.2466 -0.9039 -0.3496 +vn -1.0000 -0.0014 -0.0007 +vn -0.9998 -0.0201 -0.0094 +vn -0.9962 -0.0863 -0.0088 +vn -0.0369 0.7558 0.6537 +vn -0.5280 -0.5383 0.6569 +vn -0.5125 0.5357 0.6711 +vn 0.9154 -0.3308 0.2295 +vn 0.8818 -0.4142 0.2258 +vn 0.5606 0.8116 0.1645 +vn 0.5465 0.8279 0.1263 +vn 0.5153 0.8502 0.1080 +vn 0.7566 0.2253 0.6139 +vn 0.4886 0.7907 0.3689 +vn 0.4233 0.8221 0.3806 +vn -0.1132 -0.9094 -0.4002 +vn -0.1630 -0.8632 0.4778 +vn -0.2108 -0.8536 0.4765 +vn -0.2659 -0.8494 0.4559 +vn -0.3709 0.7777 0.5075 +vn -0.3681 0.7787 0.5080 +vn -0.3780 0.7780 0.5018 +vn 0.0922 -0.8620 0.4984 +vn 0.0534 -0.8741 0.4828 +vn 0.0534 0.8741 0.4828 +vn 0.0922 0.8620 0.4984 +vn -0.4322 0.8047 0.4069 +vn -0.5331 0.7550 0.3819 +vn -0.9091 -0.3707 0.1900 +vn -0.8476 -0.5046 0.1641 +vn -0.8546 -0.4786 0.2012 +vn 0.1470 0.9189 -0.3660 +vn -0.7614 -0.6259 0.1688 +vn -0.9526 0.1706 0.2520 +vn -0.9709 0.1751 0.1636 +vn -0.9852 0.1075 0.1337 +vn -0.9795 0.0926 0.1788 +vn -0.9662 0.0966 0.2392 +vn 0.8555 0.2919 0.4277 +vn 0.8062 0.3582 0.4709 +vn 0.8141 0.3471 0.4656 +vn 0.5153 -0.8502 0.1080 +vn 0.5465 -0.8279 0.1263 +vn 0.5606 -0.8116 0.1645 +vn -0.0269 0.8726 0.4877 +vn -0.0458 0.8749 0.4821 +vn -0.1088 0.9023 0.4172 +vn 0.8555 -0.2919 0.4277 +vn 0.8177 -0.3317 0.4705 +vn 0.8141 -0.3471 0.4656 +vn -0.5283 0.8280 0.1877 +vn 0.1470 -0.9189 -0.3660 +vn 0.4245 -0.8962 0.1293 +vn 0.2678 -0.8910 0.3666 +vn -0.0369 -0.7558 0.6537 +vn -0.7176 0.3531 0.6003 +vn 0.9691 -0.1959 0.1498 +vn 0.9477 -0.2201 0.2311 +vn 0.9533 -0.2651 0.1449 +vn 0.3981 0.7746 0.4915 +vn -0.2341 0.9086 -0.3458 +vn -0.2307 0.9111 -0.3415 +vn 0.9245 -0.1897 0.3307 +vn 0.8866 -0.1872 0.4230 +vn -0.6027 -0.7219 0.3400 +vn -0.9017 -0.2140 0.3756 +vn -0.9028 -0.2250 0.3665 +vn -0.8838 -0.2849 0.3712 +vn 0.3772 -0.9048 0.1977 +vn 0.3368 -0.9231 0.1855 +vn 0.3713 -0.8989 0.2327 +vn 0.3561 -0.9013 0.2469 +vn 0.3029 0.9124 0.2752 +vn 0.3561 0.9013 0.2469 +vn 0.3713 0.8989 0.2327 +vn 0.3368 0.9231 0.1855 +vn -0.6160 0.6071 0.5019 +vn -0.9485 -0.1784 0.2618 +vn -0.9709 -0.1751 0.1636 +vn -0.9662 -0.0966 0.2392 +vn -0.9709 -0.1718 0.1666 +vn -0.9795 -0.0926 0.1788 +vn 0.9930 -0.1174 -0.0127 +vn 0.9922 -0.1125 0.0527 +vn 0.9799 -0.1995 0.0076 +vn 0.2263 0.8929 0.3893 +vn 0.2167 0.8949 0.3901 +vn 0.7689 0.4369 0.4668 +vn 0.7630 0.4515 0.4626 +vn 0.7689 -0.4369 0.4668 +vn 0.7771 -0.4270 0.4623 +vn -0.8126 -0.1584 0.5609 +vn -0.8410 -0.1304 0.5251 +vn -0.8362 -0.0806 0.5424 +vn -0.4127 0.9060 -0.0941 +vn -0.4098 0.9069 -0.0975 +vn -0.3855 0.9091 -0.1580 +vn -0.4100 0.9077 -0.0894 +vn -0.5077 -0.7873 0.3500 +vn 0.9249 0.1770 0.3365 +vn 0.9221 0.1606 0.3522 +vn -0.7487 0.6051 0.2708 +vn -0.6074 0.7926 -0.0527 +vn -0.5222 0.8495 0.0745 +vn -0.4810 0.8754 0.0473 +vn -0.5151 0.8570 -0.0146 +vn -0.5664 0.8221 -0.0587 +vn -0.6530 0.7572 -0.0163 +vn -0.6003 0.7994 0.0264 +vn -0.6725 0.7319 -0.1101 +vn -0.5491 0.8242 0.1380 +vn -0.3701 -0.9111 0.1814 +vn 0.6338 -0.3263 0.7013 +vn -0.4266 -0.6131 0.6649 +vn -0.8215 -0.2806 0.4965 +vn -0.9406 -0.3386 0.0244 +vn -0.9314 -0.3640 -0.0053 +vn 0.5916 0.5676 0.5725 +vn 0.4245 0.8962 0.1293 +vn 0.7098 0.6301 0.3148 +vn 0.8162 0.4761 0.3272 +vt 0.648313 0.648495 +vt 0.639305 0.524687 +vt 0.725641 0.566882 +vt 0.765768 0.711581 +vt 0.793954 0.683846 +vt 0.789155 0.712090 +vt 0.843713 0.713741 +vt 0.813094 0.714567 +vt 0.830975 0.685731 +vt 0.810199 0.712586 +vt 0.834799 0.684771 +vt 0.829291 0.713043 +vt 0.655159 0.143011 +vt 0.438080 0.201364 +vt 0.461255 0.145602 +vt 0.413780 0.664014 +vt 0.493273 0.659596 +vt 0.572766 0.664014 +vt 0.816673 0.615456 +vt 0.688903 0.407118 +vt 0.696549 0.502896 +vt 0.833558 0.793344 +vt 0.819197 0.809810 +vt 0.795323 0.831421 +vt 0.661823 0.789785 +vt 0.731819 0.805883 +vt 0.741820 0.790292 +vt 0.762769 0.108185 +vt 0.779626 0.532517 +vt 0.767706 0.590148 +vt 0.847123 0.613536 +vt 0.809874 0.614344 +vt 0.833123 0.438673 +vt 0.741301 0.763475 +vt 0.754327 0.710672 +vt 0.762588 0.764083 +vt 0.645905 0.198351 +vt 0.627987 0.289810 +vt 0.697268 0.224982 +vt 0.778649 0.790203 +vt 0.770987 0.765966 +vt 0.803366 0.683421 +vt 0.797570 0.711719 +vt 0.776841 0.711212 +vt 0.837744 0.312431 +vt 0.832914 0.279296 +vt 0.851090 0.304098 +vt 0.674339 0.615913 +vt 0.765497 0.614967 +vt 0.681890 0.585670 +vt 0.821360 0.646769 +vt 0.806681 0.652958 +vt 0.762790 0.653409 +vt 0.169807 0.712168 +vt 0.143461 0.739823 +vt 0.145761 0.684264 +vt 0.789037 0.822211 +vt 0.762327 0.857706 +vt 0.799157 0.832175 +vt 0.739646 0.711085 +vt 0.743546 0.682897 +vt 0.615304 0.740650 +vt 0.601788 0.709698 +vt 0.684945 0.389012 +vt 0.817218 0.218138 +vt 0.774578 0.217635 +vt 0.209705 0.711212 +vt 0.188976 0.711719 +vt 0.183180 0.683421 +vt 0.754087 0.713098 +vt 0.724655 0.739928 +vt 0.769361 0.740011 +vt 0.744039 0.211845 +vt 0.776563 0.209884 +vt 0.795354 0.262868 +vt 0.800853 0.186886 +vt 0.821993 0.226747 +vt 0.847264 0.212008 +vt 0.785719 0.741121 +vt 0.776563 0.766966 +vt 0.815831 0.767650 +vt 0.672885 0.375467 +vt 0.653594 0.324341 +vt 0.513462 0.163031 +vt 0.478192 0.240003 +vt 0.680734 0.760930 +vt 0.655190 0.735962 +vt 0.698156 0.736448 +vt 0.828064 0.221569 +vt 0.830178 0.306008 +vt 0.784768 0.100753 +vt 0.610405 0.776160 +vt 0.426266 0.776160 +vt 0.362310 0.738967 +vt 0.747883 0.100933 +vt 0.837278 0.100863 +vt 0.816408 0.207321 +vt 0.799856 0.205160 +vt 0.779612 0.110197 +vt 0.222820 0.765893 +vt 0.197182 0.740446 +vt 0.214271 0.740032 +vt 0.802253 0.684798 +vt 0.813852 0.765893 +vt 0.839489 0.740446 +vt 0.830318 0.766323 +vt 0.867622 0.100828 +vt 0.881628 0.100806 +vt 0.878380 0.207321 +vt 0.730910 0.766712 +vt 0.750584 0.740875 +vt 0.757044 0.714002 +vt 0.431052 0.614732 +vt 0.353851 0.650097 +vt 0.351625 0.611222 +vt 0.677689 0.680918 +vt 0.703041 0.709594 +vt 0.673819 0.709107 +vt 0.779610 0.100787 +vt 0.188438 0.789289 +vt 0.160844 0.764732 +vt 0.781391 0.714051 +vt 0.774768 0.683969 +vt 0.789163 0.739961 +vt 0.806824 0.764732 +vt 0.729802 0.710124 +vt 0.734648 0.681876 +vt 0.513457 0.805883 +vt 0.629284 0.788017 +vt 0.632204 0.805883 +vt 0.873298 0.684798 +vt 0.866758 0.712967 +vt 0.858248 0.739961 +vt 0.293125 0.682897 +vt 0.270903 0.711581 +vt 0.266528 0.683363 +vt 0.706930 0.196211 +vt 0.676958 0.196254 +vt 0.223958 0.764083 +vt 0.195714 0.766196 +vt 0.177213 0.739209 +vt 0.744039 0.791246 +vt 0.754482 0.805883 +vt 0.711706 0.788073 +vt 0.767390 0.789192 +vt 0.431920 0.642834 +vt 0.390619 0.680027 +vt 0.198572 0.805883 +vt 0.225585 0.790490 +vt 0.184742 0.767650 +vt 0.610914 0.100984 +vt 0.513463 0.106459 +vt 0.500255 0.100996 +vt 0.657352 0.805883 +vt 0.634911 0.788795 +vt 0.635627 0.674655 +vt 0.644894 0.667082 +vt 0.702912 0.713772 +vt 0.796994 0.621652 +vt 0.576182 0.159136 +vt 0.513462 0.153254 +vt 0.513462 0.112408 +vt 0.796449 0.712967 +vt 0.759026 0.685076 +vt 0.839127 0.652744 +vt 0.815374 0.684322 +vt 0.301746 0.737899 +vt 0.307405 0.763647 +vt 0.282681 0.764225 +vt 0.371074 0.769197 +vt 0.422484 0.784239 +vt 0.400526 0.752024 +vt 0.797711 0.655523 +vt 0.774589 0.653999 +vt 0.734925 0.737899 +vt 0.753990 0.764225 +vt 0.729266 0.763647 +vt 0.605192 0.728029 +vt 0.568852 0.727777 +vt 0.583520 0.708504 +vt 0.308857 0.680918 +vt 0.283504 0.709594 +vt 0.279105 0.681375 +vt 0.847123 0.216075 +vt 0.877853 0.253186 +vt 0.863276 0.233931 +vt 0.868154 0.685169 +vt 0.884154 0.684771 +vt 0.889767 0.652744 +vt 0.789367 0.302043 +vt 0.679054 0.402533 +vt 0.686482 0.478854 +vt 0.789818 0.813048 +vt 0.756055 0.859991 +vt 0.734820 0.222763 +vt 0.687454 0.203058 +vt 0.783599 0.608914 +vt 0.863685 0.209610 +vt 0.607217 0.691171 +vt 0.635244 0.760057 +vt 0.403026 0.708504 +vt 0.417694 0.727777 +vt 0.381354 0.728029 +vt 0.419718 0.100430 +vt 0.338232 0.648495 +vt 0.798107 0.789289 +vt 0.809333 0.739209 +vt 0.843085 0.739823 +vt 0.691115 0.461040 +vt 0.687291 0.562480 +vt 0.607001 0.562003 +vt 0.789869 0.876759 +vt 0.720047 0.910792 +vt 0.745163 0.900813 +vt 0.821855 0.632729 +vt 0.617140 0.684158 +vt 0.629601 0.738610 +vt 0.628410 0.676669 +vt 0.706335 0.194478 +vt 0.761700 0.158434 +vt 0.696934 0.108944 +vt 0.460285 0.119498 +vt 0.797347 0.685040 +vt 0.665794 0.787158 +vt 0.238810 0.651803 +vt 0.259817 0.612449 +vt 0.262905 0.651325 +vt 0.820633 0.288017 +vt 0.810326 0.256826 +vt 0.290389 0.788640 +vt 0.269281 0.789192 +vt 0.830378 0.802662 +vt 0.827332 0.830257 +vt 0.809870 0.267212 +vt 0.806824 0.239617 +vt 0.778649 0.237699 +vt 0.206936 0.100787 +vt 0.223777 0.108185 +vt 0.206934 0.110197 +vt 0.376697 0.788795 +vt 0.354257 0.805883 +vt 0.429442 0.805883 +vt 0.849282 0.626596 +vt 0.242717 0.683846 +vt 0.221297 0.684322 +vt 0.621755 0.531756 +vt 0.650149 0.313192 +vt 0.662094 0.331094 +vt 0.816738 0.712168 +vt 0.840785 0.684264 +vt 0.331356 0.735962 +vt 0.404717 0.747811 +vt 0.206920 0.532517 +vt 0.202947 0.608914 +vt 0.174412 0.612534 +vt 0.764213 0.188859 +vt 0.755462 0.101028 +vt 0.856155 0.100862 +vt 0.324965 0.788073 +vt 0.170138 0.207321 +vt 0.195548 0.100806 +vt 0.867631 0.853799 +vt 0.883784 0.835944 +vt 0.898361 0.816689 +vt 0.852554 0.439247 +vt 0.861651 0.322992 +vt 0.870799 0.344100 +vt 0.881558 0.378676 +vt 0.773766 0.651325 +vt 0.770143 0.683363 +vt 0.288390 0.736448 +vt 0.262231 0.737026 +vt 0.786284 0.789723 +vt 0.811086 0.790490 +vt 0.206493 0.306008 +vt 0.211202 0.564730 +vt 0.191701 0.565241 +vt 0.640534 0.769197 +vt 0.250387 0.789723 +vt 0.240773 0.765379 +vt 0.844970 0.565241 +vt 0.825469 0.564730 +vt 0.755348 0.805883 +vt 0.286960 0.611990 +vt 0.305812 0.760930 +vt 0.245245 0.763475 +vt 0.812406 0.790578 +vt 0.817236 0.757443 +vt 0.830582 0.765776 +vt 0.251903 0.100753 +vt 0.839705 0.766323 +vt 0.860963 0.713437 +vt 0.807404 0.739823 +vt 0.201872 0.684771 +vt 0.226472 0.712586 +vt 0.207380 0.713043 +vt 0.851514 0.740446 +vt 0.247516 0.712090 +vt 0.222404 0.650334 +vt 0.420450 0.765417 +vt 0.566096 0.765417 +vt 0.938489 0.592891 +vt 0.943638 0.568615 +vt 0.947747 0.540513 +vt 0.374547 0.711310 +vt 0.432809 0.667110 +vt 0.886770 0.134933 +vt 0.858685 0.143036 +vt 0.923422 0.537771 +vt 0.918316 0.576650 +vt 0.911267 0.608679 +vt 0.571471 0.686986 +vt 0.800125 0.781857 +vt 0.774846 0.807006 +vt 0.382007 0.738610 +vt 0.906214 0.100769 +vt 0.891158 0.100826 +vt 0.764142 0.650334 +vt 0.739038 0.649814 +vt 0.208608 0.221569 +vt 0.235501 0.100781 +vt 0.680874 0.765610 +vt 0.698243 0.790279 +vt 0.682331 0.890498 +vt 0.718751 0.878498 +vt 0.801085 0.612935 +vt 0.842456 0.613917 +vt 0.797862 0.651803 +vt 0.514263 0.238427 +vt 0.672441 0.739739 +vt 0.699539 0.739837 +vt 0.730225 0.713091 +vt 0.707584 0.805883 +vt 0.795898 0.765379 +vt 0.911744 0.221569 +vt 0.919545 0.100781 +vt 0.271466 0.805883 +vt 0.310538 0.786260 +vt 0.318231 0.805883 +vt 0.564695 0.783332 +vt 0.668315 0.805883 +vt 0.562882 0.805883 +vt 0.715080 0.805883 +vt 0.676008 0.786260 +vt 0.866093 0.306845 +vt 0.831389 0.613054 +vt 0.790569 0.566259 +vt 0.767265 0.566621 +vt 0.723531 0.858029 +vt 0.666946 0.866816 +vt 0.714313 0.847112 +vt 0.513452 0.783195 +vt 0.247508 0.649814 +vt 0.226999 0.682399 +vt 0.749712 0.611990 +vt 0.746828 0.650868 +vt 0.685047 0.611222 +vt 0.776854 0.612449 +vt 0.658631 0.646586 +vt 0.687454 0.805883 +vt 0.861059 0.194148 +vt 0.797658 0.194758 +vt 0.812134 0.612534 +vt 0.592411 0.696379 +vt 0.451348 0.704765 +vt 0.421851 0.783332 +vt 0.423664 0.805883 +vt 0.864856 0.382798 +vt 0.890375 0.424588 +vt 0.443083 0.805883 +vt 0.905188 0.664116 +vt 0.864856 0.761295 +vt 0.878965 0.496794 +vt 0.675144 0.196850 +vt 0.622389 0.283152 +vt 0.570811 0.251296 +vt 0.788830 0.203135 +vt 0.765496 0.201552 +vt 0.765612 0.100640 +vt 0.711534 0.649322 +vt 0.707441 0.681375 +vt 0.739308 0.171001 +vt 0.680413 0.682102 +vt 0.646052 0.680027 +vt 0.713768 0.682469 +vt 0.603863 0.667110 +vt 0.605619 0.614732 +vt 0.305169 0.648875 +vt 0.297163 0.100635 +vt 0.275751 0.100393 +vt 0.189848 0.713437 +vt 0.184047 0.685169 +vt 0.119787 0.712967 +vt 0.113248 0.684798 +vt 0.128298 0.739961 +vt 0.846823 0.713437 +vt 0.822400 0.740032 +vt 0.197545 0.652744 +vt 0.194215 0.613917 +vt 0.271060 0.100640 +vt 0.841143 0.746882 +vt 0.829318 0.733975 +vt 0.232219 0.710672 +vt 0.362673 0.100975 +vt 0.787974 0.805883 +vt 0.790831 0.766196 +vt 0.874826 0.256811 +vt 0.844321 0.223118 +vt 0.881432 0.438745 +vt 0.896260 0.565241 +vt 0.192350 0.223118 +vt 0.161845 0.256811 +vt 0.879468 0.210994 +vt 0.896336 0.223118 +vt 0.861856 0.256811 +vt 0.256744 0.710124 +vt 0.251898 0.681876 +vt 0.282189 0.805883 +vt 0.329087 0.805883 +vt 0.137301 0.613536 +vt 0.127022 0.158434 +vt 0.145352 0.101028 +vt 0.119986 0.188859 +vt 0.186689 0.205160 +vt 0.155157 0.613054 +vt 0.648936 0.100975 +vt 0.799557 0.277346 +vt 0.768529 0.247663 +vt 0.820065 0.792529 +vt 0.289844 0.650868 +vt 0.746282 0.788640 +vt 0.916686 0.188859 +vt 0.891320 0.101028 +vt 0.909649 0.158434 +vt 0.557072 0.705997 +vt 0.825702 0.764732 +vt 0.759547 0.682399 +vt 0.669629 0.168439 +vt 0.849245 0.613536 +vt 0.344636 0.708689 +vt 0.312727 0.709107 +vt 0.355966 0.682015 +vt 0.513454 0.710824 +vt 0.419198 0.696379 +vt 0.682817 0.611798 +vt 0.839705 0.260065 +vt 0.854066 0.276531 +vt 0.815831 0.238453 +vt 0.231198 0.805883 +vt 0.317425 0.611575 +vt 0.850291 0.725774 +vt 0.861050 0.691198 +vt 0.297026 0.711085 +vt 0.838798 0.684264 +vt 0.724315 0.737026 +vt 0.724655 0.169061 +vt 0.699539 0.159083 +vt 0.769361 0.193116 +vt 0.666041 0.643812 +vt 0.852419 0.308015 +vt 0.854309 0.438053 +vt 0.831429 0.209610 +vt 0.837421 0.306845 +vt 0.849962 0.308015 +vt 0.863276 0.613054 +vt 0.641910 0.708689 +vt 0.630580 0.682015 +vt 0.318780 0.100641 +vt 0.427413 0.460539 +vt 0.776073 0.764812 +vt 0.801170 0.100781 +vt 0.581829 0.747811 +vt 0.662124 0.711310 +vt 0.909670 0.689888 +vt 0.901986 0.719138 +vt 0.924244 0.581281 +vt 0.917814 0.641617 +vt 0.741820 0.212168 +vt 0.731819 0.222903 +vt 0.134127 0.308015 +vt 0.132237 0.438053 +vt 0.155117 0.209610 +vt 0.149125 0.306845 +vt 0.710795 0.100393 +vt 0.698243 0.191377 +vt 0.661823 0.179376 +vt 0.851929 0.767650 +vt 0.833556 0.790902 +vt 0.415075 0.686986 +vt 0.852625 0.685169 +vt 0.625438 0.100528 +vt 0.681377 0.648875 +vt 0.691321 0.583872 +vt 0.851025 0.438053 +vt 0.594993 0.262892 +vt 0.442671 0.249918 +vt 0.752327 0.846971 +vt 0.710396 0.710626 +vt 0.790998 0.100806 +vt 0.206354 0.766323 +vt 0.753255 0.100743 +vt 0.203115 0.790902 +vt 0.893688 0.613917 +vt 0.841813 0.628461 +vt 0.474436 0.100380 +vt 0.686948 0.100589 +vt 0.235586 0.612935 +vt 0.260599 0.764812 +vt 0.233291 0.100743 +vt 0.370878 0.787158 +vt 0.416616 0.262892 +vt 0.743111 0.100684 +vt 0.905188 0.479977 +vt 0.890375 0.719505 +vt 0.913330 0.306008 +vt 0.849826 0.335900 +s 0 +f 212/1/1 2/2/1 7/3/1 +f 112/4/2 109/5/2 110/6/2 +f 21/7/3 17/8/3 22/9/3 +f 108/10/4 105/11/4 106/12/4 +f 381/13/5 394/14/5 380/15/5 +f 303/16/6 210/17/6 213/18/6 +f 49/19/7 446/20/7 456/21/7 +f 177/22/8 171/23/8 169/24/8 +f 250/25/9 459/26/9 253/27/9 +f 5/28/10 6/29/10 8/30/10 +f 367/31/11 384/32/11 395/33/11 +f 223/34/12 231/35/12 222/36/12 +f 269/37/13 485/38/13 261/39/13 +f 252/40/14 242/41/14 253/27/14 +f 289/42/15 233/43/15 232/44/15 +f 426/45/16 155/46/16 158/47/16 +f 479/48/17 300/49/17 481/50/17 +f 387/51/18 386/52/18 388/53/18 +f 324/54/19 330/55/19 366/56/19 +f 415/57/20 343/58/20 342/59/20 +f 114/60/21 113/61/21 112/4/21 +f 114/60/22 150/62/22 151/63/22 +f 447/64/23 72/65/23 71/66/23 +f 322/67/24 323/68/24 378/69/24 +f 256/70/25 244/71/25 243/72/25 +f 201/73/26 193/74/26 424/75/26 +f 270/76/27 266/77/27 265/78/27 +f 185/79/28 184/80/28 169/81/28 +f 457/82/29 443/83/29 351/39/29 +f 260/84/30 504/85/30 400/14/30 +f 224/86/31 225/87/31 227/88/31 +f 92/89/32 94/90/32 517/91/32 +f 152/92/33 148/93/33 147/94/33 +f 360/76/34 520/95/34 526/96/34 +f 272/97/35 271/98/35 4/99/35 +f 162/100/36 157/101/36 167/102/36 +f 298/51/37 297/52/37 397/103/37 +f 177/104/38 172/105/38 171/106/38 +f 493/107/39 499/108/39 362/109/39 +f 186/110/40 187/111/40 45/112/40 +f 206/113/41 139/114/41 140/115/41 +f 285/116/42 229/117/42 228/118/42 +f 5/28/43 530/119/43 4/99/43 +f 330/55/44 310/120/44 307/121/44 +f 295/32/45 277/31/45 401/33/45 +f 48/122/46 55/123/46 45/112/46 +f 25/123/47 18/122/47 15/112/47 +f 331/124/48 307/125/48 332/41/48 +f 253/27/49 242/41/49 243/72/49 +f 230/126/50 287/127/50 231/35/50 +f 469/128/51 41/129/51 416/130/51 +f 397/131/52 255/132/52 241/133/52 +f 132/134/53 131/135/53 130/136/53 +f 353/137/54 351/39/54 352/138/54 +f 312/139/55 311/140/55 308/141/55 +f 184/80/56 186/110/56 188/142/56 +f 413/143/57 176/144/57 174/145/57 +f 207/146/58 205/147/58 139/114/58 +f 406/148/59 311/140/59 312/139/59 +f 155/149/60 154/150/60 162/100/60 +f 524/151/61 259/152/61 518/153/61 +f 420/154/62 250/25/62 251/155/62 +f 476/156/63 480/157/63 26/158/63 +f 19/19/64 13/159/64 508/21/64 +f 40/160/65 38/161/65 39/162/65 +f 345/163/66 390/164/66 391/103/66 +f 119/165/67 105/11/67 107/166/67 +f 192/167/68 166/168/68 165/169/68 +f 339/170/69 382/171/69 383/172/69 +f 14/173/70 25/123/70 24/174/70 +f 183/175/71 180/176/71 181/177/71 +f 239/178/72 238/179/72 215/180/72 +f 374/181/73 319/182/73 375/183/73 +f 277/184/74 279/185/74 278/186/74 +f 103/187/75 105/188/75 119/189/75 +f 267/190/76 487/191/76 488/192/76 +f 79/162/77 78/161/77 85/160/77 +f 168/193/78 169/24/78 184/194/78 +f 201/73/79 421/195/79 458/196/79 +f 280/197/80 8/30/80 6/29/80 +f 272/109/81 514/107/81 273/198/81 +f 331/124/82 332/41/82 333/72/82 +f 434/199/83 87/129/83 88/200/83 +f 242/41/84 252/40/84 217/125/84 +f 52/9/85 47/8/85 51/7/85 +f 305/201/86 328/202/86 329/203/86 +f 489/204/87 303/16/87 302/205/87 +f 220/206/88 218/207/88 240/208/88 +f 41/129/89 477/199/89 42/200/89 +f 97/209/90 100/210/90 198/211/90 +f 333/212/91 335/213/91 334/214/91 +f 387/51/92 385/215/92 367/31/92 +f 529/95/93 270/76/93 532/96/93 +f 472/216/94 248/217/94 475/218/94 +f 77/219/95 70/220/95 190/221/95 +f 518/153/96 39/162/96 290/222/96 +f 46/223/97 47/8/97 52/9/97 +f 183/175/98 181/177/98 149/224/98 +f 44/173/99 55/123/99 46/223/99 +f 136/225/100 143/226/100 137/227/100 +f 462/228/101 153/229/101 155/46/101 +f 218/207/102 222/36/102 233/43/102 +f 165/169/103 160/230/103 159/231/103 +f 310/232/104 342/59/104 307/233/104 +f 220/234/105 217/235/105 252/236/105 +f 522/237/106 11/238/106 10/239/106 +f 341/240/107 404/241/107 419/242/107 +f 135/189/108 80/187/108 23/243/108 +f 136/225/109 128/244/109 84/245/109 +f 355/78/110 360/76/110 526/96/110 +f 213/18/111 1/246/111 212/1/111 +f 263/137/112 262/138/112 261/39/112 +f 449/247/113 448/248/113 77/219/113 +f 234/249/114 289/42/114 276/250/114 +f 315/251/115 329/203/115 327/252/115 +f 12/253/116 370/254/116 369/255/116 +f 29/256/117 204/257/117 513/258/117 +f 166/168/118 147/94/118 161/259/118 +f 10/239/119 362/260/119 499/261/119 +f 367/262/120 368/263/120 369/264/120 +f 396/164/121 255/163/121 397/103/121 +f 349/152/122 510/151/122 500/153/122 +f 49/19/123 53/243/123 98/265/123 +f 159/266/124 160/267/124 161/268/124 +f 121/269/125 109/5/125 111/270/125 +f 400/14/126 292/13/126 291/15/126 +f 317/271/127 316/272/127 319/182/127 +f 173/273/128 177/104/128 170/274/128 +f 19/19/129 32/65/129 63/265/129 +f 87/129/130 188/142/130 186/110/130 +f 60/275/131 65/276/131 66/277/131 +f 249/278/132 251/155/132 250/25/132 +f 31/66/133 32/65/133 494/64/133 +f 158/279/134 162/100/134 163/280/134 +f 94/90/135 102/281/135 101/282/135 +f 460/283/136 223/34/136 222/36/136 +f 379/222/137 381/13/137 380/15/137 +f 42/200/138 195/110/138 201/142/138 +f 142/284/139 137/227/139 143/226/139 +f 316/272/140 314/285/140 313/286/140 +f 170/287/141 408/288/141 173/289/141 +f 65/276/142 60/275/142 528/290/142 +f 51/7/143 171/291/143 104/292/143 +f 391/103/144 330/293/144 331/124/144 +f 82/294/145 86/295/145 83/296/145 +f 442/38/146 359/37/146 351/39/146 +f 81/292/147 157/297/147 156/291/147 +f 17/8/148 16/223/148 22/9/148 +f 128/244/149 131/135/149 129/298/149 +f 11/238/150 371/299/150 12/253/150 +f 326/300/151 238/179/151 236/301/151 +f 208/302/152 207/303/152 206/304/152 +f 134/305/153 208/306/153 151/63/153 +f 513/258/154 62/307/154 36/308/154 +f 124/309/155 122/310/155 113/311/155 +f 328/202/156 214/312/156 238/179/156 +f 266/77/157 487/191/157 267/190/157 +f 412/313/158 168/193/158 407/314/158 +f 338/315/159 429/216/159 432/218/159 +f 202/316/160 62/307/160 515/317/160 +f 8/30/161 281/318/161 282/319/161 +f 60/275/162 58/320/162 531/321/162 +f 336/322/163 344/323/163 340/25/163 +f 343/58/164 340/324/164 344/325/164 +f 126/326/165 127/327/165 120/328/165 +f 453/85/166 452/329/166 350/84/166 +f 37/219/167 496/248/167 497/247/167 +f 247/330/168 245/331/168 257/332/168 +f 347/332/169 334/71/169 335/331/169 +f 149/224/170 176/144/170 423/333/170 +f 178/334/171 173/273/171 174/145/171 +f 92/335/172 525/336/172 96/307/172 +f 418/337/173 309/338/173 403/339/173 +f 235/340/174 417/341/174 464/342/174 +f 466/343/175 417/341/175 219/344/175 +f 293/171/176 249/278/176 294/172/176 +f 274/345/177 265/78/177 266/77/177 +f 134/305/178 150/62/178 147/94/178 +f 154/81/179 193/80/179 194/79/179 +f 278/346/180 6/29/180 272/97/180 +f 393/347/181 392/348/181 445/192/181 +f 491/258/182 96/307/182 498/317/182 +f 188/349/183 409/350/183 405/351/183 +f 425/128/184 87/129/184 348/352/184 +f 193/80/185 201/142/185 195/110/185 +f 372/353/186 377/354/186 371/299/186 +f 436/48/187 389/49/187 388/53/187 +f 124/355/188 121/269/188 122/356/188 +f 100/210/189 124/355/189 123/357/189 +f 100/210/190 97/209/190 125/358/190 +f 435/359/191 388/53/191 390/164/191 +f 12/253/192 371/299/192 370/254/192 +f 371/299/193 378/69/193 369/255/193 +f 193/80/194 196/111/194 194/79/194 +f 402/130/195 409/360/195 188/142/195 +f 87/129/196 402/130/196 188/142/196 +f 72/65/197 75/361/197 76/308/197 +f 68/362/198 72/65/198 76/308/198 +f 68/362/199 491/258/199 69/256/199 +f 4/99/200 271/98/200 6/29/200 +f 5/28/201 4/99/201 6/29/201 +f 280/197/202 6/29/202 279/363/202 +f 296/215/203 299/53/203 298/51/203 +f 297/52/204 298/51/204 299/53/204 +f 295/32/205 401/33/205 399/347/205 +f 296/215/206 295/32/206 300/49/206 +f 294/172/207 471/364/207 470/365/207 +f 293/171/208 294/172/208 470/365/208 +f 223/34/209 219/344/209 224/86/209 +f 403/339/210 325/366/210 414/367/210 +f 235/340/211 326/300/211 236/301/211 +f 414/367/212 235/340/212 464/342/212 +f 313/286/213 309/338/213 418/337/213 +f 498/317/214 96/307/214 189/316/214 +f 468/368/215 161/268/215 146/369/215 +f 148/93/216 152/92/216 461/370/216 +f 152/371/217 423/372/217 461/373/217 +f 34/374/218 501/375/218 502/376/218 +f 101/282/219 126/326/219 125/358/219 +f 517/91/220 94/90/220 90/377/220 +f 517/91/221 89/378/221 95/379/221 +f 410/26/222 340/25/222 343/27/222 +f 528/290/223 60/275/223 531/321/223 +f 283/380/224 287/127/224 286/381/224 +f 62/307/225 202/316/225 531/336/225 +f 338/315/226 337/330/226 339/170/226 +f 270/76/227 264/382/227 263/137/227 +f 486/83/228 511/82/228 261/39/228 +f 123/357/229 198/211/229 100/210/229 +f 123/357/230 117/383/230 197/384/230 +f 124/355/231 113/61/231 115/385/231 +f 513/258/232 36/308/232 28/362/232 +f 35/361/233 32/65/233 36/308/233 +f 32/65/234 28/362/234 36/308/234 +f 197/384/235 151/63/235 200/386/235 +f 200/386/236 151/63/236 208/306/236 +f 208/306/237 199/387/237 200/386/237 +f 373/388/238 374/181/238 375/183/238 +f 509/389/239 302/205/239 373/388/239 +f 9/390/240 373/388/240 372/353/240 +f 372/353/241 371/299/241 11/238/241 +f 84/245/242 129/298/242 86/295/242 +f 17/8/243 18/122/243 16/223/243 +f 196/111/244 15/112/244 18/122/244 +f 167/102/245 81/391/245 83/296/245 +f 21/7/246 156/291/246 154/81/246 +f 80/392/247 83/296/247 81/391/247 +f 345/393/248 391/394/248 331/395/248 +f 104/396/249 182/397/249 106/12/249 +f 172/297/250 104/292/250 171/291/250 +f 136/225/251 135/398/251 145/399/251 +f 65/276/252 61/400/252 143/226/252 +f 174/401/253 408/288/253 413/402/253 +f 313/286/254 312/139/254 321/403/254 +f 142/284/255 143/226/255 61/400/255 +f 41/129/256 42/200/256 201/142/256 +f 500/153/257 506/404/257 379/222/257 +f 500/153/258 79/162/258 349/152/258 +f 222/36/259 422/405/259 460/283/259 +f 221/406/260 422/405/260 222/36/260 +f 67/407/261 92/89/261 91/408/261 +f 99/409/262 98/265/262 102/410/262 +f 63/265/263 64/409/263 66/410/263 +f 57/411/264 58/320/264 27/412/264 +f 88/200/265 87/129/265 186/110/265 +f 35/361/266 62/307/266 59/413/266 +f 57/414/267 27/415/267 59/413/267 +f 320/416/268 321/403/268 376/417/268 +f 125/358/269 120/328/269 121/269/269 +f 122/356/270 111/270/270 113/61/270 +f 463/418/271 161/259/271 468/419/271 +f 93/413/272 67/415/272 91/414/272 +f 96/307/273 76/308/273 75/361/273 +f 299/53/274 397/103/274 297/52/274 +f 367/420/275 378/69/275 366/56/275 +f 30/421/276 204/422/276 29/423/276 +f 30/220/277 37/219/277 203/221/277 +f 10/239/278 11/238/278 12/253/278 +f 361/424/279 10/239/279 12/253/279 +f 12/253/280 368/425/280 362/260/280 +f 317/271/281 315/251/281 314/285/281 +f 309/338/282 327/252/282 325/366/282 +f 234/249/283 240/208/283 218/207/283 +f 451/376/284 450/375/284 74/374/284 +f 292/13/285 269/37/285 262/138/285 +f 519/426/286 292/13/286 262/138/286 +f 519/426/287 263/137/287 264/382/287 +f 1/246/288 213/18/288 210/17/288 +f 348/352/289 419/242/289 425/128/289 +f 422/427/290 252/236/290 465/428/290 +f 406/429/291 342/59/291 310/232/291 +f 130/136/292 138/430/292 132/134/292 +f 128/244/293 137/227/293 130/136/293 +f 44/173/294 46/223/294 52/9/294 +f 175/431/295 181/177/295 180/176/295 +f 185/79/296 48/122/296 187/111/296 +f 46/223/297 48/122/297 47/8/297 +f 292/13/298 290/222/298 291/15/298 +f 519/426/299 518/153/299 290/222/299 +f 491/258/300 191/257/300 69/256/300 +f 69/432/301 191/433/301 70/434/301 +f 247/330/302 248/217/302 249/278/302 +f 333/72/303 332/41/303 343/27/303 +f 473/435/304 477/199/304 41/129/304 +f 217/436/305 220/206/305 240/208/305 +f 87/129/306 434/199/306 430/435/306 +f 346/70/307 334/71/307 347/332/307 +f 345/163/308 333/72/308 346/70/308 +f 288/437/309 282/319/309 281/318/309 +f 280/197/310 281/318/310 8/30/310 +f 281/318/311 280/197/311 279/363/311 +f 201/142/312 458/360/312 416/130/312 +f 41/129/313 201/142/313 416/130/313 +f 510/151/314 73/438/314 190/221/314 +f 191/257/315 510/151/315 190/221/315 +f 289/42/316 277/439/316 276/250/316 +f 374/181/317 306/440/317 318/441/317 +f 301/442/318 374/181/318 302/205/318 +f 180/176/319 183/175/319 112/4/319 +f 22/9/320 16/223/320 14/173/320 +f 348/352/321 431/443/321 427/365/321 +f 383/172/322 428/444/322 338/315/322 +f 131/135/323 165/169/323 129/298/323 +f 391/103/324 388/53/324 386/52/324 +f 33/438/325 524/151/325 203/221/325 +f 204/257/326 203/221/326 524/151/326 +f 484/445/327 13/159/327 14/173/327 +f 24/174/328 484/445/328 14/173/328 +f 42/200/329 26/158/329 15/112/329 +f 42/200/330 196/111/330 195/110/330 +f 467/242/331 258/352/331 469/128/331 +f 156/446/332 162/447/332 154/448/332 +f 411/449/333 313/286/333 418/337/333 +f 411/449/334 406/148/334 312/139/334 +f 139/114/335 205/147/335 132/134/335 +f 139/114/336 138/430/336 141/450/336 +f 175/451/337 174/401/337 176/452/337 +f 187/111/338 184/80/338 185/79/338 +f 381/13/339 352/138/339 359/37/339 +f 506/404/340 352/138/340 381/13/340 +f 353/137/341 352/138/341 506/404/341 +f 134/305/342 132/134/342 205/147/342 +f 147/94/343 133/453/343 134/305/343 +f 397/103/344 240/293/344 276/454/344 +f 229/117/345 226/455/345 227/88/345 +f 244/456/346 245/457/346 243/458/346 +f 26/158/347 480/157/347 482/459/347 +f 54/174/348 441/445/348 439/459/348 +f 277/439/349 268/460/349 275/461/349 +f 272/97/350 273/462/350 274/463/350 +f 277/439/351 278/346/351 268/460/351 +f 278/346/352 272/97/352 274/463/352 +f 268/464/353 278/465/353 274/345/353 +f 308/141/354 310/120/354 330/55/354 +f 285/116/355 216/466/355 211/467/355 +f 213/18/356 212/1/356 211/467/356 +f 141/450/357 533/468/357 209/469/357 +f 56/158/358 437/157/358 433/156/358 +f 56/158/359 88/200/359 45/112/359 +f 88/200/360 186/110/360 45/112/360 +f 108/10/361 106/12/361 182/397/361 +f 178/334/362 182/397/362 177/104/362 +f 108/10/363 178/334/363 179/470/363 +f 86/295/364 167/102/364 83/296/364 +f 167/102/365 163/280/365 162/100/365 +f 163/280/366 167/102/366 86/295/366 +f 150/62/367 152/92/367 147/94/367 +f 525/471/368 92/89/368 517/91/368 +f 237/472/369 239/178/369 225/87/369 +f 219/344/370 235/340/370 237/472/370 +f 357/190/371 444/191/371 356/77/371 +f 353/137/372 354/382/372 360/76/372 +f 242/41/373 241/124/373 243/72/373 +f 255/163/374 243/72/374 241/124/374 +f 118/473/375 197/384/375 117/383/375 +f 116/474/376 114/475/376 151/476/376 +f 118/477/377 116/474/377 151/476/377 +f 332/41/378 342/40/378 343/27/378 +f 324/54/379 378/69/379 323/68/379 +f 364/345/380 355/78/380 363/198/380 +f 384/32/381 385/215/381 389/49/381 +f 358/464/382 395/33/382 357/190/382 +f 385/215/383 388/53/383 389/49/383 +f 478/359/384 299/53/384 479/48/384 +f 159/266/385 426/45/385 158/47/385 +f 465/428/386 253/478/386 459/479/386 +f 226/455/387 224/86/387 227/88/387 +f 358/480/388 367/420/388 365/481/388 +f 368/425/389 367/420/389 358/480/389 +f 368/465/390 358/464/390 364/345/390 +f 363/482/391 362/260/391 364/483/391 +f 362/260/392 368/425/392 364/483/392 +f 5/28/393 7/3/393 3/484/393 +f 254/485/394 250/486/394 253/478/394 +f 170/274/395 169/487/395 168/488/395 +f 43/159/396 441/445/396 44/173/396 +f 54/174/397 44/173/397 441/445/397 +f 304/489/398 213/18/398 214/312/398 +f 106/12/399 103/490/399 104/396/399 +f 110/6/400 107/166/400 108/10/400 +f 521/491/401 3/484/401 2/2/401 +f 3/484/402 7/3/402 2/2/402 +f 7/3/403 283/380/403 284/492/403 +f 284/492/404 212/1/404 7/3/404 +f 212/1/405 1/246/405 2/2/405 +f 112/4/406 111/270/406 109/5/406 +f 22/9/407 80/187/407 21/7/407 +f 80/187/408 81/292/408 21/7/408 +f 108/10/409 107/166/409 105/11/409 +f 381/13/410 359/37/410 394/14/410 +f 440/493/411 43/159/411 456/21/411 +f 43/159/412 49/19/412 456/21/412 +f 49/19/413 72/65/413 446/20/413 +f 250/25/414 420/154/414 459/26/414 +f 395/33/415 365/494/415 367/31/415 +f 367/31/416 385/215/416 384/32/416 +f 223/34/417 226/455/417 231/35/417 +f 226/455/418 230/126/418 231/35/418 +f 231/35/419 232/44/419 222/36/419 +f 269/37/420 400/14/420 507/495/420 +f 400/14/421 505/496/421 507/495/421 +f 261/39/422 262/138/422 269/37/422 +f 485/38/423 486/83/423 261/39/423 +f 269/37/424 507/495/424 485/38/424 +f 232/44/425 231/35/425 288/437/425 +f 288/437/426 289/42/426 232/44/426 +f 426/45/427 462/228/427 155/46/427 +f 479/48/428 299/53/428 300/49/428 +f 324/54/429 308/141/429 330/55/429 +f 415/57/430 410/497/430 343/58/430 +f 114/60/431 116/498/431 115/385/431 +f 115/385/432 113/61/432 114/60/432 +f 113/61/433 111/270/433 112/4/433 +f 114/60/434 183/175/434 150/62/434 +f 69/256/435 70/220/435 77/219/435 +f 77/219/436 448/248/436 71/66/436 +f 448/248/437 447/64/437 71/66/437 +f 447/64/438 446/20/438 72/65/438 +f 72/65/439 68/362/439 71/66/439 +f 71/66/440 69/256/440 77/219/440 +f 378/69/441 377/354/441 322/67/441 +f 377/354/442 321/403/442 322/67/442 +f 256/70/443 257/332/443 244/71/443 +f 154/448/444 153/229/444 193/74/444 +f 153/229/445 424/75/445 193/74/445 +f 424/75/446 421/195/446 201/73/446 +f 265/78/447 514/107/447 532/96/447 +f 532/96/448 270/76/448 265/78/448 +f 51/7/449 47/8/449 169/81/449 +f 47/8/450 185/79/450 169/81/450 +f 291/15/451 38/161/451 260/84/451 +f 260/84/452 40/160/452 503/329/452 +f 40/160/453 502/376/453 503/329/453 +f 400/14/454 291/15/454 260/84/454 +f 504/85/455 505/496/455 400/14/455 +f 260/84/456 503/329/456 504/85/456 +f 360/76/457 354/382/457 520/95/457 +f 4/99/458 530/119/458 516/499/458 +f 516/499/459 272/97/459 4/99/459 +f 162/100/460 156/500/460 157/101/460 +f 397/103/461 276/454/461 298/51/461 +f 276/454/462 277/31/462 298/51/462 +f 277/31/463 296/215/463 298/51/463 +f 177/104/464 182/397/464 172/105/464 +f 362/109/465 363/198/465 493/107/465 +f 363/198/466 355/78/466 493/107/466 +f 206/113/467 207/146/467 139/114/467 +f 285/116/468 286/381/468 229/117/468 +f 5/28/469 512/501/469 530/119/469 +f 296/215/470 277/31/470 295/32/470 +f 277/31/471 275/494/471 401/33/471 +f 48/122/472 46/223/472 55/123/472 +f 25/123/473 16/223/473 18/122/473 +f 330/293/474 307/125/474 331/124/474 +f 307/125/475 342/40/475 332/41/475 +f 243/72/476 245/331/476 253/27/476 +f 245/331/477 246/322/477 254/323/477 +f 253/27/478 245/331/478 254/323/478 +f 230/126/479 229/117/479 286/381/479 +f 286/381/480 287/127/480 230/126/480 +f 287/127/481 288/437/481 231/35/481 +f 469/128/482 258/352/482 41/129/482 +f 132/134/483 133/453/483 131/135/483 +f 324/54/484 323/68/484 308/141/484 +f 323/68/485 322/67/485 312/139/485 +f 308/141/486 323/68/486 312/139/486 +f 413/143/487 423/333/487 176/144/487 +f 207/146/488 208/306/488 205/147/488 +f 406/148/489 310/120/489 311/140/489 +f 155/149/490 153/502/490 154/150/490 +f 293/171/491 467/242/491 251/155/491 +f 467/242/492 420/154/492 251/155/492 +f 26/158/493 42/200/493 476/156/493 +f 42/200/494 477/199/494 476/156/494 +f 13/159/495 483/493/495 508/21/495 +f 508/21/496 492/20/496 19/19/496 +f 492/20/497 32/65/497 19/19/497 +f 259/152/498 524/151/498 39/162/498 +f 524/151/499 40/160/499 39/162/499 +f 40/160/500 260/84/500 38/161/500 +f 38/161/501 291/15/501 39/162/501 +f 291/15/502 290/222/502 39/162/502 +f 345/163/503 346/70/503 390/164/503 +f 107/166/504 109/5/504 120/328/504 +f 120/328/505 119/165/505 107/166/505 +f 339/170/506 341/240/506 382/171/506 +f 14/173/507 16/223/507 25/123/507 +f 216/466/508 228/118/508 225/87/508 +f 239/178/509 237/472/509 238/179/509 +f 216/466/510 225/87/510 239/178/510 +f 215/180/511 211/467/511 239/178/511 +f 211/467/512 216/466/512 239/178/512 +f 374/181/513 318/441/513 319/182/513 +f 127/503/514 53/243/514 119/189/514 +f 53/243/515 50/504/515 52/9/515 +f 119/189/516 53/243/516 103/187/516 +f 52/9/517 103/187/517 53/243/517 +f 488/192/518 481/50/518 398/348/518 +f 481/50/519 300/49/519 398/348/519 +f 398/348/520 399/347/520 488/192/520 +f 399/347/521 267/190/521 488/192/521 +f 85/160/522 510/151/522 79/162/522 +f 510/151/523 349/152/523 79/162/523 +f 79/162/524 379/222/524 380/15/524 +f 78/161/525 350/84/525 85/160/525 +f 79/162/526 380/15/526 78/161/526 +f 184/194/527 188/349/527 407/314/527 +f 188/349/528 405/351/528 407/314/528 +f 407/314/529 168/193/529 184/194/529 +f 516/108/530 514/107/530 272/109/530 +f 514/107/531 265/78/531 273/198/531 +f 240/293/532 241/124/532 217/125/532 +f 241/124/533 242/41/533 217/125/533 +f 51/7/534 104/292/534 103/187/534 +f 103/187/535 52/9/535 51/7/535 +f 329/203/536 315/251/536 306/440/536 +f 315/251/537 318/441/537 306/440/537 +f 306/440/538 301/442/538 329/203/538 +f 301/442/539 305/201/539 329/203/539 +f 328/202/540 327/252/540 329/203/540 +f 302/205/541 509/389/541 489/204/541 +f 489/204/542 210/17/542 303/16/542 +f 220/206/543 221/406/543 218/207/543 +f 198/211/544 199/387/544 206/113/544 +f 206/113/545 209/469/545 198/211/545 +f 209/469/546 527/505/546 97/209/546 +f 198/211/547 209/469/547 97/209/547 +f 527/505/548 495/506/548 97/209/548 +f 367/31/549 366/454/549 387/51/549 +f 366/454/550 391/103/550 387/51/550 +f 391/103/551 386/52/551 387/51/551 +f 529/95/552 264/382/552 270/76/552 +f 471/364/553 248/217/553 472/216/553 +f 248/217/554 247/330/554 475/218/554 +f 70/220/555 191/257/555 190/221/555 +f 190/221/556 73/438/556 77/219/556 +f 73/438/557 74/374/557 77/219/557 +f 518/153/558 259/152/558 39/162/558 +f 181/177/559 176/144/559 149/224/559 +f 149/224/560 152/92/560 150/62/560 +f 150/62/561 183/175/561 149/224/561 +f 44/173/562 54/174/562 55/123/562 +f 136/225/563 144/507/563 143/226/563 +f 462/228/564 424/75/564 153/229/564 +f 233/43/565 234/249/565 218/207/565 +f 218/207/566 221/406/566 222/36/566 +f 222/36/567 232/44/567 233/43/567 +f 159/231/568 158/279/568 163/280/568 +f 163/280/569 164/508/569 159/231/569 +f 164/508/570 165/169/570 159/231/570 +f 522/237/571 490/509/571 11/238/571 +f 419/242/572 382/171/572 341/240/572 +f 341/240/573 340/25/573 404/241/573 +f 20/504/574 23/243/574 22/9/574 +f 23/243/575 145/503/575 135/189/575 +f 135/189/576 82/188/576 80/187/576 +f 80/187/577 22/9/577 23/243/577 +f 84/245/578 82/294/578 135/398/578 +f 135/398/579 136/225/579 84/245/579 +f 526/96/580 493/107/580 355/78/580 +f 355/78/581 356/77/581 360/76/581 +f 77/219/582 74/374/582 449/247/582 +f 74/374/583 450/375/583 449/247/583 +f 234/249/584 233/43/584 289/42/584 +f 161/259/585 160/230/585 166/168/585 +f 160/230/586 165/169/586 166/168/586 +f 166/168/587 192/167/587 147/94/587 +f 148/93/588 146/510/588 147/94/588 +f 146/510/589 161/259/589 147/94/589 +f 499/261/590 522/237/590 10/239/590 +f 10/239/591 361/424/591 362/260/591 +f 396/164/592 256/70/592 255/163/592 +f 67/415/593 72/65/593 98/265/593 +f 72/65/594 49/19/594 98/265/594 +f 49/19/595 50/504/595 53/243/595 +f 98/265/596 99/409/596 67/415/596 +f 121/269/597 120/328/597 109/5/597 +f 400/14/598 269/37/598 292/13/598 +f 316/272/599 320/416/599 319/182/599 +f 319/182/600 318/441/600 317/271/600 +f 318/441/601 315/251/601 317/271/601 +f 173/273/602 178/334/602 177/104/602 +f 32/65/603 27/415/603 63/265/603 +f 27/415/604 64/409/604 63/265/604 +f 63/265/605 23/243/605 19/19/605 +f 23/243/606 20/504/606 19/19/606 +f 254/323/607 246/322/607 250/25/607 +f 246/322/608 249/278/608 250/25/608 +f 37/219/609 30/220/609 29/256/609 +f 31/66/610 28/362/610 32/65/610 +f 37/219/611 29/256/611 31/66/611 +f 494/64/612 496/248/612 31/66/612 +f 496/248/613 37/219/613 31/66/613 +f 32/65/614 492/20/614 494/64/614 +f 158/279/615 155/149/615 162/100/615 +f 460/283/616 466/343/616 223/34/616 +f 379/222/617 506/404/617 381/13/617 +f 142/284/618 138/430/618 137/227/618 +f 316/272/619 317/271/619 314/285/619 +f 170/287/620 412/313/620 408/288/620 +f 51/7/621 169/81/621 171/291/621 +f 391/103/622 366/454/622 330/293/622 +f 82/294/623 84/245/623 86/295/623 +f 455/511/624 454/496/624 394/14/624 +f 359/37/625 352/138/625 351/39/625 +f 455/511/626 394/14/626 359/37/626 +f 351/39/627 443/83/627 442/38/627 +f 442/38/628 455/511/628 359/37/628 +f 128/244/629 130/136/629 131/135/629 +f 326/300/630 327/252/630 328/202/630 +f 328/202/151 238/179/151 326/300/151 +f 238/179/631 237/472/631 236/301/631 +f 134/305/632 205/147/632 208/306/632 +f 513/258/633 515/317/633 62/307/633 +f 328/202/634 305/201/634 304/489/634 +f 304/489/156 214/312/156 328/202/156 +f 214/312/635 215/180/635 238/179/635 +f 412/313/636 170/287/636 168/193/636 +f 432/218/637 337/330/637 338/315/637 +f 338/315/638 428/444/638 429/216/638 +f 282/319/639 283/380/639 7/3/639 +f 7/3/640 8/30/640 282/319/640 +f 340/25/641 341/240/641 339/170/641 +f 339/170/642 336/322/642 340/25/642 +f 126/326/643 101/282/643 127/327/643 +f 101/282/644 102/281/644 127/327/644 +f 127/327/645 119/165/645 120/328/645 +f 350/84/646 78/161/646 380/15/646 +f 380/15/647 394/14/647 350/84/647 +f 394/14/648 454/496/648 453/85/648 +f 394/14/649 453/85/649 350/84/649 +f 451/376/650 85/160/650 452/329/650 +f 85/160/651 350/84/651 452/329/651 +f 497/247/652 501/375/652 34/374/652 +f 34/374/653 37/219/653 497/247/653 +f 256/70/654 396/164/654 257/332/654 +f 396/164/655 478/359/655 257/332/655 +f 478/359/656 475/218/656 247/330/656 +f 245/331/657 244/71/657 257/332/657 +f 478/359/658 247/330/658 257/332/658 +f 335/331/659 337/330/659 347/332/659 +f 337/330/660 432/218/660 435/359/660 +f 347/332/661 337/330/661 435/359/661 +f 435/359/662 390/164/662 347/332/662 +f 390/164/663 346/70/663 347/332/663 +f 175/431/664 180/176/664 174/145/664 +f 180/176/665 179/470/665 174/145/665 +f 179/470/666 178/334/666 174/145/666 +f 189/316/667 96/307/667 525/336/667 +f 96/307/668 93/413/668 92/335/668 +f 93/413/669 91/414/669 92/335/669 +f 235/340/670 219/344/670 417/341/670 +f 293/171/671 251/155/671 249/278/671 +f 274/345/672 273/198/672 265/78/672 +f 134/305/673 151/63/673 150/62/673 +f 194/79/674 17/8/674 154/81/674 +f 17/8/675 21/7/675 154/81/675 +f 279/363/676 6/29/676 278/346/676 +f 6/29/677 271/98/677 272/97/677 +f 392/348/678 389/49/678 438/50/678 +f 445/192/679 444/191/679 357/190/679 +f 392/348/680 438/50/680 445/192/680 +f 357/190/681 393/347/681 445/192/681 +f 491/258/682 76/308/682 96/307/682 +f 425/128/683 402/130/683 87/129/683 +f 372/353/684 376/417/684 377/354/684 +f 436/48/685 438/50/685 389/49/685 +f 124/355/686 125/358/686 121/269/686 +f 97/209/687 495/506/687 89/378/687 +f 495/506/688 523/512/688 89/378/688 +f 523/512/689 95/379/689 89/378/689 +f 89/378/690 90/377/690 97/209/690 +f 90/377/691 125/358/691 97/209/691 +f 125/358/692 124/355/692 100/210/692 +f 435/359/693 436/48/693 388/53/693 +f 369/255/694 370/254/694 371/299/694 +f 371/299/695 377/354/695 378/69/695 +f 193/80/696 195/110/696 196/111/696 +f 69/256/697 71/66/697 68/362/697 +f 68/362/698 76/308/698 491/258/698 +f 296/215/699 300/49/699 299/53/699 +f 401/33/700 275/494/700 268/464/700 +f 268/464/701 274/345/701 266/77/701 +f 266/77/702 267/190/702 268/464/702 +f 267/190/703 399/347/703 401/33/703 +f 399/347/704 398/348/704 300/49/704 +f 401/33/705 268/464/705 267/190/705 +f 399/347/706 300/49/706 295/32/706 +f 294/172/707 248/217/707 471/364/707 +f 474/443/708 258/352/708 470/365/708 +f 258/352/709 293/171/709 470/365/709 +f 223/34/710 466/343/710 219/344/710 +f 403/339/711 309/338/711 325/366/711 +f 235/340/211 325/366/211 326/300/211 +f 414/367/212 325/366/212 235/340/212 +f 313/286/712 314/285/712 309/338/712 +f 146/369/713 148/513/713 461/373/713 +f 461/373/714 468/368/714 146/369/714 +f 152/371/715 149/514/715 423/372/715 +f 502/376/716 40/160/716 34/374/716 +f 40/160/717 33/438/717 34/374/717 +f 90/377/718 94/90/718 125/358/718 +f 94/90/719 101/282/719 125/358/719 +f 517/91/720 90/377/720 89/378/720 +f 410/26/721 404/241/721 340/25/721 +f 285/116/722 284/492/722 286/381/722 +f 284/492/723 283/380/723 286/381/723 +f 283/380/724 282/319/724 287/127/724 +f 531/336/725 58/335/725 62/307/725 +f 58/335/726 57/414/726 59/413/726 +f 62/307/727 58/335/727 59/413/727 +f 335/331/728 336/322/728 337/330/728 +f 336/322/729 339/170/729 337/330/729 +f 339/170/730 383/172/730 338/315/730 +f 261/39/731 511/82/731 266/77/731 +f 511/82/732 487/191/732 266/77/732 +f 266/77/733 270/76/733 261/39/733 +f 261/39/734 270/76/734 263/137/734 +f 123/357/735 199/387/735 198/211/735 +f 200/386/736 199/387/736 197/384/736 +f 199/387/737 123/357/737 197/384/737 +f 117/383/738 123/357/738 115/385/738 +f 123/357/739 124/355/739 115/385/739 +f 28/362/740 31/66/740 29/256/740 +f 29/256/741 513/258/741 28/362/741 +f 197/384/742 118/473/742 151/63/742 +f 208/306/237 206/113/237 199/387/237 +f 376/417/743 372/353/743 375/183/743 +f 372/353/744 373/388/744 375/183/744 +f 9/390/745 509/389/745 373/388/745 +f 11/238/746 490/509/746 9/390/746 +f 9/390/747 372/353/747 11/238/747 +f 84/245/748 128/244/748 129/298/748 +f 17/8/749 194/79/749 18/122/749 +f 194/79/750 196/111/750 18/122/750 +f 167/102/751 157/101/751 81/391/751 +f 21/7/752 81/292/752 156/291/752 +f 80/392/753 82/294/753 83/296/753 +f 104/396/754 172/105/754 182/397/754 +f 145/399/755 66/277/755 65/276/755 +f 65/276/756 144/507/756 145/399/756 +f 144/507/757 136/225/757 145/399/757 +f 143/226/758 144/507/758 65/276/758 +f 65/276/759 528/290/759 61/400/759 +f 174/401/760 173/289/760 408/288/760 +f 312/139/761 322/67/761 321/403/761 +f 321/403/762 320/416/762 316/272/762 +f 316/272/763 313/286/763 321/403/763 +f 61/400/764 533/468/764 142/284/764 +f 533/468/765 141/450/765 142/284/765 +f 500/153/766 379/222/766 79/162/766 +f 221/406/767 220/206/767 422/405/767 +f 98/265/768 53/243/768 102/410/768 +f 53/243/769 127/503/769 102/410/769 +f 102/410/770 94/515/770 99/409/770 +f 94/515/771 92/335/771 67/415/771 +f 99/409/772 94/515/772 67/415/772 +f 27/415/773 58/335/773 60/515/773 +f 66/410/774 145/503/774 23/243/774 +f 27/415/775 60/515/775 64/409/775 +f 60/515/776 66/410/776 64/409/776 +f 23/243/777 63/265/777 66/410/777 +f 59/413/778 27/415/778 35/361/778 +f 27/415/779 32/65/779 35/361/779 +f 35/361/780 36/308/780 62/307/780 +f 377/354/781 376/417/781 321/403/781 +f 376/417/782 375/183/782 320/416/782 +f 375/183/783 319/182/783 320/416/783 +f 125/358/784 126/326/784 120/328/784 +f 122/356/785 121/269/785 111/270/785 +f 463/418/786 159/231/786 161/259/786 +f 75/361/787 72/65/787 67/415/787 +f 67/415/788 93/413/788 75/361/788 +f 93/413/789 96/307/789 75/361/789 +f 299/53/790 396/164/790 397/103/790 +f 367/420/791 369/255/791 378/69/791 +f 34/374/792 33/438/792 37/219/792 +f 33/438/793 203/221/793 37/219/793 +f 203/221/794 204/257/794 30/220/794 +f 362/260/795 361/424/795 12/253/795 +f 12/253/796 369/255/796 368/425/796 +f 309/338/797 314/285/797 315/251/797 +f 315/251/798 327/252/798 309/338/798 +f 327/252/799 326/300/799 325/366/799 +f 234/249/800 276/250/800 240/208/800 +f 74/374/801 73/438/801 85/160/801 +f 85/160/802 451/376/802 74/374/802 +f 264/382/803 529/95/803 519/426/803 +f 519/426/804 262/138/804 263/137/804 +f 210/17/805 489/204/805 1/246/805 +f 489/204/806 521/491/806 1/246/806 +f 521/491/807 2/2/807 1/246/807 +f 348/352/808 382/171/808 419/242/808 +f 422/427/809 220/234/809 252/236/809 +f 406/429/810 415/57/810 342/59/810 +f 130/136/811 137/227/811 138/430/811 +f 128/244/812 136/225/812 137/227/812 +f 52/9/813 50/504/813 44/173/813 +f 50/504/814 49/19/814 44/173/814 +f 49/19/815 43/159/815 44/173/815 +f 175/431/816 176/144/816 181/177/816 +f 47/8/817 48/122/817 185/79/817 +f 48/122/818 45/112/818 187/111/818 +f 292/13/819 519/426/819 290/222/819 +f 248/217/820 294/172/820 249/278/820 +f 249/278/821 246/322/821 247/330/821 +f 246/322/822 245/331/822 247/330/822 +f 343/27/823 344/323/823 335/331/823 +f 344/323/824 336/322/824 335/331/824 +f 335/331/825 333/72/825 343/27/825 +f 41/129/826 258/352/826 473/435/826 +f 258/352/827 474/443/827 473/435/827 +f 430/435/828 431/443/828 348/352/828 +f 348/352/829 87/129/829 430/435/829 +f 346/70/830 333/72/830 334/71/830 +f 345/163/831 331/124/831 333/72/831 +f 288/437/832 287/127/832 282/319/832 +f 279/363/833 289/42/833 281/318/833 +f 289/42/834 288/437/834 281/318/834 +f 510/151/835 85/160/835 73/438/835 +f 289/42/836 279/363/836 277/439/836 +f 374/181/837 301/442/837 306/440/837 +f 374/181/838 373/388/838 302/205/838 +f 302/205/839 303/16/839 301/442/839 +f 303/16/840 304/489/840 301/442/840 +f 304/489/841 305/201/841 301/442/841 +f 183/175/842 114/60/842 112/4/842 +f 112/4/843 110/6/843 180/176/843 +f 110/6/844 179/470/844 180/176/844 +f 13/159/845 19/19/845 14/173/845 +f 19/19/846 20/504/846 14/173/846 +f 20/504/847 22/9/847 14/173/847 +f 427/365/848 383/172/848 382/171/848 +f 382/171/849 348/352/849 427/365/849 +f 383/172/850 427/365/850 428/444/850 +f 131/135/851 133/453/851 192/167/851 +f 192/167/852 165/169/852 131/135/852 +f 165/169/853 164/508/853 129/298/853 +f 391/103/854 390/164/854 388/53/854 +f 33/438/855 40/160/855 524/151/855 +f 484/445/856 483/493/856 13/159/856 +f 42/200/857 15/112/857 196/111/857 +f 467/242/858 293/171/858 258/352/858 +f 411/449/859 312/139/859 313/286/859 +f 141/450/860 140/115/860 139/114/860 +f 139/114/861 132/134/861 138/430/861 +f 138/430/862 142/284/862 141/450/862 +f 187/111/863 186/110/863 184/80/863 +f 520/95/864 354/382/864 506/404/864 +f 354/382/865 353/137/865 506/404/865 +f 134/305/866 133/453/866 132/134/866 +f 147/94/867 192/167/867 133/453/867 +f 397/103/868 241/124/868 240/293/868 +f 225/87/869 228/118/869 227/88/869 +f 228/118/870 229/117/870 227/88/870 +f 229/117/871 230/126/871 226/455/871 +f 484/445/872 24/174/872 482/459/872 +f 24/174/873 25/123/873 26/158/873 +f 482/459/874 24/174/874 26/158/874 +f 25/123/875 15/112/875 26/158/875 +f 437/157/876 56/158/876 439/459/876 +f 56/158/877 45/112/877 55/123/877 +f 439/459/878 56/158/878 54/174/878 +f 55/123/879 54/174/879 56/158/879 +f 308/141/880 311/140/880 310/120/880 +f 285/116/881 228/118/881 216/466/881 +f 212/1/882 284/492/882 285/116/882 +f 211/467/883 215/180/883 214/312/883 +f 212/1/884 285/116/884 211/467/884 +f 214/312/885 213/18/885 211/467/885 +f 533/468/886 527/505/886 209/469/886 +f 209/469/887 206/113/887 140/115/887 +f 140/115/888 141/450/888 209/469/888 +f 433/156/889 434/199/889 88/200/889 +f 88/200/890 56/158/890 433/156/890 +f 179/470/891 110/6/891 108/10/891 +f 108/10/892 182/397/892 178/334/892 +f 86/295/893 129/298/893 164/508/893 +f 164/508/894 163/280/894 86/295/894 +f 235/340/895 236/301/895 237/472/895 +f 237/472/896 225/87/896 219/344/896 +f 225/87/897 224/86/897 219/344/897 +f 356/77/898 444/191/898 457/82/898 +f 457/82/899 351/39/899 356/77/899 +f 351/39/900 353/137/900 360/76/900 +f 356/77/901 351/39/901 360/76/901 +f 255/163/902 256/70/902 243/72/902 +f 117/383/903 115/385/903 116/498/903 +f 116/498/904 118/473/904 117/383/904 +f 324/54/905 366/56/905 378/69/905 +f 364/345/906 356/77/906 355/78/906 +f 384/32/907 389/49/907 393/347/907 +f 389/49/908 392/348/908 393/347/908 +f 393/347/909 357/190/909 395/33/909 +f 357/190/910 356/77/910 358/464/910 +f 358/464/911 365/494/911 395/33/911 +f 395/33/912 384/32/912 393/347/912 +f 356/77/913 364/345/913 358/464/913 +f 385/215/914 387/51/914 388/53/914 +f 478/359/915 396/164/915 299/53/915 +f 159/266/916 463/516/916 426/45/916 +f 465/428/917 252/236/917 253/478/917 +f 226/455/918 223/34/918 224/86/918 +f 3/484/919 512/501/919 5/28/919 +f 5/28/920 8/30/920 7/3/920 +f 170/274/921 177/104/921 169/487/921 +f 43/159/922 440/493/922 441/445/922 +f 304/489/398 303/16/398 213/18/398 +f 106/12/923 105/11/923 103/490/923 +f 110/6/924 109/5/924 107/166/924 diff --git a/src/bitbots_simulation/bitbots_mujoco_sim/xml/pi_plus.xml b/src/bitbots_simulation/bitbots_mujoco_sim/xml/pi_plus.xml index f2be7755f6..2c3627c9db 100644 --- a/src/bitbots_simulation/bitbots_mujoco_sim/xml/pi_plus.xml +++ b/src/bitbots_simulation/bitbots_mujoco_sim/xml/pi_plus.xml @@ -35,22 +35,7 @@ - + @@ -101,7 +86,7 @@ - +