cumulus3d_dense/cache.rs
1/*
2 * cache.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//! Depth map cache: (image name + pose/intrinsics/size hash, settings hash) → final depth, normal and validity mask.
29//! Keeps overlapping zones from recomputing images with the same pose.
30
31use std::collections::{HashMap, VecDeque};
32use std::sync::{Arc, Mutex};
33
34/// One cached view (final scale): pre-filter depth (input to other views' geometric runs) and final depth, normal and cost (fusion input).
35#[derive(Clone, Debug)]
36pub struct CachedDepth {
37 /// Width (pixels).
38 pub width: usize,
39 /// Height (pixels).
40 pub height: usize,
41 /// Final depth before filtering (input to other views' geometric runs).
42 pub raw_depth: Vec<f32>,
43 /// Depth after the filter (0 = invalid).
44 pub depth: Vec<f32>,
45 /// Normal in the reference camera coordinates.
46 pub normal: Vec<[f32; 3]>,
47 /// Final aggregated cost.
48 pub cost: Vec<f32>,
49}
50
51type Entries = (HashMap<(u64, u64), Arc<CachedDepth>>, VecDeque<(u64, u64)>);
52
53/// Depth map cache (thread-safe; when over capacity, the oldest entries are dropped first).
54pub struct DepthMapCache {
55 inner: Mutex<Entries>,
56 capacity: usize,
57}
58
59impl Default for DepthMapCache {
60 fn default() -> Self {
61 Self::new()
62 }
63}
64
65impl DepthMapCache {
66 /// Capacity of 512 views.
67 pub fn new() -> Self {
68 Self::with_capacity(512)
69 }
70 /// Creates a cache with the given capacity (minimum 1).
71 pub fn with_capacity(capacity: usize) -> Self {
72 Self { inner: Mutex::new((HashMap::new(), VecDeque::new())), capacity: capacity.max(1) }
73 }
74 /// Looks up by key (image geometry hash, settings hash).
75 pub fn get(&self, key: (u64, u64)) -> Option<Arc<CachedDepth>> {
76 self.inner.lock().unwrap_or_else(|e| e.into_inner()).0.get(&key).cloned()
77 }
78 /// Inserts. When over capacity, the oldest entries are dropped first.
79 pub fn insert(&self, key: (u64, u64), v: Arc<CachedDepth>) {
80 let mut g = self.inner.lock().unwrap_or_else(|e| e.into_inner());
81 if g.0.insert(key, v).is_none() {
82 g.1.push_back(key);
83 }
84 while g.1.len() > self.capacity {
85 if let Some(k) = g.1.pop_front() {
86 g.0.remove(&k);
87 }
88 }
89 }
90 /// Number of stored views.
91 pub fn len(&self) -> usize {
92 self.inner.lock().unwrap_or_else(|e| e.into_inner()).0.len()
93 }
94 /// Whether it is empty.
95 pub fn is_empty(&self) -> bool {
96 self.len() == 0
97 }
98}