Skip to main content

dear_implot3d/
axis.rs

1use crate::{
2    Axis3D, Axis3DFlags, Plot3DCond, Plot3DUi, axis_tick_count_to_i32, debug_before_plot,
3    debug_before_setup, imvec2, len_i32, sys,
4};
5
6/// Axis helpers
7impl<'ui> Plot3DUi<'ui> {
8    pub fn setup_axes(
9        &self,
10        x_label: &str,
11        y_label: &str,
12        z_label: &str,
13        x_flags: Axis3DFlags,
14        y_flags: Axis3DFlags,
15        z_flags: Axis3DFlags,
16    ) {
17        self.with_bound_context(|| {
18            debug_before_setup();
19            if x_label.contains('\0') || y_label.contains('\0') || z_label.contains('\0') {
20                return;
21            }
22            dear_imgui_rs::with_scratch_txt_three(
23                x_label,
24                y_label,
25                z_label,
26                |x_ptr, y_ptr, z_ptr| unsafe {
27                    sys::ImPlot3D_SetupAxes(
28                        x_ptr,
29                        y_ptr,
30                        z_ptr,
31                        x_flags.bits() as i32,
32                        y_flags.bits() as i32,
33                        z_flags.bits() as i32,
34                    )
35                },
36            )
37        })
38    }
39
40    pub fn setup_axis(&self, axis: Axis3D, label: &str, flags: Axis3DFlags) {
41        self.with_bound_context(|| {
42            debug_before_setup();
43            if label.contains('\0') {
44                return;
45            }
46            dear_imgui_rs::with_scratch_txt(label, |ptr| unsafe {
47                sys::ImPlot3D_SetupAxis(axis as i32, ptr, flags.bits() as i32)
48            })
49        })
50    }
51
52    pub fn setup_axis_limits(&self, axis: Axis3D, min: f64, max: f64, cond: Plot3DCond) {
53        self.with_bound_context(|| {
54            debug_before_setup();
55            unsafe { sys::ImPlot3D_SetupAxisLimits(axis as i32, min, max, cond as i32) }
56        })
57    }
58
59    pub fn setup_axes_limits(
60        &self,
61        x_min: f64,
62        x_max: f64,
63        y_min: f64,
64        y_max: f64,
65        z_min: f64,
66        z_max: f64,
67        cond: Plot3DCond,
68    ) {
69        self.with_bound_context(|| {
70            debug_before_setup();
71            unsafe {
72                sys::ImPlot3D_SetupAxesLimits(x_min, x_max, y_min, y_max, z_min, z_max, cond as i32)
73            }
74        })
75    }
76
77    pub fn setup_axis_limits_constraints(&self, axis: Axis3D, v_min: f64, v_max: f64) {
78        self.with_bound_context(|| {
79            debug_before_setup();
80            unsafe { sys::ImPlot3D_SetupAxisLimitsConstraints(axis as i32, v_min, v_max) }
81        })
82    }
83
84    pub fn setup_axis_zoom_constraints(&self, axis: Axis3D, z_min: f64, z_max: f64) {
85        self.with_bound_context(|| {
86            debug_before_setup();
87            unsafe { sys::ImPlot3D_SetupAxisZoomConstraints(axis as i32, z_min, z_max) }
88        })
89    }
90
91    /// Setup axis ticks using explicit positions and optional labels.
92    ///
93    /// If `labels` is provided, it must have the same length as `values`.
94    pub fn setup_axis_ticks_values(
95        &self,
96        axis: Axis3D,
97        values: &[f64],
98        labels: Option<&[&str]>,
99        keep_default: bool,
100    ) {
101        self.with_bound_context(|| {
102            debug_before_setup();
103            let Some(n_ticks) = len_i32(values.len()) else {
104                return;
105            };
106            if let Some(lbls) = labels {
107                if lbls.len() != values.len() {
108                    return;
109                }
110                let cleaned: Vec<&str> = lbls
111                    .iter()
112                    .map(|&s| if s.contains('\0') { "" } else { s })
113                    .collect();
114                dear_imgui_rs::with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
115                    sys::ImPlot3D_SetupAxisTicks_doublePtr(
116                        axis as i32,
117                        values.as_ptr(),
118                        n_ticks,
119                        ptrs.as_ptr(),
120                        keep_default,
121                    )
122                });
123            } else {
124                unsafe {
125                    sys::ImPlot3D_SetupAxisTicks_doublePtr(
126                        axis as i32,
127                        values.as_ptr(),
128                        n_ticks,
129                        std::ptr::null(),
130                        keep_default,
131                    )
132                };
133            }
134        })
135    }
136
137    pub fn setup_axis_ticks_range(
138        &self,
139        axis: Axis3D,
140        v_min: f64,
141        v_max: f64,
142        n_ticks: usize,
143        labels: Option<&[&str]>,
144        keep_default: bool,
145    ) {
146        let n_ticks_i32 = axis_tick_count_to_i32("Plot3DUi::setup_axis_ticks_range()", n_ticks);
147        self.with_bound_context(|| {
148            debug_before_setup();
149            if let Some(lbls) = labels {
150                if lbls.len() != n_ticks {
151                    return;
152                }
153                let cleaned: Vec<&str> = lbls
154                    .iter()
155                    .map(|&s| if s.contains('\0') { "" } else { s })
156                    .collect();
157                dear_imgui_rs::with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
158                    sys::ImPlot3D_SetupAxisTicks_double(
159                        axis as i32,
160                        v_min,
161                        v_max,
162                        n_ticks_i32,
163                        ptrs.as_ptr(),
164                        keep_default,
165                    )
166                });
167            } else {
168                unsafe {
169                    sys::ImPlot3D_SetupAxisTicks_double(
170                        axis as i32,
171                        v_min,
172                        v_max,
173                        n_ticks_i32,
174                        std::ptr::null(),
175                        keep_default,
176                    )
177                };
178            }
179        })
180    }
181
182    pub fn setup_box_scale(&self, x: f32, y: f32, z: f32) {
183        self.with_bound_context(|| {
184            debug_before_setup();
185            unsafe { sys::ImPlot3D_SetupBoxScale(x as f64, y as f64, z as f64) }
186        })
187    }
188
189    pub fn setup_box_rotation(
190        &self,
191        elevation: f32,
192        azimuth: f32,
193        animate: bool,
194        cond: Plot3DCond,
195    ) {
196        self.with_bound_context(|| {
197            debug_before_setup();
198            unsafe {
199                sys::ImPlot3D_SetupBoxRotation_double(
200                    elevation as f64,
201                    azimuth as f64,
202                    animate,
203                    cond as i32,
204                )
205            }
206        })
207    }
208
209    pub fn setup_box_initial_rotation(&self, elevation: f32, azimuth: f32) {
210        self.with_bound_context(|| {
211            debug_before_setup();
212            unsafe {
213                sys::ImPlot3D_SetupBoxInitialRotation_double(elevation as f64, azimuth as f64)
214            }
215        })
216    }
217
218    pub fn plot_text(&self, text: &str, x: f32, y: f32, z: f32, angle: f32, pix_offset: [f32; 2]) {
219        self.with_bound_context(|| {
220            if text.contains('\0') {
221                return;
222            }
223            dear_imgui_rs::with_scratch_txt(text, |text_ptr| unsafe {
224                debug_before_plot();
225                sys::ImPlot3D_PlotText(
226                    text_ptr,
227                    x as f64,
228                    y as f64,
229                    z as f64,
230                    angle as f64,
231                    imvec2(pix_offset[0], pix_offset[1]),
232                )
233            })
234        })
235    }
236
237    pub fn plot_to_pixels(&self, point: [f32; 3]) -> [f32; 2] {
238        self.with_bound_context(|| unsafe {
239            let out = sys::ImPlot3D_PlotToPixels_double(
240                point[0] as f64,
241                point[1] as f64,
242                point[2] as f64,
243            );
244            [out.x, out.y]
245        })
246    }
247
248    pub fn get_frame_pos(&self) -> [f32; 2] {
249        self.with_bound_context(|| unsafe {
250            let out = sys::ImPlot3D_GetPlotRectPos();
251            [out.x, out.y]
252        })
253    }
254
255    pub fn get_frame_size(&self) -> [f32; 2] {
256        self.with_bound_context(|| unsafe {
257            let out = sys::ImPlot3D_GetPlotRectSize();
258            [out.x, out.y]
259        })
260    }
261}