ccalc_plot/proj3d.rs
1//! Orthographic 3D projection for `plot3` / `scatter3`.
2//!
3//! Projects `(x, y, z)` triples onto the 2D plane using MATLAB-compatible
4//! default view angles: azimuth = −37.5°, elevation = 30°.
5//!
6//! The projected `(x', y')` pairs can be passed directly to the ASCII
7//! or file backends as if they were 2D data.
8
9/// Default azimuth angle in degrees (MATLAB convention).
10pub const DEFAULT_AZ: f64 = -37.5;
11/// Default elevation angle in degrees (MATLAB convention).
12pub const DEFAULT_EL: f64 = 30.0;
13
14/// Projects 3D points onto a 2D plane using orthographic projection.
15///
16/// Uses the MATLAB default view (azimuth = −37.5°, elevation = 30°).
17/// All three slices must have the same length.
18///
19/// # Examples
20///
21/// ```
22/// use ccalc_plot::proj3d::project_ortho;
23/// let x = [1.0, 0.0, -1.0];
24/// let y = [0.0, 1.0, 0.0];
25/// let z = [0.0, 0.0, 1.0];
26/// let (px, py) = project_ortho(&x, &y, &z);
27/// assert_eq!(px.len(), 3);
28/// assert_eq!(py.len(), 3);
29/// ```
30pub fn project_ortho(x: &[f64], y: &[f64], z: &[f64]) -> (Vec<f64>, Vec<f64>) {
31 let az = DEFAULT_AZ.to_radians();
32 let el = DEFAULT_EL.to_radians();
33 let (sin_az, cos_az) = (az.sin(), az.cos());
34 let (sin_el, cos_el) = (el.sin(), el.cos());
35
36 let px: Vec<f64> = x
37 .iter()
38 .zip(y.iter())
39 .map(|(&xi, &yi)| -xi * sin_az + yi * cos_az)
40 .collect();
41
42 let py: Vec<f64> = x
43 .iter()
44 .zip(y.iter())
45 .zip(z.iter())
46 .map(|((&xi, &yi), &zi)| xi * cos_az * sin_el + yi * sin_az * sin_el + zi * cos_el)
47 .collect();
48
49 (px, py)
50}