Skip to content

Commit b6a39c6

Browse files
fix: review comments && column to column distance
1 parent 53026fa commit b6a39c6

6 files changed

Lines changed: 142 additions & 98 deletions

File tree

vortex-geo/src/extension/coordinate.rs

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4-
//! The coordinate building block shared by geometry extension types: the `Struct<x, y, [z], [m]>`
5-
//! storage, its [`Dimension`], the decoded [`Coordinate`] value, and the readers that decode it.
6-
//! `z`/`m` are optional, so all four GeoArrow dimensions share one value type — no third-party deps.
4+
//! Coordinate building blocks for geometry extension types: the `Struct<x, y, [z], [m]>` storage,
5+
//! its [`Dimension`], and the decoded [`Coordinate`] value.
76
87
use std::fmt::Display;
98
use std::fmt::Formatter;
109

1110
use vortex_array::ArrayRef;
12-
use vortex_array::Canonical;
1311
use vortex_array::ExecutionCtx;
12+
use vortex_array::arrays::ExtensionArray;
1413
use vortex_array::arrays::PrimitiveArray;
14+
use vortex_array::arrays::StructArray;
1515
use vortex_array::arrays::extension::ExtensionArrayExt;
1616
use vortex_array::arrays::struct_::StructArrayExt;
1717
use vortex_array::dtype::DType;
18-
use vortex_array::dtype::FieldNames;
1918
use vortex_array::dtype::Nullability;
2019
use vortex_array::dtype::PType;
21-
use vortex_array::dtype::StructFields;
2220
use vortex_array::scalar::Scalar;
2321
use vortex_error::VortexResult;
2422
use vortex_error::vortex_bail;
2523
use vortex_error::vortex_err;
2624

