use super::Point2D;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct IsometricProjection {
pub tilt: f64,
pub center_x: f64,
pub center_y: f64,
pub scale: f64,
}
impl IsometricProjection {
pub fn new(
tilt_degrees: f64,
center_x: f64,
center_y: f64,
max_intensity: f64,
max_radius: f64,
) -> Self {
Self {
tilt: tilt_degrees.to_radians(),
center_x,
center_y,
scale: if max_radius > 0.0 {
max_intensity / max_radius
} else {
1.0
},
}
}
pub fn project(&self, c_angle: f64, g_angle: f64, intensity: f64) -> Point2D {
let c_rad = c_angle.to_radians();
let g_rad = g_angle.to_radians();
let r = intensity / self.scale;
let x3d = r * g_rad.sin() * c_rad.cos();
let y3d = r * g_rad.sin() * c_rad.sin();
let z3d = r * g_rad.cos();
let cos_tilt = self.tilt.cos();
let sin_tilt = self.tilt.sin();
let sx = self.center_x + x3d;
let sy = self.center_y - y3d * cos_tilt - z3d * sin_tilt;
Point2D::new(sx, sy)
}
pub fn project_horizontal(&self, c_angle: f64, radius: f64) -> Point2D {
self.project(c_angle, 90.0, radius * self.scale)
}
pub fn horizontal_compression(&self) -> f64 {
self.tilt.cos()
}
}
#[allow(dead_code)]
pub fn polar_to_cartesian(angle_degrees: f64, radius: f64) -> Point2D {
let rad = angle_degrees.to_radians();
Point2D::new(radius * rad.cos(), radius * rad.sin())
}
#[allow(dead_code)]
pub fn gamma_to_polar_y(gamma_degrees: f64, center_y: f64, radius: f64) -> f64 {
let gamma_rad = gamma_degrees.to_radians();
center_y - radius * gamma_rad.sin()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_isometric_projection() {
let proj = IsometricProjection::new(60.0, 250.0, 250.0, 100.0, 200.0);
let center = proj.project(0.0, 0.0, 0.0);
assert!((center.x - 250.0).abs() < 0.01);
let right = proj.project(0.0, 90.0, 100.0);
assert!(right.x > 250.0);
let left = proj.project(180.0, 90.0, 100.0);
assert!(left.x < 250.0); }
#[test]
fn test_polar_to_cartesian() {
let p0 = polar_to_cartesian(0.0, 100.0);
assert!((p0.x - 100.0).abs() < 0.01);
assert!(p0.y.abs() < 0.01);
let p90 = polar_to_cartesian(90.0, 100.0);
assert!(p90.x.abs() < 0.01);
assert!((p90.y - 100.0).abs() < 0.01);
}
}