From 025d0fcca3f306f232304ca238b07441b0135247 Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Tue, 21 Mar 2023 23:22:29 -0400 Subject: [PATCH] Many improvements to wasm and web frontend --- Cargo.lock | 11 ++ spatial-coordinate-systems/src/dd.rs | 2 +- spatial-coordinate-systems/src/utm.rs | 31 ++++- src/conversions.rs | 2 - src/lib.rs | 7 ++ web-frontend/src/lib/AddressInput.svelte | 2 +- web-frontend/src/lib/CoordinateInput.svelte | 15 ++- web-frontend/src/lib/common.js | 15 --- web-frontend/src/routes/app/+page.svelte | 99 ++++++++-------- words/src/lib.rs | 2 +- xpin-wasm/Cargo.toml | 1 + xpin-wasm/src/lib.rs | 124 ++++++++++---------- 12 files changed, 175 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4524a14..3c28c7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -226,6 +226,16 @@ dependencies = [ "vec_map", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "cookie" version = "0.16.2" @@ -2110,6 +2120,7 @@ dependencies = [ name = "xpin-wasm" version = "0.1.0" dependencies = [ + "console_error_panic_hook", "spatial-coordinate-systems", "wasm-bindgen", "xpin", diff --git a/spatial-coordinate-systems/src/dd.rs b/spatial-coordinate-systems/src/dd.rs index fccfaa7..b5b784a 100644 --- a/spatial-coordinate-systems/src/dd.rs +++ b/spatial-coordinate-systems/src/dd.rs @@ -23,7 +23,7 @@ impl Coordinate { pub fn from(lat: f64, lon: f64) -> Option { if (-90_f64..=90_f64).contains(&lat) && (-180_f64..=180_f64).contains(&lon) { - Some(Self { lat: lat, lon: lon }) + Some(Self { lat, lon }) } else { None } diff --git a/spatial-coordinate-systems/src/utm.rs b/spatial-coordinate-systems/src/utm.rs index 7ed21f7..0dcfb6a 100644 --- a/spatial-coordinate-systems/src/utm.rs +++ b/spatial-coordinate-systems/src/utm.rs @@ -22,12 +22,14 @@ pub struct Coordinate { impl Coordinate { /// ```rust /// use spatial_coordinate_systems::utm::Coordinate; + /// use spatial_coordinate_systems::LatLon; /// /// assert!(Coordinate::parse("10S 706832mE 4344683mN").is_ok()); /// assert!(Coordinate::parse("10S 706832mE 4344683N").is_ok()); /// assert!(Coordinate::parse("10S 706832E 4344683N").is_ok()); /// assert!(Coordinate::parse("10S706832mE 4344683mN").is_err()); /// assert!(Coordinate::parse("10S 706832mE 4344683m").is_ok()); + /// assert!(Coordinate::parse("34H 261877.8163738246 6243185.589276327").is_ok()); /// ``` pub fn parse(i: &str) -> IResult<&str, Self> { map_opt( @@ -39,7 +41,7 @@ impl Coordinate { parse_f64, // TODO: Can there be spaces around the m here or no? opt(complete::char('m')), - // TODO: Should I allow a direction here nor no + // TODO: Should I allow a direction here or not opt(parse_direction), space1, parse_f64, @@ -112,7 +114,7 @@ impl TryFrom for Coordinate { // TODO: This does not feel right let zone_num = utm::lat_lon_to_zone_number(value.lat, value.lon); let zone_letter = utm::lat_to_zone_letter(value.lat).ok_or(())?; - let (easting, northing, _) = utm::to_utm_wgs84(value.lat, value.lon, zone_num); + let (northing, easting, _) = utm::to_utm_wgs84(value.lat, value.lon, zone_num); Ok(Self { zone_num, @@ -122,3 +124,28 @@ impl TryFrom for Coordinate { }) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_general() { + macro_rules! p { + ($tt:tt) => {{ + let cvt = Coordinate::from_str($tt); + eprintln!("Testing: {} => {:?}", $tt, cvt); + assert!(cvt.is_ok()); + eprintln!("Now converting to latlon"); + assert!(dbg!(TryInto::::try_into(cvt.unwrap())).is_ok()); + }}; + } + + dbg!(dbg!(Coordinate::try_from( + LatLon::from(-33.92487_f64, 18.42406_f64).unwrap() + )) + .unwrap() + .to_string()); + p!("34H 261877.8163738246 6243185.589276327"); + } +} diff --git a/src/conversions.rs b/src/conversions.rs index ce6bb09..4d1c1b0 100644 --- a/src/conversions.rs +++ b/src/conversions.rs @@ -11,9 +11,7 @@ use crate::Error; pub fn lat_lon_to_cellid(lat: f64, lon: f64) -> Result { // Wrap the latitudes and longitudes - eprintln!("Pre-lat: {lat},{lon}"); let (lat, lon) = wrap::wrap_latlon(lat, lon); - eprintln!("Post-lat: {lat},{lon}"); if !lat.is_finite() || !lon.is_finite() { return Err(Error::NaNLatLng); diff --git a/src/lib.rs b/src/lib.rs index 429d361..039a84c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -291,6 +291,13 @@ mod tests { } } + #[test] + fn test_general() { + assert!(dbg!(Address::from_str("6532 BROADCAST TINY apple")).is_ok()); + assert!(dbg!(Address::from_str("6532 BROADCAST TINY orange")).is_ok()); + assert!(dbg!(Address::from_lat_lon(0.0, 0.0)).is_ok()); + } + #[test] fn test_parse_v0() { // Regular case diff --git a/web-frontend/src/lib/AddressInput.svelte b/web-frontend/src/lib/AddressInput.svelte index 8d4bdfa..f92d5c0 100644 --- a/web-frontend/src/lib/AddressInput.svelte +++ b/web-frontend/src/lib/AddressInput.svelte @@ -30,6 +30,6 @@ placeholder="Enter address"> type="text" bind:value placeholder="Address" - on:input + on:change /> diff --git a/web-frontend/src/lib/CoordinateInput.svelte b/web-frontend/src/lib/CoordinateInput.svelte index 2937b1b..3bc0167 100644 --- a/web-frontend/src/lib/CoordinateInput.svelte +++ b/web-frontend/src/lib/CoordinateInput.svelte @@ -17,15 +17,14 @@ export let value; - -
- + { - let popup = leaflet.popup(); - try { - addr = getxpin(wasm.call.EncodedAddress.from_lat_lon(latlng.lat, latlng.lng)); - addrInputValue = addr.address; - coordinateInputValue = addr.decimalDegrees; - popup - .setLatLng({ - lat: addr.latLon[0], - lng: addr.latLon[1] - }) - .setContent(`${addr.address}`) - .openOn(map); - } catch (err) { - console.error(err); - addrInputValue = ''; - coordinateInputValue = '0, 0'; - popup.setLatLng(latlng).setContent(`You clicked at ${latlng}`).openOn(map); - } - }; + // const updateEditedAddress = (latlng) => { + // let popup = leaflet.popup(); + // try { + // addr = wasm.call.EncodedAddress.from_lat_lon(latlng.lat, latlng.lng); + // addrInputValue = addr.address; + // coordinateInputValue = addr.decimalDegrees; + // popup + // .setLatLng({ + // lat: addr.latLon[0], + // lng: addr.latLon[1] + // }) + // .setContent(`${addr.address}`) + // .openOn(map); + // } catch (err) { + // console.error(err); + // addrInputValue = ''; + // coordinateInputValue = '0, 0'; + // popup.setLatLng(latlng).setContent(`You clicked at ${latlng}`).openOn(map); + // } + // }; const locationfound = (e) => { console.log('Updating current location event', e); - // kupdateEditedAddress(e.detail.latlng); - updateAddr( - getxpin(wasm.call.EncodedAddress.from_coordinate(`${e.latlng.lat}, ${e.latlng.lng}`)), - false - ); + updateAddr(wasm.call.EncodedAddress.from_coordinate(`${e.latlng.lat}, ${e.latlng.lng}`), false); }; const onMapClick = (e) => { - updateAddr( - getxpin(wasm.call.EncodedAddress.from_coordinate(`${e.latlng.lat}, ${e.latlng.lng}`)), - false - ); + updateAddr(wasm.call.EncodedAddress.from_coordinate(`${e.latlng.lat}, ${e.latlng.lng}`), false); }; let init = async () => { @@ -79,6 +74,13 @@ .then(async () => { leaflet = await import('leaflet'); }) + .then(async () => { + // Initialize the app + updateAddr(wasm.call.EncodedAddress.from_coordinate(coordinateInputValue), true); + }) + .then(async () => { + initSuccess = true; + }) .catch((err) => { console.log('Erroring'); console.error(err); @@ -95,19 +97,20 @@ let outputValue = ' '; const selectedCoordinateTypeChange = () => { - console.log('New type:', selectedCoordinateType); - coordinateInputValue = addr.xpin.get_coords_repr_as( - coordinateTypes.indexOf(selectedCoordinateType) - ); + // Update everything to handle the case where the address is currently invalid + updateAddr(wasm.call.EncodedAddress.from_coordinate(coordinateInputValue), true); + + coordinateInputValue = addr.get_coords_repr_as(coordinateTypes.indexOf(selectedCoordinateType)); }; const coordinateInput = () => { try { - let parsed = wasm.call.EncodedAddress.from_coordinate(coordinateInputValue); + let xpin = wasm.call.EncodedAddress.from_coordinate(coordinateInputValue); - updateAddr(getxpin(parsed), true); + updateAddr(xpin, true); - console.log('parsed:', parsed); + console.log('xpin:', xpin); + selectedCoordinateType = coordinateTypes[xpin.srcCoordsType] || selectedCoordinateType; } catch (e) { console.error('Could not parse coordinate input:', e); } @@ -121,7 +124,9 @@ let latlng = new leaflet.LatLng(addr.latLon[0], addr.latLon[1]); map.panTo(latlng, 20); leaflet.popup().setLatLng(latlng).setContent(`${addr.address}`).openOn(map); - map.setView(latlng); + if (fromTextInput) { + map.setView(latlng); + } outputValue = ' '; addrInputValue = addr.address; @@ -130,13 +135,11 @@ if (fromTextInput) { selectedCoordinateType = coordinateTypes[addr.srcCoordsType] || selectedCoordinateType; coordinateInputValue = addr.srcCoordsRepr || coordinateInputValue; - console.log('hi'); } else { console.log('Getting it in the format of', selectedCoordinateType); - coordinateInputValue = addr.xpin.get_coords_repr_as( + coordinateInputValue = addr.get_coords_repr_as( coordinateTypes.indexOf(selectedCoordinateType) ); - console.log('Result:', coordinateInputValue); } } } catch (e) { @@ -147,7 +150,7 @@ const addressInput = () => { try { - updateAddr(getxpin(wasm.call.EncodedAddress.from_address(addrInputValue)), false); + updateAddr(wasm.call.EncodedAddress.from_address(addrInputValue), false); } catch (e) { console.error(e); outputValue = `${e}`; @@ -174,7 +177,7 @@

Address: {addr.address}

({addr.latLon}) => ({addr.latLon})

- + - - {:catch message} Could not start core module {/await} + + + + diff --git a/words/src/lib.rs b/words/src/lib.rs index fb5a2b3..3f2dcd3 100644 --- a/words/src/lib.rs +++ b/words/src/lib.rs @@ -184,7 +184,7 @@ mod tests { assert_ne!(w2e, w3e); assert_ne!(w1e, w3e); - // Make sure the encoded owrds are not the same + // Make sure the encoded words are not the same assert_ne!(w1e.number, w2e.number); assert_ne!(w2e.number, w3e.number); assert_ne!(w1e.number, w3e.number); diff --git a/xpin-wasm/Cargo.toml b/xpin-wasm/Cargo.toml index 57097a5..f51b579 100644 --- a/xpin-wasm/Cargo.toml +++ b/xpin-wasm/Cargo.toml @@ -12,3 +12,4 @@ crate-type = ["cdylib"] wasm-bindgen = "0.2" xpin = {path=".."} spatial-coordinate-systems = {path="../spatial-coordinate-systems/"} +console_error_panic_hook = "0.1.7" diff --git a/xpin-wasm/src/lib.rs b/xpin-wasm/src/lib.rs index 8a594db..ebc9a0f 100644 --- a/xpin-wasm/src/lib.rs +++ b/xpin-wasm/src/lib.rs @@ -41,61 +41,52 @@ impl From for CoordinateType { } } -#[wasm_bindgen] +#[wasm_bindgen(getter_with_clone)] pub struct EncodedAddress { - address: String, + pub address: String, /// The coordinates used to encode this address - src_coords: Option, - // coords_repr: Option, - pub lat: f64, - pub lon: f64, + src_coords: Coordinate, + #[wasm_bindgen(js_name = srcCoordsRepr)] + pub src_coords_repr: String, + #[wasm_bindgen(js_name = srcCoordsType)] + pub src_coords_type: CoordinateType, + #[wasm_bindgen(js_name = latLon)] + pub lat_lon: Box<[f64]>, + + #[wasm_bindgen(js_name = decimalDegrees)] + pub decimal_degrees: String, } #[wasm_bindgen] impl EncodedAddress { - /// Get the current address as decimal degrees - #[wasm_bindgen] - pub fn get_decimal_degrees(&self) -> String { - format!("{}, {}", self.lat, self.lon) - } - - pub fn get_coords_repr_type(&self) -> Option { - self.src_coords - .as_ref() - .map(|c| c.get_type()) - .map(From::from) - } - - /// Get the string representation of the encoded value - #[wasm_bindgen] - pub fn get_coords_repr(&self) -> Option { - self.src_coords.as_ref().map(|s| s.to_string()) - } - /// Get the string representation of the encoded value #[wasm_bindgen] + // TODO: Do not return option pub fn get_coords_repr_as(&self, coordinate_type: CoordinateType) -> Option { self.src_coords - .clone() - .as_ref() // TODO: Remove the clone here - .map(|c| c.clone().as_type(&coordinate_type.into()).ok()) - .flatten() + .clone() + .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 { - xpin::Address::from_lat_lon(lat, lon) - .as_ref() - .map(EncodedAddress::from) - .map_err(|e| e.to_string()) + Self::try_from( + xpin::Address::from_lat_lon(lat, lon) + .as_ref() + .map_err(|e| e.to_string())?, + ) + .map_err(|()| String::from("Could not convert xpin to address")) } /// 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(|()| format!("Could not parse str as a coordinate {i:?}"))?; @@ -103,43 +94,58 @@ impl EncodedAddress { let latlon = LatLon::try_from(src_coords.clone()) .map_err(|_| format!("Could not convert coordinate back to latlon"))?; - let mut ret = xpin::Address::from_lat_lon(latlon.lat, latlon.lon) - .as_ref() - .map(EncodedAddress::from) - .map_err(|e| e.to_string())?; + let mut ret = Self::try_from( + xpin::Address::from_lat_lon(latlon.lat, latlon.lon) + .as_ref() + .map_err(|e| e.to_string())?, + ) + .map_err(|()| String::from("Could not convert xpin to address"))?; - ret.src_coords = Some(src_coords); + ret.src_coords_repr = src_coords.to_string(); + ret.src_coords_type = src_coords.get_type().into(); + ret.src_coords = src_coords; Ok(ret) } #[wasm_bindgen] pub fn from_address(addr_str: &str) -> Result { - xpin::Address::from_str(addr_str) - .as_ref() - .map(EncodedAddress::from) - .map_err(|e| e.to_string()) - } - - #[wasm_bindgen] - pub fn get_address(&self) -> String { - self.address.clone() - } - - #[wasm_bindgen] - pub fn get_lat_lon(&self) -> Vec { - vec![self.lat, self.lon] + Self::try_from( + xpin::Address::from_str(addr_str) + .as_ref() + .map_err(|e| e.to_string())?, + ) + .map_err(|()| String::from("Could not convert xpin to address")) } } -impl From<&'_ Address<'_>> for EncodedAddress { - fn from(addr: &Address) -> Self { +impl TryFrom<&'_ Address<'_>> for EncodedAddress { + type Error = (); + + fn try_from(addr: &Address) -> Result { + console_error_panic_hook::set_once(); + let (lat, lon) = addr.as_lat_lon(); - Self { + let src_coords = Coordinate::from_str(&format!("{}, {}", lat, lon))?; + + Ok(Self { address: addr.to_string(), - src_coords: None, - lat, - lon, - } + // TODO: Do not use formatting here + lat_lon: Box::new([lat, lon]), + src_coords_repr: src_coords.to_string(), + src_coords_type: src_coords.get_type().into(), + src_coords, + decimal_degrees: format!("{}, {}", lat, lon), + }) } } + +// #[cfg(test)] +// mod tests { +// use super::*; + +// #[test] +// fn test_general() { +// super::from_address("6532 BROADCAST TINY apple") +// } +// }