pub mod csv;
pub mod gbfs;
pub mod geotiff;
pub mod gpx;
pub mod grib2;
pub mod gtfs;
pub mod json;
pub mod las;
pub mod nadgrid;
pub mod netcdf;
pub mod osm;
pub mod pmtiles;
pub mod s2tiles;
pub mod shapefile;
#[cfg(feature = "std")]
pub mod tile;
pub mod wkt;
#[cfg(feature = "std")]
use crate::parsers::FileReader;
use crate::parsers::{BufferReader, FeatureReader, Reader};
use alloc::{boxed::Box, collections::BTreeMap, string::String, vec, vec::Vec};
use core::fmt::Debug;
pub use csv::*;
pub use gbfs::*;
pub use geotiff::*;
pub use gpx::*;
pub use grib2::*;
pub use gtfs::*;
pub use json::*;
pub use las::*;
pub use nadgrid::*;
pub use netcdf::*;
pub use osm::*;
pub use pmtiles::*;
use s2json::{MValue, Properties, VectorFeature};
pub use s2tiles::*;
use serde::{Deserialize, Serialize};
pub use shapefile::*;
#[cfg(feature = "std")]
use std::path::Path;
#[cfg(feature = "std")]
pub use tile::*;
pub use wkt::*;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ReaderType {
CSV,
GeoTIFF,
GPX,
GRIB2,
GTFS,
JSON,
JSONLD,
JSONSQ,
LAS,
LAZ,
NADGrid,
NetCDF,
OSM,
Shapefile,
Tile,
WKT,
}
impl From<&str> for ReaderType {
fn from(value: &str) -> Self {
match value {
"csv" => ReaderType::CSV,
"geotiff" | "tif" | "tiff" | "geotif" => ReaderType::GeoTIFF,
"gpx" => ReaderType::GPX,
"grib2" | "grib" => ReaderType::GRIB2,
"gtfs" => ReaderType::GTFS,
"json" | "geojson" | "s2json" => ReaderType::JSON,
"jsonld" | "geojsonld" | "s2jsonld" | "json-ld" | "geojson-ld" | "s2json-ld" => {
ReaderType::JSONLD
}
"jsonsq" | "geojsonseq" | "geojsonsq" | "s2jsonseq" | "s2jsonsq" | "json-seq"
| "json-sq" | "geojson-seq" | "geojson-sq" | "s2json-seq" | "s2json-sq" => {
ReaderType::JSONSQ
}
"las" => ReaderType::LAS,
"laz" => ReaderType::LAZ,
"nadgrid" | "nad" | "gsb" => ReaderType::NADGrid,
"netcdf" | "nc4" | "cdf" | "nc" => ReaderType::NetCDF,
"osm" | "pbf" => ReaderType::OSM,
"shapefile" | "shp" | "zip" => ReaderType::Shapefile,
"wkt" => ReaderType::WKT,
_ => ReaderType::Tile,
}
}
}
#[derive(Debug, Clone)]
pub enum GISReader<T: Reader + Debug> {
CSV(Box<CSVReader<T, Properties>>),
GeoTIFF(Box<GeoTIFFReader<T>>),
GPX(Box<GPXReader>),
GRIB2(Box<GRIB2Reader>),
GTFS(Box<GTFSScheduleReader>),
JSON(Box<JSONReader<T, (), Properties, MValue>>),
JSONLD(Box<NewLineDelimitedJSONReader<T, (), Properties, MValue>>),
JSONSQ(Box<SequenceJSONReader<T, (), Properties, MValue>>),
LAS(Box<LASReader<T>>),
LAZ(Box<LAZReader<T>>),
NADGrid(Box<NadGridReader<T>>),
NetCDF(Box<NetCDFReader<T>>),
OSM(Box<OSMLocalReader<T>>),
Shapefile(Box<ShapeFileReader<T, Properties>>),
WKT(Box<WKTGeometryReader>),
}
impl<T: Reader + Debug> GISReader<T> {
pub fn get_type(&self) -> ReaderType {
match self {
GISReader::CSV(_) => ReaderType::CSV,
GISReader::GeoTIFF(_) => ReaderType::GeoTIFF,
GISReader::GPX(_) => ReaderType::GPX,
GISReader::GRIB2(_) => ReaderType::GRIB2,
GISReader::GTFS(_) => ReaderType::GTFS,
GISReader::JSON(_) => ReaderType::JSON,
GISReader::JSONLD(_) => ReaderType::JSONLD,
GISReader::JSONSQ(_) => ReaderType::JSONSQ,
GISReader::LAS(_) => ReaderType::LAS,
GISReader::LAZ(_) => ReaderType::LAZ,
GISReader::NADGrid(_) => ReaderType::NADGrid,
GISReader::NetCDF(_) => ReaderType::NetCDF,
GISReader::OSM(_) => ReaderType::OSM,
GISReader::Shapefile(_) => ReaderType::Shapefile,
GISReader::WKT(_) => ReaderType::WKT,
}
}
}
impl GISReader<BufferReader> {
pub fn from_buffer(
data: Vec<u8>,
file_type: ReaderType,
epsg_codes: Option<BTreeMap<String, String>>,
) -> GISReader<BufferReader> {
let buffer = BufferReader::new(data);
let epsg_codes = epsg_codes.unwrap_or_default();
match file_type {
ReaderType::CSV => GISReader::CSV(CSVReader::new(buffer, None).into()),
ReaderType::GeoTIFF => GISReader::GeoTIFF(
GeoTIFFReader::new(buffer, Some(GeoTIFFOptions { epsg_codes })).into(),
),
ReaderType::GPX => {
let input_str = buffer.parse_string(None, None);
GISReader::GPX(GPXReader::new(&input_str).into())
}
ReaderType::GRIB2 => GISReader::GRIB2(GRIB2Reader::new(buffer.into(), vec![]).into()),
ReaderType::GTFS => {
GISReader::GTFS(GTFSScheduleReader::from_gzip(&buffer.slice(None, None)).into())
}
ReaderType::JSON => GISReader::JSON(JSONReader::new(buffer).into()),
ReaderType::JSONLD => {
GISReader::JSONLD(NewLineDelimitedJSONReader::new(buffer, None).into())
}
ReaderType::JSONSQ => GISReader::JSONSQ(SequenceJSONReader::new(buffer).into()),
ReaderType::LAS => GISReader::LAS(
LASReader::new(
buffer,
Some(LASReaderOptions { epsg_codes, dont_transform: false }),
)
.into(),
),
ReaderType::LAZ => GISReader::LAZ(
LAZReader::new(
buffer,
Some(LASReaderOptions { epsg_codes, dont_transform: false }),
)
.into(),
),
ReaderType::NADGrid => {
GISReader::NADGrid(NadGridReader::new("default".into(), buffer).into())
}
ReaderType::NetCDF => GISReader::NetCDF(NetCDFReader::new(buffer, None).into()),
ReaderType::OSM => {
let mut osm = OSMLocalReader::new(buffer, None);
osm.parse_blocks();
GISReader::OSM(osm.into())
}
ReaderType::Shapefile => GISReader::Shapefile(
shapefile_from_gzip(&buffer.slice(None, None), epsg_codes).into(),
),
ReaderType::WKT => {
let input_str = buffer.parse_string(None, None);
GISReader::WKT(WKTGeometryReader::new(input_str).into())
}
_ => panic!("Unsupported file type: {file_type:?}"),
}
}
}
#[cfg(feature = "std")]
impl GISReader<FileReader> {
#[cfg(feature = "std")]
pub fn from_path<P: AsRef<Path>>(
file: P,
file_type: Option<ReaderType>,
epsg_codes: Option<BTreeMap<String, String>>,
) -> GISReader<FileReader> {
use crate::readers::file::shapefile_from_path;
use std::{ffi::OsStr, fs};
let path = file.as_ref().to_path_buf();
let path_ending = path.extension().and_then(OsStr::to_str).unwrap_or("");
let file_type: ReaderType = file_type.unwrap_or(path_ending.into());
let epsg_codes = epsg_codes.unwrap_or_default();
match file_type {
ReaderType::CSV => {
GISReader::CSV(CSVReader::new(FileReader::new(file).unwrap(), None).into())
}
ReaderType::GeoTIFF => GISReader::GeoTIFF(
GeoTIFFReader::new(
FileReader::new(file).unwrap(),
Some(GeoTIFFOptions { epsg_codes }),
)
.into(),
),
ReaderType::GPX => {
GISReader::GPX(GPXReader::new(&fs::read_to_string(file).unwrap()).into())
}
ReaderType::GRIB2 => GISReader::GRIB2(
GRIB2Reader::new(FileReader::new(file).unwrap().into(), vec![]).into(),
),
ReaderType::GTFS => {
GISReader::GTFS(GTFSScheduleReader::from_gzip(&fs::read(file).unwrap()).into())
}
ReaderType::JSON => {
GISReader::JSON(JSONReader::new(FileReader::new(file).unwrap()).into())
}
ReaderType::JSONLD => GISReader::JSONLD(
NewLineDelimitedJSONReader::new(FileReader::new(file).unwrap(), None).into(),
),
ReaderType::JSONSQ => {
GISReader::JSONSQ(SequenceJSONReader::new(FileReader::new(file).unwrap()).into())
}
ReaderType::LAS => GISReader::LAS(
LASReader::new(
FileReader::new(file).unwrap(),
Some(LASReaderOptions { epsg_codes, dont_transform: false }),
)
.into(),
),
ReaderType::LAZ => GISReader::LAZ(
LAZReader::new(
FileReader::new(file).unwrap(),
Some(LASReaderOptions { epsg_codes, dont_transform: false }),
)
.into(),
),
ReaderType::NADGrid => GISReader::NADGrid(
NadGridReader::new("default".into(), FileReader::new(file).unwrap()).into(),
),
ReaderType::NetCDF => {
GISReader::NetCDF(NetCDFReader::new(FileReader::new(file).unwrap(), None).into())
}
ReaderType::OSM => {
let mut osm = OSMLocalReader::new(FileReader::new(file).unwrap(), None);
osm.parse_blocks();
GISReader::OSM(osm.into())
}
ReaderType::Shapefile => {
if path_ending == "zip" {
unimplemented!("Shapefile from zip not implemented yet")
} else {
GISReader::Shapefile(shapefile_from_path(file, epsg_codes).into())
}
}
ReaderType::WKT => {
let input_str = fs::read_to_string(file).unwrap();
GISReader::WKT(WKTGeometryReader::new(input_str).into())
}
_ => panic!("Unsupported file type: {file_type:?}"),
}
}
}
#[derive(Debug)]
pub enum GISIterator<'a, T: Reader + Debug> {
CSV(CSVIterator<'a, T, Properties>),
GeoTIFF(GeoTIFFIterator<'a, T>),
GPX(GPXIterator<'a>),
GRIB2(GRIB2Iterator<'a>),
GTFS(GTFSScheduleIterator),
JSON(JSONIterator<'a, T, (), Properties, MValue>),
JSONLD(NewLineDelimitedJSONIterator<'a, T, (), Properties, MValue>),
JSONSQ(SequenceJSONIterator<'a, T, (), Properties, MValue>),
LAS(LASIterator<'a, T>),
LAZ(LAZIterator<'a, T>),
NADGrid(NadGridIterator<'a, T>),
NetCDF(CDFIterator<'a, T>),
OSM(OSMLocalReaderIter<'a, T>),
Shapefile(ShapefileIterator<'a, T, Properties>),
WKT(WKTIterator<'a>),
}
impl<'a, T: Reader + Debug> Iterator for GISIterator<'a, T> {
type Item = VectorFeature<(), Properties, MValue>;
fn next(&mut self) -> Option<Self::Item> {
match self {
GISIterator::CSV(iterator) => iterator.next().map(|f| f.to_m_vector_feature(|_| None)),
GISIterator::GeoTIFF(iterator) => {
iterator.next().map(|f| f.to_m_vector_feature(|_| None))
}
GISIterator::GPX(iterator) => iterator.next().map(|f| f.to_m_vector_feature(|_| None)),
GISIterator::GRIB2(iterator) => {
iterator.next().map(|f| f.to_m_vector_feature(|_| None))
}
GISIterator::GTFS(iterator) => iterator.next(),
GISIterator::JSON(iterator) => iterator.next(),
GISIterator::JSONLD(iterator) => iterator.next(),
GISIterator::JSONSQ(iterator) => iterator.next(),
GISIterator::LAS(iterator) => iterator.next().map(|f| f.to_m_vector_feature(|_| None)),
GISIterator::LAZ(iterator) => iterator.next().map(|f| f.to_m_vector_feature(|_| None)),
GISIterator::NADGrid(iterator) => iterator.next().map(|f| VectorFeature {
_type: f._type,
id: f.id,
face: f.face,
properties: f.properties,
geometry: f.geometry,
metadata: None,
}),
GISIterator::NetCDF(iterator) => iterator.next(),
GISIterator::OSM(iterator) => iterator.next().map(|f| VectorFeature {
_type: f._type,
id: f.id,
face: f.face,
properties: f.properties,
geometry: f.geometry,
metadata: None,
}),
GISIterator::Shapefile(iterator) => iterator.next(),
GISIterator::WKT(iterator) => iterator.next(),
}
}
}
impl<T: Reader + Debug> FeatureReader<(), Properties, MValue> for GISReader<T> {
type FeatureIterator<'a>
= GISIterator<'a, T>
where
T: 'a;
fn iter(&self) -> Self::FeatureIterator<'_> {
match self {
GISReader::CSV(reader) => GISIterator::CSV(reader.iter()),
GISReader::GeoTIFF(reader) => GISIterator::GeoTIFF(reader.iter()),
GISReader::GPX(reader) => GISIterator::GPX(reader.iter()),
GISReader::GRIB2(reader) => GISIterator::GRIB2(reader.iter()),
GISReader::GTFS(reader) => GISIterator::GTFS(reader.iter()),
GISReader::JSON(reader) => GISIterator::JSON(reader.iter()),
GISReader::JSONLD(reader) => GISIterator::JSONLD(reader.iter()),
GISReader::JSONSQ(reader) => GISIterator::JSONSQ(reader.iter()),
GISReader::LAS(reader) => GISIterator::LAS(reader.iter()),
GISReader::LAZ(reader) => GISIterator::LAZ(reader.iter()),
GISReader::NADGrid(reader) => GISIterator::NADGrid(reader.iter()),
GISReader::NetCDF(reader) => GISIterator::NetCDF(reader.iter()),
GISReader::OSM(reader) => GISIterator::OSM(reader.iter()),
GISReader::Shapefile(reader) => GISIterator::Shapefile(reader.iter()),
GISReader::WKT(reader) => GISIterator::WKT(reader.iter()),
}
}
fn par_iter(&self, pool_size: usize, thread_id: usize) -> Self::FeatureIterator<'_> {
match self {
GISReader::CSV(reader) => GISIterator::CSV(reader.par_iter(pool_size, thread_id)),
GISReader::GeoTIFF(reader) => {
GISIterator::GeoTIFF(reader.par_iter(pool_size, thread_id))
}
GISReader::GPX(reader) => GISIterator::GPX(reader.par_iter(pool_size, thread_id)),
GISReader::GRIB2(reader) => GISIterator::GRIB2(reader.par_iter(pool_size, thread_id)),
GISReader::GTFS(reader) => GISIterator::GTFS(reader.par_iter(pool_size, thread_id)),
GISReader::JSON(reader) => GISIterator::JSON(reader.par_iter(pool_size, thread_id)),
GISReader::JSONLD(reader) => GISIterator::JSONLD(reader.par_iter(pool_size, thread_id)),
GISReader::JSONSQ(reader) => GISIterator::JSONSQ(reader.par_iter(pool_size, thread_id)),
GISReader::LAS(reader) => GISIterator::LAS(reader.par_iter(pool_size, thread_id)),
GISReader::LAZ(reader) => GISIterator::LAZ(reader.par_iter(pool_size, thread_id)),
GISReader::NADGrid(reader) => {
GISIterator::NADGrid(reader.par_iter(pool_size, thread_id))
}
GISReader::NetCDF(reader) => GISIterator::NetCDF(reader.par_iter(pool_size, thread_id)),
GISReader::OSM(reader) => GISIterator::OSM(reader.par_iter(pool_size, thread_id)),
GISReader::Shapefile(reader) => {
GISIterator::Shapefile(reader.par_iter(pool_size, thread_id))
}
GISReader::WKT(reader) => GISIterator::WKT(reader.par_iter(pool_size, thread_id)),
}
}
}