use cam_geom::*;
use nalgebra::{
allocator::Allocator, storage::Storage, DefaultAllocator, Dim, Matrix, MatrixMN, Unit, Vector3,
U1, U2, U3, U8,
};
fn get_perspective_cam() -> Camera<f64, IntrinsicParametersPerspective<f64>> {
let intrinsics = PerspectiveParams {
fx: 100.0,
fy: 100.0,
skew: 0.0,
cx: 640.0,
cy: 480.0,
};
let camcenter = Vector3::new(10.0, 0.0, 10.0);
let lookat = Vector3::new(0.0, 0.0, 0.0);
let up = Unit::new_normalize(Vector3::new(0.0, 0.0, 1.0));
let pose = ExtrinsicParameters::from_view(&camcenter, &lookat, &up);
Camera::new(intrinsics.into(), pose)
}
fn get_ortho_cam() -> Camera<f64, IntrinsicParametersOrthographic<f64>> {
let intrinsics = OrthographicParams {
sx: 100.0,
sy: 102.0,
cx: 321.0,
cy: 239.9,
};
let camcenter = Vector3::new(10.0, 0.0, 10.0);
let lookat = Vector3::new(0.0, 0.0, 0.0);
let up = Unit::new_normalize(Vector3::new(0.0, 0.0, 1.0));
let pose = ExtrinsicParameters::from_view(&camcenter, &lookat, &up);
Camera::new(intrinsics.into(), pose)
}
struct SvgWriter {
segs: Vec<((f64, f64), (f64, f64))>,
xmin: f64,
xmax: f64,
ymin: f64,
ymax: f64,
}
impl SvgWriter {
fn new() -> Self {
Self {
xmin: std::f64::INFINITY,
xmax: -std::f64::INFINITY,
ymin: std::f64::INFINITY,
ymax: -std::f64::INFINITY,
segs: Vec::new(),
}
}
fn add_edge<S>(&mut self, pt0: &Matrix<f64, U1, U2, S>, pt1: &Matrix<f64, U1, U2, S>)
where
S: Storage<f64, U1, U2>,
{
self.xmin = self.xmin.min(pt0[0]);
self.xmin = self.xmin.min(pt1[0]);
self.ymin = self.ymin.min(pt0[1]);
self.ymin = self.ymin.min(pt1[1]);
self.xmax = self.xmax.max(pt0[0]);
self.xmax = self.xmax.max(pt1[0]);
self.ymax = self.ymax.max(pt0[1]);
self.ymax = self.ymax.max(pt1[1]);
self.segs.push(((pt0[0], pt0[1]), (pt1[0], pt1[1])));
}
fn save(&self, fname: &str) -> Result<(), std::io::Error> {
use std::io::prelude::*;
let header = "<svg version=\"1.1\" \
baseProfile=\"full\" \
width=\"300\" height=\"200\" \
xmlns=\"http://www.w3.org/2000/svg\">\n";
let footer = "</svg>\n";
let width = 300.0;
let height = 200.0;
let border = 5.0;
let mut xscale = (width - 2.0 * border) / (self.xmax - self.xmin);
let mut yscale = (height - 2.0 * border) / (self.ymax - self.ymin);
if xscale > yscale {
xscale = yscale;
} else {
yscale = xscale;
}
let xoffset = -self.xmin * xscale + border;
let yoffset = -self.ymin * yscale + border;
let mut file = std::fs::File::create(fname)?;
file.write_all(header.as_bytes())?;
let radius = border;
let stroke_width = 2.0;
for seg in &self.segs {
let x1 = (seg.0).0 * xscale + xoffset;
let x2 = (seg.1).0 * xscale + xoffset;
let y1 = (seg.0).1 * yscale + yoffset;
let y2 = (seg.1).1 * yscale + yoffset;
let buf = format!("<line x1=\"{}\" x2=\"{}\" y1=\"{}\" y2=\"{}\" stroke=\"orange\" stroke-width=\"{}\"/>",
x1, x2, y1, y2, stroke_width);
file.write_all(buf.as_bytes())?;
let buf = format!(
"<circle cx=\"{}\" cy=\"{}\" r=\"{}\" fill=\"green\" />\n",
x1, y1, radius
);
file.write_all(buf.as_bytes())?;
let buf = format!(
"<circle cx=\"{}\" cy=\"{}\" r=\"{}\" fill=\"green\" />\n",
x2, y2, radius
);
file.write_all(buf.as_bytes())?;
}
file.write_all(footer.as_bytes())?;
Ok(())
}
}
fn render_wireframe<NPTS, I, S>(
verts: &Points<WorldFrame, f64, NPTS, S>,
edges: &[(usize, usize)],
cam: &Camera<f64, I>,
fname: &str,
) -> Result<(), std::io::Error>
where
NPTS: Dim,
I: IntrinsicParameters<f64>,
S: Storage<f64, NPTS, U3>,
DefaultAllocator: Allocator<f64, NPTS, U3>,
DefaultAllocator: Allocator<f64, NPTS, U2>,
{
let pixel_coords = cam.world_to_pixel(&verts);
let mut wtr = SvgWriter::new();
for edge in edges {
let (i0, i1) = edge;
let pt0 = pixel_coords.data.row(*i0);
let pt1 = pixel_coords.data.row(*i1);
wtr.add_edge(&pt0, &pt1);
}
wtr.save(fname)?;
Ok(())
}
fn main() -> Result<(), std::io::Error> {
let world_coords =
Points::<WorldFrame, _, _, _>::new(MatrixMN::<f64, U8, U3>::from_row_slice(&[
-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, ]));
let edges = [
(0, 1),
(1, 2),
(2, 3),
(3, 0),
(4, 5),
(5, 6),
(6, 7),
(7, 4),
(0, 4),
(1, 5),
(2, 6),
(3, 7),
];
let cam = get_perspective_cam();
render_wireframe(&world_coords, &edges, &cam, "cube-perspective.svg")?;
let cam = get_ortho_cam();
render_wireframe(&world_coords, &edges, &cam, "cube-ortho.svg")?;
Ok(())
}