1use crate::types::ARdouble;
41use log::{debug, error};
42
43#[derive(Debug, Default, Clone, Copy, PartialEq)]
45#[repr(C)]
46pub struct ICP2DCoordT {
47 pub x: ARdouble,
48 pub y: ARdouble,
49}
50
51#[derive(Debug, Default, Clone, Copy, PartialEq)]
53#[repr(C)]
54pub struct ICP3DCoordT {
55 pub x: ARdouble,
56 pub y: ARdouble,
57 pub z: ARdouble,
58}
59
60#[derive(Debug, Default, Clone, Copy, PartialEq)]
62#[repr(C)]
63pub struct ICP2DLineT {
64 pub a: ARdouble,
65 pub b: ARdouble,
66 pub c: ARdouble,
67}
68
69#[derive(Debug, Default, Clone, Copy, PartialEq)]
71#[repr(C)]
72pub struct ICP2DLineSegT {
73 pub p1: ICP2DCoordT,
74 pub p2: ICP2DCoordT,
75}
76
77#[derive(Debug, Default, Clone, Copy, PartialEq)]
79#[repr(C)]
80pub struct ICP3DLineSegT {
81 pub p1: ICP3DCoordT,
82 pub p2: ICP3DCoordT,
83}
84
85#[derive(Debug, Clone, PartialEq)]
87pub struct ICPDataT {
88 pub screen_coord: Vec<ICP2DCoordT>,
89 pub world_coord: Vec<ICP3DCoordT>,
90}
91
92impl Default for ICPDataT {
93 fn default() -> Self {
94 Self {
95 screen_coord: Vec::new(),
96 world_coord: Vec::new(),
97 }
98 }
99}
100
101#[derive(Debug, Clone, PartialEq)]
103pub struct ICPStereoDataT {
104 pub screen_coord_l: Vec<ICP2DCoordT>,
105 pub world_coord_l: Vec<ICP3DCoordT>,
106 pub screen_coord_r: Vec<ICP2DCoordT>,
107 pub world_coord_r: Vec<ICP3DCoordT>,
108}
109
110impl Default for ICPStereoDataT {
111 fn default() -> Self {
112 Self {
113 screen_coord_l: Vec::new(),
114 world_coord_l: Vec::new(),
115 screen_coord_r: Vec::new(),
116 world_coord_r: Vec::new(),
117 }
118 }
119}
120
121#[derive(Debug, Clone, PartialEq)]
123#[repr(C)]
124pub struct ICPHandleT {
125 pub mat_xc2u: [[ARdouble; 4]; 3],
126 pub max_loop: i32,
127 pub break_loop_error_thresh: ARdouble,
128 pub break_loop_error_ratio_thresh: ARdouble,
129 pub break_loop_error_thresh2: ARdouble,
130 pub inlier_prob: ARdouble,
131}
132
133impl Default for ICPHandleT {
134 fn default() -> Self {
135 Self {
136 mat_xc2u: [[0.0; 4]; 3],
137 max_loop: 10,
138 break_loop_error_thresh: 0.1,
139 break_loop_error_ratio_thresh: 0.99,
140 break_loop_error_thresh2: 4.0,
141 inlier_prob: 0.50,
142 }
143 }
144}
145
146pub fn icp_set_inlier_probability(handle: &mut ICPHandleT, prob: f64) {
147 handle.inlier_prob = prob;
148}
149
150#[derive(Debug, Clone, PartialEq)]
152#[repr(C)]
153pub struct ICPStereoHandleT {
154 pub mat_xcl2ul: [[ARdouble; 4]; 3],
155 pub mat_xcr2ur: [[ARdouble; 4]; 3],
156 pub mat_c2l: [[ARdouble; 4]; 3],
157 pub mat_c2r: [[ARdouble; 4]; 3],
158 pub max_loop: i32,
159 pub break_loop_error_thresh: ARdouble,
160 pub break_loop_error_ratio_thresh: ARdouble,
161 pub break_loop_error_thresh2: ARdouble,
162 pub inlier_prob: ARdouble,
163}
164
165impl Default for ICPStereoHandleT {
166 fn default() -> Self {
167 Self {
168 mat_xcl2ul: [[0.0; 4]; 3],
169 mat_xcr2ur: [[0.0; 4]; 3],
170 mat_c2l: [[0.0; 4]; 3],
171 mat_c2r: [[0.0; 4]; 3],
172 max_loop: 10,
173 break_loop_error_thresh: 0.1,
174 break_loop_error_ratio_thresh: 0.99,
175 break_loop_error_thresh2: 4.0,
176 inlier_prob: 0.50,
177 }
178 }
179}
180
181use crate::math::ARMat;
182
183pub fn icp_mat_mul(m1: &[[ARdouble; 4]; 3], m2: &[[ARdouble; 4]; 3], dest: &mut [[ARdouble; 4]; 3]) {
184 for r in 0..3 {
185 for c in 0..4 {
186 dest[r][c] = m1[r][0] * m2[0][c]
187 + m1[r][1] * m2[1][c]
188 + m1[r][2] * m2[2][c];
189 if c == 3 {
190 dest[r][c] += m1[r][3];
191 }
192 }
193 }
194}
195
196pub fn icp_point(
197 handle: &ICPHandleT,
198 data: &ICPDataT,
199 init_mat_xw2xc: &[[ARdouble; 4]; 3],
200 mat_xw2xc: &mut [[ARdouble; 4]; 3],
201) -> Result<ARdouble, &'static str> {
202 if data.screen_coord.len() < 3 || data.world_coord.len() < 3 {
203 debug!("ICP Point: Not enough points");
204 return Err("Not enough points for ICP");
205 }
206
207 let num_points = data.screen_coord.len();
208 let mut j_u_s_table = vec![[0.0; 6]; num_points * 2];
209 let mut du = vec![0.0; num_points * 2];
210 let mut mat_xw2u = [[0.0; 4]; 3];
211 let mut ds = [0.0; 6];
212 let mut err0 = 0.0;
213 #[allow(unused_assignments)]
214 let mut err1 = 0.0;
215
216 for j in 0..3 {
217 for i in 0..4 {
218 mat_xw2xc[j][i] = init_mat_xw2xc[j][i];
219 }
220 }
221
222 let mut loop_idx = 0;
223 loop {
224 icp_mat_mul(&handle.mat_xc2u, mat_xw2xc, &mut mat_xw2u);
225
226 err1 = 0.0;
227 let mut u = ICP2DCoordT::default();
228 for j in 0..num_points {
229 icp_get_u_from_x_by_mat_x2u(&mut u, &mat_xw2u, &data.world_coord[j])?;
230 let dx = data.screen_coord[j].x - u.x;
231 let dy = data.screen_coord[j].y - u.y;
232 err1 += dx * dx + dy * dy;
233 du[j * 2 + 0] = dx;
234 du[j * 2 + 1] = dy;
235 }
236 err1 /= num_points as ARdouble;
237
238 if err1 < handle.break_loop_error_thresh {
241 break;
243 }
244 if loop_idx > 0 && err1 < handle.break_loop_error_thresh2 && (err1 / err0) > handle.break_loop_error_ratio_thresh {
245 break;
247 }
248 if loop_idx == handle.max_loop {
249 break;
251 }
252 err0 = err1;
253
254 for j in 0..num_points {
255 let mut j_u_s_local = [[0.0; 6]; 2];
256 icp_get_j_u_s(&mut j_u_s_local, &handle.mat_xc2u, mat_xw2xc, &data.world_coord[j])?;
257 for r in 0..2 {
258 for c in 0..6 {
259 j_u_s_table[j * 2 + r][c] = j_u_s_local[r][c];
260 }
261 }
262 }
263
264 if let Err(e) = icp_get_delta_s(&mut ds, &du, &j_u_s_table, num_points * 2) {
265 error!("ICP Point: icp_get_delta_s failed: {}", e);
266 return Err(e);
267 }
268 icp_update_mat(mat_xw2xc, &ds);
269
270 loop_idx += 1;
271 }
272
273 Ok(err1)
274}
275
276pub fn icp_point_robust(
277 handle: &ICPHandleT,
278 data: &ICPDataT,
279 init_mat_xw2xc: &[[ARdouble; 4]; 3],
280 mat_xw2xc: &mut [[ARdouble; 4]; 3],
281) -> Result<ARdouble, &'static str> {
282 icp_point(handle, data, init_mat_xw2xc, mat_xw2xc)
288}
289
290pub fn icp_get_xc_from_xw_by_mat_xw2xc(xc: &mut ICP3DCoordT, mat_xw2xc: &[[ARdouble; 4]; 3], xw: &ICP3DCoordT) {
291 xc.x = mat_xw2xc[0][0] * xw.x + mat_xw2xc[0][1] * xw.y + mat_xw2xc[0][2] * xw.z + mat_xw2xc[0][3];
292 xc.y = mat_xw2xc[1][0] * xw.x + mat_xw2xc[1][1] * xw.y + mat_xw2xc[1][2] * xw.z + mat_xw2xc[1][3];
293 xc.z = mat_xw2xc[2][0] * xw.x + mat_xw2xc[2][1] * xw.y + mat_xw2xc[2][2] * xw.z + mat_xw2xc[2][3];
294}
295
296pub fn icp_get_u_from_x_by_mat_x2u(u: &mut ICP2DCoordT, mat_x2u: &[[ARdouble; 4]; 3], coord3d: &ICP3DCoordT) -> Result<(), &'static str> {
297 let hx = mat_x2u[0][0] * coord3d.x + mat_x2u[0][1] * coord3d.y + mat_x2u[0][2] * coord3d.z + mat_x2u[0][3];
298 let hy = mat_x2u[1][0] * coord3d.x + mat_x2u[1][1] * coord3d.y + mat_x2u[1][2] * coord3d.z + mat_x2u[1][3];
299 let h = mat_x2u[2][0] * coord3d.x + mat_x2u[2][1] * coord3d.y + mat_x2u[2][2] * coord3d.z + mat_x2u[2][3];
300
301 if h == 0.0 {
302 return Err("Division by zero in icp_get_u_from_x_by_mat_x2u");
303 }
304
305 u.x = hx / h;
306 u.y = hy / h;
307 Ok(())
308}
309
310fn icp_get_j_u_xc(j_u_xc: &mut [[ARdouble; 3]; 2], mat_xc2u: &[[ARdouble; 4]; 3], camera_coord: &ICP3DCoordT) -> Result<(), &'static str> {
311 let w1 = mat_xc2u[0][0] * camera_coord.x + mat_xc2u[0][1] * camera_coord.y + mat_xc2u[0][2] * camera_coord.z + mat_xc2u[0][3];
312 let w2 = mat_xc2u[1][0] * camera_coord.x + mat_xc2u[1][1] * camera_coord.y + mat_xc2u[1][2] * camera_coord.z + mat_xc2u[1][3];
313 let w3 = mat_xc2u[2][0] * camera_coord.x + mat_xc2u[2][1] * camera_coord.y + mat_xc2u[2][2] * camera_coord.z + mat_xc2u[2][3];
314
315 if w3 == 0.0 { return Err("Division by zero in icp_get_j_u_xc"); }
316
317 let w3_w3 = w3 * w3;
318 j_u_xc[0][0] = (mat_xc2u[0][0] * w3 - mat_xc2u[2][0] * w1) / w3_w3;
319 j_u_xc[0][1] = (mat_xc2u[0][1] * w3 - mat_xc2u[2][1] * w1) / w3_w3;
320 j_u_xc[0][2] = (mat_xc2u[0][2] * w3 - mat_xc2u[2][2] * w1) / w3_w3;
321 j_u_xc[1][0] = (mat_xc2u[1][0] * w3 - mat_xc2u[2][0] * w2) / w3_w3;
322 j_u_xc[1][1] = (mat_xc2u[1][1] * w3 - mat_xc2u[2][1] * w2) / w3_w3;
323 j_u_xc[1][2] = (mat_xc2u[1][2] * w3 - mat_xc2u[2][2] * w2) / w3_w3;
324
325 Ok(())
326}
327
328fn icp_get_j_t_s(j_t_s: &mut [[ARdouble; 6]; 12]) {
329 for i in 0..12 {
330 for j in 0..6 { j_t_s[i][j] = 0.0; }
331 }
332 j_t_s[1][2] = -1.0;
333 j_t_s[2][1] = 1.0;
334 j_t_s[3][2] = 1.0;
335 j_t_s[5][0] = -1.0;
336 j_t_s[6][1] = -1.0;
337 j_t_s[7][0] = 1.0;
338 j_t_s[9][3] = 1.0;
339 j_t_s[10][4] = 1.0;
340 j_t_s[11][5] = 1.0;
341}
342
343fn icp_get_j_xc_s(j_xc_s: &mut [[ARdouble; 6]; 3], camera_coord: &mut ICP3DCoordT, t0: &[[ARdouble; 4]; 3], world_coord: &ICP3DCoordT) {
344 let mut j_xc_t = [[0.0; 12]; 3];
345
346 camera_coord.x = t0[0][0]*world_coord.x + t0[0][1]*world_coord.y + t0[0][2]*world_coord.z + t0[0][3];
347 camera_coord.y = t0[1][0]*world_coord.x + t0[1][1]*world_coord.y + t0[1][2]*world_coord.z + t0[1][3];
348 camera_coord.z = t0[2][0]*world_coord.x + t0[2][1]*world_coord.y + t0[2][2]*world_coord.z + t0[2][3];
349
350 for j in 0..3 {
351 j_xc_t[j][0] = t0[j][0] * world_coord.x;
352 j_xc_t[j][1] = t0[j][0] * world_coord.y;
353 j_xc_t[j][2] = t0[j][0] * world_coord.z;
354 j_xc_t[j][3] = t0[j][1] * world_coord.x;
355 j_xc_t[j][4] = t0[j][1] * world_coord.y;
356 j_xc_t[j][5] = t0[j][1] * world_coord.z;
357 j_xc_t[j][6] = t0[j][2] * world_coord.x;
358 j_xc_t[j][7] = t0[j][2] * world_coord.y;
359 j_xc_t[j][8] = t0[j][2] * world_coord.z;
360 j_xc_t[j][9] = t0[j][0];
361 j_xc_t[j][10] = t0[j][1];
362 j_xc_t[j][11] = t0[j][2];
363 }
364
365 let mut j_t_s = [[0.0; 6]; 12];
366 icp_get_j_t_s(&mut j_t_s);
367
368 for j in 0..3 {
369 for i in 0..6 {
370 j_xc_s[j][i] = 0.0;
371 for k in 0..12 {
372 j_xc_s[j][i] += j_xc_t[j][k] * j_t_s[k][i];
373 }
374 }
375 }
376}
377
378pub fn icp_get_j_u_s(j_u_s: &mut [[ARdouble; 6]; 2], mat_xc2u: &[[ARdouble; 4]; 3], mat_xw2xc: &[[ARdouble; 4]; 3], world_coord: &ICP3DCoordT) -> Result<(), &'static str> {
379 let mut j_xc_s = [[0.0; 6]; 3];
380 let mut j_u_xc = [[0.0; 3]; 2];
381 let mut xc = ICP3DCoordT::default();
382
383 icp_get_j_xc_s(&mut j_xc_s, &mut xc, mat_xw2xc, world_coord);
384 icp_get_j_u_xc(&mut j_u_xc, mat_xc2u, &xc)?;
385
386 for j in 0..2 {
387 for i in 0..6 {
388 j_u_s[j][i] = 0.0;
389 for k in 0..3 {
390 j_u_s[j][i] += j_u_xc[j][k] * j_xc_s[k][i];
391 }
392 }
393 }
394 Ok(())
395}
396
397fn icp_get_q_from_s(q: &mut [ARdouble; 7], s: &[ARdouble; 6]) {
398 let mut ra = s[0]*s[0] + s[1]*s[1] + s[2]*s[2];
399 if ra == 0.0 {
400 q[0] = 1.0;
401 q[1] = 0.0;
402 q[2] = 0.0;
403 q[3] = 0.0;
404 } else {
405 ra = ra.sqrt();
406 q[0] = s[0] / ra;
407 q[1] = s[1] / ra;
408 q[2] = s[2] / ra;
409 q[3] = ra;
410 }
411 q[4] = s[3];
412 q[5] = s[4];
413 q[6] = s[5];
414}
415
416fn icp_get_mat_from_q(mat: &mut [[ARdouble; 4]; 3], q: &[ARdouble; 7]) {
417 let cra = q[3].cos();
418 let one_cra = 1.0 - cra;
419 let sra = q[3].sin();
420
421 mat[0][0] = q[0]*q[0]*one_cra + cra;
422 mat[0][1] = q[0]*q[1]*one_cra - q[2]*sra;
423 mat[0][2] = q[0]*q[2]*one_cra + q[1]*sra;
424 mat[0][3] = q[4];
425
426 mat[1][0] = q[1]*q[0]*one_cra + q[2]*sra;
427 mat[1][1] = q[1]*q[1]*one_cra + cra;
428 mat[1][2] = q[1]*q[2]*one_cra - q[0]*sra;
429 mat[1][3] = q[5];
430
431 mat[2][0] = q[2]*q[0]*one_cra - q[1]*sra;
432 mat[2][1] = q[2]*q[1]*one_cra + q[0]*sra;
433 mat[2][2] = q[2]*q[2]*one_cra + cra;
434 mat[2][3] = q[6];
435}
436
437pub fn icp_update_mat(mat_xw2xc: &mut [[ARdouble; 4]; 3], ds: &[ARdouble; 6]) {
438 let mut q = [0.0; 7];
439 let mut mat = [[0.0; 4]; 3];
440 let mut mat2 = [[0.0; 4]; 3];
441
442 icp_get_q_from_s(&mut q, ds);
443 icp_get_mat_from_q(&mut mat, &q);
444
445 for j in 0..3 {
446 for i in 0..4 {
447 mat2[j][i] = mat_xw2xc[j][0] * mat[0][i]
448 + mat_xw2xc[j][1] * mat[1][i]
449 + mat_xw2xc[j][2] * mat[2][i];
450 }
451 mat2[j][3] += mat_xw2xc[j][3];
452 }
453
454 for j in 0..3 {
455 for i in 0..4 {
456 mat_xw2xc[j][i] = mat2[j][i];
457 }
458 }
459}
460
461pub fn icp_get_delta_s(s: &mut [ARdouble; 6], du: &[ARdouble], j_u_s: &[[ARdouble; 6]], n: usize) -> Result<(), &'static str> {
462 let mut mat_u = ARMat::new(n as i32, 1);
463 mat_u.m.copy_from_slice(du);
464
465 let mut mat_j = ARMat::new(n as i32, 6);
466 for r in 0..n {
467 for c in 0..6 {
468 mat_j.m[r * 6 + c] = j_u_s[r][c];
469 }
470 }
471
472 let mat_jt = mat_j.transpose();
473
474 let mut mat_jt_j = (&mat_jt * &mat_j)?;
475 let mat_jt_u = (&mat_jt * &mat_u)?;
476
477 if let Err(e) = mat_jt_j.self_inv() {
478 return Err(e);
479 }
480
481 let mat_s = (&mat_jt_j * &mat_jt_u)?;
482
483 for i in 0..6 {
484 s[i] = mat_s.m[i];
485 }
486
487 Ok(())
488}
489
490pub fn icp_create_handle(mat_xc2u: &[[ARdouble; 4]; 3]) -> Result<*mut ICPHandleT, &'static str> {
491 let mut handle = Box::new(ICPHandleT::default());
492 for j in 0..3 {
493 for i in 0..4 {
494 handle.mat_xc2u[j][i] = mat_xc2u[j][i];
495 }
496 }
497 Ok(Box::into_raw(handle))
498}
499
500pub fn icp_delete_handle(handle: &mut *mut ICPHandleT) -> Result<(), &'static str> {
501 if handle.is_null() {
502 return Err("Null handle");
503 }
504 unsafe {
505 drop(Box::from_raw(*handle));
506 }
507 *handle = std::ptr::null_mut();
508 Ok(())
509}
510
511#[allow(dead_code)]
512fn check_rotation(rot: &mut [[ARdouble; 3]; 3]) -> Result<(), &'static str> {
513 let v1 = [rot[0][0], rot[0][1], rot[0][2]];
514 let v2 = [rot[1][0], rot[1][1], rot[1][2]];
515 let mut v3 = [
516 v1[1] * v2[2] - v1[2] * v2[1],
517 v1[2] * v2[0] - v1[0] * v2[2],
518 v1[0] * v2[1] - v1[1] * v2[0],
519 ];
520 let w = (v3[0]*v3[0] + v3[1]*v3[1] + v3[2]*v3[2]).sqrt();
521 if w == 0.0 { return Err("Collinear vectors in check_rotation"); }
522 v3[0] /= w; v3[1] /= w; v3[2] /= w;
523
524 let mut cb = v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
525 if cb < 0.0 { cb = -cb; }
526 let ca = ((cb + 1.0).sqrt() + (1.0 - cb).sqrt()) * 0.5;
527
528 let mut rot_flag: i32;
529 if v3[1] * v1[0] - v1[1] * v3[0] != 0.0 {
530 rot_flag = 0;
531 } else {
532 if v3[2] * v1[0] - v1[2] * v3[0] != 0.0 {
533 rot_flag = 1;
534 } else {
535 rot_flag = 2;
536 }
537 }
538
539 let mut v1_temp = v1; let mut v3_temp = v3;
541
542 if rot_flag == 1 {
543 v1_temp.swap(1, 2);
544 v3_temp.swap(1, 2);
545 } else if rot_flag == 2 {
546 v1_temp.swap(0, 2);
547 v3_temp.swap(0, 2);
548 }
549
550 let denom1 = v3_temp[1] * v1_temp[0] - v1_temp[1] * v3_temp[0];
551 if denom1 == 0.0 { return Err("check_rotation denom1 is 0"); }
552 let k1 = (v1_temp[1]*v3_temp[2] - v3_temp[1]*v1_temp[2]) / denom1;
553 let k2 = (v3_temp[1] * ca) / denom1;
554
555 let denom2 = v3_temp[0] * v1_temp[1] - v1_temp[0] * v3_temp[1];
556 if denom2 == 0.0 { return Err("check_rotation denom2 is 0"); }
557 let k3 = (v1_temp[0]*v3_temp[2] - v3_temp[0]*v1_temp[2]) / denom2;
558 let k4 = (v3_temp[0] * ca) / denom2;
559
560 let a = k1*k1 + k3*k3 + 1.0;
561 let b = k1*k2 + k3*k4;
562 let c = k2*k2 + k4*k4 - 1.0;
563
564 let d = b*b - a*c;
565 if d < 0.0 { return Err("check_rotation complex roots"); }
566
567 let mut r1 = (-b + d.sqrt()) / a;
568 let mut p1 = k1*r1 + k2;
569 let mut q1 = k3*r1 + k4;
570 let mut r2 = (-b - d.sqrt()) / a;
571 let mut p2 = k1*r2 + k2;
572 let mut q2 = k3*r2 + k4;
573
574 if rot_flag == 1 {
575 std::mem::swap(&mut q1, &mut r1);
576 std::mem::swap(&mut q2, &mut r2);
577 } else if rot_flag == 2 {
578 std::mem::swap(&mut p1, &mut r1);
579 std::mem::swap(&mut p2, &mut r2);
580 }
581
582 if v3[1] * v2[0] - v2[1] * v3[0] != 0.0 {
583 rot_flag = 0;
584 } else {
585 if v3[2] * v2[0] - v2[2] * v3[0] != 0.0 {
586 rot_flag = 1;
587 } else {
588 rot_flag = 2;
589 }
590 }
591
592 let mut v2_temp = v2; v3_temp = v3; if rot_flag == 1 {
596 v2_temp.swap(1, 2);
597 v3_temp.swap(1, 2);
598 } else if rot_flag == 2 {
599 v2_temp.swap(0, 2);
600 v3_temp.swap(0, 2);
601 }
602
603 let denom3 = v3_temp[1] * v2_temp[0] - v2_temp[1] * v3_temp[0];
604 if denom3 == 0.0 { return Err("check_rotation denom3 is 0"); }
605 let k1_2 = (v2_temp[1]*v3_temp[2] - v3_temp[1]*v2_temp[2]) / denom3;
606 let k2_2 = (v3_temp[1] * ca) / denom3;
607
608 let denom4 = v3_temp[0] * v2_temp[1] - v2_temp[0] * v3_temp[1];
609 if denom4 == 0.0 { return Err("check_rotation denom4 is 0"); }
610 let k3_2 = (v2_temp[0]*v3_temp[2] - v3_temp[0]*v2_temp[2]) / denom4;
611 let k4_2 = (v3_temp[0] * ca) / denom4;
612
613 let a_2 = k1_2*k1_2 + k3_2*k3_2 + 1.0;
614 let b_2 = k1_2*k2_2 + k3_2*k4_2;
615 let c_2 = k2_2*k2_2 + k4_2*k4_2 - 1.0;
616
617 let d_2 = b_2*b_2 - a_2*c_2;
618 if d_2 < 0.0 { return Err("check_rotation complex roots 2"); }
619
620 let mut r3 = (-b_2 + d_2.sqrt()) / a_2;
621 let mut p3 = k1_2*r3 + k2_2;
622 let mut q3 = k3_2*r3 + k4_2;
623 let mut r4 = (-b_2 - d_2.sqrt()) / a_2;
624 let mut p4 = k1_2*r4 + k2_2;
625 let mut q4 = k3_2*r4 + k4_2;
626
627 if rot_flag == 1 {
628 std::mem::swap(&mut q3, &mut r3);
629 std::mem::swap(&mut q4, &mut r4);
630 } else if rot_flag == 2 {
631 std::mem::swap(&mut p3, &mut r3);
632 std::mem::swap(&mut p4, &mut r4);
633 }
634
635 let e1 = (p1*p3 + q1*q3 + r1*r3).abs();
636 let e2 = (p1*p4 + q1*q4 + r1*r4).abs();
637 let e3 = (p2*p3 + q2*q3 + r2*r3).abs();
638 let e4 = (p2*p4 + q2*q4 + r2*r4).abs();
639
640 if e1 < e2 {
641 if e1 < e3 {
642 if e1 < e4 {
643 rot[0][0] = p1; rot[0][1] = q1; rot[0][2] = r1;
644 rot[1][0] = p3; rot[1][1] = q3; rot[1][2] = r3;
645 } else {
646 rot[0][0] = p2; rot[0][1] = q2; rot[0][2] = r2;
647 rot[1][0] = p4; rot[1][1] = q4; rot[1][2] = r4;
648 }
649 } else {
650 if e3 < e4 {
651 rot[0][0] = p2; rot[0][1] = q2; rot[0][2] = r2;
652 rot[1][0] = p3; rot[1][1] = q3; rot[1][2] = r3;
653 } else {
654 rot[0][0] = p2; rot[0][1] = q2; rot[0][2] = r2;
655 rot[1][0] = p4; rot[1][1] = q4; rot[1][2] = r4;
656 }
657 }
658 } else {
659 if e2 < e3 {
660 if e2 < e4 {
661 rot[0][0] = p1; rot[0][1] = q1; rot[0][2] = r1;
662 rot[1][0] = p4; rot[1][1] = q4; rot[1][2] = r4;
663 } else {
664 rot[0][0] = p2; rot[0][1] = q2; rot[0][2] = r2;
665 rot[1][0] = p4; rot[1][1] = q4; rot[1][2] = r4;
666 }
667 } else {
668 if e3 < e4 {
669 rot[0][0] = p2; rot[0][1] = q2; rot[0][2] = r2;
670 rot[1][0] = p3; rot[1][1] = q3; rot[1][2] = r3;
671 } else {
672 rot[0][0] = p2; rot[0][1] = q2; rot[0][2] = r2;
673 rot[1][0] = p4; rot[1][1] = q4; rot[1][2] = r4;
674 }
675 }
676 }
677
678 Ok(())
679}
680
681pub fn icp_get_init_xw2xc_from_planar_data(
682 mat_xc2u: &[[ARdouble; 4]; 3],
683 screen_coord: &[ICP2DCoordT],
684 world_coord: &[ICP3DCoordT],
685 num: usize,
686 init_mat_xw2xc: &mut [[ARdouble; 4]; 3]
687) -> Result<(), &'static str> {
688 if num < 4 { return Err("Needs at least 4 points"); }
689 for i in 0..num {
690 if world_coord[i].z != 0.0 { return Err("Points must be planar (Z=0)"); }
691 }
692 if mat_xc2u[0][0] == 0.0 { return Err("mat_xc2u[0][0] is zero"); }
693 if mat_xc2u[1][0] != 0.0 { return Err("mat_xc2u[1][0] is not zero"); }
694 if mat_xc2u[1][1] == 0.0 { return Err("mat_xc2u[1][1] is zero"); }
695 if mat_xc2u[2][0] != 0.0 || mat_xc2u[2][1] != 0.0 || mat_xc2u[2][2] != 1.0 {
696 return Err("mat_xc2u row 2 invalid");
697 }
698 if mat_xc2u[0][3] != 0.0 || mat_xc2u[1][3] != 0.0 || mat_xc2u[2][3] != 0.0 {
699 return Err("mat_xc2u translation column invalid");
700 }
701
702 let mut mat_a = ARMat::new(num as i32 * 2, 8);
703 let mut mat_b = ARMat::new(num as i32 * 2, 1);
704
705 for i in 0..num {
706 mat_a.m[i * 16 + 0] = world_coord[i].x;
707 mat_a.m[i * 16 + 1] = world_coord[i].y;
708 mat_a.m[i * 16 + 2] = 1.0;
709 mat_a.m[i * 16 + 3] = 0.0;
710 mat_a.m[i * 16 + 4] = 0.0;
711 mat_a.m[i * 16 + 5] = 0.0;
712 mat_a.m[i * 16 + 6] = -(world_coord[i].x) * (screen_coord[i].x);
713 mat_a.m[i * 16 + 7] = -(world_coord[i].y) * (screen_coord[i].x);
714
715 mat_a.m[i * 16 + 8] = 0.0;
716 mat_a.m[i * 16 + 9] = 0.0;
717 mat_a.m[i * 16 + 10] = 0.0;
718 mat_a.m[i * 16 + 11] = world_coord[i].x;
719 mat_a.m[i * 16 + 12] = world_coord[i].y;
720 mat_a.m[i * 16 + 13] = 1.0;
721 mat_a.m[i * 16 + 14] = -(world_coord[i].x) * (screen_coord[i].y);
722 mat_a.m[i * 16 + 15] = -(world_coord[i].y) * (screen_coord[i].y);
723
724 mat_b.m[i * 2 + 0] = screen_coord[i].x;
725 mat_b.m[i * 2 + 1] = screen_coord[i].y;
726 }
727
728 let mat_at = mat_a.transpose();
729 let mut mat_ata = (&mat_at * &mat_a)?;
730 let mat_atb = (&mat_at * &mat_b)?;
731
732 mat_ata.self_inv()?;
734 let mat_c = (&mat_ata * &mat_atb)?;
737 let mut v = [[0.0; 3]; 3];
740 let mut t = [0.0; 3];
741
742 v[0][2] = mat_c.m[6];
743 v[0][1] = (mat_c.m[3] - mat_xc2u[1][2] * v[0][2]) / mat_xc2u[1][1];
744 v[0][0] = (mat_c.m[0] - mat_xc2u[0][2] * v[0][2] - mat_xc2u[0][1] * v[0][1]) / mat_xc2u[0][0];
745
746 v[1][2] = mat_c.m[7];
747 v[1][1] = (mat_c.m[4] - mat_xc2u[1][2] * v[1][2]) / mat_xc2u[1][1];
748 v[1][0] = (mat_c.m[1] - mat_xc2u[0][2] * v[1][2] - mat_xc2u[0][1] * v[1][1]) / mat_xc2u[0][0];
749
750 t[2] = 1.0;
751 t[1] = (mat_c.m[5] - mat_xc2u[1][2] * t[2]) / mat_xc2u[1][1];
752 t[0] = (mat_c.m[2] - mat_xc2u[0][2] * t[2] - mat_xc2u[0][1] * t[1]) / mat_xc2u[0][0];
753
754 let mut l1 = (v[0][0]*v[0][0] + v[0][1]*v[0][1] + v[0][2]*v[0][2]).sqrt();
755 let l2 = (v[1][0]*v[1][0] + v[1][1]*v[1][1] + v[1][2]*v[1][2]).sqrt();
756
757 v[0][0] /= l1;
758 v[0][1] /= l1;
759 v[0][2] /= l1;
760
761 v[1][0] /= l2;
762 v[1][1] /= l2;
763 v[1][2] /= l2;
764
765 t[0] /= (l1+l2)/2.0;
766 t[1] /= (l1+l2)/2.0;
767 t[2] /= (l1+l2)/2.0;
768
769 if t[2] < 0.0 {
770 v[0][0] = -v[0][0]; v[0][1] = -v[0][1]; v[0][2] = -v[0][2];
771 v[1][0] = -v[1][0]; v[1][1] = -v[1][1]; v[1][2] = -v[1][2];
772 t[0] = -t[0]; t[1] = -t[1]; t[2] = -t[2];
773 }
774
775
776 v[2][0] = v[0][1] * v[1][2] - v[0][2] * v[1][1];
779 v[2][1] = v[0][2] * v[1][0] - v[0][0] * v[1][2];
780 v[2][2] = v[0][0] * v[1][1] - v[0][1] * v[1][0];
781
782 l1 = (v[2][0]*v[2][0] + v[2][1]*v[2][1] + v[2][2]*v[2][2]).sqrt();
783 v[2][0] /= l1;
784 v[2][1] /= l1;
785 v[2][2] /= l1;
786
787 init_mat_xw2xc[0][0] = v[0][0]; init_mat_xw2xc[1][0] = v[0][1]; init_mat_xw2xc[2][0] = v[0][2];
788 init_mat_xw2xc[0][1] = v[1][0]; init_mat_xw2xc[1][1] = v[1][1]; init_mat_xw2xc[2][1] = v[1][2];
789 init_mat_xw2xc[0][2] = v[2][0]; init_mat_xw2xc[1][2] = v[2][1]; init_mat_xw2xc[2][2] = v[2][2];
790 init_mat_xw2xc[0][3] = t[0]; init_mat_xw2xc[1][3] = t[1]; init_mat_xw2xc[2][3] = t[2];
791
792 Ok(())
793}
794
795#[cfg(test)]
796mod tests {
797 use super::*;
798
799 #[test]
800 fn test_icp_handle_default() {
801 let handle = ICPHandleT::default();
802 assert_eq!(handle.max_loop, 10);
803 assert_eq!(handle.break_loop_error_thresh, 0.1);
804 }
805
806 #[test]
807 fn test_icp_mat_mul() {
808 let m1 = [
809 [1.0, 2.0, 3.0, 4.0],
810 [5.0, 6.0, 7.0, 8.0],
811 [9.0, 10.0, 11.0, 12.0],
812 ];
813 let m2 = [
814 [2.0, 0.0, 0.0, 1.0],
815 [0.0, 2.0, 0.0, 2.0],
816 [0.0, 0.0, 2.0, 3.0],
817 ];
818 let mut dest = [[0.0; 4]; 3];
819 icp_mat_mul(&m1, &m2, &mut dest);
820
821 assert_eq!(dest[0][0], 2.0);
828 assert_eq!(dest[0][1], 4.0);
829 assert_eq!(dest[0][2], 6.0);
830 assert_eq!(dest[0][3], 18.0);
831 }
832
833 #[test]
834 fn test_icp_get_xc_from_xw() {
835 let mat = [
836 [1.0, 0.0, 0.0, 10.0],
837 [0.0, 1.0, 0.0, 20.0],
838 [0.0, 0.0, 1.0, 30.0],
839 ];
840 let xw = ICP3DCoordT { x: 5.0, y: 5.0, z: 5.0 };
841 let mut xc = ICP3DCoordT::default();
842
843 icp_get_xc_from_xw_by_mat_xw2xc(&mut xc, &mat, &xw);
844
845 assert_eq!(xc.x, 15.0);
846 assert_eq!(xc.y, 25.0);
847 assert_eq!(xc.z, 35.0);
848 }
849
850 #[test]
851 fn test_icp_get_u_from_x() {
852 let mat = [
853 [100.0, 0.0, 50.0, 0.0],
854 [0.0, 100.0, 50.0, 0.0],
855 [0.0, 0.0, 1.0, 0.0],
856 ];
857 let xc = ICP3DCoordT { x: 10.0, y: 20.0, z: 2.0 };
858 let mut u = ICP2DCoordT::default();
859
860 icp_get_u_from_x_by_mat_x2u(&mut u, &mat, &xc).unwrap();
861
862 assert_eq!(u.x, 550.0);
868 assert_eq!(u.y, 1050.0);
869 }
870}