Skip to main content

nanonis_rs/client/
marks.rs

1use super::NanonisClient;
2use crate::error::NanonisError;
3use crate::types::NanonisValue;
4
5/// Point mark information.
6#[derive(Debug, Clone)]
7pub struct PointMark {
8    /// X coordinate (meters)
9    pub x_m: f32,
10    /// Y coordinate (meters)
11    pub y_m: f32,
12    /// Text label
13    pub text: String,
14    /// RGB color
15    pub color: u32,
16    /// Visible flag
17    pub visible: bool,
18}
19
20/// Line mark information.
21#[derive(Debug, Clone)]
22pub struct LineMark {
23    /// Start X coordinate (meters)
24    pub start_x_m: f32,
25    /// Start Y coordinate (meters)
26    pub start_y_m: f32,
27    /// End X coordinate (meters)
28    pub end_x_m: f32,
29    /// End Y coordinate (meters)
30    pub end_y_m: f32,
31    /// RGB color
32    pub color: u32,
33    /// Visible flag
34    pub visible: bool,
35}
36
37impl NanonisClient {
38    /// Draw text at a specified point in the scan frame.
39    ///
40    /// # Arguments
41    /// * `x_m` - X coordinate in meters
42    /// * `y_m` - Y coordinate in meters
43    /// * `text` - Text to draw
44    /// * `color` - RGB color value
45    ///
46    /// # Errors
47    /// Returns `NanonisError` if communication fails.
48    ///
49    /// # Examples
50    /// ```no_run
51    /// use nanonis_rs::NanonisClient;
52    ///
53    /// let mut client = NanonisClient::new("127.0.0.1", 6501)?;
54    /// // Draw red "X" at position (1nm, 2nm)
55    /// client.marks_point_draw(1e-9, 2e-9, "X", 0xFF0000)?;
56    /// # Ok::<(), Box<dyn std::error::Error>>(())
57    /// ```
58    pub fn marks_point_draw(
59        &mut self,
60        x_m: f32,
61        y_m: f32,
62        text: &str,
63        color: u32,
64    ) -> Result<(), NanonisError> {
65        self.quick_send(
66            "Marks.PointDraw",
67            vec![
68                NanonisValue::F32(x_m),
69                NanonisValue::F32(y_m),
70                NanonisValue::String(text.to_string()),
71                NanonisValue::U32(color),
72            ],
73            vec!["f", "f", "+*c", "I"],
74            vec![],
75        )?;
76        Ok(())
77    }
78
79    /// Draw text at multiple points in the scan frame.
80    ///
81    /// # Arguments
82    /// * `x_coords_m` - X coordinates in meters
83    /// * `y_coords_m` - Y coordinates in meters
84    /// * `texts` - Text labels for each point
85    /// * `colors` - RGB colors for each point
86    ///
87    /// # Errors
88    /// Returns `NanonisError` if communication fails.
89    pub fn marks_points_draw(
90        &mut self,
91        x_coords_m: &[f32],
92        y_coords_m: &[f32],
93        texts: &[String],
94        colors: &[u32],
95    ) -> Result<(), NanonisError> {
96        let num_points = x_coords_m.len() as i32;
97
98        self.quick_send(
99            "Marks.PointsDraw",
100            vec![
101                NanonisValue::I32(num_points),
102                NanonisValue::ArrayF32(x_coords_m.to_vec()),
103                NanonisValue::ArrayF32(y_coords_m.to_vec()),
104                NanonisValue::ArrayString(texts.to_vec()),
105                NanonisValue::ArrayU32(colors.to_vec()),
106            ],
107            vec!["i", "*f", "*f", "+*c", "*I"],
108            vec![],
109        )?;
110        Ok(())
111    }
112
113    /// Draw a line in the scan frame.
114    ///
115    /// # Arguments
116    /// * `start_x_m` - Start X coordinate in meters
117    /// * `start_y_m` - Start Y coordinate in meters
118    /// * `end_x_m` - End X coordinate in meters
119    /// * `end_y_m` - End Y coordinate in meters
120    /// * `color` - RGB color value
121    ///
122    /// # Errors
123    /// Returns `NanonisError` if communication fails.
124    pub fn marks_line_draw(
125        &mut self,
126        start_x_m: f32,
127        start_y_m: f32,
128        end_x_m: f32,
129        end_y_m: f32,
130        color: u32,
131    ) -> Result<(), NanonisError> {
132        self.quick_send(
133            "Marks.LineDraw",
134            vec![
135                NanonisValue::F32(start_x_m),
136                NanonisValue::F32(start_y_m),
137                NanonisValue::F32(end_x_m),
138                NanonisValue::F32(end_y_m),
139                NanonisValue::U32(color),
140            ],
141            vec!["f", "f", "f", "f", "I"],
142            vec![],
143        )?;
144        Ok(())
145    }
146
147    /// Draw multiple lines in the scan frame.
148    ///
149    /// # Arguments
150    /// * `start_x_m` - Start X coordinates in meters
151    /// * `start_y_m` - Start Y coordinates in meters
152    /// * `end_x_m` - End X coordinates in meters
153    /// * `end_y_m` - End Y coordinates in meters
154    /// * `colors` - RGB colors for each line
155    ///
156    /// # Errors
157    /// Returns `NanonisError` if communication fails.
158    pub fn marks_lines_draw(
159        &mut self,
160        start_x_m: &[f32],
161        start_y_m: &[f32],
162        end_x_m: &[f32],
163        end_y_m: &[f32],
164        colors: &[u32],
165    ) -> Result<(), NanonisError> {
166        let num_lines = start_x_m.len() as i32;
167
168        self.quick_send(
169            "Marks.LinesDraw",
170            vec![
171                NanonisValue::I32(num_lines),
172                NanonisValue::ArrayF32(start_x_m.to_vec()),
173                NanonisValue::ArrayF32(start_y_m.to_vec()),
174                NanonisValue::ArrayF32(end_x_m.to_vec()),
175                NanonisValue::ArrayF32(end_y_m.to_vec()),
176                NanonisValue::ArrayU32(colors.to_vec()),
177            ],
178            vec!["i", "*f", "*f", "*f", "*f", "*I"],
179            vec![],
180        )?;
181        Ok(())
182    }
183
184    /// Erase a point mark from the scan frame.
185    ///
186    /// # Arguments
187    /// * `point_index` - Index of point to erase (-1 to erase all)
188    ///
189    /// # Errors
190    /// Returns `NanonisError` if communication fails.
191    pub fn marks_points_erase(&mut self, point_index: i32) -> Result<(), NanonisError> {
192        self.quick_send(
193            "Marks.PointsErase",
194            vec![NanonisValue::I32(point_index)],
195            vec!["i"],
196            vec![],
197        )?;
198        Ok(())
199    }
200
201    /// Erase a line mark from the scan frame.
202    ///
203    /// # Arguments
204    /// * `line_index` - Index of line to erase (-1 to erase all)
205    ///
206    /// # Errors
207    /// Returns `NanonisError` if communication fails.
208    pub fn marks_lines_erase(&mut self, line_index: i32) -> Result<(), NanonisError> {
209        self.quick_send(
210            "Marks.LinesErase",
211            vec![NanonisValue::I32(line_index)],
212            vec!["i"],
213            vec![],
214        )?;
215        Ok(())
216    }
217
218    /// Show or hide a point mark.
219    ///
220    /// # Arguments
221    /// * `point_index` - Index of point (-1 for all)
222    /// * `visible` - True to show, false to hide
223    ///
224    /// # Errors
225    /// Returns `NanonisError` if communication fails.
226    pub fn marks_points_visible_set(
227        &mut self,
228        point_index: i32,
229        visible: bool,
230    ) -> Result<(), NanonisError> {
231        // Note: 0 = visible, 1 = invisible in the protocol
232        let flag = if visible { 0u16 } else { 1u16 };
233        self.quick_send(
234            "Marks.PointsVisibleSet",
235            vec![NanonisValue::I32(point_index), NanonisValue::U16(flag)],
236            vec!["i", "H"],
237            vec![],
238        )?;
239        Ok(())
240    }
241
242    /// Show or hide a line mark.
243    ///
244    /// # Arguments
245    /// * `line_index` - Index of line (-1 for all)
246    /// * `visible` - True to show, false to hide
247    ///
248    /// # Errors
249    /// Returns `NanonisError` if communication fails.
250    pub fn marks_lines_visible_set(
251        &mut self,
252        line_index: i32,
253        visible: bool,
254    ) -> Result<(), NanonisError> {
255        // Note: 0 = visible, 1 = invisible in the protocol
256        let flag = if visible { 0u16 } else { 1u16 };
257        self.quick_send(
258            "Marks.LinesVisibleSet",
259            vec![NanonisValue::I32(line_index), NanonisValue::U16(flag)],
260            vec!["i", "H"],
261            vec![],
262        )?;
263        Ok(())
264    }
265
266    /// Get information about all drawn point marks.
267    ///
268    /// # Returns
269    /// A vector of [`PointMark`] structs.
270    ///
271    /// # Errors
272    /// Returns `NanonisError` if communication fails.
273    pub fn marks_points_get(&mut self) -> Result<Vec<PointMark>, NanonisError> {
274        let result = self.quick_send(
275            "Marks.PointsGet",
276            vec![],
277            vec![],
278            vec!["i", "*f", "*f", "i", "*+c", "*I", "*I"],
279        )?;
280
281        if result.len() >= 7 {
282            let num_points = result[0].as_i32()? as usize;
283            let x_coords = result[1].as_f32_array()?;
284            let y_coords = result[2].as_f32_array()?;
285            let texts = result[4].as_string_array()?;
286            let colors = result[5].as_u32_array()?;
287            let visible = result[6].as_u32_array()?;
288
289            let mut points = Vec::with_capacity(num_points);
290            for i in 0..num_points {
291                if i < x_coords.len()
292                    && i < y_coords.len()
293                    && i < texts.len()
294                    && i < colors.len()
295                    && i < visible.len()
296                {
297                    points.push(PointMark {
298                        x_m: x_coords[i],
299                        y_m: y_coords[i],
300                        text: texts[i].clone(),
301                        color: colors[i],
302                        visible: visible[i] != 0,
303                    });
304                }
305            }
306            Ok(points)
307        } else {
308            Ok(vec![])
309        }
310    }
311
312    /// Get information about all drawn line marks.
313    ///
314    /// # Returns
315    /// A vector of [`LineMark`] structs.
316    ///
317    /// # Errors
318    /// Returns `NanonisError` if communication fails.
319    pub fn marks_lines_get(&mut self) -> Result<Vec<LineMark>, NanonisError> {
320        let result = self.quick_send(
321            "Marks.LinesGet",
322            vec![],
323            vec![],
324            vec!["i", "*f", "*f", "*f", "*f", "*I", "*I"],
325        )?;
326
327        if result.len() >= 7 {
328            let num_lines = result[0].as_i32()? as usize;
329            let start_x = result[1].as_f32_array()?;
330            let start_y = result[2].as_f32_array()?;
331            let end_x = result[3].as_f32_array()?;
332            let end_y = result[4].as_f32_array()?;
333            let colors = result[5].as_u32_array()?;
334            let visible = result[6].as_u32_array()?;
335
336            let mut lines = Vec::with_capacity(num_lines);
337            for i in 0..num_lines {
338                if i < start_x.len()
339                    && i < start_y.len()
340                    && i < end_x.len()
341                    && i < end_y.len()
342                    && i < colors.len()
343                    && i < visible.len()
344                {
345                    lines.push(LineMark {
346                        start_x_m: start_x[i],
347                        start_y_m: start_y[i],
348                        end_x_m: end_x[i],
349                        end_y_m: end_y[i],
350                        color: colors[i],
351                        visible: visible[i] != 0,
352                    });
353                }
354            }
355            Ok(lines)
356        } else {
357            Ok(vec![])
358        }
359    }
360}