Skip to content

Commit

Permalink
feat(core): implement 3D grid generation internal routines (#256)
Browse files Browse the repository at this point in the history
* write a hex gen fucntion for 3D beta values

* WIP

* finish the build_3d_grid routine

* add parse_3d function

need to replace handle 3D origins

* integrate 3d origin to grid descriptor

* add lint exception to split PRs

* address feedback

* reverse method rename
  • Loading branch information
imrn99 authored Mar 6, 2025
1 parent 9a4b00a commit 3687a7c
Showing 1 changed file with 347 additions and 2 deletions.
349 changes: 347 additions & 2 deletions honeycomb-core/src/cmap/builder/grid.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::attributes::AttrStorageManager;
use crate::cmap::{BuilderError, CMap2, DartIdType};
use crate::geometry::{CoordsFloat, Vector2, Vertex2};
use crate::cmap::{BuilderError, CMap2, CMap3, DartIdType, VertexIdType};
use crate::geometry::{CoordsFloat, Vector2, Vector3, Vertex2, Vertex3};

// --- grid descriptor

Expand Down Expand Up @@ -162,10 +162,79 @@ impl<T: CoordsFloat> GridDescriptor<T> {
(_, _, _) => Err(BuilderError::MissingGridParameters),
}
}

/*
/// Parse provided grid parameters to provide what's used to actually generate the grid.
#[allow(clippy::type_complexity)]
pub(crate) fn parse_3d(self) -> Result<(Vertex3<T>, [usize; 3], [T; 3]), BuilderError> {
match (self.n_cells, self.len_per_cell, self.lens) {
// from # cells and lengths per cell
(Some([nx, ny, nz]), Some([lpx, lpy, lpz]), lens) => {
if lens.is_some() {
eprintln!(
"W: All three grid parameters were specified, total lengths will be ignored"
);
}
#[rustfmt::skip]
check_parameters!(lpx, "length per x cell is null or negative");
#[rustfmt::skip]
check_parameters!(lpy, "length per y cell is null or negative");
#[rustfmt::skip]
check_parameters!(lpz, "length per z cell is null or negative");
Ok((self.origin3, [nx, ny, nz], [lpx, lpy, lpz]))
}
// from # cells and total lengths
(Some([nx, ny, nz]), None, Some([lx, ly, lz])) => {
#[rustfmt::skip]
check_parameters!(lx, "grid length along x is null or negative");
#[rustfmt::skip]
check_parameters!(ly, "grid length along y is null or negative");
#[rustfmt::skip]
check_parameters!(lz, "grid length along z is null or negative");
Ok((
self.origin3,
[nx, ny, nz],
[
lx / T::from(nx).unwrap(),
ly / T::from(ny).unwrap(),
lz / T::from(nz).unwrap(),
],
))
}
// from lengths per cell and total lengths
(None, Some([lpx, lpy, lpz]), Some([lx, ly, lz])) => {
#[rustfmt::skip]
check_parameters!(lpx, "length per x cell is null or negative");
#[rustfmt::skip]
check_parameters!(lpy, "length per y cell is null or negative");
#[rustfmt::skip]
check_parameters!(lpz, "length per z cell is null or negative");
#[rustfmt::skip]
check_parameters!(lx, "grid length along x is null or negative");
#[rustfmt::skip]
check_parameters!(ly, "grid length along y is null or negative");
#[rustfmt::skip]
check_parameters!(lz, "grid length along z is null or negative");
Ok((
self.origin3,
[
(lx / lpx).ceil().to_usize().unwrap(),
(ly / lpy).ceil().to_usize().unwrap(),
(lz / lpz).ceil().to_usize().unwrap(),
],
[lpx, lpy, lpz],
))
}
(_, _, _) => Err(BuilderError::MissingGridParameters),
}
}
*/
}

// --- building routines

// ------ 2D

/// Internal grid-building routine
#[allow(clippy::too_many_lines)]
pub fn build_2d_grid<T: CoordsFloat>(
Expand Down Expand Up @@ -381,3 +450,279 @@ fn generate_tris_beta_values(n_x: usize, n_y: usize) -> impl Iterator<Item = [Da
})
})
}

