Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
resolver = "2"
members = [
"crates/total-viewsheds",
"crates/tvs-lib",
]

[workspace.dependencies]
color-eyre = "0.6.5"
geo = "0.31.0"
serde = "1.0.219"
serde_json = "1.0.143"

# Canonical lints for whole crate
#
# Official docs:
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ rm $sqlite_db_path || true
# Do the calculations
time cargo run --features ring_data --release -- \
compute "$PROJECT_ROOT/benchmarks/cardiff.tiff" \
--rings-per-km 3 \
--process all \
--viewsheds-db-path $sqlite_db_path \
--thread-count 1
--thread-count 1 \
--angle-subdivisions 1

viewshed_file="output/viewsheds/-3.122999906539917-51.48979949951172.json"
rm $viewshed_file || true
Expand Down
15 changes: 7 additions & 8 deletions crates/total-viewsheds/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,19 @@ rust-version = "1.89"
[dependencies]
bytemuck = "1.22.0"
clap = { version = "4.5.42", features = ["derive"] }
color-eyre = "0.6.5"
color-eyre.workspace = true
gdal = "0.19.0"
geo = "0.30.0"
geo.workspace = true
geojson = "0.24.2"
image = { version = "0.25.6", default-features = false, features = ["png"] }
itertools = "0.14.0"
proj4rs = { version = "0.1.8", features = ["aeqd"] }
serde = "1.0.219"
serde_json = "1.0.143"
tracing = { version = "0.1.41" }
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
rusqlite = { version = "0.38.0", features = ["bundled"] }
memchr = "2.8.0"
serde_json.workspace = true
rusqlite = { version = "0.38.0", features = ["bundled"] }
rayon = "1.12.0"
tracing = { version = "0.1.41" }
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
tvs-lib = { path = "../tvs-lib", version = "0.1.0" }

