Skip to content

Commit

Permalink
Add simple json saving / loading
Browse files Browse the repository at this point in the history
Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
  • Loading branch information
luca-della-vedova committed Apr 3, 2024
1 parent 0cd5d19 commit 1c1380e
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 29 deletions.
45 changes: 26 additions & 19 deletions rmf_site_editor/src/site/save.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,9 @@ pub fn save_site(world: &mut World) {
if path_str.ends_with(".building.yaml") {
warn!("Detected old file format, converting to new format");
new_path = path_str.replace(".building.yaml", ".site.ron").into();
} else if !path_str.ends_with("site.ron") {
} else if path_str.ends_with(".site.json") {
// Noop
} else if !path_str.ends_with(".site.ron") {
info!("Appending .site.ron to {}", new_path.display());
new_path = new_path.with_extension("site.ron");
}
Expand All @@ -1239,27 +1241,34 @@ pub fn save_site(world: &mut World) {
}
};

match site.to_writer(f) {
Ok(()) => {
info!("Save successful");
if new_path.extension().is_some_and(|e| e == "json") {
match site.to_writer_json(f) {
Ok(()) => {
info!("Save successful");
}
Err(err) => {
if let Some(old_default_path) = old_default_path {
world.entity_mut(save_event.site).insert(old_default_path);
}
error!("Save failed: {err}");
}
}
Err(err) => {
if let Some(old_default_path) = old_default_path {
world.entity_mut(save_event.site).insert(old_default_path);
} else {
match site.to_writer(f) {
Ok(()) => {
info!("Save successful");
}
Err(err) => {
if let Some(old_default_path) = old_default_path {
world.entity_mut(save_event.site).insert(old_default_path);
}
error!("Save failed: {err}");
}
error!("Save failed: {err}");
}
}
}
ExportFormat::Sdf => {
// TODO(luca) reduce code duplication with default exporting
if path_str.ends_with(".building.yaml") {
warn!("Detected old file format, converting to new format");
new_path = path_str.replace(".building.yaml", ".world").into();
} else if !path_str.ends_with("site.ron") {
info!("Appending .world to {}", new_path.display());
new_path = new_path.with_extension("world");
}
info!("Saving to {}", new_path.display());
let parent_folder = new_path.parent().unwrap();
if !parent_folder.exists() {
Expand All @@ -1280,7 +1289,7 @@ pub fn save_site(world: &mut World) {
meshes_dir.push("meshes");
std::fs::create_dir(&meshes_dir).ok();
if let Err(e) = collect_site_meshes(world, save_event.site, &meshes_dir) {
error!("Unable to collect site meshes {e}");
error!("Unable to collect site meshes: {e}");
}

migrate_relative_paths(save_event.site, &new_path, world);
Expand All @@ -1296,9 +1305,7 @@ pub fn save_site(world: &mut World) {
let sdf = match site.to_sdf() {
Ok(sdf) => sdf,
Err(err) => {
//error!("Unable to convert site to sdf: {err}");
error!("Unable to convert site to sdf");
dbg!(err);
error!("Unable to convert site to sdf: {err}");
continue;
}
};
Expand Down
27 changes: 24 additions & 3 deletions rmf_site_editor/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ pub enum LoadWorkspace {
#[derive(Clone)]
pub enum WorkspaceData {
LegacyBuilding(Vec<u8>),
Site(Vec<u8>),
RonSite(Vec<u8>),
JsonSite(Vec<u8>),
Workcell(Vec<u8>),
WorkcellUrdf(Vec<u8>),
}
Expand All @@ -72,7 +73,9 @@ impl WorkspaceData {
if filename.ends_with(".building.yaml") {
Some(WorkspaceData::LegacyBuilding(data))
} else if filename.ends_with("site.ron") {
Some(WorkspaceData::Site(data))
Some(WorkspaceData::RonSite(data))
} else if filename.ends_with("site.json") {
Some(WorkspaceData::JsonSite(data))
} else if filename.ends_with("workcell.json") {
Some(WorkspaceData::Workcell(data))
} else if filename.ends_with("urdf") {
Expand Down Expand Up @@ -344,7 +347,7 @@ fn workspace_file_load_complete(
}
}
}
WorkspaceData::Site(data) => {
WorkspaceData::RonSite(data) => {
info!("Opening site file");
match Site::from_bytes(&data) {
Ok(site) => {
Expand All @@ -362,6 +365,24 @@ fn workspace_file_load_complete(
}
}
}
WorkspaceData::JsonSite(data) => {
info!("Opening site file");
match Site::from_json_bytes(&data) {
Ok(site) => {
// Switch state
app_state.set(AppState::SiteEditor);
load_site.send(LoadSite {
site,
focus: true,
default_file,
});
interaction_state.set(InteractionState::Enable);
}
Err(err) => {
error!("Failed loading site {:?}", err);
}
}
}
WorkspaceData::Workcell(data) => {
info!("Opening workcell file");
match Workcell::from_bytes(&data) {
Expand Down
13 changes: 7 additions & 6 deletions rmf_site_format/src/sdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,24 @@ use glam::Vec3;
use once_cell::sync::Lazy;
use sdformat_rs::*;
use std::collections::BTreeMap;
use thiserror::Error;

static WORLD_TEMPLATE: Lazy<SdfRoot> = Lazy::new(|| {
yaserde::de::from_str(include_str!("templates/gz_world.sdf"))
.expect("Failed deserializing template")
});

#[derive(Debug)]
#[derive(Debug, Error)]
pub enum SdfConversionError {
/// An asset that can't be converted to an sdf world was found.
#[error("An asset that can't be converted to an sdf world was found")]
UnsupportedAssetType,
/// Entity referenced a non existing anchor.
#[error("Entity [{0}] referenced a non existing anchor")]
BrokenAnchorReference(u32),
/// Entity referenced a non existing level.
#[error("Entity [{0}] referenced a non existing level")]
BrokenLevelReference(u32),
/// Parsing of a lift cabin failed
#[error("Parsing lift cabin for lift [{0}] failed")]
LiftParsingError(String),
/// A lift had no initial level where it could be spawned
#[error("Lift [{0}] had no initial level where it could be spawned")]
MissingInitialLevel(String),
}

Expand Down
20 changes: 19 additions & 1 deletion rmf_site_format/src/site.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ fn default_style_config() -> Style {
}

impl Site {
// TODO(luca) the functions below assume that we only serialize to ron, now that we are adding
// json these should probably be renamed or made to accept an enum for the format?
pub fn to_writer<W: io::Write>(&self, writer: W) -> ron::Result<()> {
ron::ser::to_writer_pretty(writer, self, default_style_config())
}
Expand All @@ -170,6 +172,14 @@ impl Site {
ron::ser::to_string_pretty(self, style)
}

pub fn to_writer_json<W: io::Write>(&self, writer: W) -> serde_json::Result<()> {
serde_json::to_writer_pretty(writer, self)
}

pub fn from_json_bytes(s: &[u8]) -> serde_json::Result<Self> {
serde_json::from_slice(s)
}

pub fn from_reader<R: io::Read>(reader: R) -> ron::error::SpannedResult<Self> {
// TODO(MXG): Validate the parsed data, e.g. make sure anchor pairs
// belong to the same level.
Expand Down Expand Up @@ -204,10 +214,18 @@ mod tests {
use crate::legacy::building_map::BuildingMap;

#[test]
fn serde_roundtrip() {
fn ron_roundtrip() {
let data = std::fs::read("../assets/demo_maps/office.building.yaml").unwrap();
let map = BuildingMap::from_bytes(&data).unwrap();
let site_string = map.to_site().unwrap().to_string().unwrap();
Site::from_str(&site_string).unwrap();
}

#[test]
fn json_roundtrip() {
let data = std::fs::read("../assets/demo_maps/office.building.yaml").unwrap();
let map = BuildingMap::from_bytes(&data).unwrap();
let site_string = map.to_site().unwrap().to_json().unwrap();
Site::from_json_str(&site_string).unwrap();
}
}

0 comments on commit 1c1380e

Please sign in to comment.