use std::str::FromStr; use spatial_coordinate_systems::{Coordinate, LatLon}; use wasm_bindgen::prelude::*; use xpin::Address; #[wasm_bindgen] #[derive(Debug, Copy, Clone)] pub enum CoordinateType { DD, DMS, DMM, UTM, // Xpin, Plus, } impl From for spatial_coordinate_systems::CoordinateType { fn from(val: CoordinateType) -> Self { match val { CoordinateType::DD => Self::DD, CoordinateType::DMS => Self::DMS, CoordinateType::DMM => Self::DMM, CoordinateType::UTM => Self::UTM, // CoordinateType::Xpin => Self::Xpin, CoordinateType::Plus => Self::Plus, } } } impl From for CoordinateType { fn from(value: spatial_coordinate_systems::CoordinateType) -> CoordinateType { match value { spatial_coordinate_systems::CoordinateType::DD => Self::DD, spatial_coordinate_systems::CoordinateType::DMS => Self::DMS, spatial_coordinate_systems::CoordinateType::DMM => Self::DMM, spatial_coordinate_systems::CoordinateType::UTM => Self::UTM, // spatial_coordinate_systems::CoordinateType::Xpin => Self::Xpin, spatial_coordinate_systems::CoordinateType::Plus => Self::Plus, } } } #[wasm_bindgen(getter_with_clone)] #[derive(Debug)] pub struct EncodedAddress { pub address: String, /// The coordinates used to encode this address src_coords: Coordinate, #[wasm_bindgen(js_name = latLon)] pub lat_lon: Box<[f64]>, #[wasm_bindgen(js_name = decimalDegrees)] pub decimal_degrees: String, #[wasm_bindgen(js_name = allCoordinates)] pub all_coordinates: Coordinates, } #[wasm_bindgen] impl EncodedAddress { #[wasm_bindgen(js_name = getCoordsType)] pub fn get_coords_type(&self) -> CoordinateType { self.src_coords.get_type().into() } /// Get the string representation of the encoded value #[wasm_bindgen(js_name = getCoordsRepr)] // TODO: Do not return option pub fn get_coords_repr(&self) -> String { self.src_coords.to_string() } /// Get the string representation of the encoded value as a different type #[wasm_bindgen(js_name = getCoordsReprAs)] // TODO: Do not return option pub fn get_coords_repr_as(&self, coordinate_type: CoordinateType) -> Option { self.src_coords // TODO: Remove the clone here .clone() .try_as_type(&coordinate_type.into()) .ok() .map(|s| s.to_string()) } /// Get an encoded address from a latitude/longitude #[wasm_bindgen] pub fn from_lat_lon(lat: f64, lon: f64) -> Result { Self::try_from( xpin::Address::from_lat_lon(lat, lon) .as_ref() .map_err(|e| e.to_string())?, ) .map_err(|e| e.to_string()) } /// Get an encoded address from a latitude/longitude #[wasm_bindgen] pub fn from_coordinate(i: &str) -> Result { console_error_panic_hook::set_once(); let src_coords = Coordinate::from_str(i) .map_err(|e| format!("Could not parse str {i:?} as a coordinate {e:?}"))?; let src_latlon = LatLon::from(&src_coords); let mut ret = Self::try_from( xpin::Address::from_lat_lon(src_latlon.get_lat(), src_latlon.get_lon()) .as_ref() .map_err(|e| e.to_string())?, ) .map_err(|e| e.to_string())?; ret.src_coords = ret .src_coords .try_as_type(&src_coords.get_type().into()) .map_err(|e| e.to_string())? .into(); Ok(ret) } #[wasm_bindgen] pub fn from_address(addr_str: &str) -> Result { Self::try_from( xpin::Address::from_str(addr_str) .as_ref() .map_err(|e| e.to_string())?, ) .map_err(|e| e.to_string()) } } #[wasm_bindgen(getter_with_clone)] #[derive(Debug, Clone)] pub struct Coordinates { // pub latlon: LatLon, pub dd: String, pub dms: String, pub dmm: String, pub utm: String, // pub xpin: String, pub plus: String, } impl From<&spatial_coordinate_systems::all::Coordinates> for Coordinates { fn from(value: &spatial_coordinate_systems::all::Coordinates) -> Self { Self { dd: value.dd.to_string(), dms: value.dms.to_string(), dmm: value.dmm.to_string(), utm: value.utm.to_string(), plus: value.plus.to_string(), } } } impl TryFrom<&'_ Address<'_>> for EncodedAddress { type Error = String; fn try_from(addr: &Address) -> Result { console_error_panic_hook::set_once(); let (lat, lon) = addr.as_lat_lon(); // TODO: Do not allocate a string here let src_coords = Coordinate::from_str(&format!("{}, {}", lat, lon)).map_err(|e| e.to_string())?; let all_coordinates = spatial_coordinate_systems::all::Coordinates::try_from(&src_coords) .map_err(|e| e.to_string())?; Ok(Self { address: addr.to_string(), lat_lon: Box::new([lat, lon]), src_coords, decimal_degrees: format!("{}, {}", lat, lon), all_coordinates: Coordinates::from(&all_coordinates), }) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_general() { // panic!("{:#?}", EncodedAddress::from_lat_lon(50.0, 20.0)); } }