geoarrow2/array/geometrycollection/
array.rsuse std::collections::HashMap;
use std::sync::Arc;
use arrow_array::{Array, GenericListArray, OffsetSizeTrait};
use arrow_buffer::bit_iterator::BitIterator;
use arrow_buffer::{NullBuffer, OffsetBuffer};
use arrow_schema::{DataType, Field};
use crate::array::zip_validity::ZipValidity;
use crate::array::{CoordBuffer, CoordType, MixedGeometryArray};
use crate::datatypes::GeoDataType;
use crate::scalar::GeometryCollection;
use crate::trait_::{GeoArrayAccessor, IntoArrow};
use crate::GeometryArrayTrait;
#[derive(Debug, Clone)]
pub struct GeometryCollectionArray<O: OffsetSizeTrait> {
data_type: GeoDataType,
pub array: MixedGeometryArray<O>,
pub geom_offsets: OffsetBuffer<O>,
pub validity: Option<NullBuffer>,
}
impl<O: OffsetSizeTrait> GeometryCollectionArray<O> {
pub fn new(
array: MixedGeometryArray<O>,
geom_offsets: OffsetBuffer<O>,
validity: Option<NullBuffer>,
) -> Self {
let coord_type = array.coord_type();
let data_type = match O::IS_LARGE {
true => GeoDataType::LargeGeometryCollection(coord_type),
false => GeoDataType::GeometryCollection(coord_type),
};
Self {
data_type,
array,
geom_offsets,
validity,
}
}
fn mixed_field(&self) -> Arc<Field> {
self.array.extension_field()
}
fn geometries_field(&self) -> Arc<Field> {
let name = "geometries";
match O::IS_LARGE {
true => Field::new_large_list(name, self.mixed_field(), false).into(),
false => Field::new_list(name, self.mixed_field(), false).into(),
}
}
}
impl<'a, O: OffsetSizeTrait> GeometryArrayTrait<'a> for GeometryCollectionArray<O> {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn data_type(&self) -> &GeoDataType {
&self.data_type
}
fn storage_type(&self) -> DataType {
todo!()
}
fn extension_field(&self) -> Arc<Field> {
let mut metadata = HashMap::new();
metadata.insert(
"ARROW:extension:name".to_string(),
self.extension_name().to_string(),
);
Arc::new(Field::new("geometry", self.storage_type(), true).with_metadata(metadata))
}
fn extension_name(&self) -> &str {
"geoarrow.geometrycollection"
}
fn into_array_ref(self) -> Arc<dyn Array> {
Arc::new(self.into_arrow())
}
fn with_coords(self, _coords: CoordBuffer) -> Self {
todo!()
}
fn coord_type(&self) -> CoordType {
todo!()
}
fn into_coord_type(self, _coord_type: CoordType) -> Self {
todo!()
}
#[inline]
fn len(&self) -> usize {
self.geom_offsets.len() - 1
}
#[inline]
fn validity(&self) -> Option<&NullBuffer> {
self.validity.as_ref()
}
#[inline]
fn slice(&self, offset: usize, length: usize) -> Self {
assert!(
offset + length <= self.len(),
"offset + length may not exceed length of array"
);
Self {
data_type: self.data_type.clone(),
array: self.array.clone(),
geom_offsets: self.geom_offsets.slice(offset, length),
validity: self.validity.as_ref().map(|v| v.slice(offset, length)),
}
}
fn owned_slice(&self, _offset: usize, _length: usize) -> Self {
todo!()
}
}
impl<'a, O: OffsetSizeTrait> GeoArrayAccessor<'a> for GeometryCollectionArray<O> {
type Item = GeometryCollection<'a, O>;
type ItemGeo = geo::GeometryCollection;
unsafe fn value_unchecked(&'a self, index: usize) -> Self::Item {
GeometryCollection {
array: &self.array,
geom_offsets: &self.geom_offsets,
geom_index: index,
}
}
}
impl<O: OffsetSizeTrait> IntoArrow for GeometryCollectionArray<O> {
type ArrowArray = GenericListArray<O>;
fn into_arrow(self) -> Self::ArrowArray {
let geometries_field = self.geometries_field();
let validity = self.validity;
let values = self.array.into_array_ref();
GenericListArray::new(geometries_field, self.geom_offsets, values, validity)
}
}
impl<O: OffsetSizeTrait> GeometryCollectionArray<O> {
pub fn iter_geo_values(&self) -> impl Iterator<Item = geo::GeometryCollection> + '_ {
(0..self.len()).map(|i| self.value_as_geo(i))
}
pub fn iter_geo(
&self,
) -> ZipValidity<
geo::GeometryCollection,
impl Iterator<Item = geo::GeometryCollection> + '_,
BitIterator,
> {
ZipValidity::new_with_validity(self.iter_geo_values(), self.nulls())
}
#[cfg(feature = "geos")]
pub fn value_as_geos(&self, i: usize) -> geos::Geometry {
self.value(i).try_into().unwrap()
}
#[cfg(feature = "geos")]
pub fn get_as_geos(&self, i: usize) -> Option<geos::Geometry> {
if self.is_null(i) {
return None;
}
Some(self.value_as_geos(i))
}
#[cfg(feature = "geos")]
pub fn iter_geos_values(&self) -> impl Iterator<Item = geos::Geometry> + '_ {
(0..self.len()).map(|i| self.value_as_geos(i))
}
#[cfg(feature = "geos")]
pub fn iter_geos(
&self,
) -> ZipValidity<geos::Geometry, impl Iterator<Item = geos::Geometry> + '_, BitIterator> {
ZipValidity::new_with_validity(self.iter_geos_values(), self.nulls())
}
}