Skip to content

Commit dcd6b51

Browse files
Introducing model descriptions and instances (#242)
Signed-off-by: Reuben Thomas <[email protected]> Signed-off-by: Xiyu Oh <[email protected]> Co-authored-by: Reuben Thomas <[email protected]>
1 parent 7ef0935 commit dcd6b51

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3763
-403
lines changed

Cargo.lock

Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/demo_maps/office.building.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ levels:
181181
- [814.828, 239.25, 0, "", {is_parking_spot: [4, false]}]
182182
- [1210.544, 365.254, 0, ""]
183183
- [1191.442, 824.457, 0, ""]
184-
- [1232.421, 658.567, 0, tinyRobot1_charger, {is_charger: [4, true], is_holding_point: [4, true], is_parking_spot: [4, true], spawn_robot_name: [1, tinyRobot1], spawn_robot_type: [1, TinyRobot]}]
184+
- [1232.421, 658.567, 0, tinyRobot1_charger, {is_charger: [4, true], is_holding_point: [4, true], is_parking_spot: [4, true], spawn_robot_name: [1, tinyRobot1], spawn_robot_type: [1, Open-RMF/TinyRobot]}]
185185
- [1991.121, 812.872, 0, ""]
186186
- [1990, 638.364, 0, pantry, {is_holding_point: [4, true], is_parking_spot: [4, false], pickup_dispenser: [1, coke_dispenser]}]
187187
- [2213.636, 812, 0, "", {is_parking_spot: [4, false]}]
@@ -206,7 +206,7 @@ levels:
206206
- [769.867, 618.148, 0, ""]
207207
- [2016.125, 1310.955, 0, ""]
208208
- [2468.096, 1217.693, 0, ""]
209-
- [2412.581, 627.5, 0, tinyRobot2_charger, {is_charger: [4, true], is_holding_point: [4, true], is_parking_spot: [4, true], spawn_robot_name: [1, tinyRobot2], spawn_robot_type: [1, TinyRobot]}]
209+
- [2412.581, 627.5, 0, tinyRobot2_charger, {is_charger: [4, true], is_holding_point: [4, true], is_parking_spot: [4, true], spawn_robot_name: [1, tinyRobot2], spawn_robot_type: [1, Open-RMF/TinyRobot]}]
210210
walls:
211211
- [6, 7, {alpha: [3, 1], texture_name: [1, default]}]
212212
- [7, 12, {alpha: [3, 1], texture_name: [1, default]}]

rmf_site_editor/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pathdiff = "*"
4949
ehttp = { version = "0.4", features = ["native-async"] }
5050
nalgebra = "0.32.5"
5151
anyhow = "*"
52+
strum = "*"
5253

5354
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
5455
clap = { version = "4.0.10", features = ["color", "derive", "help", "usage", "suggestions"] }

rmf_site_editor/src/interaction/cursor.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
use bevy::{ecs::system::SystemParam, prelude::*, window::PrimaryWindow};
2424
use bevy_mod_raycast::primitives::{rays::Ray3d, Primitive3d};
2525

26-
use rmf_site_format::{FloorMarker, Model, WallMarker};
26+
use rmf_site_format::{FloorMarker, ModelInstance, WallMarker};
2727
use std::collections::HashSet;
2828

2929
/// A resource that keeps track of the unique entities that play a role in
@@ -120,23 +120,21 @@ impl Cursor {
120120
}
121121
}
122122

