Skip to main content

dear_implot3d/
axis.rs

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