Annulus sampling (#13471)
# Objective Add random sampling for the `Annulus` primitive. This is part of ongoing work to bring the various `bevy_math` primitives to feature parity. ## Solution `Annulus` implements `ShapeSample`. Boundary sampling is implemented in the obvious way, and interior sampling works exactly as in the implementation for `Circle`, using the fact that the square of the radius should be taken uniformly from between r^2 and R^2, where r and R are the inner and outer radii respectively. ## Testing I generated a bunch of random points and rendered them. Here's 1000 points on the interior of the default annulus: <img width="1440" alt="Screenshot 2024-05-22 at 8 01 34 AM" src="https://github.com/bevyengine/bevy/assets/2975848/19c31bb0-edba-477f-b247-2b12d854afae"> This looks kind of weird around the edges, but I verified that they're all actually inside the annulus, so I assume it has to do with the fact that the rendered circles have some radius.
This commit is contained in:
parent
d2ef88f5e8
commit
5dbd827728
@ -191,6 +191,35 @@ impl ShapeSample for Sphere {
|
||||
}
|
||||
}
|
||||
|
||||
impl ShapeSample for Annulus {
|
||||
type Output = Vec2;
|
||||
|
||||
fn sample_interior<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::Output {
|
||||
let inner_radius = self.inner_circle.radius;
|
||||
let outer_radius = self.outer_circle.radius;
|
||||
|
||||
// Like random sampling for a circle, radius is weighted by the square.
|
||||
let r_squared = rng.gen_range((inner_radius * inner_radius)..(outer_radius * outer_radius));
|
||||
let r = r_squared.sqrt();
|
||||
let theta = rng.gen_range(0.0..TAU);
|
||||
|
||||
Vec2::new(r * theta.cos(), r * theta.sin())
|
||||
}
|
||||
|
||||
fn sample_boundary<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::Output {
|
||||
let total_perimeter = self.inner_circle.perimeter() + self.outer_circle.perimeter();
|
||||
let inner_prob = (self.inner_circle.perimeter() / total_perimeter) as f64;
|
||||
|
||||
// Sample from boundary circles, choosing which one by weighting by perimeter:
|
||||
let inner = rng.gen_bool(inner_prob);
|
||||
if inner {
|
||||
self.inner_circle.sample_boundary(rng)
|
||||
} else {
|
||||
self.outer_circle.sample_boundary(rng)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShapeSample for Rectangle {
|
||||
type Output = Vec2;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user