mod geo_ref;
mod transform;
pub use geo_ref::GeoRef;
pub use transform::Transform;
use quick_xml::{
Writer,
events::{BytesEnd, BytesStart, BytesText, Event},
};
use crate::Result;
#[derive(Debug, Clone, Default)]
pub enum CrsType {
#[default]
Local,
Epsg(u16),
Proj4(String),
GaussKrueger(u8),
Utm(i8),
}
impl CrsType {
pub fn get_epsg_code(&self) -> Option<u16> {
match self {
CrsType::Epsg(c) => Some(*c),
CrsType::Proj4(string) => {
if let Some(index) = string.find("+init=epsg:") {
let mut code = 0;
for char in string.chars().skip(index + 11) {
if (48..=57_u8).contains(&(char as u8)) {
code = code * 10 + (char as u8 - 48) as u16;
} else {
break;
}
}
if (1024..=32767).contains(&code) {
Some(code)
} else {
None
}
} else {
None
}
}
_ => None,
}
}
pub fn get_proj_string(&self) -> Option<String> {
match self {
CrsType::Local => None,
CrsType::Epsg(code) => Some(format!("+init=epsg:{}", code)),
CrsType::Proj4(proj_string) => Some(proj_string.clone()),
CrsType::GaussKrueger(code) => {
let lon = 3 * (*code as u16);
let x = 500_000 + (*code as u32 * 1_000_000);
Some(format!(
"+proj=tmerc +lat_0=0 +lon_0={} +k=1.000000 +x_0={} +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs",
lon, x
))
}
CrsType::Utm(code) => {
if *code < 0 {
Some(format!(
"+proj=utm +datum=WGS84 +zone={} +south",
code.abs()
))
} else {
Some(format!("+proj=utm +datum=WGS84 +zone={}", code.abs()))
}
}
}
}
pub(crate) fn write<W: std::io::Write>(self, writer: &mut Writer<W>) -> Result<()> {
let (id, proj_str, parameter) = match self {
CrsType::Local => {
writer.write_event(Event::Start(
BytesStart::new("projected_crs").with_attributes([("id", "Local")]),
))?;
return Ok(());
}
CrsType::Epsg(code) => ("EPSG", format!("+init=epsg:{code}"), format!("{code}")),
CrsType::Proj4(proj_string) => ("PROJ.4", proj_string.clone(), proj_string),
CrsType::GaussKrueger(code) => {
let lon = 3 * (code as u16);
let x = 500_000 + (code as u32 * 1_000_000);
(
"Gauss-Krueger, datum: Potsdam",
format!(
"+proj=tmerc +lat_0=0 +lon_0={lon} +k=1.000000 +x_0={x} +y_0=0 +ellps=bessel +datum=potsdam +units=m +no_defs"
),
format!("{code}"),
)
}
CrsType::Utm(code) => {
let (proj_str, param_str) = if code < 0 {
(
format!("+proj=utm +datum=WGS84 +zone={} +south", code.abs()),
format!("{} S", code.abs()),
)
} else {
(
format!("+proj=utm +datum=WGS84 +zone={}", code.abs()),
format!("{} N", code.abs()),
)
};
("UTM", proj_str, param_str)
}
};
writer.write_event(Event::Start(
BytesStart::new("projected_crs").with_attributes([("id", id)]),
))?;
writer.write_event(Event::Start(
BytesStart::new("spec").with_attributes([("language", "PROJ.4")]),
))?;
writer.write_event(Event::Text(BytesText::new(&proj_str)))?;
writer.write_event(Event::End(BytesEnd::new("spec")))?;
writer.write_event(Event::Start(BytesStart::new("parameter")))?;
writer.write_event(Event::Text(BytesText::new(¶meter)))?;
writer.write_event(Event::End(BytesEnd::new("parameter")))?;
Ok(())
}
}