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 = 40000;
44pub const AR_SQUARE_MAX: usize = 30;
45pub const AR_LABELING_WORK_SIZE: usize = 1024 * 32;
46
47pub const AR_TEMPLATE_MATCHING_COLOR: i32 = 0;
48pub const AR_TEMPLATE_MATCHING_MONO: i32 = 1;
49pub const AR_MATRIX_CODE_DETECTION: i32 = 2;
50pub const AR_TEMPLATE_MATCHING_COLOR_AND_MATRIX_CODE_DETECTION: i32 = 3;
51pub const AR_TEMPLATE_MATCHING_MONO_AND_MATRIX_CODE_DETECTION: i32 = 4;
52
53/// A structure to hold a timestamp in seconds and microseconds, with arbitrary epoch.
54#[derive(Debug, Clone, PartialEq, Default)]
55#[repr(C)]
56pub struct AR2VideoTimestampT {
57    pub sec: u64,
58    pub usec: u32,
59}
60
61/// A structure which carries information about a video frame retrieved by the video library.
62#[derive(Debug, Clone, Default)]
63pub struct AR2VideoBufferT {
64    /// A pointer to the packed video data for this video frame.
65    /// In Rust, we use a slice or Vec depending on ownership, usually represented as a raw slice or Vec.
66    pub buff: Option<Vec<u8>>,
67    /// For multi-planar video frames, arrays of planes.
68    pub buf_planes: Option<Vec<Vec<u8>>>,
69    /// Number of planes.
70    pub buf_plane_count: u32,
71    /// Luminance-only version of the image.
72    pub buff_luma: Option<Vec<u8>>,
73    /// Set to true when buff is valid.
74    pub fill_flag: bool,
75    /// Time at which the buffer was filled.
76    pub time: AR2VideoTimestampT,
77}
78
79/// Structure holding camera parameters, including image size, projection matrix and lens distortion parameters.
80#[derive(Debug, Clone, PartialEq, Default)]
81#[repr(C)]
82pub struct ARParam {
83    /// The width in pixels of images returned by the video library for the camera.
84    pub xsize: i32,
85    /// The height in pixels of images returned by the video library for the camera.
86    pub ysize: i32,
87    /// The projection matrix for the calibrated camera parameters.
88    pub mat: [[ARdouble; 4]; 3],
89    /// Distortion factors.
90    pub dist_factor: [ARdouble; AR_DIST_FACTOR_NUM_MAX],
91    /// Distortion function version.
92    pub dist_function_version: i32,
93}
94
95/// Captures detail of a trapezoidal region which is a candidate for marker detection.
96///
97/// This structure holds the raw 2D pixel-space information for a candidate region
98/// found by connected-component labeling and contour extraction before it is fully
99/// identified as a specific marker.
100#[derive(Debug, Clone)]
101#[repr(C)]
102pub struct ARMarkerInfo2 {
103    /// Area in pixels of the largest connected region
104    pub area: i32,
105    /// Center of the marker candidate (2D coordinate)
106    pub pos: [ARdouble; 2],
107    /// Number of coordinates corresponding to the candidate's contour
108    pub coord_num: i32,
109    /// X coordinates of the contour's perimeter pixels.
110    pub x_coord: Vec<i32>,
111    /// Y coordinates of the contour's perimeter pixels.
112    pub y_coord: Vec<i32>,
113    /// Indices into `x_coord` and `y_coord` arrays pointing to the four corners of the candidate.
114    /// The fifth element wraps around to the first corner (`vertex[4] == vertex[0]`).
115    pub vertex: [i32; 5],
116}
117
118impl Default for ARMarkerInfo2 {
119    fn default() -> Self {
120        Self {
121            area: 0,
122            pos: [0.0; 2],
123            coord_num: 0,
124            x_coord: vec![0i32; AR_CHAIN_MAX],
125            y_coord: vec![0i32; AR_CHAIN_MAX],
126            vertex: [0; 5],
127        }
128    }
129}
130
131/// Result codes returned by arDetectMarker to report state of individual detected trapezoidal regions.
132#[repr(i32)]
133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134pub enum ARMarkerInfoCutoffPhase {
135    None = 0,
136    PatternExtraction,
137    MatchGeneric,
138    MatchContrast,
139    MatchBarcodeNotFound,
140    MatchBarcodeEdcFail,
141    MatchConfidence,
142    PoseError,
143    PoseErrorMulti,
144    HeuristicTroublesomeMatrixCodes,
145}
146
147impl Default for ARMarkerInfoCutoffPhase {
148    fn default() -> Self {
149        ARMarkerInfoCutoffPhase::None
150    }
151}
152
153/// Describes a detected trapezoidal area (a candidate for a marker match).
154///
155/// This serves as the primary output of marker detection. It contains both raw properties
156/// of the shape (area, pos) and, if successfully matched, the identified marker ID and
157/// viewing direction.
158#[derive(Debug, Clone)]
159#[repr(C)]
160pub struct ARMarkerInfo {
161    /// Area in pixels of the largest connected region.
162    pub area: i32,
163    /// Marker ID if valid, or -1 if invalid (global ID regardless of matching type).
164    pub id: i32,
165    /// Template marker ID if matched via template matching, -1 otherwise.
166    pub id_patt: i32,
167    /// Matrix (barcode) marker ID if matched via matrix code, -1 otherwise.
168    pub id_matrix: i32,
169    /// Orientation of the marker (0, 1, 2, or 3) representing rotation in 90° increments.
170    pub dir: i32,
171    /// Orientation if matched via template matching.
172    pub dir_patt: i32,
173    /// Orientation if matched via matrix code.
174    pub dir_matrix: i32,
175    /// Confidence value of the match (0.0 to 1.0).
176    pub cf: ARdouble,
177    /// Confidence value from template matching.
178    pub cf_patt: ARdouble,
179    /// Confidence value from matrix code decoding.
180    pub cf_matrix: ARdouble,
181    /// Center of the marker (2D coordinate).
182    pub pos: [ARdouble; 2],
183    /// Line equations of the four sides of the marker in 2D space `[a, b, c]`.
184    pub line: [[ARdouble; 3]; 4],
185    /// 2D coordinates of the four corners in ideal (undistorted) camera space.
186    pub vertex: [[ARdouble; 2]; 4],
187    /// Pointer to source region info for this marker.
188    pub marker_info2_ptr: *mut ARMarkerInfo2,
189    /// Tracking phase at which the marker was cut off
190    pub cutoff_phase: ARMarkerInfoCutoffPhase,
191    /// The numbers of errors detected and corrected
192    pub error_corrected: i32,
193    /// Global ID for matrix codes
194    pub global_id: u64,
195}
196
197impl Default for ARMarkerInfo {
198    fn default() -> Self {
199        Self {
200            area: 0,
201            id: -1,
202            id_patt: -1,
203            id_matrix: -1,
204            dir: 0,
205            dir_patt: 0,
206            dir_matrix: 0,
207            cf: 0.0,
208            cf_patt: 0.0,
209            cf_matrix: 0.0,
210            pos: [0.0; 2],
211            line: [[0.0; 3]; 4],
212            vertex: [[0.0; 2]; 4],
213            marker_info2_ptr: std::ptr::null_mut(),
214            cutoff_phase: ARMarkerInfoCutoffPhase::None,
215            error_corrected: 0,
216            global_id: 0,
217        }
218    }
219}
220
221// Opaque/dummy types for ARHandle dependencies
222#[derive(Debug, Clone, Default)]
223pub struct ARParamLTf {
224    pub i2o: Vec<f32>,
225    pub o2i: Vec<f32>,
226    pub xsize: i32,
227    pub ysize: i32,
228    pub x_off: i32,
229    pub y_off: i32,
230}
231
232impl ARParamLTf {
233    pub fn new_basic(xsize: i32, ysize: i32) -> Self {
234        let i2o = vec![0.0f32; (xsize * ysize * 2) as usize];
235        let mut o2i = vec![0.0f32; (xsize * ysize * 2) as usize];
236        for y in 0..ysize {
237            for x in 0..xsize {
238                let idx = ((y * xsize + x) * 2) as usize;
239                o2i[idx] = x as f32;
240                o2i[idx + 1] = y as f32;
241            }
242        }
243        Self {
244            i2o,
245            o2i,
246            xsize,
247            ysize,
248            x_off: 0,
249            y_off: 0,
250        }
251    }
252}
253
254#[derive(Debug, Clone, Default)]
255pub struct ARParamLT {
256    pub param: ARParam,
257    pub param_ltf: ARParamLTf,
258}
259
260impl ARParamLT {
261    pub fn new(param: ARParam, param_ltf: ARParamLTf) -> Self {
262        Self { param, param_ltf }
263    }
264    
265    pub fn new_basic(param: ARParam) -> Self {
266        let param_ltf = ARParamLTf::new_basic(param.xsize, param.ysize);
267        Self {
268            param,
269            param_ltf,
270        }
271    }
272}
273
274#[repr(C)]
275#[derive(Debug, Clone)]
276pub struct ARTrackingHistory {
277    pub marker: ARMarkerInfo,
278    pub count: i32,
279}
280
281impl Default for ARTrackingHistory {
282    fn default() -> Self {
283        Self {
284            marker: ARMarkerInfo::default(),
285            count: 0,
286        }
287    }
288}
289
290pub type ARLabelingLabelType = i16;
291
292#[derive(Debug, Clone)]
293pub struct ARLabelInfo {
294    pub label_image: Vec<ARLabelingLabelType>,
295    pub label_num: i32,
296    pub area: Vec<i32>,
297    pub clip: Vec<[i32; 4]>,
298    pub pos: Vec<[ARdouble; 2]>,
299    pub work: Vec<i32>,
300    pub work2: Vec<i32>,
301}
302
303impl Default for ARLabelInfo {
304    fn default() -> Self {
305        Self {
306            label_image: Vec::new(),
307            label_num: 0,
308            area: vec![0; AR_LABELING_WORK_SIZE],
309            clip: vec![[0; 4]; AR_LABELING_WORK_SIZE],
310            pos: vec![[0.0; 2]; AR_LABELING_WORK_SIZE],
311            work: vec![0; AR_LABELING_WORK_SIZE],
312            work2: vec![0; AR_LABELING_WORK_SIZE * 7],
313        }
314    }
315}
316
317#[derive(Debug, Clone, Default)]
318pub struct ARPattHandle {
319    pub patt_num: i32,
320    pub patt_num_max: i32,
321    pub pattf: Vec<i32>,
322    pub patt: Vec<Vec<i32>>,
323    pub pattpow: Vec<ARdouble>,
324    pub patt_bw: Vec<Vec<i32>>,
325    pub pattpow_bw: Vec<ARdouble>,
326    pub patt_size: i32,
327}
328
329#[repr(C)]
330#[derive(Debug, Clone)]
331pub struct ARImageProcInfo {
332    _dummy: u8,
333}
334
335#[repr(i32)]
336#[derive(Debug, Clone, Copy, PartialEq, Eq)]
337pub enum ARPixelFormat {
338    Invalid = -1,
339    RGB = 0,
340    BGR,
341    RGBA,
342    BGRA,
343    ABGR,
344    MONO,
345    ARGB,
346    TwoVuy,
347    Yuvs,
348    Rgb565,
349    Rgba5551,
350    Rgba4444,
351    FourTwoZeroV,
352    FourTwoZeroF,
353    NV21,
354}
355
356impl Default for ARPixelFormat {
357    fn default() -> Self {
358        ARPixelFormat::Invalid
359    }
360}
361
362#[repr(i32)]
363#[derive(Debug, Clone, Copy, PartialEq, Eq)]
364pub enum ARLabelingThreshMode {
365    Manual = 0,
366    AutoMedian,
367    AutoOtsu,
368    AutoAdaptive,
369    AutoBracketing,
370}
371
372impl Default for ARLabelingThreshMode {
373    fn default() -> Self {
374        ARLabelingThreshMode::Manual
375    }
376}
377
378#[repr(i32)]
379#[derive(Debug, Clone, Copy, PartialEq, Eq)]
380pub enum ARMatrixCodeType {
381    /// 3x3 Matrix Code (Default)
382    Code3x3 = 0x03,
383    /// 3x3 Matrix Code with Parity (6,5)
384    Code3x3Parity65 = 0x03 | 0x100,
385    /// 3x3 Matrix Code with Hamming (6,3)
386    Code3x3Hamming63 = 0x03 | 0x200,
387    /// 4x4 Matrix Code
388    Code4x4 = 0x04,
389    /// 4x4 Matrix Code with BCH (13,9,3)
390    Code4x4BCH1393 = 0x04 | 0x300,
391    /// 4x4 Matrix Code with BCH (13,5,5)
392    Code4x4BCH1355 = 0x04 | 0x400,
393    /// 5x5 Matrix Code
394    Code5x5 = 0x05,
395    /// 5x5 Matrix Code with BCH (22,12,5)
396    Code5x5BCH22125 = 0x05 | 0x500,
397    /// 5x5 Matrix Code with BCH (22,7,7)
398    Code5x5BCH2277 = 0x05 | 0x600,
399    /// 6x6 Matrix Code
400    Code6x6 = 0x06,
401}
402
403impl Default for ARMatrixCodeType {
404    fn default() -> Self {
405        ARMatrixCodeType::Code3x3
406    }
407}
408
409/// Structure holding state of an instance of the square marker tracker.
410#[derive(Debug, Clone)]
411#[repr(C)]
412pub struct ARHandle {
413    pub ar_debug: i32,
414    pub ar_pixel_format: ARPixelFormat,
415    pub ar_pixel_size: i32,
416    pub ar_labeling_mode: i32,
417    pub ar_labeling_thresh: i32,
418    pub ar_image_proc_mode: i32,
419    pub ar_pattern_detection_mode: i32,
420    pub ar_marker_extraction_mode: i32,
421    pub ar_param_lt: *mut ARParamLT,
422    pub xsize: i32,
423    pub ysize: i32,
424    pub marker_num: i32,
425    pub marker_info: Box<[ARMarkerInfo; AR_SQUARE_MAX]>,
426    pub marker2_num: i32,
427    pub marker_info2: Box<[ARMarkerInfo2; AR_SQUARE_MAX]>,
428    pub history_num: i32,
429    pub history: Box<[ARTrackingHistory; AR_SQUARE_MAX]>,
430    pub label_info: ARLabelInfo,
431    pub patt_handle: *mut ARPattHandle,
432    pub ar_labeling_thresh_mode: ARLabelingThreshMode,
433    pub ar_labeling_thresh_auto_interval: i32,
434    pub ar_labeling_thresh_auto_interval_ttl: i32,
435    pub ar_labeling_thresh_auto_bracket_over: i32,
436    pub ar_labeling_thresh_auto_bracket_under: i32,
437    pub ar_image_proc_info: *mut ARImageProcInfo,
438    pub patt_ratio: ARdouble,
439    pub matrix_code_type: ARMatrixCodeType,
440}
441
442impl ARHandle {
443    pub fn new(param: ARParam) -> Self {
444        let mut handle = ARHandle::default();
445        handle.xsize = param.xsize;
446        handle.ysize = param.ysize;
447        // In the full port, arParamLT would be initialized here too.
448        handle
449    }
450
451    pub fn set_pixel_format(&mut self, format: ARPixelFormat) {
452        self.ar_pixel_format = format;
453        // Update pixel size based on format if needed
454        self.ar_pixel_size = match format {
455            ARPixelFormat::RGB | ARPixelFormat::BGR => 3,
456            ARPixelFormat::RGBA | ARPixelFormat::BGRA | ARPixelFormat::ABGR | ARPixelFormat::ARGB => 4,
457            ARPixelFormat::MONO => 1,
458            _ => 0,
459        };
460    }
461
462    pub fn set_matrix_code_type(&mut self, code_type: ARMatrixCodeType) {
463        self.matrix_code_type = code_type;
464    }
465
466    pub fn set_pattern_detection_mode(&mut self, mode: i32) {
467        self.ar_pattern_detection_mode = mode;
468    }
469
470    pub fn get_matrix_code_type(&self) -> ARMatrixCodeType {
471        self.matrix_code_type
472    }
473}
474
475impl Default for ARHandle {
476    fn default() -> Self {
477        Self {
478            ar_debug: 0,
479            ar_pixel_format: ARPixelFormat::default(),
480            ar_pixel_size: 0,
481            ar_labeling_mode: 0,
482            ar_labeling_thresh: 100,
483            ar_image_proc_mode: 0,
484            ar_pattern_detection_mode: 0,
485            ar_marker_extraction_mode: 0,
486            ar_param_lt: std::ptr::null_mut(),
487            xsize: 0,
488            ysize: 0,
489            marker_num: 0,
490            marker_info: vec![ARMarkerInfo::default(); AR_SQUARE_MAX]
491                .into_boxed_slice()
492                .try_into()
493                .unwrap(),
494            marker2_num: 0,
495            marker_info2: vec![ARMarkerInfo2::default(); AR_SQUARE_MAX]
496                .into_boxed_slice()
497                .try_into()
498                .unwrap(),
499            history_num: 0,
500            history: vec![ARTrackingHistory::default(); AR_SQUARE_MAX]
501                .into_boxed_slice()
502                .try_into()
503                .unwrap(),
504            label_info: ARLabelInfo::default(),
505            patt_handle: std::ptr::null_mut(),
506            ar_labeling_thresh_mode: ARLabelingThreshMode::default(),
507            ar_labeling_thresh_auto_interval: 0,
508            ar_labeling_thresh_auto_interval_ttl: 0,
509            ar_labeling_thresh_auto_bracket_over: 0,
510            ar_labeling_thresh_auto_bracket_under: 0,
511            ar_image_proc_info: std::ptr::null_mut(),
512            patt_ratio: 0.5,
513            matrix_code_type: ARMatrixCodeType::default(),
514        }
515    }
516}
517
518pub use crate::icp::{ICPHandleT, ICPStereoHandleT};
519
520/// Structure holding state of an instance of the monocular pose estimator.
521#[derive(Debug, Clone)]
522#[repr(C)]
523pub struct AR3DHandle {
524    pub icp_handle: *mut ICPHandleT,
525}
526
527impl Default for AR3DHandle {
528    fn default() -> Self {
529        Self {
530            icp_handle: std::ptr::null_mut(),
531        }
532    }
533}
534
535/// Structure holding state of an instance of the stereo pose estimator.
536#[derive(Debug, Clone)]
537#[repr(C)]
538pub struct AR3DStereoHandle {
539    pub icp_stereo_handle: *mut ICPStereoHandleT,
540}
541
542impl Default for AR3DStereoHandle {
543    fn default() -> Self {
544        Self {
545            icp_stereo_handle: std::ptr::null_mut(),
546        }
547    }
548}
549
550#[cfg(test)]
551mod tests {
552    use super::*;
553
554    #[test]
555    fn test_arparam_default_initialization() {
556        let param = ARParam::default();
557        assert_eq!(param.xsize, 0);
558        assert_eq!(param.ysize, 0);
559        assert_eq!(param.mat, [[0.0; 4]; 3]);
560        assert_eq!(param.dist_factor, [0.0; AR_DIST_FACTOR_NUM_MAX]);
561        assert_eq!(param.dist_function_version, 0);
562    }
563
564    #[test]
565    fn test_armarkerinfo_default_initialization() {
566        let marker_info = ARMarkerInfo::default();
567        assert_eq!(marker_info.area, 0);
568        assert_eq!(marker_info.id, -1);
569        assert_eq!(marker_info.id_patt, -1);
570        assert_eq!(marker_info.id_matrix, -1);
571        assert_eq!(marker_info.dir, 0);
572        assert_eq!(marker_info.cf, 0.0);
573        assert_eq!(marker_info.pos, [0.0; 2]);
574        assert_eq!(marker_info.cutoff_phase, ARMarkerInfoCutoffPhase::None);
575        assert_eq!(marker_info.error_corrected, 0);
576        assert_eq!(marker_info.global_id, 0);
577    }
578
579    #[test]
580    fn test_arhandle_initial_state() {
581        let handle = ARHandle::default();
582        assert_eq!(handle.ar_debug, 0);
583        assert_eq!(handle.ar_labeling_thresh, 100);
584        assert_eq!(handle.patt_ratio, 0.5);
585        assert_eq!(handle.matrix_code_type, ARMatrixCodeType::Code3x3);
586        assert_eq!(handle.ar_pattern_detection_mode, 0);
587    }
588
589    #[test]
590    fn test_ar3dhandle_default_initialization() {
591        let handle = AR3DHandle::default();
592        assert_eq!(handle.icp_handle, std::ptr::null_mut());
593    }
594
595    #[test]
596    fn test_ar3dstereohandle_default_initialization() {
597        let handle = AR3DStereoHandle::default();
598        assert_eq!(handle.icp_stereo_handle, std::ptr::null_mut());
599    }
600}
601
602
603