Trait bevy::math::prelude::ShapeSample

pub trait ShapeSample {
    type Output;

    // Required methods
    fn sample_interior<R>(&self, rng: &mut R) -> Self::Output
       where R: Rng + ?Sized;
    fn sample_boundary<R>(&self, rng: &mut R) -> Self::Output
       where R: Rng + ?Sized;

    // Provided methods
    fn interior_dist(self) -> impl Distribution<Self::Output>
       where Self: Sized { ... }
    fn boundary_dist(self) -> impl Distribution<Self::Output>
       where Self: Sized { ... }
}
Expand description

Exposes methods to uniformly sample a variety of primitive shapes.

Required Associated Types§

type Output

The type of vector returned by the sample methods, Vec2 for 2D shapes and Vec3 for 3D shapes.

Required Methods§

fn sample_interior<R>(&self, rng: &mut R) -> Self::Output
where R: Rng + ?Sized,

Uniformly sample a point from inside the area/volume of this shape, centered on 0.

Shapes like Cylinder, Capsule2d and Capsule3d are oriented along the y-axis.

§Example
let square = Rectangle::new(2.0, 2.0);

// Returns a Vec2 with both x and y between -1 and 1.
println!("{:?}", square.sample_interior(&mut rand::thread_rng()));

fn sample_boundary<R>(&self, rng: &mut R) -> Self::Output
where R: Rng + ?Sized,

Uniformly sample a point from the surface of this shape, centered on 0.

Shapes like Cylinder, Capsule2d and Capsule3d are oriented along the y-axis.

§Example
let square = Rectangle::new(2.0, 2.0);

// Returns a Vec2 where one of the coordinates is at ±1,
//  and the other is somewhere between -1 and 1.
println!("{:?}", square.sample_boundary(&mut rand::thread_rng()));

Provided Methods§

fn interior_dist(self) -> impl Distribution<Self::Output>
where Self: Sized,

Extract a Distribution whose samples are points of this shape’s interior, taken uniformly.

§Example
let square = Rectangle::new(2.0, 2.0);
let rng = rand::thread_rng();

// Iterate over points randomly drawn from `square`'s interior:
for random_val in square.interior_dist().sample_iter(rng).take(5) {
    println!("{:?}", random_val);
}
Examples found in repository?
examples/math/random_sampling.rs (line 196)
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
fn handle_keypress(
    mut commands: Commands,
    keyboard: Res<ButtonInput<KeyCode>>,
    mut mode: ResMut<Mode>,
    shape: Res<SampledShape>,
    mut random_source: ResMut<RandomSource>,
    sample_mesh: Res<PointMesh>,
    sample_material: Res<PointMaterial>,
    samples: Query<Entity, With<SamplePoint>>,
) {
    // R => restart, deleting all samples
    if keyboard.just_pressed(KeyCode::KeyR) {
        for entity in &samples {
            commands.entity(entity).despawn();
        }
    }

    // S => sample once
    if keyboard.just_pressed(KeyCode::KeyS) {
        let rng = &mut random_source.0;

        // Get a single random Vec3:
        let sample: Vec3 = match *mode {
            Mode::Interior => shape.0.sample_interior(rng),
            Mode::Boundary => shape.0.sample_boundary(rng),
        };

        // Spawn a sphere at the random location:
        commands.spawn((
            PbrBundle {
                mesh: sample_mesh.0.clone(),
                material: sample_material.0.clone(),
                transform: Transform::from_translation(sample),
                ..default()
            },
            SamplePoint,
        ));

        // NOTE: The point is inside the cube created at setup just because of how the
        // scene is constructed; in general, you would want to use something like
        // `cube_transform.transform_point(sample)` to get the position of where the sample
        // would be after adjusting for the position and orientation of the cube.
        //
        // If the spawned point also needed to follow the position of the cube as it moved,
        // then making it a child entity of the cube would be a good approach.
    }

    // D => generate many samples
    if keyboard.just_pressed(KeyCode::KeyD) {
        let mut rng = &mut random_source.0;

        // Get 100 random Vec3s:
        let samples: Vec<Vec3> = match *mode {
            Mode::Interior => {
                let dist = shape.0.interior_dist();
                dist.sample_iter(&mut rng).take(100).collect()
            }
            Mode::Boundary => {
                let dist = shape.0.boundary_dist();
                dist.sample_iter(&mut rng).take(100).collect()
            }
        };

        // For each sample point, spawn a sphere:
        for sample in samples {
            commands.spawn((
                PbrBundle {
                    mesh: sample_mesh.0.clone(),
                    material: sample_material.0.clone(),
                    transform: Transform::from_translation(sample),
                    ..default()
                },
                SamplePoint,
            ));
        }

        // NOTE: See the previous note above regarding the positioning of these samples
        // relative to the transform of the cube containing them.
    }

    // M => toggle mode between interior and boundary.
    if keyboard.just_pressed(KeyCode::KeyM) {
        match *mode {
            Mode::Interior => *mode = Mode::Boundary,
            Mode::Boundary => *mode = Mode::Interior,
        }
    }
}

