Skip to content

Commit

Permalink
feat: euclidean distance between h3 centroids
Browse files Browse the repository at this point in the history
  • Loading branch information
sunng87 committed Oct 31, 2024
1 parent 24dc675 commit 441e47f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/common/function/src/scalars/geo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ impl GeoFunctions {

// h3 measurement
registry.register(Arc::new(h3::H3CellDistanceSphereKm));
registry.register(Arc::new(h3::H3CellDistanceEuclideanDegree));

// s2
registry.register(Arc::new(s2::S2LatLngToCell));
Expand Down
70 changes: 70 additions & 0 deletions src/common/function/src/scalars/geo/h3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,62 @@ impl Function for H3CellDistanceSphereKm {
}
}

/// Get Euclidean distance of two cell centroid
#[derive(Clone, Debug, Default, Display)]
#[display("{}", self.name())]
pub struct H3CellDistanceEuclideanDegree;

impl H3CellDistanceEuclideanDegree {
fn distance(centroid_this: LatLng, centroid_that: LatLng) -> f64 {
((centroid_this.lat() - centroid_that.lat()).powi(2)
+ (centroid_this.lng() - centroid_that.lng()).powi(2))
.sqrt()
}
}

impl Function for H3CellDistanceEuclideanDegree {
fn name(&self) -> &str {
"h3_distance_degree"
}
fn return_type(&self, _input_types: &[ConcreteDataType]) -> Result<ConcreteDataType> {
Ok(ConcreteDataType::float64_datatype())
}

fn signature(&self) -> Signature {
signature_of_double_cells()
}

fn eval(&self, _func_ctx: FunctionContext, columns: &[VectorRef]) -> Result<VectorRef> {
ensure_columns_n!(columns, 2);

let cell_this_vec = &columns[0];
let cell_that_vec = &columns[1];
let size = cell_this_vec.len();

let mut results = Float64VectorBuilder::with_capacity(size);

for i in 0..size {
let result = match (
cell_from_value(cell_this_vec.get(i))?,
cell_from_value(cell_that_vec.get(i))?,
) {
(Some(cell_this), Some(cell_that)) => {
let centroid_this = LatLng::from(cell_this);
let centroid_that = LatLng::from(cell_that);

let dist = Self::distance(centroid_this, centroid_that);
Some(dist)
}
_ => None,
};

results.push(result);
}

Ok(results.to_vector())
}
}

fn value_to_resolution(v: Value) -> Result<Resolution> {
let r = match v {
Value::Int8(v) => v as u8,
Expand Down Expand Up @@ -1302,3 +1358,17 @@ fn cells_from_value(v: Value) -> Result<Vec<CellIndex>> {
_ => Ok(vec![]),
}
}

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

#[test]
fn test_h3_euclidean_distance() {
let point_this = LatLng::new(42.3521, -72.1235).expect("incorrect lat lng");
let point_that = LatLng::new(42.45, -72.1260).expect("incorrect lat lng");

let dist = H3CellDistanceEuclideanDegree::distance(point_this, point_that);
assert_eq!(dist, 0.09793191512474639);
}
}
15 changes: 8 additions & 7 deletions tests/cases/standalone/common/function/geo.result

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions tests/cases/standalone/common/function/geo.sql
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ SELECT
h3_grid_distance(cell1, cell2) AS distance,
h3_grid_path_cells(cell1, cell2) AS path_cells,
h3_distance_sphere_km(cell1, cell2) AS sphere_distance,
h3_distance_degree(cell1, cell2) AS euclidean_distance,
FROM
(
SELECT
h3_latlng_to_cell(37.76938, -122.3889, 8::UInt64) AS cell1,
h3_latlng_to_cell(39.634, -104.999, 8::UInt64) AS cell2
h3_string_to_cell('86283082fffffff') AS cell1,
h3_string_to_cell('86283470fffffff') AS cell2
);

SELECT
Expand Down

0 comments on commit 441e47f

Please sign in to comment.