Skip to main content

cumulus3d_core/
ids.rs

1/*
2 * ids.rs
3 *
4 * Copyright (c) 2026 ParkSangWoo
5 *
6 * Author(s):
7 *
8 *      ParkSangWoo <dev.parksangwoo@gmail.com>
9 *
10 *
11 * This file is part of cumulus3d.
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 *      http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *
25 * SPDX-License-Identifier: Apache-2.0
26 */
27
28//! Identifier types and pair ids.
29
30use crate::error::{Error, Result};
31
32/// Camera id.
33pub type CameraId = u32;
34/// rig id.
35pub type RigId = u32;
36/// Frame id.
37pub type FrameId = u32;
38/// Image id.
39pub type ImageId = u32;
40/// Index of a 2D point (feature) within an image.
41pub type Point2DIdx = u32;
42/// 3D point id.
43pub type Point3DId = u64;
44/// Pair id (see `pair_id_of`).
45pub type PairId = u64;
46
47/// Invalid camera id.
48pub const INVALID_CAMERA_ID: CameraId = u32::MAX;
49/// Invalid rig id.
50pub const INVALID_RIG_ID: RigId = u32::MAX;
51/// Invalid frame id.
52pub const INVALID_FRAME_ID: FrameId = u32::MAX;
53/// Invalid image id.
54pub const INVALID_IMAGE_ID: ImageId = u32::MAX;
55/// Invalid 2D point index.
56pub const INVALID_POINT2D_IDX: Point2DIdx = u32::MAX;
57/// Invalid 3D point id (the 2D point is not linked to a 3D point).
58pub const INVALID_POINT3D_ID: Point3DId = u64::MAX;
59/// Invalid pair id.
60pub const INVALID_PAIR_ID: PairId = u64::MAX;
61
62/// Pair id constant M = 2^31 − 1. Image ids must be smaller than this.
63pub const MAX_NUM_IMAGES: u64 = 2_147_483_647;
64
65/// Sensor kind. Stored as i32 in files.
66#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
67pub enum SensorKind {
68    /// Invalid sensor.
69    Invalid = -1,
70    /// Camera.
71    Camera = 0,
72    /// Inertial measurement unit.
73    Imu = 1,
74}
75
76impl SensorKind {
77    /// Integer value -> kind. None if the value is unknown.
78    pub fn from_i32(v: i32) -> Option<Self> {
79        match v {
80            -1 => Some(SensorKind::Invalid),
81            0 => Some(SensorKind::Camera),
82            1 => Some(SensorKind::Imu),
83            _ => None,
84        }
85    }
86    /// Integer value used for file storage.
87    pub fn as_i32(self) -> i32 {
88        self as i32
89    }
90    /// Text format name.
91    pub fn name(self) -> &'static str {
92        match self {
93            SensorKind::Invalid => "INVALID",
94            SensorKind::Camera => "CAMERA",
95            SensorKind::Imu => "IMU",
96        }
97    }
98    /// Text format name -> kind.
99    pub fn from_name(s: &str) -> Option<Self> {
100        match s {
101            "INVALID" => Some(SensorKind::Invalid),
102            "CAMERA" => Some(SensorKind::Camera),
103            "IMU" => Some(SensorKind::Imu),
104            _ => None,
105        }
106    }
107}
108
109/// Sensor identifier (kind, id). Lexicographic ordering (kind -> id).
110#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
111pub struct SensorKey {
112    /// Sensor kind.
113    pub sensor_type: SensorKind,
114    /// Sensor id within the kind.
115    pub id: u32,
116}
117
118impl SensorKey {
119    /// Creates from (kind, id).
120    pub fn new(sensor_type: SensorKind, id: u32) -> Self {
121        Self { sensor_type, id }
122    }
123    /// Camera sensor (id = camera id).
124    pub fn camera(camera_id: CameraId) -> Self {
125        Self { sensor_type: SensorKind::Camera, id: camera_id }
126    }
127}
128
129/// Data identifier (sensor, data id). For camera data the data id is the image id.
130#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
131pub struct SensorDataKey {
132    /// Sensor that produced the data.
133    pub sensor_id: SensorKey,
134    /// Data id (the image id for a camera).
135    pub id: u64,
136}
137
138impl SensorDataKey {
139    /// Creates from (sensor, data id).
140    pub fn new(sensor_id: SensorKey, id: u64) -> Self {
141        Self { sensor_id, id }
142    }
143    /// Camera image data key.
144    pub fn image(camera_id: CameraId, image_id: ImageId) -> Self {
145        Self { sensor_id: SensorKey::camera(camera_id), id: image_id as u64 }
146    }
147}
148
149/// Whether the order of the two image ids is "larger -> smaller", so a swap is needed when storing.
150pub fn swap_image_pair(image_id1: ImageId, image_id2: ImageId) -> bool {
151    image_id1 > image_id2
152}
153
154/// Pair id = M·min + max. Error if an image id is M or greater.
155pub fn pair_id_of(image_id1: ImageId, image_id2: ImageId) -> Result<PairId> {
156    if image_id1 as u64 >= MAX_NUM_IMAGES || image_id2 as u64 >= MAX_NUM_IMAGES {
157        return Err(Error::InvalidArgument(format!("영상 id 는 {MAX_NUM_IMAGES} 미만이어야 함: ({image_id1}, {image_id2})")));
158    }
159    let (a, b) = if image_id1 <= image_id2 { (image_id1, image_id2) } else { (image_id2, image_id1) };
160    Ok(MAX_NUM_IMAGES * a as u64 + b as u64)
161}
162
163/// Pair id -> (smaller id, larger id).
164pub fn images_of_pair(pair_id: PairId) -> (ImageId, ImageId) {
165    let id2 = pair_id % MAX_NUM_IMAGES;
166    let id1 = (pair_id - id2) / MAX_NUM_IMAGES;
167    (id1 as ImageId, id2 as ImageId)
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173
174    #[test]
175    fn pair_id_roundtrip() {
176        assert_eq!(pair_id_of(1, 2).unwrap(), 2147483649);
177        assert_eq!(pair_id_of(2, 1).unwrap(), 2147483649);
178        assert_eq!(images_of_pair(2147483649), (1, 2));
179        for (a, b) in [(0u32, 0u32), (5, 3), (2147483646, 7), (100, 2147483646)] {
180            let id = pair_id_of(a, b).unwrap();
181            assert_eq!(images_of_pair(id), (a.min(b), a.max(b)));
182        }
183        assert!(pair_id_of(2147483647, 1).is_err());
184        assert!(swap_image_pair(2, 1));
185        assert!(!swap_image_pair(1, 2));
186    }
187
188    #[test]
189    fn sensor_ordering() {
190        let a = SensorDataKey::image(1, 5);
191        let b = SensorDataKey::image(2, 1);
192        assert!(a < b);
193        assert!(SensorKey::new(SensorKind::Camera, 9) < SensorKey::new(SensorKind::Imu, 0));
194    }
195}