use crate::core::{
clusters::generate_block_cluster,
mesh::Mesh,
selection::select_nodes_in_box,
transformation::{
build_rotation_matrix, rotate_node, rotate_nodes, transform_selected_nodes,
},
};
use crate::error::{Error, Result};
#[derive(Debug, Clone)]
pub struct DesignBlock {
pub nodes: Vec<[f64; 3]>,
pub length: [f64; 3],
pub centre: [f64; 3],
pub theta: [f64; 3],
pub resolution: [usize; 3],
pub corner_nodes: [[f64; 3]; 8],
pub scaling_factors: [f64; 3],
pub local_coordinate_system: [[f64; 3]; 4],
}
impl DesignBlock {
pub fn new(
length: [f64; 3],
centre: [f64; 3],
theta: [f64; 3],
resolution: [usize; 3],
) -> Result<Self> {
let nodes = generate_block_cluster(length, centre, theta, resolution)?;
let scaling_factors = [1. / length[0], 1. / length[1], 1. / length[2]];
let [cx, cy, cz] = centre;
let [lx, ly, lz] = length;
let half_lx = lx / 2.0;
let half_ly = ly / 2.0;
let half_lz = lz / 2.0;
let mut corner_nodes = [
[cx - half_lx, cy - half_ly, cz - half_lz], [cx + half_lx, cy - half_ly, cz - half_lz], [cx - half_lx, cy + half_ly, cz - half_lz], [cx + half_lx, cy + half_ly, cz - half_lz], [cx - half_lx, cy - half_ly, cz + half_lz], [cx + half_lx, cy - half_ly, cz + half_lz], [cx - half_lx, cy + half_ly, cz + half_lz], [cx + half_lx, cy + half_ly, cz + half_lz], ];
rotate_nodes(&mut corner_nodes, &theta, ¢re);
let local_coordinate_system = [
corner_nodes[0],
corner_nodes[1],
corner_nodes[2],
corner_nodes[4],
];
let updated_coordinate_system: [[f64; 3]; 4] = {
let mut result = [[0.0; 3]; 4];
for (i, &node) in local_coordinate_system.iter().enumerate() {
result[i] = [
node[0] - corner_nodes[0][0],
node[1] - corner_nodes[0][1],
node[2] - corner_nodes[0][2],
];
}
result
};
Ok(DesignBlock {
nodes,
length,
centre,
theta,
resolution,
corner_nodes,
scaling_factors,
local_coordinate_system: updated_coordinate_system,
})
}
pub fn select_free_design_nodes(
&self,
target_mesh: &Mesh,
fixed_layers: Option<usize>,
) -> Result<Vec<usize>> {
let fixed_layers = fixed_layers.unwrap_or(2);
if self.resolution.iter().any(|&res| res < fixed_layers) {
return Err(Error::Deformation(
"Block resultion must be at least the size of the fixed layers!"
.to_string(),
));
}
let corner = self.corner_nodes;
let sides = [
[corner[0], corner[1], corner[3], corner[2]], [corner[4], corner[5], corner[7], corner[6]], [corner[0], corner[1], corner[5], corner[4]], [corner[2], corner[3], corner[7], corner[6]], [corner[0], corner[2], corner[6], corner[4]], [corner[1], corner[3], corner[7], corner[5]], ];
let mut fixed_sides: Vec<usize> = Vec::new();
for (i, side) in sides.iter().enumerate() {
let a = [
side[1][0] - side[0][0],
side[1][1] - side[0][1],
side[1][2] - side[0][2],
];
let b = [
side[2][0] - side[0][0],
side[2][1] - side[0][1],
side[2][2] - side[0][2],
];
let normal = [
a[1] * b[2] - a[2] * b[1],
a[2] * b[0] - a[0] * b[2],
a[0] * b[1] - a[1] * b[0],
];
let mut centre = [0.0; 3];
for point in side.iter() {
centre[0] += point[0];
centre[1] += point[1];
centre[2] += point[2];
}
centre[0] /= 4.0;
centre[1] /= 4.0;
centre[2] /= 4.0;
if target_mesh.slice(centre, normal).is_some() {
fixed_sides.push(i)
}
}
let mut new_length = self.length;
let mut new_centre = self.centre;
let step = [
self.length[0] / (self.resolution[0] as f64),
self.length[1] / (self.resolution[1] as f64),
self.length[2] / (self.resolution[2] as f64),
];
let correction_factor = 0.01;
let correction = [
step[0] * (fixed_layers - 1) as f64 + correction_factor * step[0],
step[1] * (fixed_layers - 1) as f64 + correction_factor * step[1],
step[2] * (fixed_layers - 1) as f64 + correction_factor * step[2],
];
if fixed_sides.contains(&4) {
new_length[0] -= correction[0];
new_centre[0] += 0.5 * correction[0];
}
if fixed_sides.contains(&5) {
new_length[0] -= correction[0];
new_centre[0] -= 0.5 * correction[0];
}
if fixed_sides.contains(&2) {
new_length[1] -= correction[1];
new_centre[1] += 0.5 * correction[1];
}
if fixed_sides.contains(&3) {
new_length[1] -= correction[1];
new_centre[1] -= 0.5 * correction[1];
}
if fixed_sides.contains(&0) {
new_length[2] -= correction[2];
new_centre[2] += 0.5 * correction[2];
}
if fixed_sides.contains(&1) {
new_length[2] -= correction[2];
new_centre[2] -= 0.5 * correction[2];
}
new_length[0] += 0.1 * correction_factor * step[0];
new_length[1] += 0.1 * correction_factor * step[1];
new_length[2] += 0.1 * correction_factor * step[2];
let rotation_matrix = build_rotation_matrix(&self.theta);
rotate_node(&mut new_centre, &rotation_matrix, &self.centre);
let free_node_ids =
select_nodes_in_box(&self.nodes, new_length, new_centre, self.theta);
Ok(free_node_ids)
}
pub fn select_mesh_nodes_inside(
&self,
target_mesh_nodes: &[[f64; 3]],
) -> Result<Vec<usize>> {
Ok(select_nodes_in_box(
target_mesh_nodes,
self.length,
self.centre,
self.theta,
))
}
pub fn transform_subset(
&self,
node_ids: &[usize],
transform_matrix: &[[f64; 4]; 4],
pivot: &[f64; 3],
) -> Vec<[f64; 3]> {
transform_selected_nodes(&self.nodes, node_ids, transform_matrix, pivot)
}
}
pub fn evaluate_lcs_from_components(
length: [f64; 3],
centre: [f64; 3],
theta: [f64; 3],
) -> [[f64; 3]; 4] {
let origin = [
0.5 * length[0] - centre[0],
0.5 * length[1] - centre[1],
0.5 * length[2] - centre[2],
];
let mut local_coordinate_system = [
[centre[0], centre[1], centre[2]],
[centre[0] + length[0], centre[1], centre[2]],
[centre[0], centre[1] + length[1], centre[2]],
[centre[0], centre[1], centre[2] + length[2]],
];
rotate_nodes(&mut local_coordinate_system, &theta, &origin);
local_coordinate_system
}