diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 38325b3..8317113 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -169,7 +169,7 @@ jobs: - name: Publish to PyPI uses: PyO3/maturin-action@v1 env: - MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_PASSWORD }} with: command: upload args: --non-interactive --skip-existing wheels-*/* diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 0506d35..3239c4c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,5 +1,13 @@ name: Rust build and test -on: push +on: + push: + branches: + - main + - master + tags: + - '*' + pull_request: + workflow_dispatch: jobs: stable: runs-on: ${{matrix.platform}} diff --git a/build.rs b/build.rs index e0249b4..4fcb0ca 100644 --- a/build.rs +++ b/build.rs @@ -1,14 +1,22 @@ +use path_slash::PathExt; use std::env; use std::fs; use std::io::prelude::*; use std::path::Path; -use path_slash::PathExt; pub static GSHHS_F: &str = "gshhs_f_-180.000000E-90.000000N180.000000E90.000000N.wkb.xz"; pub static GSHHS_F_CS: &str = "05bdf3089407b9829a7a5be7ee43f1e4205f2bbc641e4778af77e4814be216da"; -pub static MASK: &str = "mask.tbmap.xz"; -pub static MASK_CS: &str = "5ea0e772ffc6ca8ad10c5de02be50670cbaedcff20b3541df6b78d3e1fdf48a1"; +pub static GSHHG_MASK: &str = "gshhg_mask.tbmap.xz"; +pub static GSHHG_MASK_SHA256: &str = + "5ea0e772ffc6ca8ad10c5de02be50670cbaedcff20b3541df6b78d3e1fdf48a1"; + +pub static OSM: &str = "osm.wkb.xz"; +pub static OSM_SHA256: &str = "7cbbbb56dc8f6a339d837e57aac4c50c9f54e7ac1118803274725cf61226b727"; + +pub static OSM_MASK: &str = "osm_mask.tbmap.xz"; +pub static OSM_MASK_SHA256: &str = + "e60dd30737ad8480619d727bb246a1107d30a66563b73628337dc3f92255b684"; fn main() { println!("hello"); @@ -30,15 +38,17 @@ use rust_embed::RustEmbed; #[folder = \"{}\"] pub struct GsshgData; - ", - assets_dir.to_slash().unwrap() - ) - .unwrap(); - } +#[derive(RustEmbed)] +#[folder = \"{}\"] +pub struct OsmData; + ", + assets_dir.to_slash().unwrap(), + assets_dir.to_slash().unwrap() + ) + .unwrap(); - let gshhs = Path::new(&out_dir).join("gshhs"); - if !gshhs.exists() { - fs::create_dir(gshhs).unwrap(); + if !assets_dir.exists() { + fs::create_dir(assets_dir).unwrap(); } // copy or download files @@ -83,6 +93,9 @@ fn copy_or_download(from: impl AsRef, csum: &str) { if &expected != &actual.as_ref() { // Delete erronous file fs::remove_file(&full_to).unwrap(); - panic!("Checksum mismatched for {:?}, downloaded file deleted..", &from); + panic!( + "Checksum mismatched for {:?}, downloaded file deleted..", + &from + ); } } diff --git a/src/devel/make_bitmap.rs b/src/devel/make_bitmap.rs index 4bd42d8..9873f56 100644 --- a/src/devel/make_bitmap.rs +++ b/src/devel/make_bitmap.rs @@ -1,6 +1,6 @@ -use std::io::prelude::*; -use std::fs::File; use roaring::*; +use std::fs::File; +use std::io::prelude::*; fn main() -> std::io::Result<()> { println!("opening mask.bin.."); @@ -33,7 +33,10 @@ fn main() -> std::io::Result<()> { } } - println!("serialized size: {} mb", tmap.serialized_size() / 1024 / 1024); + println!( + "serialized size: {} mb", + tmap.serialized_size() / 1024 / 1024 + ); println!("serializing bitmap to file: mask.tbmap.."); { diff --git a/src/lib.rs b/src/lib.rs index ff9962a..b063fa3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,10 +71,12 @@ use pyo3::prelude::*; use std::io; pub mod mask; +pub mod providers; pub mod shapes; pub use mask::RoaringMask; -pub use shapes::Gshhg; +pub use providers::LandmaskProvider; +pub use shapes::Shapes; include!(concat!(env!("OUT_DIR"), "/gshhs.rs")); @@ -100,8 +102,16 @@ pub struct RoaringLandmask { impl RoaringLandmask { #[staticmethod] pub fn new(py: Python) -> io::Result { - let mask = RoaringMask::new()?; - let shapes = Gshhg::new(py)?; + Self::new_with_provider(py, LandmaskProvider::Gshhg) + } + + #[staticmethod] + pub fn new_with_provider( + py: Python, + landmask_provider: LandmaskProvider, + ) -> io::Result { + let mask = RoaringMask::new(landmask_provider)?; + let shapes = Shapes::new(py, landmask_provider)?; Ok(RoaringLandmask { mask, shapes }) } @@ -213,23 +223,20 @@ mod tests { fn test_dateline_wrap() { pyo3::prepare_freethreaded_python(); pyo3::Python::with_gil(|py| { - let mask = RoaringLandmask::new(py).unwrap(); - - // Close to NP - assert!(!mask.contains(5., 89.)); - - // Close to SP - assert!(mask.contains(5., -89.)); - - // Within bounds - let x = (-180..180).map(f64::from).collect::>(); - let m = x.iter().map(|x| mask.contains(*x, 65.)).collect::>(); - - // Wrapped bounds - let x = (180..540).map(f64::from).collect::>(); - let mm = x.iter().map(|x| mask.contains(*x, 65.)).collect::>(); - - assert_eq!(m, mm); + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringLandmask::new(py, provider).unwrap(); + // Close to NP + assert!(!mask.contains(5., 89.)); + // Close to SP + assert!(mask.contains(5., -89.)); + // Within bounds + let x = (-180..180).map(f64::from).collect::>(); + let m = x.iter().map(|x| mask.contains(*x, 65.)).collect::>(); + // Wrapped bounds + let x = (180..540).map(f64::from).collect::>(); + let mm = x.iter().map(|x| mask.contains(*x, 65.)).collect::>(); + assert_eq!(m, mm); + } }) } @@ -262,12 +269,12 @@ mod tests { fn test_contains_on_land(b: &mut Bencher) { pyo3::prepare_freethreaded_python(); pyo3::Python::with_gil(|py| { - let mask = RoaringLandmask::new(py).unwrap(); - - assert!(mask.contains(15., 65.6)); - assert!(mask.contains(10., 60.0)); - - b.iter(|| mask.contains(15., 65.6)) + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringLandmask::new(py, provider).unwrap(); + assert!(mask.contains(15., 65.6)); + assert!(mask.contains(10., 60.0)); + b.iter(|| mask.contains(15., 65.6)); + } }) } @@ -275,11 +282,11 @@ mod tests { fn test_contains_in_ocean(b: &mut Bencher) { pyo3::prepare_freethreaded_python(); pyo3::Python::with_gil(|py| { - let mask = RoaringLandmask::new(py).unwrap(); - - assert!(!mask.contains(5., 65.6)); - - b.iter(|| mask.contains(5., 65.6)); + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringLandmask::new(py, provider).unwrap(); + assert!(!mask.contains(5., 65.6)); + b.iter(|| mask.contains(5., 65.6)); + } }); } @@ -287,44 +294,39 @@ mod tests { fn test_contains_many(b: &mut Bencher) { pyo3::prepare_freethreaded_python(); pyo3::Python::with_gil(|py| { - let mask = RoaringLandmask::new(py).unwrap(); - - let (x, y): (Vec, Vec) = (0..360 * 2) - .map(|v| v as f64 * 0.5 - 180.) - .map(|x| { - (0..180 * 2) - .map(|y| y as f64 * 0.5 - 90.) - .map(move |y| (x, y)) - }) - .flatten() - .unzip(); - - let mask = RoaringLandmask::new(py).unwrap(); - - let (x, y): (Vec, Vec) = (0..360 * 2) - .map(|v| v as f64 * 0.5 - 180.) - .map(|x| { - (0..180 * 2) - .map(|y| y as f64 * 0.5 - 90.) - .map(move |y| (x, y)) - }) - .flatten() - .unzip(); - - let x = PyArray::from_vec(py, x); - let y = PyArray::from_vec(py, y); - - println!("testing {} points..", x.len()); - - b.iter(|| { - let len = x.len(); - - let x = x.to_dyn().readonly(); - let y = y.to_dyn().readonly(); - - let onland = mask.contains_many(py, x, y); - assert!(onland.as_ref(py).len() == len); - }) + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringLandmask::new(py, provider).unwrap(); + let (x, y): (Vec, Vec) = (0..360 * 2) + .map(|v| v as f64 * 0.5 - 180.) + .map(|x| { + (0..180 * 2) + .map(|y| y as f64 * 0.5 - 90.) + .map(move |y| (x, y)) + }) + .flatten() + .unzip(); + let (x, y): (Vec, Vec) = (0..360 * 2) + .map(|v| v as f64 * 0.5 - 180.) + .map(|x| { + (0..180 * 2) + .map(|y| y as f64 * 0.5 - 90.) + .map(move |y| (x, y)) + }) + .flatten() + .unzip(); + let x = PyArray::from_vec(py, x); + let y = PyArray::from_vec(py, y); + println!("testing {} points..", x.len()); + b.iter(|| { + let len = x.len(); + + let x = x.to_dyn().readonly(); + let y = y.to_dyn().readonly(); + + let onland = mask.contains_many(py, x, y); + assert!(onland.as_ref(py).len() == len); + }); + } }) } @@ -333,44 +335,39 @@ mod tests { fn test_contains_many_par(b: &mut Bencher) { pyo3::prepare_freethreaded_python(); pyo3::Python::with_gil(|py| { - let mask = RoaringLandmask::new(py).unwrap(); - - let (x, y): (Vec, Vec) = (0..360 * 2) - .map(|v| v as f64 * 0.5 - 180.) - .map(|x| { - (0..180 * 2) - .map(|y| y as f64 * 0.5 - 90.) - .map(move |y| (x, y)) - }) - .flatten() - .unzip(); - - let mask = RoaringLandmask::new(py).unwrap(); - - let (x, y): (Vec, Vec) = (0..360 * 2) - .map(|v| v as f64 * 0.5 - 180.) - .map(|x| { - (0..180 * 2) - .map(|y| y as f64 * 0.5 - 90.) - .map(move |y| (x, y)) - }) - .flatten() - .unzip(); - - let x = PyArray::from_vec(py, x); - let y = PyArray::from_vec(py, y); - - println!("testing {} points..", x.len()); - - b.iter(|| { - let len = x.len(); - - let x = x.to_dyn().readonly(); - let y = y.to_dyn().readonly(); - - let onland = mask.contains_many_par(py, x, y); - assert!(onland.as_ref(py).len() == len); - }) + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringLandmask::new(py, provider).unwrap(); + let (x, y): (Vec, Vec) = (0..360 * 2) + .map(|v| v as f64 * 0.5 - 180.) + .map(|x| { + (0..180 * 2) + .map(|y| y as f64 * 0.5 - 90.) + .map(move |y| (x, y)) + }) + .flatten() + .unzip(); + let (x, y): (Vec, Vec) = (0..360 * 2) + .map(|v| v as f64 * 0.5 - 180.) + .map(|x| { + (0..180 * 2) + .map(|y| y as f64 * 0.5 - 90.) + .map(move |y| (x, y)) + }) + .flatten() + .unzip(); + let x = PyArray::from_vec(py, x); + let y = PyArray::from_vec(py, y); + println!("testing {} points..", x.len()); + b.iter(|| { + let len = x.len(); + + let x = x.to_dyn().readonly(); + let y = y.to_dyn().readonly(); + + let onland = mask.contains_many_par(py, x, y); + assert!(onland.as_ref(py).len() == len); + }); + } }) } } diff --git a/src/mask.rs b/src/mask.rs index 4470173..7f9e51b 100644 --- a/src/mask.rs +++ b/src/mask.rs @@ -84,8 +84,15 @@ impl RoaringMask { impl RoaringMask { #[staticmethod] /// Make a new mask. - pub fn new() -> io::Result { + pub fn new(provider: LandmaskProvider) -> io::Result { use crate::GsshgData; + use crate::OsmData; + + let buf = match provider { + LandmaskProvider::Gshhg => GsshgData::get(&GSHHG), + LandmaskProvider::Osm => OsmData::get(&OSM), + } + .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "cannot find mask"))?; let buf = GsshgData::get("mask.tbmap.xz") .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "cannot find mask"))?; @@ -186,22 +193,27 @@ mod tests { fn required_size() { println!("upper bound coordinate system: {}", NY * NX); - let mask = RoaringMask::new().unwrap(); - println!("maximum in tree: {:?}", mask.tmap.max()); - - assert!(mask.tmap.max().unwrap() <= std::u32::MAX as u64); + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringMask::new(provider).unwrap(); + println!("maximum in tree: {:?}", mask.tmap.max()); + assert!(mask.tmap.max().unwrap() <= std::u32::MAX as u64); + } } #[test] fn test_np() { - let mask = RoaringMask::new().unwrap(); - assert!(!mask.contains(5., 90.)); + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringMask::new(provider).unwrap(); + assert!(!mask.contains(5., 90.)); + } } #[test] fn test_sp() { - let mask = RoaringMask::new().unwrap(); - assert!(mask.contains(5., -90.)); + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringMask::new(provider).unwrap(); + assert!(mask.contains(5., -90.)); + } } #[cfg(feature = "nightly")] @@ -212,7 +224,9 @@ mod tests { #[bench] fn load_tmap(b: &mut Bencher) { b.iter(|| { - let _mask = RoaringMask::new().unwrap(); + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let _mask = RoaringMask::new(provider).unwrap(); + } }) } @@ -242,33 +256,50 @@ mod tests { #[bench] fn test_contains_on_land(b: &mut Bencher) { - let mask = RoaringMask::new().unwrap(); + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringMask::new(provider).unwrap(); - assert!(mask.contains(15., 65.6)); - assert!(mask.contains(10., 60.0)); + assert!(mask.contains(15., 65.6)); + assert!(mask.contains(10., 60.0)); - b.iter(|| mask.contains(15., 65.6)) + b.iter(|| mask.contains(15., 65.6)) + } } #[bench] fn test_contains_in_ocean(b: &mut Bencher) { - let mask = RoaringMask::new().unwrap(); + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringMask::new(provider).unwrap(); - assert!(!mask.contains(5., 65.6)); + assert!(!mask.contains(5., 65.6)); - b.iter(|| mask.contains(5., 65.6)) + b.iter(|| mask.contains(5., 65.6)) + } } #[bench] fn test_contains_many(b: &mut Bencher) { - let mask = RoaringMask::new().unwrap(); - - let (x, y): (Vec, Vec) = (0..360 * 2) - .map(|v| v as f64 * 0.5 - 180.) - .map(|x| { - (0..180 * 2) - .map(|y| y as f64 * 0.5 - 90.) - .map(move |y| (x, y)) + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let mask = RoaringMask::new(provider).unwrap(); + + let (x, y): (Vec, Vec) = (0..360 * 2) + .map(|v| v as f64 * 0.5 - 180.) + .map(|x| { + (0..180 * 2) + .map(|y| y as f64 * 0.5 - 90.) + .map(move |y| (x, y)) + }) + .flatten() + .unzip(); + + println!("testing {} points..", x.len()); + + b.iter(|| { + let _onland = x + .iter() + .zip(y.iter()) + .map(|(x, y)| mask.contains(*x, *y)) + .collect::>(); }) .flatten() .unzip(); diff --git a/src/providers.rs b/src/providers.rs new file mode 100644 index 0000000..03c014c --- /dev/null +++ b/src/providers.rs @@ -0,0 +1,8 @@ +use pyo3::prelude::*; + +#[pyclass] +#[derive(Clone, Copy)] +pub enum LandmaskProvider { + Gshhg, + Osm, +} diff --git a/src/shapes.rs b/src/shapes.rs index 514de6c..3427a08 100644 --- a/src/shapes.rs +++ b/src/shapes.rs @@ -10,21 +10,21 @@ use numpy::{PyArray, PyReadonlyArrayDyn}; pub static GSHHS_F: &str = "gshhs_f_-180.000000E-90.000000N180.000000E90.000000N.wkb.xz"; #[pyclass] -pub struct Gshhg { +pub struct Shapes { // prepped requires `geom` above to be around, and is valid as long as geom is alive. geom: Geometry, prepped: PreparedGeometry, } -// impl Drop for Gshhg { +// impl Drop for Shapes { // fn drop(&mut self) { // unsafe { drop(Box::from_raw(self.geom)) } // } // } -// PreparedGeometry is Send+Sync, Geometry is Send+Sync. *mut Geometry is never modified. -// unsafe impl Send for Gshhg {} -// unsafe impl Sync for Gshhg {} +// // PreparedGeometry is Send+Sync, Geometry is Send+Sync. *mut Geometry is never modified. +// unsafe impl Send for Shapes {} +// unsafe impl Sync for Shapes {} // `PreparededGeometry::contains` needs a call to `contains` before it is thread-safe: // https://github.com/georust/geos/issues/95 @@ -40,26 +40,23 @@ impl Clone for Gshhg { let prepped = geom.to_prepared_geom().unwrap(); warmup_prepped(&prepped); - Gshhg { - geom, - prepped, - } + Shapes { geom, prepped } } } -impl Gshhg { - pub fn from_geom(geom: Geometry) -> io::Result { +impl Shapes { + pub fn from_geom(geom: Geometry) -> io::Result { // let bxd = Box::new(geom); // let gptr = Box::into_raw(bxd); // let prepped = unsafe { (&*gptr).to_prepared_geom() } // .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "cannot prepare geomtry"))?; - let prepped = geom.to_prepared_geom().map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "cannot prepare geomtry"))?; + + let prepped = geom + .to_prepared_geom() + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "cannot prepare geomtry"))?; warmup_prepped(&prepped); - Ok(Gshhg { - geom, - prepped, - }) + Ok(Shapes { geom, prepped }) } pub fn from_compressed>(path: P) -> io::Result { @@ -93,6 +90,13 @@ impl Gshhg { #[staticmethod] pub fn wkb(py: Python) -> io::Result<&PyBytes> { use crate::GsshgData; + use crate::OsmData; + + let buf = match provider { + LandmaskProvider::Gshhg => GsshgData::get(&GSHHG), + LandmaskProvider::Osm => OsmData::get(&OSM), + } + .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "cannot find shapes"))?; let buf = GsshgData::get(&GSHHS_F) .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "cannot find shapes"))?; @@ -176,7 +180,11 @@ mod tests { #[test] fn test_load() { pyo3::prepare_freethreaded_python(); - Python::with_gil(|py| Gshhg::new(py)).unwrap(); + Python::with_gil(|py| { + Shapes::new(py, LandmaskProvider::Gshhg); + Shapes::new(py, LandmaskProvider::Osm); + }) + .unwrap(); } #[test] @@ -206,12 +214,12 @@ mod tests { fn test_contains_on_land(b: &mut Bencher) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { - let s = Gshhg::new(py).unwrap(); - - assert!(s.contains(15., 65.6)); - assert!(s.contains(10., 60.0)); - - b.iter(|| s.contains(15., 65.6)) + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let s = Shapes::new(py, provider).unwrap(); + assert!(s.contains(15., 65.6)); + assert!(s.contains(10., 60.0)); + b.iter(|| s.contains(15., 65.6)); + } }) } @@ -219,11 +227,11 @@ mod tests { fn test_contains_in_ocean(b: &mut Bencher) { pyo3::prepare_freethreaded_python(); Python::with_gil(|py| { - let s = Gshhg::new(py).unwrap(); - - assert!(!s.contains(5., 65.6)); - - b.iter(|| s.contains(5., 65.6)) + for provider in [LandmaskProvider::Gshhg, LandmaskProvider::Osm] { + let s = Shapes::new(py, provider).unwrap(); + assert!(!s.contains(5., 65.6)); + b.iter(|| s.contains(5., 65.6)); + } }) } } diff --git a/tests/test_geos_par_prepped.rs b/tests/test_geos_par_prepped.rs index 7f1cbc4..46eb831 100644 --- a/tests/test_geos_par_prepped.rs +++ b/tests/test_geos_par_prepped.rs @@ -1,29 +1,23 @@ -use roaring_landmask::Gshhg; use geos::{CoordSeq, Geom, Geometry}; +use roaring_landmask::Shapes; #[ignore] #[test] fn test_par_prepped_no_warmup() { use rayon::prelude::*; - // let s = Gshhg::new().unwrap(); - // let prepped = &s.prepped; - - let g = Gshhg::get_geometry_from_compressed( - "gshhs/gshhs_f_-180.000000E-90.000000N180.000000E90.000000N.wkb.xz", - ).unwrap(); - let prepped = g.to_prepared_geom().unwrap(); - - (0..10000).into_par_iter().for_each(|k| { - - let x = k % 180; - let y = (k / 180) % 90; - - - let point = CoordSeq::new_from_vec(&[&[x as f64, y as f64]]).unwrap(); - let point = Geometry::create_point(point).unwrap(); - prepped.contains(&point).unwrap(); - }); + for landmask_path in [GSHHG, OSM] { + let g = Shapes::get_geometry_from_compressed(landmask_path).unwrap(); + let prepped = g.to_prepared_geom().unwrap(); + (0..10000).into_par_iter().for_each(|k| { + let x = k % 180; + let y = (k / 180) % 90; + + let point = CoordSeq::new_from_vec(&[&[x as f64, y as f64]]).unwrap(); + let point = Geometry::create_point(point).unwrap(); + prepped.contains(&point).unwrap(); + }); + } } #[ignore] @@ -31,25 +25,21 @@ fn test_par_prepped_no_warmup() { fn test_par_prepped_with_warmup() { use rayon::prelude::*; - // let s = Gshhg::new().unwrap(); - // let prepped = &s.prepped; + for landmask_path in [GSHHG, OSM] { + let g = Shapes::get_geometry_from_compressed(landmask_path).unwrap(); + let prepped = g.to_prepared_geom().unwrap(); - let g = Gshhg::get_geometry_from_compressed( - "gshhs/gshhs_f_-180.000000E-90.000000N180.000000E90.000000N.wkb.xz", - ).unwrap(); - let prepped = g.to_prepared_geom().unwrap(); - - let point = CoordSeq::new_from_vec(&[&[10., 50.]]).unwrap(); - let point = Geometry::create_point(point).unwrap(); - prepped.contains(&point).unwrap(); - - (0..10000).into_par_iter().for_each(|k| { - let x = k % 180; - let y = (k / 180) % 90; - - - let point = CoordSeq::new_from_vec(&[&[x as f64, y as f64]]).unwrap(); + let point = CoordSeq::new_from_vec(&[&[10., 50.]]).unwrap(); let point = Geometry::create_point(point).unwrap(); prepped.contains(&point).unwrap(); - }); + + (0..10000).into_par_iter().for_each(|k| { + let x = k % 180; + let y = (k / 180) % 90; + + let point = CoordSeq::new_from_vec(&[&[x as f64, y as f64]]).unwrap(); + let point = Geometry::create_point(point).unwrap(); + prepped.contains(&point).unwrap(); + }); + } }