[dev-dependencies]
tempfile = "3.20.0"
Expand Down
14 changes: 7 additions & 7 deletions crates/total-viewsheds/src/compute/area_of_interest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ impl Pruner {
/// Convert user-provided lon/lat coordinates to a polygon.
pub fn lonlat_coords_to_polygon(
points: Vec<(f32, f32)>,
metadata: &crate::storage::metadata::MetaData,
metadata: &tvs_lib::metadata::MetaData,
) -> Result<geo::Polygon> {
let mut vertices = Vec::new();

for intrest_point in points {
let lonlat = crate::projection::LonLatCoord(
let lonlat = tvs_lib::projector::LonLatCoord(
geo::coord!(x: intrest_point.0.into(), y: intrest_point.1.into()),
);
let dem_coord = crate::projection::Converter::lonlat_to_dem_coord(metadata, lonlat)?;
let dem_coord = tvs_lib::projector::Convert::lonlat_to_dem_coord(metadata, lonlat)?;
let dem_point = geo::point!(x: dem_coord.0.x, y: dem_coord.0.y);
vertices.push(dem_point);
}
Expand All @@ -52,10 +52,10 @@ impl Pruner {
reason = "We're only dealing with a max of the DEM's width"
)]
/// Convert a DEM 1D index to a 2D coordinate.
pub fn convert_dem_id_to_coord(&self, dem_id: i64) -> crate::dem::Coordinate {
pub fn convert_dem_id_to_coord(&self, dem_id: i64) -> tvs_lib::dem::Coordinate {
let x = dem_id.rem_euclid(self.width.into()) as f64;
let y = dem_id.div_euclid(self.width.into()) as f64;
crate::dem::Coordinate(geo::coord! {x: x, y: y})
tvs_lib::dem::Coordinate(geo::coord! {x: x, y: y})
}
}

Expand All @@ -65,10 +65,10 @@ mod tests {

fn make_pruner() -> Pruner {
let width = 300;
let metadata = crate::storage::metadata::MetaData {
let metadata = tvs_lib::metadata::MetaData {
width,
scale: 100.0,
centre: crate::projection::LonLatCoord((-3.1791, 51.4816).into()),
centre: tvs_lib::projector::LonLatCoord((-3.1791, 51.4816).into()),
..Default::default()
};
let cardiff_10km = vec![
Expand Down
4 changes: 2 additions & 2 deletions crates/total-viewsheds/src/compute/kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,11 @@ mod test {
let dem = &crate::tests::fixtures::bigger_dem();
let db_worker = crate::storage::worker::Worker::new_noop();
let width = 4;
let metadata = crate::storage::metadata::MetaData {
let metadata = tvs_lib::metadata::MetaData {
width,
scale: 1.0,
max_line_of_sight: width,
centre: crate::projection::LonLatCoord((0.0, 0.0).into()),
centre: tvs_lib::projector::LonLatCoord((0.0, 0.0).into()),
neighbourhood_size: 0,
angle_subdivisions: 1,
};
Expand Down
2 changes: 1 addition & 1 deletion crates/total-viewsheds/src/compute/unrolled_los.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn generate_distances(max_los: usize, refraction: f32, scale: f32) -> (Vec<f32>,
.map(|step| {
let distance = (step as f32) * scale;
let adjustment =
(distance * distance * adjusted_refraction) / crate::projection::EARTH_DIAMETER;
(distance * distance * adjusted_refraction) / tvs_lib::projector::EARTH_DIAMETER;

(distance, adjustment)
})
Expand Down
22 changes: 12 additions & 10 deletions crates/total-viewsheds/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use std::mem;
use tracing_subscriber::{Layer as _, layer::SubscriberExt as _, util::SubscriberInitExt as _};

mod config;
mod dem;
mod dump_usage;
mod los_pack;
mod post_process;
Expand Down Expand Up @@ -65,7 +64,6 @@ mod compute {
mod storage {
pub mod db;
pub mod engine;
pub mod metadata;
pub mod segments;
pub mod worker;
}
Expand All @@ -76,10 +74,14 @@ mod output {
pub mod bresenham;
pub mod png;
pub mod tiff;
pub mod viewshed;
}

mod projection;
/// Load, parse and reconstruct euclidean polygon viewsheds from their raw polar segments.
pub mod viewsheds {
pub mod join;
pub mod viewshed;
pub mod visible_polygon;
}
}

fn main() -> Result<()> {
color_eyre::install()?;
Expand All @@ -91,15 +93,15 @@ fn main() -> Result<()> {
config::Commands::Compute(compute_config) => compute(compute_config)?,
config::Commands::Viewshed(viewshed_config) => {
for coordinate in &viewshed_config.coordinates {
let geo_coord = projection::LonLatCoord(
let geo_coord = tvs_lib::projector::LonLatCoord(
geo::coord! {x: f64::from(coordinate.0), y: f64::from(coordinate.1)},
);

let (_, viewshed) = crate::output::viewshed::Viewshed::reconstruct(
let (_, viewshed) = crate::output::viewsheds::viewshed::Viewshed::reconstruct(
viewshed_config.db_path.clone(),
geo_coord,
)?;
crate::output::viewshed::Reconstructor::save(
crate::output::viewsheds::viewshed::Viewshed::save(
viewshed,
&viewshed_config.output_dir,
geo_coord,
Expand Down Expand Up @@ -145,7 +147,7 @@ fn compute(config: &config::Compute) -> Result<()> {

let max_line_of_sight_as_points = tile.width.div_euclid(3);

let mut dem = crate::dem::DEM::new(
let mut dem = tvs_lib::dem::DEM::new(
tile.centre,
tile.width,
tile.scale,
Expand All @@ -159,7 +161,7 @@ fn compute(config: &config::Compute) -> Result<()> {
// Free up RAM
drop(tile);

let dem_metadata = crate::storage::metadata::MetaData {
let dem_metadata = tvs_lib::metadata::MetaData {
width: dem.width,
scale: dem.scale,
max_line_of_sight: max_line_of_sight_as_points,
Expand Down
12 changes: 6 additions & 6 deletions crates/total-viewsheds/src/output/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![cfg(test)]
#![expect(clippy::indexing_slicing, reason = "This code is mostly for tests")]

use crate::output::viewshed::Viewshed;
use crate::output::viewsheds::viewshed::Viewshed;

pub fn make_viewshed(
elevations: &[i16],
Expand All @@ -16,14 +16,14 @@ pub fn make_viewshed(
x: viewshed_pov.x - dem_half_width,
y: -(viewshed_pov.y - dem_half_width),
};
let coord_lonlat = crate::projection::Converter { base: dem.centre }
let coord_lonlat = tvs_lib::projector::Convert::new(dem.centre)
.to_degrees(viewshed_pov_metric)
.unwrap();

crate::run::test::compute(&mut dem, config.clone());
let (pov_coord, mut viewshed) =
Viewshed::reconstruct(config.viewsheds_db_path, coord_lonlat).unwrap();
let viewsheder = crate::output::viewshed::Viewshed {
let viewsheder = crate::output::viewsheds::viewshed::Viewshed {
dem: &dem,
pov_coord,
};
Expand All @@ -43,9 +43,9 @@ pub fn make_viewshed(
let mut maybe_from = None;
for coordinate in line.coords_mut() {
let projected = viewsheder
.convert_viewshed_coord_to_dem_coord(crate::output::viewshed::Coordinate(
*coordinate,
))
.convert_viewshed_coord_to_dem_coord(
crate::output::viewsheds::viewshed::Coordinate(*coordinate),
)
.unwrap();
if maybe_from.is_none() {
maybe_from = Some(projected);
Expand Down
2 changes: 1 addition & 1 deletion crates/total-viewsheds/src/output/tiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use color_eyre::Result;

/// Save an array of `f32`s (total surfaces, longest lines of sight) to a `.tiff` file.
pub fn save(dem: &crate::dem::DEM, data: &[f32], path: &std::path::PathBuf) -> Result<()> {
pub fn save(dem: &tvs_lib::dem::DEM, data: &[f32], path: &std::path::PathBuf) -> Result<()> {
let driver = gdal::DriverManager::get_driver_by_name("GTiff")?;

let mut dataset = driver.create_with_band_type::<f32, _>(
Expand Down
32 changes: 32 additions & 0 deletions crates/total-viewsheds/src/output/viewsheds/join.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//! Join the visible segments from each computed angle into the viewshed.

impl super::visible_polygon::VisiblePolygon {
/// Convert polar segments to euclidean polygons.
pub fn parse_polar_segments(
data: &[Vec<crate::storage::segments::Segment>],
scale: f32,
) -> geo::MultiPolygon {
let angle_count = data.len();
let mut polygons = Vec::new();
for (anglish, segments) in data.iter().enumerate() {
#[expect(
clippy::as_conversions,
clippy::cast_precision_loss,
reason = "The angle count should never strain the f32 mantissa"
)]
let (anglish_f32, angle_count_f32) = { (anglish as f32, angle_count as f32) };
let polygoner = Self {
scale,
current_angle: (anglish_f32 / angle_count_f32) * 360.0,
};
for segment in segments {
let opening = u32::from(segment.start());
let closing = u32::from(segment.start() + segment.distance());
let polygon = polygoner.make_visible_polygon(opening, closing);
polygons.push(polygon);
}
}

geo::unary_union(polygons.iter())
}
}
Loading
Loading