// ------ 3D

#[allow(unused)]
/// Internal grid-building routine
#[allow(clippy::too_many_lines)]
pub fn build_3d_grid<T: CoordsFloat>(
origin: Vertex3<T>,
n_cells_per_axis: [usize; 3],
lengths: [T; 3],
manager: AttrStorageManager,
) -> CMap3<T> {
let [n_square_x, n_square_y, n_square_z] = n_cells_per_axis;
let n_darts = 24 * n_square_x * n_square_y * n_square_z;

let map: CMap3<T> = CMap3::new_with_undefined_attributes(n_darts, manager);

// init beta functions
(1..=n_darts as DartIdType)
.zip(generate_hex_beta_values(n_cells_per_axis))
.for_each(|(dart, images)| {
map.set_betas(dart, images);
});

// place vertices
(1..=n_darts as DartIdType)
.filter(|d| *d as VertexIdType == map.vertex_id(*d))
.for_each(|d| {
let v = origin + generate_hex_offset(d, n_cells_per_axis, lengths);
map.force_write_vertex(d as VertexIdType, v);
});

// check the number of built volumes
// this is set as debug only because the operation cost scales with map size
// this can quickly overshadow the exectime of all previous code
debug_assert_eq!(
map.iter_volumes().count(),
n_square_x * n_square_y * n_square_z
);

map
}

//
// y+
// |
// |
// |
// +------x+
// \
// \
// z+
//
// faces:
// y-: 1
// y+: 21
// z-: 5
// z+: 13
// x-: 17
// x+: 9
#[allow(clippy::inline_always, unused)]
#[rustfmt::skip]
#[inline(always)]
fn generate_hex_beta_values(
[n_x, n_y, n_z]: [usize; 3],
) -> impl Iterator<Item = [DartIdType; 4]> {
// this loop hierarchy yields the value in correct order
// left to right first, then bottom to top
(0..n_z).flat_map(move |iz| {
(0..n_y).flat_map(move |iy| {
(0..n_x).flat_map(move |ix| {
let d1 = (1 + 24 * ix + n_x * 24 * iy + n_x * n_y * 24 * iz) as DartIdType;
let ( d2 , d3 , d4 , d5 , d6 , d7 , d8 ,
d9 , d10, d11, d12, d13, d14, d15, d16,
d17, d18, d19, d20, d21, d22, d23, d24,
) = ( d1 + 1 , d1 + 2 , d1 + 3 , d1 + 4 , d1 + 5 , d1 + 6 , d1 + 7 ,
d1 + 8 , d1 + 9 , d1 + 10, d1 + 11, d1 + 12, d1 + 13, d1 + 14, d1 + 15,
d1 + 16, d1 + 17, d1 + 18, d1 + 19, d1 + 20, d1 + 21, d1 + 22, d1 + 23,
);
let noffset_x = 24;
let noffset_y = 24 * n_x as DartIdType;
let noffset_z = 24 * (n_x * n_y ) as DartIdType;

// beta images of the cube (tm)
[
// down (1, y-)
[d4 , d2 , d5 , if iy == 0 { 0 } else { d21 - noffset_y }],
[d1 , d3 , d9 , if iy == 0 { 0 } else { d24 - noffset_y }],
[d2 , d4 , d13, if iy == 0 { 0 } else { d23 - noffset_y }],
[d3 , d1 , d17, if iy == 0 { 0 } else { d22 - noffset_y }],
// side (5 , z-)
[d8 , d6 , d1 , if iz == 0 { 0 } else { d13 - noffset_z }],
[d5 , d7 , d10, if iz == 0 { 0 } else { d16 - noffset_z }],
[d6 , d8 , d21, if iz == 0 { 0 } else { d15 - noffset_z }],
[d7 , d5 , d20, if iz == 0 { 0 } else { d14 - noffset_z }],
// side (9 , x+)
[d12, d10, d2 , if ix == n_x - 1 { 0 } else { d17 - noffset_z }],
[d9 , d11, d6 , if ix == n_x - 1 { 0 } else { d20 - noffset_z }],
[d10, d12, d24, if ix == n_x - 1 { 0 } else { d19 - noffset_z }],
[d11, d9 , d14, if ix == n_x - 1 { 0 } else { d18 - noffset_z }],
// side (13, z+)
[d16, d14, d3 , if iz == n_z - 1 { 0 } else { d5 + noffset_z }],
[d13, d15, d12, if iz == n_z - 1 { 0 } else { d8 + noffset_z }],
[d14, d16, d23, if iz == n_z - 1 { 0 } else { d7 + noffset_z }],
[d15, d13, d18, if iz == n_z - 1 { 0 } else { d6 + noffset_z }],
// side (17, x-)
[d20, d18, d4 , if ix == 0 { 0 } else { d9 + noffset_z }],
[d17, d19, d16, if ix == 0 { 0 } else { d12 + noffset_z }],
[d18, d20, d22, if ix == 0 { 0 } else { d11 + noffset_z }],
[d19, d17, d8 , if ix == 0 { 0 } else { d10 + noffset_z }],
// up (21, y+)
[d24, d22, d7 , if iy == n_y - 1 { 0 } else { d1 + noffset_y }],
[d21, d23, d14, if iy == n_y - 1 { 0 } else { d4 + noffset_y }],
[d22, d24, d15, if iy == n_y - 1 { 0 } else { d3 + noffset_y }],
[d23, d21, d11, if iy == n_y - 1 { 0 } else { d2 + noffset_y }],
]
.into_iter()
})
})
})
}

