use std::num::NonZeroUsize;
use crate::cpl::CslStringList;
use crate::errors;
use crate::raster::processing::dem::options::common_dem_options;
use crate::raster::processing::dem::DemSlopeAlg;
use super::options::CommonOptions;
#[derive(Debug, Clone, Default)]
pub struct SlopeOptions {
common_options: CommonOptions,
algorithm: Option<DemSlopeAlg>,
scale: Option<f64>,
percentage_results: Option<bool>,
}
impl SlopeOptions {
pub fn new() -> Self {
Default::default()
}
common_dem_options!();
pub fn with_algorithm(&mut self, algorithm: DemSlopeAlg) -> &mut Self {
self.algorithm = Some(algorithm);
self
}
pub fn with_scale(&mut self, scale: f64) -> &mut Self {
self.scale = Some(scale);
self
}
pub fn with_percentage_results(&mut self, state: bool) -> &mut Self {
self.percentage_results = Some(state);
self
}
pub fn to_options_list(&self) -> errors::Result<CslStringList> {
let mut opts = CslStringList::default();
self.store_common_options_to(&mut opts)?;
if let Some(alg) = self.algorithm {
opts.add_string("-alg")?;
opts.add_string(alg.to_gdal_option())?;
}
if let Some(scale) = self.scale {
opts.add_string("-s")?;
opts.add_string(&scale.to_string())?;
}
if self.percentage_results == Some(true) {
opts.add_string("-p")?;
}
Ok(opts)
}
}
#[cfg(test)]
mod tests {
use crate::cpl::CslStringList;
use crate::errors::Result;
use crate::raster::processing::dem::slope;
use crate::raster::StatisticsAll;
use crate::test_utils::{fixture, InMemoryFixture};
use crate::Dataset;
use crate::{assert_near, GeoTransformEx};
use super::*;
#[test]
fn test_options() -> Result<()> {
let mut proc = SlopeOptions::new();
proc.with_input_band(2.try_into().unwrap())
.with_algorithm(DemSlopeAlg::ZevenbergenThorne)
.with_scale(98473.0)
.with_compute_edges(true)
.with_percentage_results(true)
.with_output_format("GTiff")
.with_additional_options("CPL_DEBUG=ON".parse()?);
let expected: CslStringList =
"-compute_edges -b 2 -of GTiff CPL_DEBUG=ON -alg ZevenbergenThorne -s 98473 -p"
.parse()?;
assert_eq!(expected.to_string(), proc.to_options_list()?.to_string());
Ok(())
}
#[test]
fn test_slope() -> Result<()> {
fn scaling_estimate(ds: &Dataset) -> f64 {
let (_, lat) = ds.geo_transform().unwrap().apply(0., 0.);
0.5 * (111120.0 + lat.to_radians().cos() * 111120.0)
}
let ds = Dataset::open(fixture("dem-hills.tiff"))?;
let scale_factor = scaling_estimate(&ds);
let mut opts = SlopeOptions::new();
opts.with_algorithm(DemSlopeAlg::Horn)
.with_percentage_results(true)
.with_scale(scale_factor);
let output = InMemoryFixture::new("dem-hills-slope.tiff");
let slope = slope(&ds, output.path(), &opts)?;
let stats = slope.rasterband(1)?.get_statistics(true, false)?.unwrap();
let expected = StatisticsAll {
min: 0.0,
max: 65.440422058105,
mean: 6.1710967990449,
std_dev: 8.73558602352,
};
assert_near!(StatisticsAll, stats, expected, epsilon = 1e-8);
Ok(())
}
}