fn boundary_dist(self) -> impl Distribution<Self::Output>
where Self: Sized,

Extract a Distribution whose samples are points of this shape’s boundary, taken uniformly.

§Example
let square = Rectangle::new(2.0, 2.0);
let rng = rand::thread_rng();

// Iterate over points randomly drawn from `square`'s boundary:
for random_val in square.boundary_dist().sample_iter(rng).take(5) {
    println!("{:?}", random_val);
}
Examples found in repository?
examples/math/random_sampling.rs (line 200)
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
fn handle_keypress(
    mut commands: Commands,
    keyboard: Res<ButtonInput<KeyCode>>,
    mut mode: ResMut<Mode>,
    shape: Res<SampledShape>,
    mut random_source: ResMut<RandomSource>,
    sample_mesh: Res<PointMesh>,
    sample_material: Res<PointMaterial>,
    samples: Query<Entity, With<SamplePoint>>,
) {
    // R => restart, deleting all samples
    if keyboard.just_pressed(KeyCode::KeyR) {
        for entity in &samples {
            commands.entity(entity).despawn();
        }
    }

    // S => sample once
    if keyboard.just_pressed(KeyCode::KeyS) {
        let rng = &mut random_source.0;

        // Get a single random Vec3:
        let sample: Vec3 = match *mode {
            Mode::Interior => shape.0.sample_interior(rng),
            Mode::Boundary => shape.0.sample_boundary(rng),
        };

        // Spawn a sphere at the random location:
        commands.spawn((
            PbrBundle {
                mesh: sample_mesh.0.clone(),
                material: sample_material.0.clone(),
                transform: Transform::from_translation(sample),
                ..default()
            },
            SamplePoint,
        ));

        // NOTE: The point is inside the cube created at setup just because of how the
        // scene is constructed; in general, you would want to use something like
        // `cube_transform.transform_point(sample)` to get the position of where the sample
        // would be after adjusting for the position and orientation of the cube.
        //
        // If the spawned point also needed to follow the position of the cube as it moved,
        // then making it a child entity of the cube would be a good approach.
    }

    // D => generate many samples
    if keyboard.just_pressed(KeyCode::KeyD) {
        let mut rng = &mut random_source.0;

        // Get 100 random Vec3s:
        let samples: Vec<Vec3> = match *mode {
            Mode::Interior => {
                let dist = shape.0.interior_dist();
                dist.sample_iter(&mut rng).take(100).collect()
            }
            Mode::Boundary => {
                let dist = shape.0.boundary_dist();
                dist.sample_iter(&mut rng).take(100).collect()
            }
        };

        // For each sample point, spawn a sphere:
        for sample in samples {
            commands.spawn((
                PbrBundle {
                    mesh: sample_mesh.0.clone(),
                    material: sample_material.0.clone(),
                    transform: Transform::from_translation(sample),
                    ..default()
                },
                SamplePoint,
            ));
        }

        // NOTE: See the previous note above regarding the positioning of these samples
        // relative to the transform of the cube containing them.
    }

    // M => toggle mode between interior and boundary.
    if keyboard.just_pressed(KeyCode::KeyM) {
        match *mode {
            Mode::Interior => *mode = Mode::Boundary,
            Mode::Boundary => *mode = Mode::Interior,
        }
    }
}

Object Safety§

This trait is not object safe.

Implementors§