Skip to content

Commit

Permalink
feat: implement FlattenTreeTransform and enhance Entity structure wit…
Browse files Browse the repository at this point in the history
…h optional id and typename (#28)
  • Loading branch information
miseyu authored Oct 18, 2024
1 parent f9883fc commit 61d694d
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 4 deletions.
14 changes: 14 additions & 0 deletions nusamai-citygml/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ pub enum Value {
}

impl Value {
pub fn id(&self) -> Option<&str> {
match self {
Value::Object(obj) => obj.stereotype.id(),
_ => None,
}
}

pub fn typename(&self) -> Option<&str> {
match self {
Value::Object(obj) => Some(obj.typename.as_ref()),
_ => None,
}
}

/// Traverses the attribute tree and apply the function to each object.
pub fn traverse_object_mut(&mut self, mut f: impl FnMut(&mut Object)) {
self.traverse_object_mut_inner(&mut f);
Expand Down
143 changes: 139 additions & 4 deletions nusamai-plateau/src/entity.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::sync::{Arc, RwLock};

use hashbrown::HashSet;
use nusamai_citygml::object::Map;
use nusamai_citygml::{geometry::GeometryStore, object::Value, GeometryRefs};
use nusamai_citygml::{
object::{Object, ObjectStereotype},
Expand All @@ -13,11 +14,9 @@ use crate::appearance::AppearanceStore;
#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
pub struct Entity {
/// GML id
pub id: String,
/// Description
pub description: Option<String>,
pub id: Option<String>,
/// City object type
pub name: String,
pub typename: Option<String>,
/// Attribute tree
pub root: Value,
/// Base url of the entity
Expand Down Expand Up @@ -80,3 +79,139 @@ impl GeometricMergedownTransform {
is_feature
}
}

pub struct FlattenTreeTransform;

enum Parent {
Feature { id: String, typename: String },
Data { typename: String }, // Data stereotype does not have an id
Object { id: String, typename: String },
}

impl FlattenTreeTransform {
pub fn transform(entity: Entity) -> Vec<Entity> {
let geom_store = entity.geometry_store;
let appearance_store = entity.appearance_store;
let mut out = Vec::new();
Self::flatten_entity(
entity.root,
&geom_store,
&appearance_store,
&entity.bounded_by,
&mut out,
&None,
);
out
}

fn flatten_entity(
value: Value,
geom_store: &Arc<RwLock<GeometryStore>>,
appearance_store: &Arc<RwLock<AppearanceStore>>,
bounded_by: &Vec<BoundedBy>,
out: &mut Vec<Entity>,
parent: &Option<Parent>,
) -> Option<Value> {
let id = value.id().map(|v| v.to_string());
let typename = value.typename().map(|v| v.to_string());
match value {
Value::Object(mut obj) => {
let new_parent = match &obj.stereotype {
ObjectStereotype::Feature { id, .. } => Some(Parent::Feature {
id: id.to_string(),
typename: obj.typename.to_string(),
}),
ObjectStereotype::Data => Some(Parent::Data {
typename: obj.typename.to_string(),
}),
ObjectStereotype::Object { id, .. } => Some(Parent::Object {
id: id.to_string(),
typename: obj.typename.to_string(),
}),
};
// Attributes
let mut new_attribs = Map::default();
for (key, value) in obj.attributes.drain(..) {
if let Some(v) = Self::flatten_entity(
value,
geom_store,
appearance_store,
bounded_by,
out,
&new_parent,
) {
new_attribs.insert(key, v);
}
}
obj.attributes = new_attribs;

if Self::is_flatten_target(&obj) {
// set parent id and type to attributes
if let Some(parent) = parent {
match parent {
Parent::Feature { id, typename } => {
obj.attributes
.insert("parentId".to_string(), Value::String(id.to_string()));
obj.attributes.insert(
"parentType".to_string(),
Value::String(typename.to_string()),
);
}
Parent::Data { typename } => {
obj.attributes.insert(
"parentType".to_string(),
Value::String(typename.to_string()),
);
}
Parent::Object { id, typename } => {
obj.attributes
.insert("parentId".to_string(), Value::String(id.to_string()));
obj.attributes.insert(
"parentType".to_string(),
Value::String(typename.to_string()),
);
}
}
}
out.push(Entity {
id,
typename,
root: Value::Object(obj),
base_url: url::Url::parse("file:///dummy").expect("should be valid"),
geometry_store: geom_store.clone(),
appearance_store: appearance_store.clone(),
bounded_by: bounded_by.clone(),
});
return None;
}

Some(Value::Object(obj))
}
Value::Array(mut arr) => {
let mut new_arr = Vec::with_capacity(arr.len());
for value in arr.drain(..) {
if let Some(v) = Self::flatten_entity(
value,
geom_store,
appearance_store,
bounded_by,
out,
parent,
) {
new_arr.push(v)
}
}
if new_arr.is_empty() {
None
} else {
Some(Value::Array(new_arr))
}
}
_ => Some(value),
}
}

fn is_flatten_target(obj: &Object) -> bool {
obj.typename != "gen:genericAttribute"
}
}
1 change: 1 addition & 0 deletions nusamai-plateau/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ mod entity;
pub mod models;
pub use entity::BoundedBy;
pub use entity::Entity;
pub use entity::FlattenTreeTransform;
pub use entity::GeometricMergedownTransform;

0 comments on commit 61d694d

Please sign in to comment.