2725
/// Coordinate dimensions, matching GeoArrow. Field order is fixed: x, y, then z before m.
2826
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29-
pub enum Dimension {
27+
pub(crate) enum Dimension {
3028
/// 2D: `x`, `y`.
3129
Xy,
3230
/// 3D with elevation: `x`, `y`, `z`.
@@ -38,18 +36,8 @@ pub enum Dimension {
3836
}
3937

4038
impl Dimension {
41-
/// The coordinate struct field names for this dimension, in GeoArrow order.
42-
pub fn field_names(self) -> &'static [&'static str] {
43-
match self {
44-
Dimension::Xy => &["x", "y"],
45-
Dimension::Xyz => &["x", "y", "z"],
46-
Dimension::Xym => &["x", "y", "m"],
47-
Dimension::Xyzm => &["x", "y", "z", "m"],
48-
}
49-
}
50-
5139
/// Recover the dimension from a coordinate's field names, in GeoArrow order.
52-
pub fn from_field_names(names: &[&str]) -> VortexResult<Dimension> {
40+
pub(crate) fn from_field_names(names: &[&str]) -> VortexResult<Dimension> {
5341
Ok(match names {
5442
["x", "y"] => Dimension::Xy,
5543
["x", "y", "z"] => Dimension::Xyz,
@@ -61,16 +49,19 @@ impl Dimension {
6149
}
6250

6351
/// A decoded coordinate. `z`/`m` are `Some` iff the storage dimension includes them.
52+
///
53+
/// This is the native value produced when unpacking a [`Point`](crate::extension::Point) scalar;
54+
/// the rest of the coordinate machinery is crate-internal.
6455
#[derive(Debug, Clone, Copy, PartialEq)]
6556
pub struct Coordinate {
6657
/// The x (longitude/easting) ordinate.
67-
pub x: f64,
58+
x: f64,
6859
/// The y (latitude/northing) ordinate.
69-
pub y: f64,
60+
y: f64,
7061
/// The optional z (elevation) ordinate.
71-
pub z: Option<f64>,
62+
z: Option<f64>,
7263
/// The optional m (measure) ordinate.
73-
pub m: Option<f64>,
64+
m: Option<f64>,
7465
}
7566

7667
impl Coordinate {
@@ -83,6 +74,26 @@ impl Coordinate {
8374
m: None,
8475
}
8576
}
77+
78+
/// The x (longitude/easting) ordinate.
79+
pub fn x(&self) -> f64 {
80+
self.x
81+
}
82+
83+
/// The y (latitude/northing) ordinate.
84+
pub fn y(&self) -> f64 {
85+
self.y
86+
}
87+
88+
/// The z (elevation) ordinate, if the dimension includes one.
89+
pub fn z(&self) -> Option<f64> {
90+
self.z
91+
}
92+
93+
/// The m (measure) ordinate, if the dimension includes one.
94+
pub fn m(&self) -> Option<f64> {
95+
self.m
96+
}
8697
}
8798

8899
impl Display for Coordinate {
@@ -91,23 +102,9 @@ impl Display for Coordinate {
91102
}
92103
}
93104

94-
/// The coordinate storage dtype for a dimension: `Struct<x, y, [z], [m]>` of non-nullable f64.
95-
pub fn coordinate_dtype(dim: Dimension, nullability: Nullability) -> DType {
96-
let names = dim.field_names();
97-
let fields = std::iter::repeat_n(
98-
DType::Primitive(PType::F64, Nullability::NonNullable),
99-
names.len(),
100-
)
101-
.collect::<Vec<_>>();
102-
DType::Struct(
103-
StructFields::new(FieldNames::from(names), fields),
104-
nullability,
105-
)
106-
}
107-
108105
/// Validate that `dtype` is a coordinate struct of non-nullable `f64` fields, returning its
109106
/// [`Dimension`]. Any of the four GeoArrow dimensions validates.
110-
pub fn coordinate_dimension(dtype: &DType) -> VortexResult<Dimension> {
107+
pub(crate) fn coordinate_dimension(dtype: &DType) -> VortexResult<Dimension> {
111108
let DType::Struct(fields, _) = dtype else {
112109
vortex_bail!("coordinate storage must be a Struct, was {dtype}");
113110
};
@@ -153,36 +150,32 @@ pub(crate) fn coordinate_from_struct(scalar: &Scalar) -> VortexResult<Coordinate
153150

154151
/// Decode a [`Coordinate`] from an extension-typed point scalar (unwrapped to its coordinate
155152
/// storage) or a bare coordinate `Struct` scalar. The per-row decode used by the distance fns.
156-
pub fn coordinate_from_scalar(scalar: &Scalar) -> VortexResult<Coordinate> {
153+
pub(crate) fn coordinate_from_scalar(scalar: &Scalar) -> VortexResult<Coordinate> {
157154
match scalar.dtype().as_extension_opt() {
158155
Some(_) => coordinate_from_struct(&scalar.as_extension().to_storage_scalar()),
159156
None => coordinate_from_struct(scalar),
160157
}
161158
}
162159

163160
/// Canonicalize a point column once and return its flat `x`/`y` `f64` columns. The bulk counterpart
164-
/// to [`coordinate_from_scalar`]; distance is planar, so `z`/`m` are ignored.
161+
/// to [`coordinate_from_scalar`]; distances use only `x`/`y`, so `z`/`m` are ignored.
165162
pub(crate) fn xy_columns(
166163
points: &ArrayRef,
167164
ctx: &mut ExecutionCtx,
168165
) -> VortexResult<(PrimitiveArray, PrimitiveArray)> {
169166
let storage = points
170167
.clone()
171-
.execute::<Canonical>(ctx)?
172-
.into_extension()
168+
.execute::<ExtensionArray>(ctx)?
173169
.storage_array()
174170
.clone()
175-
.execute::<Canonical>(ctx)?
176-
.into_struct();
171+
.execute::<StructArray>(ctx)?;
177172
let xs = storage
178173
.unmasked_field_by_name("x")?
179174
.clone()
180-
.execute::<Canonical>(ctx)?
181-
.into_primitive();
175+
.execute::<PrimitiveArray>(ctx)?;
182176
let ys = storage
183177
.unmasked_field_by_name("y")?
184178
.clone()
185-
.execute::<Canonical>(ctx)?
186-
.into_primitive();
179+
.execute::<PrimitiveArray>(ctx)?;
187180
Ok((xs, ys))
188181
}

vortex-geo/src/extension/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4-
mod coordinate;
4+
pub(crate) mod coordinate;
55
mod point;
66
mod wkb;
77

88
use std::fmt::Display;
99

10-
pub(crate) use coordinate::xy_columns;
11-
pub use coordinate::*;
1210
pub use point::*;
1311
pub use wkb::*;
1412

vortex-geo/src/extension/point.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,43 @@ mod tests {
6161
use vortex_array::arrays::PrimitiveArray;
6262
use vortex_array::arrays::StructArray;
6363
use vortex_array::dtype::DType;
64+
use vortex_array::dtype::FieldNames;
6465
use vortex_array::dtype::Nullability;
6566
use vortex_array::dtype::PType;
67+
use vortex_array::dtype::StructFields;
6668
use vortex_array::dtype::extension::ExtDType;
6769
use vortex_array::session::ArraySession;
6870
use vortex_error::VortexResult;
6971
use vortex_session::VortexSession;
7072

7173
use super::Point;
72-
use crate::extension::Coordinate;
73-
use crate::extension::Dimension;
7474
use crate::extension::GeoMetadata;
75-
use crate::extension::coordinate_dimension;
76-
use crate::extension::coordinate_dtype;
77-
use crate::extension::coordinate_from_scalar;
75+
use crate::extension::coordinate::Coordinate;
76+
use crate::extension::coordinate::Dimension;
77+
use crate::extension::coordinate::coordinate_dimension;
78+
use crate::extension::coordinate::coordinate_from_scalar;
7879

7980
fn geo_meta() -> GeoMetadata {
8081
GeoMetadata {
8182
crs: Some("EPSG:4326".to_string()),
8283
}
8384
}
8485

85-
/// `Point` accepts every GeoArrow dimension; the storage carries the canonical field names and
86-
/// the dimension round-trips, so a z/m swap or a mislabel would be caught.
86+
/// A coordinate storage dtype with the given field names, non-nullable `f64` per field.
87+
fn coordinate_dtype(names: &[&'static str]) -> DType {
88+
let fields = std::iter::repeat_n(
89+
DType::Primitive(PType::F64, Nullability::NonNullable),
90+
names.len(),
91+
)
92+
.collect::<Vec<_>>();
93+
DType::Struct(
94+
StructFields::new(FieldNames::from(names), fields),
95+
Nullability::NonNullable,
96+
)
97+
}
98+
99+
/// `Point` accepts every GeoArrow dimension; the canonical field names round-trip to their
100+
/// dimension, so a z/m swap or a mislabel would be caught.
87101
#[test]
88102
fn point_validates_every_dimension() -> VortexResult<()> {
89103
let cases = [
@@ -92,13 +106,8 @@ mod tests {
92106
(Dimension::Xym, ["x", "y", "m"].as_slice()),
93107
(Dimension::Xyzm, ["x", "y", "z", "m"].as_slice()),
94108
];
95-
for (dim, expected_fields) in cases {
96-
let storage = coordinate_dtype(dim, Nullability::NonNullable);
97-
let DType::Struct(fields, _) = &storage else {
98-
unreachable!("coordinate_dtype builds a struct");
99-
};
100-
let names: Vec<&str> = fields.names().iter().map(|n| n.as_ref()).collect();
101-
assert_eq!(names.as_slice(), expected_fields);
109+
for (dim, names) in cases {
110+
let storage = coordinate_dtype(names);
102111
assert_eq!(coordinate_dimension(&storage)?, dim);
103112
ExtDType::<Point>::try_new(geo_meta(), storage)?;
104113
}

vortex-geo/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use vortex_session::VortexSession;
77

88
use crate::extension::Point;
99
use crate::extension::WellKnownBinary;
10-
use crate::scalar_fn::GeoDistance;
10+
use crate::scalar_fn::distance::GeoDistance;
1111

1212
pub mod extension;
1313
pub mod scalar_fn;

0 commit comments

Comments
 (0)