Skip to content

Commit

Permalink
地下埋設物を対象とした平面直角座標系への対応 (#640)
Browse files Browse the repository at this point in the history
<!-- Close or Related Issues -->
Close #500 

### What I did(変更内容)
<!-- Please describe the motivation behind this PR and the changes it
introduces. -->
<!-- どのような変更をしますか? 目的は? -->

https://www.mlit.go.jp/plateaudocument/#toc9_06


PLATEAUのCityGMLデータにおいて、地下埋設物のジオメトリは「日本測地系2011における平面直角座標系と東京湾平均海面を基準とする標高の複合座標参照系」で記述されており、他のデータと異なっている

現在地下埋設物が配置されている竹芝モデルを対象とし、座標変換に対応した
(実際は実装の簡素化のため、平面直角座標系を6697に一旦変換してから、実装済みの変換を適用している)

各ジオメトリに紐付けられているEPSGコードをgml内から取得し適用している

### Notes(連絡事項)
<!-- If manual testing is required, please describe the procedure. -->
<!-- 手動での動作確認が必要なら手順を簡単に伝えてください。そのほか連絡事項など。 -->


- **(訂正済)** ~~現在はPLATEAUの仕様に基づき、ファイル名を第一ソースとして座標系のEPSGを取得している
(CityGMLの仕様には即していない)~~
  - ~~https://www.mlit.go.jp/plateaudocument/#toc9_07_04~~
  - ~~((下記はPRまでに行うfuture work))~~
  - ~~今後はgml内のタグのプロパティで取得することを視野に入れる~~
    - ~~実装はコメントアウトしている~~
    - ~~現在はこの点ではデータ側が不正確と考えられるため、応急処置としてこの方針としている~~
  • Loading branch information
TadaTeruki authored Sep 15, 2024
2 parents 9454ae4 + 911a97a commit 58eb3e2
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 147 deletions.
21 changes: 19 additions & 2 deletions nusamai-citygml/src/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use nusamai_projection::crs::*;

use crate::LocalId;

/// URI prefix for EPSG codes
const CRS_URI_EPSG_PREFIX: &str = "http://www.opengis.net/def/crs/EPSG/0/";

#[derive(Debug, Clone, Copy)]
pub enum GeometryParseType {
Geometry,
Expand Down Expand Up @@ -84,6 +87,7 @@ pub struct SurfaceSpan {
#[derive(Default)]
pub(crate) struct GeometryCollector {
pub vertices: indexmap::IndexSet<[u64; 3], ahash::RandomState>,
pub geometry_crs_uri: Option<String>,
pub multipolygon: MultiPolygon<'static, u32>,
pub multilinestring: MultiLineString<'static, u32>,
pub multipoint: MultiPoint<'static, u32>,
Expand Down Expand Up @@ -122,7 +126,7 @@ impl GeometryCollector {
}));
}

pub fn into_geometries(self) -> GeometryStore {
pub fn into_geometries(self, envelope_crs_uri: Option<String>) -> GeometryStore {
let mut vertices = Vec::with_capacity(self.vertices.len());
for vbits in &self.vertices {
vertices.push([
Expand All @@ -132,8 +136,21 @@ impl GeometryCollector {
]);
}

let crs_uri = envelope_crs_uri.unwrap_or(self.geometry_crs_uri.unwrap_or_default());

let epsg = if crs_uri.starts_with(CRS_URI_EPSG_PREFIX) {
if let Some(stripped) = crs_uri.strip_prefix(CRS_URI_EPSG_PREFIX) {
stripped.parse::<EpsgCode>().ok()
} else {
None
}
} else {
None
}
.unwrap_or(EPSG_JGD2011_GEOGRAPHIC_3D);

GeometryStore {
epsg: EPSG_JGD2011_GEOGRAPHIC_3D,
epsg,
vertices,
multipolygon: self.multipolygon,
multilinestring: self.multilinestring,
Expand Down
14 changes: 10 additions & 4 deletions nusamai-citygml/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,9 +319,9 @@ impl<'b, R: BufRead> SubTreeReader<'_, 'b, R> {
self.state.context.id_to_integer_id(id)
}

pub fn collect_geometries(&mut self) -> GeometryStore {
pub fn collect_geometries(&mut self, envelope_crs_uri: Option<String>) -> GeometryStore {
let collector = std::mem::take(&mut self.state.geometry_collector);
collector.into_geometries()
collector.into_geometries(envelope_crs_uri)
}

/// Expect a geometric attribute of CityGML
Expand Down Expand Up @@ -519,14 +519,18 @@ impl<'b, R: BufRead> SubTreeReader<'_, 'b, R> {
Ok(Event::Start(start)) => {
let (nsres, localname) = self.reader.resolve_element(start.name());
let poly_begin = self.state.geometry_collector.multipolygon.len();
let mut geometry_crs_uri = None;

// surface id
for attr in start.attributes().flatten() {
let (nsres, localname) = self.reader.resolve_attribute(attr.key);
// surface id
if nsres == Bound(GML31_NS) && localname.as_ref() == b"id" {
let id = String::from_utf8_lossy(attr.value.as_ref()).to_string();
surface_id = Some(self.state.context.id_to_integer_id(id));
break;
}
if localname.as_ref() == b"srsName" {
geometry_crs_uri =
Some(String::from_utf8_lossy(attr.value.as_ref()).to_string());
}
}

Expand Down Expand Up @@ -595,6 +599,8 @@ impl<'b, R: BufRead> SubTreeReader<'_, 'b, R> {
end: poly_end as u32,
});
}

self.state.geometry_collector.geometry_crs_uri = geometry_crs_uri;
}
}
Ok(Event::End(_)) => break,
Expand Down
9 changes: 7 additions & 2 deletions nusamai-citygml/src/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,13 +630,18 @@ impl<T: CityGmlElement + Default> CityGmlElement for Box<T> {
pub struct Envelope {
lower_corner: Point,
upper_corner: Point,
// TODO: crs_uri: Option<String>,
pub crs_uri: Option<String>,
}

impl CityGmlElement for Envelope {
#[inline(never)]
fn parse<R: BufRead>(&mut self, st: &mut SubTreeReader<R>) -> Result<(), ParseError> {
// TODO: parse CRS URI
st.parse_attributes(|k, v, _| {
if k == b"@srsName" {
self.crs_uri = Some(String::from_utf8_lossy(v).into());
}
Ok(())
})?;

st.parse_children(|st| {
match st.current_path() {
Expand Down
2 changes: 1 addition & 1 deletion nusamai-plateau/examples/parse_and_compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn example_toplevel_dispatcher<R: BufRead>(
b"core:cityObjectMember" => {
let mut cityobj: nusamai_plateau::models::TopLevelCityObject = Default::default();
cityobj.parse(st)?;
let geometries = st.collect_geometries();
let geometries = st.collect_geometries(None);

if let Some(root) = cityobj.into_object() {
let obj = self::TopLevelCityObject { root, geometries };
Expand Down
2 changes: 1 addition & 1 deletion nusamai-plateau/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn toplevel_dispatcher<R: BufRead>(
b"core:cityObjectMember" => {
let mut cityobj: TopLevelCityObject = Default::default();
cityobj.parse(st)?;
let geometries = st.collect_geometries();
let geometries = st.collect_geometries(None);
cityobjs.push(CityObject {
cityobj,
geometries,
Expand Down
1 change: 0 additions & 1 deletion nusamai/src/sink/obj/obj_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ fn write_obj(

mesh_data.push((feature_id, mesh, vertex_offset, uv_offset));
}

let mut obj_writer = BufWriter::new(File::create(obj_path)?);

writeln!(obj_writer, "mtllib {}.mtl", file_name)?;
Expand Down
4 changes: 2 additions & 2 deletions nusamai/src/source/citygml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ fn toplevel_dispatcher<R: BufRead>(
) -> Result<(), ParseError> {
let mut entities = Vec::new();
let mut global_appearances = AppearanceStore::default();
let mut envelope = Envelope::default();

st.parse_children(|st| {
if feedback.is_canceled() {
Expand All @@ -100,14 +101,13 @@ fn toplevel_dispatcher<R: BufRead>(
Ok(())
}
b"gml:boundedBy/gml:Envelope" => {
let mut envelope = Envelope::default();
envelope.parse(st)?;
Ok(())
}
b"core:cityObjectMember" => {
let mut cityobj: models::TopLevelCityObject = Default::default();
cityobj.parse(st)?;
let geometry_store = st.collect_geometries();
let geometry_store = st.collect_geometries(envelope.crs_uri.clone());

if let Some(root) = cityobj.into_object() {
let entity = Entity {
Expand Down
Loading

0 comments on commit 58eb3e2

Please sign in to comment.