123-
pub fn set_model_preview(
123+
pub fn set_model_instance_preview(
124124
&mut self,
125125
commands: &mut Commands,
126126
model_loader: &mut ModelLoader,
127-
model: Option<Model>,
127+
model_instance: Option<ModelInstance<Entity>>,
128128
) {
129129
self.remove_preview(commands);
130-
self.preview_model = if let Some(model) = model {
130+
self.preview_model = model_instance.and_then(|model_instance| {
131131
Some(
132132
model_loader
133-
.spawn_model(self.frame, model.clone())
133+
.spawn_model_instance(self.frame, model_instance)
134134
.insert(Pending)
135135
.id(),
136136
)
137-
} else {
138-
None
139-
};
137+
});
140138
}
141139

142140
pub fn should_be_visible(&self) -> bool {

rmf_site_editor/src/interaction/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ pub use lift::*;
5454
pub mod light;
5555
pub use light::*;
5656

57+
pub mod model;
58+
pub use model::*;
59+
5760
pub mod model_preview;
5861
pub use model_preview::*;
5962

@@ -197,6 +200,7 @@ impl Plugin for InteractionPlugin {
197200
.add_systems(
198201
Update,
199202
(
203+
update_model_instance_visual_cues.after(SelectionServiceStages::Select),
200204
update_lane_visual_cues.after(SelectionServiceStages::Select),
201205
update_edge_visual_cues.after(SelectionServiceStages::Select),
202206
update_point_visual_cues.after(SelectionServiceStages::Select),
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright (C) 2024 Open Source Robotics Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
use crate::{interaction::*, site::*};
19+
use bevy::prelude::*;
20+
21+
pub fn update_model_instance_visual_cues(
22+
model_descriptions: Query<
23+
(Entity, &Selected, &Hovered),
24+
(
25+
With<ModelMarker>,
26+
With<Group>,
27+
Or<(Changed<Hovered>, Changed<Selected>)>,
28+
),
29+
>,
30+
mut model_instances: Query<
31+
(
32+
Entity,
33+
&mut Selected,
34+
&mut Hovered,
35+
&mut Affiliation<Entity>,
36+
Option<Ref<Tasks<Entity>>>,
37+
),
38+
(With<ModelMarker>, Without<Group>),
39+
>,
40+
mut locations: Query<(&mut Selected, &mut Hovered), (With<LocationTags>, Without<ModelMarker>)>,
41+
mut removed_components: RemovedComponents<Tasks<Entity>>,
42+
) {
43+
for (instance_entity, mut instance_selected, mut instance_hovered, affiliation, tasks) in
44+
&mut model_instances
45+
{
46+
let mut is_description_selected = false;
47+
if let Some(description_entity) = affiliation.0 {
48+
if let Ok((_, description_selected, description_hovered)) =
49+
model_descriptions.get(description_entity)
50+
{
51+
if description_selected.cue() {
52+
instance_selected
53+
.support_selected
54+
.insert(description_entity);
55+
is_description_selected = true;
56+
} else {
57+
instance_selected
58+
.support_selected
59+
.remove(&description_entity);
60+
}
61+
if description_hovered.cue() {
62+
instance_hovered.support_hovering.insert(description_entity);
63+
} else {
64+
instance_hovered
65+
.support_hovering
66+
.remove(&description_entity);
67+
}
68+
}
69+
}
70+
71+
// When an instance is selected, select all locations supporting it
72+
if let Some(tasks) = tasks {
73+
// When tasks for an instance have changed, reset all locations from supporting this instance
74+
if tasks.is_changed() {
75+
for (mut location_selected, mut location_hovered) in locations.iter_mut() {
76+
location_selected.support_selected.remove(&instance_entity);
77+
location_hovered.support_hovering.remove(&instance_entity);
78+
}
79+
}
80+
81+
if let Some(task_location) = tasks.0.first().and_then(|t| t.location()) {
82+
if let Ok((mut location_selected, mut location_hovered)) =
83+
locations.get_mut(task_location.0)
84+
{
85+
if instance_selected.cue() && !is_description_selected {
86+
location_selected.support_selected.insert(instance_entity);
87+
} else {
88+
location_selected.support_selected.remove(&instance_entity);
89+
}
90+
if instance_hovered.cue() {
91+
location_hovered.support_hovering.insert(instance_entity);
92+
} else {
93+
location_hovered.support_hovering.remove(&instance_entity);
94+
}
95+
}
96+
}
97+
}
98+
}
99+
100+
// When instances are removed, prevent any location from supporting them
101+
for removed in removed_components.read() {
102+
for (mut location_selected, mut location_hovered) in locations.iter_mut() {
103+
location_selected.support_selected.remove(&removed);
104+
location_hovered.support_hovering.remove(&removed);
105+
}
106+
}
107+
}

rmf_site_editor/src/interaction/select/place_object.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
use crate::{
1919
interaction::select::*,
20-
site::{CurrentLevel, Model},
20+
site::{CurrentLevel, ModelInstance},
2121
};
2222
use bevy::ecs::system::{Command, SystemParam, SystemState};
2323

@@ -51,7 +51,7 @@ pub struct ObjectPlacement<'w, 's> {
5151
}
5252

5353
impl<'w, 's> ObjectPlacement<'w, 's> {
54-
pub fn place_object_2d(&mut self, object: Model) {
54+
pub fn place_object_2d(&mut self, object: ModelInstance<Entity>) {
5555
let Some(level) = self.current_level.0 else {
5656
warn!("Unble to create [object:?] outside a level");
5757
return;
@@ -75,17 +75,17 @@ impl<'w, 's> ObjectPlacement<'w, 's> {
7575

7676
/// Trait to be implemented to allow placing models with commands
7777
pub trait ObjectPlacementExt<'w, 's> {
78-
fn place_object_2d(&mut self, object: Model);
78+
fn place_object_2d(&mut self, object: ModelInstance<Entity>);
7979
}
8080

8181
impl<'w, 's> ObjectPlacementExt<'w, 's> for Commands<'w, 's> {
82-
fn place_object_2d(&mut self, object: Model) {
82+
fn place_object_2d(&mut self, object: ModelInstance<Entity>) {
8383
self.add(ObjectPlaceCommand(object));
8484
}
8585
}
8686

8787
#[derive(Deref, DerefMut)]
88-
pub struct ObjectPlaceCommand(Model);
88+
pub struct ObjectPlaceCommand(ModelInstance<Entity>);
8989

9090
impl Command for ObjectPlaceCommand {
9191
fn apply(self, world: &mut World) {

rmf_site_editor/src/interaction/select/place_object_2d.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
use crate::{
1919
interaction::select::*,
20-
site::{Model, ModelLoader},
20+
site::{ModelInstance, ModelLoader},
2121
};
2222
use bevy::prelude::Input as UserInput;
2323

@@ -104,7 +104,7 @@ pub fn build_place_object_2d_workflow(
104104
}
105105

106106
pub struct PlaceObject2d {
107-
pub object: Model,
107+
pub object: ModelInstance<Entity>,
108108
pub level: Entity,
109109
}
110110

@@ -121,7 +121,7 @@ pub fn place_object_2d_setup(
121121
let mut access = access.get_mut(&key).or_broken_buffer()?;
122122
let state = access.newest_mut().or_broken_buffer()?;
123123

124-
cursor.set_model_preview(&mut commands, &mut model_loader, Some(state.object.clone()));
124+
cursor.set_model_instance_preview(&mut commands, &mut model_loader, Some(state.object.clone()));
125125
set_visibility(cursor.dagger, &mut visibility, false);
126126
set_visibility(cursor.halo, &mut visibility, false);
127127

@@ -206,7 +206,7 @@ pub fn on_placement_chosen_2d(
206206

207207
state.object.pose = placement.into();
208208
model_loader
209-
.spawn_model(state.level, state.object)
209+
.spawn_model_instance(state.level, state.object)
210210
.insert(Category::Model);
211211

212212
Ok(())

rmf_site_editor/src/occupancy.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ pub struct CalculateGrid {
140140
pub floor: f32,
141141
/// Ignore meshes above this height
142142
pub ceiling: f32,
143+
// Ignore these entities
144+
pub ignore: HashSet<Entity>,
143145
}
144146

145147
enum Group {
@@ -180,6 +182,12 @@ fn calculate_grid(
180182
let physical_entities = collect_physical_entities(&bodies, &meta);
181183
info!("Checking {:?} physical entities", physical_entities.len());
182184
for e in &physical_entities {
185+
if !request.ignore.is_empty() {
186+
if AncestorIter::new(&parents, *e).any(|p| request.ignore.contains(&p)) {
187+
continue;
188+
}
189+
}
190+
183191
let (_, mesh, aabb, tf) = match bodies.get(*e) {
184192
Ok(body) => body,
185193
Err(_) => continue,

rmf_site_editor/src/site/group.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,9 @@ pub struct MergeGroups {
2727
pub into_group: Entity,
2828
}
2929

30-
#[derive(Component, Deref)]
30+
#[derive(Component, Deref, DerefMut)]
3131
pub struct Members(Vec<Entity>);
3232

33-
impl Members {
34-
pub fn iter(&self) -> impl Iterator<Item = &Entity> {
35-
self.0.iter()
36-
}
37-
}
38-
3933
#[derive(Component, Clone, Copy)]
4034
struct LastAffiliation(Option<Entity>);
4135

0 commit comments

Comments
 (0)