diff --git a/rust/geoarrow/Cargo.toml b/rust/geoarrow/Cargo.toml index 6299e9b41..84cad2987 100644 --- a/rust/geoarrow/Cargo.toml +++ b/rust/geoarrow/Cargo.toml @@ -129,6 +129,11 @@ name = "area" harness = false required-features = ["flatgeobuf"] +[[bench]] +name = "total_bounds" +harness = false +required-features = ["flatgeobuf"] + [[bench]] name = "from_geo" harness = false diff --git a/rust/geoarrow/benches/geos_buffer.rs b/rust/geoarrow/benches/geos_buffer.rs index 810f6ae21..6aa14773a 100644 --- a/rust/geoarrow/benches/geos_buffer.rs +++ b/rust/geoarrow/benches/geos_buffer.rs @@ -1,10 +1,11 @@ use criterion::{criterion_group, criterion_main, Criterion}; use geoarrow::algorithm::geos::Buffer; use geoarrow::array::{CoordBuffer, InterleavedCoordBuffer, PointArray, PolygonArray}; +use geoarrow::datatypes::Dimension; fn generate_data() -> PointArray<2> { let coords = vec![0.0; 100_000]; - let coord_buffer = CoordBuffer::Interleaved(InterleavedCoordBuffer::new(coords.into())); + let coord_buffer = CoordBuffer::new_interleaved(coords.into(), Dimension::XY).unwrap(); PointArray::new(coord_buffer, None, Default::default()) } diff --git a/rust/geoarrow/benches/total_bounds.rs b/rust/geoarrow/benches/total_bounds.rs new file mode 100644 index 000000000..950ff9211 --- /dev/null +++ b/rust/geoarrow/benches/total_bounds.rs @@ -0,0 +1,34 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use geoarrow::algorithm::geo::Area; +use geoarrow::algorithm::native::TotalBounds; +use geoarrow::array::{AsChunkedNativeArray, MultiPolygonArray}; +use geoarrow::io::flatgeobuf::read_flatgeobuf; +use geoarrow::trait_::ArrayAccessor; +use std::fs::File; + +fn load_file() -> MultiPolygonArray<2> { + let mut file = File::open("fixtures/flatgeobuf/countries.fgb").unwrap(); + let table = read_flatgeobuf(&mut file, Default::default()).unwrap(); + table + .geometry_column(None) + .unwrap() + .as_ref() + .as_multi_polygon::<2>() + .chunks() + .first() + .unwrap() + .clone() +} + +fn criterion_benchmark(c: &mut Criterion) { + let data = load_file(); + + c.bench_function("total_bounds", |bencher| { + bencher.iter(|| { + criterion::black_box(criterion::black_box(&data).total_bounds()); + }); + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/rust/geoarrow/src/algorithm/native/downcast.rs b/rust/geoarrow/src/algorithm/native/downcast.rs index 1643ba03b..bdf306bbd 100644 --- a/rust/geoarrow/src/algorithm/native/downcast.rs +++ b/rust/geoarrow/src/algorithm/native/downcast.rs @@ -144,7 +144,7 @@ impl Downcast for MultiPointArray<2> { fn downcast(&self, small_offsets: bool) -> Self::Output { // Note: this won't allow a downcast for empty MultiPoints if *self.geom_offsets.last() as usize == self.len() { - return Arc::new(PointArray::new( + return Arc::new(PointArray::<2>::new( self.coords.clone(), self.validity.clone(), self.metadata(), @@ -173,7 +173,7 @@ impl Downcast for MultiLineStringArray<2> { fn downcast(&self, small_offsets: bool) -> Self::Output { if *self.geom_offsets.last() as usize == self.len() { - return Arc::new(LineStringArray::new( + return Arc::new(LineStringArray::<2>::new( self.coords.clone(), self.ring_offsets.clone(), self.validity.clone(), @@ -203,7 +203,7 @@ impl Downcast for MultiPolygonArray<2> { fn downcast(&self, small_offsets: bool) -> Self::Output { if *self.geom_offsets.last() as usize == self.len() { - return Arc::new(PolygonArray::new( + return Arc::new(PolygonArray::<2>::new( self.coords.clone(), self.polygon_offsets.clone(), self.ring_offsets.clone(), diff --git a/rust/geoarrow/src/algorithm/native/map_coords.rs b/rust/geoarrow/src/algorithm/native/map_coords.rs index 45ae9e690..92174eaed 100644 --- a/rust/geoarrow/src/algorithm/native/map_coords.rs +++ b/rust/geoarrow/src/algorithm/native/map_coords.rs @@ -18,25 +18,25 @@ pub trait MapCoords { fn map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> geo::Coord + Sync, + F: Fn(&crate::scalar::Coord) -> geo::Coord + Sync, { self.try_map_coords(|coord| Ok::<_, GeoArrowError>(map_op(coord))) } fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From; } // Scalar impls -impl MapCoords for Coord<'_, 2> { +impl MapCoords for Coord<'_> { type Output = geo::Coord; fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(map_op(self)?) @@ -48,7 +48,7 @@ impl MapCoords for Point<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(geo::Point(map_op(&self.coord())?)) @@ -60,7 +60,7 @@ impl MapCoords for LineString<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let output_coords = self @@ -76,7 +76,7 @@ impl MapCoords for Polygon<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { if self.exterior().is_none() { @@ -98,7 +98,7 @@ impl MapCoords for MultiPoint<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let points = self @@ -114,7 +114,7 @@ impl MapCoords for MultiLineString<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let lines = self @@ -131,7 +131,7 @@ impl MapCoords for MultiPolygon<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let polygons = self @@ -147,7 +147,7 @@ impl MapCoords for Geometry<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { use GeometryType::*; @@ -175,7 +175,7 @@ impl MapCoords for GeometryCollection<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let geoms = self @@ -191,7 +191,7 @@ impl MapCoords for Rect<'_, 2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let lower = self.min(); @@ -201,7 +201,7 @@ impl MapCoords for Rect<'_, 2> { let maxx = upper.x(); let maxy = upper.y(); let coords = vec![minx, miny, maxx, maxy]; - let coord_buffer = CoordBuffer::Interleaved(InterleavedCoordBuffer::new(coords.into())); + let coord_buffer = CoordBuffer::new_interleaved(coords.into(), Dimension::XY).unwrap(); let lower_coord = coord_buffer.value(0); let upper_coord = coord_buffer.value(1); @@ -216,7 +216,7 @@ impl MapCoords for PointArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = PointBuilder::with_capacity_and_options( @@ -241,7 +241,7 @@ impl MapCoords for LineStringArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = LineStringBuilder::with_capacity_and_options( @@ -266,7 +266,7 @@ impl MapCoords for PolygonArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = PolygonBuilder::with_capacity_and_options( @@ -291,7 +291,7 @@ impl MapCoords for MultiPointArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = MultiPointBuilder::with_capacity_and_options( @@ -316,7 +316,7 @@ impl MapCoords for MultiLineStringArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = MultiLineStringBuilder::with_capacity_and_options( @@ -341,7 +341,7 @@ impl MapCoords for MultiPolygonArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = MultiPolygonBuilder::with_capacity_and_options( @@ -366,7 +366,7 @@ impl MapCoords for MixedGeometryArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = MixedGeometryBuilder::with_capacity_and_options( @@ -392,7 +392,7 @@ impl MapCoords for GeometryCollectionArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = GeometryCollectionBuilder::with_capacity_and_options( @@ -418,7 +418,7 @@ impl MapCoords for RectArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { let mut builder = RectBuilder::with_capacity_and_options(self.len(), self.metadata()); @@ -439,7 +439,7 @@ impl MapCoords for &dyn NativeArray { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { use Dimension::*; @@ -470,7 +470,7 @@ impl MapCoords for ChunkedPointArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -484,7 +484,7 @@ impl MapCoords for ChunkedLineStringArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -498,7 +498,7 @@ impl MapCoords for ChunkedPolygonArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -512,7 +512,7 @@ impl MapCoords for ChunkedMultiPointArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -526,7 +526,7 @@ impl MapCoords for ChunkedMultiLineStringArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -540,7 +540,7 @@ impl MapCoords for ChunkedMultiPolygonArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -554,7 +554,7 @@ impl MapCoords for ChunkedMixedGeometryArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -568,7 +568,7 @@ impl MapCoords for ChunkedGeometryCollectionArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -582,7 +582,7 @@ impl MapCoords for ChunkedRectArray<2> { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { Ok(ChunkedGeometryArray::new( @@ -596,7 +596,7 @@ impl MapCoords for &dyn ChunkedNativeArray { fn try_map_coords(&self, map_op: F) -> Result where - F: Fn(&crate::scalar::Coord<2>) -> std::result::Result + Sync, + F: Fn(&crate::scalar::Coord) -> std::result::Result + Sync, GeoArrowError: From, { use Dimension::*; diff --git a/rust/geoarrow/src/array/coord/array.rs b/rust/geoarrow/src/array/coord/array.rs new file mode 100644 index 000000000..dd05b5516 --- /dev/null +++ b/rust/geoarrow/src/array/coord/array.rs @@ -0,0 +1,355 @@ +use std::sync::Arc; + +use arrow::array::AsArray; +use arrow::datatypes::Float64Type; +use arrow_array::{Array, ArrayRef, FixedSizeListArray, Float64Array, StructArray}; +use arrow_buffer::{Buffer, NullBuffer, ScalarBuffer}; +use arrow_schema::{DataType, Field}; + +use crate::algorithm::native::eq::coord_eq; +use crate::array::{CoordType, InterleavedCoordBufferBuilder, SeparatedCoordBufferBuilder}; +use crate::datatypes::{coord_type_to_data_type, Dimension}; +use crate::error::{GeoArrowError, Result}; +use crate::scalar::Coord; +use crate::trait_::IntoArrow; + +/// A GeoArrow coordinate buffer +#[derive(Clone, Debug)] +pub struct CoordBuffer { + /// We always store 4 buffers in an array, but not all 4 of these may have valid coordinates. + /// The number of valid buffers is stored in `num_buffers` and matches the physical size of the + /// dimension. For example, `XY` coordinates will only have two valid buffers, in slots `0` and + /// `1`. `XYZ` and `XYM` will have three valid buffers and `XYZM` will have four valid buffers. + /// + /// In the case of interleaved coordinates, each slot will be a clone of the same + /// reference-counted buffer. + pub(crate) buffers: [ScalarBuffer; 4], + + /// The number of coordinates in this buffer + pub(crate) num_coords: usize, + + /// The number of valid buffers in the buffers array. (i.e., number of physical dimensions) + /// TODO: unsure if this is needed since we also store the logical dimension? Maybe still + /// faster than doing the Dimension enum lookup on coord access. + pub(crate) num_buffers: usize, + + /// The number of elements to advance a given value pointer to the next ordinate. + /// + /// - For interleaved coordinates, `coords_stride` will equal `num_buffers`. + /// - For struct coordinates, `coords_stride` will be 1. + pub(crate) coords_stride: usize, + + /// The coordinate type of this buffer (interleaved or separated). + pub(crate) coord_type: CoordType, + + /// The dimension of this buffer (e.g. `XY`, `XYZ`). + pub(crate) dim: Dimension, +} + +impl CoordBuffer { + /// Construct a new buffer from interleaved coordinates. + pub fn new_interleaved(coords: ScalarBuffer, dim: Dimension) -> Result { + if coords.len() % dim.size() != 0 { + return Err(GeoArrowError::General(format!( + "Coordinate length {} should be a multiple of physical dimension {:?}", + coords.len(), + dim + ))); + } + + // These buffers are reference-counted and clones are cheap + let buffers = [ + coords.clone(), + coords.clone(), + coords.clone(), + coords.clone(), + ]; + + Ok(Self { + buffers, + num_coords: coords.len() / dim.size(), + num_buffers: 1, + coords_stride: dim.size(), + coord_type: CoordType::Interleaved, + dim, + }) + } + + /// Construct a new buffer from separated coordinates. + /// + /// - All coordinate buffers must have the same length. + /// + /// This takes a slice of coords because cloning is cheap and that allows both vec and array + /// input. + pub fn new_separated(coords: &[ScalarBuffer], dim: Dimension) -> Result { + if !coords.windows(2).all(|w| w[0].len() == w[1].len()) { + return Err(GeoArrowError::General( + "all input coordinate buffers must have the same length".to_string(), + )); + } + + let num_buffers = match dim { + Dimension::XY => 2, + Dimension::XYZ => 3, + }; + if coords.len() != num_buffers { + return Err(GeoArrowError::General(format!( + "Expected {} buffers, got {}", + num_buffers, + coords.len() + ))); + } + + let empty_buffer = ScalarBuffer::from(Buffer::from_vec(Vec::::new())); + let buffers = match num_buffers { + 2 => [ + coords[0].clone(), + coords[1].clone(), + empty_buffer.clone(), + empty_buffer.clone(), + ], + 3 => [ + coords[0].clone(), + coords[1].clone(), + coords[2].clone(), + empty_buffer.clone(), + ], + 4 => [ + coords[0].clone(), + coords[1].clone(), + coords[2].clone(), + coords[3].clone(), + ], + _ => unreachable!(), + }; + + Ok(Self { + buffers, + num_coords: coords[0].len(), + num_buffers, + coords_stride: 1, + coord_type: CoordType::Separated, + dim, + }) + } + + pub fn from_arrow(array: &dyn Array, dim: Dimension) -> Result { + match array.data_type() { + DataType::FixedSizeList(inner_field, inner_size) => { + todo!() + } + DataType::Struct(inner_fields) => { + todo!() + } + dt => Err(GeoArrowError::General(format!( + "Unexpected data type in from_arrow: {}", + dt + ))), + } + } + + pub fn coord_type(&self) -> CoordType { + self.coord_type + } + + pub fn len(&self) -> usize { + self.num_coords + } + + /// Convert this coordinate buffer to another coord type. + pub fn into_coord_type(self, coord_type: CoordType) -> Self { + match (self.coord_type, coord_type) { + (CoordType::Interleaved, CoordType::Interleaved) => self, + (CoordType::Interleaved, CoordType::Separated) => { + // let mut new_buffer = SeparatedCoordBufferBuilder::with_capacity(self.num_coords); + // for i in 0..self.num_coords { + // new_buffer.push_coord(&self.value_unchecked(i)); + // } + + todo!() + // Self::new_separated(new_buffer.buffers, dim) + } + (CoordType::Separated, CoordType::Separated) => self, + (CoordType::Separated, CoordType::Interleaved) => { + todo!() + // let mut new_buffer = InterleavedCoordBufferBuilder::with_capacity(self.num_coords); + // for row_idx in 0..cb.len() { + // new_buffer.push(core::array::from_fn(|i| cb.buffers[i][row_idx])); + // } + // CoordBuffer::Interleaved(new_buffer.into()) + } + } + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn slice(&self, offset: usize, length: usize) -> Self { + todo!() + } + + pub fn owned_slice(&self, offset: usize, length: usize) -> Self { + todo!() + } + + pub fn value(&self, index: usize) -> Coord<'_> { + assert!(index <= self.len()); + self.value_unchecked(index) + } + + pub fn value_unchecked(&self, index: usize) -> Coord<'_> { + Coord { + buffer: self, + i: index, + } + } + + fn interleaved_values_array(&self) -> Float64Array { + debug_assert_eq!(self.coord_type, CoordType::Interleaved); + Float64Array::new(self.buffers[0].clone(), None) + } + + fn interleaved_values_field(&self) -> Field { + debug_assert_eq!(self.coord_type, CoordType::Interleaved); + match self.dim { + Dimension::XY => Field::new("xy", DataType::Float64, false), + Dimension::XYZ => Field::new("xyz", DataType::Float64, false), + } + } + + fn separated_values_array(&self) -> Vec { + debug_assert_eq!(self.coord_type, CoordType::Separated); + match self.dim { + Dimension::XY => { + vec![ + Arc::new(Float64Array::new(self.buffers[0].clone(), None)), + Arc::new(Float64Array::new(self.buffers[1].clone(), None)), + ] + } + Dimension::XYZ => { + vec![ + Arc::new(Float64Array::new(self.buffers[0].clone(), None)), + Arc::new(Float64Array::new(self.buffers[1].clone(), None)), + Arc::new(Float64Array::new(self.buffers[2].clone(), None)), + ] + } + } + } + + fn separated_values_field(&self) -> Vec { + debug_assert_eq!(self.coord_type, CoordType::Separated); + match self.dim { + Dimension::XY => { + vec![ + Field::new("x", DataType::Float64, false), + Field::new("y", DataType::Float64, false), + ] + } + Dimension::XYZ => { + vec![ + Field::new("x", DataType::Float64, false), + Field::new("y", DataType::Float64, false), + Field::new("z", DataType::Float64, false), + ] + } + } + } + + pub fn storage_type(&self) -> DataType { + coord_type_to_data_type(self.coord_type, self.dim) + } + + pub(crate) fn into_arrow_with_validity(self, nulls: Option) -> ArrayRef { + match self.coord_type { + CoordType::Separated => Arc::new(StructArray::new( + self.separated_values_field().into(), + self.separated_values_array(), + nulls, + )), + CoordType::Interleaved => Arc::new(FixedSizeListArray::new( + Arc::new(self.interleaved_values_field()), + self.dim.size().try_into().unwrap(), + Arc::new(self.interleaved_values_array()), + nulls, + )), + } + } +} + +impl IntoArrow for CoordBuffer { + type ArrowArray = ArrayRef; + + fn into_arrow(self) -> Self::ArrowArray { + self.into_arrow_with_validity(None) + } +} + +impl PartialEq for CoordBuffer { + fn eq(&self, other: &Self) -> bool { + if self.num_coords != other.num_coords { + return false; + } + + for i in 0..self.num_coords { + let left = self.value_unchecked(i); + let right = other.value_unchecked(i); + + if !coord_eq(&left, &right) { + return false; + } + } + + true + } +} + +impl TryFrom<&FixedSizeListArray> for CoordBuffer { + type Error = GeoArrowError; + + fn try_from(value: &FixedSizeListArray) -> std::result::Result { + let dim = Dimension::try_from(value.value_length() as usize).unwrap(); + let coord_array_values = value + .values() + .as_any() + .downcast_ref::() + .unwrap(); + CoordBuffer::new_interleaved(coord_array_values.values().clone(), dim) + } +} + +impl TryFrom<&StructArray> for CoordBuffer { + type Error = GeoArrowError; + + fn try_from(value: &StructArray) -> std::result::Result { + let arrays = value.columns(); + let dim = Dimension::try_from(arrays.len()).unwrap(); + let buffers = arrays + .iter() + .map(|arr| arr.as_primitive::().values().clone()) + .collect::>(); + + CoordBuffer::new_separated(&buffers, dim) + } +} + +impl TryFrom<&dyn Array> for CoordBuffer { + type Error = GeoArrowError; + + fn try_from(value: &dyn Array) -> Result { + match value.data_type() { + DataType::Struct(_) => { + let downcasted = value.as_any().downcast_ref::().unwrap(); + downcasted.try_into() + } + DataType::FixedSizeList(_, _) => { + let downcasted = value.as_any().downcast_ref::().unwrap(); + downcasted.try_into() + } + _ => Err(GeoArrowError::General(format!( + "Unexpected type: {:?}", + value.data_type() + ))), + } + } +} diff --git a/rust/geoarrow/src/array/coord/combined/array.rs b/rust/geoarrow/src/array/coord/combined/array.rs index f2c4350c7..9c3b6b920 100644 --- a/rust/geoarrow/src/array/coord/combined/array.rs +++ b/rust/geoarrow/src/array/coord/combined/array.rs @@ -29,20 +29,6 @@ pub enum CoordBuffer { } impl CoordBuffer { - pub fn get_x(&self, i: usize) -> f64 { - match self { - CoordBuffer::Interleaved(c) => c.get_x(i), - CoordBuffer::Separated(c) => c.get_x(i), - } - } - - pub fn get_y(&self, i: usize) -> f64 { - match self { - CoordBuffer::Interleaved(c) => c.get_y(i), - CoordBuffer::Separated(c) => c.get_y(i), - } - } - pub fn slice(&self, offset: usize, length: usize) -> Self { match self { CoordBuffer::Interleaved(c) => CoordBuffer::Interleaved(c.slice(offset, length)), diff --git a/rust/geoarrow/src/array/coord/combined/builder.rs b/rust/geoarrow/src/array/coord/combined/builder.rs index a87405fb6..ab84c7d26 100644 --- a/rust/geoarrow/src/array/coord/combined/builder.rs +++ b/rust/geoarrow/src/array/coord/combined/builder.rs @@ -3,6 +3,7 @@ use core::f64; use crate::array::{ CoordBuffer, CoordType, InterleavedCoordBufferBuilder, SeparatedCoordBufferBuilder, }; +use arrow_buffer::ScalarBuffer; use geo_traits::{CoordTrait, PointTrait}; /// The GeoArrow equivalent to `Vec`: a mutable collection of coordinates. @@ -126,11 +127,20 @@ impl CoordBufferBuilder<2> { } } -impl From> for CoordBuffer { +impl From> for CoordBuffer { fn from(value: CoordBufferBuilder) -> Self { match value { - CoordBufferBuilder::Interleaved(cb) => CoordBuffer::Interleaved(cb.into()), - CoordBufferBuilder::Separated(cb) => CoordBuffer::Separated(cb.into()), + CoordBufferBuilder::Interleaved(cb) => { + CoordBuffer::new_interleaved(cb.coords.into(), D.try_into().unwrap()).unwrap() + } + CoordBufferBuilder::Separated(cb) => { + let coord_buffers = cb + .buffers + .into_iter() + .map(|buf| ScalarBuffer::from(buf)) + .collect::>(); + CoordBuffer::new_separated(&coord_buffers, D.try_into().unwrap()).unwrap() + } } } } diff --git a/rust/geoarrow/src/array/coord/combined/mod.rs b/rust/geoarrow/src/array/coord/combined/mod.rs index 88d1b1e05..384dc067b 100644 --- a/rust/geoarrow/src/array/coord/combined/mod.rs +++ b/rust/geoarrow/src/array/coord/combined/mod.rs @@ -1,5 +1,3 @@ -mod array; mod builder; -pub use array::CoordBuffer; pub use builder::CoordBufferBuilder; diff --git a/rust/geoarrow/src/array/coord/interleaved/array.rs b/rust/geoarrow/src/array/coord/interleaved/array.rs index db97d8d17..01c3ef220 100644 --- a/rust/geoarrow/src/array/coord/interleaved/array.rs +++ b/rust/geoarrow/src/array/coord/interleaved/array.rs @@ -65,16 +65,6 @@ impl InterleavedCoordBuffer { } } - pub fn get_x(&self, i: usize) -> f64 { - let c = self.value(i); - c.x() - } - - pub fn get_y(&self, i: usize) -> f64 { - let c = self.value(i); - c.y() - } - pub fn slice(&self, offset: usize, length: usize) -> Self { assert!( offset + length <= self.len(), diff --git a/rust/geoarrow/src/array/coord/interleaved/builder.rs b/rust/geoarrow/src/array/coord/interleaved/builder.rs index f113774b3..2993c6b4a 100644 --- a/rust/geoarrow/src/array/coord/interleaved/builder.rs +++ b/rust/geoarrow/src/array/coord/interleaved/builder.rs @@ -8,7 +8,7 @@ use geo_traits::{CoordTrait, PointTrait}; /// Converting an [`InterleavedCoordBufferBuilder`] into a [`InterleavedCoordBuffer`] is `O(1)`. #[derive(Debug, Clone)] pub struct InterleavedCoordBufferBuilder { - pub coords: Vec, + pub(crate) coords: Vec, } impl InterleavedCoordBufferBuilder { diff --git a/rust/geoarrow/src/array/coord/mod.rs b/rust/geoarrow/src/array/coord/mod.rs index 5a96375dc..6b480f416 100644 --- a/rust/geoarrow/src/array/coord/mod.rs +++ b/rust/geoarrow/src/array/coord/mod.rs @@ -4,11 +4,13 @@ //! Coordinates can be either _interleaved_, where they're represented as a `FixedSizeList`, or //! _separated_, where they're represented with a `StructArray`. +mod array; mod combined; mod interleaved; mod separated; -pub use combined::{CoordBuffer, CoordBufferBuilder}; +pub use array::CoordBuffer; +pub use combined::CoordBufferBuilder; pub use interleaved::{InterleavedCoordBuffer, InterleavedCoordBufferBuilder}; pub use separated::{SeparatedCoordBuffer, SeparatedCoordBufferBuilder}; diff --git a/rust/geoarrow/src/array/coord/separated/array.rs b/rust/geoarrow/src/array/coord/separated/array.rs index 81b51554c..bd387300b 100644 --- a/rust/geoarrow/src/array/coord/separated/array.rs +++ b/rust/geoarrow/src/array/coord/separated/array.rs @@ -79,16 +79,6 @@ impl SeparatedCoordBuffer { } } - pub fn get_x(&self, i: usize) -> f64 { - let c = self.value(i); - c.x() - } - - pub fn get_y(&self, i: usize) -> f64 { - let c = self.value(i); - c.y() - } - pub fn slice(&self, offset: usize, length: usize) -> Self { assert!( offset + length <= self.len(), diff --git a/rust/geoarrow/src/array/coord/separated/builder.rs b/rust/geoarrow/src/array/coord/separated/builder.rs index 3298f814e..f15b34965 100644 --- a/rust/geoarrow/src/array/coord/separated/builder.rs +++ b/rust/geoarrow/src/array/coord/separated/builder.rs @@ -10,7 +10,7 @@ use geo_traits::{CoordTrait, PointTrait}; /// Converting an [`SeparatedCoordBufferBuilder`] into a [`SeparatedCoordBuffer`] is `O(1)`. #[derive(Debug, Clone)] pub struct SeparatedCoordBufferBuilder { - buffers: [Vec; D], + pub(crate) buffers: [Vec; D], } impl SeparatedCoordBufferBuilder { diff --git a/rust/geoarrow/src/array/geometrycollection/array.rs b/rust/geoarrow/src/array/geometrycollection/array.rs index a7d9d580f..ac7e5b374 100644 --- a/rust/geoarrow/src/array/geometrycollection/array.rs +++ b/rust/geoarrow/src/array/geometrycollection/array.rs @@ -212,7 +212,7 @@ impl NativeArray for GeometryCollectionArray { } impl GeometryArraySelfMethods for GeometryCollectionArray { - fn with_coords(self, _coords: CoordBuffer) -> Self { + fn with_coords(self, _coords: CoordBuffer) -> Self { todo!() } diff --git a/rust/geoarrow/src/array/linestring/array.rs b/rust/geoarrow/src/array/linestring/array.rs index 6b1c44bf8..ecfcb021c 100644 --- a/rust/geoarrow/src/array/linestring/array.rs +++ b/rust/geoarrow/src/array/linestring/array.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::marker::PhantomData; use std::sync::Arc; use crate::algorithm::native::downcast::can_downcast_multi; @@ -35,17 +36,18 @@ pub struct LineStringArray { pub(crate) metadata: Arc, - pub(crate) coords: CoordBuffer, + pub(crate) coords: CoordBuffer, /// Offsets into the coordinate array where each geometry starts pub(crate) geom_offsets: OffsetBuffer, /// Validity bitmap pub(crate) validity: Option, + // dim_size: PhantomData, } -pub(super) fn check( - coords: &CoordBuffer, +pub(super) fn check( + coords: &CoordBuffer, validity_len: Option, geom_offsets: &OffsetBuffer, ) -> Result<()> { @@ -76,7 +78,7 @@ impl LineStringArray { /// - if the validity is not `None` and its length is different from the number of geometries /// - if the largest geometry offset does not match the number of coordinates pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, validity: Option, metadata: Arc, @@ -95,7 +97,7 @@ impl LineStringArray { /// - if the validity buffer does not have the same length as the number of geometries /// - if the geometry offsets do not match the number of coordinates pub fn try_new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, validity: Option, metadata: Arc, @@ -118,11 +120,11 @@ impl LineStringArray { Field::new("vertices", self.coords.storage_type(), false).into() } - pub fn coords(&self) -> &CoordBuffer { + pub fn coords(&self) -> &CoordBuffer { &self.coords } - pub fn into_inner(self) -> (CoordBuffer, OffsetBuffer, Option) { + pub fn into_inner(self) -> (CoordBuffer, OffsetBuffer, Option) { (self.coords, self.geom_offsets, self.validity) } @@ -176,25 +178,26 @@ impl LineStringArray { } pub fn owned_slice(&self, offset: usize, length: usize) -> Self { - assert!( - offset + length <= self.len(), - "offset + length may not exceed length of array" - ); - assert!(length >= 1, "length must be at least 1"); + todo!(); + // assert!( + // offset + length <= self.len(), + // "offset + length may not exceed length of array" + // ); + // assert!(length >= 1, "length must be at least 1"); - // Find the start and end of the coord buffer - let (start_coord_idx, _) = self.geom_offsets.start_end(offset); - let (_, end_coord_idx) = self.geom_offsets.start_end(offset + length - 1); + // // Find the start and end of the coord buffer + // let (start_coord_idx, _) = self.geom_offsets.start_end(offset); + // let (_, end_coord_idx) = self.geom_offsets.start_end(offset + length - 1); - let geom_offsets = owned_slice_offsets(&self.geom_offsets, offset, length); + // let geom_offsets = owned_slice_offsets(&self.geom_offsets, offset, length); - let coords = self - .coords - .owned_slice(start_coord_idx, end_coord_idx - start_coord_idx); + // let coords = self + // .coords + // .owned_slice(start_coord_idx, end_coord_idx - start_coord_idx); - let validity = owned_slice_validity(self.nulls(), offset, length); + // let validity = owned_slice_validity(self.nulls(), offset, length); - Self::new(coords, geom_offsets, validity, self.metadata()) + // Self::new(coords, geom_offsets, validity, self.metadata()) } pub fn to_coord_type(&self, coord_type: CoordType) -> Self { @@ -297,7 +300,7 @@ impl NativeArray for LineStringArray { } impl GeometryArraySelfMethods for LineStringArray { - fn with_coords(self, coords: CoordBuffer) -> Self { + fn with_coords(self, coords: CoordBuffer) -> Self { assert_eq!(coords.len(), self.coords.len()); Self::new(coords, self.geom_offsets, self.validity, self.metadata) } @@ -324,7 +327,7 @@ impl<'a, const D: usize> crate::trait_::NativeGEOSGeometryAccessor<'a> for LineS &'a self, index: usize, ) -> std::result::Result { - let geom = LineString::new(&self.coords, &self.geom_offsets, index); + let geom = LineString::::new(&self.coords, &self.geom_offsets, index); (&geom).try_into() } } @@ -344,7 +347,7 @@ impl IntoArrow for LineStringArray { fn into_arrow(self) -> Self::ArrowArray { let vertices_field = self.vertices_field(); let validity = self.validity; - let coord_array = self.coords.into_array_ref(); + let coord_array = self.coords.into_arrow(); GenericListArray::new(vertices_field, self.geom_offsets, coord_array, validity) } } @@ -353,7 +356,7 @@ impl TryFrom<&GenericListArray> for LineStringArray { type Error = GeoArrowError; fn try_from(value: &GenericListArray) -> Result { - let coords: CoordBuffer = value.values().as_ref().try_into()?; + let coords: CoordBuffer = value.values().as_ref().try_into()?; let geom_offsets = value.offsets(); let validity = value.nulls(); @@ -370,7 +373,7 @@ impl TryFrom<&GenericListArray> for LineStringArray { type Error = GeoArrowError; fn try_from(value: &GenericListArray) -> Result { - let coords: CoordBuffer = value.values().as_ref().try_into()?; + let coords: CoordBuffer = value.values().as_ref().try_into()?; let geom_offsets = offsets_buffer_i64_to_i32(value.offsets())?; let validity = value.nulls(); diff --git a/rust/geoarrow/src/array/mixed/array.rs b/rust/geoarrow/src/array/mixed/array.rs index e4d25c20b..b15a15aba 100644 --- a/rust/geoarrow/src/array/mixed/array.rs +++ b/rust/geoarrow/src/array/mixed/array.rs @@ -411,7 +411,7 @@ impl NativeArray for MixedGeometryArray { } impl GeometryArraySelfMethods for MixedGeometryArray { - fn with_coords(self, _coords: crate::array::CoordBuffer) -> Self { + fn with_coords(self, _coords: crate::array::CoordBuffer) -> Self { todo!(); } diff --git a/rust/geoarrow/src/array/multilinestring/array.rs b/rust/geoarrow/src/array/multilinestring/array.rs index 1e36c372e..946b1846d 100644 --- a/rust/geoarrow/src/array/multilinestring/array.rs +++ b/rust/geoarrow/src/array/multilinestring/array.rs @@ -33,7 +33,7 @@ pub struct MultiLineStringArray { pub(crate) metadata: Arc, - pub(crate) coords: CoordBuffer, + pub(crate) coords: CoordBuffer, /// Offsets into the ring array where each geometry starts pub(crate) geom_offsets: OffsetBuffer, @@ -45,8 +45,8 @@ pub struct MultiLineStringArray { pub(crate) validity: Option, } -pub(super) fn check( - coords: &CoordBuffer, +pub(super) fn check( + coords: &CoordBuffer, geom_offsets: &OffsetBuffer, ring_offsets: &OffsetBuffer, validity_len: Option, @@ -85,7 +85,7 @@ impl MultiLineStringArray { /// - if the largest ring offset does not match the number of coordinates /// - if the largest geometry offset does not match the size of ring offsets pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, validity: Option, @@ -106,7 +106,7 @@ impl MultiLineStringArray { /// - if the largest ring offset does not match the number of coordinates /// - if the largest geometry offset does not match the size of ring offsets pub fn try_new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, validity: Option, @@ -140,7 +140,7 @@ impl MultiLineStringArray { Field::new_list("linestrings", self.vertices_field(), false).into() } - pub fn coords(&self) -> &CoordBuffer { + pub fn coords(&self) -> &CoordBuffer { &self.coords } @@ -189,40 +189,41 @@ impl MultiLineStringArray { } pub fn owned_slice(&self, offset: usize, length: usize) -> Self { - assert!( - offset + length <= self.len(), - "offset + length may not exceed length of array" - ); - assert!(length >= 1, "length must be at least 1"); - - // Find the start and end of the ring offsets - let (start_ring_idx, _) = self.geom_offsets.start_end(offset); - let (_, end_ring_idx) = self.geom_offsets.start_end(offset + length - 1); - - // Find the start and end of the coord buffer - let (start_coord_idx, _) = self.ring_offsets.start_end(start_ring_idx); - let (_, end_coord_idx) = self.ring_offsets.start_end(end_ring_idx - 1); - - // Slice the geom_offsets - let geom_offsets = owned_slice_offsets(&self.geom_offsets, offset, length); - let ring_offsets = owned_slice_offsets( - &self.ring_offsets, - start_ring_idx, - end_ring_idx - start_ring_idx, - ); - let coords = self - .coords - .owned_slice(start_coord_idx, end_coord_idx - start_coord_idx); + todo!() + // assert!( + // offset + length <= self.len(), + // "offset + length may not exceed length of array" + // ); + // assert!(length >= 1, "length must be at least 1"); + + // // Find the start and end of the ring offsets + // let (start_ring_idx, _) = self.geom_offsets.start_end(offset); + // let (_, end_ring_idx) = self.geom_offsets.start_end(offset + length - 1); + + // // Find the start and end of the coord buffer + // let (start_coord_idx, _) = self.ring_offsets.start_end(start_ring_idx); + // let (_, end_coord_idx) = self.ring_offsets.start_end(end_ring_idx - 1); + + // // Slice the geom_offsets + // let geom_offsets = owned_slice_offsets(&self.geom_offsets, offset, length); + // let ring_offsets = owned_slice_offsets( + // &self.ring_offsets, + // start_ring_idx, + // end_ring_idx - start_ring_idx, + // ); + // let coords = self + // .coords + // .owned_slice(start_coord_idx, end_coord_idx - start_coord_idx); - let validity = owned_slice_validity(self.nulls(), offset, length); + // let validity = owned_slice_validity(self.nulls(), offset, length); - Self::new( - coords, - geom_offsets, - ring_offsets, - validity, - self.metadata(), - ) + // Self::new( + // coords, + // geom_offsets, + // ring_offsets, + // validity, + // self.metadata(), + // ) } pub fn to_coord_type(&self, coord_type: CoordType) -> Self { @@ -317,7 +318,7 @@ impl NativeArray for MultiLineStringArray { } impl GeometryArraySelfMethods for MultiLineStringArray { - fn with_coords(self, coords: CoordBuffer) -> Self { + fn with_coords(self, coords: CoordBuffer) -> Self { assert_eq!(coords.len(), self.coords.len()); Self::new( coords, @@ -357,7 +358,7 @@ impl<'a, const D: usize> crate::trait_::NativeGEOSGeometryAccessor<'a> for Multi index: usize, ) -> std::result::Result { let geom = - MultiLineString::new(&self.coords, &self.geom_offsets, &self.ring_offsets, index); + MultiLineString::::new(&self.coords, &self.geom_offsets, &self.ring_offsets, index); (&geom).try_into() } } @@ -378,7 +379,7 @@ impl IntoArrow for MultiLineStringArray { let vertices_field = self.vertices_field(); let linestrings_field = self.linestrings_field(); let validity = self.validity; - let coord_array = self.coords.into_array_ref(); + let coord_array = self.coords.into_arrow(); let ring_array = Arc::new(GenericListArray::new( vertices_field, self.ring_offsets, @@ -400,7 +401,7 @@ impl TryFrom<&GenericListArray> for MultiLineStringArray let rings_array = rings_dyn_array.as_list::(); let ring_offsets = rings_array.offsets(); - let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; + let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; Ok(Self::new( coords, @@ -423,7 +424,7 @@ impl TryFrom<&GenericListArray> for MultiLineStringArray let rings_array = rings_dyn_array.as_list::(); let ring_offsets = offsets_buffer_i64_to_i32(rings_array.offsets())?; - let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; + let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; Ok(Self::new( coords, diff --git a/rust/geoarrow/src/array/multipoint/array.rs b/rust/geoarrow/src/array/multipoint/array.rs index 6246bd34a..7e78300f7 100644 --- a/rust/geoarrow/src/array/multipoint/array.rs +++ b/rust/geoarrow/src/array/multipoint/array.rs @@ -32,7 +32,7 @@ pub struct MultiPointArray { pub(crate) metadata: Arc, - pub(crate) coords: CoordBuffer, + pub(crate) coords: CoordBuffer, /// Offsets into the coordinate array where each geometry starts pub(crate) geom_offsets: OffsetBuffer, @@ -41,8 +41,8 @@ pub struct MultiPointArray { pub(crate) validity: Option, } -pub(super) fn check( - coords: &CoordBuffer, +pub(super) fn check( + coords: &CoordBuffer, validity_len: Option, geom_offsets: &OffsetBuffer, ) -> Result<()> { @@ -73,7 +73,7 @@ impl MultiPointArray { /// - if the validity is not `None` and its length is different from the number of geometries /// - if the largest geometry offset does not match the number of coordinates pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, validity: Option, metadata: Arc, @@ -92,7 +92,7 @@ impl MultiPointArray { /// - if the validity is not `None` and its length is different from the number of geometries /// - if the geometry offsets do not match the number of coordinates pub fn try_new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, validity: Option, metadata: Arc, @@ -115,11 +115,11 @@ impl MultiPointArray { Field::new("points", self.coords.storage_type(), false).into() } - pub fn coords(&self) -> &CoordBuffer { + pub fn coords(&self) -> &CoordBuffer { &self.coords } - pub fn into_inner(self) -> (CoordBuffer, OffsetBuffer, Option) { + pub fn into_inner(self) -> (CoordBuffer, OffsetBuffer, Option) { (self.coords, self.geom_offsets, self.validity) } @@ -284,7 +284,7 @@ impl NativeArray for MultiPointArray { } impl GeometryArraySelfMethods for MultiPointArray { - fn with_coords(self, coords: CoordBuffer) -> Self { + fn with_coords(self, coords: CoordBuffer) -> Self { assert_eq!(coords.len(), self.coords.len()); Self::new(coords, self.geom_offsets, self.validity, self.metadata) } @@ -311,7 +311,7 @@ impl<'a, const D: usize> crate::trait_::NativeGEOSGeometryAccessor<'a> for Multi &'a self, index: usize, ) -> std::result::Result { - let geom = MultiPoint::new(&self.coords, &self.geom_offsets, index); + let geom = MultiPoint::::new(&self.coords, &self.geom_offsets, index); (&geom).try_into() } } @@ -340,7 +340,7 @@ impl TryFrom<&GenericListArray> for MultiPointArray { type Error = GeoArrowError; fn try_from(value: &GenericListArray) -> Result { - let coords: CoordBuffer = value.values().as_ref().try_into()?; + let coords: CoordBuffer = value.values().as_ref().try_into()?; let geom_offsets = value.offsets(); let validity = value.nulls(); @@ -357,7 +357,7 @@ impl TryFrom<&GenericListArray> for MultiPointArray { type Error = GeoArrowError; fn try_from(value: &GenericListArray) -> Result { - let coords: CoordBuffer = value.values().as_ref().try_into()?; + let coords: CoordBuffer = value.values().as_ref().try_into()?; let geom_offsets = offsets_buffer_i64_to_i32(value.offsets())?; let validity = value.nulls(); diff --git a/rust/geoarrow/src/array/multipolygon/array.rs b/rust/geoarrow/src/array/multipolygon/array.rs index 52c29ab21..f46ac059a 100644 --- a/rust/geoarrow/src/array/multipolygon/array.rs +++ b/rust/geoarrow/src/array/multipolygon/array.rs @@ -33,7 +33,7 @@ pub struct MultiPolygonArray { pub(crate) metadata: Arc, - pub(crate) coords: CoordBuffer, + pub(crate) coords: CoordBuffer, /// Offsets into the polygon array where each geometry starts pub(crate) geom_offsets: OffsetBuffer, @@ -48,8 +48,8 @@ pub struct MultiPolygonArray { pub(crate) validity: Option, } -pub(super) fn check( - coords: &CoordBuffer, +pub(super) fn check( + coords: &CoordBuffer, geom_offsets: &OffsetBuffer, polygon_offsets: &OffsetBuffer, ring_offsets: &OffsetBuffer, @@ -95,7 +95,7 @@ impl MultiPolygonArray { /// - if the largest polygon offset does not match the size of ring offsets /// - if the largest geometry offset does not match the size of polygon offsets pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, polygon_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, @@ -126,7 +126,7 @@ impl MultiPolygonArray { /// - if the largest polygon offset does not match the size of ring offsets /// - if the largest geometry offset does not match the size of polygon offsets pub fn try_new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, polygon_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, @@ -169,14 +169,14 @@ impl MultiPolygonArray { Field::new_list(name, self.rings_field(), false).into() } - pub fn coords(&self) -> &CoordBuffer { + pub fn coords(&self) -> &CoordBuffer { &self.coords } pub fn into_inner( self, ) -> ( - CoordBuffer, + CoordBuffer, OffsetBuffer, OffsetBuffer, OffsetBuffer, @@ -240,50 +240,52 @@ impl MultiPolygonArray { } pub fn owned_slice(&self, offset: usize, length: usize) -> Self { - assert!( - offset + length <= self.len(), - "offset + length may not exceed length of array" - ); - assert!(length >= 1, "length must be at least 1"); - - // Find the start and end of the polygon offsets - let (start_polygon_idx, _) = self.geom_offsets.start_end(offset); - let (_, end_polygon_idx) = self.geom_offsets.start_end(offset + length - 1); - - // Find the start and end of the ring offsets - let (start_ring_idx, _) = self.polygon_offsets.start_end(start_polygon_idx); - let (_, end_ring_idx) = self.polygon_offsets.start_end(end_polygon_idx - 1); + todo!() - // Find the start and end of the coord buffer - let (start_coord_idx, _) = self.ring_offsets.start_end(start_ring_idx); - let (_, end_coord_idx) = self.ring_offsets.start_end(end_ring_idx - 1); - - // Slice the geom_offsets - let geom_offsets = owned_slice_offsets(&self.geom_offsets, offset, length); - let polygon_offsets = owned_slice_offsets( - &self.polygon_offsets, - start_polygon_idx, - end_polygon_idx - start_polygon_idx, - ); - let ring_offsets = owned_slice_offsets( - &self.ring_offsets, - start_ring_idx, - end_ring_idx - start_ring_idx, - ); - let coords = self - .coords - .owned_slice(start_coord_idx, end_coord_idx - start_coord_idx); + // assert!( + // offset + length <= self.len(), + // "offset + length may not exceed length of array" + // ); + // assert!(length >= 1, "length must be at least 1"); + + // // Find the start and end of the polygon offsets + // let (start_polygon_idx, _) = self.geom_offsets.start_end(offset); + // let (_, end_polygon_idx) = self.geom_offsets.start_end(offset + length - 1); + + // // Find the start and end of the ring offsets + // let (start_ring_idx, _) = self.polygon_offsets.start_end(start_polygon_idx); + // let (_, end_ring_idx) = self.polygon_offsets.start_end(end_polygon_idx - 1); + + // // Find the start and end of the coord buffer + // let (start_coord_idx, _) = self.ring_offsets.start_end(start_ring_idx); + // let (_, end_coord_idx) = self.ring_offsets.start_end(end_ring_idx - 1); + + // // Slice the geom_offsets + // let geom_offsets = owned_slice_offsets(&self.geom_offsets, offset, length); + // let polygon_offsets = owned_slice_offsets( + // &self.polygon_offsets, + // start_polygon_idx, + // end_polygon_idx - start_polygon_idx, + // ); + // let ring_offsets = owned_slice_offsets( + // &self.ring_offsets, + // start_ring_idx, + // end_ring_idx - start_ring_idx, + // ); + // let coords = self + // .coords + // .owned_slice(start_coord_idx, end_coord_idx - start_coord_idx); - let validity = owned_slice_validity(self.nulls(), offset, length); + // let validity = owned_slice_validity(self.nulls(), offset, length); - Self::new( - coords, - geom_offsets, - polygon_offsets, - ring_offsets, - validity, - self.metadata(), - ) + // Self::new( + // coords, + // geom_offsets, + // polygon_offsets, + // ring_offsets, + // validity, + // self.metadata(), + // ) } pub fn to_coord_type(&self, coord_type: CoordType) -> Self { @@ -379,7 +381,7 @@ impl NativeArray for MultiPolygonArray { } impl GeometryArraySelfMethods for MultiPolygonArray { - fn with_coords(self, coords: CoordBuffer) -> Self { + fn with_coords(self, coords: CoordBuffer) -> Self { assert_eq!(coords.len(), self.coords.len()); Self::new( coords, @@ -421,7 +423,7 @@ impl<'a, const D: usize> crate::trait_::NativeGEOSGeometryAccessor<'a> for Multi &'a self, index: usize, ) -> std::result::Result { - let geom = MultiPolygon::new( + let geom = MultiPolygon::::new( &self.coords, &self.geom_offsets, &self.polygon_offsets, @@ -488,7 +490,7 @@ impl TryFrom<&GenericListArray> for MultiPolygonArray { let rings_array = rings_dyn_array.as_list::(); let ring_offsets = rings_array.offsets(); - let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; + let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; Ok(Self::new( coords, @@ -516,7 +518,7 @@ impl TryFrom<&GenericListArray> for MultiPolygonArray { let rings_array = rings_dyn_array.as_list::(); let ring_offsets = offsets_buffer_i64_to_i32(rings_array.offsets())?; - let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; + let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; Ok(Self::new( coords, diff --git a/rust/geoarrow/src/array/point/array.rs b/rust/geoarrow/src/array/point/array.rs index 852ba2f39..fd60c89b2 100644 --- a/rust/geoarrow/src/array/point/array.rs +++ b/rust/geoarrow/src/array/point/array.rs @@ -27,14 +27,11 @@ pub struct PointArray { // Always NativeType::Point data_type: NativeType, pub(crate) metadata: Arc, - pub(crate) coords: CoordBuffer, + pub(crate) coords: CoordBuffer, pub(crate) validity: Option, } -pub(super) fn check( - coords: &CoordBuffer, - validity_len: Option, -) -> Result<()> { +pub(super) fn check(coords: &CoordBuffer, validity_len: Option) -> Result<()> { if validity_len.map_or(false, |len| len != coords.len()) { return Err(GeoArrowError::General( "validity mask length must match the number of values".to_string(), @@ -55,7 +52,7 @@ impl PointArray { /// /// - if the validity is not `None` and its length is different from the number of geometries pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, validity: Option, metadata: Arc, ) -> Self { @@ -72,7 +69,7 @@ impl PointArray { /// /// - if the validity is not `None` and its length is different from the number of geometries pub fn try_new( - coords: CoordBuffer, + coords: CoordBuffer, validity: Option, metadata: Arc, ) -> Result { @@ -86,11 +83,11 @@ impl PointArray { }) } - pub fn coords(&self) -> &CoordBuffer { + pub fn coords(&self) -> &CoordBuffer { &self.coords } - pub fn into_inner(self) -> (CoordBuffer, Option) { + pub fn into_inner(self) -> (CoordBuffer, Option) { (self.coords, self.validity) } @@ -123,17 +120,18 @@ impl PointArray { } pub fn owned_slice(&self, offset: usize, length: usize) -> Self { - assert!( - offset + length <= self.len(), - "offset + length may not exceed length of array" - ); - assert!(length >= 1, "length must be at least 1"); + todo!() + // assert!( + // offset + length <= self.len(), + // "offset + length may not exceed length of array" + // ); + // assert!(length >= 1, "length must be at least 1"); - let coords = self.coords.owned_slice(offset, length); + // let coords = self.coords.owned_slice(offset, length); - let validity = owned_slice_validity(self.nulls(), offset, length); + // let validity = owned_slice_validity(self.nulls(), offset, length); - Self::new(coords, validity, self.metadata()) + // Self::new(coords, validity, self.metadata()) } pub fn to_coord_type(&self, coord_type: CoordType) -> Self { @@ -226,7 +224,7 @@ impl NativeArray for PointArray { } impl GeometryArraySelfMethods for PointArray { - fn with_coords(self, coords: CoordBuffer) -> Self { + fn with_coords(self, coords: CoordBuffer) -> Self { assert_eq!(coords.len(), self.coords.len()); Self::new(coords, self.validity, self.metadata) } @@ -248,7 +246,7 @@ impl<'a, const D: usize> crate::trait_::NativeGEOSGeometryAccessor<'a> for Point &'a self, index: usize, ) -> std::result::Result { - let geom = Point::new(&self.coords, index); + let geom = Point::::new(&self.coords, index); (&geom).try_into() } } @@ -267,18 +265,7 @@ impl IntoArrow for PointArray { fn into_arrow(self) -> Self::ArrowArray { let validity = self.validity; - match self.coords { - CoordBuffer::Interleaved(c) => Arc::new(FixedSizeListArray::new( - c.values_field().into(), - D as i32, - Arc::new(c.values_array()), - validity, - )), - CoordBuffer::Separated(c) => { - let fields = c.values_field(); - Arc::new(StructArray::new(fields.into(), c.values_array(), validity)) - } - } + self.coords.into_arrow_with_validity(validity) } } @@ -286,10 +273,8 @@ impl TryFrom<&FixedSizeListArray> for PointArray { type Error = GeoArrowError; fn try_from(value: &FixedSizeListArray) -> Result { - let interleaved_coords: InterleavedCoordBuffer = value.try_into()?; - Ok(Self::new( - CoordBuffer::Interleaved(interleaved_coords), + value.try_into()?, value.nulls().cloned(), Default::default(), )) @@ -303,7 +288,7 @@ impl TryFrom<&StructArray> for PointArray { let validity = value.nulls(); let separated_coords: SeparatedCoordBuffer = value.try_into()?; Ok(Self::new( - CoordBuffer::Separated(separated_coords), + value.try_into()?, validity.cloned(), Default::default(), )) diff --git a/rust/geoarrow/src/array/polygon/array.rs b/rust/geoarrow/src/array/polygon/array.rs index 7151febf1..e6b3601e2 100644 --- a/rust/geoarrow/src/array/polygon/array.rs +++ b/rust/geoarrow/src/array/polygon/array.rs @@ -36,7 +36,7 @@ pub struct PolygonArray { pub(crate) metadata: Arc, - pub(crate) coords: CoordBuffer, + pub(crate) coords: CoordBuffer, /// Offsets into the ring array where each geometry starts pub(crate) geom_offsets: OffsetBuffer, @@ -48,8 +48,8 @@ pub struct PolygonArray { pub(crate) validity: Option, } -pub(super) fn check( - coords: &CoordBuffer, +pub(super) fn check( + coords: &CoordBuffer, geom_offsets: &OffsetBuffer, ring_offsets: &OffsetBuffer, validity_len: Option, @@ -88,7 +88,7 @@ impl PolygonArray { /// - if the largest ring offset does not match the number of coordinates /// - if the largest geometry offset does not match the size of ring offsets pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, validity: Option, @@ -109,7 +109,7 @@ impl PolygonArray { /// - if the largest ring offset does not match the number of coordinates /// - if the largest geometry offset does not match the size of ring offsets pub fn try_new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, validity: Option, @@ -144,7 +144,7 @@ impl PolygonArray { Field::new_list(name, self.vertices_field(), false).into() } - pub fn coords(&self) -> &CoordBuffer { + pub fn coords(&self) -> &CoordBuffer { &self.coords } @@ -193,40 +193,41 @@ impl PolygonArray { } pub fn owned_slice(&self, offset: usize, length: usize) -> Self { - assert!( - offset + length <= self.len(), - "offset + length may not exceed length of array" - ); - assert!(length >= 1, "length must be at least 1"); - - // Find the start and end of the ring offsets - let (start_ring_idx, _) = self.geom_offsets.start_end(offset); - let (_, end_ring_idx) = self.geom_offsets.start_end(offset + length - 1); - - // Find the start and end of the coord buffer - let (start_coord_idx, _) = self.ring_offsets.start_end(start_ring_idx); - let (_, end_coord_idx) = self.ring_offsets.start_end(end_ring_idx - 1); - - // Slice the geom_offsets - let geom_offsets = owned_slice_offsets(&self.geom_offsets, offset, length); - let ring_offsets = owned_slice_offsets( - &self.ring_offsets, - start_ring_idx, - end_ring_idx - start_ring_idx, - ); - let coords = self - .coords - .owned_slice(start_coord_idx, end_coord_idx - start_coord_idx); + todo!() + // assert!( + // offset + length <= self.len(), + // "offset + length may not exceed length of array" + // ); + // assert!(length >= 1, "length must be at least 1"); + + // // Find the start and end of the ring offsets + // let (start_ring_idx, _) = self.geom_offsets.start_end(offset); + // let (_, end_ring_idx) = self.geom_offsets.start_end(offset + length - 1); + + // // Find the start and end of the coord buffer + // let (start_coord_idx, _) = self.ring_offsets.start_end(start_ring_idx); + // let (_, end_coord_idx) = self.ring_offsets.start_end(end_ring_idx - 1); + + // // Slice the geom_offsets + // let geom_offsets = owned_slice_offsets(&self.geom_offsets, offset, length); + // let ring_offsets = owned_slice_offsets( + // &self.ring_offsets, + // start_ring_idx, + // end_ring_idx - start_ring_idx, + // ); + // let coords = self + // .coords + // .owned_slice(start_coord_idx, end_coord_idx - start_coord_idx); - let validity = owned_slice_validity(self.nulls(), offset, length); + // let validity = owned_slice_validity(self.nulls(), offset, length); - Self::new( - coords, - geom_offsets, - ring_offsets, - validity, - self.metadata.clone(), - ) + // Self::new( + // coords, + // geom_offsets, + // ring_offsets, + // validity, + // self.metadata.clone(), + // ) } pub fn to_coord_type(&self, coord_type: CoordType) -> Self { @@ -321,7 +322,7 @@ impl NativeArray for PolygonArray { } impl GeometryArraySelfMethods for PolygonArray { - fn with_coords(self, coords: CoordBuffer) -> Self { + fn with_coords(self, coords: CoordBuffer) -> Self { assert_eq!(coords.len(), self.coords.len()); Self::new( coords, @@ -360,7 +361,7 @@ impl<'a, const D: usize> crate::trait_::NativeGEOSGeometryAccessor<'a> for Polyg &'a self, index: usize, ) -> std::result::Result { - let geom = Polygon::new(&self.coords, &self.geom_offsets, &self.ring_offsets, index); + let geom = Polygon::::new(&self.coords, &self.geom_offsets, &self.ring_offsets, index); (&geom).try_into() } } @@ -403,7 +404,7 @@ impl TryFrom<&GenericListArray> for PolygonArray { let rings_array = rings_dyn_array.as_list::(); let ring_offsets = rings_array.offsets(); - let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; + let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; Ok(Self::new( coords, @@ -426,7 +427,7 @@ impl TryFrom<&GenericListArray> for PolygonArray { let rings_array = rings_dyn_array.as_list::(); let ring_offsets = offsets_buffer_i64_to_i32(rings_array.offsets())?; - let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; + let coords: CoordBuffer = rings_array.values().as_ref().try_into()?; Ok(Self::new( coords, diff --git a/rust/geoarrow/src/array/rect/array.rs b/rust/geoarrow/src/array/rect/array.rs index 67a5c2f1d..a8e731964 100644 --- a/rust/geoarrow/src/array/rect/array.rs +++ b/rust/geoarrow/src/array/rect/array.rs @@ -169,7 +169,7 @@ impl NativeArray for RectArray { } impl GeometryArraySelfMethods for RectArray { - fn with_coords(self, _coords: CoordBuffer) -> Self { + fn with_coords(self, _coords: CoordBuffer) -> Self { unimplemented!() } diff --git a/rust/geoarrow/src/io/geos/scalar/coord/combined.rs b/rust/geoarrow/src/io/geos/scalar/coord/combined.rs index b873ef10a..41d4d1266 100644 --- a/rust/geoarrow/src/io/geos/scalar/coord/combined.rs +++ b/rust/geoarrow/src/io/geos/scalar/coord/combined.rs @@ -3,10 +3,10 @@ use crate::scalar::Coord; use geo_traits::CoordTrait; use geos::{CoordDimensions, CoordSeq}; -impl<'a, const D: usize> TryFrom<&'a Coord<'_, D>> for geos::CoordSeq { +impl<'a> TryFrom<&'a Coord<'_>> for geos::CoordSeq { type Error = geos::Error; - fn try_from(point: &'a Coord<'_, D>) -> std::result::Result { + fn try_from(point: &'a Coord<'_>) -> std::result::Result { use geo_traits::Dimensions; match point.dim() { @@ -30,13 +30,14 @@ impl<'a, const D: usize> TryFrom<&'a Coord<'_, D>> for geos::CoordSeq { } } -impl TryFrom> for CoordSeq { +impl TryFrom for CoordSeq { type Error = geos::Error; - fn try_from(value: CoordBuffer) -> std::result::Result { - match value { - CoordBuffer::Separated(cb) => cb.try_into(), - CoordBuffer::Interleaved(cb) => cb.try_into(), - } + fn try_from(value: CoordBuffer) -> std::result::Result { + todo!() + // match value { + // CoordBuffer::Separated(cb) => cb.try_into(), + // CoordBuffer::Interleaved(cb) => cb.try_into(), + // } } } diff --git a/rust/geoarrow/src/scalar/coord/mod.rs b/rust/geoarrow/src/scalar/coord/mod.rs index 102da2db4..388cfb577 100644 --- a/rust/geoarrow/src/scalar/coord/mod.rs +++ b/rust/geoarrow/src/scalar/coord/mod.rs @@ -1,7 +1,9 @@ mod combined; mod interleaved; +mod scalar; mod separated; -pub use combined::Coord; +pub use scalar::Coord; +// pub use combined::Coord; pub use interleaved::InterleavedCoord; pub use separated::SeparatedCoord; diff --git a/rust/geoarrow/src/scalar/coord/scalar.rs b/rust/geoarrow/src/scalar/coord/scalar.rs new file mode 100644 index 000000000..39261951c --- /dev/null +++ b/rust/geoarrow/src/scalar/coord/scalar.rs @@ -0,0 +1,38 @@ +use geo_traits::CoordTrait; + +use crate::array::CoordBuffer; + +pub struct Coord<'a> { + /// The underlying coord buffer + pub(crate) buffer: &'a CoordBuffer, + + /// The index within the buffer + pub(crate) i: usize, +} + +impl<'a> Coord<'a> { + /// Return `true` if all values in the coordinate are f64::NAN + pub(crate) fn is_nan(&self) -> bool { + (0..self.dim().size()).all(|coord_dim| self.nth_unchecked(coord_dim).is_nan()) + } +} + +impl<'a> CoordTrait for Coord<'a> { + type T = f64; + + fn dim(&self) -> geo_traits::Dimensions { + self.buffer.dim.into() + } + + fn nth_unchecked(&self, n: usize) -> Self::T { + self.buffer.buffers[n][self.i * self.buffer.coords_stride + n] + } + + fn x(&self) -> Self::T { + self.buffer.buffers[0][self.i * self.buffer.coords_stride] + } + + fn y(&self) -> Self::T { + self.buffer.buffers[1][self.i * self.buffer.coords_stride + 1] + } +} diff --git a/rust/geoarrow/src/scalar/linestring/owned.rs b/rust/geoarrow/src/scalar/linestring/owned.rs index ebc4cc085..84e245c8f 100644 --- a/rust/geoarrow/src/scalar/linestring/owned.rs +++ b/rust/geoarrow/src/scalar/linestring/owned.rs @@ -6,7 +6,7 @@ use geo_traits::LineStringTrait; #[derive(Clone, Debug)] pub struct OwnedLineString { - coords: CoordBuffer, + coords: CoordBuffer, /// Offsets into the coordinate array where each geometry starts geom_offsets: OffsetBuffer, @@ -15,7 +15,7 @@ pub struct OwnedLineString { } impl OwnedLineString { - pub fn new(coords: CoordBuffer, geom_offsets: OffsetBuffer, geom_index: usize) -> Self { + pub fn new(coords: CoordBuffer, geom_offsets: OffsetBuffer, geom_index: usize) -> Self { Self { coords, geom_offsets, @@ -52,7 +52,7 @@ impl From> for LineStringArray { impl LineStringTrait for OwnedLineString { type T = f64; - type CoordType<'b> = Coord<'b, D> where Self: 'b; + type CoordType<'b> = Coord<'b> where Self: 'b; fn dim(&self) -> geo_traits::Dimensions { // TODO: pass through field information from array diff --git a/rust/geoarrow/src/scalar/linestring/scalar.rs b/rust/geoarrow/src/scalar/linestring/scalar.rs index 64d0ab11a..31e4432b5 100644 --- a/rust/geoarrow/src/scalar/linestring/scalar.rs +++ b/rust/geoarrow/src/scalar/linestring/scalar.rs @@ -12,7 +12,7 @@ use rstar::{RTreeObject, AABB}; /// An Arrow equivalent of a LineString #[derive(Debug, Clone)] pub struct LineString<'a, const D: usize> { - pub(crate) coords: &'a CoordBuffer, + pub(crate) coords: &'a CoordBuffer, /// Offsets into the coordinate array where each geometry starts pub(crate) geom_offsets: &'a OffsetBuffer, @@ -24,7 +24,7 @@ pub struct LineString<'a, const D: usize> { impl<'a, const D: usize> LineString<'a, D> { pub fn new( - coords: &'a CoordBuffer, + coords: &'a CoordBuffer, geom_offsets: &'a OffsetBuffer, geom_index: usize, ) -> Self { @@ -37,8 +37,8 @@ impl<'a, const D: usize> LineString<'a, D> { } } - pub fn into_owned_inner(self) -> (CoordBuffer, OffsetBuffer, usize) { - let arr = LineStringArray::new( + pub fn into_owned_inner(self) -> (CoordBuffer, OffsetBuffer, usize) { + let arr = LineStringArray::::new( self.coords.clone(), self.geom_offsets.clone(), None, @@ -69,7 +69,7 @@ impl<'a, const D: usize> NativeScalar for LineString<'a, D> { impl<'a, const D: usize> LineStringTrait for LineString<'a, D> { type T = f64; - type CoordType<'b> = Coord<'a, D> where Self: 'b; + type CoordType<'b> = Coord<'a> where Self: 'b; fn dim(&self) -> geo_traits::Dimensions { // TODO: pass through field information from array @@ -92,7 +92,7 @@ impl<'a, const D: usize> LineStringTrait for LineString<'a, D> { impl<'a, const D: usize> LineStringTrait for &'a LineString<'a, D> { type T = f64; - type CoordType<'b> = Coord<'a, D> where Self: 'b; + type CoordType<'b> = Coord<'a> where Self: 'b; fn dim(&self) -> geo_traits::Dimensions { // TODO: pass through field information from array diff --git a/rust/geoarrow/src/scalar/multilinestring/owned.rs b/rust/geoarrow/src/scalar/multilinestring/owned.rs index 69e864a43..32bb99d6a 100644 --- a/rust/geoarrow/src/scalar/multilinestring/owned.rs +++ b/rust/geoarrow/src/scalar/multilinestring/owned.rs @@ -6,7 +6,7 @@ use geo_traits::MultiLineStringTrait; #[derive(Clone, Debug)] pub struct OwnedMultiLineString { - coords: CoordBuffer, + coords: CoordBuffer, /// Offsets into the coordinate array where each geometry starts geom_offsets: OffsetBuffer, @@ -18,7 +18,7 @@ pub struct OwnedMultiLineString { impl OwnedMultiLineString { pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, geom_index: usize, diff --git a/rust/geoarrow/src/scalar/multilinestring/scalar.rs b/rust/geoarrow/src/scalar/multilinestring/scalar.rs index 58e3576fa..9593cb17f 100644 --- a/rust/geoarrow/src/scalar/multilinestring/scalar.rs +++ b/rust/geoarrow/src/scalar/multilinestring/scalar.rs @@ -12,7 +12,7 @@ use rstar::{RTreeObject, AABB}; /// An Arrow equivalent of a MultiLineString #[derive(Debug, Clone)] pub struct MultiLineString<'a, const D: usize> { - pub(crate) coords: &'a CoordBuffer, + pub(crate) coords: &'a CoordBuffer, /// Offsets into the ring array where each geometry starts pub(crate) geom_offsets: &'a OffsetBuffer, @@ -27,7 +27,7 @@ pub struct MultiLineString<'a, const D: usize> { impl<'a, const D: usize> MultiLineString<'a, D> { pub fn new( - coords: &'a CoordBuffer, + coords: &'a CoordBuffer, geom_offsets: &'a OffsetBuffer, ring_offsets: &'a OffsetBuffer, geom_index: usize, @@ -42,8 +42,8 @@ impl<'a, const D: usize> MultiLineString<'a, D> { } } - pub fn into_owned_inner(self) -> (CoordBuffer, OffsetBuffer, OffsetBuffer, usize) { - let arr = MultiLineStringArray::new( + pub fn into_owned_inner(self) -> (CoordBuffer, OffsetBuffer, OffsetBuffer, usize) { + let arr = MultiLineStringArray::::new( self.coords.clone(), self.geom_offsets.clone(), self.ring_offsets.clone(), diff --git a/rust/geoarrow/src/scalar/multipoint/owned.rs b/rust/geoarrow/src/scalar/multipoint/owned.rs index d7b8e384e..985883c85 100644 --- a/rust/geoarrow/src/scalar/multipoint/owned.rs +++ b/rust/geoarrow/src/scalar/multipoint/owned.rs @@ -6,7 +6,7 @@ use geo_traits::MultiPointTrait; #[derive(Clone, Debug)] pub struct OwnedMultiPoint { - coords: CoordBuffer, + coords: CoordBuffer, /// Offsets into the coordinate array where each geometry starts geom_offsets: OffsetBuffer, @@ -15,7 +15,7 @@ pub struct OwnedMultiPoint { } impl OwnedMultiPoint { - pub fn new(coords: CoordBuffer, geom_offsets: OffsetBuffer, geom_index: usize) -> Self { + pub fn new(coords: CoordBuffer, geom_offsets: OffsetBuffer, geom_index: usize) -> Self { Self { coords, geom_offsets, diff --git a/rust/geoarrow/src/scalar/multipoint/scalar.rs b/rust/geoarrow/src/scalar/multipoint/scalar.rs index 83550753f..90eb60c97 100644 --- a/rust/geoarrow/src/scalar/multipoint/scalar.rs +++ b/rust/geoarrow/src/scalar/multipoint/scalar.rs @@ -13,7 +13,7 @@ use rstar::{RTreeObject, AABB}; #[derive(Debug, Clone)] pub struct MultiPoint<'a, const D: usize> { /// Buffer of coordinates - pub(crate) coords: &'a CoordBuffer, + pub(crate) coords: &'a CoordBuffer, /// Offsets into the coordinate array where each geometry starts pub(crate) geom_offsets: &'a OffsetBuffer, @@ -25,7 +25,7 @@ pub struct MultiPoint<'a, const D: usize> { impl<'a, const D: usize> MultiPoint<'a, D> { pub fn new( - coords: &'a CoordBuffer, + coords: &'a CoordBuffer, geom_offsets: &'a OffsetBuffer, geom_index: usize, ) -> Self { @@ -38,8 +38,8 @@ impl<'a, const D: usize> MultiPoint<'a, D> { } } - pub fn into_owned_inner(self) -> (CoordBuffer, OffsetBuffer, usize) { - let arr = MultiPointArray::new( + pub fn into_owned_inner(self) -> (CoordBuffer, OffsetBuffer, usize) { + let arr = MultiPointArray::::new( self.coords.clone(), self.geom_offsets.clone(), None, diff --git a/rust/geoarrow/src/scalar/multipolygon/owned.rs b/rust/geoarrow/src/scalar/multipolygon/owned.rs index 6d38f30c1..44a42594c 100644 --- a/rust/geoarrow/src/scalar/multipolygon/owned.rs +++ b/rust/geoarrow/src/scalar/multipolygon/owned.rs @@ -6,7 +6,7 @@ use geo_traits::MultiPolygonTrait; #[derive(Clone, Debug)] pub struct OwnedMultiPolygon { - coords: CoordBuffer, + coords: CoordBuffer, /// Offsets into the coordinate array where each geometry starts geom_offsets: OffsetBuffer, @@ -20,7 +20,7 @@ pub struct OwnedMultiPolygon { impl OwnedMultiPolygon { pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, polygon_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, diff --git a/rust/geoarrow/src/scalar/multipolygon/scalar.rs b/rust/geoarrow/src/scalar/multipolygon/scalar.rs index 720b0fda8..7b8dd42d0 100644 --- a/rust/geoarrow/src/scalar/multipolygon/scalar.rs +++ b/rust/geoarrow/src/scalar/multipolygon/scalar.rs @@ -12,7 +12,7 @@ use rstar::{RTreeObject, AABB}; /// An Arrow equivalent of a MultiPolygon #[derive(Debug, Clone)] pub struct MultiPolygon<'a, const D: usize> { - pub(crate) coords: &'a CoordBuffer, + pub(crate) coords: &'a CoordBuffer, /// Offsets into the polygon array where each geometry starts pub(crate) geom_offsets: &'a OffsetBuffer, @@ -30,7 +30,7 @@ pub struct MultiPolygon<'a, const D: usize> { impl<'a, const D: usize> MultiPolygon<'a, D> { pub fn new( - coords: &'a CoordBuffer, + coords: &'a CoordBuffer, geom_offsets: &'a OffsetBuffer, polygon_offsets: &'a OffsetBuffer, ring_offsets: &'a OffsetBuffer, @@ -50,13 +50,13 @@ impl<'a, const D: usize> MultiPolygon<'a, D> { pub fn into_owned_inner( self, ) -> ( - CoordBuffer, + CoordBuffer, OffsetBuffer, OffsetBuffer, OffsetBuffer, usize, ) { - let arr = MultiPolygonArray::new( + let arr = MultiPolygonArray::::new( self.coords.clone(), self.geom_offsets.clone(), self.polygon_offsets.clone(), diff --git a/rust/geoarrow/src/scalar/point/owned.rs b/rust/geoarrow/src/scalar/point/owned.rs index 22f307eb1..3f52cea2c 100644 --- a/rust/geoarrow/src/scalar/point/owned.rs +++ b/rust/geoarrow/src/scalar/point/owned.rs @@ -6,16 +6,16 @@ use geo_traits::PointTrait; #[derive(Clone, Debug)] pub struct OwnedPoint { - coords: CoordBuffer, + coords: CoordBuffer, geom_index: usize, } impl OwnedPoint { - pub fn new(coords: CoordBuffer, geom_index: usize) -> Self { + pub fn new(coords: CoordBuffer, geom_index: usize) -> Self { Self { coords, geom_index } } - pub fn coord(&self) -> Coord { + pub fn coord(&self) -> Coord { self.coords.value(self.geom_index) } } @@ -41,7 +41,7 @@ impl From> for PointArray { impl PointTrait for OwnedPoint { type T = f64; - type CoordType<'a> = Coord<'a, D>; + type CoordType<'a> = Coord<'a>; fn dim(&self) -> geo_traits::Dimensions { // TODO: pass through field information from array diff --git a/rust/geoarrow/src/scalar/point/scalar.rs b/rust/geoarrow/src/scalar/point/scalar.rs index d0e2ca168..6540514d4 100644 --- a/rust/geoarrow/src/scalar/point/scalar.rs +++ b/rust/geoarrow/src/scalar/point/scalar.rs @@ -10,20 +10,20 @@ use rstar::{RTreeObject, AABB}; /// An Arrow equivalent of a Point #[derive(Debug, Clone)] pub struct Point<'a, const D: usize> { - coords: &'a CoordBuffer, + coords: &'a CoordBuffer, geom_index: usize, } impl<'a, const D: usize> Point<'a, D> { - pub fn new(coords: &'a CoordBuffer, geom_index: usize) -> Self { + pub fn new(coords: &'a CoordBuffer, geom_index: usize) -> Self { Point { coords, geom_index } } - pub fn coord(&self) -> Coord { + pub fn coord(&self) -> Coord { self.coords.value(self.geom_index) } - pub fn into_owned_inner(self) -> (CoordBuffer, usize) { + pub fn into_owned_inner(self) -> (CoordBuffer, usize) { let coords = self.coords.owned_slice(self.geom_index, 1); (coords, self.geom_index) } @@ -48,7 +48,7 @@ impl<'a, const D: usize> NativeScalar for Point<'a, D> { impl<'a, const D: usize> PointTrait for Point<'a, D> { type T = f64; - type CoordType<'b> = Coord<'a, D> where Self: 'b; + type CoordType<'b> = Coord<'a> where Self: 'b; fn dim(&self) -> geo_traits::Dimensions { // TODO: pass through field information from array @@ -71,7 +71,7 @@ impl<'a, const D: usize> PointTrait for Point<'a, D> { impl<'a, const D: usize> PointTrait for &Point<'a, D> { type T = f64; - type CoordType<'b> = Coord<'a, D> where Self: 'b; + type CoordType<'b> = Coord<'a> where Self: 'b; fn dim(&self) -> geo_traits::Dimensions { // TODO: pass through field information from array @@ -133,16 +133,17 @@ mod test { /// Test Eq where the current index is true but another index is false #[test] fn test_eq_other_index_false() { - let x1 = vec![0., 1., 2.]; - let y1 = vec![3., 4., 5.]; - let buf1 = CoordBuffer::Separated((x1, y1).try_into().unwrap()); - let arr1 = PointArray::new(buf1, None, Default::default()); - - let x2 = vec![0., 100., 2.]; - let y2 = vec![3., 400., 5.]; - let buf2 = CoordBuffer::Separated((x2, y2).try_into().unwrap()); - let arr2 = PointArray::new(buf2, None, Default::default()); - - assert_eq!(arr1.value(0), arr2.value(0)); + todo!() + // let x1 = vec![0., 1., 2.]; + // let y1 = vec![3., 4., 5.]; + // let buf1 = CoordBuffer::Separated((x1, y1).try_into().unwrap()); + // let arr1 = PointArray::new(buf1, None, Default::default()); + + // let x2 = vec![0., 100., 2.]; + // let y2 = vec![3., 400., 5.]; + // let buf2 = CoordBuffer::Separated((x2, y2).try_into().unwrap()); + // let arr2 = PointArray::new(buf2, None, Default::default()); + + // assert_eq!(arr1.value(0), arr2.value(0)); } } diff --git a/rust/geoarrow/src/scalar/polygon/owned.rs b/rust/geoarrow/src/scalar/polygon/owned.rs index 6e5439592..9ad6a28aa 100644 --- a/rust/geoarrow/src/scalar/polygon/owned.rs +++ b/rust/geoarrow/src/scalar/polygon/owned.rs @@ -6,7 +6,7 @@ use geo_traits::PolygonTrait; #[derive(Clone, Debug)] pub struct OwnedPolygon { - coords: CoordBuffer, + coords: CoordBuffer, /// Offsets into the coordinate array where each geometry starts geom_offsets: OffsetBuffer, @@ -18,7 +18,7 @@ pub struct OwnedPolygon { impl OwnedPolygon { pub fn new( - coords: CoordBuffer, + coords: CoordBuffer, geom_offsets: OffsetBuffer, ring_offsets: OffsetBuffer, geom_index: usize, diff --git a/rust/geoarrow/src/scalar/polygon/scalar.rs b/rust/geoarrow/src/scalar/polygon/scalar.rs index 6e9955bfa..21d5fa437 100644 --- a/rust/geoarrow/src/scalar/polygon/scalar.rs +++ b/rust/geoarrow/src/scalar/polygon/scalar.rs @@ -12,7 +12,7 @@ use rstar::{RTreeObject, AABB}; /// An Arrow equivalent of a Polygon #[derive(Debug, Clone)] pub struct Polygon<'a, const D: usize> { - pub(crate) coords: &'a CoordBuffer, + pub(crate) coords: &'a CoordBuffer, /// Offsets into the ring array where each geometry starts pub(crate) geom_offsets: &'a OffsetBuffer, @@ -27,7 +27,7 @@ pub struct Polygon<'a, const D: usize> { impl<'a, const D: usize> Polygon<'a, D> { pub fn new( - coords: &'a CoordBuffer, + coords: &'a CoordBuffer, geom_offsets: &'a OffsetBuffer, ring_offsets: &'a OffsetBuffer, geom_index: usize, @@ -42,8 +42,8 @@ impl<'a, const D: usize> Polygon<'a, D> { } } - pub fn into_owned_inner(self) -> (CoordBuffer, OffsetBuffer, OffsetBuffer, usize) { - let arr = PolygonArray::new( + pub fn into_owned_inner(self) -> (CoordBuffer, OffsetBuffer, OffsetBuffer, usize) { + let arr = PolygonArray::::new( self.coords.clone(), self.geom_offsets.clone(), self.ring_offsets.clone(), diff --git a/rust/geoarrow/src/trait_.rs b/rust/geoarrow/src/trait_.rs index 205976979..99023db25 100644 --- a/rust/geoarrow/src/trait_.rs +++ b/rust/geoarrow/src/trait_.rs @@ -711,7 +711,7 @@ pub trait GeometryArraySelfMethods { /// assert_eq!(value.x(), 3.); /// assert_eq!(value.y(), 4.); /// ``` - fn with_coords(self, coords: CoordBuffer) -> Self; + fn with_coords(self, coords: CoordBuffer) -> Self; /// Casts the coordinate buffer of this geometry array to the given coordinate type. ///