Browse Source

Add homogenous point.

A homogenous point, that is (x, y, z, w) is needed for some
transdormations and calculations. Right now i need it to get
correct 1/z values after 2D projection which in turn will be
needed for z-buffer and texture mapping.
master
Georg Hopp 6 years ago
parent
commit
9911ab0166
Signed by: ghopp GPG Key ID: 4C5D226768784538
  1. 167
      fractional/src/geometry.rs
  2. 38
      fractional/src/main.rs
  3. 18
      fractional/src/transform.rs
  4. 13
      fractional/src/vector.rs

167
fractional/src/geometry.rs

@ -18,12 +18,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
use std::convert::From;
use std::convert::{From, Into};
use std::ops::{Add,Sub,Neg,Mul,Div}; use std::ops::{Add,Sub,Neg,Mul,Div};
use std::fmt::Debug; use std::fmt::Debug;
use crate::easel::{Canvas,Coordinate,Coordinates,Polygon}; use crate::easel::{Canvas,Coordinate,Coordinates,Polygon};
use crate::transform::TMatrix;
use crate::transform::{TMatrix, Transformable};
use crate::trigonometry::Trig; use crate::trigonometry::Trig;
use crate::vector::Vector; use crate::vector::Vector;
@ -34,10 +34,113 @@ where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
normal :Option<Vector<T>>, normal :Option<Vector<T>>,
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Point<T>(pub Vector<T>, T)
where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig;
impl<T> Point<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ PartialEq + Trig + Copy + From<i32> {
pub fn new(x :T, y :T, z :T) -> Self {
Self(Vector(x, y, z), 1.into())
}
}
impl<T> Add for Point<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ PartialEq + Trig + Copy {
type Output = Self;
fn add(self, other :Self) -> Self {
let Point(v1, w1) = self;
let Point(v2, w2) = other;
Self(v1 + v2, w1 + w2)
}
}
impl<T> Neg for Point<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ PartialEq + Trig + Copy {
type Output = Self;
fn neg(self) -> Self {
let Point(v, w) = self;
Self(-v, -w)
}
}
impl<T> Sub for Point<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ PartialEq + Trig + Copy {
type Output = Self;
fn sub(self, other :Self) -> Self {
self + -other
}
}
impl<T> Mul for Point<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ PartialEq + Trig + Copy + From<i32> {
type Output = Self;
fn mul(self, other :Self) -> Self {
let a :Vector<T> = self.into();
let b :Vector<T> = other.into();
Point(a * b, 1.into())
}
}
impl<T> From<Vector<T>> for Point<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ PartialEq + Trig + Copy + From<i32> {
fn from(v :Vector<T>) -> Self {
Point(v, 1.into())
}
}
impl<T> Into<Vector<T>> for Point<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ PartialEq + Trig + Copy + From<i32> {
fn into(self) -> Vector<T> {
let Point(v, w) = self;
if w == 0.into() {
v
} else {
v.mul(&w.recip())
}
}
}
impl<T> Transformable<T> for Point<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ PartialEq + Debug + Trig + Copy + From<i32> {
fn transform(&self, m :&TMatrix<T>) -> Self {
let Point(v, w) = *self;
let (v, w) = m.apply(&v, w);
if w == 0.into() {
v.into()
} else {
v.mul(&w.recip()).into()
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Polyeder<T> pub struct Polyeder<T>
where T: Add + Sub + Neg + Mul + Div + Copy + Trig {
points :Vec<Vector<T>>,
where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {
points :Vec<Point<T>>,
faces :Vec<Face<T>>, faces :Vec<Face<T>>,
} }
@ -65,7 +168,7 @@ where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {
impl<T> Camera<T> impl<T> Camera<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T> + Mul<Output = T> + Div<Output = T>
+ Debug + Copy + Trig + From<i32> {
+ PartialEq + Debug + Copy + Trig + From<i32> {
// This code assumes that the size of the viewport is always // 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 // 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 // effects can't be done. See book for examples with different viewport
@ -91,9 +194,9 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
self.project self.project
} }
pub fn project(&self, v :Vector<T>) -> Coordinate {
let p = self.project.apply(&v);
Coordinate(T::round(&p.x()), T::round(&p.y()))
pub fn project(&self, p :Point<T>) -> Coordinate {
let Point(v, _) = p.transform(&self.project);
Coordinate(T::round(&v.x()), T::round(&v.y()))
} }
} }
@ -113,16 +216,16 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
impl<T> Face<T> impl<T> Face<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T> + Mul<Output = T> + Div<Output = T>
+ Debug + Copy + Trig + From<i32> {
fn new(corners :Vec<usize>, ps :&[Vector<T>]) -> Self {
+ PartialEq + Debug + Copy + Trig + From<i32> {
fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {
let mut f = Face{ corners: corners, normal: None }; let mut f = Face{ corners: corners, normal: None };
f.update_normal(ps); f.update_normal(ps);
f f
} }
fn update_normal(&mut self, ps :&[Vector<T>]) {
let edge10 = ps[self.corners[1]] - ps[self.corners[0]];
let edge12 = ps[self.corners[1]] - ps[self.corners[2]];
fn update_normal(&mut self, ps :&[Point<T>]) {
let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();
let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();
self.normal = Some(edge10 * edge12); self.normal = Some(edge10 * edge12);
} }
} }
@ -130,7 +233,7 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
impl<T> Polyeder<T> impl<T> Polyeder<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T> + Mul<Output = T> + Div<Output = T>
+ Debug + Copy + Trig + From<i32> {
+ PartialEq + Debug + Copy + Trig + From<i32> {
fn update_normals(&mut self) { fn update_normals(&mut self) {
for f in self.faces.iter_mut() { for f in self.faces.iter_mut() {
f.update_normal(&self.points); f.update_normal(&self.points);
@ -156,10 +259,10 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
// half the deeps in z // half the deeps in z
let _zh :T = T::sqrt(f3).unwrap() / f4 * a; let _zh :T = T::sqrt(f3).unwrap() / f4 * a;
let ps = vec!( Vector( f0, yc, f0)
, Vector(-ah, -yi, -zi)
, Vector( ah, -yi, -zi)
, Vector( f0, -yi, zc) );
let ps = vec!( Point::new( f0, yc, f0)
, Point::new(-ah, -yi, -zi)
, Point::new( ah, -yi, -zi)
, Point::new( f0, -yi, zc) );
let fs = vec!( Face::new(vec!(1, 2, 3), &ps) let fs = vec!( Face::new(vec!(1, 2, 3), &ps)
, Face::new(vec!(1, 0, 2), &ps) , Face::new(vec!(1, 0, 2), &ps)
@ -177,9 +280,9 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
let zc :T = T::sqrt(f3).unwrap() / f3 * a; let zc :T = T::sqrt(f3).unwrap() / f3 * a;
let ah :T = a / 2.into(); let ah :T = a / 2.into();
let ps = vec!( Vector(-ah, f0, -zi)
, Vector( f0, f0, zc)
, Vector( ah, f0, -zi) );
let ps = vec!( Point::new(-ah, f0, -zi)
, Point::new( f0, f0, zc)
, Point::new( ah, f0, -zi) );
let fs = vec!(Face::new(vec!(0, 1, 2), &ps)); let fs = vec!(Face::new(vec!(0, 1, 2), &ps));
@ -191,14 +294,14 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
pub fn cube(a :T) -> Polyeder<T> { pub fn cube(a :T) -> Polyeder<T> {
let ah :T = a / From::<i32>::from(2); let ah :T = a / From::<i32>::from(2);
let ps = vec!( Vector(-ah, ah, -ah) // 0 => front 1
, Vector(-ah, -ah, -ah) // 1 => front 2
, Vector( ah, -ah, -ah) // 2 => front 3
, Vector( ah, ah, -ah) // 3 => front 4
, Vector(-ah, ah, ah) // 4 => back 1
, Vector(-ah, -ah, ah) // 5 => back 2
, Vector( ah, -ah, ah) // 6 => back 3
, Vector( ah, ah, ah) ); // 7 => back 4
let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1
, Point::new(-ah, -ah, -ah) // 1 => front 2
, Point::new( ah, -ah, -ah) // 2 => front 3
, Point::new( ah, ah, -ah) // 3 => front 4
, Point::new(-ah, ah, ah) // 4 => back 1
, Point::new(-ah, -ah, ah) // 5 => back 2
, Point::new( ah, -ah, ah) // 6 => back 3
, Point::new( ah, ah, ah) ); // 7 => back 4
let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front
, Face::new(vec!(7, 6, 5, 4), &ps) // back , Face::new(vec!(7, 6, 5, 4), &ps) // back
@ -218,8 +321,10 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
fn transform(&self, m :&TMatrix<T>) -> Self { fn transform(&self, m :&TMatrix<T>) -> Self {
let Polyeder{ points: ps, faces: fs } = self; let Polyeder{ points: ps, faces: fs } = self;
let mut p = Polyeder{ points: ps.iter().map(|p| m.apply(p)).collect()
, faces: fs.to_vec() };
let mut p = Polyeder{
points: ps.iter().map(|p| p.transform(m)).collect()
, faces: fs.to_vec()
};
// TODO alternatively we could rotate the normals too, but this cannot // TODO alternatively we could rotate the normals too, but this cannot
// done with the original matrix… the question is, what is faster. // done with the original matrix… the question is, what is faster.

38
fractional/src/main.rs

@ -34,7 +34,7 @@ use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline
use fractional::fractional::{Fractional, from_vector}; use fractional::fractional::{Fractional, from_vector};
use fractional::trigonometry::Trig; use fractional::trigonometry::Trig;
use fractional::vector::Vector; use fractional::vector::Vector;
use fractional::transform::TMatrix;
use fractional::transform::{TMatrix, Transformable};
use fractional::xcb::XcbEasel; use fractional::xcb::XcbEasel;
use fractional::easel::Canvas; use fractional::easel::Canvas;
@ -204,7 +204,8 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
+ Debug + From<i32> + Copy + Display { + Debug + From<i32> + Copy + Display {
println!("{:>14} : {}", "Vector v1", v1); println!("{:>14} : {}", "Vector v1", v1);
println!("{:>14} : {}", "translate v1", TMatrix::translate(v).apply(&v1));
println!( "{:>14} : {}", "translate v1"
, v.transform(&TMatrix::translate(v)));
println!(); println!();
fn _rot<T>( o :&str , n :&str , v :&Vector<T> fn _rot<T>( o :&str , n :&str , v :&Vector<T>
@ -218,7 +219,7 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
let mi = fs.iter().map(|f| f(*d as i32)); let mi = fs.iter().map(|f| f(*d as i32));
println!( "{:>14} : {}" println!( "{:>14} : {}"
, format!("{} {} {}", o, d, n) , format!("{} {} {}", o, d, n)
, TMatrix::combine(mi).apply(v) );
, v.transform(&TMatrix::combine(mi)) );
} }
} }
@ -237,7 +238,7 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
, 210, 225, 240, 270, 300, 315, 330 ].iter() { , 210, 225, 240, 270, 300, 315, 330 ].iter() {
println!( "{:>14} : {}" println!( "{:>14} : {}"
, format!("rot_v {} v2", d) , format!("rot_v {} v2", d)
, TMatrix::rotate_v(&v, *d as i32).apply(&v2));
, v2.transform(&TMatrix::rotate_v(&v, *d as i32)) );
} }
} }
@ -273,9 +274,9 @@ fn _line() {
let k = Vector(Fractional(-30,1), Fractional( 30,1), Fractional(0,1)); let k = Vector(Fractional(-30,1), Fractional( 30,1), Fractional(0,1));
let rot :TMatrix<Fractional> = TMatrix::rotate_z(20); let rot :TMatrix<Fractional> = TMatrix::rotate_z(20);
let Vector(ix, iy, _) = rot.apply(&i);
let Vector(jx, jy, _) = rot.apply(&j);
let Vector(kx, ky, _) = rot.apply(&k);
let Vector(ix, iy, _) = i.transform(&rot);
let Vector(jx, jy, _) = j.transform(&rot);
let Vector(kx, ky, _) = k.transform(&rot);
fn to_i32(x :Fractional) -> i32 { fn to_i32(x :Fractional) -> i32 {
let Fractional(n, d) = x; let Fractional(n, d) = x;
@ -294,9 +295,9 @@ fn _line() {
let k = Vector(-30.0, 30.0, 0.0); let k = Vector(-30.0, 30.0, 0.0);
let rot :TMatrix<f64> = TMatrix::rotate_z(20); let rot :TMatrix<f64> = TMatrix::rotate_z(20);
let Vector(ix, iy, _) = rot.apply(&i);
let Vector(jx, jy, _) = rot.apply(&j);
let Vector(kx, ky, _) = rot.apply(&k);
let Vector(ix, iy, _) = i.transform(&rot);
let Vector(jx, jy, _) = j.transform(&rot);
let Vector(kx, ky, _) = k.transform(&rot);
fn to_i32_2(x :f64) -> i32 { fn to_i32_2(x :f64) -> i32 {
x.round() as i32 x.round() as i32
@ -334,24 +335,15 @@ fn _democanvas<T>( xcb :&XcbEasel
let step = Duration::from_millis(25); let step = Duration::from_millis(25);
let mut last = Instant::now(); let mut last = Instant::now();
let t :TMatrix<T> = TMatrix::translate(Vector( 0.into()
, 0.into()
, 150.into() ));
// We do not need this here… it is used within projection…
// let p :TMatrix<T> = camera.get_projection();
let t = TMatrix::translate(Vector(0.into() , 0.into() , 150.into()));
loop { loop {
let deg = ((start.elapsed() / 25).as_millis() % 360) as i32; let deg = ((start.elapsed() / 25).as_millis() % 360) as i32;
let rz :TMatrix<T> = TMatrix::rotate_z(deg);
let rx :TMatrix<T> = TMatrix::rotate_x(-deg*2);
let ry :TMatrix<T> = TMatrix::rotate_y(-deg*2);
let rz = TMatrix::rotate_z(deg);
let rx = TMatrix::rotate_x(-deg*2);
let ry = TMatrix::rotate_y(-deg*2);
// I can not apply the projection in one turn, as I generate the
// normals always… and this is no longer possible after the
// projection…
// let rot1 = TMatrix::combine(vec!(rz, rx, t, p));
// let rot2 = TMatrix::combine(vec!(rz, ry, t, p));
let rot1 = TMatrix::combine(vec!(rz, rx, t)); let rot1 = TMatrix::combine(vec!(rz, rx, t));
let rot2 = TMatrix::combine(vec!(rz, ry, t)); let rot2 = TMatrix::combine(vec!(rz, ry, t));

18
fractional/src/transform.rs

@ -31,6 +31,11 @@ pub struct TMatrix<T>( (T, T, T, T)
, (T, T, T, T) ) , (T, T, T, T) )
where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy; where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy;
pub trait Transformable<T>
where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy {
fn transform(&self, m :&TMatrix<T>) -> Self;
}
impl<T> TMatrix<T> impl<T> TMatrix<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T> + Mul<Output = T> + Div<Output = T>
@ -127,19 +132,20 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
mi.into_iter().fold(Self::unit(), |acc, x| x * acc) mi.into_iter().fold(Self::unit(), |acc, x| x * acc)
} }
pub fn apply(&self, v :&Vector<T>) -> Vector<T> {
pub fn apply(&self, v :&Vector<T>, w :T) -> (Vector<T>, T) {
let TMatrix( (a11, a12, a13, a14) let TMatrix( (a11, a12, a13, a14)
, (a21, a22, a23, a24) , (a21, a22, a23, a24)
, (a31, a32, a33, a34) , (a31, a32, a33, a34)
, (a41, a42, a43, a44) ) = *self; , (a41, a42, a43, a44) ) = *self;
let Vector(x, y, z) = *v; let Vector(x, y, z) = *v;
let v = Vector( a11 * x + a12 * y + a13 * z + a14
, a21 * x + a22 * y + a23 * z + a24
, a31 * x + a32 * y + a33 * z + a34 );
let w = a41 * x + a42 * y + a43 * z + a44;
let v = Vector( a11 * x + a12 * y + a13 * z + a14 * w
, a21 * x + a22 * y + a23 * z + a24 * w
, a31 * x + a32 * y + a33 * z + a34 * w );
let w = a41 * x + a42 * y + a43 * z + a44 * w;
v.mul(&w.recip())
//v.mul(&w.recip())
(v, w)
} }
} }

13
fractional/src/vector.rs

@ -18,10 +18,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>. // along with this program. If not, see <http://www.gnu.org/licenses/>.
// //
use std::fmt::{Formatter, Display, Result};
use std::fmt::{Debug, Display, Formatter, Result};
use std::ops::{Add, Sub, Neg, Mul, Div}; use std::ops::{Add, Sub, Neg, Mul, Div};
use crate::trigonometry::Trig; use crate::trigonometry::Trig;
use crate::transform::{TMatrix, Transformable};
#[derive(Debug, Eq, Clone, Copy)] #[derive(Debug, Eq, Clone, Copy)]
pub struct Vector<T>(pub T, pub T, pub T) pub struct Vector<T>(pub T, pub T, pub T)
@ -126,3 +127,13 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
, ax * by - ay * bx ) , ax * by - ay * bx )
} }
} }
impl<T> Transformable<T> for Vector<T>
where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
+ Mul<Output = T> + Div<Output = T>
+ Trig + Copy + Debug + From<i32> {
fn transform(&self, m :&TMatrix<T>) -> Self {
let (v, _) = m.apply(self, 0.into());
v
}
}
Loading…
Cancel
Save