1use std::borrow::Cow;
2
3use crate::item_style::{Plot3DItemStyle, plot3d_spec_with_style};
4use crate::{
5 Item3DFlags, Plot3DDataLayout, Plot3DUi, Surface3DFlags, debug_before_plot, plot3d_spec_from,
6 surface_count_to_i32, sys,
7};
8
9pub struct Surface3DBuilder<'ui> {
11 pub(crate) _ui: &'ui Plot3DUi<'ui>,
12 pub(crate) label: Cow<'ui, str>,
13 pub(crate) xs: &'ui [f32],
14 pub(crate) ys: &'ui [f32],
15 pub(crate) zs: &'ui [f32],
16 pub(crate) scale_min: f64,
17 pub(crate) scale_max: f64,
18 pub(crate) flags: Surface3DFlags,
19 pub(crate) item_flags: Item3DFlags,
20 pub(crate) style: Plot3DItemStyle,
21}
22
23impl<'ui> Surface3DBuilder<'ui> {
24 pub fn scale(mut self, min: f64, max: f64) -> Self {
25 self.scale_min = min;
26 self.scale_max = max;
27 self
28 }
29 pub fn flags(mut self, flags: Surface3DFlags) -> Self {
30 self.flags = flags;
31 self
32 }
33 pub fn plot(self) {
34 let _guard = self._ui.bind();
35 let x_count = match i32::try_from(self.xs.len()) {
36 Ok(v) => v,
37 Err(_) => return,
38 };
39 let y_count = match i32::try_from(self.ys.len()) {
40 Ok(v) => v,
41 Err(_) => return,
42 };
43 let expected = match self.xs.len().checked_mul(self.ys.len()) {
44 Some(v) => v,
45 None => return,
46 };
47 if self.zs.len() != expected {
48 return;
49 }
50 let label = self.label.as_ref();
51 let label = if label.contains('\0') {
52 "surface"
53 } else {
54 label
55 };
56 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
57 let spec = plot3d_spec_with_style(
58 self.style,
59 self.flags.bits() | self.item_flags.bits(),
60 Plot3DDataLayout::DEFAULT,
61 );
62 sys::ImPlot3D_PlotSurface_FloatPtr(
63 label_ptr,
64 self.xs.as_ptr(),
65 self.ys.as_ptr(),
66 self.zs.as_ptr(),
67 x_count,
68 y_count,
69 self.scale_min,
70 self.scale_max,
71 spec,
72 );
73 })
74 }
75}
76
77impl<'ui> Plot3DUi<'ui> {
78 pub fn surface_f32(
80 &'ui self,
81 label: impl Into<Cow<'ui, str>>,
82 xs: &'ui [f32],
83 ys: &'ui [f32],
84 zs: &'ui [f32],
85 ) -> Surface3DBuilder<'ui> {
86 let _guard = self.bind();
87 Surface3DBuilder {
88 _ui: self,
89 label: label.into(),
90 xs,
91 ys,
92 zs,
93 scale_min: f64::NAN,
94 scale_max: f64::NAN,
95 flags: Surface3DFlags::NONE,
96 item_flags: Item3DFlags::NONE,
97 style: Plot3DItemStyle::default(),
98 }
99 }
100
101 pub fn surface_f32_raw<S: AsRef<str>>(
103 &self,
104 label: S,
105 xs: &[f32],
106 ys: &[f32],
107 zs: &[f32],
108 scale_min: f64,
109 scale_max: f64,
110 flags: Surface3DFlags,
111 layout: Plot3DDataLayout,
112 ) {
113 let _guard = self.bind();
114 debug_before_plot();
115 let x_count = xs.len();
116 let y_count = ys.len();
117 let Some(x_count_i32) = surface_count_to_i32(x_count) else {
118 return;
119 };
120 let Some(y_count_i32) = surface_count_to_i32(y_count) else {
121 return;
122 };
123 let expected = match x_count.checked_mul(y_count) {
124 Some(v) => v,
125 None => return,
126 };
127 if zs.len() != expected {
128 return;
130 }
131
132 let mut xs_flat = Vec::with_capacity(expected);
134 let mut ys_flat = Vec::with_capacity(expected);
135 for yi in 0..y_count {
136 for xi in 0..x_count {
137 xs_flat.push(xs[xi]);
138 ys_flat.push(ys[yi]);
139 }
140 }
141
142 let label = label.as_ref();
143 if label.contains('\0') {
144 return;
145 }
146 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
147 let spec = plot3d_spec_from(flags.bits(), layout);
148 sys::ImPlot3D_PlotSurface_FloatPtr(
149 label_ptr,
150 xs_flat.as_ptr(),
151 ys_flat.as_ptr(),
152 zs.as_ptr(),
153 x_count_i32,
154 y_count_i32,
155 scale_min,
156 scale_max,
157 spec,
158 );
159 })
160 }
161
162 pub fn surface_f32_flat<S: AsRef<str>>(
167 &self,
168 label: S,
169 xs_flat: &[f32],
170 ys_flat: &[f32],
171 zs: &[f32],
172 x_count: usize,
173 y_count: usize,
174 scale_min: f64,
175 scale_max: f64,
176 flags: Surface3DFlags,
177 layout: Plot3DDataLayout,
178 ) {
179 let _guard = self.bind();
180 debug_before_plot();
181 let Some(x_count_i32) = surface_count_to_i32(x_count) else {
182 return;
183 };
184 let Some(y_count_i32) = surface_count_to_i32(y_count) else {
185 return;
186 };
187 let Some(expected) = x_count.checked_mul(y_count) else {
188 return;
189 };
190 if xs_flat.len() != expected || ys_flat.len() != expected || zs.len() != expected {
191 return;
192 }
193 let label = label.as_ref();
194 if label.contains('\0') {
195 return;
196 }
197 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
198 let spec = plot3d_spec_from(flags.bits(), layout);
199 sys::ImPlot3D_PlotSurface_FloatPtr(
200 label_ptr,
201 xs_flat.as_ptr(),
202 ys_flat.as_ptr(),
203 zs.as_ptr(),
204 x_count_i32,
205 y_count_i32,
206 scale_min,
207 scale_max,
208 spec,
209 );
210 })
211 }
212}