#[cfg(not(tarpaulin_include))]
mod area {
extern crate pretty_assertions;
use geo::line_string;
use geo::polygon;
use geo::CoordFloat;
use geo::Geometry;
use geo::LineString;
use geo::MultiLineString;
use geo::MultiPolygon;
use geo::Point;
use geo::Polygon;
use geo_types::Coord;
use pretty_assertions::assert_eq;
use d3_geo_rs::area::Area;
use d3_geo_rs::circle::generator::Generator as CircleGenerator;
use d3_geo_rs::data_object::sphere::Sphere;
use d3_geo_rs::graticule::generate as generate_graticule;
use d3_geo_rs::in_delta::in_delta;
use d3_geo_rs::range::range;
fn stripes<T>(a: T, b: T) -> Polygon<T>
where
T: CoordFloat,
{
let mut exterior: Vec<(T, T)> = Vec::new();
let mut interior: Vec<(T, T)> = Vec::new();
for (i, d) in [a, b].iter().enumerate() {
let mut stripe: Vec<(T, T)> = range(
T::from(-180_f64).unwrap(),
T::from(180_f64).unwrap(),
T::from(0.1_f64).unwrap(),
)
.iter()
.map(|x| (*x, *d))
.collect();
stripe.push(stripe[0]);
if i == 0usize {
exterior = stripe;
} else {
stripe.reverse();
interior = stripe;
}
}
Polygon::new(LineString::from(exterior), vec![LineString::from(interior)])
}
#[test]
fn point() {
println!("area: Point");
let g = Geometry::Point(Point::new(0_f64, 0_f64));
let area = Area::calc(&g);
assert_eq!(area, 0_f64);
}
#[test]
fn multipoint() {
println!("area: Mutlipoint");
let g = Geometry::MultiPoint(vec![(0_f64, 1_f64), (2_f64, 3_f64)].into());
let area = Area::calc(&g);
assert_eq!(area, 0_f64);
}
#[test]
fn line_string() {
println!("area: LineString");
let g = Geometry::LineString(vec![(0_f64, 1_f64), (2_f64, 3_f64)].into());
let area = Area::calc(&g);
assert_eq!(area, 0_f64);
}
#[test]
fn multiline_string() {
println!("area: LineString");
let g = MultiLineString(vec![
line_string![(x:0_f64, y:1_f64), (x:2_f64, y:3_f64)],
line_string![(x:4_f64, y:5_f64), (x:6_f64,y:7_f64)],
]);
let area = Area::calc(&g);
assert_eq!(area, 0_f64);
}
#[test]
fn polygon_tiny() {
println!("area: Polygon - tiny");
#[allow(clippy::excessive_precision)]
let g = polygon![
(x:-64.66070178517852, y:18.33986913231323),
(x:-64.66079715091509, y:18.33994007490749),
(x:-64.66074946804680, y:18.33994007490749),
(x:-64.66070178517852, y:18.33986913231323)
];
let area = Area::calc(&g);
assert!(in_delta(area, 4.890516e-13, 1e-13));
}
#[test]
fn polygon_zero_area() {
println!("area: Polygon - zero area");
#[allow(clippy::excessive_precision)]
let g = polygon![
(x: 96.79142432523281, y:5.262704519048153),
(x: 96.81065389253769, y:5.272455576551362),
(x: 96.82988345984256, y:5.272455576551362),
(x: 96.81065389253769, y:5.272455576551362),
(x: 96.79142432523281, y:5.262704519048153)
];
let area = Area::calc(&g);
assert_eq!(area, 0_f32);
}
#[test]
fn polygon_semilune() {
println!("area: Polygon - semilune");
let g = polygon![
(x:0_f64, y:0_f64),
(x:0_f64, y:90_f64),
(x:90_f64, y:0_f64),
(x:0_f64, y:0_f64)
];
let area = Area::calc(&g);
assert!(in_delta(area, std::f64::consts::PI / 2_f64, 1e-6));
}
#[test]
fn polygon_lune() {
println!("area: Polygon - lune");
let g = polygon![
(x:0_f64, y:0_f64),
(x:0_f64, y:90_f64),
(x:90_f64, y:0_f64),
(x:0_f64, y:-90_f64),
(x:0_f64, y:0_f64)
];
let area = Area::calc(&g);
assert!(in_delta(area, std::f64::consts::PI, 1e-6));
}
#[test]
fn polygon_hemispheres_north() {
println!("area: Polygon - hemispheres north");
let g = polygon![
(x:0_f64, y:0_f64),
(x:-90_f64, y:0_f64),
(x:180_f64, y:0_f64),
(x:90_f64, y:0_f64),
(x:0_f64, y:0_f64)
];
let area = Area::calc(&g);
assert!(in_delta(area, 2_f64 * std::f64::consts::PI, 1e-6));
}
#[test]
fn polygon_hemispheres_south() {
println!("area: Polygon - hemispheres south");
let g = polygon![
(x:0_f64, y:0_f64),
(x:90_f64, y:0_f64),
(x:180_f64, y:0_f64),
(x:-90_f64, y:0_f64),
(x:0_f64, y:0_f64)
];
let area = Area::calc(&g);
assert!(in_delta(area, 2_f64 * std::f64::consts::PI, 1e-6));
}
#[test]
fn polygon_hemispheres_east() {
println!("area: Polygon - hemispheres east");
let g = polygon![
(x:0_f64, y:0_f64),
(x:0_f64, y:90_f64),
(x:180_f64, y:0_f64),
(x:0_f64, y:-90_f64),
(x:0_f64, y:0_f64)
];
let area = Area::calc(&g);
assert!(in_delta(area, 2_f64 * std::f64::consts::PI, 1e-6));
}
#[test]
fn polygon_hemispheres_west() {
println!("area: Polygon - hemispheres west");
let g = polygon![
(x:0_f64, y:0_f64),
(x:0_f64, y:-90_f64),
(x:180_f64, y:0_f64),
(x:0_f64, y:90_f64),
(x:0_f64, y:0_f64)
];
let area = Area::calc(&g);
assert!(in_delta(area, 2_f64 * std::f64::consts::PI, 1e-6));
}
#[test]
fn graticule_outline_sphere() {
println!("area: Polygon - graticule outline sphere");
let mut graticule = generate_graticule();
graticule.extent_set([[-180_f64, -90_f64], [180_f64, 90_f64]]);
let outline = graticule.outline();
let area = Area::calc(&outline);
assert!(in_delta(area, 4_f64 * std::f64::consts::PI, 1e-5));
}
#[test]
fn graticule_outline_hemisphere() {
println!("area: Polygon - graticule outline hemisphere");
let mut graticule = generate_graticule();
graticule.extent_set([[-180_f64, 0_f64], [180_f64, 90_f64]]);
let outline = graticule.outline();
let area = Area::calc(&outline);
assert!(in_delta(area, 2_f64 * std::f64::consts::PI, 1e-5));
}
#[test]
fn graticule_outline_semilune() {
println!("area: Polygon - graticule outline semilune");
let mut graticule = generate_graticule();
graticule.extent_set([[0_f64, 0_f64], [90_f64, 90_f64]]);
let outline = graticule.outline();
let area = Area::calc(&outline);
assert!(in_delta(area, std::f64::consts::FRAC_PI_2, 1e-5));
}
#[test]
fn circle_hemisphere() {
println!("area: Polygon - circles hemisphere");
let circle = CircleGenerator::default().radius_set(90_f64).circle();
let area = Area::calc(&circle);
assert!(in_delta(area, 2_f64 * std::f64::consts::PI, 1e-5));
}
#[test]
fn circle_plus_60() {
println!("area: Polygon - circles 60°");
let circle = CircleGenerator::default()
.radius_set(60_f64)
.precision_set(0.1_f64)
.circle();
let area = Area::calc(&circle);
assert!(in_delta(area, std::f64::consts::PI, 1e-5));
}
#[test]
fn circle_plus_60_north() {
println!("area: Polygon - circles 60° North");
let circle = CircleGenerator::default()
.radius_set(60_f64)
.precision_set(0.1_f64)
.center_set(&Coord {
x: 0_f64,
y: 90_f64,
})
.circle();
let area = Area::calc(&circle);
assert!(in_delta(area, std::f64::consts::PI, 1e-5));
}
#[test]
fn circle_plus_45() {
println!("area: Polygon - circles 45°");
let circle = CircleGenerator::default()
.radius_set(45_f64)
.precision_set(0.1_f64)
.circle();
let area = Area::calc(&circle);
assert!(in_delta(
area,
(2_f64 - (2_f64).sqrt()) * std::f64::consts::PI,
1e-5
));
}
#[test]
fn circle_plus_45_north() {
println!("area: Polygon - circles 45° North");
let circle = CircleGenerator::default()
.radius_set(45_f64)
.precision_set(0.1_f64)
.center_set(&Coord {
x: 0_f64,
y: 90_f64,
})
.circle();
let area = Area::calc(&circle);
assert!(in_delta(
area,
(2_f64 - (2_f64).sqrt()) * std::f64::consts::PI,
1e-5
));
}
#[test]
fn circle_plus_45_south() {
println!("area: Polygon - circles 45° South");
let circle = CircleGenerator::default()
.radius_set(45_f64)
.precision_set(0.1_f64)
.center_set(&Coord {
x: 0_f64,
y: -90_f64,
})
.circle();
let area = Area::calc(&circle);
assert!(in_delta(
area,
(2_f64 - (2_f64).sqrt()) * std::f64::consts::PI,
1e-5
));
}
#[test]
fn circle_plus_135() {
println!("area: Polygon - circles 45° South");
let circle = CircleGenerator::default()
.radius_set(135_f64)
.precision_set(0.1_f64)
.circle();
let area = Area::calc(&circle);
assert!(in_delta(
area,
(2_f64 + (2_f64).sqrt()) * std::f64::consts::PI,
1e-5
));
}
#[test]
fn circle_plus_135_north() {
println!("area: Polygon - circles 45° South");
let circle = CircleGenerator::default()
.radius_set(135_f64)
.precision_set(0.1_f64)
.center_set(&Coord {
x: 0_f64,
y: 90_f64,
})
.circle();
let area = Area::calc(&circle);
assert!(in_delta(
area,
(2_f64 + (2_f64).sqrt()) * std::f64::consts::PI,
1e-5
));
}
#[test]
fn circle_plus_135_south() {
println!("area: Polygon - circles 45° South");
let circle = CircleGenerator::default()
.radius_set(135_f64)
.precision_set(0.1_f64)
.center_set(&Coord {
x: 0_f64,
y: -90_f64,
})
.circle();
let area = Area::calc(&circle);
assert!(in_delta(
area,
(2_f64 + (2_f64).sqrt()) * std::f64::consts::PI,
1e-5
));
}
#[test]
fn circles_tiny() {
println!("area: Polygon - circles tiny");
let circle = CircleGenerator::default()
.radius_set(1e-6_f64)
.precision_set(0.1_f64)
.circle();
let area = Area::calc(&circle);
assert!(in_delta(area, 0_f64, 1e-5));
}
#[test]
fn circles_huge() {
println!("area: Polygon - circles tiny");
let circle = CircleGenerator::default()
.radius_set(180_f64 - 1e-6_f64)
.precision_set(0.1_f64)
.circle();
let area = Area::calc(&circle);
assert!(in_delta(area, 4_f64 * std::f64::consts::PI, 1e-5));
}
#[test]
fn circles_60_with_45_hole() {
println!("area: Polygon - circles 60° with 45° hole");
let ring1 = CircleGenerator::default()
.precision_set(0.1)
.radius_set(60_f64)
.circle()
.exterior()
.clone();
let ring2 = CircleGenerator::default()
.precision_set(0.1)
.radius_set(45_f64)
.circle()
.exterior()
.clone();
let rev_vec = ring2.into_iter().rev().collect();
let ring2_rev = LineString(rev_vec);
let polygon = Polygon::new(ring1, vec![ring2_rev]);
assert!(in_delta(
Area::calc(&polygon),
(2_f64.sqrt() - 1_f64) * std::f64::consts::PI,
1e-5
));
}
#[test]
fn circles_45_with_hole_0_0_and_0_90() {
println!("area: Polygon - circles 45° holes at [0°, 0°] and [0°, 90°]");
let ring1 = CircleGenerator::default()
.precision_set(0.1)
.radius_set(45_f64)
.center_set(&Coord { x: 0_f64, y: 0_f64 })
.circle()
.exterior()
.clone();
let rev1_vec: Vec<Coord<f64>> = ring1.into_iter().rev().collect();
let ring1_rev = LineString(rev1_vec);
let ring2 = CircleGenerator::default()
.precision_set(0.1)
.radius_set(45_f64)
.center_set(&Coord {
x: 0_f64,
y: 90_f64,
})
.circle()
.exterior()
.clone();
let rev2_vec = ring2.into_iter().rev().collect();
let ring2_rev = LineString(rev2_vec);
let polygon = Polygon::new(ring1_rev, vec![ring2_rev]);
assert!(in_delta(
Area::calc(&polygon),
2_f64 * 2_f64.sqrt() * std::f64::consts::PI,
1e-5
));
}
#[test]
fn circles_45_with_hole_0_90_and_0_0() {
println!("area: Polygon - circles 45° holes at [0°, 90°] and [0°, 0°]");
let ring1 = CircleGenerator::default()
.precision_set(0.1)
.radius_set(45_f64)
.center_set(&Coord {
x: 0_f64,
y: 90_f64,
})
.circle()
.exterior()
.clone();
let rev1_vec: Vec<Coord<f64>> = ring1.into_iter().rev().collect();
let ring1_rev = LineString(rev1_vec);
let ring2 = CircleGenerator::default()
.precision_set(0.1)
.radius_set(45_f64)
.center_set(&Coord { x: 0_f64, y: 0_f64 })
.circle()
.exterior()
.clone();
let rev2_vec: Vec<Coord<f64>> = ring2.into_iter().rev().collect();
let ring2_rev = LineString(rev2_vec);
let polygon = Polygon::new(ring1_rev, vec![ring2_rev]);
assert!(in_delta(
Area::calc(&polygon),
2_f64 * 2_f64.sqrt() * std::f64::consts::PI,
1e-5
));
}
#[test]
fn stripes_45_minus_45() {
println!("area: Polygon - stripes 45°, -45°");
let stripes = stripes(45_f64, -45_f64);
let area = Area::calc(&stripes);
assert!(in_delta(
area,
std::f64::consts::PI * 2_f64 * 2f64.sqrt(),
1e-5
));
}
#[test]
fn stripes_minus_45_plus_45() {
println!("area: Polygon - stripes 45°, 45°");
let stripes = stripes(-45_f64, 45_f64);
let area = Area::calc(&stripes);
assert!(in_delta(
area,
std::f64::consts::PI * 2_f64 * (2_f64 - 2f64.sqrt()),
1e-5
));
}
#[test]
fn stripes_45_30() {
println!("area: Polygon - stripes 45°, 30°");
let stripes = stripes(45_f64, 30_f64);
let area = Area::calc(&stripes);
assert!(in_delta(
area,
std::f64::consts::PI * (2f64.sqrt() - 1_f64),
1e-5
));
}
#[test]
fn two_hemispheres() {
println!("area: MultiPolygon two hemispheres");
let mp = MultiPolygon(vec![
Polygon::new(
line_string![
(x: 0_f64, y:0_f64),
(x:-90_f64, y:0_f64),
(x: 180_f64, y: 0_f64),
(x:90_f64, y:0_f64),
(x:0_f64, y:0_f64)
],
vec![],
),
Polygon::new(
line_string![
(x: 0_f64, y:0_f64),
(x:90_f64, y:0_f64),
(x: 180_f64, y: 0_f64),
(x:-90_f64, y:0_f64),
(x:0_f64, y:0_f64)
],
vec![],
),
]);
let data_o = Geometry::MultiPolygon(mp);
let area = Area::calc(&data_o);
assert!(in_delta(area, 4_f64 * std::f64::consts::PI, 1e-6));
}
#[test]
fn sphere() {
println!("area: Sphere");
let g = Sphere::default();
let area = Area::calc(&g);
assert!(in_delta(area, 4_f64 * std::f64::consts::PI, 1e-6));
}
}