pub struct Render3D<'a> {
pub painter: &'a Painter,
pub center: Pos2,
pub ground_y: f32,
pub camera_orbit: f32,
pub zoom: f32,
}Expand description
Contexte transmis lors du callback de dessin d’une frame.
Regroupe tout ce qu’il faut pour projeter un point 3D vers l’écran et dessiner par-dessus (maillages, repères, trajectoires, graphes).
Fields§
§painter: &'a Painter§center: Pos2§ground_y: f32§camera_orbit: f32§zoom: f32Implementations§
Source§impl<'a> Render3D<'a>
impl<'a> Render3D<'a>
Sourcepub fn world_to_screen(&self, pos: Vec3) -> Pos2
pub fn world_to_screen(&self, pos: Vec3) -> Pos2
Projection d’un point du monde 3D vers un point écran 2D.
Projection orthographique simplifiée avec rotation orbitale sur l’axe horizontal ; suffisante pour de la télémétrie temps réel.
Sourcepub fn draw_mesh(
&self,
mesh: &Mesh3D,
position: Vec3,
rotation: Rotation3D,
color: Color32,
)
pub fn draw_mesh( &self, mesh: &Mesh3D, position: Vec3, rotation: Rotation3D, color: Color32, )
Dessine un maillage en fil de fer à la position/orientation données.
Examples found in repository?
46 fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
47 let ctx = ui.ctx().clone();
48
49 // 1. Simulation physique / télémétrie
50 if !self.paused {
51 let dt = ctx.input(|i| i.stable_dt).min(0.1); // Pas de temps fluide
52 self.time += dt * self.orbit_speed;
53
54 // Orbite circulaire avec oscillation verticale (altitude)
55 self.state.position = [
56 self.time.cos() * self.orbit_radius,
57 (self.time * 1.5).sin() * 0.6,
58 self.time.sin() * self.orbit_radius,
59 ];
60
61 // Attachement d'attitude (Roll, Pitch, Yaw dynamiques)
62 self.state.rotation = Rotation3D::new(
63 (self.time * 2.0).sin() * 0.2, // Léger roulis
64 (self.time * 1.5).cos() * 0.3, // Tangage
65 self.time * 0.5, // Lacet continu
66 );
67
68 // Mise à jour des historiques
69 self.trail.push(self.state.position);
70
71 self.altitude_history.push(self.state.position[1]);
72 if self.altitude_history.len() > 200 {
73 self.altitude_history.remove(0);
74 }
75 }
76
77 // 2. Panneau de contrôle latéral (IHM)
78 egui::Panel::left("control_panel")
79 .resizable(true)
80 .default_size(240.0)
81 .show(ui, |ui| {
82 ui.heading("🛰️ Orbit Viewer");
83 ui.small("Station de sol & Télémétrie");
84 ui.separator();
85
86 // Contrôles de simulation
87 ui.label("Contrôles de l'orbite :");
88 ui.checkbox(&mut self.paused, "Pause simulation");
89 ui.add(egui::Slider::new(&mut self.orbit_speed, 0.1..=3.0).text("Vitesse"));
90 ui.add(egui::Slider::new(&mut self.orbit_radius, 0.5..=4.0).text("Rayon"));
91
92 if ui.button("🗑️ Effacer la trajectoire").clicked() {
93 self.trail.clear();
94 self.altitude_history.clear();
95 }
96
97 ui.separator();
98
99 // Telemetry Data Box
100 ui.label("Données en direct :");
101 egui::Frame::group(ui.style()).show(ui, |ui| {
102 ui.monospace(format!("Pos X: {:+.2} m", self.state.position[0]));
103 ui.monospace(format!("Alt Y: {:+.2} m", self.state.position[1]));
104 ui.monospace(format!("Pos Z: {:+.2} m", self.state.position[2]));
105 ui.separator();
106 ui.monospace(format!("Pitch: {:+.2} rad", self.state.rotation.pitch));
107 ui.monospace(format!("Yaw: {:+.2} rad", self.state.rotation.yaw));
108 });
109
110 ui.separator();
111 ui.collapsing("🖱️ Contrôles Caméra", |ui| {
112 ui.small("• Clic Gauche + Glisser : Orbite");
113 ui.small("• Molette : Zoom");
114 ui.small("• Clic Droit / Molette : Panoramique");
115 });
116 });
117
118 // 3. Zone de rendu 3D
119 egui::CentralPanel::default().show(ui, |ui| {
120 // Calcul préalable du rectangle du graphe pour éviter tout conflit de borrow avec `ui`
121 let avail_rect = ui.available_rect_before_wrap();
122 let chart_rect = egui::Rect::from_min_size(
123 egui::pos2(avail_rect.max.x - 230.0, avail_rect.min.y + 15.0),
124 egui::vec2(215.0, 90.0),
125 );
126
127 self.engine.render(ui, |r| {
128 // Rendu du maillage fil de fer du cube
129 r.draw_mesh(
130 &self.mesh,
131 self.state.position,
132 self.state.rotation,
133 egui::Color32::from_rgb(100, 200, 255),
134 );
135
136 // Repère d'axes XYZ sur l'objet
137 r.draw_axes(self.state.position, self.state.rotation, 1.2);
138
139 // Trajectoire historique
140 r.draw_trail(self.trail.as_slice(), egui::Color32::GOLD);
141
142 // Overlay Graphe 2D de télémétrie (Altitude)
143 r.draw_chart(
144 chart_rect,
145 &self.altitude_history,
146 -1.0, // Min Y
147 1.0, // Max Y
148 egui::Color32::GREEN,
149 );
150 });
151 });
152
153 // Demande le rafraîchissement continu de l'affichage
154 ctx.request_repaint();
155 }Sourcepub fn draw_mesh_with_stroke(
&self,
mesh: &Mesh3D,
position: Vec3,
rotation: Rotation3D,
stroke: Stroke,
)
pub fn draw_mesh_with_stroke( &self, mesh: &Mesh3D, position: Vec3, rotation: Rotation3D, stroke: Stroke, )
Variante de draw_mesh avec un Stroke complet (épaisseur incluse).
Sourcepub fn draw_axes(&self, position: Vec3, rotation: Rotation3D, length: f32)
pub fn draw_axes(&self, position: Vec3, rotation: Rotation3D, length: f32)
Dessine le repère d’axes XYZ (Rouge=X, Vert=Y, Bleu=Z) à une position.
Examples found in repository?
46 fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
47 let ctx = ui.ctx().clone();
48
49 // 1. Simulation physique / télémétrie
50 if !self.paused {
51 let dt = ctx.input(|i| i.stable_dt).min(0.1); // Pas de temps fluide
52 self.time += dt * self.orbit_speed;
53
54 // Orbite circulaire avec oscillation verticale (altitude)
55 self.state.position = [
56 self.time.cos() * self.orbit_radius,
57 (self.time * 1.5).sin() * 0.6,
58 self.time.sin() * self.orbit_radius,
59 ];
60
61 // Attachement d'attitude (Roll, Pitch, Yaw dynamiques)
62 self.state.rotation = Rotation3D::new(
63 (self.time * 2.0).sin() * 0.2, // Léger roulis
64 (self.time * 1.5).cos() * 0.3, // Tangage
65 self.time * 0.5, // Lacet continu
66 );
67
68 // Mise à jour des historiques
69 self.trail.push(self.state.position);
70
71 self.altitude_history.push(self.state.position[1]);
72 if self.altitude_history.len() > 200 {
73 self.altitude_history.remove(0);
74 }
75 }
76
77 // 2. Panneau de contrôle latéral (IHM)
78 egui::Panel::left("control_panel")
79 .resizable(true)
80 .default_size(240.0)
81 .show(ui, |ui| {
82 ui.heading("🛰️ Orbit Viewer");
83 ui.small("Station de sol & Télémétrie");
84 ui.separator();
85
86 // Contrôles de simulation
87 ui.label("Contrôles de l'orbite :");
88 ui.checkbox(&mut self.paused, "Pause simulation");
89 ui.add(egui::Slider::new(&mut self.orbit_speed, 0.1..=3.0).text("Vitesse"));
90 ui.add(egui::Slider::new(&mut self.orbit_radius, 0.5..=4.0).text("Rayon"));
91
92 if ui.button("🗑️ Effacer la trajectoire").clicked() {
93 self.trail.clear();
94 self.altitude_history.clear();
95 }
96
97 ui.separator();
98
99 // Telemetry Data Box
100 ui.label("Données en direct :");
101 egui::Frame::group(ui.style()).show(ui, |ui| {
102 ui.monospace(format!("Pos X: {:+.2} m", self.state.position[0]));
103 ui.monospace(format!("Alt Y: {:+.2} m", self.state.position[1]));
104 ui.monospace(format!("Pos Z: {:+.2} m", self.state.position[2]));
105 ui.separator();
106 ui.monospace(format!("Pitch: {:+.2} rad", self.state.rotation.pitch));
107 ui.monospace(format!("Yaw: {:+.2} rad", self.state.rotation.yaw));
108 });
109
110 ui.separator();
111 ui.collapsing("🖱️ Contrôles Caméra", |ui| {
112 ui.small("• Clic Gauche + Glisser : Orbite");
113 ui.small("• Molette : Zoom");
114 ui.small("• Clic Droit / Molette : Panoramique");
115 });
116 });
117
118 // 3. Zone de rendu 3D
119 egui::CentralPanel::default().show(ui, |ui| {
120 // Calcul préalable du rectangle du graphe pour éviter tout conflit de borrow avec `ui`
121 let avail_rect = ui.available_rect_before_wrap();
122 let chart_rect = egui::Rect::from_min_size(
123 egui::pos2(avail_rect.max.x - 230.0, avail_rect.min.y + 15.0),
124 egui::vec2(215.0, 90.0),
125 );
126
127 self.engine.render(ui, |r| {
128 // Rendu du maillage fil de fer du cube
129 r.draw_mesh(
130 &self.mesh,
131 self.state.position,
132 self.state.rotation,
133 egui::Color32::from_rgb(100, 200, 255),
134 );
135
136 // Repère d'axes XYZ sur l'objet
137 r.draw_axes(self.state.position, self.state.rotation, 1.2);
138
139 // Trajectoire historique
140 r.draw_trail(self.trail.as_slice(), egui::Color32::GOLD);
141
142 // Overlay Graphe 2D de télémétrie (Altitude)
143 r.draw_chart(
144 chart_rect,
145 &self.altitude_history,
146 -1.0, // Min Y
147 1.0, // Max Y
148 egui::Color32::GREEN,
149 );
150 });
151 });
152
153 // Demande le rafraîchissement continu de l'affichage
154 ctx.request_repaint();
155 }Sourcepub fn draw_trail(&self, points: &[Vec3], color: Color32)
pub fn draw_trail(&self, points: &[Vec3], color: Color32)
Dessine l’historique d’une trajectoire (polyligne reliant points).
Examples found in repository?
46 fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
47 let ctx = ui.ctx().clone();
48
49 // 1. Simulation physique / télémétrie
50 if !self.paused {
51 let dt = ctx.input(|i| i.stable_dt).min(0.1); // Pas de temps fluide
52 self.time += dt * self.orbit_speed;
53
54 // Orbite circulaire avec oscillation verticale (altitude)
55 self.state.position = [
56 self.time.cos() * self.orbit_radius,
57 (self.time * 1.5).sin() * 0.6,
58 self.time.sin() * self.orbit_radius,
59 ];
60
61 // Attachement d'attitude (Roll, Pitch, Yaw dynamiques)
62 self.state.rotation = Rotation3D::new(
63 (self.time * 2.0).sin() * 0.2, // Léger roulis
64 (self.time * 1.5).cos() * 0.3, // Tangage
65 self.time * 0.5, // Lacet continu
66 );
67
68 // Mise à jour des historiques
69 self.trail.push(self.state.position);
70
71 self.altitude_history.push(self.state.position[1]);
72 if self.altitude_history.len() > 200 {
73 self.altitude_history.remove(0);
74 }
75 }
76
77 // 2. Panneau de contrôle latéral (IHM)
78 egui::Panel::left("control_panel")
79 .resizable(true)
80 .default_size(240.0)
81 .show(ui, |ui| {
82 ui.heading("🛰️ Orbit Viewer");
83 ui.small("Station de sol & Télémétrie");
84 ui.separator();
85
86 // Contrôles de simulation
87 ui.label("Contrôles de l'orbite :");
88 ui.checkbox(&mut self.paused, "Pause simulation");
89 ui.add(egui::Slider::new(&mut self.orbit_speed, 0.1..=3.0).text("Vitesse"));
90 ui.add(egui::Slider::new(&mut self.orbit_radius, 0.5..=4.0).text("Rayon"));
91
92 if ui.button("🗑️ Effacer la trajectoire").clicked() {
93 self.trail.clear();
94 self.altitude_history.clear();
95 }
96
97 ui.separator();
98
99 // Telemetry Data Box
100 ui.label("Données en direct :");
101 egui::Frame::group(ui.style()).show(ui, |ui| {
102 ui.monospace(format!("Pos X: {:+.2} m", self.state.position[0]));
103 ui.monospace(format!("Alt Y: {:+.2} m", self.state.position[1]));
104 ui.monospace(format!("Pos Z: {:+.2} m", self.state.position[2]));
105 ui.separator();
106 ui.monospace(format!("Pitch: {:+.2} rad", self.state.rotation.pitch));
107 ui.monospace(format!("Yaw: {:+.2} rad", self.state.rotation.yaw));
108 });
109
110 ui.separator();
111 ui.collapsing("🖱️ Contrôles Caméra", |ui| {
112 ui.small("• Clic Gauche + Glisser : Orbite");
113 ui.small("• Molette : Zoom");
114 ui.small("• Clic Droit / Molette : Panoramique");
115 });
116 });
117
118 // 3. Zone de rendu 3D
119 egui::CentralPanel::default().show(ui, |ui| {
120 // Calcul préalable du rectangle du graphe pour éviter tout conflit de borrow avec `ui`
121 let avail_rect = ui.available_rect_before_wrap();
122 let chart_rect = egui::Rect::from_min_size(
123 egui::pos2(avail_rect.max.x - 230.0, avail_rect.min.y + 15.0),
124 egui::vec2(215.0, 90.0),
125 );
126
127 self.engine.render(ui, |r| {
128 // Rendu du maillage fil de fer du cube
129 r.draw_mesh(
130 &self.mesh,
131 self.state.position,
132 self.state.rotation,
133 egui::Color32::from_rgb(100, 200, 255),
134 );
135
136 // Repère d'axes XYZ sur l'objet
137 r.draw_axes(self.state.position, self.state.rotation, 1.2);
138
139 // Trajectoire historique
140 r.draw_trail(self.trail.as_slice(), egui::Color32::GOLD);
141
142 // Overlay Graphe 2D de télémétrie (Altitude)
143 r.draw_chart(
144 chart_rect,
145 &self.altitude_history,
146 -1.0, // Min Y
147 1.0, // Max Y
148 egui::Color32::GREEN,
149 );
150 });
151 });
152
153 // Demande le rafraîchissement continu de l'affichage
154 ctx.request_repaint();
155 }Sourcepub fn draw_chart(
&self,
rect: Rect,
values: &[f32],
min_val: f32,
max_val: f32,
color: Color32,
)
pub fn draw_chart( &self, rect: Rect, values: &[f32], min_val: f32, max_val: f32, color: Color32, )
Dessine un graphique 2D (courbe de valeurs) dans un rectangle donné de l’écran, indépendamment de la caméra 3D.
Examples found in repository?
46 fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
47 let ctx = ui.ctx().clone();
48
49 // 1. Simulation physique / télémétrie
50 if !self.paused {
51 let dt = ctx.input(|i| i.stable_dt).min(0.1); // Pas de temps fluide
52 self.time += dt * self.orbit_speed;
53
54 // Orbite circulaire avec oscillation verticale (altitude)
55 self.state.position = [
56 self.time.cos() * self.orbit_radius,
57 (self.time * 1.5).sin() * 0.6,
58 self.time.sin() * self.orbit_radius,
59 ];
60
61 // Attachement d'attitude (Roll, Pitch, Yaw dynamiques)
62 self.state.rotation = Rotation3D::new(
63 (self.time * 2.0).sin() * 0.2, // Léger roulis
64 (self.time * 1.5).cos() * 0.3, // Tangage
65 self.time * 0.5, // Lacet continu
66 );
67
68 // Mise à jour des historiques
69 self.trail.push(self.state.position);
70
71 self.altitude_history.push(self.state.position[1]);
72 if self.altitude_history.len() > 200 {
73 self.altitude_history.remove(0);
74 }
75 }
76
77 // 2. Panneau de contrôle latéral (IHM)
78 egui::Panel::left("control_panel")
79 .resizable(true)
80 .default_size(240.0)
81 .show(ui, |ui| {
82 ui.heading("🛰️ Orbit Viewer");
83 ui.small("Station de sol & Télémétrie");
84 ui.separator();
85
86 // Contrôles de simulation
87 ui.label("Contrôles de l'orbite :");
88 ui.checkbox(&mut self.paused, "Pause simulation");
89 ui.add(egui::Slider::new(&mut self.orbit_speed, 0.1..=3.0).text("Vitesse"));
90 ui.add(egui::Slider::new(&mut self.orbit_radius, 0.5..=4.0).text("Rayon"));
91
92 if ui.button("🗑️ Effacer la trajectoire").clicked() {
93 self.trail.clear();
94 self.altitude_history.clear();
95 }
96
97 ui.separator();
98
99 // Telemetry Data Box
100 ui.label("Données en direct :");
101 egui::Frame::group(ui.style()).show(ui, |ui| {
102 ui.monospace(format!("Pos X: {:+.2} m", self.state.position[0]));
103 ui.monospace(format!("Alt Y: {:+.2} m", self.state.position[1]));
104 ui.monospace(format!("Pos Z: {:+.2} m", self.state.position[2]));
105 ui.separator();
106 ui.monospace(format!("Pitch: {:+.2} rad", self.state.rotation.pitch));
107 ui.monospace(format!("Yaw: {:+.2} rad", self.state.rotation.yaw));
108 });
109
110 ui.separator();
111 ui.collapsing("🖱️ Contrôles Caméra", |ui| {
112 ui.small("• Clic Gauche + Glisser : Orbite");
113 ui.small("• Molette : Zoom");
114 ui.small("• Clic Droit / Molette : Panoramique");
115 });
116 });
117
118 // 3. Zone de rendu 3D
119 egui::CentralPanel::default().show(ui, |ui| {
120 // Calcul préalable du rectangle du graphe pour éviter tout conflit de borrow avec `ui`
121 let avail_rect = ui.available_rect_before_wrap();
122 let chart_rect = egui::Rect::from_min_size(
123 egui::pos2(avail_rect.max.x - 230.0, avail_rect.min.y + 15.0),
124 egui::vec2(215.0, 90.0),
125 );
126
127 self.engine.render(ui, |r| {
128 // Rendu du maillage fil de fer du cube
129 r.draw_mesh(
130 &self.mesh,
131 self.state.position,
132 self.state.rotation,
133 egui::Color32::from_rgb(100, 200, 255),
134 );
135
136 // Repère d'axes XYZ sur l'objet
137 r.draw_axes(self.state.position, self.state.rotation, 1.2);
138
139 // Trajectoire historique
140 r.draw_trail(self.trail.as_slice(), egui::Color32::GOLD);
141
142 // Overlay Graphe 2D de télémétrie (Altitude)
143 r.draw_chart(
144 chart_rect,
145 &self.altitude_history,
146 -1.0, // Min Y
147 1.0, // Max Y
148 egui::Color32::GREEN,
149 );
150 });
151 });
152
153 // Demande le rafraîchissement continu de l'affichage
154 ctx.request_repaint();
155 }Auto Trait Implementations§
impl<'a> !RefUnwindSafe for Render3D<'a>
impl<'a> !UnwindSafe for Render3D<'a>
impl<'a> Freeze for Render3D<'a>
impl<'a> Send for Render3D<'a>
impl<'a> Sync for Render3D<'a>
impl<'a> Unpin for Render3D<'a>
impl<'a> UnsafeUnpin for Render3D<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more