hoomd_bevy/representation/
plane_mesh.rs

1// Copyright (c) 2024-2026 The Regents of the University of Michigan.
2// Part of hoomd-rs, released under the BSD 3-Clause License.
3
4//! A 2D mesh
5//!
6//! The [`PlaneMesh`] representation places a bevy `Mesh2d` at each site.
7
8use bevy::prelude::*;
9use itertools::{
10    EitherOrBoth::{Both, Left, Right},
11    Itertools,
12};
13use std::marker::PhantomData;
14
15/// Represent each entity with a triangle mesh in 2D.
16///
17/// Each entity is an instanced copy of the given mesh. Provide the position and
18/// orientation of each mesh to [`sync`](Self::sync).
19///
20/// All triangle meshes of the same type must have the same material. To display
21/// meshes with different materials, call `setup` and `sync` for multiple types of
22/// triangle meshes with different marker types.
23///
24/// To use:
25/// * Add [`setup`](Self::setup) to the `Startup` schedule.
26/// * Call [`sync`](Self::sync) in an `Update` schedule that runs after `AdvanceSet`.
27#[derive(Component)]
28pub struct PlaneMesh<T> {
29    /// Mark the type of the disk.
30    marker: PhantomData<T>,
31}
32
33/// Assets that represent a 3D mesh in the scene.
34#[derive(Resource)]
35pub struct Representation<T> {
36    /// The mesh.
37    mesh: Handle<Mesh>,
38    /// The material.
39    material: Handle<ColorMaterial>,
40    /// Mark the type of the triangle mesh assets.
41    marker: PhantomData<T>,
42}
43
44impl<T> Representation<T> {
45    /// Get the material
46    #[must_use]
47    pub fn material(&self) -> &Handle<ColorMaterial> {
48        &self.material
49    }
50}
51
52impl<T: Send + Sync + 'static> PlaneMesh<T> {
53    /// Create assets to render instanced triangle meshes.
54    pub fn setup(
55        mesh_material: In<(Mesh, ColorMaterial)>,
56        mut commands: Commands,
57        mut meshes: ResMut<Assets<Mesh>>,
58        mut materials: ResMut<Assets<ColorMaterial>>,
59    ) {
60        let (mesh, material) = mesh_material.0;
61        let mesh = meshes.add(mesh);
62        let material = materials.add(material.clone());
63
64        commands.insert_resource(Representation::<T> {
65            mesh,
66            material,
67            marker: PhantomData,
68        });
69    }
70
71    /// Copy the current positions of simulation particles to bevy entities.
72    pub fn sync<I>(
73        commands: &mut Commands,
74        plane_mesh_representation: Res<Representation<T>>,
75        query: Query<(Entity, &mut Transform), With<Self>>,
76        triangle_meshes: I,
77    ) where
78        I: IntoIterator<Item = (Vec3, f32)>,
79    {
80        for item in &mut query.into_iter().zip_longest(triangle_meshes) {
81            match item {
82                Both((_, mut transform), (position, theta)) => {
83                    transform.translation = position;
84                    transform.rotation = Quat::from_rotation_z(theta);
85                }
86                Left((entity, _)) => commands.entity(entity).despawn(),
87                Right((position, theta)) => {
88                    commands.spawn((
89                        Mesh2d(plane_mesh_representation.mesh.clone()),
90                        MeshMaterial2d(plane_mesh_representation.material.clone()),
91                        Transform::from_translation(position)
92                            .with_rotation(Quat::from_rotation_z(theta)),
93                        Self {
94                            marker: PhantomData,
95                        },
96                    ));
97                }
98            }
99        }
100    }
101}