Commit 9911ab0166cd4abf0e50252234b5dba8b1360b9b
1 parent
6fd0ac65
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.
Showing
4 changed files
with
175 additions
and
61 deletions
... | ... | @@ -18,12 +18,12 @@ |
18 | 18 | // You should have received a copy of the GNU General Public License |
19 | 19 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | 20 | // |
21 | -use std::convert::From; | |
21 | +use std::convert::{From, Into}; | |
22 | 22 | use std::ops::{Add,Sub,Neg,Mul,Div}; |
23 | 23 | use std::fmt::Debug; |
24 | 24 | |
25 | 25 | use crate::easel::{Canvas,Coordinate,Coordinates,Polygon}; |
26 | -use crate::transform::TMatrix; | |
26 | +use crate::transform::{TMatrix, Transformable}; | |
27 | 27 | use crate::trigonometry::Trig; |
28 | 28 | use crate::vector::Vector; |
29 | 29 | |
... | ... | @@ -34,10 +34,113 @@ where T: Add + Sub + Neg + Mul + Div + Copy + Trig { |
34 | 34 | normal :Option<Vector<T>>, |
35 | 35 | } |
36 | 36 | |
37 | +#[derive(Debug, PartialEq, Eq, Clone, Copy)] | |
38 | +pub struct Point<T>(pub Vector<T>, T) | |
39 | + where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig; | |
40 | + | |
41 | +impl<T> Point<T> | |
42 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
43 | + + Mul<Output = T> + Div<Output = T> | |
44 | + + PartialEq + Trig + Copy + From<i32> { | |
45 | + pub fn new(x :T, y :T, z :T) -> Self { | |
46 | + Self(Vector(x, y, z), 1.into()) | |
47 | + } | |
48 | +} | |
49 | + | |
50 | +impl<T> Add for Point<T> | |
51 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
52 | + + Mul<Output = T> + Div<Output = T> | |
53 | + + PartialEq + Trig + Copy { | |
54 | + type Output = Self; | |
55 | + | |
56 | + fn add(self, other :Self) -> Self { | |
57 | + let Point(v1, w1) = self; | |
58 | + let Point(v2, w2) = other; | |
59 | + Self(v1 + v2, w1 + w2) | |
60 | + } | |
61 | +} | |
62 | + | |
63 | +impl<T> Neg for Point<T> | |
64 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
65 | + + Mul<Output = T> + Div<Output = T> | |
66 | + + PartialEq + Trig + Copy { | |
67 | + type Output = Self; | |
68 | + | |
69 | + fn neg(self) -> Self { | |
70 | + let Point(v, w) = self; | |
71 | + Self(-v, -w) | |
72 | + } | |
73 | +} | |
74 | + | |
75 | +impl<T> Sub for Point<T> | |
76 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
77 | + + Mul<Output = T> + Div<Output = T> | |
78 | + + PartialEq + Trig + Copy { | |
79 | + type Output = Self; | |
80 | + | |
81 | + fn sub(self, other :Self) -> Self { | |
82 | + self + -other | |
83 | + } | |
84 | +} | |
85 | + | |
86 | +impl<T> Mul for Point<T> | |
87 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
88 | + + Mul<Output = T> + Div<Output = T> | |
89 | + + PartialEq + Trig + Copy + From<i32> { | |
90 | + type Output = Self; | |
91 | + | |
92 | + fn mul(self, other :Self) -> Self { | |
93 | + let a :Vector<T> = self.into(); | |
94 | + let b :Vector<T> = other.into(); | |
95 | + | |
96 | + Point(a * b, 1.into()) | |
97 | + } | |
98 | +} | |
99 | + | |
100 | +impl<T> From<Vector<T>> for Point<T> | |
101 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
102 | + + Mul<Output = T> + Div<Output = T> | |
103 | + + PartialEq + Trig + Copy + From<i32> { | |
104 | + fn from(v :Vector<T>) -> Self { | |
105 | + Point(v, 1.into()) | |
106 | + } | |
107 | +} | |
108 | + | |
109 | +impl<T> Into<Vector<T>> for Point<T> | |
110 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
111 | + + Mul<Output = T> + Div<Output = T> | |
112 | + + PartialEq + Trig + Copy + From<i32> { | |
113 | + fn into(self) -> Vector<T> { | |
114 | + let Point(v, w) = self; | |
115 | + | |
116 | + if w == 0.into() { | |
117 | + v | |
118 | + } else { | |
119 | + v.mul(&w.recip()) | |
120 | + } | |
121 | + } | |
122 | +} | |
123 | + | |
124 | +impl<T> Transformable<T> for Point<T> | |
125 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
126 | + + Mul<Output = T> + Div<Output = T> | |
127 | + + PartialEq + Debug + Trig + Copy + From<i32> { | |
128 | + fn transform(&self, m :&TMatrix<T>) -> Self { | |
129 | + let Point(v, w) = *self; | |
130 | + let (v, w) = m.apply(&v, w); | |
131 | + | |
132 | + if w == 0.into() { | |
133 | + v.into() | |
134 | + } else { | |
135 | + v.mul(&w.recip()).into() | |
136 | + } | |
137 | + } | |
138 | +} | |
139 | + | |
37 | 140 | #[derive(Debug)] |
38 | 141 | pub struct Polyeder<T> |
39 | -where T: Add + Sub + Neg + Mul + Div + Copy + Trig { | |
40 | - points :Vec<Vector<T>>, | |
142 | +where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig { | |
143 | + points :Vec<Point<T>>, | |
41 | 144 | faces :Vec<Face<T>>, |
42 | 145 | } |
43 | 146 | |
... | ... | @@ -65,7 +168,7 @@ where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> { |
65 | 168 | impl<T> Camera<T> |
66 | 169 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
67 | 170 | + Mul<Output = T> + Div<Output = T> |
68 | - + Debug + Copy + Trig + From<i32> { | |
171 | + + PartialEq + Debug + Copy + Trig + From<i32> { | |
69 | 172 | // This code assumes that the size of the viewport is always |
70 | 173 | // equal to the size of the physical screen… e.g. window/canvas thus some |
71 | 174 | // 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> |
91 | 194 | self.project |
92 | 195 | } |
93 | 196 | |
94 | - pub fn project(&self, v :Vector<T>) -> Coordinate { | |
95 | - let p = self.project.apply(&v); | |
96 | - Coordinate(T::round(&p.x()), T::round(&p.y())) | |
197 | + pub fn project(&self, p :Point<T>) -> Coordinate { | |
198 | + let Point(v, _) = p.transform(&self.project); | |
199 | + Coordinate(T::round(&v.x()), T::round(&v.y())) | |
97 | 200 | } |
98 | 201 | } |
99 | 202 | |
... | ... | @@ -113,16 +216,16 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
113 | 216 | impl<T> Face<T> |
114 | 217 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
115 | 218 | + Mul<Output = T> + Div<Output = T> |
116 | - + Debug + Copy + Trig + From<i32> { | |
117 | - fn new(corners :Vec<usize>, ps :&[Vector<T>]) -> Self { | |
219 | + + PartialEq + Debug + Copy + Trig + From<i32> { | |
220 | + fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self { | |
118 | 221 | let mut f = Face{ corners: corners, normal: None }; |
119 | 222 | f.update_normal(ps); |
120 | 223 | f |
121 | 224 | } |
122 | 225 | |
123 | - fn update_normal(&mut self, ps :&[Vector<T>]) { | |
124 | - let edge10 = ps[self.corners[1]] - ps[self.corners[0]]; | |
125 | - let edge12 = ps[self.corners[1]] - ps[self.corners[2]]; | |
226 | + fn update_normal(&mut self, ps :&[Point<T>]) { | |
227 | + let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into(); | |
228 | + let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into(); | |
126 | 229 | self.normal = Some(edge10 * edge12); |
127 | 230 | } |
128 | 231 | } |
... | ... | @@ -130,7 +233,7 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
130 | 233 | impl<T> Polyeder<T> |
131 | 234 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
132 | 235 | + Mul<Output = T> + Div<Output = T> |
133 | - + Debug + Copy + Trig + From<i32> { | |
236 | + + PartialEq + Debug + Copy + Trig + From<i32> { | |
134 | 237 | fn update_normals(&mut self) { |
135 | 238 | for f in self.faces.iter_mut() { |
136 | 239 | f.update_normal(&self.points); |
... | ... | @@ -156,10 +259,10 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
156 | 259 | // half the deeps in z |
157 | 260 | let _zh :T = T::sqrt(f3).unwrap() / f4 * a; |
158 | 261 | |
159 | - let ps = vec!( Vector( f0, yc, f0) | |
160 | - , Vector(-ah, -yi, -zi) | |
161 | - , Vector( ah, -yi, -zi) | |
162 | - , Vector( f0, -yi, zc) ); | |
262 | + let ps = vec!( Point::new( f0, yc, f0) | |
263 | + , Point::new(-ah, -yi, -zi) | |
264 | + , Point::new( ah, -yi, -zi) | |
265 | + , Point::new( f0, -yi, zc) ); | |
163 | 266 | |
164 | 267 | let fs = vec!( Face::new(vec!(1, 2, 3), &ps) |
165 | 268 | , Face::new(vec!(1, 0, 2), &ps) |
... | ... | @@ -177,9 +280,9 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
177 | 280 | let zc :T = T::sqrt(f3).unwrap() / f3 * a; |
178 | 281 | let ah :T = a / 2.into(); |
179 | 282 | |
180 | - let ps = vec!( Vector(-ah, f0, -zi) | |
181 | - , Vector( f0, f0, zc) | |
182 | - , Vector( ah, f0, -zi) ); | |
283 | + let ps = vec!( Point::new(-ah, f0, -zi) | |
284 | + , Point::new( f0, f0, zc) | |
285 | + , Point::new( ah, f0, -zi) ); | |
183 | 286 | |
184 | 287 | let fs = vec!(Face::new(vec!(0, 1, 2), &ps)); |
185 | 288 | |
... | ... | @@ -191,14 +294,14 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
191 | 294 | pub fn cube(a :T) -> Polyeder<T> { |
192 | 295 | let ah :T = a / From::<i32>::from(2); |
193 | 296 | |
194 | - let ps = vec!( Vector(-ah, ah, -ah) // 0 => front 1 | |
195 | - , Vector(-ah, -ah, -ah) // 1 => front 2 | |
196 | - , Vector( ah, -ah, -ah) // 2 => front 3 | |
197 | - , Vector( ah, ah, -ah) // 3 => front 4 | |
198 | - , Vector(-ah, ah, ah) // 4 => back 1 | |
199 | - , Vector(-ah, -ah, ah) // 5 => back 2 | |
200 | - , Vector( ah, -ah, ah) // 6 => back 3 | |
201 | - , Vector( ah, ah, ah) ); // 7 => back 4 | |
297 | + let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1 | |
298 | + , Point::new(-ah, -ah, -ah) // 1 => front 2 | |
299 | + , Point::new( ah, -ah, -ah) // 2 => front 3 | |
300 | + , Point::new( ah, ah, -ah) // 3 => front 4 | |
301 | + , Point::new(-ah, ah, ah) // 4 => back 1 | |
302 | + , Point::new(-ah, -ah, ah) // 5 => back 2 | |
303 | + , Point::new( ah, -ah, ah) // 6 => back 3 | |
304 | + , Point::new( ah, ah, ah) ); // 7 => back 4 | |
202 | 305 | |
203 | 306 | let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front |
204 | 307 | , Face::new(vec!(7, 6, 5, 4), &ps) // back |
... | ... | @@ -218,8 +321,10 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
218 | 321 | fn transform(&self, m :&TMatrix<T>) -> Self { |
219 | 322 | let Polyeder{ points: ps, faces: fs } = self; |
220 | 323 | |
221 | - let mut p = Polyeder{ points: ps.iter().map(|p| m.apply(p)).collect() | |
222 | - , faces: fs.to_vec() }; | |
324 | + let mut p = Polyeder{ | |
325 | + points: ps.iter().map(|p| p.transform(m)).collect() | |
326 | + , faces: fs.to_vec() | |
327 | + }; | |
223 | 328 | |
224 | 329 | // TODO alternatively we could rotate the normals too, but this cannot |
225 | 330 | // done with the original matrix… the question is, what is faster. | ... | ... |
... | ... | @@ -34,7 +34,7 @@ use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline |
34 | 34 | use fractional::fractional::{Fractional, from_vector}; |
35 | 35 | use fractional::trigonometry::Trig; |
36 | 36 | use fractional::vector::Vector; |
37 | -use fractional::transform::TMatrix; | |
37 | +use fractional::transform::{TMatrix, Transformable}; | |
38 | 38 | |
39 | 39 | use fractional::xcb::XcbEasel; |
40 | 40 | use fractional::easel::Canvas; |
... | ... | @@ -204,7 +204,8 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>) |
204 | 204 | + Debug + From<i32> + Copy + Display { |
205 | 205 | |
206 | 206 | println!("{:>14} : {}", "Vector v1", v1); |
207 | - println!("{:>14} : {}", "translate v1", TMatrix::translate(v).apply(&v1)); | |
207 | + println!( "{:>14} : {}", "translate v1" | |
208 | + , v.transform(&TMatrix::translate(v))); | |
208 | 209 | println!(); |
209 | 210 | |
210 | 211 | 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>) |
218 | 219 | let mi = fs.iter().map(|f| f(*d as i32)); |
219 | 220 | println!( "{:>14} : {}" |
220 | 221 | , format!("{} {} {}", o, d, n) |
221 | - , TMatrix::combine(mi).apply(v) ); | |
222 | + , v.transform(&TMatrix::combine(mi)) ); | |
222 | 223 | } |
223 | 224 | } |
224 | 225 | |
... | ... | @@ -237,7 +238,7 @@ fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>) |
237 | 238 | , 210, 225, 240, 270, 300, 315, 330 ].iter() { |
238 | 239 | println!( "{:>14} : {}" |
239 | 240 | , format!("rot_v {} v2", d) |
240 | - , TMatrix::rotate_v(&v, *d as i32).apply(&v2)); | |
241 | + , v2.transform(&TMatrix::rotate_v(&v, *d as i32)) ); | |
241 | 242 | } |
242 | 243 | } |
243 | 244 | |
... | ... | @@ -273,9 +274,9 @@ fn _line() { |
273 | 274 | let k = Vector(Fractional(-30,1), Fractional( 30,1), Fractional(0,1)); |
274 | 275 | |
275 | 276 | let rot :TMatrix<Fractional> = TMatrix::rotate_z(20); |
276 | - let Vector(ix, iy, _) = rot.apply(&i); | |
277 | - let Vector(jx, jy, _) = rot.apply(&j); | |
278 | - let Vector(kx, ky, _) = rot.apply(&k); | |
277 | + let Vector(ix, iy, _) = i.transform(&rot); | |
278 | + let Vector(jx, jy, _) = j.transform(&rot); | |
279 | + let Vector(kx, ky, _) = k.transform(&rot); | |
279 | 280 | |
280 | 281 | fn to_i32(x :Fractional) -> i32 { |
281 | 282 | let Fractional(n, d) = x; |
... | ... | @@ -294,9 +295,9 @@ fn _line() { |
294 | 295 | let k = Vector(-30.0, 30.0, 0.0); |
295 | 296 | |
296 | 297 | let rot :TMatrix<f64> = TMatrix::rotate_z(20); |
297 | - let Vector(ix, iy, _) = rot.apply(&i); | |
298 | - let Vector(jx, jy, _) = rot.apply(&j); | |
299 | - let Vector(kx, ky, _) = rot.apply(&k); | |
298 | + let Vector(ix, iy, _) = i.transform(&rot); | |
299 | + let Vector(jx, jy, _) = j.transform(&rot); | |
300 | + let Vector(kx, ky, _) = k.transform(&rot); | |
300 | 301 | |
301 | 302 | fn to_i32_2(x :f64) -> i32 { |
302 | 303 | x.round() as i32 |
... | ... | @@ -334,24 +335,15 @@ fn _democanvas<T>( xcb :&XcbEasel |
334 | 335 | let step = Duration::from_millis(25); |
335 | 336 | let mut last = Instant::now(); |
336 | 337 | |
337 | - let t :TMatrix<T> = TMatrix::translate(Vector( 0.into() | |
338 | - , 0.into() | |
339 | - , 150.into() )); | |
340 | - // We do not need this here… it is used within projection… | |
341 | - // let p :TMatrix<T> = camera.get_projection(); | |
338 | + let t = TMatrix::translate(Vector(0.into() , 0.into() , 150.into())); | |
342 | 339 | |
343 | 340 | loop { |
344 | 341 | let deg = ((start.elapsed() / 25).as_millis() % 360) as i32; |
345 | 342 | |
346 | - let rz :TMatrix<T> = TMatrix::rotate_z(deg); | |
347 | - let rx :TMatrix<T> = TMatrix::rotate_x(-deg*2); | |
348 | - let ry :TMatrix<T> = TMatrix::rotate_y(-deg*2); | |
343 | + let rz = TMatrix::rotate_z(deg); | |
344 | + let rx = TMatrix::rotate_x(-deg*2); | |
345 | + let ry = TMatrix::rotate_y(-deg*2); | |
349 | 346 | |
350 | - // I can not apply the projection in one turn, as I generate the | |
351 | - // normals always… and this is no longer possible after the | |
352 | - // projection… | |
353 | - // let rot1 = TMatrix::combine(vec!(rz, rx, t, p)); | |
354 | - // let rot2 = TMatrix::combine(vec!(rz, ry, t, p)); | |
355 | 347 | let rot1 = TMatrix::combine(vec!(rz, rx, t)); |
356 | 348 | let rot2 = TMatrix::combine(vec!(rz, ry, t)); |
357 | 349 | ... | ... |
... | ... | @@ -31,6 +31,11 @@ pub struct TMatrix<T>( (T, T, T, T) |
31 | 31 | , (T, T, T, T) ) |
32 | 32 | where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy; |
33 | 33 | |
34 | +pub trait Transformable<T> | |
35 | +where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy { | |
36 | + fn transform(&self, m :&TMatrix<T>) -> Self; | |
37 | +} | |
38 | + | |
34 | 39 | impl<T> TMatrix<T> |
35 | 40 | where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
36 | 41 | + Mul<Output = T> + Div<Output = T> |
... | ... | @@ -127,19 +132,20 @@ where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> |
127 | 132 | mi.into_iter().fold(Self::unit(), |acc, x| x * acc) |
128 | 133 | } |
129 | 134 | |
130 | - pub fn apply(&self, v :&Vector<T>) -> Vector<T> { | |
135 | + pub fn apply(&self, v :&Vector<T>, w :T) -> (Vector<T>, T) { | |
131 | 136 | let TMatrix( (a11, a12, a13, a14) |
132 | 137 | , (a21, a22, a23, a24) |
133 | 138 | , (a31, a32, a33, a34) |
134 | 139 | , (a41, a42, a43, a44) ) = *self; |
135 | 140 | let Vector(x, y, z) = *v; |
136 | 141 | |
137 | - let v = Vector( a11 * x + a12 * y + a13 * z + a14 | |
138 | - , a21 * x + a22 * y + a23 * z + a24 | |
139 | - , a31 * x + a32 * y + a33 * z + a34 ); | |
140 | - let w = a41 * x + a42 * y + a43 * z + a44; | |
142 | + let v = Vector( a11 * x + a12 * y + a13 * z + a14 * w | |
143 | + , a21 * x + a22 * y + a23 * z + a24 * w | |
144 | + , a31 * x + a32 * y + a33 * z + a34 * w ); | |
145 | + let w = a41 * x + a42 * y + a43 * z + a44 * w; | |
141 | 146 | |
142 | - v.mul(&w.recip()) | |
147 | + //v.mul(&w.recip()) | |
148 | + (v, w) | |
143 | 149 | } |
144 | 150 | } |
145 | 151 | ... | ... |
... | ... | @@ -18,10 +18,11 @@ |
18 | 18 | // You should have received a copy of the GNU General Public License |
19 | 19 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | 20 | // |
21 | -use std::fmt::{Formatter, Display, Result}; | |
21 | +use std::fmt::{Debug, Display, Formatter, Result}; | |
22 | 22 | use std::ops::{Add, Sub, Neg, Mul, Div}; |
23 | 23 | |
24 | 24 | use crate::trigonometry::Trig; |
25 | +use crate::transform::{TMatrix, Transformable}; | |
25 | 26 | |
26 | 27 | #[derive(Debug, Eq, Clone, Copy)] |
27 | 28 | 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> |
126 | 127 | , ax * by - ay * bx ) |
127 | 128 | } |
128 | 129 | } |
130 | + | |
131 | +impl<T> Transformable<T> for Vector<T> | |
132 | +where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T> | |
133 | + + Mul<Output = T> + Div<Output = T> | |
134 | + + Trig + Copy + Debug + From<i32> { | |
135 | + fn transform(&self, m :&TMatrix<T>) -> Self { | |
136 | + let (v, _) = m.apply(self, 0.into()); | |
137 | + v | |
138 | + } | |
139 | +} | ... | ... |
Please
register
or
login
to post a comment