Skip to main content

eulumdat_bevy/
eulumdat_impl.rs

1//! Implementation of PhotometricData for Eulumdat.
2//!
3//! This file bridges the eulumdat crate with the photometric module.
4//! When extracting `bevy_photometry` as a standalone crate, this file
5//! stays in `eulumdat-bevy` while the `photometric/` module is extracted.
6
7use crate::photometric::{parse_color_temperature, parse_cri, PhotometricData};
8use eulumdat::Eulumdat;
9
10impl PhotometricData for Eulumdat {
11    fn sample(&self, c_angle: f64, g_angle: f64) -> f64 {
12        // Eulumdat::sample already handles symmetry expansion and interpolation
13        Eulumdat::sample(self, c_angle, g_angle)
14    }
15
16    fn max_intensity(&self) -> f64 {
17        Eulumdat::max_intensity(self)
18    }
19
20    fn total_flux(&self) -> f64 {
21        self.total_luminous_flux()
22    }
23
24    fn light_output_ratio(&self) -> f64 {
25        self.light_output_ratio / 100.0 // Convert from % to fraction
26    }
27
28    fn downward_fraction(&self) -> f64 {
29        self.downward_flux_fraction / 100.0 // Convert from % to fraction
30    }
31
32    fn dimensions(&self) -> (f32, f32, f32) {
33        // Convert from mm to meters
34        (
35            (self.width / 1000.0) as f32,
36            (self.length / 1000.0) as f32,
37            (self.height / 1000.0).max(0.05) as f32, // Minimum height for visibility
38        )
39    }
40
41    fn color_temperature(&self) -> Option<f32> {
42        self.lamp_sets
43            .first()
44            .and_then(|lamp| parse_color_temperature(&lamp.color_appearance))
45    }
46
47    fn cri(&self) -> Option<f32> {
48        self.lamp_sets
49            .first()
50            .map(|lamp| parse_cri(&lamp.color_rendering_group))
51    }
52
53    fn beam_angle(&self) -> f64 {
54        // Calculate beam angle: find gamma where intensity drops to 50% of max
55        let max_intensity = self.max_intensity();
56        if max_intensity <= 0.0 {
57            return std::f64::consts::FRAC_PI_4; // 45 degrees default
58        }
59
60        let half_max = max_intensity * 0.5;
61
62        // Scan from nadir (0°) outward to find 50% point
63        for g in 0..90 {
64            let intensity = self.sample(0.0, g as f64);
65            if intensity < half_max {
66                return (g as f64).to_radians();
67            }
68        }
69
70        std::f64::consts::FRAC_PI_2 // 90 degrees if not found
71    }
72}
73
74/// Type alias for convenience
75pub type EulumdatLight = crate::photometric::PhotometricLight<Eulumdat>;
76
77/// Type alias for convenience
78pub type EulumdatLightBundle = crate::photometric::PhotometricLightBundle<Eulumdat>;