Showing
2 changed files
with
56 additions
and
39 deletions
@@ -29,68 +29,76 @@ use crate::vector::Vector; | @@ -29,68 +29,76 @@ use crate::vector::Vector; | ||
29 | 29 | ||
30 | #[derive(Debug)] | 30 | #[derive(Debug)] |
31 | pub struct Polyeder<T> | 31 | pub struct Polyeder<T> |
32 | -where T: Add + Sub + Neg + Mul + Div + Copy + Trig { | 32 | +where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig { |
33 | points :Vec<Vector<T>>, | 33 | points :Vec<Vector<T>>, |
34 | faces :Vec<Vec<usize>>, | 34 | faces :Vec<Vec<usize>>, |
35 | } | 35 | } |
36 | 36 | ||
37 | pub trait Primitives<T> | 37 | pub trait Primitives<T> |
38 | -where T: Add + Sub + Neg + Mul + Div + Copy + Trig + From<i32> { | 38 | +where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> { |
39 | fn transform(&self, m :&TMatrix<T>) -> Self; | 39 | fn transform(&self, m :&TMatrix<T>) -> Self; |
40 | fn project(&self, camera :&Camera<T>) -> Vec<Polygon>; | 40 | fn project(&self, camera :&Camera<T>) -> Vec<Polygon>; |
41 | } | 41 | } |
42 | 42 | ||
43 | pub struct Camera<T> | 43 | pub struct Camera<T> |
44 | -where T: Add + Sub + Neg + Mul + Div + Copy + Trig { | ||
45 | - width :T, | ||
46 | - height :T, | ||
47 | - fovx :T, | ||
48 | - fovy :T, | 44 | +where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> { |
45 | + width :T, | ||
46 | + height :T, | ||
47 | + project :TMatrix<T>, | ||
49 | } | 48 | } |
50 | 49 | ||
51 | impl<T> Camera<T> | 50 | impl<T> Camera<T> |
52 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | 51 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
53 | + Mul<Output = T> + Div<Output = T> | 52 | + Mul<Output = T> + Div<Output = T> |
54 | - + Copy + Trig + From<i32> { | 53 | + + Debug + Copy + Trig + From<i32> { |
54 | + // This code assumes that the size of the viewport is always | ||
55 | + // equal to the size of the physical screen… e.g. window/canvas thus some | ||
56 | + // effects can't be done. See book for examples with different viewport | ||
57 | + // and screen sizes. | ||
55 | pub fn new(c :&dyn Canvas, angle :i32) -> Self { | 58 | pub fn new(c :&dyn Canvas, angle :i32) -> Self { |
56 | - let width = <T as From<i32>>::from(c.width() as i32); | ||
57 | - let height = <T as From<i32>>::from(c.height() as i32); | ||
58 | - | ||
59 | - // The calculations for fovx and fovy are taken from a book, but I | ||
60 | - // have the impression, coming from my limited algebra knowledge, | ||
61 | - // that they are always equal… | ||
62 | - Camera { width: width | ||
63 | - , height: height | ||
64 | - , fovx: T::cot(angle) * width | ||
65 | - , fovy: width / height * T::cot(angle) * height } | 59 | + let width :T = (c.width() as i32).into(); |
60 | + let height :T = (c.height() as i32).into(); | ||
61 | + let d :T = 1.into(); | ||
62 | + let fov = T::cot(angle) * width; | ||
63 | + let wh = width / 2.into(); | ||
64 | + let hh = height / 2.into(); | ||
65 | + | ||
66 | + Camera { width: width | ||
67 | + , height: height | ||
68 | + , project: TMatrix::new( | ||
69 | + ( fov, 0.into(), wh, 0.into()) | ||
70 | + , (0.into(), fov, hh, 0.into()) | ||
71 | + , (0.into(), 0.into(), d, 1.into()) | ||
72 | + , (0.into(), 0.into(), 1.into(), 0.into()) ) } | ||
66 | } | 73 | } |
67 | 74 | ||
68 | - pub fn project(&self, v :Vector<T>) -> Coordinate { | ||
69 | - let f2 = From::<i32>::from(2); | ||
70 | - let xs = v.x() / v.z() * self.fovx + self.width / f2; | ||
71 | - let ys = v.y() / v.z() * self.fovy + self.height / f2; | 75 | + pub fn get_projection(&self) -> TMatrix<T> { |
76 | + self.project | ||
77 | + } | ||
72 | 78 | ||
73 | - Coordinate(T::round(&xs), T::round(&ys)) | 79 | + pub fn project(&self, v :Vector<T>) -> Coordinate { |
80 | + let p = self.project.apply(&v); | ||
81 | + Coordinate(T::round(&p.x()), T::round(&p.y())) | ||
74 | } | 82 | } |
75 | } | 83 | } |
76 | 84 | ||
77 | impl<T> Polyeder<T> | 85 | impl<T> Polyeder<T> |
78 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | 86 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
79 | + Mul<Output = T> + Div<Output = T> | 87 | + Mul<Output = T> + Div<Output = T> |
80 | - + Copy + Trig + From<i32> { | 88 | + + Debug + Copy + Trig + From<i32> { |
81 | // https://rechneronline.de/pi/tetrahedron.php | 89 | // https://rechneronline.de/pi/tetrahedron.php |
82 | pub fn tetrahedron(a :T) -> Polyeder<T> { | 90 | pub fn tetrahedron(a :T) -> Polyeder<T> { |
83 | - let f0 :T = From::<i32>::from(0); | ||
84 | - let f3 :T = From::<i32>::from(3); | ||
85 | - let f4 :T = From::<i32>::from(4); | ||
86 | - let f6 :T = From::<i32>::from(6); | ||
87 | - let f12 :T = From::<i32>::from(12); | 91 | + let f0 :T = 0.into(); |
92 | + let f3 :T = 3.into(); | ||
93 | + let f4 :T = 4.into(); | ||
94 | + let f6 :T = 6.into(); | ||
95 | + let f12 :T = 12.into(); | ||
88 | 96 | ||
89 | let yi :T = a / f12 * T::sqrt(f6).unwrap(); | 97 | let yi :T = a / f12 * T::sqrt(f6).unwrap(); |
90 | let yc :T = a / f4 * T::sqrt(f6).unwrap(); | 98 | let yc :T = a / f4 * T::sqrt(f6).unwrap(); |
91 | let zi :T = T::sqrt(f3).unwrap() / f6 * a; | 99 | let zi :T = T::sqrt(f3).unwrap() / f6 * a; |
92 | let zc :T = T::sqrt(f3).unwrap() / f3 * a; | 100 | let zc :T = T::sqrt(f3).unwrap() / f3 * a; |
93 | - let ah :T = a / From::<i32>::from(2); | 101 | + let ah :T = a / 2.into(); |
94 | 102 | ||
95 | // half the height in y | 103 | // half the height in y |
96 | let _yh :T = a / f6 * T::sqrt(f6).unwrap(); | 104 | let _yh :T = a / f6 * T::sqrt(f6).unwrap(); |
@@ -130,19 +138,27 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | @@ -130,19 +138,27 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | ||
130 | impl<T> Primitives<T> for Polyeder<T> | 138 | impl<T> Primitives<T> for Polyeder<T> |
131 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | 139 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
132 | + Mul<Output = T> + Div<Output = T> | 140 | + Mul<Output = T> + Div<Output = T> |
133 | - + Copy + Trig + From<i32> + From<i32> { | 141 | + + Debug + Copy + Trig + From<i32> + From<i32> { |
134 | fn transform(&self, m :&TMatrix<T>) -> Self { | 142 | fn transform(&self, m :&TMatrix<T>) -> Self { |
135 | Polyeder{ points: self.points.iter().map(|p| m.apply(p)).collect() | 143 | Polyeder{ points: self.points.iter().map(|p| m.apply(p)).collect() |
136 | , faces: self.faces.to_vec() } | 144 | , faces: self.faces.to_vec() } |
137 | } | 145 | } |
138 | 146 | ||
139 | - fn project(&self, camera :&Camera<T>) -> Vec<Polygon> { | 147 | + // TODO for now we assume already prejected vertices (points) |
148 | + // in future we need to distinguish more clear between vertex and point | ||
149 | + // and projected_point. | ||
150 | + fn project(&self, _camera :&Camera<T>) -> Vec<Polygon> { | ||
140 | fn polygon<I>(c :I) -> Polygon | 151 | fn polygon<I>(c :I) -> Polygon |
141 | where I: Iterator<Item = Coordinate> { | 152 | where I: Iterator<Item = Coordinate> { |
142 | Polygon(Coordinates(c.collect())) | 153 | Polygon(Coordinates(c.collect())) |
143 | } | 154 | } |
144 | 155 | ||
145 | - let to_coord = |p :&usize| camera.project(self.points[*p]); | 156 | + // this one does the projection... as the projection was the last |
157 | + // matrix we do not need to do it here. | ||
158 | + // let to_coord = |p :&usize| _camera.project(self.points[*p]); | ||
159 | + let to_coord = |p :&usize| { | ||
160 | + let v = self.points[*p]; | ||
161 | + Coordinate(v.x().round(), v.y().round()) }; | ||
146 | let to_poly = |f :&Vec<usize>| polygon(f.iter().map(to_coord)); | 162 | let to_poly = |f :&Vec<usize>| polygon(f.iter().map(to_coord)); |
147 | 163 | ||
148 | self.faces.iter().map(to_poly).collect() | 164 | self.faces.iter().map(to_poly).collect() |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | // | 20 | // |
21 | use std::convert::{TryFrom, TryInto, Into}; | 21 | use std::convert::{TryFrom, TryInto, Into}; |
22 | use std::f64::consts::PI as FPI; | 22 | use std::f64::consts::PI as FPI; |
23 | -use std::fmt::Display; | 23 | +use std::fmt::{Debug, Display}; |
24 | use std::marker::Send; | 24 | use std::marker::Send; |
25 | use std::num::TryFromIntError; | 25 | use std::num::TryFromIntError; |
26 | use std::ops::{Add,Sub,Neg,Mul,Div}; | 26 | use std::ops::{Add,Sub,Neg,Mul,Div}; |
@@ -201,7 +201,7 @@ fn _transform2() { | @@ -201,7 +201,7 @@ fn _transform2() { | ||
201 | fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>) | 201 | fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>) |
202 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | 202 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
203 | + Mul<Output = T> + Div<Output = T> + Trig | 203 | + Mul<Output = T> + Div<Output = T> + Trig |
204 | - + From<i32> + Copy + Display { | 204 | + + Debug + From<i32> + Copy + Display { |
205 | 205 | ||
206 | println!("{:>14} : {}", "Vector v1", v1); | 206 | println!("{:>14} : {}", "Vector v1", v1); |
207 | println!("{:>14} : {}", "translate v1", translate(v).apply(&v1)); | 207 | 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>) | @@ -211,7 +211,7 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>) | ||
211 | , fs :&[&dyn Fn(i32) -> TMatrix<T>] ) | 211 | , fs :&[&dyn Fn(i32) -> TMatrix<T>] ) |
212 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | 212 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
213 | + Mul<Output = T> + Div<Output = T> + Trig | 213 | + Mul<Output = T> + Div<Output = T> + Trig |
214 | - + From<i32> + Copy + Display { | 214 | + + Debug + From<i32> + Copy + Display { |
215 | 215 | ||
216 | for d in [ 30, 45, 60, 90, 120, 135, 150, 180 | 216 | for d in [ 30, 45, 60, 90, 120, 135, 150, 180 |
217 | , 210, 225, 240, 270, 300, 315, 330 ].iter() { | 217 | , 210, 225, 240, 270, 300, 315, 330 ].iter() { |
@@ -317,7 +317,7 @@ fn _democanvas<T>( xcb :&XcbEasel | @@ -317,7 +317,7 @@ fn _democanvas<T>( xcb :&XcbEasel | ||
317 | , cube :Polyeder<T> ) | 317 | , cube :Polyeder<T> ) |
318 | where T: 'static + Add<Output = T> + Sub<Output = T> + Neg<Output = T> | 318 | where T: 'static + Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
319 | + Mul<Output = T> + Div<Output = T> | 319 | + Mul<Output = T> + Div<Output = T> |
320 | - + Copy + Trig + Send + From<i32> { | 320 | + + Debug + Copy + Trig + Send + From<i32> { |
321 | 321 | ||
322 | let mut canvas = xcb.canvas(151, 151).unwrap(); | 322 | let mut canvas = xcb.canvas(151, 151).unwrap(); |
323 | let camera = Camera::<T>::new(&canvas, 45); // the orig. view angle | 323 | let camera = Camera::<T>::new(&canvas, 45); // the orig. view angle |
@@ -333,14 +333,15 @@ fn _democanvas<T>( xcb :&XcbEasel | @@ -333,14 +333,15 @@ fn _democanvas<T>( xcb :&XcbEasel | ||
333 | let mut last = Instant::now(); | 333 | let mut last = Instant::now(); |
334 | 334 | ||
335 | let t :TMatrix<T> = translate(Vector(0.into(), 0.into(), 150.into())); | 335 | let t :TMatrix<T> = translate(Vector(0.into(), 0.into(), 150.into())); |
336 | + let p :TMatrix<T> = camera.get_projection(); | ||
336 | 337 | ||
337 | loop { | 338 | loop { |
338 | let deg = ((start.elapsed() / 25).as_millis() % 360) as i32; | 339 | let deg = ((start.elapsed() / 25).as_millis() % 360) as i32; |
339 | 340 | ||
340 | let rz :TMatrix<T> = rotate_z(deg); | 341 | let rz :TMatrix<T> = rotate_z(deg); |
341 | 342 | ||
342 | - let rot1 = TMatrix::combine(vec!(rz, rotate_x(-deg*2), t)); | ||
343 | - let rot2 = TMatrix::combine(vec!(rz, rotate_y(-deg*2), t)); | 343 | + let rot1 = TMatrix::combine(vec!(rz, rotate_x(-deg*2), t, p)); |
344 | + let rot2 = TMatrix::combine(vec!(rz, rotate_y(-deg*2), t, p)); | ||
344 | 345 | ||
345 | let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) | 346 | let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) |
346 | , ( cube.transform(&rot2), 0x0000FF) ); | 347 | , ( cube.transform(&rot2), 0x0000FF) ); |
Please
register
or
login
to post a comment