Skip to content

Commit

Permalink
KML Sink:属性(第一階層) (#279)
Browse files Browse the repository at this point in the history
#278
のマージが前提です。

属性をKML地物に付与し、Google Earth上で表示可能なSchemaを付与。

ExtendedDataなので、機械的にも可読である
![スクリーンショット 2024-02-15 12 15
28](https://github.com/MIERUNE/nusamai/assets/83005951/2cd4b12a-b4a1-4f59-9d47-dac7b2adf11d)

<img width="1582" alt="スクリーンショット 2024-02-15 12 12 28"
src="https://github.com/MIERUNE/nusamai/assets/83005951/4ab95d92-705c-4642-b247-12992ca83265">

TODO:
- 属性の階層を処理していないので、文字列になっている


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit


- **新機能**
    - `KmlPolygon`の`Vec<KmlPolygon>`への変更
    - `polygon_to_kml_polygon_with_mapping`の導入
    - 既存の関数の更新
    - `CityObjects`から`GeoJSON`オブジェクトから`KML`オブジェクトへの切り替え
    - 新しいデータ構造の導入: `Element`, `Geometry`, `Polygon`, `SimpleData`
    - プロパティの処理と`KML`要素の生成ロジックの更新
    - スキーマデータエントリの作成
    - 拡張データの処理
    - `KML`出力の構造の調整
    - `.gitignore`に`data/*`と`*.kml`を追加して、これらのファイルとディレクトリをバージョン管理から除外
-
`.vscode/launch.json`にLLDBを使用してプロジェクト内の異なるコンポーネントとテストをデバッグするための様々な起動構成を設定
- 実行可能ファイル、ユニットテスト、統合テスト、ライブラリ、およびワークスペース内の複数のパッケージの例をデバッグするための構成のセットアップ

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
xinmiaooo authored Feb 15, 2024
2 parents 7360691 + 36f55f8 commit 9ce23fc
Showing 1 changed file with 105 additions and 6 deletions.
111 changes: 105 additions & 6 deletions nusamai/src/sink/kml/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use nusamai_plateau::Entity;
use rayon::prelude::*;

use kml::{
types::{Geometry, Kml, MultiGeometry, Placemark, Polygon as KmlPolygon},
types::{Element, Geometry, Kml, MultiGeometry, Placemark, Polygon as KmlPolygon, SimpleData},
KmlWriter,
};

Expand Down Expand Up @@ -80,6 +80,34 @@ impl DataSink for KmlSink {

let polygons = entity_to_kml_polygons(&parcel.entity);

let simple_data_items = property_to_schema_data_entries(
&entity_to_properties(&parcel.entity).unwrap_or_default(),
);
let schema_data = Element {
name: "SchemaData".to_string(),
attrs: {
let mut attrs = HashMap::new();
attrs.insert("schemaUrl".to_string(), "#Schema_1".to_string());
attrs
},
content: None,
children: simple_data_items
.into_iter()
.map(|simple_data| Element {
name: "SimpleData".to_string(),
attrs: simple_data.attrs,
content: Some(simple_data.value),
children: Vec::new(),
})
.collect::<Vec<_>>(),
};
let extended_data_entry = Element {
name: "ExtendedData".to_string(),
attrs: HashMap::new(),
content: None,
children: vec![schema_data],
};

let geoms = polygons.into_iter().map(Geometry::Polygon).collect();
let multi_geom = MultiGeometry {
geometries: geoms,
Expand All @@ -88,7 +116,10 @@ impl DataSink for KmlSink {

let placemark = Placemark {
geometry: Some(Geometry::MultiGeometry(multi_geom)),
..Default::default()
children: vec![extended_data_entry],
name: None,
description: None,
attrs: HashMap::new(),
};

if sender.send(placemark).is_err() {
Expand All @@ -98,10 +129,56 @@ impl DataSink for KmlSink {
})
},
|| {
// TODO?:QGIS attribute
let schema_element = Element {
name: "Schema".to_string(),
attrs: {
let mut attrs = HashMap::new();
attrs.insert("name".to_string(), "Schema_1".to_string());
attrs.insert("id".to_string(), "Schema_1".to_string());
attrs
},
content: None,
children: Vec::new(),
// children: {
// let mut children = Vec::new();
// children.push(Element {
// name: "SimpleField".to_string(),
// attrs: {
// let mut attrs = HashMap::new();
// attrs.insert("name".to_string(), "id".to_string());
// attrs.insert("type".to_string(), "string".to_string());
// attrs
// },
// content: None,
// children: Vec::new(),
// });
// children.push(Element {
// name: "SimpleField".to_string(),
// attrs: {
// let mut attrs = HashMap::new();
// attrs.insert("name".to_string(), "type".to_string());
// attrs.insert("type".to_string(), "string".to_string());
// attrs
// },
// content: None,
// children: Vec::new(),
// });
// children
// },
};

// let placemarks = receiver.into_iter();
let placemarks = receiver.into_iter().collect::<Vec<_>>();
let folder = Kml::Folder {

let kml_doc = Kml::Document {
attrs: HashMap::new(),
elements: placemarks.into_iter().map(Kml::Placemark).collect(),
elements: {
let mut elements = Vec::<Kml>::new();
elements.push(Kml::Element(schema_element));
elements.extend(placemarks.into_iter().map(Kml::Placemark));
elements
},
};

let mut file = File::create(&self.output_path).unwrap();
Expand All @@ -113,8 +190,9 @@ impl DataSink for KmlSink {
r#"<kml xmlns="http://www.opengis.net/kml/2.2">"#
)
.unwrap();

let mut kml_writer = KmlWriter::from_writer(&mut buf_writer);
let _ = kml_writer.write(&folder);
let _ = kml_writer.write(&kml_doc);
writeln!(buf_writer, "</kml>").unwrap();

Ok(())
Expand Down Expand Up @@ -144,8 +222,29 @@ fn extract_properties(value: &nusamai_citygml::object::Value) -> Option<geojson:
}
}

pub fn entity_to_properties(entity: &Entity) -> Option<geojson::JsonObject> {
extract_properties(&entity.root)
}

pub fn property_to_schema_data_entries(properties: &geojson::JsonObject) -> Vec<SimpleData> {
let mut simple_data_entries = Vec::new();

for (key, value) in properties.iter() {
let simpledata = SimpleData {
name: key.to_string(),
value: serde_json::to_string(value).unwrap(),
attrs: {
let mut attrs = HashMap::new();
attrs.insert("name".to_string(), key.to_string());
attrs
},
};
simple_data_entries.push(simpledata);
}
simple_data_entries
}

pub fn entity_to_kml_polygons(entity: &Entity) -> Vec<KmlPolygon> {
let _properties = extract_properties(&entity.root);
let geom_store = entity.geometry_store.read().unwrap();

let Value::Object(obj) = &entity.root else {
Expand Down

0 comments on commit 9ce23fc

Please sign in to comment.