use scirs2_core::ndarray::array;
use scirs2_spatial::transform::spherical::{
cart_to_spherical, cart_to_spherical_batch, geodesic_distance, spherical_to_cart,
spherical_to_cart_batch, spherical_triangle_area,
};
use scirs2_spatial::SpatialResult;
use std::f64::consts::PI;
#[allow(dead_code)]
fn main() -> SpatialResult<()> {
println!("Spherical Coordinate Transformations Example");
println!("===========================================\n");
println!("Single Point Conversions");
println!("-----------------------");
let points_cart = [
array![1.0, 0.0, 0.0], array![0.0, 1.0, 0.0], array![0.0, 0.0, 1.0], array![1.0, 1.0, 1.0], ];
let point_names = ["X-axis", "Y-axis", "Z-axis", "Octant (1,1,1)"];
for (i, point) in points_cart.iter().enumerate() {
println!("\n{}. {} point:", i + 1, point_names[i]);
println!(
" Cartesian coordinates: [{:.4}, {:.4}, {:.4}]",
point[0], point[1], point[2]
);
let spherical = cart_to_spherical(&point.view())?;
println!(" Spherical coordinates (r, θ, φ):");
println!(" r = {:.4}", spherical[0]);
println!(
" θ (radians) = {:.4}, θ (degrees) = {:.2}°",
spherical[1],
spherical[1] * 180.0 / PI
);
println!(
" φ (radians) = {:.4}, φ (degrees) = {:.2}°",
spherical[2],
spherical[2] * 180.0 / PI
);
let cart_again = spherical_to_cart(&spherical.view())?;
println!(
" Back to Cartesian: [{:.4}, {:.4}, {:.4}]",
cart_again[0], cart_again[1], cart_again[2]
);
}
println!("\n\nBatch Conversion");
println!("----------------");
let batch_cart = array![
[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 1.0, 1.0], ];
println!("Cartesian coordinates (batch):");
for (i, row) in batch_cart.rows().into_iter().enumerate() {
println!(" {}: [{:.4}, {:.4}, {:.4}]", i + 1, row[0], row[1], row[2]);
}
let batch_spherical = cart_to_spherical_batch(&batch_cart.view())?;
println!("\nSpherical coordinates (batch):");
println!(" [r, θ (rad), φ (rad)]");
for (i, row) in batch_spherical.rows().into_iter().enumerate() {
println!(" {}: [{:.4}, {:.4}, {:.4}]", i + 1, row[0], row[1], row[2]);
}
let batch_cart_again = spherical_to_cart_batch(&batch_spherical.view())?;
println!("\nBack to Cartesian (batch):");
for (i, row) in batch_cart_again.rows().into_iter().enumerate() {
println!(" {}: [{:.4}, {:.4}, {:.4}]", i + 1, row[0], row[1], row[2]);
}
println!("\n\nGeodesic Distance on a Sphere");
println!("---------------------------");
let north_pole = array![1.0, 0.0, 0.0]; let south_pole = array![1.0, PI, 0.0]; let equator_0 = array![1.0, PI / 2.0, 0.0]; let equator_90 = array![1.0, PI / 2.0, PI / 2.0];
println!("Points on a unit sphere:");
println!(" 1. North pole: (r=1, θ=0°, φ=0°)");
println!(" 2. South pole: (r=1, θ=180°, φ=0°)");
println!(" 3. Equator at φ=0°: (r=1, θ=90°, φ=0°)");
println!(" 4. Equator at φ=90°: (r=1, θ=90°, φ=90°)");
println!("\nGeodetic distances:");
let distance = geodesic_distance(&north_pole.view(), &south_pole.view())?;
println!(
" North pole to South pole: {:.4} radians = {:.2}°",
distance,
distance * 180.0 / PI
);
let distance = geodesic_distance(&north_pole.view(), &equator_0.view())?;
println!(
" North pole to Equator: {:.4} radians = {:.2}°",
distance,
distance * 180.0 / PI
);
let distance = geodesic_distance(&equator_0.view(), &equator_90.view())?;
println!(
" Between points 90° apart on equator: {:.4} radians = {:.2}°",
distance,
distance * 180.0 / PI
);
println!("\n\nSpherical Triangle Area");
println!("----------------------");
let area = spherical_triangle_area(&north_pole.view(), &equator_0.view(), &equator_90.view())?;
println!("Triangle: North pole and two points 90° apart on the equator");
println!(
" Area: {:.4} steradians (out of 4π = {:.4} for the whole sphere)",
area,
4.0 * PI
);
println!(
" This is 1/8 of the sphere's surface, or {:.2}%",
100.0 * area / (4.0 * PI)
);
let p1 = array![1.0, 0.0, 0.0]; let p2 = array![1.0, PI / 2.0, 0.0]; let p3 = array![1.0, PI / 2.0, PI / 2.0];
let area = spherical_triangle_area(&p1.view(), &p2.view(), &p3.view())?;
println!("\nTriangle: North pole and two points on the equator 90° apart");
println!(" Area: {area:.4} steradians");
println!("\n\nError Handling Examples");
println!("---------------------");
let p1 = array![1.0, 0.0, 0.0]; let p2 = array![2.0, 0.0, 0.0];
println!("Points on different spheres:");
println!(" p1: (r=1, θ=0°, φ=0°)");
println!(" p2: (r=2, θ=0°, φ=0°)");
match geodesic_distance(&p1.view(), &p2.view()) {
Ok(distance) => println!(" Distance: {distance:.4}"),
Err(e) => println!(" Error: {e}"),
}
let invalid = array![1.0, -0.1, 0.0];
println!("\nInvalid spherical coordinates:");
println!(" (r=1, θ=-0.1, φ=0°)");
match spherical_to_cart(&invalid.view()) {
Ok(cart) => println!(" Converted to: {cart:?}"),
Err(e) => println!(" Error: {e}"),
}
Ok(())
}