// FIXME: merge match arms once there are tests
#[allow(
clippy::inline_always,
unused,
clippy::match_same_arms,
clippy::too_many_lines,
clippy::many_single_char_names
)]
#[inline(always)]
fn generate_hex_offset<T: CoordsFloat>(
dart: DartIdType,
[n_x, n_y, _]: [usize; 3],
[lx, ly, lz]: [T; 3],
) -> Vector3<T> {
// d = p + 24*x + 24*NX*y + 24*NX*NY*z
let d = dart as usize;
let dm = d % 24;
let dmm = d % (24 * n_x);
let dmmm = d % (24 * n_x * n_y);
let p = dm;
let x = (dmm - dm) / 24;
let y = (dmmm - dmm) / (24 * n_x);
let z = dmmm / (24 * n_x * n_y);
match p {
// d1 to d24
// y- face
1 => Vector3(
T::from(x).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z).unwrap() * lz,
),
2 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z).unwrap() * lz,
),
3 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
4 => Vector3(
T::from(x).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
// z- face
5 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z).unwrap() * lz,
),
6 => Vector3(
T::from(x).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z).unwrap() * lz,
),
7 => Vector3(
T::from(x).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z).unwrap() * lz,
),
8 => Vector3(
T::from(x).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z).unwrap() * lz,
),
// x+ face
9 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
10 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z).unwrap() * lz,
),
11 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z).unwrap() * lz,
),
12 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
// z+ face
13 => Vector3(
T::from(x).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
14 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
15 => Vector3(
T::from(x).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
16 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
// x- face
17 => Vector3(
T::from(x).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z).unwrap() * lz,
),
18 => Vector3(
T::from(x).unwrap() * lx,
T::from(y).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
19 => Vector3(
T::from(x).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
20 => Vector3(
T::from(x).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z).unwrap() * lz,
),
// y+ face
21 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z).unwrap() * lz,
),
22 => Vector3(
T::from(x).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z).unwrap() * lz,
),
23 => Vector3(
T::from(x).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
0 => Vector3(
T::from(x + 1).unwrap() * lx,
T::from(y + 1).unwrap() * ly,
T::from(z + 1).unwrap() * lz,
),
_ => unreachable!(),
}
}

0 comments on commit 3687a7c

Please sign in to comment.