use crate::{Bearing, CameraPoint, UnscaledRelativeCameraPose};
use nalgebra::{Matrix4, Point3, RowVector4, Vector3};
pub fn make_one_pose_dlt_triangulator<B>(
epsilon: f64,
max_iterations: usize,
) -> impl Fn(UnscaledRelativeCameraPose, B, B) -> Option<Point3<f64>>
where
B: Bearing,
{
move |pose, a, b| {
let pose = pose.to_homogeneous();
let a = a.bearing_unnormalized();
let b = b.bearing_unnormalized();
let mut design = Matrix4::zeros();
design
.row_mut(0)
.copy_from(&RowVector4::new(-a.z, 0.0, a.x, 0.0));
design
.row_mut(1)
.copy_from(&RowVector4::new(0.0, -a.z, a.y, 0.0));
design
.row_mut(2)
.copy_from(&(b.x * pose.row(2) - b.z * pose.row(0)));
design
.row_mut(3)
.copy_from(&(b.y * pose.row(2) - b.z * pose.row(1)));
let svd = design.try_svd(false, true, epsilon, max_iterations)?;
svd.singular_values
.iter()
.enumerate()
.min_by_key(|&(_, &n)| float_ord::FloatOrd(n))
.map(|(ix, _)| svd.v_t.unwrap().row(ix).transpose().into_owned())
.map(|h| (h.xyz() / h.w).into())
}
}
pub fn triangulate_bearing_intersection<B>(
bearing: Vector3<f64>,
from: CameraPoint,
to: B,
) -> Option<f64>
where
B: Bearing,
{
let from = from.0.coords;
let to = to.bearing_unnormalized();
let hv = to.cross(&-from);
let h = hv.norm();
let kv = to.cross(&bearing);
let k = kv.norm();
let l = h / k;
Some(if hv.dot(&kv) > 0.0 { l } else { -l })
}
pub fn triangulate_bearing_reproject<B>(
bearing: Vector3<f64>,
from: CameraPoint,
to: B,
) -> Option<f64>
where
B: Bearing,
{
let a = to.bearing_unnormalized();
let b = from;
let t = bearing;
Some((a.y * b.x - a.x * b.y) / (a.x * t.y - a.y * t.x))
}