Commit 9911ab0166cd4abf0e50252234b5dba8b1360b9b

Authored by Georg Hopp
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.
... ... @@ -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