Skip to content

Commit a83a94b

Browse files
xiyuohmxgrey
andauthored
Do not query SiteParent (#260)
* Do not query SiteParent Signed-off-by: Xiyu Oh <[email protected]> * Add diagnostic if unable to add to current level Signed-off-by: Xiyu Oh <[email protected]> * Fix merge conflicts Signed-off-by: Michael X. Grey <[email protected]> * Remove misalignment and fix deviation in commit history Signed-off-by: Xiyu Oh <[email protected]> * Use Parented Signed-off-by: Xiyu Oh <[email protected]> * Review comments Signed-off-by: Xiyu Oh <[email protected]> --------- Signed-off-by: Xiyu Oh <[email protected]> Signed-off-by: Michael X. Grey <[email protected]> Co-authored-by: Michael X. Grey <[email protected]>
1 parent 0b302db commit a83a94b

File tree

12 files changed

+113
-136
lines changed

12 files changed

+113
-136
lines changed

rmf_site_editor/src/interaction/cursor.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,11 @@ impl Cursor {
127127
model_instance: Option<ModelInstance<Entity>>,
128128
) {
129129
self.remove_preview(commands);
130-
self.preview_model = model_instance.and_then(|model_instance| {
131-
Some(
132-
model_loader
133-
.spawn_model_instance(self.frame, model_instance)
134-
.insert(Pending)
135-
.id(),
136-
)
130+
self.preview_model = model_instance.map(|instance| {
131+
model_loader
132+
.spawn_model_instance(self.frame, instance)
133+
.insert(Pending)
134+
.id()
137135
});
138136
}
139137

rmf_site_editor/src/site/load.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -362,16 +362,20 @@ fn generate_site_entities(
362362
}
363363
}
364364

365-
for (model_instance_id, model_instance_data) in &site_data.model_instances {
366-
let model_instance = model_instance_data
365+
for (model_instance_id, parented_model_instance) in &site_data.model_instances {
366+
let model_instance = parented_model_instance
367+
.bundle
367368
.convert(&id_to_entity)
368369
.for_site(site_id)?;
369370

371+
// The parent id is invalid, we do not spawn this model instance and generate
372+
// an error instead
373+
let parent = id_to_entity
374+
.get(&parented_model_instance.parent)
375+
.ok_or_else(|| LoadSiteError::new(site_id, parented_model_instance.parent))?;
376+
370377
let model_instance_entity = model_loader
371-
.spawn_model_instance(
372-
model_instance.parent.0.unwrap_or(site_id),
373-
model_instance.clone(),
374-
)
378+
.spawn_model_instance(*parent, model_instance.clone())
375379
.insert((Category::Model, SiteID(*model_instance_id)))
376380
.id();
377381
id_to_entity.insert(*model_instance_id, model_instance_entity);

rmf_site_editor/src/site/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ impl Plugin for SitePlugin {
281281
check_for_duplicated_dock_names,
282282
check_for_fiducials_without_affiliation,
283283
check_for_close_unconnected_anchors,
284+
check_for_orphan_model_instances,
284285
fetch_image_for_texture,
285286
detect_last_selected_texture::<FloorMarker>,
286287
apply_last_selected_texture::<FloorMarker>
@@ -305,7 +306,6 @@ impl Plugin for SitePlugin {
305306
assign_orphan_levels_to_site,
306307
assign_orphan_nav_elements_to_site,
307308
assign_orphan_fiducials_to_parent,
308-
assign_orphan_model_instances_to_level,
309309
assign_orphan_elements_to_level::<DoorMarker>,
310310
assign_orphan_elements_to_level::<DrawingMarker>,
311311
assign_orphan_elements_to_level::<FloorMarker>,

rmf_site_editor/src/site/model.rs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@
1717

1818
use crate::{
1919
interaction::{DragPlaneBundle, Preview, MODEL_PREVIEW_LAYER},
20-
site::{CurrentLevel, SiteAssets, SiteParent},
20+
site::SiteAssets,
2121
site_asset_io::MODEL_ENVIRONMENT_VARIABLE,
22+
Issue, ValidateWorkspace,
2223
};
2324
use bevy::{
2425
ecs::system::{EntityCommands, SystemParam},
2526
gltf::Gltf,
2627
prelude::*,
2728
render::view::RenderLayers,
2829
scene::SceneInstance,
30+
utils::Uuid,
2931
};
3032
use bevy_impulse::*;
3133
use bevy_mod_outline::OutlineMeshExt;
3234
use rmf_site_format::{
33-
Affiliation, AssetSource, Group, ModelInstance, ModelMarker, ModelProperty, Pending, Scale,
35+
Affiliation, AssetSource, Group, IssueKey, ModelInstance, ModelMarker, ModelProperty,
36+
NameInSite, Pending, Scale,
3437
};
3538
use smallvec::SmallVec;
3639
use std::{any::TypeId, collections::HashSet, fmt, future::Future};
@@ -783,25 +786,48 @@ pub fn update_model_instances<T: Component + Default + Clone>(
783786
}
784787
}
785788

786-
pub fn assign_orphan_model_instances_to_level(
789+
/// Unique UUID to identify issue of orphan model instance
790+
pub const ORPHAN_MODEL_INSTANCE_ISSUE_UUID: Uuid =
791+
Uuid::from_u128(0x4e98ce0bc28e4fe528cb0a028f4d5c08u128);
792+
793+
pub fn check_for_orphan_model_instances(
787794
mut commands: Commands,
795+
mut validate_events: EventReader<ValidateWorkspace>,
788796
mut orphan_instances: Query<
789-
(Entity, Option<&Parent>, &mut SiteParent<Entity>),
790-
(With<ModelMarker>, Without<Group>),
797+
(Entity, &NameInSite, &Affiliation<Entity>),
798+
(With<ModelMarker>, Without<Group>, Without<Parent>),
791799
>,
792-
current_level: Res<CurrentLevel>,
800+
model_descriptions: Query<&NameInSite, (With<ModelMarker>, With<Group>)>,
793801
) {
794-
let current_level = match current_level.0 {
795-
Some(c) => c,
796-
None => return,
797-
};
798-
799-
for (instance_entity, parent, mut site_parent) in orphan_instances.iter_mut() {
800-
if parent.is_none() {
801-
commands.entity(current_level).add_child(instance_entity);
802-
}
803-
if site_parent.0.is_none() {
804-
site_parent.0 = Some(current_level);
802+
for root in validate_events.read() {
803+
for (instance_entity, instance_name, affiliation) in orphan_instances.iter_mut() {
804+
let brief = match affiliation
805+
.0
806+
.map(|e| model_descriptions.get(e).ok())
807+
.flatten()
808+
{
809+
Some(description_name) => format!(
810+
"Parent level entity not found for model instance {:?} with \
811+
affiliated model description {:?}",
812+
instance_name, description_name
813+
),
814+
None => format!(
815+
"Parent level entity not found for model instance {:?} when saving",
816+
instance_name,
817+
),
818+
};
819+
let issue = Issue {
820+
key: IssueKey {
821+
entities: [instance_entity].into(),
822+
kind: ORPHAN_MODEL_INSTANCE_ISSUE_UUID,
823+
},
824+
brief,
825+
hint: "Model instances need to be assigned to a parent level entity. \
826+
Respawn the orphan model instance"
827+
.to_string(),
828+
};
829+
let issue_id = commands.spawn(issue).id();
830+
commands.entity(**root).add_child(issue_id);
805831
}
806832
}
807833
}

rmf_site_editor/src/site/save.rs

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,18 +1250,11 @@ fn generate_model_descriptions(
12501250
fn generate_model_instances(
12511251
site: Entity,
12521252
world: &mut World,
1253-
) -> Result<BTreeMap<u32, ModelInstance<u32>>, SiteGenerationError> {
1253+
) -> Result<BTreeMap<u32, Parented<u32, ModelInstance<u32>>>, SiteGenerationError> {
12541254
let mut state: SystemState<(
12551255
Query<&SiteID, (With<ModelMarker>, With<Group>, Without<Pending>)>,
12561256
Query<
1257-
(
1258-
Entity,
1259-
&SiteID,
1260-
&NameInSite,
1261-
&Pose,
1262-
&SiteParent<Entity>,
1263-
&Affiliation<Entity>,
1264-
),
1257+
(Entity, &SiteID, &NameInSite, &Pose, &Affiliation<Entity>),
12651258
(With<ModelMarker>, Without<Group>, Without<Pending>),
12661259
>,
12671260
Query<(Entity, &SiteID), With<LevelElevation>>,
@@ -1279,28 +1272,22 @@ fn generate_model_instances(
12791272
site_levels_ids.insert(level_entity, site_id.0);
12801273
}
12811274
}
1282-
let mut res = BTreeMap::<u32, ModelInstance<u32>>::new();
1283-
for (
1284-
_instance_entity,
1285-
instance_id,
1286-
instance_name,
1287-
instance_pose,
1288-
instance_parent,
1289-
instance_affiliation,
1290-
) in model_instances.iter()
1275+
let mut res = BTreeMap::<u32, Parented<u32, ModelInstance<u32>>>::new();
1276+
for (instance_entity, instance_id, instance_name, instance_pose, instance_affiliation) in
1277+
model_instances.iter()
12911278
{
1292-
let Ok(parent) = instance_parent
1293-
.0
1294-
.map(|p| site_levels_ids.get(&p).copied().ok_or(()))
1295-
.transpose()
1279+
let Some(level_id) = parents
1280+
.get(instance_entity)
1281+
.ok()
1282+
.map(|p| site_levels_ids.get(&p.get()).copied())
1283+
.flatten()
12961284
else {
12971285
error!("Unable to find parent for instance [{}]", instance_name.0);
12981286
continue;
12991287
};
13001288
let mut model_instance = ModelInstance::<u32> {
13011289
name: instance_name.clone(),
13021290
pose: instance_pose.clone(),
1303-
parent: SiteParent(parent),
13041291
description: Affiliation(
13051292
instance_affiliation
13061293
.0
@@ -1309,7 +1296,7 @@ fn generate_model_instances(
13091296
),
13101297
..Default::default()
13111298
};
1312-
if let Ok(robot_tasks) = tasks.get(_instance_entity) {
1299+
if let Ok(robot_tasks) = tasks.get(instance_entity) {
13131300
let tasks: Vec<Task<u32>> = robot_tasks
13141301
.0
13151302
.clone()
@@ -1333,7 +1320,13 @@ fn generate_model_instances(
13331320
.0
13341321
.push(OptionalModelProperty::Tasks(Tasks(tasks.clone())));
13351322
}
1336-
res.insert(instance_id.0, model_instance);
1323+
res.insert(
1324+
instance_id.0,
1325+
Parented {
1326+
parent: level_id,
1327+
bundle: model_instance,
1328+
},
1329+
);
13371330
}
13381331
Ok(res)
13391332
}

rmf_site_editor/src/site/scenario.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
interaction::{Select, Selection},
2020
site::{
2121
Affiliation, CurrentScenario, Delete, DeletionBox, DeletionFilters, Dependents,
22-
InstanceMarker, Pending, Pose, Scenario, ScenarioBundle, ScenarioMarker, SiteParent,
22+
InstanceMarker, Pending, Pose, Scenario, ScenarioBundle, ScenarioMarker,
2323
},
2424
CurrentWorkspace,
2525
};
@@ -37,10 +37,7 @@ pub fn update_current_scenario(
3737
mut current_scenario: ResMut<CurrentScenario>,
3838
current_workspace: Res<CurrentWorkspace>,
3939
scenarios: Query<&Scenario<Entity>>,
40-
mut instances: Query<
41-
(Entity, &mut Pose, &SiteParent<Entity>, &mut Visibility),
42-
With<InstanceMarker>,
43-
>,
40+
mut instances: Query<(Entity, &mut Pose, &mut Visibility), With<InstanceMarker>>,
4441
) {
4542
if let Some(ChangeCurrentScenario(scenario_entity)) = change_current_scenario.read().last() {
4643
// Used to build a scenario from root
@@ -79,14 +76,8 @@ pub fn update_current_scenario(
7976
};
8077

8178
// If active, assign parent to level, otherwise assign parent to site
82-
for (entity, mut pose, parent, mut visibility) in instances.iter_mut() {
79+
for (entity, mut pose, mut visibility) in instances.iter_mut() {
8380
if let Some(new_pose) = active_instances.get(&entity) {
84-
if let Some(parent_entity) = parent.0 {
85-
commands.entity(entity).set_parent(parent_entity);
86-
} else {
87-
commands.entity(entity).set_parent(current_site_entity);
88-
warn!("Model instance {:?} has no valid site parent", entity);
89-
}
9081
*pose = new_pose.clone();
9182
*visibility = Visibility::Inherited;
9283
} else {

rmf_site_format/src/legacy/building_map.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::{
77
Drawing as SiteDrawing, DrawingProperties, Fiducial as SiteFiducial, FiducialGroup,
88
FiducialMarker, Guided, Lane as SiteLane, LaneMarker, Level as SiteLevel, LevelElevation,
99
LevelProperties as SiteLevelProperties, ModelDescriptionBundle, ModelInstance, Motion,
10-
NameInSite, NameOfSite, NavGraph, Navigation, OrientationConstraint, PixelsPerMeter, Pose,
11-
PreferredSemiTransparency, RankingsInLevel, ReverseLane, Rotation, ScenarioBundle, Site,
10+
NameInSite, NameOfSite, NavGraph, Navigation, OrientationConstraint, Parented, PixelsPerMeter,
11+
Pose, PreferredSemiTransparency, RankingsInLevel, ReverseLane, Rotation, ScenarioBundle, Site,
1212
SiteProperties, Texture as SiteTexture, TextureGroup, UserCameraPose, DEFAULT_NAV_GRAPH_COLORS,
1313
};
1414
use glam::{DAffine2, DMat3, DQuat, DVec2, DVec3, EulerRot};
@@ -203,7 +203,7 @@ impl BuildingMap {
203203
let mut cartesian_fiducials: HashMap<u32, Vec<DVec2>> = HashMap::new();
204204

205205
let mut model_descriptions: BTreeMap<u32, ModelDescriptionBundle<u32>> = BTreeMap::new();
206-
let mut model_instances: BTreeMap<u32, ModelInstance<u32>> = BTreeMap::new();
206+
let mut model_instances: BTreeMap<u32, Parented<u32, ModelInstance<u32>>> = BTreeMap::new();
207207
let mut model_description_name_map = HashMap::<String, u32>::new();
208208
let mut scenarios: BTreeMap<u32, ScenarioBundle<u32>> = BTreeMap::new();
209209
let default_scenario_id = site_id.next().unwrap();

rmf_site_format/src/legacy/model.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
Affiliation, Angle, AssetSource, InstanceMarker, IsStatic, ModelDescriptionBundle,
3-
ModelInstance, ModelMarker, ModelProperty, NameInSite, Pose, Rotation, Scale, SiteParent,
3+
ModelInstance, ModelMarker, ModelProperty, NameInSite, Parented, Pose, Rotation, Scale,
44
};
55
use glam::DVec2;
66
use serde::{Deserialize, Serialize};
@@ -33,7 +33,7 @@ impl Model {
3333
&self,
3434
model_description_name_map: &mut HashMap<String, u32>,
3535
model_descriptions: &mut BTreeMap<u32, ModelDescriptionBundle<u32>>,
36-
model_instances: &mut BTreeMap<u32, ModelInstance<u32>>,
36+
model_instances: &mut BTreeMap<u32, Parented<u32, ModelInstance<u32>>>,
3737
site_id: &mut RangeFrom<u32>,
3838
level_id: u32,
3939
) -> (u32, Pose) {
@@ -64,13 +64,18 @@ impl Model {
6464
let model_instance = ModelInstance {
6565
name: NameInSite(self.instance_name.clone()),
6666
pose: pose.clone(),
67-
parent: SiteParent(Some(level_id)),
6867
description: Affiliation(Some(model_description_id)),
6968
marker: ModelMarker,
7069
instance_marker: InstanceMarker,
7170
..Default::default()
7271
};
73-
model_instances.insert(model_instance_id, model_instance);
72+
model_instances.insert(
73+
model_instance_id,
74+
Parented {
75+
parent: level_id,
76+
bundle: model_instance,
77+
},
78+
);
7479
(model_instance_id, pose)
7580
}
7681
}

rmf_site_format/src/misc.rs

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -472,38 +472,11 @@ pub struct PreviewableMarker;
472472
#[cfg_attr(feature = "bevy", derive(Component, Deref, DerefMut))]
473473
pub struct SiteID(pub u32);
474474

475-
/// This component is applied to an entity as a reference to its parent entity.
476-
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
477-
#[serde(transparent)]
478-
#[cfg_attr(feature = "bevy", derive(Component, Reflect))]
479-
pub struct SiteParent<T: RefTrait>(pub Option<T>);
480-
481-
impl<T: RefTrait> From<T> for SiteParent<T> {
482-
fn from(value: T) -> Self {
483-
SiteParent(Some(value))
484-
}
485-
}
486-
487-
impl<T: RefTrait> From<Option<T>> for SiteParent<T> {
488-
fn from(value: Option<T>) -> Self {
489-
SiteParent(value)
490-
}
491-
}
492-
493-
impl<T: RefTrait> Default for SiteParent<T> {
494-
fn default() -> Self {
495-
SiteParent(None)
496-
}
497-
}
498-
499-
impl<T: RefTrait> SiteParent<T> {
500-
pub fn convert<U: RefTrait>(&self, id_map: &HashMap<T, U>) -> Result<SiteParent<U>, T> {
501-
if let Some(x) = self.0 {
502-
Ok(SiteParent(Some(id_map.get(&x).ok_or(x)?.clone())))
503-
} else {
504-
Ok(SiteParent(None))
505-
}
506-
}
475+
/// Helper structure to serialize / deserialize entities with parents
476+
#[derive(Serialize, Deserialize, Clone, Debug)]
477+
pub struct Parented<P: RefTrait, T> {
478+
pub parent: P,
479+
pub bundle: T,
507480
}
508481

509482
/// The Pending component indicates that an element is not yet ready to be

rmf_site_format/src/model.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ impl<T: RefTrait> Default for ModelDescriptionBundle<T> {
158158
pub struct ModelInstance<T: RefTrait> {
159159
pub name: NameInSite,
160160
pub pose: Pose,
161-
pub parent: SiteParent<T>,
162161
pub description: Affiliation<T>,
163162
#[serde(skip)]
164163
pub marker: ModelMarker,
@@ -172,7 +171,6 @@ impl<T: RefTrait> Default for ModelInstance<T> {
172171
Self {
173172
name: NameInSite("<Unnamed>".to_string()),
174173
pose: Pose::default(),
175-
parent: SiteParent::default(),
176174
description: Affiliation::default(),
177175
marker: ModelMarker,
178176
instance_marker: InstanceMarker,
@@ -186,7 +184,6 @@ impl<T: RefTrait> ModelInstance<T> {
186184
Ok(ModelInstance {
187185
name: self.name.clone(),
188186
pose: self.pose.clone(),
189-
parent: self.parent.convert(id_map)?,
190187
description: self.description.convert(id_map)?,
191188
optional_properties: self.optional_properties.convert(id_map)?,
192189
..Default::default()

0 commit comments

Comments
 (0)