Skip to main content

webarkitlib_rs/
types.rs

1/*
2 *  types.rs
3 *  WebARKitLib-rs
4 *
5 *  This file is part of WebARKitLib-rs - WebARKit.
6 *
7 *  WebARKitLib-rs is free software: you can redistribute it and/or modify
8 *  it under the terms of the GNU Lesser General Public License as published by
9 *  the Free Software Foundation, either version 3 of the License, or
10 *  (at your option) any later version.
11 *
12 *  WebARKitLib-rs is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU Lesser General Public License for more details.
16 *
17 *  You should have received a copy of the GNU Lesser General Public License
18 *  along with WebARKitLib-rs.  If not, see <http://www.gnu.org/licenses/>.
19 *
20 *  As a special exception, the copyright holders of this library give you
21 *  permission to link this library with independent modules to produce an
22 *  executable, regardless of the license terms of these independent modules, and to
23 *  copy and distribute the resulting executable under terms of your choice,
24 *  provided that you also meet, for each linked independent module, the terms and
25 *  conditions of the license of that module. An independent module is a module
26 *  which is neither derived from nor based on this library. If you modify this
27 *  library, you may extend this exception to your version of the library, but you
28 *  are not obligated to do so. If you do not wish to do so, delete this exception
29 *  statement from your version.
30 *
31 *  Copyright 2026 WebARKit.
32 *
33 *  Author(s): Walter Perdan @kalwalt https://github.com/kalwalt
34 *
35 */
36
37//! Core Data Structures for WebARKitLib
38//! Translated from ARToolKit C headers (ar.h, param.h, etc.)
39
40pub type ARdouble = f64;
41
42pub const AR_DIST_FACTOR_NUM_MAX: usize = 9;
43pub const AR_CHAIN_MAX: usize = 10000;
44pub const AR_SQUARE_MAX: usize = 30;
45pub const AR_LABELING_WORK_SIZE: usize = 1024 * 32;
46
47/// A structure to hold a timestamp in seconds and microseconds, with arbitrary epoch.
48#[derive(Debug, Clone, PartialEq, Default)]
49#[repr(C)]
50pub struct AR2VideoTimestampT {
51    pub sec: u64,
52    pub usec: u32,
53}
54
55/// A structure which carries information about a video frame retrieved by the video library.
56#[derive(Debug, Clone, Default)]
57pub struct AR2VideoBufferT {
58    /// A pointer to the packed video data for this video frame.
59    /// In Rust, we use a slice or Vec depending on ownership, usually represented as a raw slice or Vec.
60    pub buff: Option<Vec<u8>>,
61    /// For multi-planar video frames, arrays of planes.
62    pub buf_planes: Option<Vec<Vec<u8>>>,
63    /// Number of planes.
64    pub buf_plane_count: u32,
65    /// Luminance-only version of the image.
66    pub buff_luma: Option<Vec<u8>>,
67    /// Set to true when buff is valid.
68    pub fill_flag: bool,
69    /// Time at which the buffer was filled.
70    pub time: AR2VideoTimestampT,
71}
72
73/// Structure holding camera parameters, including image size, projection matrix and lens distortion parameters.
74#[derive(Debug, Clone, PartialEq, Default)]
75#[repr(C)]
76pub struct ARParam {
77    /// The width in pixels of images returned by the video library for the camera.
78    pub xsize: i32,
79    /// The height in pixels of images returned by the video library for the camera.
80    pub ysize: i32,
81    /// The projection matrix for the calibrated camera parameters.
82    pub mat: [[ARdouble; 4]; 3],
83    /// Distortion factors.
84    pub dist_factor: [ARdouble; AR_DIST_FACTOR_NUM_MAX],
85    /// Distortion function version.
86    pub dist_function_version: i32,
87}
88
89/// Captures detail of a trapezoidal region which is a candidate for marker detection.
90#[derive(Debug, Clone)]
91#[repr(C)]
92pub struct ARMarkerInfo2 {
93    pub area: i32,
94    pub pos: [ARdouble; 2],
95    pub coord_num: i32,
96    pub x_coord: [i32; AR_CHAIN_MAX],
97    pub y_coord: [i32; AR_CHAIN_MAX],
98    pub vertex: [i32; 5],
99}
100
101impl Default for ARMarkerInfo2 {
102    fn default() -> Self {
103        Self {
104            area: 0,
105            pos: [0.0; 2],
106            coord_num: 0,
107            x_coord: [0; AR_CHAIN_MAX],
108            y_coord: [0; AR_CHAIN_MAX],
109            vertex: [0; 5],
110        }
111    }
112}
113
114/// Result codes returned by arDetectMarker to report state of individual detected trapezoidal regions.
115#[repr(i32)]
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub enum ARMarkerInfoCutoffPhase {
118    None = 0,
119    PatternExtraction,
120    MatchGeneric,
121    MatchContrast,
122    MatchBarcodeNotFound,
123    MatchBarcodeEdcFail,
124    MatchConfidence,
125    PoseError,
126    PoseErrorMulti,
127    HeuristicTroublesomeMatrixCodes,
128}
129
130impl Default for ARMarkerInfoCutoffPhase {
131    fn default() -> Self {
132        ARMarkerInfoCutoffPhase::None
133    }
134}
135
136/// Describes a detected trapezoidal area (a candidate for a marker match).
137#[derive(Debug, Clone)]
138#[repr(C)]
139pub struct ARMarkerInfo {
140    /// Area in pixels of the largest connected region
141    pub area: i32,
142    /// Marker ID if valid, or -1 if invalid
143    pub id: i32,
144    pub id_patt: i32,
145    pub id_matrix: i32,
146    /// Marker direction (0 to 3)
147    pub dir: i32,
148    pub dir_patt: i32,
149    pub dir_matrix: i32,
150    /// Marker matching confidence (0.0 to 1.0)
151    pub cf: ARdouble,
152    pub cf_patt: ARdouble,
153    pub cf_matrix: ARdouble,
154    /// 2D position of the centre of the marker
155    pub pos: [ARdouble; 2],
156    /// Line equations for the 4 sides of the marker
157    pub line: [[ARdouble; 3]; 4],
158    /// 2D positions of the corners of the marker
159    pub vertex: [[ARdouble; 2]; 4],
160    /// Pointer to source region info for this marker.
161    pub marker_info2_ptr: *mut ARMarkerInfo2,
162    /// Tracking phase at which the marker was cut off
163    pub cutoff_phase: ARMarkerInfoCutoffPhase,
164    /// The numbers of errors detected and corrected
165    pub error_corrected: i32,
166    /// Global ID for matrix codes
167    pub global_id: u64,
168}
169
170impl Default for ARMarkerInfo {
171    fn default() -> Self {
172        Self {
173            area: 0,
174            id: -1,
175            id_patt: -1,
176            id_matrix: -1,
177            dir: 0,
178            dir_patt: 0,
179            dir_matrix: 0,
180            cf: 0.0,
181            cf_patt: 0.0,
182            cf_matrix: 0.0,
183            pos: [0.0; 2],
184            line: [[0.0; 3]; 4],
185            vertex: [[0.0; 2]; 4],
186            marker_info2_ptr: std::ptr::null_mut(),
187            cutoff_phase: ARMarkerInfoCutoffPhase::None,
188            error_corrected: 0,
189            global_id: 0,
190        }
191    }
192}
193
194// Opaque/dummy types for ARHandle dependencies
195#[derive(Debug, Clone, Default)]
196pub struct ARParamLTf {
197    pub i2o: Vec<f32>,
198    pub o2i: Vec<f32>,
199    pub xsize: i32,
200    pub ysize: i32,
201    pub x_off: i32,
202    pub y_off: i32,
203}
204
205impl ARParamLTf {
206    pub fn new_basic(xsize: i32, ysize: i32) -> Self {
207        let i2o = vec![0.0f32; (xsize * ysize * 2) as usize];
208        let mut o2i = vec![0.0f32; (xsize * ysize * 2) as usize];
209        for y in 0..ysize {
210            for x in 0..xsize {
211                let idx = ((y * xsize + x) * 2) as usize;
212                o2i[idx] = x as f32;
213                o2i[idx + 1] = y as f32;
214            }
215        }
216        Self {
217            i2o,
218            o2i,
219            xsize,
220            ysize,
221            x_off: 0,
222            y_off: 0,
223        }
224    }
225}
226
227#[derive(Debug, Clone, Default)]
228pub struct ARParamLT {
229    pub param: ARParam,
230    pub param_ltf: ARParamLTf,
231}
232
233impl ARParamLT {
234    pub fn new(param: ARParam, param_ltf: ARParamLTf) -> Self {
235        Self { param, param_ltf }
236    }
237    
238    pub fn new_basic(param: ARParam) -> Self {
239        let param_ltf = ARParamLTf::new_basic(param.xsize, param.ysize);
240        Self {
241            param,
242            param_ltf,
243        }
244    }
245}
246
247#[repr(C)]
248#[derive(Debug, Clone)]
249pub struct ARTrackingHistory {
250    pub marker: ARMarkerInfo,
251    pub count: i32,
252}
253
254impl Default for ARTrackingHistory {
255    fn default() -> Self {
256        Self {
257            marker: ARMarkerInfo::default(),
258            count: 0,
259        }
260    }
261}
262
263pub type ARLabelingLabelType = i16;
264
265#[derive(Debug, Clone)]
266pub struct ARLabelInfo {
267    pub label_image: Vec<ARLabelingLabelType>,
268    pub label_num: i32,
269    pub area: Vec<i32>,
270    pub clip: Vec<[i32; 4]>,
271    pub pos: Vec<[ARdouble; 2]>,
272    pub work: Vec<i32>,
273    pub work2: Vec<i32>,
274}
275
276impl Default for ARLabelInfo {
277    fn default() -> Self {
278        Self {
279            label_image: Vec::new(),
280            label_num: 0,
281            area: vec![0; AR_LABELING_WORK_SIZE],
282            clip: vec![[0; 4]; AR_LABELING_WORK_SIZE],
283            pos: vec![[0.0; 2]; AR_LABELING_WORK_SIZE],
284            work: vec![0; AR_LABELING_WORK_SIZE],
285            work2: vec![0; AR_LABELING_WORK_SIZE * 7],
286        }
287    }
288}
289
290#[derive(Debug, Clone, Default)]
291pub struct ARPattHandle {
292    pub patt_num: i32,
293    pub patt_num_max: i32,
294    pub pattf: Vec<i32>,
295    pub patt: Vec<Vec<i32>>,
296    pub pattpow: Vec<ARdouble>,
297    pub patt_bw: Vec<Vec<i32>>,
298    pub pattpow_bw: Vec<ARdouble>,
299    pub patt_size: i32,
300}
301
302#[repr(C)]
303#[derive(Debug, Clone)]
304pub struct ARImageProcInfo {
305    _dummy: u8,
306}
307
308#[repr(i32)]
309#[derive(Debug, Clone, Copy, PartialEq, Eq)]
310pub enum ARPixelFormat {
311    Invalid = -1,
312    RGB = 0,
313    BGR,
314    RGBA,
315    BGRA,
316    ABGR,
317    MONO,
318    ARGB,
319    TwoVuy,
320    Yuvs,
321    Rgb565,
322    Rgba5551,
323    Rgba4444,
324    FourTwoZeroV,
325    FourTwoZeroF,
326    NV21,
327}
328
329impl Default for ARPixelFormat {
330    fn default() -> Self {
331        ARPixelFormat::Invalid
332    }
333}
334
335#[repr(i32)]
336#[derive(Debug, Clone, Copy, PartialEq, Eq)]
337pub enum ARLabelingThreshMode {
338    Manual = 0,
339    AutoMedian,
340    AutoOtsu,
341    AutoAdaptive,
342    AutoBracketing,
343}
344
345impl Default for ARLabelingThreshMode {
346    fn default() -> Self {
347        ARLabelingThreshMode::Manual
348    }
349}
350
351#[repr(i32)]
352#[derive(Debug, Clone, Copy, PartialEq, Eq)]
353pub enum ARMatrixCodeType {
354    Code3x3 = 0x03,
355}
356
357impl Default for ARMatrixCodeType {
358    fn default() -> Self {
359        ARMatrixCodeType::Code3x3
360    }
361}
362
363/// Structure holding state of an instance of the square marker tracker.
364#[derive(Debug, Clone)]
365#[repr(C)]
366pub struct ARHandle {
367    pub ar_debug: i32,
368    pub ar_pixel_format: ARPixelFormat,
369    pub ar_pixel_size: i32,
370    pub ar_labeling_mode: i32,
371    pub ar_labeling_thresh: i32,
372    pub ar_image_proc_mode: i32,
373    pub ar_pattern_detection_mode: i32,
374    pub ar_marker_extraction_mode: i32,
375    pub ar_param_lt: *mut ARParamLT,
376    pub xsize: i32,
377    pub ysize: i32,
378    pub marker_num: i32,
379    pub marker_info: Box<[ARMarkerInfo; AR_SQUARE_MAX]>,
380    pub marker2_num: i32,
381    pub marker_info2: Box<[ARMarkerInfo2; AR_SQUARE_MAX]>,
382    pub history_num: i32,
383    pub history: Box<[ARTrackingHistory; AR_SQUARE_MAX]>,
384    pub label_info: ARLabelInfo,
385    pub patt_handle: *mut ARPattHandle,
386    pub ar_labeling_thresh_mode: ARLabelingThreshMode,
387    pub ar_labeling_thresh_auto_interval: i32,
388    pub ar_labeling_thresh_auto_interval_ttl: i32,
389    pub ar_labeling_thresh_auto_bracket_over: i32,
390    pub ar_labeling_thresh_auto_bracket_under: i32,
391    pub ar_image_proc_info: *mut ARImageProcInfo,
392    pub patt_ratio: ARdouble,
393    pub matrix_code_type: ARMatrixCodeType,
394}
395
396impl ARHandle {
397    pub fn new(param: ARParam) -> Self {
398        let mut handle = ARHandle::default();
399        handle.xsize = param.xsize;
400        handle.ysize = param.ysize;
401        // In the full port, arParamLT would be initialized here too.
402        handle
403    }
404
405    pub fn set_pixel_format(&mut self, format: ARPixelFormat) {
406        self.ar_pixel_format = format;
407        // Update pixel size based on format if needed
408        self.ar_pixel_size = match format {
409            ARPixelFormat::RGB | ARPixelFormat::BGR => 3,
410            ARPixelFormat::RGBA | ARPixelFormat::BGRA | ARPixelFormat::ABGR | ARPixelFormat::ARGB => 4,
411            ARPixelFormat::MONO => 1,
412            _ => 0,
413        };
414    }
415}
416
417impl Default for ARHandle {
418    fn default() -> Self {
419        Self {
420            ar_debug: 0,
421            ar_pixel_format: ARPixelFormat::default(),
422            ar_pixel_size: 0,
423            ar_labeling_mode: 0,
424            ar_labeling_thresh: 100,
425            ar_image_proc_mode: 0,
426            ar_pattern_detection_mode: 0,
427            ar_marker_extraction_mode: 0,
428            ar_param_lt: std::ptr::null_mut(),
429            xsize: 0,
430            ysize: 0,
431            marker_num: 0,
432            marker_info: vec![ARMarkerInfo::default(); AR_SQUARE_MAX]
433                .into_boxed_slice()
434                .try_into()
435                .unwrap(),
436            marker2_num: 0,
437            marker_info2: vec![ARMarkerInfo2::default(); AR_SQUARE_MAX]
438                .into_boxed_slice()
439                .try_into()
440                .unwrap(),
441            history_num: 0,
442            history: vec![ARTrackingHistory::default(); AR_SQUARE_MAX]
443                .into_boxed_slice()
444                .try_into()
445                .unwrap(),
446            label_info: ARLabelInfo::default(),
447            patt_handle: std::ptr::null_mut(),
448            ar_labeling_thresh_mode: ARLabelingThreshMode::default(),
449            ar_labeling_thresh_auto_interval: 0,
450            ar_labeling_thresh_auto_interval_ttl: 0,
451            ar_labeling_thresh_auto_bracket_over: 0,
452            ar_labeling_thresh_auto_bracket_under: 0,
453            ar_image_proc_info: std::ptr::null_mut(),
454            patt_ratio: 0.5,
455            matrix_code_type: ARMatrixCodeType::default(),
456        }
457    }
458}
459
460pub use crate::icp::{ICPHandleT, ICPStereoHandleT};
461
462/// Structure holding state of an instance of the monocular pose estimator.
463#[derive(Debug, Clone)]
464#[repr(C)]
465pub struct AR3DHandle {
466    pub icp_handle: *mut ICPHandleT,
467}
468
469impl Default for AR3DHandle {
470    fn default() -> Self {
471        Self {
472            icp_handle: std::ptr::null_mut(),
473        }
474    }
475}
476
477/// Structure holding state of an instance of the stereo pose estimator.
478#[derive(Debug, Clone)]
479#[repr(C)]
480pub struct AR3DStereoHandle {
481    pub icp_stereo_handle: *mut ICPStereoHandleT,
482}
483
484impl Default for AR3DStereoHandle {
485    fn default() -> Self {
486        Self {
487            icp_stereo_handle: std::ptr::null_mut(),
488        }
489    }
490}
491
492#[cfg(test)]
493mod tests {
494    use super::*;
495
496    #[test]
497    fn test_arparam_default_initialization() {
498        let param = ARParam::default();
499        assert_eq!(param.xsize, 0);
500        assert_eq!(param.ysize, 0);
501        assert_eq!(param.mat, [[0.0; 4]; 3]);
502        assert_eq!(param.dist_factor, [0.0; AR_DIST_FACTOR_NUM_MAX]);
503        assert_eq!(param.dist_function_version, 0);
504    }
505
506    #[test]
507    fn test_armarkerinfo_default_initialization() {
508        let marker_info = ARMarkerInfo::default();
509        assert_eq!(marker_info.area, 0);
510        assert_eq!(marker_info.id, -1);
511        assert_eq!(marker_info.id_patt, -1);
512        assert_eq!(marker_info.id_matrix, -1);
513        assert_eq!(marker_info.dir, 0);
514        assert_eq!(marker_info.cf, 0.0);
515        assert_eq!(marker_info.pos, [0.0; 2]);
516        assert_eq!(marker_info.cutoff_phase, ARMarkerInfoCutoffPhase::None);
517        assert_eq!(marker_info.error_corrected, 0);
518        assert_eq!(marker_info.global_id, 0);
519    }
520
521    #[test]
522    fn test_arhandle_initial_state() {
523        let handle = ARHandle::default();
524        assert_eq!(handle.ar_debug, 0);
525        assert_eq!(handle.ar_labeling_thresh, 100);
526        assert_eq!(handle.patt_ratio, 0.5);
527        assert_eq!(handle.matrix_code_type, ARMatrixCodeType::Code3x3);
528        assert_eq!(handle.ar_pattern_detection_mode, 0);
529    }
530
531    #[test]
532    fn test_ar3dhandle_default_initialization() {
533        let handle = AR3DHandle::default();
534        assert_eq!(handle.icp_handle, std::ptr::null_mut());
535    }
536
537    #[test]
538    fn test_ar3dstereohandle_default_initialization() {
539        let handle = AR3DStereoHandle::default();
540        assert_eq!(handle.icp_stereo_handle, std::ptr::null_mut());
541    }
542}
543
544
545