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
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ serde_json = "1.0.143"
[workspace.lints.rust]
# It's always good to write as much documentation as possible
missing_docs = "warn"
unreachable_pub = "warn"

[workspace.lints.clippy]
# `clippy::all` is already on by default. It implies the following:
Expand Down Expand Up @@ -93,3 +94,8 @@ multiple_unsafe_ops_per_block = "allow"

# i dont write docs with punctuation but you can still tell what im saying
doc_paragraphs_missing_punctuation = "allow"

# Along with `unreachable_pub = "warn"` this enforces the practice of explicitly defining visibility.
# Therefore, if a symbol isn't truly public to the outside world then it should be qualified with
# `pub(crate)`, `pub(super)`, etc.
redundant_pub_crate = "allow"
10 changes: 5 additions & 5 deletions crates/total-viewsheds/src/compute/area_of_interest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use color_eyre::Result;
use geo::Contains as _;

/// `Pruner`
pub struct Pruner {
pub(crate) struct Pruner {
/// Width of the DEM in points
width: u32,
/// The DEM coordinates for the Area of Interest.
Expand All @@ -14,12 +14,12 @@ pub struct Pruner {

impl Pruner {
/// Instantiate.
pub const fn new(width: u32, polygon: geo::Polygon) -> Self {
pub(crate) const fn new(width: u32, polygon: geo::Polygon) -> Self {
Self { width, polygon }
}

/// Convert user-provided lon/lat coordinates to a polygon.
pub fn lonlat_coords_to_polygon(
pub(crate) fn lonlat_coords_to_polygon(
points: Vec<(f32, f32)>,
metadata: &tvs_lib::metadata::MetaData,
) -> Result<geo::Polygon> {
Expand All @@ -41,7 +41,7 @@ impl Pruner {
}

/// Can the given DEM ID be ignored in computations.
pub fn is_prunable(&self, dem_id: i64) -> bool {
pub(crate) fn is_prunable(&self, dem_id: i64) -> bool {
let dem_coord = self.convert_dem_id_to_coord(dem_id);
!self.polygon.contains(&dem_coord.0)
}
Expand All @@ -52,7 +52,7 @@ 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) -> tvs_lib::dem::Coordinate {
pub(crate) 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;
tvs_lib::dem::Coordinate(geo::coord! {x: x, y: y})
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 @@ -7,7 +7,7 @@ use geo::HasDimensions as _;
use itertools::izip;

/// The data output by a single angle.
pub struct OutputData {
pub(crate) struct OutputData {
/// The visibile surface area.
pub surfaces: Vec<f32>,
/// The longest lines of sight.
Expand Down Expand Up @@ -57,7 +57,7 @@ const DEFAULT_UNROLL: usize = const {

/// `kernel` will calculate the longest line of sight heatmap for a given angle and elevation map
/// assuming that the maximum line of sight is `max_los`
pub fn kernel(
pub(crate) fn kernel(
db_worker: &crate::storage::worker::Worker,
elevation_map: &[i16],
output: &mut OutputData,
Expand Down
9 changes: 5 additions & 4 deletions crates/total-viewsheds/src/compute/los.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// `LineOfSight` abstracts the implementation of line of sight calculations to
/// any "carry through" that can be materialized into a (f32, f32).
pub trait LineOfSight<Output: Into<(f32, f32)>, LOS: Angle + PrefixMax + Accumulate<Output>> {
pub(crate) trait LineOfSight<Output: Into<(f32, f32)>, LOS: Angle + PrefixMax + Accumulate<Output>>
{
/// `line_of_sight` calculates a line of sight for the given `pov_height`
/// and outputs a triple of the surface area, longest line of sight in meters
/// and a vector of bools of which
Expand All @@ -9,7 +10,7 @@ pub trait LineOfSight<Output: Into<(f32, f32)>, LOS: Angle + PrefixMax + Accumul

/// `Angle` abstracts the angle calculation between a pov and all the elevation data within
/// its band of sight
pub trait Angle {
pub(crate) trait Angle {
/// `calculate_angles` calculates the angle from the `pov_height` to a given elevation
fn calculate_angles(
pov_height: f32,
Expand All @@ -23,7 +24,7 @@ pub trait Angle {
/// `Accumulate` accumulates the surface area visible and longest line of sight
/// in a pair of (f32, f32). `Accumulate` doesn't care about the implementation details
/// of accumulation so long as the `Output` type can be materialized to (f32, f32)
pub trait Accumulate<Output: Into<(f32, f32)>> {
pub(crate) trait Accumulate<Output: Into<(f32, f32)>> {
/// `accumulate` accumulates the surface area using the distances by comparing
/// whether a point at a distance is visible (angle > prefix)
/// If `output_sector` is true, it should output a bitmap of which distances are visible
Expand All @@ -38,7 +39,7 @@ pub trait Accumulate<Output: Into<(f32, f32)>> {
}

/// `PrefixMax` calculates the prefix maximum of the given angles
pub trait PrefixMax {
pub(crate) trait PrefixMax {
/// `prefix_max` calculates the prefix max of the
fn prefix_max(highest: f32, angles_in: &[f32], angles_out: &mut [f32]);
}
2 changes: 1 addition & 1 deletion crates/total-viewsheds/src/compute/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::rc::Rc;
reason = "rotation should not be out of bounds"
)]
#[expect(clippy::expect_used, reason = "invriants broken if options not none")]
pub fn lines(
pub(crate) fn lines(
elevs: &[i16],
max_los: usize,
angle: f64,
Expand Down
10 changes: 5 additions & 5 deletions crates/total-viewsheds/src/compute/rotator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/// * 180°: (`width_index` - x, `width_index` - y)
// * 270°: (y, `width_index` - x)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Quadrant {
pub(crate) enum Quadrant {
/// Top-right quadrant: 0° to 90°
TopRight,
/// Top-left quadrant: 90° to 180°
Expand Down Expand Up @@ -55,7 +55,7 @@ impl From<f64> for Quadrant {
}

/// Rotator struct.
pub struct Rotator {
pub(crate) struct Rotator {
/// The centre of the DEM in relative coordinates.
centre: (f64, f64),
/// The index of the last point in a row/column of the DEM.
Expand All @@ -72,7 +72,7 @@ pub struct Rotator {

impl Rotator {
/// Instantiate.
pub fn new(angle: f64, width: isize) -> Self {
pub(crate) fn new(angle: f64, width: isize) -> Self {
assert!(
(0.0f64..360.0f64).contains(&angle),
"Angle {angle} must be in range 0..360"
Expand Down Expand Up @@ -109,7 +109,7 @@ impl Rotator {
/// we'd just make the angle negative here. But seeing as the rest of the maths involved in
/// skew rotation is based in positive angles it's better to achieve the same rotation
/// through a positive but inverted angle.
pub fn invert_angle(angle: f64) -> f64 {
pub(crate) fn invert_angle(angle: f64) -> f64 {
if angle > 0.0f64 {
360.0f64 - angle
} else {
Expand All @@ -122,7 +122,7 @@ impl Rotator {
///
/// Note that each shear step _must_ be rounded. This is essential to achieving a bijective
/// mapping.
pub fn rotate(&self, x: isize, y: isize) -> (isize, isize) {
pub(crate) fn rotate(&self, x: isize, y: isize) -> (isize, isize) {
let (x_centre, y_centre) = self.centre;
let (quadrant_x, quadrant_y) = self.rotate_to_quadrant(x, y);

Expand Down
6 changes: 3 additions & 3 deletions crates/total-viewsheds/src/compute/unrolled_los.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn generate_distances(max_los: usize, refraction: f32, scale: f32) -> (Vec<f32>,
/// Unroll holds an unrolled heatmap and unrolled longest line of sight calculation
/// Since in Line of Sight-land max/addition are commutative, then Unroll will be materialized
/// into (f32, f32)
pub struct UnrollVector<const UNROLL: usize, const VECTOR_WIDTH: usize>
pub(crate) struct UnrollVector<const UNROLL: usize, const VECTOR_WIDTH: usize>
where
[(); UNROLL * VECTOR_WIDTH]:,
{
Expand All @@ -40,7 +40,7 @@ where
}

/// `UnrolledLOS` implements an Unrolled `LineOfSight` calculation
pub struct UnrolledVectorLos<const UNROLL: usize, const VECTOR_WIDTH: usize> {
pub(crate) struct UnrolledVectorLos<const UNROLL: usize, const VECTOR_WIDTH: usize> {
/// `angles` holds a buffer for line of sight angles to be put into
/// which is exactly `max_los+1` long
angles: Vec<f32>,
Expand Down Expand Up @@ -81,7 +81,7 @@ where
impl<const UNROLL: usize, const VECTOR_WIDTH: usize> UnrolledVectorLos<UNROLL, VECTOR_WIDTH> {
/// `new` initializes a new `UnrolledLOS`, and precalculates all the distances
/// and earth curvature adjustments
pub fn new(max_los: usize, refraction: f32, scale: f32) -> Self {
pub(crate) fn new(max_los: usize, refraction: f32, scale: f32) -> Self {
assert_eq!(
max_los % VECTOR_WIDTH,
0,
Expand Down
8 changes: 4 additions & 4 deletions crates/total-viewsheds/src/compute/vector_intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ use std::simd::{Mask, Simd, f32x4};

/// `VectorMax` performs an element-wise SIMD max of floats, allowing for architecture
/// specific implementations
pub trait VectorMax<const WIDTH: usize> {
pub(crate) trait VectorMax<const WIDTH: usize> {
/// `max` computes an element-wise maximum from lhs and rhs, assuming neither contain NaNs
/// or -0.0
fn max(lhs: Simd<f32, WIDTH>, rhs: Simd<f32, WIDTH>) -> Simd<f32, WIDTH>;
}

/// `VectorGreater` performs a SIMD greater than of floats, allowing for architecture
/// specific implementations
pub trait VectorGreater<const WIDTH: usize> {
pub(crate) trait VectorGreater<const WIDTH: usize> {
/// gt computes an element-wise maximum from lhs and rhs, assuming neither contain NaNs
/// or -0.0
fn gt(lhs: Simd<f32, WIDTH>, rhs: Simd<f32, WIDTH>) -> Mask<i32, WIDTH>;
}

/// `VectorLos` is an implementation of the internals of `PrefixMax`, `Angle`, and `Accumulate`
/// for Portable SIMD
pub struct VectorLos<const WIDTH: usize>;
pub(crate) struct VectorLos<const WIDTH: usize>;

impl<const WIDTH: usize> VectorMax<WIDTH> for VectorLos<WIDTH> {
#[inline]
Expand Down Expand Up @@ -333,7 +333,7 @@ impl<const WIDTH: usize> Angle for VectorLos<WIDTH> {

/// `DEFAULT_VECTOR_LENGTH` determines the CPU Kernel's default vector length based off
/// the architecture that the binary is built for
pub const DEFAULT_VECTOR_LENGTH: usize = const {
pub(crate) const DEFAULT_VECTOR_LENGTH: usize = const {
if cfg!(target_feature = "avx512f") {
16
} else if cfg!(any(test, feature = "ring_data")) {
Expand Down
16 changes: 8 additions & 8 deletions crates/total-viewsheds/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ use std::path::PathBuf;
#[command(
about = "Generate _all_ the viewsheds for a given Digital Elevation Model, therefore the total viewsheds."
)]
pub struct Config {
pub(crate) struct Config {
#[command(subcommand)]
/// The subcommand.
pub command: Commands,
}

/// CLI subcommand.
#[derive(clap::Subcommand, Debug)]
pub enum Commands {
pub(crate) enum Commands {
/// Run main computations.
Compute(Compute),
/// Reconstruct a viewshed.
Expand All @@ -35,7 +35,7 @@ pub enum Commands {

/// Arguments to the `compute` subcommand.
#[derive(clap::Parser, Debug, Default)]
pub struct Compute {
pub(crate) struct Compute {
// TODO: make this "reserved rings" and add support to the kernel so that the user can get
// feedback of the actual number needed.
//
Expand Down Expand Up @@ -154,7 +154,7 @@ pub struct Compute {

/// Arguments to the `viewshed` subcommand.
#[derive(clap::Parser, Debug)]
pub struct Viewshed {
pub(crate) struct Viewshed {
/// Path or directory where viewshed DB was saved.
#[arg(value_name = "Path to existing database")]
pub db_path: std::path::PathBuf,
Expand All @@ -170,7 +170,7 @@ pub struct Viewshed {

/// Arguments to the `post-process` subcommand.
#[derive(clap::Parser, Debug)]
pub struct PostProcess {
pub(crate) struct PostProcess {
/// Directory where viewshed DBs were saved.
#[arg(value_name = "Path to existing databases")]
pub db_dir: std::path::PathBuf,
Expand Down Expand Up @@ -211,7 +211,7 @@ fn is_perfect_square(argument: &str) -> Result<u16> {

/// Where to run the computations.
#[derive(clap::ValueEnum, Clone, Debug, Default)]
pub enum Backend {
pub(crate) enum Backend {
/// Optimised cache-efficient CPU kernel
#[default]
CPU,
Expand All @@ -221,7 +221,7 @@ pub enum Backend {

/// Which calculations to process.
#[derive(clap::ValueEnum, Clone, Debug, PartialEq, Eq)]
pub enum Process {
pub(crate) enum Process {
/// Calculate everything.
All,
/// Compute all the polar segments saving them to disk so that they can be used to later
Expand All @@ -231,7 +231,7 @@ pub enum Process {

/// Where to run the computations.
#[derive(clap::ValueEnum, Clone, Debug, Copy, Default)]
pub enum HeatmapNormalisation {
pub(crate) enum HeatmapNormalisation {
/// Just scale between 0 and 1
UnitScale,
/// Scale between 0 and 1 with an exponential factor.
Expand Down
2 changes: 1 addition & 1 deletion crates/total-viewsheds/src/dump_usage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use color_eyre::Result;

/// main dump usage function
#[expect(clippy::print_stdout, reason = "We need to output the usage.")]
pub fn dump_full_usage_for_readme() -> Result<()> {
pub(crate) fn dump_full_usage_for_readme() -> Result<()> {
use clap::CommandFactory as _;
let mut command = crate::config::Config::command();

Expand Down
14 changes: 7 additions & 7 deletions crates/total-viewsheds/src/los_pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const U10_MAX: u32 = (1 << 10) - 1;

#[derive(Default, Debug, Clone, Copy)]
/// Line of sight data that can be packed within 32 bits.
pub struct LineOfSightPacked(f32);
pub(crate) struct LineOfSightPacked(f32);

#[expect(
clippy::big_endian_bytes,
Expand All @@ -21,7 +21,7 @@ impl LineOfSightPacked {
///
/// f32 is better than u32 because I imagine that floats are just more widely recognised in general.
/// At the end of the day, they're just bits that are neither valid f32 nor u32.
pub fn new(distance: u32, angle: u16) -> Result<Self> {
pub(crate) fn new(distance: u32, angle: u16) -> Result<Self> {
if distance > U22_MAX {
color_eyre::eyre::bail!("{} is greater than u22 max {U22_MAX}", distance);
}
Expand All @@ -37,7 +37,7 @@ impl LineOfSightPacked {

/// create a packed line of sight without checking if the values fit within
/// the packed bit widths
pub unsafe fn new_unchecked(distance: u32, angle: u16) -> Self {
pub(crate) unsafe fn new_unchecked(distance: u32, angle: u16) -> Self {
let angle_u32 = u32::from(angle);

let distance_bits = (distance & U22_MAX) << 10u32;
Expand All @@ -54,25 +54,25 @@ impl LineOfSightPacked {
}

/// Distance in meters from the point of view to the visible point.
pub const fn distance(self) -> u32 {
pub(crate) const fn distance(self) -> u32 {
(self.to_u32() >> 10u32) & U22_MAX
}

/// The angle of the line of sight from the point of view.
#[expect(clippy::as_conversions, reason = "(self & 2^10) < 2^16")]
pub const fn angle(self) -> u16 {
pub(crate) const fn angle(self) -> u16 {
(self.to_u32() & U10_MAX) as u16
}

/// Get the raw f32 value. It doesn't represent any useful data, it's just the f32 view of the
/// packed data.
pub const fn as_f32(self) -> f32 {
pub(crate) const fn as_f32(self) -> f32 {
self.0
}

/// calculate the longer packed line of sight, and when distances are equal
/// choose the smaller angle
pub const fn max(self, rhs: Self) -> Self {
pub(crate) const fn max(self, rhs: Self) -> Self {
if rhs.distance() > self.distance() {
return rhs;
}
Expand Down
Loading
Loading