Browse Source

user projection matrix

master
Georg Hopp 6 years ago
parent
commit
2052a7a843
Signed by: ghopp GPG Key ID: 4C5D226768784538
  1. 72
      fractional/src/geometry.rs
  2. 13
      fractional/src/main.rs

72
fractional/src/geometry.rs

@ -29,68 +29,76 @@ use crate::vector::Vector;
#[derive(Debug)]
pub struct Polyeder<T>
where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig {
points :Vec<Vector<T>>,
faces :Vec<Vec<usize>>,
}
pub trait Primitives<T>
where T: Add + Sub + Neg + Mul + Div + Copy + Trig + From<i32> {
where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
fn transform(&self, m :&TMatrix<T>) -> Self;
fn project(&self, camera :&Camera<T>) -> Vec<Polygon>;
}
pub struct Camera<T>
where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
width :T,
height :T,
fovx :T,
fovy :T,
project :TMatrix<T>,
}
impl<T> Camera<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ Copy + Trig + From<i32> {
+ Debug + Copy + Trig + From<i32> {
// This code assumes that the size of the viewport is always
// equal to the size of the physical screen… e.g. window/canvas thus some
// effects can't be done. See book for examples with different viewport
// and screen sizes.
pub fn new(c :&dyn Canvas, angle :i32) -> Self {
let width = <T as From<i32>>::from(c.width() as i32);
let height = <T as From<i32>>::from(c.height() as i32);
let width :T = (c.width() as i32).into();
let height :T = (c.height() as i32).into();
let d :T = 1.into();
let fov = T::cot(angle) * width;
let wh = width / 2.into();
let hh = height / 2.into();
// The calculations for fovx and fovy are taken from a book, but I
// have the impression, coming from my limited algebra knowledge,
// that they are always equal…
Camera { width: width
, height: height
, fovx: T::cot(angle) * width
, fovy: width / height * T::cot(angle) * height }
, project: TMatrix::new(
( fov, 0.into(), wh, 0.into())
, (0.into(), fov, hh, 0.into())
, (0.into(), 0.into(), d, 1.into())
, (0.into(), 0.into(), 1.into(), 0.into()) ) }
}
pub fn project(&self, v :Vector<T>) -> Coordinate {
let f2 = From::<i32>::from(2);
let xs = v.x() / v.z() * self.fovx + self.width / f2;
let ys = v.y() / v.z() * self.fovy + self.height / f2;
pub fn get_projection(&self) -> TMatrix<T> {
self.project
}
Coordinate(T::round(&xs), T::round(&ys))
pub fn project(&self, v :Vector<T>) -> Coordinate {
let p = self.project.apply(&v);
Coordinate(T::round(&p.x()), T::round(&p.y()))
}
}
impl<T> Polyeder<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ Copy + Trig + From<i32> {
+ Debug + Copy + Trig + From<i32> {
// https://rechneronline.de/pi/tetrahedron.php
pub fn tetrahedron(a :T) -> Polyeder<T> {
let f0 :T = From::<i32>::from(0);
let f3 :T = From::<i32>::from(3);
let f4 :T = From::<i32>::from(4);
let f6 :T = From::<i32>::from(6);
let f12 :T = From::<i32>::from(12);
let f0 :T = 0.into();
let f3 :T = 3.into();
let f4 :T = 4.into();
let f6 :T = 6.into();
let f12 :T = 12.into();
let yi :T = a / f12 * T::sqrt(f6).unwrap();
let yc :T = a / f4 * T::sqrt(f6).unwrap();
let zi :T = T::sqrt(f3).unwrap() / f6 * a;
let zc :T = T::sqrt(f3).unwrap() / f3 * a;
let ah :T = a / From::<i32>::from(2);
let ah :T = a / 2.into();
// half the height in y
let _yh :T = a / f6 * T::sqrt(f6).unwrap();
@ -130,19 +138,27 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
impl<T> Primitives<T> for Polyeder<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ Copy + Trig + From<i32> + From<i32> {
+ Debug + Copy + Trig + From<i32> + From<i32> {
fn transform(&self, m :&TMatrix<T>) -> Self {
Polyeder{ points: self.points.iter().map(|p| m.apply(p)).collect()
, faces: self.faces.to_vec() }
}
fn project(&self, camera :&Camera<T>) -> Vec<Polygon> {
// TODO for now we assume already prejected vertices (points)
// in future we need to distinguish more clear between vertex and point
// and projected_point.
fn project(&self, _camera :&Camera<T>) -> Vec<Polygon> {
fn polygon<I>(c :I) -> Polygon
where I: Iterator<Item = Coordinate> {
Polygon(Coordinates(c.collect()))
}
let to_coord = |p :&usize| camera.project(self.points[*p]);
// this one does the projection... as the projection was the last
// matrix we do not need to do it here.
// let to_coord = |p :&usize| _camera.project(self.points[*p]);
let to_coord = |p :&usize| {
let v = self.points[*p];
Coordinate(v.x().round(), v.y().round()) };
let to_poly = |f :&Vec<usize>| polygon(f.iter().map(to_coord));
self.faces.iter().map(to_poly).collect()

13
fractional/src/main.rs

@ -20,7 +20,7 @@
//
use std::convert::{TryFrom, TryInto, Into};
use std::f64::consts::PI as FPI;
use std::fmt::Display;
use std::fmt::{Debug, Display};
use std::marker::Send;
use std::num::TryFromIntError;
use std::ops::{Add,Sub,Neg,Mul,Div};
@ -201,7 +201,7 @@ fn _transform2() {
fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T> + Trig
+ From<i32> + Copy + Display {
+ Debug + From<i32> + Copy + Display {
println!("{:>14} : {}", "Vector v1", v1);
println!("{:>14} : {}", "translate v1", translate(v).apply(&v1));
@ -211,7 +211,7 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
, fs :&[&dyn Fn(i32) -> TMatrix<T>] )
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T> + Trig
+ From<i32> + Copy + Display {
+ Debug + From<i32> + Copy + Display {
for d in [ 30, 45, 60, 90, 120, 135, 150, 180
, 210, 225, 240, 270, 300, 315, 330 ].iter() {
@ -317,7 +317,7 @@ fn _democanvas<T>( xcb :&XcbEasel
, cube :Polyeder<T> )
where T: 'static + Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ Copy + Trig + Send + From<i32> {
+ Debug + Copy + Trig + Send + From<i32> {
let mut canvas = xcb.canvas(151, 151).unwrap();
let camera = Camera::<T>::new(&canvas, 45); // the orig. view angle
@ -333,14 +333,15 @@ fn _democanvas<T>( xcb :&XcbEasel
let mut last = Instant::now();
let t :TMatrix<T> = translate(Vector(0.into(), 0.into(), 150.into()));
let p :TMatrix<T> = camera.get_projection();
loop {
let deg = ((start.elapsed() / 25).as_millis() % 360) as i32;
let rz :TMatrix<T> = rotate_z(deg);
let rot1 = TMatrix::combine(vec!(rz, rotate_x(-deg*2), t));
let rot2 = TMatrix::combine(vec!(rz, rotate_y(-deg*2), t));
let rot1 = TMatrix::combine(vec!(rz, rotate_x(-deg*2), t, p));
let rot2 = TMatrix::combine(vec!(rz, rotate_y(-deg*2), t, p));
let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00)
, ( cube.transform(&rot2), 0x0000FF) );

Loading…
Cancel
Save