use catenary::Catenary;
use contourable::Contour;
use levenberg_marquardt::LevenbergMarquardt;
use nalgebra::{Affine2, DVector, Point2};
use num_dual::DualDVec64;
use plotpoint::{image::Image, optim::PointProblem};
fn main() {
let contour = contourable::closed::circle::Circle {
radius: 0.5,
center: Point2::origin(),
};
let cat0 = Catenary::from_points_length(&contour.position(&2.5), &contour.position(&1.0), 1.4)
.unwrap();
println!("cat: {:?}, length: {}", cat0, cat0.length());
let res = (20, 30);
let chain_width = 0.05;
let scale = res.0 as f64 / (2.0 * contour.radius);
let n = (cat0.length() * scale) as u32;
let n = n * 4;
let cat_pts = cat0.divide(cat0.s_0, cat0.s_1, n);
let translation = nalgebra::Translation2::new(res.1 as f64 / 2.0, res.0 as f64 / 2.0);
let rotation = nalgebra::UnitComplex::identity();
let pix_to_point = nalgebra::Similarity2::<f64>::from_parts(translation, rotation, scale);
let mut m = pix_to_point.to_homogeneous();
m[(1, 1)] *= -1.0;
let pix_to_point = Affine2::from_matrix_unchecked(m);
println!("{:?}", pix_to_point.to_homogeneous());
let background = nalgebra::DMatrix::from_element(res.0, res.1, 1.0);
let weight = cat0.length() / (n - 1) as f64 * scale.powf(2.0) * chain_width;
println!("w:{:?}", weight);
let point_weights = cat_pts.iter().map(|p| (*p, weight)).collect::<Vec<_>>();
let img = Image::from_points(&point_weights, &pix_to_point, &background);
let output = img.to_image();
output.save("cat.png").unwrap();
let param = DVector::from_column_slice(&[2.5 * 0.9, 1.0 * 1.10, cat0.length() * 1.2]); let table = catenary::grid::CatenaryTable::load(
"/home/hubert/Documents/test/catenary/output/catenary_grid_t1000_d1000.bin", )
.unwrap();
let pb = PointProblem::new(
¶m,
img,
|x| {
let contour_0 = &x[0];
let contour_1 = &x[1];
let cat_l = &x[2];
let p0 = contour.position(contour_0);
let p1 = contour.position(contour_1);
let cat = table.get_catenary::<DualDVec64>(&p0, &p1, cat_l)?;
let n = 100;
let pts = cat.divide(cat.s_0.clone(), cat.s_1.clone(), n);
let w = cat.length() * scale.powf(2.0) * chain_width / (n - 1) as f64;
let pts_w = pts
.iter()
.map(|p| (p.clone(), w.clone()))
.collect::<Vec<_>>();
Some(pts_w)
},
pix_to_point,
);
let solver = LevenbergMarquardt::new().with_ftol(1e-20).with_xtol(1e-20);
save_result(
"cat_opt_before.png",
&contour,
n,
&pix_to_point,
&background,
scale,
chain_width,
&pb.params,
);
let (result, report) = solver.minimize(pb);
println!("params: {:?}", result.params);
println!("report: {:?}", report);
save_result(
"cat_opt_after.png",
&contour,
n,
&pix_to_point,
&background,
scale,
chain_width,
&result.params,
);
}
fn save_result(
path: &str,
contour: &contourable::closed::circle::Circle<f64>,
n: u32,
pix_to_point: &nalgebra::Transform<f64, nalgebra::TAffine, 2>,
background: &nalgebra::Matrix<
f64,
nalgebra::Dyn,
nalgebra::Dyn,
nalgebra::VecStorage<f64, nalgebra::Dyn, nalgebra::Dyn>,
>,
scale: f64,
chain_width: f64,
params: &DVector<f64>,
) {
let contour_0 = ¶ms[0];
let contour_1 = ¶ms[1];
let cat_l = ¶ms[2];
let p0 = contour.position(contour_0);
let p1 = contour.position(contour_1);
let cat = Catenary::from_points_length(&p0, &p1, *cat_l);
if cat.is_none() {
println!("cat is none for {:?}", path);
return;
}
let cat = cat.unwrap();
let cat_pts = cat.divide(cat.s_0, cat.s_1, n);
let w = cat.length() * scale.powf(2.0) * chain_width / (n - 1) as f64;
let pts_w = cat_pts.iter().map(|p| (*p, w)).collect::<Vec<_>>();
let img = Image::from_points(&pts_w, pix_to_point, background);
let output = img.to_image();
output.save(path).unwrap();
}