1use crate::{LodError, LodIndex, LodResult, NodeId};
2
3pub fn copc_query_for_nodes(
8 index: &LodIndex,
9 nodes: &[NodeId],
10 max_resolution: f64,
11) -> LodResult<spatialrust_io::CopcQuery> {
12 if nodes.is_empty() {
13 return Err(LodError::Copc("at least one selected node is required".into()));
14 }
15 if !max_resolution.is_finite() || max_resolution <= 0.0 {
16 return Err(LodError::Copc("COPC max resolution must be finite and positive".into()));
17 }
18 let first = index.node(nodes[0]).ok_or(LodError::UnknownNode(nodes[0].0))?;
19 let mut bounds = first.bounds;
20 for id in &nodes[1..] {
21 let node = index.node(*id).ok_or(LodError::UnknownNode(id.0))?;
22 bounds = bounds.union(node.bounds);
23 }
24 let copc_bounds = spatialrust_io::CopcBounds::new(
25 [bounds.min.x as f64, bounds.min.y as f64, bounds.min.z as f64],
26 [bounds.max.x as f64, bounds.max.y as f64, bounds.max.z as f64],
27 );
28 let query = spatialrust_io::CopcQuery::with_resolution(copc_bounds, max_resolution);
29 query.validate().map_err(|error| LodError::Copc(error.to_string()))?;
30 Ok(query)
31}
32
33#[cfg(test)]
34mod tests {
35 use spatialrust_math::Vec3;
36
37 use crate::{LodBounds, LodIndex, LodNode, NodeId};
38
39 #[test]
40 fn selected_nodes_become_one_bounded_resolution_query() {
41 let index = LodIndex::try_new([
42 LodNode {
43 id: NodeId(0),
44 parent: None,
45 children: vec![NodeId(1)],
46 bounds: LodBounds::try_new(Vec3::new(-1.0, -1.0, -1.0), Vec3::new(1.0, 1.0, 1.0))
47 .unwrap(),
48 geometric_error: 1.0,
49 point_count: 10,
50 host_bytes: 40,
51 upload_bytes: 40,
52 gpu_bytes: 40,
53 },
54 LodNode {
55 id: NodeId(1),
56 parent: Some(NodeId(0)),
57 children: Vec::new(),
58 bounds: LodBounds::try_new(Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 1.0, 1.0))
59 .unwrap(),
60 geometric_error: 0.5,
61 point_count: 5,
62 host_bytes: 20,
63 upload_bytes: 20,
64 gpu_bytes: 20,
65 },
66 ])
67 .unwrap();
68 let query = super::copc_query_for_nodes(&index, &[NodeId(1)], 0.25).unwrap();
69 assert_eq!(query.bounds.min, [0.0, 0.0, 0.0]);
70 assert_eq!(query.bounds.max, [1.0, 1.0, 1.0]);
71 assert_eq!(query.max_resolution, Some(0.25));
72 assert!(super::copc_query_for_nodes(&index, &[], 0.25).is_err());
73 }
74}