diff --git a/rmf_site_editor/src/interaction/anchor.rs b/rmf_site_editor/src/interaction/anchor.rs index 90160806..570bb789 100644 --- a/rmf_site_editor/src/interaction/anchor.rs +++ b/rmf_site_editor/src/interaction/anchor.rs @@ -46,25 +46,25 @@ pub fn add_anchor_visual_cues( _ => site_assets.site_anchor_mesh.clone(), }; - let mut entity_commands = commands.entity(e); - let body = entity_commands.add_children(|parent| { - let mut body = parent.spawn(PbrBundle { + let body = commands + .spawn(PbrBundle { mesh: body_mesh, material: site_assets.passive_anchor_material.clone(), ..default() - }); - body.insert(Selectable::new(e)); - if subordinate.is_none() { - body.insert(DragPlaneBundle::new(e, Vec3::Z)); - } - let body = body.id(); - - body - }); + }) + .insert(Selectable::new(e)) + .id(); + if subordinate.is_none() { + commands + .entity(body) + .insert(DragPlaneBundle::new(e, Vec3::Z)); + } + let mut entity_commands = commands.entity(e); entity_commands .insert(AnchorVisualization { body, drag: None }) - .insert(OutlineVisualization::Anchor { body }); + .insert(OutlineVisualization::Anchor { body }) + .add_child(body); // 3D anchors should always be visible with arrow cue meshes if anchor.is_3D() { diff --git a/rmf_site_editor/src/interaction/assets.rs b/rmf_site_editor/src/interaction/assets.rs index c66f3fa2..a6c452dd 100644 --- a/rmf_site_editor/src/interaction/assets.rs +++ b/rmf_site_editor/src/interaction/assets.rs @@ -63,7 +63,7 @@ impl InteractionAssets { pub fn make_axis( &self, - command: &mut Commands, + commands: &mut Commands, // What entity will be moved when this gizmo is dragged for_entity_opt: Option, // What entity should be the parent frame of this gizmo @@ -73,22 +73,24 @@ impl InteractionAssets { rotation: Quat, scale: f32, ) -> Entity { - return command.entity(parent).add_children(|parent| { - let mut child_entity = parent.spawn(PbrBundle { + let child_entity = commands + .spawn(PbrBundle { transform: Transform::from_rotation(rotation) .with_translation(offset) .with_scale(Vec3::splat(scale)), mesh: self.arrow_mesh.clone(), material: material_set.passive.clone(), ..default() - }); + }) + .set_parent(parent) + .id(); - if let Some(for_entity) = for_entity_opt { - child_entity - .insert(DragAxisBundle::new(for_entity, Vec3::Z).with_materials(material_set)); - } - child_entity.id() - }); + if let Some(for_entity) = for_entity_opt { + commands + .entity(child_entity) + .insert(DragAxisBundle::new(for_entity, Vec3::Z).with_materials(material_set)); + } + child_entity } pub fn make_draggable_axis( @@ -121,12 +123,11 @@ impl InteractionAssets { anchor: Entity, cue: &mut AnchorVisualization, ) { - let drag_parent = commands.entity(anchor).add_children(|parent| { - parent - .spawn(SpatialBundle::default()) - .insert(VisualCue::no_outline().irregular().always_xray()) - .id() - }); + let drag_parent = commands + .spawn(SpatialBundle::default()) + .insert(VisualCue::no_outline().irregular().always_xray()) + .set_parent(anchor) + .id(); let height = 0.0; let scale = 0.2; @@ -167,12 +168,11 @@ impl InteractionAssets { cue: &mut AnchorVisualization, draggable: bool, ) { - let drag_parent = commands.entity(anchor).add_children(|parent| { - parent - .spawn(SpatialBundle::default()) - .insert(VisualCue::no_outline().irregular().always_xray()) - .id() - }); + let drag_parent = commands + .spawn(SpatialBundle::default()) + .insert(VisualCue::no_outline().irregular().always_xray()) + .id(); + commands.entity(anchor).add_child(drag_parent); let for_entity = if draggable { Some(anchor) } else { None }; let scale = 0.2; @@ -197,7 +197,7 @@ impl InteractionAssets { self.make_axis(commands, for_entity, drag_parent, m, p, r, scale); } - commands.entity(drag_parent).add_children(|parent| { + commands.entity(drag_parent).with_children(|parent| { for (polyline, material) in &self.centimeter_finite_grid { parent.spawn(PolylineBundle { polyline: polyline.clone(), diff --git a/rmf_site_editor/src/interaction/light.rs b/rmf_site_editor/src/interaction/light.rs index 1c04e6d6..60f8d875 100644 --- a/rmf_site_editor/src/interaction/light.rs +++ b/rmf_site_editor/src/interaction/light.rs @@ -65,98 +65,95 @@ pub fn add_physical_light_visual_cues( headlight_toggle.0 = false; } - let bodies = commands - .entity(e) - .insert(light_material.clone()) - .add_children(|parent| { - let point = parent - .spawn(SpatialBundle { - visibility: Visibility { - is_visible: kind.is_point(), - }, - ..default() - }) - .with_children(|point| { - point - .spawn(PbrBundle { - mesh: assets.point_light_socket_mesh.clone(), - material: assets.physical_light_cover_material.clone(), - ..default() - }) - .insert(Selectable::new(e)) - .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); - - point - .spawn(PbrBundle { - mesh: assets.point_light_shine_mesh.clone(), - material: light_material.clone(), - ..default() - }) - .insert(Selectable::new(e)) - .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); - }) - .id(); - - let spot = parent - .spawn(SpatialBundle { - visibility: Visibility { - is_visible: kind.is_spot(), - }, + let point = commands + .spawn(SpatialBundle { + visibility: Visibility { + is_visible: kind.is_point(), + }, + ..default() + }) + .with_children(|point| { + point + .spawn(PbrBundle { + mesh: assets.point_light_socket_mesh.clone(), + material: assets.physical_light_cover_material.clone(), ..default() }) - .with_children(|spot| { - spot.spawn(PbrBundle { - mesh: assets.spot_light_cover_mesh.clone(), - material: assets.physical_light_cover_material.clone(), - ..default() - }) - .insert(Selectable::new(e)) - .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); - - spot.spawn(PbrBundle { - mesh: assets.spot_light_shine_mesh.clone(), - material: light_material.clone(), - ..default() - }) - .insert(Selectable::new(e)) - .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); - }) - .id(); + .insert(Selectable::new(e)) + .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); - let directional = parent - .spawn(SpatialBundle { - visibility: Visibility { - is_visible: kind.is_directional(), - }, + point + .spawn(PbrBundle { + mesh: assets.point_light_shine_mesh.clone(), + material: light_material.clone(), ..default() }) - .with_children(|dir| { - dir.spawn(PbrBundle { - mesh: assets.directional_light_cover_mesh.clone(), - material: assets.direction_light_cover_material.clone(), - ..default() - }) - .insert(Selectable::new(e)) - .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); - - dir.spawn(PbrBundle { - mesh: assets.directional_light_shine_mesh.clone(), - material: light_material.clone(), - ..default() - }) - .insert(Selectable::new(e)) - .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); - }) - .id(); - - return LightBodies { - point, - spot, - directional, - }; - }); - - commands.entity(e).insert(bodies); + .insert(Selectable::new(e)) + .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); + }) + .id(); + + let spot = commands + .spawn(SpatialBundle { + visibility: Visibility { + is_visible: kind.is_spot(), + }, + ..default() + }) + .with_children(|spot| { + spot.spawn(PbrBundle { + mesh: assets.spot_light_cover_mesh.clone(), + material: assets.physical_light_cover_material.clone(), + ..default() + }) + .insert(Selectable::new(e)) + .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); + + spot.spawn(PbrBundle { + mesh: assets.spot_light_shine_mesh.clone(), + material: light_material.clone(), + ..default() + }) + .insert(Selectable::new(e)) + .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); + }) + .id(); + + let directional = commands + .spawn(SpatialBundle { + visibility: Visibility { + is_visible: kind.is_directional(), + }, + ..default() + }) + .with_children(|dir| { + dir.spawn(PbrBundle { + mesh: assets.directional_light_cover_mesh.clone(), + material: assets.direction_light_cover_material.clone(), + ..default() + }) + .insert(Selectable::new(e)) + .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); + + dir.spawn(PbrBundle { + mesh: assets.directional_light_shine_mesh.clone(), + material: light_material.clone(), + ..default() + }) + .insert(Selectable::new(e)) + .insert(DragPlaneBundle::new(e, Vec3::Z).globally()); + }) + .id(); + + commands + .entity(e) + .insert(light_material.clone()) + .insert(LightBodies { + point, + spot, + directional, + }) + .push_children(&[point, spot, directional]); } } diff --git a/rmf_site_editor/src/occupancy.rs b/rmf_site_editor/src/occupancy.rs index 877fe3c0..34779b7b 100644 --- a/rmf_site_editor/src/occupancy.rs +++ b/rmf_site_editor/src/occupancy.rs @@ -276,7 +276,7 @@ fn calculate_grid( ); } - commands.entity(level).add_children(|level| { + commands.entity(level).with_children(|level| { level .spawn(PbrBundle { mesh: meshes.add(mesh.into()), diff --git a/rmf_site_editor/src/site/door.rs b/rmf_site_editor/src/site/door.rs index 1135bb5f..9a2404fc 100644 --- a/rmf_site_editor/src/site/door.rs +++ b/rmf_site_editor/src/site/door.rs @@ -275,42 +275,36 @@ pub fn add_door_visuals( let (pose_tf, door_tfs, cue_inner_mesh, cue_outline_mesh) = make_door_visuals(e, edge, &anchors, kind); - let mut commands = commands.entity(e); - let (body, cue_inner, cue_outline) = commands.add_children(|parent| { - let bodies = door_tfs - .iter() - .map(|tf| { - parent - .spawn(PbrBundle { - mesh: assets.box_mesh.clone(), - material: assets.door_body_material.clone(), - transform: *tf, - ..default() - }) - .insert(Selectable::new(e)) - .id() - }) - .collect::>(); - let body = DoorBodyType::from_door_type(kind, &bodies); - - let cue_inner = parent - .spawn(PbrBundle { - mesh: meshes.add(cue_inner_mesh), - material: assets.translucent_white.clone(), - ..default() - }) - .id(); - - let cue_outline = parent - .spawn(PbrBundle { - mesh: meshes.add(cue_outline_mesh), - material: assets.translucent_black.clone(), - ..default() - }) - .id(); + let bodies = door_tfs + .iter() + .map(|tf| { + commands + .spawn(PbrBundle { + mesh: assets.box_mesh.clone(), + material: assets.door_body_material.clone(), + transform: *tf, + ..default() + }) + .insert(Selectable::new(e)) + .id() + }) + .collect::>(); + let body = DoorBodyType::from_door_type(kind, &bodies); + let cue_inner = commands + .spawn(PbrBundle { + mesh: meshes.add(cue_inner_mesh), + material: assets.translucent_white.clone(), + ..default() + }) + .id(); - (body, cue_inner, cue_outline) - }); + let cue_outline = commands + .spawn(PbrBundle { + mesh: meshes.add(cue_outline_mesh), + material: assets.translucent_black.clone(), + ..default() + }) + .id(); // Level doors for lifts may have already been given a Visibility // component upon creation, in which case we should respect whatever @@ -322,6 +316,7 @@ pub fn add_door_visuals( }; commands + .entity(e) .insert(SpatialBundle { transform: pose_tf, visibility: Visibility { is_visible }, @@ -333,7 +328,9 @@ pub fn add_door_visuals( cue_outline, }) .insert(Category::Door) - .insert(EdgeLabels::LeftRight); + .insert(EdgeLabels::LeftRight) + .push_children(&[cue_inner, cue_outline]) + .push_children(&bodies); for anchor in edge.array() { if let Ok(mut deps) = dependents.get_mut(anchor) { diff --git a/rmf_site_editor/src/site/drawing.rs b/rmf_site_editor/src/site/drawing.rs index 2d1f0711..00c9d41f 100644 --- a/rmf_site_editor/src/site/drawing.rs +++ b/rmf_site_editor/src/site/drawing.rs @@ -157,14 +157,16 @@ pub fn handle_loaded_drawing( // We can ignore the layer height here since that update // will be handled by another system. } else { - let mut cmd = commands.entity(entity); - let leaf = cmd.add_children(|p| p.spawn_empty().id()); + let leaf = commands.spawn_empty().id(); - cmd.insert(DrawingSegments { leaf }) + commands + .entity(entity) + .insert(DrawingSegments { leaf }) .insert(SpatialBundle::from_transform(pose.transform().with_scale( Vec3::new(1.0 / pixels_per_meter.0, 1.0 / pixels_per_meter.0, 1.), ))) - .insert(Selectable::new(entity)); + .insert(Selectable::new(entity)) + .push_children(&[leaf]); leaf }; let z = drawing_layer_height(rank); diff --git a/rmf_site_editor/src/site/floor.rs b/rmf_site_editor/src/site/floor.rs index cc966383..61d6d2f3 100644 --- a/rmf_site_editor/src/site/floor.rs +++ b/rmf_site_editor/src/site/floor.rs @@ -229,7 +229,6 @@ pub fn add_floor_visuals( let (base_color_texture, texture) = from_texture_source(texture_source, &textures); let mesh = make_floor_mesh(e, new_floor, &texture, &anchors); - let mut cmd = commands.entity(e); let height = floor_height(rank); let default_vis = parent .map(|p| default_floor_vis.get(p.get()).ok()) @@ -242,26 +241,27 @@ pub fn add_floor_visuals( ..default() }); - let mesh_entity_id = cmd + let mesh_entity_id = commands + .spawn(PbrBundle { + mesh: meshes.add(mesh), + material, + ..default() + }) + .insert(Selectable::new(e)) + .id(); + + commands + .entity(e) .insert(SpatialBundle { transform: Transform::from_xyz(0.0, 0.0, height), ..default() }) - .add_children(|p| { - p.spawn(PbrBundle { - mesh: meshes.add(mesh), - material, - ..default() - }) - .insert(Selectable::new(e)) - .id() - }); - - cmd.insert(FloorSegments { - mesh: mesh_entity_id, - }) - .insert(Category::Floor) - .insert(PathBehavior::for_floor()); + .insert(FloorSegments { + mesh: mesh_entity_id, + }) + .insert(Category::Floor) + .insert(PathBehavior::for_floor()) + .add_child(mesh_entity_id); for anchor in &new_floor.0 { let mut deps = dependents.get_mut(*anchor).unwrap(); diff --git a/rmf_site_editor/src/site/lane.rs b/rmf_site_editor/src/site/lane.rs index 5f0fb1f7..aec379ea 100644 --- a/rmf_site_editor/src/site/lane.rs +++ b/rmf_site_editor/src/site/lane.rs @@ -117,81 +117,67 @@ pub fn add_lane_visuals( let end_anchor = anchors .point_in_parent_frame_of(edge.end(), Category::Lane, e) .unwrap(); - let mut commands = commands.entity(e); - let (layer, start, mid, end, outlines) = commands.add_children(|parent| { - // Create a "layer" entity that manages the height of the lane, - // determined by the DisplayHeight of the graph. - let mut layer_cmd = parent.spawn(SpatialBundle { + + // Create a "layer" entity that manages the height of the lane, + // determined by the DisplayHeight of the graph. + let layer = commands + .spawn(SpatialBundle { transform: Transform::from_xyz(0.0, 0.0, height), ..default() - }); + }) + .set_parent(e) + .id(); - let (start, mid, end, outlines) = layer_cmd.add_children(|parent| { - let mut start = parent.spawn(PbrBundle { - mesh: assets.lane_end_mesh.clone(), - material: lane_material.clone(), - transform: Transform::from_translation(start_anchor), - ..default() - }); - let start_outline = start.add_children(|start| { - start - .spawn(PbrBundle { - mesh: assets.lane_end_outline.clone(), - transform: Transform::from_translation(-0.000_5 * Vec3::Z), - visibility: Visibility { is_visible: false }, - ..default() - }) - .id() - }); - let start = start.id(); - - let mut mid = parent.spawn(PbrBundle { - mesh: assets.lane_mid_mesh.clone(), + let mut spawn_lane_mesh_and_outline = |lane_tf, lane_mesh, outline_mesh| { + let mesh = commands + .spawn(PbrBundle { + mesh: lane_mesh, material: lane_material.clone(), - transform: line_stroke_transform(&start_anchor, &end_anchor, LANE_WIDTH), + transform: lane_tf, ..default() - }); - let mid_outline = mid.add_children(|mid| { - mid.spawn(PbrBundle { - mesh: assets.lane_mid_outline.clone(), - transform: Transform::from_translation(-0.000_5 * Vec3::Z), - visibility: Visibility { is_visible: false }, - ..default() - }) - .id() - }); - let mid = mid.id(); - - let mut end = parent.spawn(PbrBundle { - mesh: assets.lane_end_mesh.clone(), - material: lane_material.clone(), - transform: Transform::from_translation(end_anchor), + }) + .set_parent(layer) + .id(); + + let outline = commands + .spawn(PbrBundle { + mesh: outline_mesh, + transform: Transform::from_translation(-0.000_5 * Vec3::Z), + visibility: Visibility { is_visible: false }, ..default() - }); - let end_outline = end.add_children(|end| { - end.spawn(PbrBundle { - mesh: assets.lane_end_outline.clone(), - transform: Transform::from_translation(-0.000_5 * Vec3::Z), - visibility: Visibility { is_visible: false }, - ..default() - }) - .id() - }); - let end = end.id(); - - (start, mid, end, [start_outline, mid_outline, end_outline]) - }); - - (layer_cmd.id(), start, mid, end, outlines) - }); + }) + .set_parent(mesh) + .id(); + + (mesh, outline) + }; + + let (start, start_outline) = spawn_lane_mesh_and_outline( + Transform::from_translation(start_anchor), + assets.lane_end_mesh.clone(), + assets.lane_end_outline.clone(), + ); + + let (mid, mid_outline) = spawn_lane_mesh_and_outline( + line_stroke_transform(&start_anchor, &end_anchor, LANE_WIDTH), + assets.lane_mid_mesh.clone(), + assets.lane_mid_outline.clone(), + ); + + let (end, end_outline) = spawn_lane_mesh_and_outline( + Transform::from_translation(end_anchor), + assets.lane_end_mesh.clone(), + assets.lane_end_outline.clone(), + ); commands + .entity(e) .insert(LaneSegments { layer, start, mid, end, - outlines, + outlines: [start_outline, mid_outline, end_outline], }) .insert(SpatialBundle { transform: Transform::from_translation([0., 0., LANE_LAYER_START].into()), diff --git a/rmf_site_editor/src/site/lift.rs b/rmf_site_editor/src/site/lift.rs index 5064697f..4b876969 100644 --- a/rmf_site_editor/src/site/lift.rs +++ b/rmf_site_editor/src/site/lift.rs @@ -297,12 +297,14 @@ pub fn update_lift_cabin( *cabin_anchor_groups.get_mut(group).unwrap() = cabin_tf; } None => { - let group = commands.entity(e).add_children(|p| { - p.spawn(SpatialBundle::from_transform(cabin_tf)) - .insert(CabinAnchorGroupBundle::default()) - .id() - }); - commands.entity(e).insert(ChildCabinAnchorGroup(group)); + let group = commands + .spawn(SpatialBundle::from_transform(cabin_tf)) + .insert(CabinAnchorGroupBundle::default()) + .id(); + commands + .entity(e) + .insert(ChildCabinAnchorGroup(group)) + .add_child(group); } }; } diff --git a/rmf_site_editor/src/site/load.rs b/rmf_site_editor/src/site/load.rs index 09eed4a8..7523144f 100644 --- a/rmf_site_editor/src/site/load.rs +++ b/rmf_site_editor/src/site/load.rs @@ -76,232 +76,244 @@ fn generate_site_entities( } }; - let mut site_cmd = commands.spawn(SpatialBundle::INVISIBLE_IDENTITY); - let site_id = site_cmd.id(); - site_cmd + let site_id = commands + .spawn(SpatialBundle::INVISIBLE_IDENTITY) .insert(Category::Site) .insert(site_data.properties.clone()) .insert(WorkspaceMarker) - .add_children(|site| { - for (anchor_id, anchor) in &site_data.anchors { - let anchor_entity = site + .id(); + + for (anchor_id, anchor) in &site_data.anchors { + let anchor_entity = commands + .spawn(AnchorBundle::new(anchor.clone())) + .insert(SiteID(*anchor_id)) + .set_parent(site_id) + .id(); + id_to_entity.insert(*anchor_id, anchor_entity); + consider_id(*anchor_id); + } + + for (group_id, group) in &site_data.fiducial_groups { + let group_entity = commands + .spawn(group.clone()) + .insert(SiteID(*group_id)) + .set_parent(site_id) + .id(); + id_to_entity.insert(*group_id, group_entity); + consider_id(*group_id); + } + + for (group_id, group) in &site_data.textures { + let group_entity = commands + .spawn(group.clone()) + .insert(SiteID(*group_id)) + .set_parent(site_id) + .id(); + id_to_entity.insert(*group_id, group_entity); + consider_id(*group_id); + } + + for (level_id, level_data) in &site_data.levels { + let level_entity = commands.spawn(SiteID(*level_id)).set_parent(site_id).id(); + + for (anchor_id, anchor) in &level_data.anchors { + let anchor_entity = commands + .spawn(AnchorBundle::new(anchor.clone())) + .insert(SiteID(*anchor_id)) + .set_parent(level_entity) + .id(); + id_to_entity.insert(*anchor_id, anchor_entity); + consider_id(*anchor_id); + } + + for (door_id, door) in &level_data.doors { + let door_entity = commands + .spawn(door.convert(&id_to_entity).for_site(site_id)?) + .insert(SiteID(*door_id)) + .set_parent(level_entity) + .id(); + id_to_entity.insert(*door_id, door_entity); + consider_id(*door_id); + } + + for (drawing_id, drawing) in &level_data.drawings { + let drawing_entity = commands + .spawn(DrawingBundle::new(drawing.properties.clone())) + .insert(SiteID(*drawing_id)) + .set_parent(level_entity) + .id(); + + for (anchor_id, anchor) in &drawing.anchors { + let anchor_entity = commands .spawn(AnchorBundle::new(anchor.clone())) .insert(SiteID(*anchor_id)) + .set_parent(drawing_entity) .id(); id_to_entity.insert(*anchor_id, anchor_entity); consider_id(*anchor_id); } - for (group_id, group) in &site_data.fiducial_groups { - let group_entity = site.spawn(group.clone()).insert(SiteID(*group_id)).id(); - id_to_entity.insert(*group_id, group_entity); - consider_id(*group_id); - } - - for (group_id, group) in &site_data.textures { - let group_entity = site.spawn(group.clone()).insert(SiteID(*group_id)).id(); - id_to_entity.insert(*group_id, group_entity); - consider_id(*group_id); + for (fiducial_id, fiducial) in &drawing.fiducials { + commands + .spawn(fiducial.convert(&id_to_entity).for_site(site_id)?) + .insert(SiteID(*fiducial_id)) + .set_parent(drawing_entity) + .id(); + consider_id(*fiducial_id); } - for (level_id, level_data) in &site_data.levels { - let mut level_cmd = site.spawn(SiteID(*level_id)); - - level_cmd - .insert(SpatialBundle::INVISIBLE_IDENTITY) - .insert(level_data.properties.clone()) - .insert(Category::Level) - .add_children(|level| { - for (anchor_id, anchor) in &level_data.anchors { - let anchor_entity = level - .spawn(AnchorBundle::new(anchor.clone())) - .insert(SiteID(*anchor_id)) - .id(); - id_to_entity.insert(*anchor_id, anchor_entity); - consider_id(*anchor_id); - } - - for (door_id, door) in &level_data.doors { - let door_entity = level - .spawn(door.convert(&id_to_entity).for_site(site_id)?) - .insert(SiteID(*door_id)) - .id(); - id_to_entity.insert(*door_id, door_entity); - consider_id(*door_id); - } - - for (drawing_id, drawing) in &level_data.drawings { - level - .spawn(DrawingBundle::new(drawing.properties.clone())) - .insert(SiteID(*drawing_id)) - .add_children(|drawing_parent| { - for (anchor_id, anchor) in &drawing.anchors { - let anchor_entity = drawing_parent - .spawn(AnchorBundle::new(anchor.clone())) - .insert(SiteID(*anchor_id)) - .id(); - id_to_entity.insert(*anchor_id, anchor_entity); - consider_id(*anchor_id); - } - for (fiducial_id, fiducial) in &drawing.fiducials { - drawing_parent - .spawn( - fiducial - .convert(&id_to_entity) - .for_site(site_id)?, - ) - .insert(SiteID(*fiducial_id)); - consider_id(*fiducial_id); - } - for (measurement_id, measurement) in &drawing.measurements { - drawing_parent - .spawn( - measurement - .convert(&id_to_entity) - .for_site(site_id)?, - ) - .insert(SiteID(*measurement_id)); - consider_id(*measurement_id); - } - Ok(()) - })?; - consider_id(*drawing_id); - } - - for (floor_id, floor) in &level_data.floors { - level - .spawn(floor.convert(&id_to_entity).for_site(site_id)?) - .insert(SiteID(*floor_id)); - consider_id(*floor_id); - } - - for (light_id, light) in &level_data.lights { - level.spawn(light.clone()).insert(SiteID(*light_id)); - consider_id(*light_id); - } - - for (model_id, model) in &level_data.models { - level.spawn(model.clone()).insert(SiteID(*model_id)); - consider_id(*model_id); - } - - for (physical_camera_id, physical_camera) in &level_data.physical_cameras { - level - .spawn(physical_camera.clone()) - .insert(SiteID(*physical_camera_id)); - consider_id(*physical_camera_id); - } - - for (wall_id, wall) in &level_data.walls { - level - .spawn(wall.convert(&id_to_entity).for_site(site_id)?) - .insert(SiteID(*wall_id)); - consider_id(*wall_id); - } - Ok(()) - })?; - - // TODO(MXG): Log when a RecencyRanking fails to load correctly. - let level_entity = level_cmd - .insert( - RecencyRanking::::from_u32( - &level_data.rankings.floors, - &id_to_entity, - ) - .unwrap_or(RecencyRanking::new()), - ) - .insert( - RecencyRanking::::from_u32( - &level_data.rankings.drawings, - &id_to_entity, - ) - .unwrap_or(RecencyRanking::new()), - ) + for (measurement_id, measurement) in &drawing.measurements { + commands + .spawn(measurement.convert(&id_to_entity).for_site(site_id)?) + .insert(SiteID(*measurement_id)) + .set_parent(drawing_entity) .id(); - id_to_entity.insert(*level_id, level_entity); - consider_id(*level_id); + consider_id(*measurement_id); } - for (lift_id, lift_data) in &site_data.lifts { - let mut lift = site.spawn(SiteID(*lift_id)); - lift.add_children(|lift| { - let lift_entity = lift.parent_entity(); - lift.spawn(SpatialBundle::default()) - .insert(CabinAnchorGroupBundle::default()) - .with_children(|anchor_group| { - for (anchor_id, anchor) in &lift_data.cabin_anchors { - let anchor_entity = anchor_group - .spawn(AnchorBundle::new(anchor.clone())) - .insert(SiteID(*anchor_id)) - .id(); - id_to_entity.insert(*anchor_id, anchor_entity); - consider_id(*anchor_id); - } - }); - - for (door_id, door) in &lift_data.cabin_doors { - let door_entity = lift - .spawn(door.convert(&id_to_entity).for_site(site_id)?) - .insert(Dependents::single(lift_entity)) + consider_id(*drawing_id); + } + + for (floor_id, floor) in &level_data.floors { + commands + .spawn(floor.convert(&id_to_entity).for_site(site_id)?) + .insert(SiteID(*floor_id)) + .set_parent(level_entity) + .id(); + consider_id(*floor_id); + } + + for (wall_id, wall) in &level_data.walls { + commands + .spawn(wall.convert(&id_to_entity).for_site(site_id)?) + .insert(SiteID(*wall_id)) + .set_parent(level_entity) + .id(); + consider_id(*wall_id); + } + + commands + .entity(level_entity) + .insert(SpatialBundle::INVISIBLE_IDENTITY) + .insert(level_data.properties.clone()) + .insert(Category::Level) + .with_children(|level| { + // These don't need a return value so can be wrapped in a with_children + for (light_id, light) in &level_data.lights { + level.spawn(light.clone()).insert(SiteID(*light_id)); + consider_id(*light_id); + } + + for (model_id, model) in &level_data.models { + level.spawn(model.clone()).insert(SiteID(*model_id)); + consider_id(*model_id); + } + + for (physical_camera_id, physical_camera) in &level_data.physical_cameras { + level + .spawn(physical_camera.clone()) + .insert(SiteID(*physical_camera_id)); + consider_id(*physical_camera_id); + } + }); + + // TODO(MXG): Log when a RecencyRanking fails to load correctly. + commands + .entity(level_entity) + .insert( + RecencyRanking::::from_u32(&level_data.rankings.floors, &id_to_entity) + .unwrap_or(RecencyRanking::new()), + ) + .insert( + RecencyRanking::::from_u32( + &level_data.rankings.drawings, + &id_to_entity, + ) + .unwrap_or(RecencyRanking::new()), + ); + id_to_entity.insert(*level_id, level_entity); + consider_id(*level_id); + } + + for (lift_id, lift_data) in &site_data.lifts { + let lift_entity = commands.spawn(SiteID(*lift_id)).set_parent(site_id).id(); + + commands.entity(lift_entity).with_children(|lift| { + lift.spawn(SpatialBundle::default()) + .insert(CabinAnchorGroupBundle::default()) + .with_children(|anchor_group| { + for (anchor_id, anchor) in &lift_data.cabin_anchors { + let anchor_entity = anchor_group + .spawn(AnchorBundle::new(anchor.clone())) + .insert(SiteID(*anchor_id)) .id(); - id_to_entity.insert(*door_id, door_entity); - consider_id(*door_id); + id_to_entity.insert(*anchor_id, anchor_entity); + consider_id(*anchor_id); } - Ok(()) - })?; - - let lift = lift - .insert(Category::Lift) - .insert( - lift_data - .properties - .convert(&id_to_entity) - .for_site(site_id)?, - ) - .id(); - id_to_entity.insert(*lift_id, lift); - consider_id(*lift_id); - } + }); + }); - for (fiducial_id, fiducial) in &site_data.fiducials { - let fiducial_entity = site - .spawn(fiducial.convert(&id_to_entity).for_site(site_id)?) - .insert(SiteID(*fiducial_id)) - .id(); - id_to_entity.insert(*fiducial_id, fiducial_entity); - consider_id(*fiducial_id); - } + for (door_id, door) in &lift_data.cabin_doors { + let door_entity = commands + .spawn(door.convert(&id_to_entity).for_site(site_id)?) + .insert(Dependents::single(lift_entity)) + .set_parent(lift_entity) + .id(); + id_to_entity.insert(*door_id, door_entity); + consider_id(*door_id); + } - for (nav_graph_id, nav_graph_data) in &site_data.navigation.guided.graphs { - let nav_graph = site - .spawn(SpatialBundle::default()) - .insert(nav_graph_data.clone()) - .insert(SiteID(*nav_graph_id)) - .id(); - id_to_entity.insert(*nav_graph_id, nav_graph); - consider_id(*nav_graph_id); - } + commands.entity(lift_entity).insert(Category::Lift).insert( + lift_data + .properties + .convert(&id_to_entity) + .for_site(site_id)?, + ); - for (lane_id, lane_data) in &site_data.navigation.guided.lanes { - let lane = site - .spawn(lane_data.convert(&id_to_entity).for_site(site_id)?) - .insert(SiteID(*lane_id)) - .id(); - id_to_entity.insert(*lane_id, lane); - consider_id(*lane_id); - } + id_to_entity.insert(*lift_id, lift_entity); + consider_id(*lift_id); + } - for (location_id, location_data) in &site_data.navigation.guided.locations { - let location = site - .spawn(location_data.convert(&id_to_entity).for_site(site_id)?) - .insert(SiteID(*location_id)) - .id(); - id_to_entity.insert(*location_id, location); - consider_id(*location_id); - } + for (fiducial_id, fiducial) in &site_data.fiducials { + let fiducial_entity = commands + .spawn(fiducial.convert(&id_to_entity).for_site(site_id)?) + .insert(SiteID(*fiducial_id)) + .set_parent(site_id) + .id(); + id_to_entity.insert(*fiducial_id, fiducial_entity); + consider_id(*fiducial_id); + } + + for (nav_graph_id, nav_graph_data) in &site_data.navigation.guided.graphs { + let nav_graph = commands + .spawn(SpatialBundle::default()) + .insert(nav_graph_data.clone()) + .insert(SiteID(*nav_graph_id)) + .set_parent(site_id) + .id(); + id_to_entity.insert(*nav_graph_id, nav_graph); + consider_id(*nav_graph_id); + } + + for (lane_id, lane_data) in &site_data.navigation.guided.lanes { + let lane = commands + .spawn(lane_data.convert(&id_to_entity).for_site(site_id)?) + .insert(SiteID(*lane_id)) + .set_parent(site_id) + .id(); + id_to_entity.insert(*lane_id, lane); + consider_id(*lane_id); + } - Ok(()) - })?; + for (location_id, location_data) in &site_data.navigation.guided.locations { + let location = commands + .spawn(location_data.convert(&id_to_entity).for_site(site_id)?) + .insert(SiteID(*location_id)) + .set_parent(site_id) + .id(); + id_to_entity.insert(*location_id, location); + consider_id(*location_id); + } let nav_graph_rankings = match RecencyRanking::::from_u32( &site_data.navigation.guided.ranking, @@ -317,7 +329,8 @@ fn generate_site_entities( } }; - site_cmd + commands + .entity(site_id) .insert(nav_graph_rankings) .insert(NextSiteID(highest_id + 1)); @@ -510,7 +523,7 @@ fn generate_imported_nav_graphs( } } if !already_existing { - params.commands.entity(anchor_group).add_children(|group| { + params.commands.entity(anchor_group).with_children(|group| { let e_anchor = group.spawn(AnchorBundle::new(anchor.clone())).id(); id_to_entity.insert(*anchor_id, e_anchor); }); @@ -538,7 +551,7 @@ fn generate_imported_nav_graphs( } } if !already_existing { - params.commands.entity(level_e).add_children(|level| { + params.commands.entity(level_e).with_children(|level| { let e_anchor = level.spawn(AnchorBundle::new(anchor.clone())).id(); id_to_entity.insert(*anchor_id, e_anchor); }); @@ -561,7 +574,7 @@ fn generate_imported_nav_graphs( } } if !already_existing { - params.commands.entity(into_site).add_children(|site| { + params.commands.entity(into_site).with_children(|site| { let e_anchor = site.spawn(AnchorBundle::new(anchor.clone())).id(); id_to_entity.insert(*anchor_id, e_anchor); }); @@ -570,7 +583,7 @@ fn generate_imported_nav_graphs( } for (nav_graph_id, nav_graph_data) in &from_site_data.navigation.guided.graphs { - params.commands.entity(into_site).add_children(|site| { + params.commands.entity(into_site).with_children(|site| { let e = site .spawn(SpatialBundle::default()) .insert(nav_graph_data.clone()) @@ -583,7 +596,7 @@ fn generate_imported_nav_graphs( let lane_data = lane_data .convert(&id_to_entity) .map_err(ImportNavGraphError::BrokenInternalReference)?; - params.commands.entity(into_site).add_children(|site| { + params.commands.entity(into_site).with_children(|site| { let e = site.spawn(lane_data).id(); id_to_entity.insert(*lane_id, e); }); @@ -593,7 +606,7 @@ fn generate_imported_nav_graphs( let location_data = location_data .convert(&id_to_entity) .map_err(ImportNavGraphError::BrokenInternalReference)?; - params.commands.entity(into_site).add_children(|site| { + params.commands.entity(into_site).with_children(|site| { let e = site.spawn(location_data).id(); id_to_entity.insert(*location_id, e); }); diff --git a/rmf_site_editor/src/site/model.rs b/rmf_site_editor/src/site/model.rs index 7c20c524..6279ded1 100644 --- a/rmf_site_editor/src/site/model.rs +++ b/rmf_site_editor/src/site/model.rs @@ -102,59 +102,64 @@ pub fn handle_model_loaded_events( for (e, h, scale, render_layer) in loading_models.iter() { if asset_server.get_load_state(&h.0) == LoadState::Loaded { let model_id = if let Some(gltf) = gltfs.get(&h.typed_weak::()) { - Some(commands.entity(e).add_children(|parent| { - // Get default scene if present, otherwise index 0 - let scene = gltf - .default_scene - .as_ref() - .map(|s| s.clone()) - .unwrap_or(gltf.scenes.get(0).unwrap().clone()); - parent + // Get default scene if present, otherwise index 0 + let scene = gltf + .default_scene + .as_ref() + .map(|s| s.clone()) + .unwrap_or(gltf.scenes.get(0).unwrap().clone()); + Some( + commands .spawn(SceneBundle { scene, transform: Transform::from_scale(**scale), ..default() }) - .id() - })) + .set_parent(e) + .id(), + ) } else if scenes.contains(&h.typed_weak::()) { - Some(commands.entity(e).add_children(|parent| { - let h_typed = h.0.clone().typed::(); - parent + let h_typed = h.0.clone().typed::(); + Some( + commands .spawn(SceneBundle { scene: h_typed, transform: Transform::from_scale(**scale), ..default() }) - .id() - })) + .set_parent(e) + .id(), + ) } else if meshes.contains(&h.typed_weak::()) { - Some(commands.entity(e).add_children(|parent| { - let h_typed = h.0.clone().typed::(); - parent + let h_typed = h.0.clone().typed::(); + Some( + commands .spawn(PbrBundle { mesh: h_typed, material: site_assets.default_mesh_grey_material.clone(), transform: Transform::from_scale(**scale), ..default() }) - .id() - })) + .set_parent(e) + .id(), + ) } else if let Some(urdf) = urdfs.get(&h.typed_weak::()) { - Some(commands.entity(e).add_children(|parent| { - parent + Some( + commands .spawn(SpatialBundle::VISIBLE_IDENTITY) .insert(urdf.clone()) .insert(Category::Workcell) - .id() - })) + .set_parent(e) + .id(), + ) } else if let Some(sdf) = sdfs.get(&h.typed_weak::()) { - Some(commands.entity(e).add_children(|parent| { - parent + Some( + commands .spawn(SpatialBundle::VISIBLE_IDENTITY) .insert(sdf.clone()) - .id() - })) + .set_parent(e) + .id(), + ) } else { None }; diff --git a/rmf_site_editor/src/site/site.rs b/rmf_site_editor/src/site/site.rs index df7d32d5..0e3e9f6e 100644 --- a/rmf_site_editor/src/site/site.rs +++ b/rmf_site_editor/src/site/site.rs @@ -116,16 +116,16 @@ pub fn change_site( if !found_level { // Create a new blank level for the user - let new_level = commands.entity(cmd.site).add_children(|site| { - site.spawn(SpatialBundle::default()) - .insert(LevelProperties { - name: NameInSite("".to_owned()), - elevation: LevelElevation(0.), - global_floor_visibility: default(), - global_drawing_visibility: default(), - }) - .id() - }); + let new_level = commands + .spawn(SpatialBundle::default()) + .insert(LevelProperties { + name: NameInSite("".to_owned()), + elevation: LevelElevation(0.), + global_floor_visibility: default(), + global_drawing_visibility: default(), + }) + .set_parent(cmd.site) + .id(); commands.entity(cmd.site).insert(CachedLevel(new_level)); current_level.0 = Some(new_level); diff --git a/rmf_site_editor/src/workcell/workcell.rs b/rmf_site_editor/src/workcell/workcell.rs index 218aec07..3b851298 100644 --- a/rmf_site_editor/src/workcell/workcell.rs +++ b/rmf_site_editor/src/workcell/workcell.rs @@ -56,7 +56,7 @@ pub fn add_workcell_visualization( for e in new_workcells.iter() { let body_mesh = site_assets.site_anchor_mesh.clone(); let mut entity_commands = commands.entity(e); - entity_commands.add_children(|parent| { + entity_commands.with_children(|parent| { let mut body = parent.spawn(PbrBundle { mesh: body_mesh, material: site_assets.passive_anchor_material.clone(),