evoxel_transform/
filter.rs1use crate::Error;
2use evoxel_core::{VoxelDataColumnType, VoxelGrid};
3use nalgebra::Point3;
4use polars::datatypes::PlSmallStr;
5use polars::frame::DataFrame;
6
7use crate::Error::LowerCornerMustBeBelowUpperCorner;
8use polars::prelude::{ChunkCompareIneq, IntoLazy, Selector, all, col, len};
9
10pub fn aggregate_by_index(voxel_grid: &VoxelGrid) -> Result<VoxelGrid, Error> {
11 let voxel_data = voxel_grid.voxel_data();
12 let partition_columns = vec![
13 VoxelDataColumnType::X.as_str(),
14 VoxelDataColumnType::Y.as_str(),
15 VoxelDataColumnType::Z.as_str(),
16 ];
17
18 let partitioned: DataFrame = voxel_data
19 .clone()
20 .lazy()
21 .group_by(partition_columns)
22 .agg([all().as_expr(), len()])
23 .collect()?;
25 let filtered_voxel_grid = VoxelGrid::new(
42 partitioned,
43 voxel_grid.info().clone(),
44 voxel_grid.reference_frames().clone(),
45 )?;
46 Ok(filtered_voxel_grid)
47}
48
49pub fn explode(voxel_grid: &VoxelGrid) -> Result<VoxelGrid, Error> {
50 let voxel_data = voxel_grid.voxel_data();
51
52 let column_names: Vec<&str> = voxel_data
53 .get_columns()
54 .iter()
55 .filter(|s| s.dtype().inner_dtype().is_some()) .map(|s| s.name().as_str())
57 .collect();
58
59 let df: DataFrame = voxel_data
60 .clone()
61 .lazy()
62 .explode(Selector::ByName {
63 names: column_names.into_iter().map(PlSmallStr::from_str).collect(),
64 strict: false,
65 })
66 .collect()?;
68
69 let filtered_voxel_grid = VoxelGrid::new(
70 df,
71 voxel_grid.info().clone(),
72 voxel_grid.reference_frames().clone(),
73 )?;
74 Ok(filtered_voxel_grid)
75}
76
77pub fn filter_by_count(voxel_grid: &VoxelGrid, minimum: usize) -> Result<VoxelGrid, Error> {
78 let voxel_data = voxel_grid.voxel_data().clone();
79
80 let mask = voxel_data
81 .column(VoxelDataColumnType::Count.as_str())?
82 .as_materialized_series()
83 .gt_eq(minimum as i32)?;
84
85 let filtered_voxel_data = voxel_data.filter(&mask)?;
86 let filtered_voxel_grid = VoxelGrid::new(
87 filtered_voxel_data,
88 voxel_grid.info().clone(),
89 voxel_grid.reference_frames().clone(),
90 )?;
91
92 Ok(filtered_voxel_grid)
93}
94
95pub fn filter_by_index_bounds(
96 voxel_grid: &VoxelGrid,
97 lower_corner: Point3<i64>,
98 upper_corner: Point3<i64>,
99) -> Result<VoxelGrid, Error> {
100 if lower_corner >= upper_corner {
101 return Err(LowerCornerMustBeBelowUpperCorner(""));
102 }
103
104 let voxel_data = voxel_grid.voxel_data().clone();
105
106 let filtered_voxel_data = voxel_data
107 .lazy()
108 .filter(
109 col(VoxelDataColumnType::X.as_str())
110 .gt_eq(lower_corner.x)
111 .and(col(VoxelDataColumnType::X.as_str()).lt_eq(upper_corner.x)),
112 )
113 .filter(
114 col(VoxelDataColumnType::Y.as_str())
115 .gt_eq(lower_corner.y)
116 .and(col(VoxelDataColumnType::Y.as_str()).lt_eq(upper_corner.y)),
117 )
118 .filter(
119 col(VoxelDataColumnType::Z.as_str())
120 .gt_eq(lower_corner.z)
121 .and(col(VoxelDataColumnType::Z.as_str()).lt_eq(upper_corner.z)),
122 )
123 .collect()?;
124 let filtered_voxel_grid = VoxelGrid::new(
125 filtered_voxel_data,
126 voxel_grid.info().clone(),
127 voxel_grid.reference_frames().clone(),
128 )?;
129
130 Ok(filtered_voxel_grid)
131}