Compare commits
No commits in common. "548f801bcfc4fa1b15ecfc9306fcc33144560f32" and "0880f3e76117785d2762ca6d3ca415e0e8d40da3" have entirely different histories.
548f801bcf
...
0880f3e761
220
src/main.rs
220
src/main.rs
|
|
@ -1,59 +1,133 @@
|
||||||
use {
|
use {
|
||||||
clap::{Parser, Subcommand},
|
clap::Parser,
|
||||||
geo_types::Point,
|
geo_types::Point,
|
||||||
image::{ImageBuffer, Luma},
|
image::{ImageBuffer, Luma},
|
||||||
las::Read as LasRead,
|
las::Read as LasRead,
|
||||||
proj::Proj,
|
proj::Proj,
|
||||||
std::path::PathBuf,
|
std::{
|
||||||
|
ops::{Add, Div, Mul, Sub},
|
||||||
|
path::PathBuf,
|
||||||
|
},
|
||||||
tokio::io::AsyncReadExt,
|
tokio::io::AsyncReadExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod geonb;
|
mod geonb;
|
||||||
mod numeric_types;
|
|
||||||
use numeric_types::{Float, Integer, ToFloat};
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about=None)]
|
#[clap(author, version, about, long_about=None)]
|
||||||
struct Args {
|
struct Args {
|
||||||
/// Print extra debug info when initializing graphics
|
// Latitude to fetch LIDAR tile at
|
||||||
#[arg(long)]
|
#[clap(long)]
|
||||||
|
latitude: Option<f64>,
|
||||||
|
|
||||||
|
// Longitude to fetch LIDAR tile at
|
||||||
|
#[clap(long)]
|
||||||
|
longitude: Option<f64>,
|
||||||
|
|
||||||
|
// Print extra debug info when initializing raphics
|
||||||
|
#[clap(long)]
|
||||||
debug_init: bool,
|
debug_init: bool,
|
||||||
|
|
||||||
#[command(subcommand)]
|
#[clap(long)]
|
||||||
command: Command,
|
laz_file: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(long)]
|
||||||
|
grid_cell_size: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
trait FromFloatFloor<F> {
|
||||||
enum Command {
|
fn from_float_floor(f: F) -> Self;
|
||||||
/// Download data from GeoNB
|
|
||||||
GeoNB {
|
|
||||||
#[command(subcommand)]
|
|
||||||
command: GeoNBCommand,
|
|
||||||
},
|
|
||||||
/// Create a grid DEM from point data
|
|
||||||
GridPoints {
|
|
||||||
#[arg(long, short = 'i')]
|
|
||||||
laz_filename: PathBuf,
|
|
||||||
|
|
||||||
#[arg(long)]
|
|
||||||
grid_cell_size: f64,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
trait ToFloat<F> {
|
||||||
enum GeoNBCommand {
|
fn to_float(self) -> F;
|
||||||
/// Download the LIDAR tile that includes a location
|
|
||||||
DownloadLidarTile {
|
|
||||||
/// Latitude to fetch LIDAR tile at
|
|
||||||
#[arg(long, allow_hyphen_values = true)]
|
|
||||||
latitude: f64,
|
|
||||||
|
|
||||||
/// Longitude to fetch LIDAR tile at
|
|
||||||
#[arg(long, allow_hyphen_values = true)]
|
|
||||||
longitude: f64,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait Integer:
|
||||||
|
Copy
|
||||||
|
+ Default
|
||||||
|
+ Add<Self, Output = Self>
|
||||||
|
+ Sub<Self, Output = Self>
|
||||||
|
+ Mul<Self, Output = Self>
|
||||||
|
+ Div<Self, Output = Self>
|
||||||
|
+ FromFloatFloor<f32>
|
||||||
|
+ FromFloatFloor<f64>
|
||||||
|
+ ToFloat<f32>
|
||||||
|
+ ToFloat<f64>
|
||||||
|
{
|
||||||
|
const MIN: Self;
|
||||||
|
const MAX: Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_int {
|
||||||
|
( $t:ident ) => {
|
||||||
|
impl FromFloatFloor<f32> for $t {
|
||||||
|
fn from_float_floor(f: f32) -> Self {
|
||||||
|
f as $t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FromFloatFloor<f64> for $t {
|
||||||
|
fn from_float_floor(f: f64) -> Self {
|
||||||
|
f as $t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToFloat<f32> for $t {
|
||||||
|
fn to_float(self) -> f32 {
|
||||||
|
self as f32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToFloat<f64> for $t {
|
||||||
|
fn to_float(self) -> f64 {
|
||||||
|
self as f64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Integer for $t {
|
||||||
|
const MIN: $t = $t::MIN;
|
||||||
|
const MAX: $t = $t::MAX;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_int!(u8);
|
||||||
|
impl_int!(i8);
|
||||||
|
impl_int!(u16);
|
||||||
|
impl_int!(i16);
|
||||||
|
impl_int!(u32);
|
||||||
|
impl_int!(i32);
|
||||||
|
impl_int!(u64);
|
||||||
|
impl_int!(i64);
|
||||||
|
|
||||||
|
trait Unsigned {}
|
||||||
|
|
||||||
|
impl Unsigned for u8 {}
|
||||||
|
impl Unsigned for u16 {}
|
||||||
|
impl Unsigned for u32 {}
|
||||||
|
impl Unsigned for u64 {}
|
||||||
|
|
||||||
|
trait Float:
|
||||||
|
Copy
|
||||||
|
+ Default
|
||||||
|
+ Add<Self, Output = Self>
|
||||||
|
+ Sub<Self, Output = Self>
|
||||||
|
+ Mul<Self, Output = Self>
|
||||||
|
+ Div<Self, Output = Self>
|
||||||
|
{
|
||||||
|
fn to_int_floor<I: Integer>(self) -> I;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_float {
|
||||||
|
( $t:ident ) => {
|
||||||
|
impl Float for $t {
|
||||||
|
fn to_int_floor<I: Integer>(self) -> I {
|
||||||
|
I::from_float_floor(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_float!(f32);
|
||||||
|
impl_float!(f64);
|
||||||
|
|
||||||
struct Grid<T> {
|
struct Grid<T> {
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
|
|
@ -157,47 +231,38 @@ where
|
||||||
async fn main() -> Result<(), anyhow::Error> {
|
async fn main() -> Result<(), anyhow::Error> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
match args.command {
|
if let (Some(latitude), Some(longitude)) = (args.latitude, args.longitude) {
|
||||||
Command::GeoNB {
|
let location = Proj::new_known_crs("+proj=longlat +datum=WGS84", "EPSG:2953", None)
|
||||||
command:
|
.unwrap()
|
||||||
GeoNBCommand::DownloadLidarTile {
|
.convert(Point::new(longitude, latitude))
|
||||||
latitude,
|
.unwrap();
|
||||||
longitude,
|
println!("{:?}", location);
|
||||||
},
|
let mut las_reader =
|
||||||
} => {
|
tokio::io::BufReader::new(geonb::get_lidar_tile_around_point(location).await?);
|
||||||
let location = Proj::new_known_crs("+proj=longlat +datum=WGS84", "EPSG:2953", None)
|
let mut las_bytes = Vec::new();
|
||||||
.unwrap()
|
let mut buffer = [0_u8; 4096];
|
||||||
.convert(Point::new(longitude, latitude))
|
let mut byte_count = 0;
|
||||||
.unwrap();
|
loop {
|
||||||
println!("{:?}", location);
|
let num_bytes = las_reader.read(&mut buffer).await?;
|
||||||
let mut las_reader =
|
if num_bytes == 0 {
|
||||||
tokio::io::BufReader::new(geonb::get_lidar_tile_around_point(location).await?);
|
break;
|
||||||
let mut las_bytes = Vec::new();
|
|
||||||
let mut buffer = [0_u8; 4096];
|
|
||||||
let mut byte_count = 0;
|
|
||||||
loop {
|
|
||||||
let num_bytes = las_reader.read(&mut buffer).await?;
|
|
||||||
if num_bytes == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
byte_count += num_bytes;
|
|
||||||
print!("{} bytes read\r", byte_count);
|
|
||||||
las_bytes.extend_from_slice(&buffer[0..num_bytes]);
|
|
||||||
}
|
}
|
||||||
println!();
|
byte_count += num_bytes;
|
||||||
let mut las_reader = las::Reader::new(std::io::Cursor::new(las_bytes))?;
|
print!("{} bytes read\r", byte_count);
|
||||||
for wrapped_point in las_reader.points().take(10) {
|
las_bytes.extend_from_slice(&buffer[0..num_bytes]);
|
||||||
let point = wrapped_point.unwrap();
|
|
||||||
println!("Point coordinates: ({}, {}, {})", point.x, point.y, point.z);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Command::GridPoints {
|
println!();
|
||||||
laz_filename,
|
let mut las_reader = las::Reader::new(std::io::Cursor::new(las_bytes))?;
|
||||||
grid_cell_size,
|
for wrapped_point in las_reader.points().take(10) {
|
||||||
} => {
|
let point = wrapped_point.unwrap();
|
||||||
let mut las_reader = las::Reader::from_path(laz_filename).unwrap();
|
println!("Point coordinates: ({}, {}, {})", point.x, point.y, point.z);
|
||||||
let bounds = las_reader.header().bounds();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(laz_filename) = args.laz_file {
|
||||||
|
let mut las_reader = las::Reader::from_path(laz_filename).unwrap();
|
||||||
|
let bounds = las_reader.header().bounds();
|
||||||
|
if let Some(grid_cell_size) = args.grid_cell_size {
|
||||||
let num_cells_x = ((bounds.max.x - bounds.min.x) / grid_cell_size).ceil() as usize;
|
let num_cells_x = ((bounds.max.x - bounds.min.x) / grid_cell_size).ceil() as usize;
|
||||||
let num_cells_y = ((bounds.max.y - bounds.min.y) / grid_cell_size).ceil() as usize;
|
let num_cells_y = ((bounds.max.y - bounds.min.y) / grid_cell_size).ceil() as usize;
|
||||||
let mut height_grid = Grid::new(num_cells_y, num_cells_x);
|
let mut height_grid = Grid::new(num_cells_y, num_cells_x);
|
||||||
|
|
@ -223,7 +288,8 @@ async fn main() -> Result<(), anyhow::Error> {
|
||||||
ImageBuffer::from_raw(num_cells_x as u32, num_cells_y as u32, grid_u8.data)
|
ImageBuffer::from_raw(num_cells_x as u32, num_cells_y as u32, grid_u8.data)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
image.save("test.png")?;
|
image.save("test.png")?;
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
use std::ops::{Add, Div, Mul, Sub};
|
|
||||||
|
|
||||||
pub trait FromFloatFloor<F> {
|
|
||||||
fn from_float_floor(f: F) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ToFloat<F> {
|
|
||||||
fn to_float(self) -> F;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Integer:
|
|
||||||
Copy
|
|
||||||
+ Default
|
|
||||||
+ Add<Self, Output = Self>
|
|
||||||
+ Sub<Self, Output = Self>
|
|
||||||
+ Mul<Self, Output = Self>
|
|
||||||
+ Div<Self, Output = Self>
|
|
||||||
+ FromFloatFloor<f32>
|
|
||||||
+ FromFloatFloor<f64>
|
|
||||||
+ ToFloat<f32>
|
|
||||||
+ ToFloat<f64>
|
|
||||||
{
|
|
||||||
const MIN: Self;
|
|
||||||
const MAX: Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_int {
|
|
||||||
( $t:ident ) => {
|
|
||||||
impl FromFloatFloor<f32> for $t {
|
|
||||||
fn from_float_floor(f: f32) -> Self {
|
|
||||||
f as $t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FromFloatFloor<f64> for $t {
|
|
||||||
fn from_float_floor(f: f64) -> Self {
|
|
||||||
f as $t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ToFloat<f32> for $t {
|
|
||||||
fn to_float(self) -> f32 {
|
|
||||||
self as f32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ToFloat<f64> for $t {
|
|
||||||
fn to_float(self) -> f64 {
|
|
||||||
self as f64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Integer for $t {
|
|
||||||
const MIN: $t = $t::MIN;
|
|
||||||
const MAX: $t = $t::MAX;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_int!(u8);
|
|
||||||
impl_int!(i8);
|
|
||||||
impl_int!(u16);
|
|
||||||
impl_int!(i16);
|
|
||||||
impl_int!(u32);
|
|
||||||
impl_int!(i32);
|
|
||||||
impl_int!(u64);
|
|
||||||
impl_int!(i64);
|
|
||||||
|
|
||||||
pub trait Unsigned {}
|
|
||||||
|
|
||||||
impl Unsigned for u8 {}
|
|
||||||
impl Unsigned for u16 {}
|
|
||||||
impl Unsigned for u32 {}
|
|
||||||
impl Unsigned for u64 {}
|
|
||||||
|
|
||||||
pub trait Float:
|
|
||||||
Copy
|
|
||||||
+ Default
|
|
||||||
+ Add<Self, Output = Self>
|
|
||||||
+ Sub<Self, Output = Self>
|
|
||||||
+ Mul<Self, Output = Self>
|
|
||||||
+ Div<Self, Output = Self>
|
|
||||||
{
|
|
||||||
fn to_int_floor<I: Integer>(self) -> I;
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_float {
|
|
||||||
( $t:ident ) => {
|
|
||||||
impl Float for $t {
|
|
||||||
fn to_int_floor<I: Integer>(self) -> I {
|
|
||||||
I::from_float_floor(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_float!(f32);
|
|
||||||
impl_float!(f64);
|
|
||||||
Loading…
Reference in New Issue