1use core::ops::{Range, RangeInclusive};
65
66use rand::distributions::uniform::{
67 SampleBorrow, SampleRange, SampleUniform, UniformFloat, UniformSampler,
68};
69use rand::distributions::{Distribution, Standard};
70use rand::Rng;
71
72use crate::float::Float;
73use crate::units::{Degrees, Gradians, Radians, Turns};
74use crate::{Angle, AngleUnbounded};
75
76impl<F: Float> Distribution<Angle<F>> for Standard
81where
82 Self: Distribution<F>,
83{
84 #[inline]
85 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Angle<F> {
86 let x = rng.gen::<F>();
88
89 let x = x * F::TAU; let x = x - F::PI; let x = -x; debug_assert!(-F::PI < x && x <= F::PI);
94
95 Angle::from_radians_unchecked(x)
96 }
97}
98
99impl<F: Float> Distribution<AngleUnbounded<F>> for Standard
100where
101 Self: Distribution<Angle<F>>,
102{
103 #[inline]
104 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> AngleUnbounded<F> {
105 rng.gen::<Angle<F>>().to_unbounded()
106 }
107}
108
109macro_rules! impl_distribution_for_unit {
110 (
111 $($Unit:ident),+
112 ) => {
113 $(
114 impl<T> Distribution<$Unit<T>> for Standard
115 where
116 Self: Distribution<T>,
117 {
118 #[inline]
119 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> $Unit<T> {
120 $Unit(rng.gen())
121 }
122 }
123 )+
124 };
125}
126
127impl_distribution_for_unit!(Radians, Degrees, Turns, Gradians);
128
129#[derive(Clone, Copy, Debug, PartialEq)]
138pub struct UniformAngle<F>(UniformFloat<F>);
139
140impl<F: Float> SampleUniform for Angle<F>
141where
142 UniformFloat<F>: UniformSampler<X = F>,
143 F: SampleBorrow<F>,
144{
145 type Sampler = UniformAngle<F>;
146}
147
148impl<F: Float> UniformSampler for UniformAngle<F>
149where
150 UniformFloat<F>: UniformSampler<X = F>,
151 F: SampleBorrow<F>,
152{
153 type X = Angle<F>;
154
155 #[inline]
156 fn new<B1, B2>(low: B1, high: B2) -> Self
157 where
158 B1: SampleBorrow<Self::X> + Sized,
159 B2: SampleBorrow<Self::X> + Sized,
160 {
161 let low = low.borrow().to_radians();
162 let mut high = high.borrow().to_radians();
163 if low > high {
164 high += F::TAU;
165 }
166 Self(UniformFloat::new(low, high))
167 }
168
169 #[inline]
170 fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
171 where
172 B1: SampleBorrow<Self::X> + Sized,
173 B2: SampleBorrow<Self::X> + Sized,
174 {
175 let low = low.borrow().to_radians();
176 let mut high = high.borrow().to_radians();
177 if low > high {
178 high += F::TAU;
179 }
180 Self(UniformFloat::new_inclusive(low, high))
181 }
182
183 #[inline]
184 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
185 let x = self.0.sample(rng);
186 Angle::from_radians(x)
187 }
188}
189
190impl<F: Float> SampleRange<Angle<F>> for Range<Angle<F>>
191where
192 UniformFloat<F>: UniformSampler<X = F>,
193 F: SampleBorrow<F>,
194{
195 #[inline]
196 fn sample_single<R: rand::RngCore + ?Sized>(self, rng: &mut R) -> Angle<F> {
197 UniformAngle::sample_single(self.start, self.end, rng)
198 }
199
200 #[inline]
201 fn is_empty(&self) -> bool {
202 self.start == self.end
203 }
204}
205
206impl<F: Float> SampleRange<Angle<F>> for RangeInclusive<Angle<F>>
207where
208 UniformFloat<F>: UniformSampler<X = F>,
209 F: SampleBorrow<F>,
210{
211 #[inline]
212 fn sample_single<R: rand::RngCore + ?Sized>(self, rng: &mut R) -> Angle<F> {
213 UniformAngle::sample_single_inclusive(self.start(), self.end(), rng)
214 }
215
216 #[inline]
217 fn is_empty(&self) -> bool {
218 false
219 }
220}
221
222#[derive(Clone, Copy, Debug, PartialEq)]
229pub struct UniformAngleUnbounded<F>(UniformFloat<F>);
230
231impl<F: Copy> SampleUniform for AngleUnbounded<F>
232where
233 UniformFloat<F>: UniformSampler<X = F>,
234 F: SampleBorrow<F>,
235{
236 type Sampler = UniformAngleUnbounded<F>;
237}
238
239impl<F: Copy> UniformSampler for UniformAngleUnbounded<F>
240where
241 UniformFloat<F>: UniformSampler<X = F>,
242 F: SampleBorrow<F>,
243{
244 type X = AngleUnbounded<F>;
245
246 fn new<B1, B2>(low: B1, high: B2) -> Self
247 where
248 B1: SampleBorrow<Self::X> + Sized,
249 B2: SampleBorrow<Self::X> + Sized,
250 {
251 let low = low.borrow().to_radians();
252 let high = high.borrow().to_radians();
253 Self(UniformFloat::new(low, high))
254 }
255
256 fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
257 where
258 B1: SampleBorrow<Self::X> + Sized,
259 B2: SampleBorrow<Self::X> + Sized,
260 {
261 let low = low.borrow().to_radians();
262 let high = high.borrow().to_radians();
263 Self(UniformFloat::new_inclusive(low, high))
264 }
265
266 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
267 let x = self.0.sample(rng);
268 AngleUnbounded::from_radians(x)
269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use rand::Rng;
275
276 use crate::{units::*, Angle32, Angle64, AngleUnbounded32, AngleUnbounded64};
277
278 #[test]
279 fn check_rand_impl() {
280 let mut rng = rand::thread_rng();
281
282 macro_rules! check {
284 (
285 $($angle:ident),+
286 ) => {
287 $(
288 let _: $angle = rand::random();
289 let _: Radians<$angle> = rand::random();
290 let _: Degrees<$angle> = rand::random();
291 let _: Turns<$angle> = rand::random();
292 let _: Gradians<$angle> = rand::random();
293
294 let _: $angle = rng.gen_range($angle::ZERO..$angle::RAD_PI);
295 let _: $angle = rng.gen_range($angle::ZERO..=$angle::RAD_PI);
296 )+
297 };
298 }
299
300 check!(Angle32, Angle64, AngleUnbounded32, AngleUnbounded64);
301 }
302}