Skip to content

Commit

Permalink
gpkg: Bboxのリファクタリング (#274)
Browse files Browse the repository at this point in the history
「小さいプルリク」ということで、この単位で投げさせてください!

動作は変わっておらず、 `bbox.rs` にまとめて切り出した、というものです。

- Gpkgでは、レイヤーに「バウンディングボックス(bbox)」情報を設定できる
- 各オブジェクトごとに、範囲を確認して、全オブジェクトでのbboxを更新

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

## Summary by CodeRabbit

- **機能改善**
-
バウンディングボックスの操作と計算のための新しいモジュールと構造体を追加しました。これにより、バウンディングボックスの更新がより効率的になります。

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
sorami authored Feb 14, 2024
1 parent 44bea54 commit f6d776e
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 43 deletions.
8 changes: 3 additions & 5 deletions nusamai-gpkg/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,11 @@ impl GpkgHandler {
Ok(())
}

/// Update the bounding box of a table (min_x, min_y, max_x, max_y)
pub async fn update_bbox(
&self,
table_name: String,
min_x: f64,
min_y: f64,
max_x: f64,
max_y: f64,
(min_x, min_y, max_x, max_y): (f64, f64, f64, f64),
) -> Result<(), GpkgError> {
sqlx::query("UPDATE gpkg_contents SET min_x = ?, min_y = ?, max_x = ?, max_y = ? WHERE table_name = ?;"
)
Expand Down Expand Up @@ -278,7 +276,7 @@ mod tests {
assert_eq!(max_y, 45.55722222);

handler
.update_bbox("mpoly3d".into(), -111.0, 222.0, 333.0, -444.0)
.update_bbox("mpoly3d".into(), (-111.0, 222.0, 333.0, -444.0))
.await
.unwrap();
let (min_x, min_y, max_x, max_y) = handler.bbox("mpoly3d".into()).await.unwrap();
Expand Down
85 changes: 85 additions & 0 deletions nusamai/src/sink/gpkg/bbox.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/// Bounding box
pub struct Bbox {
min_x: f64,
min_y: f64,
max_x: f64,
max_y: f64,
}

impl Default for Bbox {
fn default() -> Self {
Bbox {
min_x: f64::MAX,
min_y: f64::MAX,
max_x: f64::MIN,
max_y: f64::MIN,
}
}
}

impl Bbox {
/// To a tuple (min_x, min_y, max_x, max_y)
pub fn to_tuple(&self) -> (f64, f64, f64, f64) {
(self.min_x, self.min_y, self.max_x, self.max_y)
}

/// Update the bounding box with a new point and return the updated bounding box
pub fn updated_with(&mut self, x: f64, y: f64) -> Self {
Bbox {
min_x: self.min_x.min(x),
min_y: self.min_y.min(y),
max_x: self.max_x.max(x),
max_y: self.max_y.max(y),
}
}

/// Merge with another bounding box and return the merged bounding box
pub fn merged_with(&self, other: &Bbox) -> Bbox {
Bbox {
min_x: self.min_x.min(other.min_x),
min_y: self.min_y.min(other.min_y),
max_x: self.max_x.max(other.max_x),
max_y: self.max_y.max(other.max_y),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_updated_with() {
let mut bbox = Bbox::default();
bbox = bbox.updated_with(0.5, 0.5);
assert_eq!(bbox.to_tuple(), (0.5, 0.5, 0.5, 0.5));

bbox = bbox.updated_with(1.0, 1.0);
assert_eq!(bbox.to_tuple(), (0.5, 0.5, 1.0, 1.0));

bbox = bbox.updated_with(-1.0, -1.0);
assert_eq!(bbox.to_tuple(), (-1.0, -1.0, 1.0, 1.0));
}

#[test]
fn test_merged_with() {
let bbox1 = Bbox {
min_x: 0.0,
min_y: 0.0,
max_x: 1.0,
max_y: 1.0,
};
let bbox2 = Bbox {
min_x: 1.0,
min_y: 1.0,
max_x: 2.0,
max_y: 2.0,
};

let merged = bbox1.merged_with(&bbox2);
assert_eq!(merged.min_x, 0.0);
assert_eq!(merged.min_y, 0.0);
assert_eq!(merged.max_x, 2.0);
assert_eq!(merged.max_y, 2.0);
}
}
47 changes: 9 additions & 38 deletions nusamai/src/sink/gpkg/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! GeoPackage sink
mod bbox;

use std::path::PathBuf;
use url::Url;

Expand All @@ -12,6 +14,7 @@ use crate::parameters::*;
use crate::pipeline::{Feedback, PipelineError, Receiver, Result};
use crate::sink::{DataSink, DataSinkProvider, SinkInfo};
use crate::{get_parameter_value, transformer};
use bbox::Bbox;

use nusamai_citygml::object::{Object, ObjectStereotype, Value};
use nusamai_citygml::schema::{Schema, TypeDef, TypeRef};
Expand Down Expand Up @@ -82,12 +85,7 @@ impl GpkgSink {
handler.add_columns(attribute_columns).await.unwrap();

// global bounding box, to be updated per entity
let mut global_bbox = Bbox {
min_x: f64::MAX,
min_y: f64::MAX,
max_x: f64::MIN,
max_y: f64::MIN,
};
let mut global_bbox: Bbox = Default::default();

let (sender, mut receiver) = tokio::sync::mpsc::channel(100);

Expand Down Expand Up @@ -164,21 +162,12 @@ impl GpkgSink {
tx.insert_feature(&gpkg_bin, &attributes).await.unwrap();

// track the global bounding box values
global_bbox.min_x = global_bbox.min_x.min(bbox.min_x);
global_bbox.min_y = global_bbox.min_y.min(bbox.min_y);
global_bbox.max_x = global_bbox.max_x.max(bbox.max_x);
global_bbox.max_y = global_bbox.max_y.max(bbox.max_y);
global_bbox = global_bbox.merged_with(&bbox);
}
tx.commit().await.unwrap();

handler
.update_bbox(
"mpoly3d".into(),
global_bbox.min_x,
global_bbox.min_y,
global_bbox.max_x,
global_bbox.max_y,
)
.update_bbox("mpoly3d".into(), global_bbox.to_tuple())
.await
.unwrap();

Expand Down Expand Up @@ -345,30 +334,15 @@ fn schema_to_columns(schema: &Schema) -> IndexMap<String, String> {
attribute_columns
}

struct Bbox {
min_x: f64,
min_y: f64,
max_x: f64,
max_y: f64,
}

// Get Bounding box of a MultiPolygon
fn get_indexed_multipolygon_bbox(vertices: &[[f64; 3]], mpoly: &MultiPolygon<1, u32>) -> Bbox {
let mut bbox = Bbox {
min_x: f64::MAX,
min_y: f64::MAX,
max_x: f64::MIN,
max_y: f64::MIN,
};
let mut bbox: Bbox = Default::default();

for poly in mpoly {
for linestring in &poly.exterior() {
for point_idx in linestring.iter() {
let [x, y, _z] = vertices[*point_idx as usize];
bbox.min_x = bbox.min_x.min(x);
bbox.min_y = bbox.min_y.min(y);
bbox.max_x = bbox.max_x.max(x);
bbox.max_y = bbox.max_y.max(y);
bbox = bbox.updated_with(x, y);
}
}
}
Expand Down Expand Up @@ -400,9 +374,6 @@ mod tests {

let bbox = get_indexed_multipolygon_bbox(&geometries.vertices, &geometries.multipolygon);

assert_eq!(bbox.min_x, 10.);
assert_eq!(bbox.min_y, 100.);
assert_eq!(bbox.max_x, 20.);
assert_eq!(bbox.max_y, 200.);
assert_eq!(bbox.to_tuple(), (10., 100., 20., 200.));
}
}

0 comments on commit f6d776e

Please sign in to comment.