#![cfg(not(tarpaulin_include))]
use std::{collections::HashMap, ops::Deref};
use chashmap::CHashMap;
use geo::{Coord, Geometry, Intersects, Rect, SimplifyVw, Polygon, LineString, MultiPolygon};
use geojson::{Feature, FeatureCollection, GeoJson};
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
use serde_json::{Map, Value};
use std::path::Path;
#[cfg(feature = "self-contained")]
use bincode::{error::{EncodeError, DecodeError}, enc::Encoder, Encode, Decode, de::{Decoder, BorrowDecoder, read::BorrowReader}, BorrowDecode, config::Configuration};
use crate::base::types::Float;
pub type Id = u32;
pub type RoundDegree = i16;
pub type RoundLngLat = (RoundDegree, RoundDegree);
pub type IdFeaturePair = (usize, geojson::Feature);
#[derive(Debug)]
#[cfg_attr(feature = "self-contained", derive(Encode, Decode))]
pub struct ConcreteVec<T>(Vec<T>)
where
T: 'static;
impl<T> Deref for ConcreteVec<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> From<geojson::FeatureCollection> for ConcreteVec<T>
where
T: From<IdFeaturePair>,
{
fn from(value: geojson::FeatureCollection) -> ConcreteVec<T> {
let values = value.features.into_iter().enumerate().map(T::from).collect::<Vec<T>>();
ConcreteVec(values)
}
}
impl<T> IntoIterator for ConcreteVec<T> {
type IntoIter = std::vec::IntoIter<T>;
type Item = T;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'a, T> IntoIterator for &'a ConcreteVec<T> {
type IntoIter = std::slice::Iter<'a, T>;
type Item = &'a T;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
pub trait HasGeometry {
fn id(&self) -> usize;
fn geometry(&self) -> &Geometry<Float>;
}
pub trait HasProperties {
fn properties(&self) -> Map<String, Value>;
}
pub trait ToGeoJsonFeature {
fn to_feature(&self) -> geojson::Feature;
}
impl<T> ToGeoJsonFeature for T
where
T: HasGeometry + HasProperties,
{
fn to_feature(&self) -> geojson::Feature {
let geometry = self.geometry();
let properties = self.properties();
geojson::Feature {
properties: Some(properties),
geometry: Some(geojson::Geometry::from(geometry)),
..geojson::Feature::default()
}
}
}
pub trait ToGeoJsonFeatureCollection {
fn to_feature_collection(&self) -> geojson::FeatureCollection;
}
impl<'a, L, D, T> ToGeoJsonFeatureCollection for &'a L
where
L: Deref<Target = D>,
D: Deref<Target = [T]>,
T: ToGeoJsonFeature + 'static,
{
fn to_feature_collection(&self) -> geojson::FeatureCollection {
let features = self.iter().map(|x| x.to_feature()).collect();
geojson::FeatureCollection {
features,
bbox: None,
foreign_members: None,
}
}
}
pub trait ToGeoJson {
fn to_geojson(&self) -> GeoJson;
}
impl<T> ToGeoJson for T
where
T: ToGeoJsonFeatureCollection,
{
fn to_geojson(&self) -> GeoJson {
GeoJson::FeatureCollection(self.to_feature_collection())
}
}
pub fn simplify_geometry(geometry: Geometry<Float>, simplification_epsilon: Float) -> Geometry<Float> {
#[cfg(not(feature = "unsimplified"))]
let geometry = match geometry {
Geometry::Polygon(polygon) => {
let simplified = polygon.simplify_vw(&simplification_epsilon);
Geometry::Polygon(simplified)
}
Geometry::MultiPolygon(multi_polygon) => {
let simplified = multi_polygon.simplify_vw(&simplification_epsilon);
Geometry::MultiPolygon(simplified)
}
Geometry::LineString(line_string) => {
let simplified = line_string.simplify_vw(&simplification_epsilon);
Geometry::LineString(simplified)
}
Geometry::MultiLineString(multi_line_string) => {
let simplified = multi_line_string.simplify_vw(&simplification_epsilon);
Geometry::MultiLineString(simplified)
}
g => g,
};
geometry
}
pub fn get_lookup_from_geometries<T>(geometries: &ConcreteVec<T>) -> HashMap<RoundLngLat, EncodableIds>
where
T: HasGeometry + Send + Sync,
{
let map = CHashMap::new();
(-180..180).into_par_iter().for_each(|x| {
for y in -90..90 {
let xf = x as Float;
let yf = y as Float;
let rect = Rect::new(Coord { x: xf, y: yf }, Coord { x: xf + 1.0, y: yf + 1.0 });
let mut intersected = Vec::new();
for g in geometries {
if g.geometry().intersects(&rect) {
intersected.push(g.id() as Id);
}
}
map.insert((x as RoundDegree, y as RoundDegree), intersected);
}
});
let mut cache = HashMap::new();
for (key, value) in map.into_iter() {
cache.insert(key, EncodableIds(value));
}
cache
}
#[cfg(feature = "self-contained")]
fn generate_lookup_bincode<T>(bincode_input: impl AsRef<Path>, bincode_destination: impl AsRef<Path>)
where
T: HasGeometry + Decode + Send + Sync + 'static,
{
let data = std::fs::read(bincode_input).unwrap();
let (timezones, _len): (ConcreteVec<T>, usize) = bincode::decode_from_slice(&data, get_global_bincode_config()).unwrap();
let cache = get_lookup_from_geometries(&timezones);
std::fs::write(bincode_destination, bincode::encode_to_vec(cache, get_global_bincode_config()).unwrap()).unwrap();
}
pub fn get_items_from_features<T>(features: FeatureCollection) -> ConcreteVec<T>
where
T: HasGeometry + From<IdFeaturePair>,
{
ConcreteVec::from(features)
}
#[cfg(feature = "self-contained")]
fn generate_item_bincode<T>(geojson_features: FeatureCollection, bincode_destination: impl AsRef<Path>)
where
T: HasGeometry + Encode + From<IdFeaturePair> + 'static,
{
let items: ConcreteVec<T> = get_items_from_features(geojson_features);
std::fs::write(bincode_destination, bincode::encode_to_vec(items, get_global_bincode_config()).unwrap()).unwrap();
}
pub fn get_geojson_features_from_file(geojson_input: impl AsRef<Path>) -> FeatureCollection {
let geojson = std::fs::read_to_string(geojson_input).unwrap();
FeatureCollection::try_from(geojson.parse::<GeoJson>().unwrap()).unwrap()
}
pub fn get_geojson_features_from_string(geojson_input: &str) -> FeatureCollection {
FeatureCollection::try_from(geojson_input.parse::<GeoJson>().unwrap()).unwrap()
}
pub fn get_geojson_feature_from_file(geojson_input: impl AsRef<Path>) -> Feature {
let geojson = std::fs::read_to_string(geojson_input).unwrap();
Feature::try_from(geojson.parse::<GeoJson>().unwrap()).unwrap()
}
pub fn get_geojson_feature_from_string(geojson_input: &str) -> Feature {
Feature::try_from(geojson_input.parse::<GeoJson>().unwrap()).unwrap()
}
#[cfg(feature = "self-contained")]
pub fn generate_bincodes<T>(geojson_features: FeatureCollection, timezone_bincode_destination: impl AsRef<Path>, lookup_bincode_destination: impl AsRef<Path>)
where
T: HasGeometry + Encode + From<IdFeaturePair> + Decode + Send + Sync + 'static,
{
generate_item_bincode::<T>(geojson_features, timezone_bincode_destination.as_ref());
generate_lookup_bincode::<T>(timezone_bincode_destination, lookup_bincode_destination);
}
pub trait CanGetGeoJsonFeaturesFromSource {
fn get_geojson_features_from_source() -> geojson::FeatureCollection;
}
#[cfg(all(feature = "self-contained", target_endian = "big"))]
pub fn get_global_bincode_config() -> Configuration<bincode::config::BigEndian, bincode::config::Fixint> {
bincode::config::legacy()
.with_big_endian()
}
#[cfg(all(feature = "self-contained", target_endian = "little"))]
pub fn get_global_bincode_config() -> Configuration<bincode::config::LittleEndian, bincode::config::Fixint> {
bincode::config::legacy()
}
#[derive(Debug)]
pub struct EncodableGeometry(pub Geometry<Float>);
#[cfg(feature = "self-contained")]
fn encode_poly<E>(polygon: &Polygon<Float>, encoder: &mut E) -> Result<(), EncodeError>
where
E: Encoder,
{
let exterior = &polygon.exterior().0;
exterior.len().encode(encoder)?;
for point in exterior {
point.x.encode(encoder)?;
point.y.encode(encoder)?;
}
let interiors = polygon.interiors();
interiors.len().encode(encoder)?;
for interior in interiors {
let interior = &interior.0;
interior.len().encode(encoder)?;
for point in interior {
point.x.encode(encoder)?;
point.y.encode(encoder)?;
}
}
Ok(())
}
#[cfg(feature = "self-contained")]
impl Encode for EncodableGeometry {
fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
where
E: Encoder,
{
match &self.0 {
Geometry::Polygon(polygon) => {
0u8.encode(encoder)?;
encode_poly(polygon, encoder)?;
}
Geometry::MultiPolygon(multi_polygon) => {
1u8.encode(encoder)?;
let polygons = &multi_polygon.0;
polygons.len().encode(encoder)?;
for polygon in polygons {
encode_poly(polygon, encoder)?;
}
}
_ => panic!("Unsupported geometry variant."),
}
Ok(())
}
}
#[cfg(feature = "self-contained")]
fn decode_poly<D>(decoder: &mut D) -> Result<Polygon<Float>, DecodeError>
where
D: Decoder,
{
let exterior_len = usize::decode(decoder)?;
let mut exterior = Vec::with_capacity(exterior_len);
for _ in 0..exterior_len {
let x = Float::decode(decoder)?;
let y = Float::decode(decoder)?;
exterior.push(Coord { x, y });
}
let interior_len = usize::decode(decoder)?;
let mut interiors = Vec::with_capacity(interior_len);
for _ in 0..interior_len {
let interior_len = usize::decode(decoder)?;
let mut interior = Vec::with_capacity(interior_len);
for _ in 0..interior_len {
let x = Float::decode(decoder)?;
let y = Float::decode(decoder)?;
interior.push(Coord { x, y });
}
interiors.push(LineString(interior));
}
Ok(Polygon::new(LineString(exterior), interiors))
}
#[cfg(feature = "self-contained")]
fn borrow_decode_poly<'de, D>(decoder: &mut D) -> Result<Polygon<Float>, DecodeError>
where
D: BorrowDecoder<'de>,
{
let exterior_len = usize::decode(decoder)?;
let exterior_slice = decoder.borrow_reader().take_bytes(exterior_len * std::mem::size_of::<Float>() * 2)?;
let exterior = unsafe { Vec::from_raw_parts(exterior_slice.as_ptr() as *mut Coord<Float>, exterior_len, exterior_len) };
let interior_len = usize::decode(decoder)?;
let mut interiors = Vec::with_capacity(interior_len);
for _ in 0..interior_len {
let interior_len = usize::decode(decoder)?;
let interior_slice = decoder.borrow_reader().take_bytes(interior_len * std::mem::size_of::<Float>() * 2)?;
let interior = unsafe { Vec::from_raw_parts(interior_slice.as_ptr() as *mut Coord<Float>, interior_len, interior_len) };
interiors.push(LineString(interior));
}
Ok(Polygon::new(LineString(exterior), interiors))
}
#[cfg(feature = "self-contained")]
impl Decode for EncodableGeometry
{
fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
where
D: Decoder,
{
let variant = u8::decode(decoder)?;
let geometry = match variant {
0 => {
let polygon = decode_poly(decoder)?;
Geometry::Polygon(polygon)
}
1 => {
let polygon_len = usize::decode(decoder)?;
let mut polygons = Vec::with_capacity(polygon_len);
for _ in 0..polygon_len {
let polygon = decode_poly(decoder)?;
polygons.push(polygon);
}
Geometry::MultiPolygon(MultiPolygon::new(polygons))
}
_ => panic!("Unsupported geometry variant."),
};
Ok(EncodableGeometry(geometry))
}
}
#[cfg(feature = "self-contained")]
impl<'de> BorrowDecode<'de> for EncodableGeometry {
fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
where
D: BorrowDecoder<'de>,
{
let variant = u8::decode(decoder)?;
let geometry = match variant {
0 => {
let polygon = borrow_decode_poly(decoder)?;
Geometry::Polygon(polygon)
}
1 => {
let polygon_len = usize::decode(decoder)?;
let mut polygons = Vec::with_capacity(polygon_len);
for _ in 0..polygon_len {
let polygon = borrow_decode_poly(decoder)?;
polygons.push(polygon);
}
Geometry::MultiPolygon(MultiPolygon::new(polygons))
}
_ => panic!("Unsupported geometry variant."),
};
Ok(EncodableGeometry(geometry))
}
}
#[derive(Debug)]
pub struct EncodableIds(pub Vec<Id>);
impl Deref for EncodableIds {
type Target = Vec<Id>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl AsRef<[Id]> for EncodableIds {
fn as_ref(&self) -> &[Id] {
&self.0
}
}
#[cfg(feature = "self-contained")]
impl Encode for EncodableIds {
fn encode<E>(&self, encoder: &mut E) -> Result<(), EncodeError>
where
E: Encoder,
{
self.0.len().encode(encoder)?;
for x in &self.0 {
x.encode(encoder)?;
}
Ok(())
}
}
#[cfg(feature = "self-contained")]
impl Decode for EncodableIds
{
fn decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
where
D: Decoder,
{
let len = usize::decode(decoder)?;
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
let x = Id::decode(decoder)?;
vec.push(x);
}
Ok(EncodableIds(vec))
}
}
#[cfg(feature = "self-contained")]
impl<'de> BorrowDecode<'de> for EncodableIds {
fn borrow_decode<D>(decoder: &mut D) -> Result<Self, DecodeError>
where
D: BorrowDecoder<'de>,
{
let len = usize::decode(decoder)?;
let slice = decoder.borrow_reader().take_bytes(len * std::mem::size_of::<Id>())?;
let vec = unsafe { Vec::from_raw_parts(slice.as_ptr() as *mut Id, len, len) };
Ok(EncodableIds(vec))
}
}