1use crate::core::{
2 clusters::generate_block_cluster,
3 mesh::Mesh,
4 selection::select_nodes_in_box,
5 transformation::{
6 build_rotation_matrix, rotate_node, rotate_nodes, transform_selected_nodes,
7 },
8};
9
10use crate::error::{Error, Result};
11
12#[derive(Debug, Clone)]
24pub struct DesignBlock {
25 pub nodes: Vec<[f64; 3]>,
26 pub length: [f64; 3],
27 pub centre: [f64; 3],
28 pub theta: [f64; 3],
29 pub resolution: [usize; 3],
30 pub corner_nodes: [[f64; 3]; 8],
31 pub scaling_factors: [f64; 3],
32 pub local_coordinate_system: [[f64; 3]; 4],
33}
34
35impl DesignBlock {
36 pub fn new(
47 length: [f64; 3],
48 centre: [f64; 3],
49 theta: [f64; 3],
50 resolution: [usize; 3],
51 ) -> Result<Self> {
52 let nodes = generate_block_cluster(length, centre, theta, resolution)?;
53
54 let scaling_factors = [1. / length[0], 1. / length[1], 1. / length[2]];
56
57 let [cx, cy, cz] = centre;
59 let [lx, ly, lz] = length;
60
61 let half_lx = lx / 2.0;
62 let half_ly = ly / 2.0;
63 let half_lz = lz / 2.0;
64
65 let mut corner_nodes = [
66 [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], ];
75
76 rotate_nodes(&mut corner_nodes, &theta, ¢re);
77
78 let local_coordinate_system = [
79 corner_nodes[0],
80 corner_nodes[1],
81 corner_nodes[2],
82 corner_nodes[4],
83 ];
84
85 let updated_coordinate_system: [[f64; 3]; 4] = {
86 let mut result = [[0.0; 3]; 4];
87 for (i, &node) in local_coordinate_system.iter().enumerate() {
88 result[i] = [
89 node[0] - corner_nodes[0][0],
90 node[1] - corner_nodes[0][1],
91 node[2] - corner_nodes[0][2],
92 ];
93 }
94 result
95 };
96
97 Ok(DesignBlock {
98 nodes,
99 length,
100 centre,
101 theta,
102 resolution,
103 corner_nodes,
104 scaling_factors,
105 local_coordinate_system: updated_coordinate_system,
106 })
107 }
108
109 pub fn select_free_design_nodes(
118 &self,
119 target_mesh: &Mesh,
120 fixed_layers: Option<usize>,
121 ) -> Result<Vec<usize>> {
122 let fixed_layers = fixed_layers.unwrap_or(2);
123
124 if self.resolution.iter().any(|&res| res < fixed_layers) {
125 return Err(Error::Deformation(
126 "Block resultion must be at least the size of the fixed layers!"
127 .to_string(),
128 ));
129 }
130
131 let corner = self.corner_nodes;
133
134 let sides = [
135 [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]], ];
142
143 let mut fixed_sides: Vec<usize> = Vec::new();
144 for (i, side) in sides.iter().enumerate() {
145 let a = [
146 side[1][0] - side[0][0],
147 side[1][1] - side[0][1],
148 side[1][2] - side[0][2],
149 ];
150 let b = [
151 side[2][0] - side[0][0],
152 side[2][1] - side[0][1],
153 side[2][2] - side[0][2],
154 ];
155
156 let normal = [
157 a[1] * b[2] - a[2] * b[1],
158 a[2] * b[0] - a[0] * b[2],
159 a[0] * b[1] - a[1] * b[0],
160 ];
161
162 let mut centre = [0.0; 3];
163 for point in side.iter() {
164 centre[0] += point[0];
165 centre[1] += point[1];
166 centre[2] += point[2];
167 }
168 centre[0] /= 4.0;
169 centre[1] /= 4.0;
170 centre[2] /= 4.0;
171
172 if target_mesh.slice(centre, normal).is_some() {
174 fixed_sides.push(i)
175 }
176 }
177
178 let mut new_length = self.length;
180 let mut new_centre = self.centre;
181
182 let step = [
183 self.length[0] / (self.resolution[0] as f64),
184 self.length[1] / (self.resolution[1] as f64),
185 self.length[2] / (self.resolution[2] as f64),
186 ];
187
188 let correction_factor = 0.01;
189 let correction = [
190 step[0] * (fixed_layers - 1) as f64 + correction_factor * step[0],
191 step[1] * (fixed_layers - 1) as f64 + correction_factor * step[1],
192 step[2] * (fixed_layers - 1) as f64 + correction_factor * step[2],
193 ];
194
195 if fixed_sides.contains(&4) {
197 new_length[0] -= correction[0];
198 new_centre[0] += 0.5 * correction[0];
199 }
200 if fixed_sides.contains(&5) {
202 new_length[0] -= correction[0];
203 new_centre[0] -= 0.5 * correction[0];
204 }
205
206 if fixed_sides.contains(&2) {
208 new_length[1] -= correction[1];
209 new_centre[1] += 0.5 * correction[1];
210 }
211 if fixed_sides.contains(&3) {
213 new_length[1] -= correction[1];
214 new_centre[1] -= 0.5 * correction[1];
215 }
216 if fixed_sides.contains(&0) {
218 new_length[2] -= correction[2];
219 new_centre[2] += 0.5 * correction[2];
220 }
221 if fixed_sides.contains(&1) {
223 new_length[2] -= correction[2];
224 new_centre[2] -= 0.5 * correction[2];
225 }
226
227 new_length[0] += 0.1 * correction_factor * step[0];
228 new_length[1] += 0.1 * correction_factor * step[1];
229 new_length[2] += 0.1 * correction_factor * step[2];
230
231 let rotation_matrix = build_rotation_matrix(&self.theta);
232 rotate_node(&mut new_centre, &rotation_matrix, &self.centre);
233
234 let free_node_ids =
235 select_nodes_in_box(&self.nodes, new_length, new_centre, self.theta);
236
237 Ok(free_node_ids)
238 }
239
240 pub fn select_mesh_nodes_inside(
248 &self,
249 target_mesh_nodes: &[[f64; 3]],
250 ) -> Result<Vec<usize>> {
251 Ok(select_nodes_in_box(
252 target_mesh_nodes,
253 self.length,
254 self.centre,
255 self.theta,
256 ))
257 }
258
259 pub fn transform_subset(
269 &self,
270 node_ids: &[usize],
271 transform_matrix: &[[f64; 4]; 4],
272 pivot: &[f64; 3],
273 ) -> Vec<[f64; 3]> {
274 transform_selected_nodes(&self.nodes, node_ids, transform_matrix, pivot)
275 }
276}
277
278pub fn evaluate_lcs_from_components(
296 length: [f64; 3],
297 centre: [f64; 3],
298 theta: [f64; 3],
299) -> [[f64; 3]; 4] {
300 let origin = [
301 0.5 * length[0] - centre[0],
302 0.5 * length[1] - centre[1],
303 0.5 * length[2] - centre[2],
304 ];
305 let mut local_coordinate_system = [
306 [centre[0], centre[1], centre[2]],
307 [centre[0] + length[0], centre[1], centre[2]],
308 [centre[0], centre[1] + length[1], centre[2]],
309 [centre[0], centre[1], centre[2] + length[2]],
310 ];
311
312 rotate_nodes(&mut local_coordinate_system, &theta, &origin);
313
314 local_coordinate_system
315}