Skip to content

Commit

Permalink
仮のtransformer (x-y swap, to wgs84)、gpkg/geojsonのリファクタリング、その他 (#152)
Browse files Browse the repository at this point in the history
## 変更内容

### #153 

#### 仮のTransformerで「とりあえず」の全頂点の変換処理を行う
- x-y 入れかえ処理を入れておく
    - これにともない GeoJSON, GeoPackage ドライバ内での x-y 入れかえは除去する
- CRSを WGS 84 にしておく処理も追加 #155

#### Gpkg, GeoJSON 周りのリファクタリング
- `nusamai-geojson` に "indexed" でないふつうのジオメトリをGeoJSON
Valueに変換する関数を追加(tiling2d sink で使う)。
    - #154 もこのPRにマージ
- Gpkg のバイナリジオメトリの構築で、 `Vec<u8>` でなく `std::io::Write` trait
を使う(`Vec<u8>`はWrite)。一時的なVecの生成も除去。

### その他

- Gpkg sink が、インメモリSQLiteを扱えていない(`:memory:` というファイルを作ってしまう)問題を修正
- SipHash → aHash #156
- Iterator::chain 除去 #157
- Noop Sink, Serde Sinkを走らせるだけのテストに GeoJSONとGPKG も追加
- `nusamai_citygml::object::Geometries` の名前を `GeometryStore`
に変更(ジオメトリのつめあわせであることを多少分かりやすく)
- `GeometryStore` にCRSの情報をもたせられるようにしておく(仮)
- その他細かい調整など
  • Loading branch information
ciscorn authored Jan 9, 2024
1 parent 6f9e5b8 commit d4b184c
Show file tree
Hide file tree
Showing 46 changed files with 601 additions and 396 deletions.
2 changes: 1 addition & 1 deletion nusamai-3dtiles/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"

[dependencies]
serde = { version = "1.0.192", features = ["derive"] }
serde_json = { version = "1.0.108", features = ["float_roundtrip"] }
serde_json = { version = "1.0.108", features = ["indexmap", "float_roundtrip"] }
serde_repr = "0.1.17"
nusamai-gltf = { path = "../nusamai-gltf" }

Expand Down
4 changes: 3 additions & 1 deletion nusamai-citygml/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ default = ["serde"]
serde = ["dep:serde", "serde_json", "nusamai-geometry/serde"]

[dependencies]
ahash = "0.8.7"
chrono = { version = "0.4.31", features = ["serde"], default-features = false }
indexmap = { version = "2.1", features = ["serde"] }
macros = { path = "./macros" }
nusamai-geometry = { path = "../nusamai-geometry", features = ["serde"]}
nusamai-projection = { path = "../nusamai-projection"}
quick-xml = "0.31"
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = { version = "1.0.108", optional = true }
serde_json = { version = "1.0.108", features = ["indexmap"], optional = true }
thiserror = "1.0"
url = "2.5.0"
4 changes: 2 additions & 2 deletions nusamai-citygml/macros/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ fn generate_citygml_impl_for_struct(
typename: #typename.into(),
id: #id_value,
attributes: {
let mut attributes = ::nusamai_citygml::object::Map::new();
let mut attributes = ::nusamai_citygml::object::Map::default();
#(#into_object_stmts)*
attributes
},
Expand All @@ -255,7 +255,7 @@ fn generate_citygml_impl_for_struct(
::nusamai_citygml::object::Data {
typename: #typename.into(),
attributes: {
let mut attributes = ::nusamai_citygml::object::Map::new();
let mut attributes = ::nusamai_citygml::object::Map::default();
#(#into_object_stmts)*
attributes
},
Expand Down
21 changes: 14 additions & 7 deletions nusamai-citygml/src/geometry.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use nusamai_geometry::{MultiLineString, MultiPoint, MultiPolygon};
use nusamai_projection::crs::*;

#[derive(Debug, Clone, Copy)]
pub enum GeometryParseType {
Expand Down Expand Up @@ -35,20 +36,25 @@ pub struct GeometryRefEntry {

pub type GeometryRef = Vec<GeometryRefEntry>;

/// Geometries in a toplevel city object and its children.
/// Geometries in a city object and all its children.
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Debug, Default)]
pub struct Geometries {
pub struct GeometryStore {
/// EPSG code of the Coordinate Reference System (CRS)
pub epsg: EPSGCode,
/// Shared vertex buffer for all geometries
pub vertices: Vec<[f64; 3]>,
/// All polygons, referenced by `GeometryRef`
pub multipolygon: MultiPolygon<'static, 1, u32>,
/// All line-strings of , referenced by `GeometryRef`
pub multilinestring: MultiLineString<'static, 1, u32>,
/// All points, referenced by `GeometryRef`
pub multipoint: MultiPoint<'static, 1, u32>,
}

/// Store for collecting vertices and polygons from GML.
#[derive(Default)]
pub struct GeometryCollector {
pub vertices: indexmap::IndexSet<[u64; 3]>,
pub(crate) struct GeometryCollector {
pub vertices: indexmap::IndexSet<[u64; 3], ahash::RandomState>,
pub multipolygon: MultiPolygon<'static, 1, u32>,
pub multilinestring: MultiLineString<'static, 1, u32>,
pub multipoint: MultiPoint<'static, 1, u32>,
Expand All @@ -75,7 +81,7 @@ impl GeometryCollector {
}));
}

pub fn into_geometries(self) -> Geometries {
pub fn into_geometries(self) -> GeometryStore {
let mut vertices = Vec::with_capacity(self.vertices.len());
for vbits in &self.vertices {
vertices.push([
Expand All @@ -84,7 +90,8 @@ impl GeometryCollector {
f64::from_bits(vbits[2]),
]);
}
Geometries {
GeometryStore {
epsg: EPSG_JGD2011_GEOGRAPHIC_3D,
vertices,
multipolygon: self.multipolygon,
multilinestring: self.multilinestring,
Expand Down
86 changes: 39 additions & 47 deletions nusamai-citygml/src/object.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
//! Object representation of the city objects.
use std::borrow::Cow;

use crate::geometry::{self, GeometryRef};
use crate::values::{Code, Point, URI};
use crate::Measure;
use chrono::NaiveDate;
use serde::{Deserialize, Serialize};

pub type Map = indexmap::IndexMap<String, Value>;
pub type Map = indexmap::IndexMap<String, Value, ahash::RandomState>;

#[derive(Debug, Deserialize, Serialize)]
pub struct CityObject {
pub root: Value,
pub geometries: geometry::Geometries,
pub geometries: geometry::GeometryStore,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct Feature {
pub typename: String,
pub typename: Cow<'static, str>,
pub id: Option<String>,
pub attributes: Map,
pub geometries: Option<GeometryRef>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct Data {
pub typename: String,
pub typename: Cow<'static, str>,
pub attributes: Map,
}

Expand All @@ -51,7 +53,7 @@ impl Value {
pub fn to_attribute_json(&self) -> serde_json::Value {
use Value::*;
match &self {
String(s) => serde_json::Value::String(s.clone()),
String(s) => serde_json::Value::String(s.into()),
Code(c) => serde_json::Value::String(c.value().to_owned()),
Integer(i) => serde_json::Value::Number((*i).into()),
Double(d) => serde_json::Value::Number(serde_json::Number::from_f64(*d).unwrap()),
Expand All @@ -70,24 +72,25 @@ impl Value {
// }
}
Array(a) => serde_json::Value::Array(a.iter().map(Value::to_attribute_json).collect()),
Feature(feat) => serde_json::Value::from_iter(
feat.attributes
.iter()
.map(|(k, v)| (k.clone(), v.to_attribute_json()))
.chain(
std::iter::once(("type".into(), feat.typename.clone().into()))
.chain(std::iter::once(("id".into(), feat.id.clone().into()))),
),
),
Data(feat) => serde_json::Value::from_iter(
feat.attributes
.iter()
.map(|(k, v)| (k.clone(), v.to_attribute_json()))
.chain(std::iter::once((
"type".into(),
feat.typename.clone().into(),
))),
),
Feature(feat) => {
let mut m = serde_json::Map::from_iter(
feat.attributes
.iter()
.map(|(k, v)| (k.into(), v.to_attribute_json())),
);
m.insert("type".into(), feat.typename.clone().into());
m.insert("id".into(), feat.id.clone().into());
serde_json::Value::Object(m)
}
Data(data) => {
let mut m = serde_json::Map::from_iter(
data.attributes
.iter()
.map(|(k, v)| (k.into(), v.to_attribute_json())),
);
m.insert("type".into(), data.typename.clone().into());
serde_json::Value::Object(m)
}
}
}
}
Expand All @@ -101,42 +104,33 @@ mod tests {
#[test]
fn to_attribute_json() {
let obj = Value::String("test".into());
let value = obj.to_attribute_json();
assert_eq!(value, json!("test"));
assert_eq!(obj.to_attribute_json(), json!("test"));

let obj = Value::Code(Code::new("12345".into(), "12345".into()));
let value = obj.to_attribute_json();
assert_eq!(value, json!("12345"));
assert_eq!(obj.to_attribute_json(), json!("12345"));

let obj = Value::Integer(12345);
let value = obj.to_attribute_json();
assert_eq!(value, json!(12345));
assert_eq!(obj.to_attribute_json(), json!(12345));

let obj = Value::Double(1.0);
let value = obj.to_attribute_json();
assert_eq!(value, json!(1.0));
assert_eq!(obj.to_attribute_json(), json!(1.0));

let obj = Value::Measure(Measure { value: 1.0 });
let value = obj.to_attribute_json();
assert_eq!(value, json!(1.0));
assert_eq!(obj.to_attribute_json(), json!(1.0));

let obj = Value::Boolean(true);
let value = obj.to_attribute_json();
assert_eq!(value, json!(true));
assert_eq!(obj.to_attribute_json(), json!(true));

let obj = Value::URI(URI::new("http://example.com"));
let value = obj.to_attribute_json();
assert_eq!(value, json!("http://example.com"));
assert_eq!(obj.to_attribute_json(), json!("http://example.com"));

let obj = Value::Date(NaiveDate::from_ymd_opt(2020, 1, 1).unwrap());
let value = obj.to_attribute_json();
assert_eq!(value, json!("2020-01-01"));
assert_eq!(obj.to_attribute_json(), json!("2020-01-01"));

let obj = Value::Array(vec![Value::String("test".into()), Value::Integer(1)]);
let value = obj.to_attribute_json();
assert_eq!(value, json!(["test", 1]));
assert_eq!(obj.to_attribute_json(), json!(["test", 1]));

let mut attributes = Map::new();
let mut attributes = Map::default();
attributes.insert("String".into(), Value::String("test".into()));
attributes.insert("Integer".into(), Value::Integer(1));
let obj = Value::Feature(Feature {
Expand All @@ -145,9 +139,8 @@ mod tests {
attributes,
geometries: None,
});
let value = obj.to_attribute_json();
assert_eq!(
value,
obj.to_attribute_json(),
json! {
{
"type": "test",
Expand All @@ -158,16 +151,15 @@ mod tests {
}
);

let mut attributes = Map::new();
let mut attributes = Map::default();
attributes.insert("String".into(), Value::String("test".into()));
attributes.insert("Integer".into(), Value::Integer(1));
let obj = Value::Data(Data {
typename: "test".into(),
attributes,
});
let value = obj.to_attribute_json();
assert_eq!(
value,
obj.to_attribute_json(),
json! {
{
"type": "test",
Expand Down
5 changes: 3 additions & 2 deletions nusamai-citygml/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use url::Url;

use crate::codelist::{self, CodeResolver};
use crate::geometry::{
Geometries, GeometryCollector, GeometryParseType, GeometryRef, GeometryRefEntry, GeometryType,
GeometryCollector, GeometryParseType, GeometryRef, GeometryRefEntry, GeometryStore,
GeometryType,
};
use crate::namespace::{wellknown_prefix_from_nsres, GML31_NS};

Expand Down Expand Up @@ -294,7 +295,7 @@ impl<R: BufRead> SubTreeReader<'_, '_, R> {
&self.state.context
}

pub fn collect_geometries(&mut self) -> Geometries {
pub fn collect_geometries(&mut self) -> GeometryStore {
let collector = std::mem::take(&mut self.state.geometry_collector);
collector.into_geometries()
}
Expand Down
4 changes: 2 additions & 2 deletions nusamai-citygml/src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ impl CityGMLElement for GenericAttribute {
}

fn into_object(self) -> Option<Value> {
let mut map = object::Map::new();
let mut map = object::Map::default();
map.extend(
self.string_attrs
.into_iter()
Expand Down Expand Up @@ -413,7 +413,7 @@ impl CityGMLElement for GenericAttribute {
}),
);
Some(Value::Data(object::Data {
typename: "gen:genericAttribute".to_string(),
typename: "gen:genericAttribute".into(),
attributes: map,
}))
}
Expand Down
2 changes: 1 addition & 1 deletion nusamai-geojson/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ edition = "2021"
[dependencies]
geojson = "0.24.1"
nusamai-geometry = { path = "../nusamai-geometry" }
serde_json = "1.0.108"
serde_json = { version = "1.0.108", features = ["indexmap"] }
Loading

0 comments on commit d4b184c

Please sign in to comment.