Commit e78ff6b6132e602aa67ff751a0360d4083b00ea8

Authored by Georg Hopp
1 parent e4b19add

reduce to easel3d-xcb demo program

Showing 56 changed files with 163 additions and 4581 deletions

Too many changes to show.

To preserve performance only 56 of 56+ files are displayed.

1 [package] 1 [package]
2 -name = "xcb-test" 2 +name = "easel3d-xcb"
3 version = "0.1.0" 3 version = "0.1.0"
4 authors = ["Georg Hopp <georg@steffers.org>"] 4 authors = ["Georg Hopp <georg@steffers.org>"]
5 edition = "2018" 5 edition = "2018"
6 6
7 [dependencies] 7 [dependencies]
  8 +easel3d = { path = "../easel3d" }
8 libc = "0.2" 9 libc = "0.2"
9 -gl = "0.5.2"  
10 -x11 = { version = "2.3", features = ["glx"] }  
11 xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] } 10 xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] }
1 -# Rust playground 1 +# Easel3D-XCB
2 2
3 -Things I have recently done while learning the Rust programming language. 3 +X windows demo application using Easel3D...
4 4
5 ## Synopsis 5 ## Synopsis
6 6
7 -Change in one of the toplevel subdirectories and try `cargo build` or  
8 -`cargo run`. Maybe not everything is working oob. Feel free to fix whatever  
9 -you want. 7 +Checkout this repository as well as the _easel3d_ repository to the same
  8 +destination directory.
10 9
11 -## Description  
12 -  
13 -Various small examples I have tried while learning rust. The biggest and  
14 -currently most active project is **fractional** which started as an  
15 -implamentation of a rational number data type and then switched to a 3D  
16 -math playground visualizing using **XCB** (in future it might also use  
17 -a **HTML5 Canvas** for drawing as WebAssembly application.  
18 -Using fractions with 3D math has several drawbacks: 10 +In the root of this repository call `cargo run`.
19 11
20 -1. A huge part of 3D math is non rational, like sin, cos, tan and sqrt.  
21 -2. The numerator and denominator tend to become very huge while nearing to non  
22 - rational numbers and reduction is difficult and time consuming.  
23 -3. Because of 2 it is way slower than the floating point calculation (at least  
24 - with a decent coprocessor). 12 +## Description
25 13
26 -Anyway, implementing the vector math stuff for both fractions and floating  
27 -point was a nice playground for generics and traits. In future I might add  
28 -another data type which implements the math as done by David Braben for the  
29 -elite computer game. 14 +A demo application using easel3d to draw in an X-Window.
30 15
31 ## Requirements 16 ## Requirements
32 17
33 -### Always  
34 -  
35 - A recent version of the Rust programming language as well as tooling. 18 - A recent version of the Rust programming language as well as tooling.
36 Currently I use Rust 1.39.0. 19 Currently I use Rust 1.39.0.
  20 +- X11 (xcb, x11-shm)
37 21
38 -### For fractional 22 +## Dependencies
39 23
40 -- A running X Server with **XCB** and **X11-SHM** extentions 24 +### Rust crates.
41 25
42 -## Dependencies 26 +- easel3d (from parent directory)
  27 +- libc >=0.2
  28 +- xcb >=0.8
43 29
44 -... 30 +Along with the dependencies of the xcb crate. `cargo build` should take care
  31 +of having them available.
45 32
46 ## Contributing 33 ## Contributing
47 34
1 -# This file is automatically @generated by Cargo.  
2 -# It is not intended for manual editing.  
3 -[[package]]  
4 -name = "branches"  
5 -version = "0.1.0"  
6 -  
1 -[package]  
2 -name = "branches"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  
8 -  
9 -[dependencies]  
1 -//  
2 -// Control Flow Examples  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -  
22 -fn main() {  
23 - let condition = true;  
24 - let number = if condition {  
25 - 5  
26 - } else {  
27 - 6  
28 - };  
29 -  
30 - println!("The value of number is: {}", number);  
31 -}  
No preview for this file type
1 -[package]  
2 -name = "fractional"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -[dependencies]  
8 -lazy_static = "1.4.0"  
9 -libc = "0.2"  
10 -gl = "0.5.2"  
11 -x11 = { version = "2.3", features = ["glx"] }  
12 -xcb = { version = "0.8", features = ["dri2", "randr", "thread", "xlib_xcb", "shm"] }  
No preview for this file type
1 -http://www.jongware.com/galaxy1.html  
1 -I really would like to see a HTML5 canvas as canvas for the 3D code.  
2 -  
3 -Some URLs:  
4 -- https://stackoverflow.com/questions/42806037/modify-canvas-from-wasm  
5 -- https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.HtmlCanvasElement.html  
6 -- https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.CanvasRenderingContext2d.html  
7 -- https://stackoverflow.com/questions/49935207/editing-canvas-pixel-data-in-webassembly-rust  
1 -https://www.themathpage.com/Alg/reciprocals.htm  
No preview for this file type
No preview for this file type
1 -https://en.wikipedia.org/wiki/Texture_mapping  
2 -http://www.gamers.org/dEngine/quake/papers/checker_texmap.html  
3 -https://www.cs.uic.edu/~jbell/CourseNotes/ComputerGraphics/TextureMapping.html  
4 -http://www.decew.net/OSS/References/chapter_2_texture_mapping.pdf  
5 -  
6 -# example affine texture mapping  
7 -http://archive.gamedev.net/archive/reference/articles/article852.html  
8 -  
9 -  
10 -http://www.lysator.liu.se/~mikaelk/doc/perspectivetexture/  
11 -  
12 -# Shader... This also describes z-Buffer... :)  
13 -https://people.ece.cornell.edu/land/OldStudentProjects/cs490-95to96/GUO/report.html  
14 -https://software.intel.com/en-us/articles/the-basics-of-the-art-of-lighting-part-3-lighting-and-shaders/  
15 -https://docs.unity3d.com/Manual/Lighting.html  
1 -//  
2 -// A «continued fraction» is a representation of a fraction as a vector  
3 -// of integrals… Irrational fractions will result in infinite most of the  
4 -// time repetitive vectors. They can be used to get a resonable approximation  
5 -// for sqrt on fractionals.  
6 -//  
7 -// Georg Hopp <georg@steffers.org>  
8 -//  
9 -// Copyright © 2019 Georg Hopp  
10 -//  
11 -// This program is free software: you can redistribute it and/or modify  
12 -// it under the terms of the GNU General Public License as published by  
13 -// the Free Software Foundation, either version 3 of the License, or  
14 -// (at your option) any later version.  
15 -//  
16 -// This program is distributed in the hope that it will be useful,  
17 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
18 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
19 -// GNU General Public License for more details.  
20 -//  
21 -// You should have received a copy of the GNU General Public License  
22 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
23 -//  
24 -use crate::Fractional;  
25 -  
26 -#[derive(Debug)]  
27 -pub struct Continuous (Vec<i64>);  
28 -  
29 -impl Continuous {  
30 - // calculate a sqrt as continued fraction sequence. Taken from:  
31 - // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#  
32 - // Continued_fraction_expansion  
33 - pub fn sqrt(x :i64, a0 :i64) -> Self {  
34 - fn inner(v :&mut [i64], x :i64, a0 :i64, mn :i64, dn :i64, an :i64) {  
35 - let mn_1 = dn * an - mn;  
36 - let dn_1 = (x - mn_1 * mn_1) / dn;  
37 - let an_1 = (a0 + mn_1) / dn_1;  
38 -  
39 - v[0] = an;  
40 - // The convergence criteria „an_1 == 2 * a0“ is not good for  
41 - // very small x thus I decided to break the iteration at constant  
42 - // time. Which is the 5 below.  
43 - if v.len() > 1 {  
44 - inner(&mut v[1..], x, a0, mn_1, dn_1, an_1);  
45 - }  
46 - }  
47 -  
48 - let mut v :Vec<i64> = vec!(0; 5);  
49 - inner(&mut v, x, a0, 0, 1, a0);  
50 - Continuous(v)  
51 - }  
52 -  
53 - // general continous fraction form of a fractional...  
54 - pub fn from_prec(f :&Fractional, prec :Option<usize>) -> Self {  
55 - fn inner(v :&mut Vec<i64>, f :Fractional, prec :Option<usize>) {  
56 - let mut process = |prec :Option<usize>| {  
57 - let Fractional(n, d) = f;  
58 - let a = n / d;  
59 - let Fractional(_n, _d) = f.noreduce_sub(a.into());  
60 -  
61 - v.push(a);  
62 - match _n {  
63 - 1 => v.push(_d),  
64 - 0 => {},  
65 - _ => inner(v, Fractional(_d, _n), prec),  
66 - }  
67 - };  
68 -  
69 - match prec {  
70 - Some(0) => {},  
71 - None => process(None),  
72 - Some(p) => process(Some(p - 1)),  
73 - }  
74 - }  
75 -  
76 - let mut v = match prec {  
77 - None => Vec::with_capacity(100),  
78 - Some(p) => Vec::with_capacity(p + 1),  
79 - };  
80 -  
81 - inner(&mut v, *f, prec);  
82 - Continuous(v)  
83 - }  
84 -  
85 - pub fn into_prec(&self, prec :Option<usize>) -> Fractional {  
86 - let Continuous(c) = self;  
87 - let p = match prec {  
88 - Some(p) => if p <= c.len() { p } else { c.len() },  
89 - None => c.len(),  
90 - };  
91 -  
92 - let to_frac = |acc :Fractional, x :&i64| {  
93 - let Fractional(an, ad) = acc.noreduce_add((*x).into());  
94 - Fractional(ad, an)  
95 - };  
96 -  
97 - let Fractional(n, d) = c[..p]  
98 - . into_iter()  
99 - . rev()  
100 - . fold(Fractional(0, 1), to_frac);  
101 - Fractional(d, n)  
102 - }  
103 -}  
104 -  
105 -impl From<&Fractional> for Continuous {  
106 - fn from(x :&Fractional) -> Self {  
107 - Self::from_prec(x, None)  
108 - }  
109 -}  
110 -  
111 -impl Into<Fractional> for &Continuous {  
112 - fn into(self) -> Fractional {  
113 - (&self).into_prec(None)  
114 - }  
115 -}  
1 -//  
2 -// This is an abstraction over a drawing environment.  
3 -// Future note: z-Buffer is described here:  
4 -// https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes  
5 -//  
6 -// Georg Hopp <georg@steffers.org>  
7 -//  
8 -// Copyright © 2019 Georg Hopp  
9 -//  
10 -// This program is free software: you can redistribute it and/or modify  
11 -// it under the terms of the GNU General Public License as published by  
12 -// the Free Software Foundation, either version 3 of the License, or  
13 -// (at your option) any later version.  
14 -//  
15 -// This program is distributed in the hope that it will be useful,  
16 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
17 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
18 -// GNU General Public License for more details.  
19 -//  
20 -// You should have received a copy of the GNU General Public License  
21 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
22 -//  
23 -use std::cmp;  
24 -use std::fmt::{Formatter, Debug, Display, Result};  
25 -use std::ops::{Add, Sub, Div};  
26 -use std::sync::mpsc;  
27 -  
28 -pub trait Easel {  
29 - //fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>;  
30 -}  
31 -  
32 -pub trait Canvas<T> {  
33 - fn init_events(&self);  
34 - fn start_events(&self, tx :mpsc::Sender<i32>);  
35 -  
36 - fn width(&self) -> u16;  
37 - fn height(&self) -> u16;  
38 -  
39 - fn clear(&mut self);  
40 - fn draw(&mut self, c :&dyn Drawable<T>, ofs :Coordinate<T>, color :u32);  
41 - fn put_text(&self, ofs :Coordinate<T>, s :&str);  
42 - fn set_pixel(&mut self, c :Coordinate<T>, color :u32);  
43 - fn show(&self);  
44 -}  
45 -  
46 -pub trait Drawable<T> {  
47 - fn plot(&self) -> Coordinates<T>;  
48 -}  
49 -  
50 -pub trait Fillable<T>  
51 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
52 - + Debug + Copy + From<i32> {  
53 - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32);  
54 -}  
55 -  
56 -#[derive(Debug, Clone, Copy)]  
57 -pub struct Coordinate<T>(pub i32, pub i32, pub T);  
58 -  
59 -#[derive(Debug, Clone)]  
60 -pub struct Coordinates<T>(pub Vec<Coordinate<T>>);  
61 -  
62 -#[derive(Debug, Clone, Copy)]  
63 -pub struct LineIterator<T> where T: Debug {  
64 - a :Option<Coordinate<T>>  
65 - , b :Coordinate<T>  
66 - , dx :i32  
67 - , dy :i32  
68 - , dz :T  
69 - , sx :i32  
70 - , sy :i32  
71 - , err :i32  
72 - , only_edges :bool  
73 -}  
74 -  
75 -impl<T> Iterator for LineIterator<T>  
76 -where T: Add<Output = T> + Debug + Copy + From<i32> {  
77 - type Item = Coordinate<T>;  
78 -  
79 - fn next(&mut self) -> Option<Self::Item> {  
80 - match self.a {  
81 - None => None,  
82 - Some(a) => {  
83 - let Coordinate(ax, ay, az) = a;  
84 - let Coordinate(bx, by, _) = self.b;  
85 -  
86 - if ax != bx || ay != by {  
87 - match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) {  
88 - (true, false) => {  
89 - let r = self.a;  
90 - self.a = Some(Coordinate( ax + self.sx  
91 - , ay  
92 - , az + self.dz ));  
93 - self.err = self.err + self.dy;  
94 - if self.only_edges { self.next() } else { r }  
95 - },  
96 - (false, true) => {  
97 - let r = self.a;  
98 - self.a = Some(Coordinate( ax  
99 - , ay + self.sy  
100 - , az + self.dz ));  
101 - self.err = self.err + self.dx;  
102 - r  
103 - },  
104 - _ => {  
105 - let r = self.a;  
106 - self.a = Some(Coordinate( ax + self.sx  
107 - , ay + self.sy  
108 - , az + self.dz ));  
109 - self.err = self.err + self.dx + self.dy;  
110 - r  
111 - },  
112 - }  
113 - } else {  
114 - self.a = None;  
115 - Some(self.b)  
116 - }  
117 - }  
118 - }  
119 - }  
120 -}  
121 -  
122 -impl<T> Coordinate<T>  
123 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
124 - + Debug + Clone + Copy + From<i32> {  
125 - fn iter(self, b :&Self, only_edges :bool) -> LineIterator<T> {  
126 - let Coordinate(ax, ay, az) = self;  
127 - let Coordinate(bx, by, bz) = *b;  
128 -  
129 - let dx = (bx - ax).abs();  
130 - let dy = -(by - ay).abs();  
131 -  
132 - LineIterator { a: Some(self)  
133 - , b: *b  
134 - , dx: dx  
135 - , dy: dy  
136 - , dz: (bz - az) / cmp::max(dx, -dy).into()  
137 - , sx: if ax < bx { 1 } else { -1 }  
138 - , sy: if ay < by { 1 } else { -1 }  
139 - , err: dx + dy  
140 - , only_edges: only_edges  
141 - }  
142 - }  
143 -  
144 - fn line_iter(self, b :&Self) -> LineIterator<T> {  
145 - self.iter(b, false)  
146 - }  
147 -  
148 - fn line(self, b :&Self) -> Vec<Self> {  
149 - self.line_iter(b).collect()  
150 - }  
151 -  
152 - fn edge_iter(self, b :&Self) -> LineIterator<T> {  
153 - self.iter(b, true)  
154 - }  
155 -  
156 - fn edge(self, b :&Self) -> Vec<Self> {  
157 - self.edge_iter(b).collect()  
158 - }  
159 -  
160 - fn face(edges :&[Self]) -> Vec<Self> {  
161 - edges.to_vec()  
162 - }  
163 -}  
164 -  
165 -impl<T> Display for Coordinate<T> {  
166 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
167 - write!(f, "<{},{}>", self.0, self.1)  
168 - }  
169 -}  
170 -  
171 -impl<T> Display for Coordinates<T> where T: Copy {  
172 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
173 - let Coordinates(is) = self;  
174 -  
175 - let c = match is[..] {  
176 - [] => String::from(""),  
177 - [a] => format!("{}", a),  
178 - _ => {  
179 - let mut a = format!("{}", is[0]);  
180 - for i in is[1..].iter() {  
181 - a = a + &format!(",{}", i);  
182 - }  
183 - a  
184 - }  
185 - };  
186 -  
187 - write!(f, "Coordinates[{}]", c)  
188 - }  
189 -}  
190 -  
191 -  
192 -#[derive(Debug, Clone, Copy)]  
193 -pub struct Point<T>(pub Coordinate<T>);  
194 -  
195 -impl<T> Drawable<T> for Point<T> where T: Copy {  
196 - fn plot(&self) -> Coordinates<T> {  
197 - let Point(c) = *self;  
198 - Coordinates(vec!(c))  
199 - }  
200 -}  
201 -  
202 -impl<T> Display for Point<T> {  
203 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
204 - let Point(p) = self;  
205 - write!(f, "Point[{}]", p)  
206 - }  
207 -}  
208 -  
209 -#[derive(Debug, Clone, Copy)]  
210 -pub struct Line<T>(pub Coordinate<T>, pub Coordinate<T>);  
211 -  
212 -impl<T> Drawable<T> for Line<T>  
213 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
214 - + Debug + Clone + Copy + From<i32> {  
215 - fn plot(&self) -> Coordinates<T> {  
216 - let Line(a, b) = *self;  
217 - Coordinates(a.line(&b))  
218 - }  
219 -}  
220 -  
221 -impl<T> Display for Line<T> {  
222 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
223 - let Line(a, b) = self;  
224 - write!(f, "Line[{},{}]", a, b)  
225 - }  
226 -}  
227 -  
228 -#[derive(Debug, Clone)]  
229 -pub struct Polyline<T>(pub Coordinates<T>);  
230 -  
231 -impl<T> Drawable<T> for Polyline<T>  
232 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
233 - + Debug + Clone + Copy + From<i32> {  
234 - fn plot(&self) -> Coordinates<T> {  
235 - let Polyline(Coordinates(cs)) = self;  
236 -  
237 - match cs[..] {  
238 - [] => Coordinates(Vec::<Coordinate<T>>::new()),  
239 - [a] => Coordinates(vec!(a)),  
240 - [a, b] => Coordinates(a.line(&b)),  
241 - _ => {  
242 - let (a, b) = (cs[0], cs[1]);  
243 - let mut r = a.line(&b);  
244 - let mut i = b;  
245 - for j in cs[2..].iter() {  
246 - r.append(&mut i.line(j)[1..].to_vec());  
247 - i = *j;  
248 - }  
249 - Coordinates(r)  
250 - },  
251 - }  
252 - }  
253 -}  
254 -  
255 -impl<T> Display for Polyline<T> where T: Copy {  
256 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
257 - let Polyline(a) = self;  
258 - write!(f, "PLine[{}]", a)  
259 - }  
260 -}  
261 -  
262 -#[derive(Debug, Clone, Copy)]  
263 -enum Direction { Left, Right }  
264 -  
265 -#[derive(Debug, Clone)]  
266 -pub struct Polygon<T>(pub Coordinates<T>);  
267 -  
268 -#[derive(Debug, Clone)]  
269 -enum VertexIteratorMode { Vertex, Edge }  
270 -#[derive(Debug, Clone)]  
271 -pub struct VertexIterator<'a,T> where T: Debug {  
272 - p :&'a Polygon<T>,  
273 - top :usize,  
274 - current :Option<usize>,  
275 - edge :Option<LineIterator<T>>,  
276 - mode :VertexIteratorMode,  
277 - direction :Direction,  
278 -}  
279 -  
280 -impl<'a,T> VertexIterator<'a,T>  
281 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
282 - + Debug + Copy + From<i32> {  
283 - fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {  
284 - let top = p.vert_min(direction);  
285 - let next = p.next_y(top, direction);  
286 - let edge = match next {  
287 - None => None,  
288 - Some(next) => Some(p.vertex(top).edge_iter(&p.vertex(next))),  
289 - };  
290 -  
291 - VertexIterator { p: p  
292 - , top: top  
293 - , current: next  
294 - , edge: edge  
295 - , mode: VertexIteratorMode::Edge  
296 - , direction: direction }  
297 - }  
298 -  
299 - fn vertex(p :&'a Polygon<T>, direction :Direction) -> Self {  
300 - let top = p.vert_min(direction);  
301 - let next = p.next_y(top, direction);  
302 -  
303 - VertexIterator { p: p  
304 - , top: top  
305 - , current: next  
306 - , edge: None  
307 - , mode: VertexIteratorMode::Vertex  
308 - , direction: direction }  
309 - }  
310 -  
311 - // if this yields "None" we are finished.  
312 - fn next_edge(&mut self) -> Option<LineIterator<T>> {  
313 - let current = self.current?;  
314 - let next = self.p.next_y(current, self.direction)?;  
315 - let mut edge = self.p.vertex(current).edge_iter(&self.p.vertex(next));  
316 -  
317 - match edge.next() {  
318 - // It should be impossible that a new edge iterator has no values  
319 - // at all… anyway, just in case I handle it here.  
320 - None => self.next_edge(),  
321 - Some(_) => {  
322 - self.current = Some(next);  
323 - self.edge = Some(edge);  
324 - self.edge  
325 - },  
326 - }  
327 - }  
328 -}  
329 -  
330 -impl<'a,T> Iterator for VertexIterator<'a,T>  
331 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
332 - + Debug + Copy + From<i32> {  
333 - type Item = Coordinate<T>;  
334 -  
335 - fn next(&mut self) -> Option<Self::Item> {  
336 - match self.mode {  
337 - VertexIteratorMode::Edge => {  
338 - // if for whatever reason edge is "None" finish this iterator.  
339 - let next = self.edge.as_mut()?.next();  
340 -  
341 - match next {  
342 - Some(_) => next,  
343 - None => {  
344 - self.next_edge()?;  
345 - self.next()  
346 - },  
347 - }  
348 - },  
349 - VertexIteratorMode::Vertex => {  
350 - let current = self.current?;  
351 - self.current = self.p.next_y(current, self.direction);  
352 - Some(self.p.vertex(current))  
353 - },  
354 - }  
355 - }  
356 -}  
357 -  
358 -impl<T> Polygon<T>  
359 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
360 - + Copy + Debug + From<i32> {  
361 - #[inline]  
362 - fn vertex(&self, v :usize) -> Coordinate<T> {  
363 - let Polygon(Coordinates(cs)) = self;  
364 - cs[v]  
365 - }  
366 -  
367 - fn vert_min<'a>(&'a self, d :Direction) -> usize {  
368 - let Polygon(Coordinates(cs)) = self;  
369 -  
370 - type ICoord<'a,T> = (usize, &'a Coordinate<T>);  
371 -  
372 - // TODO I guess the problem here is that it does not account for the  
373 - // same y vertex on the beggining and the end. So i guess correct  
374 - // would be finding the first one and then dependings on the  
375 - // given direction either search left or right for same y's.  
376 - let fold = |acc :Option<ICoord<'a,T>>, x :ICoord<'a,T>|  
377 - match acc {  
378 - None => Some(x),  
379 - Some(a) => {  
380 - let Coordinate(_, ay, _) = a.1;  
381 - let Coordinate(_, xy, _) = x.1;  
382 - if xy < ay {Some(x)} else {Some(a)}  
383 - },  
384 - };  
385 -  
386 - let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0;  
387 - let mut next = self.step(min, d);  
388 -  
389 - while self.vertex(min).1 == self.vertex(next).1 {  
390 - min = next;  
391 - next = self.step(min, d);  
392 - }  
393 -  
394 - min  
395 - }  
396 -  
397 - fn left_edge(&self) -> VertexIterator<T> {  
398 - VertexIterator::edge(self, Direction::Left)  
399 - }  
400 -  
401 - fn right_edge(&self) -> VertexIterator<T> {  
402 - VertexIterator::edge(self, Direction::Right)  
403 - }  
404 -  
405 - fn left_vertices(&self) -> VertexIterator<T> {  
406 - VertexIterator::vertex(self, Direction::Left)  
407 - }  
408 -  
409 - fn right_vertices(&self) -> VertexIterator<T> {  
410 - VertexIterator::vertex(self, Direction::Right)  
411 - }  
412 -  
413 - fn left(&self, v :usize) -> usize {  
414 - let Polygon(Coordinates(cs)) = self;  
415 -  
416 - match v {  
417 - 0 => cs.len() - 1,  
418 - _ => v - 1,  
419 - }  
420 - }  
421 -  
422 - fn right(&self, v :usize) -> usize {  
423 - let Polygon(Coordinates(cs)) = self;  
424 -  
425 - (v + 1) % cs.len()  
426 - }  
427 -  
428 - fn step(&self, v :usize, d :Direction) -> usize {  
429 - match d {  
430 - Direction::Left => self.left(v),  
431 - Direction::Right => self.right(v),  
432 - }  
433 - }  
434 -  
435 - fn next_y(&self, c :usize, d :Direction) -> Option<usize> {  
436 - fn inner<T>( p :&Polygon<T>  
437 - , c :usize  
438 - , n :usize  
439 - , d :Direction) -> Option<usize>  
440 - where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
441 - + Copy + Debug + From<i32> {  
442 - if c == n {  
443 - None  
444 - } else {  
445 - let Coordinate(_, cy, _) = p.vertex(c);  
446 - let Coordinate(_, ny, _) = p.vertex(n);  
447 -  
448 - if ny < cy { None } else { Some(n) }  
449 - }  
450 - }  
451 -  
452 - inner(self, c, self.step(c, d), d)  
453 - }  
454 -  
455 - pub fn debug(&self) {  
456 - let mut left = self.left_vertices();  
457 - let mut right = self.right_vertices();  
458 -  
459 - if left.find(|l| right.find(|r| l.0 == r.0).is_some()).is_some() {  
460 - let left :Vec<Coordinate<T>> = self.left_vertices().collect();  
461 - let right :Vec<Coordinate<T>> = self.right_vertices().collect();  
462 -  
463 - println!("===");  
464 - println!("== poly : {:?}", self);  
465 - println!("== ltop : {:?}", self.vert_min(Direction::Left));  
466 - println!("== rtop : {:?}", self.vert_min(Direction::Right));  
467 - println!("== left : {:?}", left);  
468 - println!("== right : {:?}", right);  
469 - println!("===");  
470 - }  
471 - }  
472 -}  
473 -  
474 -impl<T> Drawable<T> for Polygon<T>  
475 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
476 - + Debug + Clone + Copy + From<i32> {  
477 - fn plot(&self) -> Coordinates<T> {  
478 - let Polygon(Coordinates(cs)) = self;  
479 -  
480 - match cs[..] {  
481 - [] => Coordinates(Vec::<Coordinate<T>>::new()),  
482 - [a] => Coordinates(vec!(a)),  
483 - [a, b] => Coordinates(a.line(&b)),  
484 - _ => {  
485 - let (a, b) = (cs[0], cs[1]);  
486 - let mut r = a.line(&b);  
487 - let mut i = b;  
488 - for j in cs[2..].iter() {  
489 - r.append(&mut i.line(j)[1..].to_vec());  
490 - i = *j;  
491 - }  
492 - let mut j = a.line(&i);  
493 - let l = j.len();  
494 - if l > 1 {  
495 - r.append(&mut j[1..l-1].to_vec());  
496 - }  
497 - Coordinates(r)  
498 - },  
499 - }  
500 - }  
501 -}  
502 -  
503 -impl<T> Fillable<T> for Polygon<T>  
504 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
505 - + Debug + Clone + Copy + From<i32> {  
506 - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) {  
507 - let scanlines = self.left_edge().zip(self.right_edge());  
508 -  
509 - for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) {  
510 - canvas.set_pixel(l, color);  
511 - }  
512 - }  
513 -}  
514 -  
515 -impl<T> Display for Polygon<T> where T: Copy {  
516 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
517 - let Polygon(a) = self;  
518 - write!(f, "Poly[{}]", a)  
519 - }  
520 -}  
1 -//  
2 -// Some code to support fractional numbers for full precision rational number  
3 -// calculations. (At least for the standard operations.)  
4 -// This also implements a sqrt on fractional numbers, which can not be precise  
5 -// because of the irrational nature of most sqare roots.  
6 -// Fractions can only represent rational numbers precise.  
7 -//  
8 -// Georg Hopp <georg@steffers.org>  
9 -//  
10 -// Copyright © 2019 Georg Hopp  
11 -//  
12 -// This program is free software: you can redistribute it and/or modify  
13 -// it under the terms of the GNU General Public License as published by  
14 -// the Free Software Foundation, either version 3 of the License, or  
15 -// (at your option) any later version.  
16 -//  
17 -// This program is distributed in the hope that it will be useful,  
18 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
19 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
20 -// GNU General Public License for more details.  
21 -//  
22 -// You should have received a copy of the GNU General Public License  
23 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
24 -//  
25 -use std::cmp::Ordering;  
26 -use std::convert::{TryFrom, TryInto};  
27 -use std::fmt::{Formatter, Display};  
28 -use std::num::TryFromIntError;  
29 -use std::ops::{Add,Sub,Neg,Mul,Div};  
30 -  
31 -use crate::continuous::Continuous;  
32 -  
33 -#[derive(Debug, Eq, Clone, Copy)]  
34 -pub struct Fractional (pub i64, pub i64);  
35 -  
36 -#[inline]  
37 -fn hcf(x :i64, y :i64) -> i64 {  
38 - match y {  
39 - 0 => x,  
40 - _ => hcf(y, x % y),  
41 - }  
42 -}  
43 -  
44 -pub fn from_vector(xs: &Vec<i64>) -> Vec<Fractional> {  
45 - xs.iter().map(|x| Fractional(*x, 1)).collect()  
46 -}  
47 -  
48 -impl Fractional {  
49 - #[inline]  
50 - pub fn gcd(self, other: Self) -> i64 {  
51 - let Fractional(_, d1) = self;  
52 - let Fractional(_, d2) = other;  
53 - (d1 * d2) / hcf(d1, d2)  
54 - }  
55 -  
56 - #[inline]  
57 - pub fn reduce(self) -> Self {  
58 - let Fractional(n, d) = self;  
59 - let (_n, _d) = if n > d { (n, d) } else { (d, n) };  
60 -  
61 - // if the difference from _n % _d to _n is very big we are close to  
62 - // a whole number and can ignore the fractional part... this reduces  
63 - // the precision but ensures smaller numbers for numerator and  
64 - // denominator.  
65 - if _d > 1 && (_n % _d) * 10000000 < _n {  
66 - if n == _n {  
67 - Self(_n / _d, 1)  
68 - } else {  
69 - Self(1, _n / _d)  
70 - }  
71 - } else {  
72 - // Self(n / hcf(n, d), d / hcf(n, d))  
73 - // The above reduces prcisely but results in very large numerator  
74 - // or denominator occasionally. The below is less precise but  
75 - // keeps the numbers small… the bad point is, that it is not very  
76 - // fast.  
77 - let cont = Continuous::from_prec(&self, Some(5));  
78 - (&cont).into()  
79 - }  
80 - }  
81 -  
82 - pub fn noreduce_add(self, other: Self) -> Self {  
83 - let Fractional(n1, d1) = self;  
84 - let Fractional(n2, d2) = other;  
85 - let n = n1 * (self.gcd(other) / d1) + n2 * (self.gcd(other) / d2);  
86 - Self(n, self.gcd(other))  
87 - }  
88 -  
89 - pub fn noreduce_sub(self, other: Self) -> Self {  
90 - self.noreduce_add(other.noreduce_neg())  
91 - }  
92 -  
93 - pub fn noreduce_neg(self) -> Self {  
94 - let Fractional(n, d) = self;  
95 - Self(-n, d)  
96 - }  
97 -}  
98 -  
99 -impl From<i64> for Fractional {  
100 - fn from(x: i64) -> Self {  
101 - Self(x, 1)  
102 - }  
103 -}  
104 -  
105 -impl From<i32> for Fractional {  
106 - fn from(x: i32) -> Self {  
107 - Self(x as i64, 1)  
108 - }  
109 -}  
110 -  
111 -impl TryFrom<usize> for Fractional {  
112 - type Error = &'static str;  
113 -  
114 - fn try_from(x: usize) -> Result<Self, Self::Error> {  
115 - let v = i64::try_from(x);  
116 - match v {  
117 - Err(_) => Err("Conversion from usize to i32 failed"),  
118 - Ok(_v) => Ok(Self(_v, 1)),  
119 - }  
120 - }  
121 -}  
122 -  
123 -impl TryInto<f64> for Fractional {  
124 - type Error = TryFromIntError;  
125 -  
126 - fn try_into(self) -> Result<f64, Self::Error> {  
127 - let n :i32 = self.0.try_into()?;  
128 - let d :i32 = self.1.try_into()?;  
129 - Ok(f64::from(n) / f64::from(d))  
130 - }  
131 -}  
132 -  
133 -impl TryInto<(i32, i32)> for Fractional {  
134 - type Error = TryFromIntError;  
135 -  
136 - fn try_into(self) -> Result<(i32, i32), Self::Error> {  
137 - let a :i32 = (self.0 / self.1).try_into()?;  
138 - let b :i32 = (self.0 % self.1).try_into()?;  
139 - Ok((a, b))  
140 - }  
141 -}  
142 -  
143 -impl Display for Fractional {  
144 - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {  
145 - write!(f, "({}/{})", self.0, self.1)  
146 - }  
147 -}  
148 -  
149 -impl PartialEq for Fractional {  
150 - fn eq(&self, other: &Self) -> bool {  
151 - let Fractional(n1, d1) = self;  
152 - let Fractional(n2, d2) = other;  
153 - n1 * (self.gcd(*other) / d1) == n2 * (self.gcd(*other) / d2)  
154 - }  
155 -}  
156 -  
157 -impl PartialOrd for Fractional {  
158 - fn partial_cmp(&self, other: &Self) -> Option<Ordering> {  
159 - Some(self.cmp(other))  
160 - }  
161 -}  
162 -  
163 -impl Ord for Fractional {  
164 - fn cmp(&self, other: &Self) -> Ordering {  
165 - let Fractional(n1, d1) = self;  
166 - let Fractional(n2, d2) = other;  
167 - let x = n1 * (self.gcd(*other) / d1);  
168 - let y = n2 * (self.gcd(*other) / d2);  
169 - x.cmp(&y)  
170 - }  
171 -}  
172 -  
173 -impl Add for Fractional {  
174 - type Output = Self;  
175 -  
176 - fn add(self, other: Self) -> Self {  
177 - self.noreduce_add(other).reduce()  
178 - }  
179 -}  
180 -  
181 -impl Sub for Fractional {  
182 - type Output = Self;  
183 -  
184 - fn sub(self, other: Self) -> Self {  
185 - self + -other  
186 - }  
187 -}  
188 -  
189 -impl Neg for Fractional {  
190 - type Output = Self;  
191 -  
192 - fn neg(self) -> Self {  
193 - let Fractional(n, d) = self;  
194 - Self(-n, d)  
195 - }  
196 -}  
197 -  
198 -impl Mul for Fractional {  
199 - type Output = Self;  
200 -  
201 - fn mul(self, other :Self) -> Self {  
202 - let Fractional(n1, d1) = self;  
203 - let Fractional(n2, d2) = other;  
204 - Self(n1 * n2, d1 * d2).reduce()  
205 - }  
206 -}  
207 -  
208 -impl Div for Fractional {  
209 - type Output = Self;  
210 -  
211 - fn div(self, other: Self) -> Self {  
212 - let Fractional(n, d) = other;  
213 - self * Fractional(d, n)  
214 - }  
215 -}  
216 -  
217 - /* some stuff that could be tested...  
218 - let x = Fractional(1, 3);  
219 - let y = Fractional(1, 6);  
220 -  
221 - println!(  
222 - "Greatest common denominator of {} and {}: {}", x, y, x.gcd(y));  
223 - println!("Numerator of {}: {}", x, x.numerator());  
224 - println!("Denominator of {}: {}", x, x.denominator());  
225 - assert_eq!(Fractional(1, 3), Fractional(2, 6));  
226 - assert_eq!(Fractional(1, 3), Fractional(1, 3));  
227 - assert_eq!(y < x, true);  
228 - assert_eq!(y > x, false);  
229 - assert_eq!(x == y, false);  
230 - assert_eq!(x == x, true);  
231 - assert_eq!(x + y, Fractional(1, 2));  
232 - println!("{} + {} = {}", x, y, x + y);  
233 - assert_eq!(x - y, Fractional(1, 6));  
234 - println!("{} - {} = {}", x, y, x - y);  
235 - assert_eq!(y - x, Fractional(-1, 6));  
236 - println!("{} - {} = {}", y, x, y - x);  
237 - assert_eq!(-x, Fractional(-1, 3));  
238 - println!("-{} = {}", x, -x);  
239 - assert_eq!(x * y, Fractional(1, 18));  
240 - println!("{} * {} = {}", x, y, x * y);  
241 - assert_eq!(x / y, Fractional(2, 1));  
242 - println!("{} / {} = {}", x, y, x / y);  
243 - assert_eq!(y / x, Fractional(1, 2));  
244 - println!("{} / {} = {}", y, x, y / x);  
245 -  
246 - println!("Fractional from 3: {}", Fractional::from(3));  
247 - let z :f64 = Fractional::into(x);  
248 - println!("Floating point of {}: {}", x, z);  
249 - let (d, r) = Fractional::into(x);  
250 - println!("(div, rest) of {}: ({}, {})", x, d, r);  
251 - */  
252 -  
1 -//  
2 -// Basic geometric things...  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -use std::convert::{From, Into};  
22 -use std::ops::{Add,Sub,Neg,Mul,Div};  
23 -use std::fmt::Debug;  
24 -  
25 -use crate::easel::{Canvas, Coordinate, Coordinates, Polygon};  
26 -use crate::transform::{TMatrix, Transformable};  
27 -use crate::trigonometry::Trig;  
28 -use crate::vector::Vector;  
29 -  
30 -#[derive(Debug, Clone)]  
31 -pub struct Face<T>  
32 -where T: Add + Sub + Neg + Mul + Div + Copy + Trig {  
33 - corners :Vec<usize>,  
34 - normal :Option<Vector<T>>,  
35 -}  
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 -  
140 -#[derive(Debug)]  
141 -pub struct Polyeder<T>  
142 -where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {  
143 - points :Vec<Point<T>>,  
144 - faces :Vec<Face<T>>,  
145 -}  
146 -  
147 -pub trait Primitives<T>  
148 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
149 - fn transform(&self, m :&TMatrix<T>) -> Self;  
150 - fn project( &self  
151 - , camera :&Camera<T>  
152 - , light :&DirectLight<T>  
153 - , col :u32 ) -> Vec<(Polygon<T>, u32)>;  
154 -}  
155 -  
156 -pub struct Camera<T>  
157 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
158 - width :T,  
159 - height :T,  
160 - distance :T,  
161 - project :TMatrix<T>,  
162 -}  
163 -  
164 -pub struct DirectLight<T>  
165 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
166 - direction: Vector<T>,  
167 -}  
168 -  
169 -impl<T> Camera<T>  
170 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
171 - + Mul<Output = T> + Div<Output = T>  
172 - + PartialEq + Debug + Copy + Trig + From<i32> {  
173 - // This code assumes that the size of the viewport is always  
174 - // equal to the size of the physical screen… e.g. window/canvas thus some  
175 - // effects can't be done. See book for examples with different viewport  
176 - // and screen sizes.  
177 - pub fn new(c :&dyn Canvas<T>, angle :i32) -> Self {  
178 - let width :T = (c.width() as i32).into();  
179 - let height :T = (c.height() as i32).into();  
180 - let d :T = 1.into();  
181 - let fov = T::cot(angle) * width;  
182 - let wh = width / 2.into();  
183 - let hh = height / 2.into();  
184 -  
185 - Camera { width: width  
186 - , height: height  
187 - , distance: d  
188 - , project: TMatrix::new(  
189 - ( fov, 0.into(), wh, 0.into())  
190 - , (0.into(), fov, hh, 0.into())  
191 - , (0.into(), 0.into(), d, 1.into())  
192 - , (0.into(), 0.into(), 1.into(), 0.into()) ) }  
193 - }  
194 -  
195 - pub fn get_distance(&self) -> T {  
196 - self.distance  
197 - }  
198 -  
199 - pub fn get_projection(&self) -> TMatrix<T> {  
200 - self.project  
201 - }  
202 -  
203 - pub fn project(&self, p :Point<T>) -> Point<T> {  
204 - p.transform(&self.project)  
205 - }  
206 -}  
207 -  
208 -impl<T> DirectLight<T>  
209 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
210 - + Mul<Output = T> + Div<Output = T>  
211 - + Debug + Copy + Trig + From<i32> {  
212 - pub fn new(v :Vector<T>) -> Self {  
213 - DirectLight{ direction: v }  
214 - }  
215 -  
216 - pub fn dir(&self) -> Vector<T> {  
217 - self.direction  
218 - }  
219 -}  
220 -  
221 -impl<T> Face<T>  
222 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
223 - + Mul<Output = T> + Div<Output = T>  
224 - + PartialEq + Debug + Copy + Trig + From<i32> {  
225 - fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {  
226 - let mut f = Face{ corners: corners, normal: None };  
227 - f.update_normal(ps);  
228 - f  
229 - }  
230 -  
231 - fn update_normal(&mut self, ps :&[Point<T>]) {  
232 - let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();  
233 - let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();  
234 - self.normal = Some(edge10 * edge12);  
235 - }  
236 -}  
237 -  
238 -impl<T> Polyeder<T>  
239 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
240 - + Mul<Output = T> + Div<Output = T>  
241 - + PartialEq + Debug + Copy + Trig + From<i32> {  
242 - fn update_normals(&mut self) {  
243 - for f in self.faces.iter_mut() {  
244 - f.update_normal(&self.points);  
245 - }  
246 - }  
247 -  
248 - // construct via cube, see polyhedra.pdf  
249 - pub fn tetrahedron(a :T) -> Polyeder<T> {  
250 - let f2 :T = 2.into();  
251 - let ch = a / (f2 * T::sqrt(f2).unwrap());  
252 -  
253 - let ps = vec!( Point::new(-ch, -ch, ch) // A  
254 - , Point::new(-ch, ch, -ch) // C  
255 - , Point::new( ch, -ch, -ch) // E  
256 - , Point::new( ch, ch, ch) ); // G  
257 -  
258 - // bottom: 1, 2, 3  
259 - let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom  
260 - , Face::new(vec!(3, 2, 0), &ps)  
261 - , Face::new(vec!(0, 1, 3), &ps)  
262 - , Face::new(vec!(1, 2, 3), &ps) );  
263 - //let fs = vec!( Face::new(vec!(0, 1, 2), &ps) // bottom  
264 - // , Face::new(vec!(0, 2, 3), &ps)  
265 - // , Face::new(vec!(3, 1, 0), &ps)  
266 - // , Face::new(vec!(3, 2, 1), &ps) );  
267 -  
268 - Polyeder{ points: ps, faces: fs }  
269 - }  
270 -  
271 - pub fn triangle(a :T) -> Polyeder<T> {  
272 - let f0 :T = 0.into();  
273 - let f3 :T = 3.into();  
274 - let f6 :T = 6.into();  
275 - let zi :T = T::sqrt(f3).unwrap() / f6 * a;  
276 - let zc :T = T::sqrt(f3).unwrap() / f3 * a;  
277 - let ah :T = a / 2.into();  
278 -  
279 - let ps = vec!( Point::new(-ah, f0, -zi)  
280 - , Point::new( f0, f0, zc)  
281 - , Point::new( ah, f0, -zi) );  
282 -  
283 - let fs = vec!(Face::new(vec!(0, 1, 2), &ps));  
284 -  
285 - Polyeder{ points: ps, faces: fs }  
286 - }  
287 -  
288 - pub fn cube(a :T) -> Polyeder<T> {  
289 - let ah :T = a / From::<i32>::from(2);  
290 -  
291 - let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1  
292 - , Point::new(-ah, -ah, -ah) // 1 => front 2  
293 - , Point::new( ah, -ah, -ah) // 2 => front 3  
294 - , Point::new( ah, ah, -ah) // 3 => front 4  
295 - , Point::new(-ah, ah, ah) // 4 => back 1  
296 - , Point::new(-ah, -ah, ah) // 5 => back 2  
297 - , Point::new( ah, -ah, ah) // 6 => back 3  
298 - , Point::new( ah, ah, ah) ); // 7 => back 4  
299 -  
300 - let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front  
301 - , Face::new(vec!(7, 6, 5, 4), &ps) // back  
302 - , Face::new(vec!(1, 5, 6, 2), &ps) // top  
303 - , Face::new(vec!(0, 3, 7, 4), &ps) // bottom  
304 - , Face::new(vec!(0, 4, 5, 1), &ps) // left  
305 - , Face::new(vec!(2, 6, 7, 3), &ps) ); // right  
306 -  
307 - Polyeder{ points: ps, faces: fs }  
308 - }  
309 -}  
310 -  
311 -impl<T> Primitives<T> for Polyeder<T>  
312 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
313 - + Mul<Output = T> + Div<Output = T>  
314 - + Debug + Copy + Trig + From<i32> + PartialOrd {  
315 - // TODO Maybe this should also be an instance of Transformable…  
316 - fn transform(&self, m :&TMatrix<T>) -> Self {  
317 - let Polyeder{ points: ps, faces: fs } = self;  
318 -  
319 - let mut p = Polyeder{  
320 - points: ps.iter().map(|p| p.transform(m)).collect()  
321 - , faces: fs.to_vec()  
322 - };  
323 -  
324 - // TODO alternatively we could rotate the normals too, but this cannot  
325 - // done with the original matrix… the question is, what is faster.  
326 - p.update_normals();  
327 - p  
328 - }  
329 -  
330 - fn project( &self  
331 - , camera :&Camera<T>  
332 - , light :&DirectLight<T>  
333 - , color :u32 ) -> Vec<(Polygon<T>, u32)> {  
334 - // Helper to create a Polygon from Coordinates…  
335 - // TODO probably there needs to be a Polygon constructor for this.  
336 - fn polygon<I, T>(c :I) -> Polygon<T>  
337 - where I: Iterator<Item = Coordinate<T>> {  
338 - Polygon(Coordinates(c.collect()))  
339 - }  
340 -  
341 - // this one does the projection... as the projection was the last  
342 - // matrix we do not need to do it here.  
343 - let to_coord = |p :&usize| {  
344 - let Point(v, _) = camera.project(self.points[*p]);  
345 - Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())  
346 - };  
347 - let to_poly = |f :&Face<T>| {  
348 - let pg = polygon(f.corners.iter().map(to_coord));  
349 - let mut r :T = (((color >> 16) & 0xFF) as i32).into();  
350 - let mut g :T = (((color >> 8) & 0xFF) as i32).into();  
351 - let mut b :T = (((color ) & 0xFF) as i32).into();  
352 - let lf :T = match f.normal {  
353 - None => 1.into(),  
354 - Some(n) => n.dot(light.dir())  
355 - / (n.mag() * light.dir().mag()),  
356 - };  
357 -  
358 - // this "if" represents a first simple backface culling  
359 - // approach. We only return face that face towards us.  
360 - if lf < 0.into() {  
361 - r = r * -lf;  
362 - g = g * -lf;  
363 - b = b * -lf;  
364 -  
365 - let c :u32 = (r.round() as u32) << 16  
366 - | (g.round() as u32) << 8  
367 - | (b.round() as u32);  
368 -  
369 - Some((pg, c))  
370 - } else {  
371 - None  
372 - }};  
373 -  
374 - self.faces.iter().filter_map(to_poly).collect()  
375 - }  
376 -}  
1 -//  
2 -// Lib for fractional calculations.  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -extern crate lazy_static;  
22 -  
23 -pub type Error = &'static str;  
24 -  
25 -pub mod continuous;  
26 -pub mod easel;  
27 -pub mod fractional;  
28 -pub mod transform;  
29 -pub mod trigonometry;  
30 -pub mod vector;  
31 -pub mod xcb;  
32 -pub mod geometry;  
33 -  
34 -use fractional::Fractional;  
35 -use vector::Vector;  
1 -//  
2 -// Test our fractional crate / module...  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -use std::convert::{TryFrom, TryInto, Into};  
22 -use std::f64::consts::PI as FPI;  
23 -use std::fmt::{Debug, Display};  
24 -use std::marker::Send;  
25 -use std::num::TryFromIntError;  
26 -use std::ops::{Add,Sub,Neg,Mul,Div};  
27 -use std::sync::mpsc;  
28 -use std::thread;  
29 -use std::time::{Duration, Instant};  
30 -  
31 -use fractional::continuous::Continuous;  
32 -use fractional::easel::{ Coordinate, Coordinates, Drawable, Line, Polyline  
33 - , Polygon, Canvas, Fillable };  
34 -use fractional::fractional::{Fractional, from_vector};  
35 -use fractional::trigonometry::Trig;  
36 -use fractional::vector::Vector;  
37 -use fractional::transform::{TMatrix, Transformable};  
38 -use fractional::xcb::XcbEasel;  
39 -use fractional::geometry::{Camera, DirectLight, Polyeder, Primitives};  
40 -  
41 -fn mean(v: &Vec<i64>) -> Result<Fractional, TryFromIntError> {  
42 - let r = v.iter().fold(0, |acc, x| acc + x);  
43 - let l = i64::try_from(v.len())?;  
44 - Ok(Fractional(r, l))  
45 -}  
46 -  
47 -fn common_fractional() {  
48 - let a = vec![3, 6, 1, 9];  
49 - let b = from_vector(&a);  
50 - let c = mean(&a).unwrap(); // This might fail if the len of the  
51 - // vector (usize) does not fit into i32.  
52 - let cr :f64 = c.try_into().unwrap();  
53 -  
54 - println!(" [i32] : {:?}", a);  
55 - println!(" [Fractional] : {:?}", b);  
56 - println!(" mean of [i32] : {}" , c);  
57 - println!(" as f64 : {}" , cr);  
58 - println!(" again as f64 : {}" , TryInto::<f64>::try_into(c).unwrap());  
59 -}  
60 -  
61 -fn continuous() {  
62 - let d = Fractional(45, 16);  
63 - let e = Fractional(16, 45);  
64 -  
65 - let dc :Continuous = (&d).into();  
66 - let ec :Continuous = (&e).into();  
67 -  
68 - println!("cont frac of d : {} => {:?}", d, dc);  
69 - println!("cont frac of e : {} => {:?}", e, ec);  
70 - println!(" reverted dc : {:?} {}", dc, Into::<Fractional>::into(&dc));  
71 - println!(" reverted ec : {:?} {}", ec, Into::<Fractional>::into(&ec));  
72 -}  
73 -  
74 -fn sqrt() {  
75 - let f = Fractional(-9, 4);  
76 - let fr :f64 = f.try_into().unwrap();  
77 - let sq = f.sqrt();  
78 - let _sq = fr.sqrt();  
79 -  
80 - println!("{:>14} : {:?} / {}", format!("sqrt {}", f), sq, _sq);  
81 -  
82 - for f in [ Fractional(9, 4)  
83 - , Fractional(45, 16)  
84 - , Fractional(16, 45)  
85 - , Fractional(9, 3) ].iter() {  
86 - let fr :f64 = (*f).try_into().unwrap();  
87 - let sq = f.sqrt().unwrap();  
88 - let sqr :f64 = sq.try_into().unwrap();  
89 - let _sqr = fr.sqrt();  
90 -  
91 - println!("{:>14} : {} {} / {}", format!("sqrt {}", f), sq, sqr, _sqr);  
92 - }  
93 -}  
94 -  
95 -fn pi() {  
96 - let pi = Fractional::pi();  
97 - let pir :f64 = pi.try_into().unwrap();  
98 - let pit :(i32, i32) = pi.try_into().unwrap();  
99 - let pi2r :f64 = (pi * pi).try_into().unwrap();  
100 -  
101 - println!(" Rust π : {}" , FPI);  
102 - println!(" π : {} {}" , pi, pir);  
103 - println!(" π as tuple : {:?}" , pit);  
104 - println!(" Rust π² : {}" , FPI * FPI);  
105 - println!(" π² : {} {}" , pi * pi, pi2r);  
106 -}  
107 -  
108 -fn _sin() {  
109 - for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315  
110 - , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {  
111 - let s = Fractional::sin(*d as i32);  
112 - let sr :f64 = s.try_into().unwrap();  
113 - let _s = f64::sin(*d as f64 * FPI / 180.0);  
114 -  
115 - println!("{:>14} : {} {} / {}", format!("sin {}", d), s, sr, _s);  
116 - }  
117 -}  
118 -  
119 -fn _tan() {  
120 - for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315  
121 - , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {  
122 - let t = Fractional::tan(*d as i32);  
123 - let tr :f64 = t.try_into().unwrap();  
124 - let _t = f64::tan(*d as f64 * FPI / 180.0);  
125 -  
126 - println!("{:>14} : {} {} / {}", format!("tan {}", d), t, tr, _t);  
127 - }  
128 -}  
129 -  
130 -fn _cos() {  
131 - for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315  
132 - , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {  
133 - let c = Fractional::cos(*d as i32);  
134 - let cr :f64 = c.try_into().unwrap();  
135 - let _c = f64::cos(*d as f64 * FPI / 180.0);  
136 -  
137 - println!("{:>14} : {} {} / {}", format!("cos {}", d), c, cr, _c);  
138 - }  
139 -}  
140 -  
141 -fn _vector1() {  
142 - let v1 = Vector(1.into(), 2.into(), 3.into());  
143 - let v2 = Vector(2.into(), 2.into(), 3.into());  
144 - let s :Fractional = 3.into();  
145 -  
146 - _vector(v1, v2, s);  
147 -}  
148 -  
149 -fn _vector2() {  
150 - let v1 = Vector(1.0, 2.0, 3.0);  
151 - let v2 = Vector(2.0, 2.0, 3.0);  
152 - let s = 3.0;  
153 -  
154 - _vector(v1, v2, s);  
155 -}  
156 -  
157 -fn _vector<T>(v1 :Vector<T>, v2 :Vector<T>, s :T)  
158 - where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
159 - + Mul<Output = T> + Div<Output = T> + Trig + Copy + Display {  
160 - println!("{:>14} : {}", "Vector v1", v1);  
161 - println!("{:>14} : {}", "Vector v2", v2);  
162 - println!("{:>14} : {}", "magnitude v1", v1.mag());  
163 - println!("{:>14} : {}", "-v1", -v1);  
164 - println!("{:>14} : {}", "v1 + v1", v1 + v1);  
165 - println!("{:>14} : {}", "v1 - v1", v1 - v1);  
166 - println!("{:>14} : {}", "v2 - v1", v2 - v1);  
167 - println!("{:>14} : {}", format!("v1 * {}", s), v1.mul(&s));  
168 - println!("{:>14} : {}", "norm v1", v1.norm());  
169 - println!("{:>14} : {}", "magnitude norm v1", v1.norm().mag());  
170 - println!("{:>14} : {}", "magnitude v1", v1.mag());  
171 - println!("{:>14} : {}", "norm * magnitude", v1.norm().mul(&v1.mag()));  
172 - println!("{:>14} : {}", "distance v1 v2", v1.distance(v2));  
173 - println!("{:>14} : {}", "distance v2 v1", v2.distance(v1));  
174 - println!("{:>14} : {}", "v1 dot v2", v1.dot(v2));  
175 - println!("{:>14} : {}", "v2 dot v1", v2.dot(v1));  
176 - println!("{:>14} : {}", "v1 * v2", v1 * v2);  
177 - println!("{:>14} : {}", "v2 * v1", v2 * v1);  
178 -}  
179 -  
180 -fn _transform1() {  
181 - let v = Vector(Fractional(1,1), Fractional(1,1), Fractional(1,1));  
182 - let v1 = Vector(Fractional(1,1), Fractional(2,1), Fractional(3,1));  
183 - let v2 = Vector(Fractional(1,1), Fractional(1,1), Fractional(0,1));  
184 - let v3 = Vector(Fractional(1,1), Fractional(0,1), Fractional(1,1));  
185 -  
186 - _transform(v, v1, v2, v3);  
187 -}  
188 -  
189 -fn _transform2() {  
190 - let v = Vector(1.0, 1.0, 1.0);  
191 - let v1 = Vector(1.0, 2.0, 3.0);  
192 - let v2 = Vector(1.0, 1.0, 0.0);  
193 - let v3 = Vector(1.0, 0.0, 1.0);  
194 -  
195 - _transform(v, v1, v2, v3);  
196 -}  
197 -  
198 -fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)  
199 - where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
200 - + Mul<Output = T> + Div<Output = T> + Trig  
201 - + Debug + From<i32> + Copy + Display {  
202 -  
203 - println!("{:>14} : {}", "Vector v1", v1);  
204 - println!( "{:>14} : {}", "translate v1"  
205 - , v.transform(&TMatrix::translate(v)));  
206 - println!();  
207 -  
208 - fn _rot<T>( o :&str , n :&str , v :&Vector<T>  
209 - , fs :&[&dyn Fn(i32) -> TMatrix<T>] )  
210 - where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
211 - + Mul<Output = T> + Div<Output = T> + Trig  
212 - + Debug + From<i32> + Copy + Display {  
213 -  
214 - for d in [ 30, 45, 60, 90, 120, 135, 150, 180  
215 - , 210, 225, 240, 270, 300, 315, 330 ].iter() {  
216 - let mi = fs.iter().map(|f| f(*d as i32));  
217 - println!( "{:>14} : {}"  
218 - , format!("{} {} {}", o, d, n)  
219 - , v.transform(&TMatrix::combine(mi)) );  
220 - }  
221 - }  
222 -  
223 - println!("{:>14} : {}", "Vector v2", v2);  
224 - _rot("rot_x", "v2", &v2, &[&TMatrix::rotate_x]);  
225 - println!();  
226 - _rot("rot_y", "v2", &v2, &[&TMatrix::rotate_y]);  
227 - println!();  
228 - _rot("rot_xy", "v2", &v2, &[&TMatrix::rotate_x, &TMatrix::rotate_y]);  
229 - println!();  
230 - println!("{:>14} : {}", "Vector v3", v3);  
231 - _rot("rot_z", "v3", &v3, &[&TMatrix::rotate_z]);  
232 - println!();  
233 -  
234 - for d in [ 30, 45, 60, 90, 120, 135, 150, 180  
235 - , 210, 225, 240, 270, 300, 315, 330 ].iter() {  
236 - println!( "{:>14} : {}"  
237 - , format!("rot_v {} v2", d)  
238 - , v2.transform(&TMatrix::rotate_v(&v, *d as i32)) );  
239 - }  
240 -}  
241 -  
242 -fn _line() {  
243 - let a = (Coordinate(0, 1, 0.0), Coordinate(6, 4, 0.0));  
244 - let b = (Coordinate(0, 4, 0.0), Coordinate(6, 1, 0.0));  
245 - let c = (Coordinate(1, 0, 0.0), Coordinate(6, 8, 0.0));  
246 - let d = (Coordinate(1, 8, 0.0), Coordinate(6, 0, 0.0));  
247 -  
248 - for i in [a, b, c, d].iter() {  
249 - println!("{:>14} : {}", Line(i.0, i.1), Line(i.0, i.1).plot());  
250 - println!("{:>14} : {}", Line(i.1, i.0), Line(i.1, i.0).plot());  
251 - }  
252 -  
253 - println!();  
254 - let pl = Polyline(  
255 - Coordinates(vec!(a.0, a.1, b.0, b.1, c.0, c.1, d.0, d.1)));  
256 - println!("{:>14} : {}", pl, pl.plot());  
257 -  
258 - println!();  
259 - let pg = Polygon(  
260 - Coordinates(vec!( Coordinate( 0, -10, 0.0)  
261 - , Coordinate( 10, 10, 0.0)  
262 - , Coordinate(-10, 10, 0.0) )));  
263 - println!("{:>14} : {}", pg, pg.plot());  
264 -  
265 - let i = Vector(Fractional( 0,1), Fractional(-30,1), Fractional(0,1));  
266 - let j = Vector(Fractional( 30,1), Fractional( 30,1), Fractional(0,1));  
267 - let k = Vector(Fractional(-30,1), Fractional( 30,1), Fractional(0,1));  
268 -  
269 - let rot :TMatrix<Fractional> = TMatrix::rotate_z(20);  
270 - let Vector(ix, iy, _) = i.transform(&rot);  
271 - let Vector(jx, jy, _) = j.transform(&rot);  
272 - let Vector(kx, ky, _) = k.transform(&rot);  
273 -  
274 - fn to_i32(x :Fractional) -> i32 {  
275 - let Fractional(n, d) = x;  
276 - (n / d + if (n % d).abs() < (n / 2).abs() { 0 } else { 1 }) as i32  
277 - }  
278 -  
279 - println!();  
280 - let pg = Polygon(  
281 - Coordinates(vec!( Coordinate(to_i32(ix) + 100, to_i32(iy) + 100, 0.0)  
282 - , Coordinate(to_i32(jx) + 100, to_i32(jy) + 100, 0.0)  
283 - , Coordinate(to_i32(kx) + 100, to_i32(ky) + 100, 0.0) )));  
284 - println!("{:>14} : {}", pg, pg.plot());  
285 -  
286 - let i = Vector( 0.0, -30.0, 0.0);  
287 - let j = Vector( 30.0, 30.0, 0.0);  
288 - let k = Vector(-30.0, 30.0, 0.0);  
289 -  
290 - let rot :TMatrix<f64> = TMatrix::rotate_z(20);  
291 - let Vector(ix, iy, _) = i.transform(&rot);  
292 - let Vector(jx, jy, _) = j.transform(&rot);  
293 - let Vector(kx, ky, _) = k.transform(&rot);  
294 -  
295 - fn to_i32_2(x :f64) -> i32 {  
296 - x.round() as i32  
297 - }  
298 -  
299 - println!();  
300 - let pg = Polygon(  
301 - Coordinates(vec!( Coordinate(to_i32_2(ix) + 100, to_i32_2(iy) + 100, 0.0)  
302 - , Coordinate(to_i32_2(jx) + 100, to_i32_2(jy) + 100, 0.0)  
303 - , Coordinate(to_i32_2(kx) + 100, to_i32_2(ky) + 100, 0.0) )));  
304 - println!("{:>14} : {}", pg, pg.plot());  
305 -}  
306 -  
307 -fn _democanvas<T>( xcb :&XcbEasel  
308 - , title :&'static str  
309 - , tx :mpsc::Sender<i32>  
310 - , _triangle :Polyeder<T>  
311 - , tetrahedron :Polyeder<T>  
312 - , cube :Polyeder<T>  
313 - , light :DirectLight<T> )  
314 - where T: 'static + Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
315 - + Mul<Output = T> + Div<Output = T>  
316 - + Debug + Copy + Trig + Send + From<i32> + PartialOrd {  
317 -  
318 - let mut canvas = xcb.canvas(151, 151).unwrap();  
319 - let camera = Camera::<T>::new(&canvas, 45); // the orig. view angle  
320 - // was 50.  
321 -  
322 - canvas.set_title(title);  
323 - canvas.init_events();  
324 - canvas.start_events(tx.clone());  
325 -  
326 - thread::spawn(move || {  
327 - let start = Instant::now();  
328 - let step = Duration::from_millis(25);  
329 - let mut last = Instant::now();  
330 -  
331 - let t = TMatrix::translate(Vector(0.into() , 0.into() , 150.into()));  
332 -  
333 - loop {  
334 - let deg = ((start.elapsed() / 25).as_millis() % 360) as i32;  
335 -  
336 - let rz = TMatrix::rotate_z(deg);  
337 - let rx = TMatrix::rotate_x(-deg*2);  
338 - let ry = TMatrix::rotate_y(-deg*2);  
339 -  
340 - let rot1 = TMatrix::combine(vec!(rz, rx, t));  
341 - let rot2 = TMatrix::combine(vec!(rz, ry, t));  
342 -  
343 - let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00)  
344 - , ( cube.transform(&rot2), 0x0000FF) );  
345 - //let objects = vec!( ( cube.transform(&rot2), 0x0000FF) );  
346 - //let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) );  
347 - //let objects = vec!( (triangle.transform(&rot1), 0xFFFF00) );  
348 -  
349 - canvas.clear();  
350 -  
351 - for (o, color) in objects {  
352 - for (pg, c) in o.project(&camera, &light, color) {  
353 - //canvas.draw(&pg, Coordinate(0, 0, 0.into()), c);  
354 - (&pg).fill(&mut canvas, c);  
355 - //(&pg).debug();  
356 - //println!("\n");  
357 - }  
358 - }  
359 -  
360 - let passed = Instant::now() - last;  
361 - let f = (passed.as_nanos() / step.as_nanos()) as u32;  
362 -  
363 - if f > 1 {  
364 - println!("{} !!! Detected frame drop", title);  
365 - }  
366 -  
367 - last = last + step*(f + 1);  
368 - canvas.put_text( Coordinate(10, 15, 0.into())  
369 - , &format!( "sleep: {:?}"  
370 - , last - Instant::now() ));  
371 - canvas.show();  
372 - thread::sleep(last - Instant::now());  
373 - }  
374 - });  
375 -}  
376 -  
377 -fn main() {  
378 - common_fractional();  
379 - println!();  
380 - continuous();  
381 - println!();  
382 - sqrt();  
383 - println!();  
384 - pi();  
385 - println!();  
386 - _sin();  
387 - println!();  
388 - _cos();  
389 - println!();  
390 - _tan();  
391 - println!();  
392 - _vector1();  
393 - println!();  
394 - _vector2();  
395 - println!();  
396 - _transform1();  
397 - println!();  
398 - _transform2();  
399 - println!();  
400 - _line();  
401 -  
402 - let xcb = XcbEasel::new().unwrap();  
403 - let (tx, rx) = mpsc::channel();  
404 -  
405 -  
406 - _democanvas( &xcb, "Something...(f64)", tx.clone()  
407 - , Polyeder::triangle(60.0)  
408 - , Polyeder::tetrahedron(100.0)  
409 - , Polyeder::cube(56.25)  
410 - , DirectLight::new(Vector(0.0, 0.0, 1.0)) );  
411 - /*  
412 - _democanvas( &xcb, "Something...(Fractional)", tx.clone()  
413 - , Polyeder::triangle(Fractional(60,1))  
414 - , Polyeder::tetrahedron(Fractional(80,1))  
415 - , Polyeder::cube(Fractional(55,1))  
416 - , DirectLight::new(Vector( Fractional(0,1)  
417 - , Fractional(0,1)  
418 - , Fractional(1,1) )) );  
419 - */  
420 -  
421 - for x in rx {  
422 - match x {  
423 - 1 => break,  
424 - _ => {},  
425 - }  
426 - }  
427 -}  
1 -//  
2 -// Transformation of vectors in a given coordinate system...  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -use std::ops::{Add, Sub, Neg, Mul, Div};  
22 -use std::fmt::Debug;  
23 -  
24 -use crate::Vector;  
25 -use crate::trigonometry::Trig;  
26 -  
27 -#[derive(Debug, Clone, Copy)]  
28 -pub struct TMatrix<T>( (T, T, T, T)  
29 - , (T, T, T, T)  
30 - , (T, T, T, T)  
31 - , (T, T, T, T) )  
32 - where T: Add + Sub + Neg + Mul + Div + Debug + Trig + From<i32> + Copy;  
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 -  
39 -impl<T> TMatrix<T>  
40 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
41 - + Mul<Output = T> + Div<Output = T>  
42 - + Debug + Trig + From<i32> + Copy {  
43 - pub fn new( r1 :(T, T, T, T)  
44 - , r2 :(T, T, T, T)  
45 - , r3 :(T, T, T, T)  
46 - , r4 :(T, T, T, T) ) -> Self {  
47 - TMatrix(r1, r2, r3, r4)  
48 - }  
49 -  
50 - pub fn unit() -> Self {  
51 - Self::new( (1.into(), 0.into(), 0.into(), 0.into())  
52 - , (0.into(), 1.into(), 0.into(), 0.into())  
53 - , (0.into(), 0.into(), 1.into(), 0.into())  
54 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
55 - }  
56 -  
57 - pub fn translate(v :Vector<T>) -> Self {  
58 - let Vector(x, y, z) = v;  
59 -  
60 - Self::new( (1.into(), 0.into(), 0.into(), x)  
61 - , (0.into(), 1.into(), 0.into(), y)  
62 - , (0.into(), 0.into(), 1.into(), z)  
63 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
64 - }  
65 -  
66 - pub fn rotate_x(a :i32) -> Self {  
67 - let sin :T = Trig::sin(a);  
68 - let cos :T = Trig::cos(a);  
69 -  
70 - Self::new( (1.into(), 0.into(), 0.into(), 0.into())  
71 - , (0.into(), cos , -sin , 0.into())  
72 - , (0.into(), sin , cos , 0.into())  
73 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
74 - }  
75 -  
76 - pub fn rotate_y(a :i32) -> Self {  
77 - let sin :T = Trig::sin(a);  
78 - let cos :T = Trig::cos(a);  
79 -  
80 - Self::new( (cos , 0.into(), sin , 0.into())  
81 - , (0.into(), 1.into(), 0.into(), 0.into())  
82 - , (-sin , 0.into(), cos , 0.into())  
83 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
84 - }  
85 -  
86 - pub fn rotate_z(a :i32) -> Self {  
87 - let sin :T = Trig::sin(a);  
88 - let cos :T = Trig::cos(a);  
89 -  
90 - Self::new( (cos , -sin , 0.into(), 0.into())  
91 - , (sin , cos , 0.into(), 0.into())  
92 - , (0.into(), 0.into(), 1.into(), 0.into())  
93 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
94 - }  
95 -  
96 - pub fn rotate_v(v :&Vector<T>, a :i32) -> Self {  
97 - let Vector(x, y, z) = *v;  
98 -  
99 - let sin :T = Trig::sin(a);  
100 - let cos :T = Trig::cos(a);  
101 -  
102 - let zero :T = 0.into();  
103 - let one :T = 1.into();  
104 -  
105 - Self::new( ( (one - cos) * x * x + cos  
106 - , (one - cos) * x * y - sin * z  
107 - , (one - cos) * x * z + sin * y  
108 - , zero )  
109 - , ( (one - cos) * x * y + sin * z  
110 - , (one - cos) * y * y + cos  
111 - , (one - cos) * y * z - sin * x  
112 - , zero )  
113 - , ( (one - cos) * x * z - sin * y  
114 - , (one - cos) * y * z + sin * x  
115 - , (one - cos) * z * z + cos  
116 - , zero )  
117 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
118 - }  
119 -  
120 - pub fn scale(v :Vector<T>) -> Self {  
121 - let Vector(x, y, z) = v;  
122 -  
123 - Self::new( ( x, 0.into(), 0.into(), 0.into())  
124 - , (0.into(), y, 0.into(), 0.into())  
125 - , (0.into(), 0.into(), z, 0.into())  
126 - , (0.into(), 0.into(), 0.into(), 1.into()) )  
127 - }  
128 -  
129 - pub fn combine<I>(mi :I) -> TMatrix<T>  
130 - where I: IntoIterator<Item = TMatrix<T>> {  
131 -  
132 - mi.into_iter().fold(Self::unit(), |acc, x| x * acc)  
133 - }  
134 -  
135 - pub fn apply(&self, v :&Vector<T>, w :T) -> (Vector<T>, T) {  
136 - let TMatrix( (a11, a12, a13, a14)  
137 - , (a21, a22, a23, a24)  
138 - , (a31, a32, a33, a34)  
139 - , (a41, a42, a43, a44) ) = *self;  
140 - let Vector(x, y, z) = *v;  
141 -  
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;  
146 -  
147 - //v.mul(&w.recip())  
148 - (v, w)  
149 - }  
150 -}  
151 -  
152 -impl<T> Mul for TMatrix<T>  
153 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
154 - + Mul<Output = T> + Div<Output = T>  
155 - + Debug + Trig + From<i32> + Copy {  
156 - type Output = Self;  
157 -  
158 - // ATTENTION: This is not commutative, nor assoziative.  
159 - fn mul(self, other :Self) -> Self {  
160 - let TMatrix( (a11, a12, a13, a14)  
161 - , (a21, a22, a23, a24)  
162 - , (a31, a32, a33, a34)  
163 - , (a41, a42, a43, a44) ) = self;  
164 - let TMatrix( (b11, b12, b13, b14)  
165 - , (b21, b22, b23, b24)  
166 - , (b31, b32, b33, b34)  
167 - , (b41, b42, b43, b44) ) = other;  
168 -  
169 - TMatrix( ( a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41  
170 - , a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42  
171 - , a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43  
172 - , a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44 )  
173 - , ( a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41  
174 - , a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42  
175 - , a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43  
176 - , a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44 )  
177 - , ( a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41  
178 - , a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42  
179 - , a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43  
180 - , a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44 )  
181 - , ( a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41  
182 - , a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42  
183 - , a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43  
184 - , a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44 ) )  
185 - }  
186 -}  
1 -//  
2 -// Some trigonometic functions with Fractions results.  
3 -// Currently only sin, cos and tan are implemented.  
4 -// As I was unable to find a really good integral approximation for them I  
5 -// implement them as a table which is predefined using the floating point  
6 -// function f64::sin and then transformed into a fraction of a given  
7 -// PRECISION.  
8 -// These approximations are quite good and for a few edge cases  
9 -// even better than the floating point implementations.  
10 -//  
11 -// Georg Hopp <georg@steffers.org>  
12 -//  
13 -// Copyright © 2019 Georg Hopp  
14 -//  
15 -// This program is free software: you can redistribute it and/or modify  
16 -// it under the terms of the GNU General Public License as published by  
17 -// the Free Software Foundation, either version 3 of the License, or  
18 -// (at your option) any later version.  
19 -//  
20 -// This program is distributed in the hope that it will be useful,  
21 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
22 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
23 -// GNU General Public License for more details.  
24 -//  
25 -// You should have received a copy of the GNU General Public License  
26 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
27 -//  
28 -use std::cmp::Ordering;  
29 -use std::ops::Div;  
30 -use std::ops::Neg;  
31 -use std::marker::Sized;  
32 -use crate::{Fractional, Error};  
33 -use crate::continuous::Continuous;  
34 -  
35 -pub trait Trig {  
36 - fn pi() -> Self;  
37 - fn recip(self) -> Self;  
38 - fn round(&self) -> i32;  
39 - fn sqrt(self) -> Result<Self, Error> where Self: Sized;  
40 - fn sintab() -> Vec<Self> where Self: Sized;  
41 - fn tantab() -> Vec<Self> where Self: Sized;  
42 -  
43 - fn sin(d :i32) -> Self  
44 - where Self: Sized + Neg<Output = Self> + Copy {  
45 - match d {  
46 - 0 ..=90 => Self::sintab()[d as usize],  
47 - 91 ..=180 => Self::sintab()[180 - d as usize],  
48 - 181..=270 => -Self::sintab()[d as usize - 180],  
49 - 271..=359 => -Self::sintab()[360 - d as usize],  
50 - _ => {  
51 - Self::sin(if d < 0 { d % 360 + 360 } else { d % 360 })  
52 - },  
53 - }  
54 - }  
55 -  
56 - fn cos(d :i32) -> Self  
57 - where Self: Sized + Neg<Output = Self> + Copy {  
58 - match d {  
59 - 0 ..=90 => Self::sintab()[90 - d as usize],  
60 - 91 ..=180 => -Self::sintab()[90 - (180 - d as usize)],  
61 - 181..=270 => -Self::sintab()[90 - (d as usize - 180)],  
62 - 271..=359 => Self::sintab()[90 - (360 - d as usize)],  
63 - _ => {  
64 - Self::cos(if d < 0 { d % 360 + 360 } else { d % 360 })  
65 - },  
66 - }  
67 - }  
68 -  
69 - fn tan(d :i32) -> Self where Self: Sized + Copy {  
70 - match d {  
71 - 0 ..=179 => Self::tantab()[d as usize],  
72 - 180..=359 => Self::tantab()[d as usize - 180],  
73 - _ => {  
74 - Self::tan(if d < 0 { d % 360 + 360 } else { d % 360 })  
75 - },  
76 - }  
77 - }  
78 -  
79 - fn cot(d :i32) -> Self  
80 - where Self: Sized + Copy + From<i32> + Div<Output = Self> {  
81 - Into::<Self>::into(1) / Self::tan(d)  
82 - }  
83 -}  
84 -  
85 -// Try to keep precision as high as possible while having a denominator  
86 -// as small as possible. The values are taken by try and error.  
87 -const PRECISION :i64 = 1000000;  
88 -const MAX_DENOMINATOR :i64 = 7000;  
89 -  
90 -// This is a really close fractional approximation for pi.  
91 -impl Trig for Fractional {  
92 - fn pi() -> Self {  
93 - Fractional(355, 113)  
94 - }  
95 -  
96 - fn recip(self) -> Self {  
97 - let Fractional(n, d) = self;  
98 - Fractional(d, n)  
99 - }  
100 -  
101 - fn round(&self) -> i32 {  
102 - let Fractional(n, d) = self;  
103 - (n / d) as i32  
104 - }  
105 -  
106 - // This is a really bad approximation of sqrt for a fractional...  
107 - // for (9/3) it will result 3 which if way to far from the truth,  
108 - // which is ~1.7320508075  
109 - // BUT we can use this value as starting guess for creating a  
110 - // continous fraction for the sqrt... and create a much better  
111 - // fractional representation of the sqrt.  
112 - // So, if inner converges, but is not a perfect square (does not  
113 - // end up in an Ordering::Equal - which is the l > h case)  
114 - // we use the l - 1 as starting guess for sqrt_cfrac.  
115 - // taken from:  
116 - // https://www.geeksforgeeks.org/square-root-of-an-integer/  
117 - fn sqrt(self) -> Result<Self, Error> {  
118 - // find the sqrt of x in O(log x/2).  
119 - // This stops if a perfect sqare was found. Else it passes  
120 - // the found value as starting guess to the continous fraction  
121 - // sqrt function.  
122 - fn floor_sqrt(x :i64) -> Fractional {  
123 - fn inner(l :i64, h :i64, x :i64) -> Fractional {  
124 - if l > h {  
125 - (&Continuous::sqrt(x, l - 1)).into()  
126 - } else {  
127 - let m = (l + h) / 2;  
128 - match x.cmp(&(m * m)) {  
129 - Ordering::Equal => m.into(),  
130 - Ordering::Less => inner(l, m - 1, x),  
131 - Ordering::Greater => inner(m + 1, h, x),  
132 - }  
133 - }  
134 - }  
135 -  
136 - match x {  
137 - 0 => 0.into(),  
138 - 1 => 1.into(),  
139 - _ => inner(1, x / 2, x),  
140 - }  
141 - }  
142 -  
143 - let Fractional(n, d) = self;  
144 -  
145 - let n = match n.cmp(&0) {  
146 - Ordering::Equal => 0.into(),  
147 - Ordering::Less => return Err("sqrt on negative undefined"),  
148 - Ordering::Greater => floor_sqrt(n),  
149 - };  
150 -  
151 - let d = match d.cmp(&0) {  
152 - Ordering::Equal => 0.into(),  
153 - Ordering::Less => return Err("sqrt on negative undefined"),  
154 - Ordering::Greater => floor_sqrt(d),  
155 - };  
156 -  
157 - Ok(n / d)  
158 - }  
159 -  
160 - fn sintab() -> Vec<Self> {  
161 - // hold sin Fractionals from 0 to 89 ...  
162 - // luckily with a bit of index tweeking this can also be used for  
163 - // cosine values.  
164 - lazy_static::lazy_static! {  
165 - static ref SINTAB :Vec<Fractional> =  
166 - (0..=90).map(|x| _sin(x)).collect();  
167 - }  
168 -  
169 - // fractional sin from f64 sin. (From 0° to 90°)  
170 - fn _sin(d: u32) -> Fractional {  
171 - match d {  
172 - 0 => Fractional(0, 1),  
173 - 90 => Fractional(1, 1),  
174 - _ => generate(d, PRECISION, &f64::sin),  
175 - }  
176 - }  
177 -  
178 - SINTAB.to_vec()  
179 - }  
180 -  
181 - fn tantab() -> Vec<Self> {  
182 - // This table exists only because the sin(α) / cos(α) method  
183 - // yields very large unreducable denominators in a lot of cases.  
184 - lazy_static::lazy_static! {  
185 - static ref TANTAB :Vec<Fractional> =  
186 - (0..180).map(|x| _tan(x)).collect();  
187 - }  
188 -  
189 - // fractional tan from f64 tan. (From 0° to 179°)  
190 - fn _tan(d: u32) -> Fractional {  
191 - match d {  
192 - 0 => Fractional(0, 1),  
193 - 45 => Fractional(1, 1),  
194 - 90 => Fractional(1, 0), // although they are both inf and -inf.  
195 - 135 => -Fractional(1, 1),  
196 - _ => generate(d, PRECISION, &f64::tan),  
197 - }  
198 - }  
199 -  
200 - TANTAB.to_vec()  
201 - }  
202 -}  
203 -  
204 -// search for a fraction with a denominator less than MAX_DENOMINATOR that  
205 -// provides the minimal PRECISION criteria.  
206 -// !! With f = &f64::tan and d close to the inf boundarys of tan  
207 -// we get very large numerators because the numerator becomes a  
208 -// multiple of the denominator.  
209 -fn generate(d :u32, p :i64, f :&dyn Fn(f64) -> f64) -> Fractional {  
210 - // This is undefined behaviour for very large f64, but our f64  
211 - // is always between 0.0 and 1000000.0 which should be fine.  
212 - let s = (f((d as f64).to_radians()) * p as f64).round() as i64;  
213 - let Fractional(n, dn) = Fractional(s, p).reduce();  
214 - match dn.abs().cmp(&MAX_DENOMINATOR) {  
215 - Ordering::Less => Fractional(n, dn),  
216 - _ => generate(d, p + 1, f),  
217 - }  
218 -}  
219 -  
220 -impl Trig for f64 {  
221 - fn pi() -> Self {  
222 - std::f64::consts::PI  
223 - }  
224 -  
225 - fn recip(self) -> Self {  
226 - self.recip()  
227 - }  
228 -  
229 - fn round(&self) -> i32 {  
230 - f64::round(*self) as i32  
231 - }  
232 -  
233 - fn sqrt(self) -> Result<Self, Error> {  
234 - let x = self.sqrt();  
235 - match x.is_nan() {  
236 - true => Err("sqrt on negative undefined"),  
237 - false => Ok(x),  
238 - }  
239 - }  
240 -  
241 - fn sintab() -> Vec<Self> {  
242 - lazy_static::lazy_static! {  
243 - static ref SINTAB :Vec<f64> =  
244 - (0..=90).map(|x| _sin(x)).collect();  
245 - }  
246 -  
247 - // f64 sin. (From 0° to 90°)  
248 - fn _sin(d: u32) -> f64 {  
249 - match d {  
250 - 0 => 0.0,  
251 - 90 => 1.0,  
252 - _ => (d as f64).to_radians().sin(),  
253 - }  
254 - }  
255 -  
256 - SINTAB.to_vec()  
257 - }  
258 -  
259 - fn tantab() -> Vec<Self> {  
260 - // This table exists only because the sin(α) / cos(α) method  
261 - // yields very large unreducable denominators in a lot of cases.  
262 - lazy_static::lazy_static! {  
263 - static ref TANTAB :Vec<f64> =  
264 - (0..180).map(|x| _tan(x)).collect();  
265 - }  
266 -  
267 - // fractional tan from f64 tan. (From 0° to 179°)  
268 - fn _tan(d: u32) -> f64 {  
269 - match d {  
270 - 0 => 0.0,  
271 - 45 => 1.0,  
272 - 90 => std::f64::INFINITY,  
273 - 135 => -1.0,  
274 - _ => (d as f64).to_radians().tan(),  
275 - }  
276 - }  
277 -  
278 - TANTAB.to_vec()  
279 - }  
280 -}  
1 -//  
2 -// Stuff for manipulating 3 dimensional vectors.  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -use std::fmt::{Debug, Display, Formatter, Result};  
22 -use std::ops::{Add, Sub, Neg, Mul, Div};  
23 -  
24 -use crate::trigonometry::Trig;  
25 -use crate::transform::{TMatrix, Transformable};  
26 -  
27 -#[derive(Debug, Eq, Clone, Copy)]  
28 -pub struct Vector<T>(pub T, pub T, pub T)  
29 - where T: Add + Sub + Neg + Mul + Div + Trig + Copy;  
30 -  
31 -impl<T> Vector<T>  
32 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
33 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
34 - pub fn x(self) -> T { self.0 }  
35 - pub fn y(self) -> T { self.1 }  
36 - pub fn z(self) -> T { self.2 }  
37 -  
38 - pub fn mag(self) -> T {  
39 - let Vector(x, y, z) = self;  
40 - (x * x + y * y + z * z).sqrt().unwrap()  
41 - }  
42 -  
43 - pub fn mul(self, s :&T) -> Self {  
44 - let Vector(x, y, z) = self;  
45 - Vector(x * *s, y * *s, z * *s)  
46 - }  
47 -  
48 - pub fn dot(self, other :Self) -> T {  
49 - let Vector(x1, y1, z1) = self;  
50 - let Vector(x2, y2, z2) = other;  
51 -  
52 - x1 * x2 + y1 * y2 + z1 * z2  
53 - }  
54 -  
55 - pub fn norm(self) -> Self {  
56 - // TODO This can result in 0 or inf Vectors…  
57 - // Maybe we need to handle zero and inf magnitude here…  
58 - self.mul(&self.mag().recip())  
59 - }  
60 -  
61 - pub fn distance(self, other :Self) -> T {  
62 - (self - other).mag()  
63 - }  
64 -}  
65 -  
66 -impl<T> Display for Vector<T>  
67 -where T: Add + Sub + Neg + Mul + Div + Trig + Display + Copy {  
68 - fn fmt(&self, f :&mut Formatter<'_>) -> Result {  
69 - let Vector(x, y, z) = self;  
70 - write!(f, "({}, {}, {})", x, y, z)  
71 - }  
72 -}  
73 -  
74 -impl<T> PartialEq for Vector<T>  
75 -where T: Add + Sub + Neg + Mul + Div + Trig + PartialEq + Copy {  
76 - fn eq(&self, other :&Self) -> bool {  
77 - let Vector(x1, y1, z1) = self;  
78 - let Vector(x2, y2, z2) = other;  
79 - x1 == x2 && y1 == y2 && z1 == z2  
80 - }  
81 -}  
82 -  
83 -impl<T> Add for Vector<T>  
84 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
85 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
86 - type Output = Self;  
87 -  
88 - fn add(self, other :Self) -> Self {  
89 - let Vector(x1, y1, z1) = self;  
90 - let Vector(x2, y2, z2) = other;  
91 - Vector(x1 + x2, y1 + y2, z1 + z2)  
92 - }  
93 -}  
94 -  
95 -impl<T> Sub for Vector<T>  
96 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
97 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
98 - type Output = Self;  
99 -  
100 - fn sub(self, other :Self) -> Self {  
101 - self + -other  
102 - }  
103 -}  
104 -  
105 -impl<T> Neg for Vector<T>  
106 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
107 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
108 - type Output = Self;  
109 -  
110 - fn neg(self) -> Self {  
111 - let Vector(x, y, z) = self;  
112 - Self(-x, -y, -z)  
113 - }  
114 -}  
115 -  
116 -impl<T> Mul for Vector<T>  
117 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
118 - + Mul<Output = T> + Div<Output = T> + Trig + Copy {  
119 - type Output = Self;  
120 -  
121 - fn mul(self, other :Self) -> Self {  
122 - let Vector(ax, ay, az) = self;  
123 - let Vector(bx, by, bz) = other;  
124 -  
125 - Vector( ay * bz - az * by  
126 - , az * bx - ax * bz  
127 - , ax * by - ay * bx )  
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 -}  
1 -# This file is automatically @generated by Cargo.  
2 -# It is not intended for manual editing.  
3 -[[package]]  
4 -name = "functions"  
5 -version = "0.1.0"  
6 -  
1 -[package]  
2 -name = "functions"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  
8 -  
9 -[dependencies]  
1 -fn main() {  
2 - another_function(5, add_five(6));  
3 -}  
4 -  
5 -fn another_function(x: i32, y: i32) {  
6 - println!("The value of x id: {}", x);  
7 - println!("The value of y id: {}", y);  
8 -}  
9 -  
10 -fn add_five(x: i32) -> i32 {  
11 - x + 5  
12 -}  
1 -# This file is automatically @generated by Cargo.  
2 -# It is not intended for manual editing.  
3 -[[package]]  
4 -name = "fuchsia-cprng"  
5 -version = "0.1.1"  
6 -source = "registry+https://github.com/rust-lang/crates.io-index"  
7 -  
8 -[[package]]  
9 -name = "guessing_game"  
10 -version = "0.1.0"  
11 -dependencies = [  
12 - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",  
13 -]  
14 -  
15 -[[package]]  
16 -name = "libc"  
17 -version = "0.2.65"  
18 -source = "registry+https://github.com/rust-lang/crates.io-index"  
19 -  
20 -[[package]]  
21 -name = "rand"  
22 -version = "0.3.23"  
23 -source = "registry+https://github.com/rust-lang/crates.io-index"  
24 -dependencies = [  
25 - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",  
26 - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",  
27 -]  
28 -  
29 -[[package]]  
30 -name = "rand"  
31 -version = "0.4.6"  
32 -source = "registry+https://github.com/rust-lang/crates.io-index"  
33 -dependencies = [  
34 - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",  
35 - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",  
36 - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",  
37 - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",  
38 - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",  
39 -]  
40 -  
41 -[[package]]  
42 -name = "rand_core"  
43 -version = "0.3.1"  
44 -source = "registry+https://github.com/rust-lang/crates.io-index"  
45 -dependencies = [  
46 - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",  
47 -]  
48 -  
49 -[[package]]  
50 -name = "rand_core"  
51 -version = "0.4.2"  
52 -source = "registry+https://github.com/rust-lang/crates.io-index"  
53 -  
54 -[[package]]  
55 -name = "rdrand"  
56 -version = "0.4.0"  
57 -source = "registry+https://github.com/rust-lang/crates.io-index"  
58 -dependencies = [  
59 - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",  
60 -]  
61 -  
62 -[[package]]  
63 -name = "winapi"  
64 -version = "0.3.8"  
65 -source = "registry+https://github.com/rust-lang/crates.io-index"  
66 -dependencies = [  
67 - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",  
68 - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",  
69 -]  
70 -  
71 -[[package]]  
72 -name = "winapi-i686-pc-windows-gnu"  
73 -version = "0.4.0"  
74 -source = "registry+https://github.com/rust-lang/crates.io-index"  
75 -  
76 -[[package]]  
77 -name = "winapi-x86_64-pc-windows-gnu"  
78 -version = "0.4.0"  
79 -source = "registry+https://github.com/rust-lang/crates.io-index"  
80 -  
81 -[metadata]  
82 -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"  
83 -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"  
84 -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"  
85 -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"  
86 -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"  
87 -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"  
88 -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"  
89 -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"  
90 -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"  
91 -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"  
1 -[package]  
2 -name = "guessing_game"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -[dependencies]  
8 -rand = "0.3.14"  
1 -use std::io;  
2 -use std::cmp::Ordering;  
3 -use rand::Rng;  
4 -  
5 -fn main() {  
6 - println!("Guess the number!");  
7 -  
8 - let secret_number = rand::thread_rng()  
9 - .gen_range(1, 101);  
10 -  
11 - loop {  
12 - println!("Please input your guess.");  
13 -  
14 - let mut guess = String::new();  
15 -  
16 - io::stdin()  
17 - .read_line(&mut guess)  
18 - .expect("Failed to read line");  
19 -  
20 - let guess: u32 = match guess.trim().parse() {  
21 - Ok(num) => num,  
22 - Err(_) => continue,  
23 - };  
24 -  
25 - println!("You guessed: {}", guess);  
26 -  
27 - match guess.cmp(&secret_number) {  
28 - Ordering::Less => println!("Too small!"),  
29 - Ordering::Greater => println!("Too big!"),  
30 - Ordering::Equal => {  
31 - println!("You win!");  
32 - break;  
33 - }  
34 - }  
35 - }  
36 -}  
1 -# This file is automatically @generated by Cargo.  
2 -# It is not intended for manual editing.  
3 -[[package]]  
4 -name = "hello"  
5 -version = "0.1.0"  
6 -  
1 -[package]  
2 -name = "hello"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -[dependencies]  
1 -fn main() {  
2 - println!("Hello, world!");  
3 -}  
1 -# Here I collect some interesting links.  
2 -  
3 -## cargo environment  
4 -  
5 -Currently I always build all dependencies within th projects own .cargo subdir  
6 -by setting the environment variable CARGO_HOME.  
7 -  
8 - export CARGO_HOME=./.cargo  
9 -  
10 -Actually I am quite unsure if that is really a good idea because this results  
11 -in a lot of rebuilds for each new project.  
12 -  
13 -## Implement Monads with rust.  
14 -  
15 -Which is currently difficult through impossible, but might be feasible with  
16 -some small additions to the rust type system, namely  
17 -«(generic) associated traits.»  
18 -  
19 -[Read here](https://varkor.github.io/blog/2019/03/28/idiomatic-monads-in-rust.html)  
20 -  
21 -### Is impl Trait what we needed?  
22 -  
23 -A new language feature which sounded a bit like the needed one for above is:  
24 -  
25 -[impl Trait](https://medium.com/@iopguy/impl-trait-in-rust-explanation-efde0d94946a)  
26 -  
27 -Crossreading it a bit seems to indicate that this is not like the above needed  
28 -language feature.  
29 -  
30 -## WASM ... on gentoo ...  
31 -  
32 -Right now rust is not really a first class citizen within the gentoo eco  
33 -system. For that reason at least when compiling rust with the `system-llvm`  
34 -use flag some manual preparations are needed.  
35 -  
36 -### general informations about Wasm from MDN ...  
37 -  
38 -[WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly)  
39 -  
40 -### rustwasm tutorial  
41 -  
42 -[rustwasm](https://rustwasm.github.io/book/introduction.html)  
43 -  
44 -### location of rustlib ...  
45 -  
46 -`wasm-pack` expects the wasm runtime under /usr/lib/rustlib/ but a gentoo  
47 -installation puts it under /usr/lib/rust-1.39.0/rustlib/. To come around this  
48 -issue I just created a symlink.  
49 -  
50 -Maybe it would be best to send a patch for also settings this symlink to  
51 -upstream eselect-rust.  
52 -  
53 -### Missing lld  
54 -  
55 -Again `wasm-pack` searches for llvm-lld or rust-lld for the link phase. This  
56 -is currently not a dependency for llvm with WASM support, so I installed it  
57 -manually. Finally you have to tell rustc to use lld as linker via this  
58 -environment variable:  
59 -  
60 - export RUSTFLAGS="-C linker=lld"  
61 -  
62 -## Traits when, how & why  
63 -  
64 -A slightly old but still worthwhile post about rusts standard traits.  
65 -  
66 -[About traits](https://llogiq.github.io/2015/07/30/traits.html)  
67 -  
68 -# Side note... 3d math  
69 -[3d math primer](https://www.3dgep.com/3d-math-primer-for-game-programmers-vector-operations/)  
70 -[basic 3d math](https://matrix44.net/cms/notes/opengl-3d-graphics/basic-3d-math-vectors/)  
71 -[vector calculator](https://www.mathportal.org/calculators/matrices-calculators/vector-calculator.php)  
72 -[3d vector mathematics](https://vvvv.org/documentation/3d-vector-mathematics)  
73 -[sin appr. with fractions](https://dsp.stackexchange.com/questions/46629/finding-polynomial-approximations-of-a-sine-wave)  
74 -  
75 -# transformations within a coordinate system.  
76 -[migenius](https://www.migenius.com/articles/3d-transformations-part1-matrices)  
77 -[tutorialspoint](https://www.tutorialspoint.com/computer_graphics/3d_transformation.htm)  
78 -  
79 -# more math...  
80 -  
81 -A whole lot of interesting stuff about continued fractions:  
82 -[continues fractions](http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/cfINTRO.html)  
83 -  
1 -# This file is automatically @generated by Cargo.  
2 -# It is not intended for manual editing.  
3 -[[package]]  
4 -name = "loops"  
5 -version = "0.1.0"  
6 -  
1 -[package]  
2 -name = "loops"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  
8 -  
9 -[dependencies]  
1 -//  
2 -// Loops examples.  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -  
22 -fn main() {  
23 - // It seams that to use loops this way you absolutely need a mutable.  
24 - // If I build it with a normal type and try to shadow it within the loop  
25 - // the outer variable is always used as input for the shadow, thus it is  
26 - // always the same.... that really sucks.  
27 - let mut counter = 0;  
28 -  
29 - let result = loop {  
30 - counter = counter + 1;  
31 - if counter == 10 {  
32 - break counter * 2;  
33 - }  
34 - };  
35 -  
36 - println!("The result is {}", result);  
37 -  
38 - // The same is true with «while» ... which again sucks.  
39 - let mut number = 3;  
40 -  
41 - while number != 0 {  
42 - println!("{}!", number);  
43 - number = number - 1;  
44 - }  
45 -  
46 - println!("LIFTOFF!!!");  
47 -  
48 - // apart from beeing frustrated about the above facts... lets continue.  
49 - let a = [10, 20, 30, 40, 50];  
50 - let mut index = 0;  
51 -  
52 - while index < 5 {  
53 - println!("the value is: {}", a[index]);  
54 - index = index + 1;  
55 - }  
56 -  
57 - for element in a.iter() {  
58 - println!("the value is still: {}", element);  
59 - }  
60 -  
61 - for number in (1..4).rev() {  
62 - println!("for {}!", number);  
63 - }  
64 -}  
1 -# This file is automatically @generated by Cargo.  
2 -# It is not intended for manual editing.  
3 -[[package]]  
4 -name = "ownership"  
5 -version = "0.1.0"  
6 -  
1 -[package]  
2 -name = "ownership"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  
8 -  
9 -[dependencies]  
1 -//  
2 -// Examples related to ownership, also introducing String.  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -  
22 -fn main() {  
23 - concat();  
24 - move_variable();  
25 - clone_variable();  
26 -  
27 - let s = String::from("hello"); // s comes into scope  
28 -  
29 - take_ownership(s); // s's value moves into the function  
30 - // … and so is no longer valid here.  
31 - let x = 5; // x comes into scope  
32 -  
33 - makes_copy(x); // the scalar value has the Copy trait and  
34 - // lives on the stack and thus is still  
35 - // valid here.  
36 -  
37 - let _s1 = gives_ownership(); // move the return value into _s1  
38 - let s2 = String::from("hello"); // s2 comes into scope  
39 - let _s3 = takes_and_gives(s2); // s2 is moved into function, which in  
40 - // turn moves the return value into _s3.  
41 -  
42 - let s1 = String::from("hello"); // s1 comes into scope.  
43 - let len = calculate_length(&s1); // A reference to s1 is given to a  
44 - // calculate_length which effectively is  
45 - // not s1 itself but another pointer to  
46 - // s1… which is the reason that we still  
47 - // can use it below.  
48 - let _another_s = &s1; // again only a reference which does not  
49 - // take ownership, thus s1 can still be  
50 - // used below.  
51 - println!("The length of '{}' is {}.", s1, len);  
52 -  
53 - // Passing values as reference to a function is called borrowing. A  
54 - // borrowed value can't be changed.  
55 - change(&s1);  
56 -  
57 - // but we can force this… which is probably not the best of ideas most  
58 - // of the time…  
59 - let mut s_mut = String::from("hello");  
60 - change_mutable(&mut s_mut);  
61 -  
62 - // but you can have only one mutable reference of a value in a single  
63 - // scope. The following would fail with:  
64 - // cannot borrow `s_mut` as mutable more than once at a time second  
65 - // mutable borrow occurs here  
66 - // let r1 = &mut s_mut;  
67 - // let r2 = &mut s_mut;  
68 - // println!("{}, {}", r1, r2);  
69 -  
70 - // We also can't have an immutable reference while we have a mutable one.  
71 - // Look on Page 98 for an explanation.  
72 -  
73 - // The scope of references is not the whole block they are introduced in  
74 - // but goes only until their last usage. Thus if you first have an  
75 - // immutable reference but never use it after a mutable reference is  
76 - // declared, that would be ok… At all this is kind of confusing and very  
77 - // Mozzilaish. :D  
78 -  
79 - // Now we demonstrate string slices…  
80 - let s4 = String::from("hello world");  
81 - let s_slice = first_word(&s4);  
82 -  
83 - // working with an mutable reference like with s4.clear() will not  
84 - // compile at this point because we already have and use later on an  
85 - // immutable reference.  
86 -  
87 - println!("The slice was: {}", s_slice);  
88 -  
89 - // not that string literals are slices. They are immutable references of  
90 - // the programs TEXT segment. Thats the reason why they are immutable.  
91 -  
92 - // Thus try generic_first_word…  
93 - println!("First word on literal: {}", generic_first_word("hello world"));  
94 - println!("First word on String: {}", generic_first_word(&s4[..]));  
95 -} // x and s go out of scope but nothing happens for s because this function  
96 - // has no longer the ownership of s.  
97 - // s3 goes out of scope and is dropped. s2 was moved and s1 is dropped.  
98 -  
99 -fn concat() {  
100 - let mut s = String::from("hello");  
101 - s.push_str(", world!");  
102 - println!("{}", s);  
103 -}  
104 -  
105 -fn move_variable() {  
106 - let s1 = String::from("hello");  
107 - let s2 = s1; // does not copy data but only the String structure.  
108 - // when using s1 below we get an error that a moved value was borrowed.  
109 - println!("{}, world!", s2);  
110 -}  
111 -  
112 -fn clone_variable() {  
113 - let s1 = String::from("hello");  
114 - let s2 = s1.clone();  
115 - // this time both are valid.  
116 - println!("s1 = {}, s2 = {}", s1, s2)  
117 -}  
118 -  
119 -fn take_ownership(some_string: String) { // some_string comes into scope  
120 - println!("{}", some_string);  
121 -} // some_string goes out of scope and «drop» is called, thus memory freed.  
122 -  
123 -fn makes_copy(some_integer: i32) { // some integer comes into scope  
124 - println!("{}", some_integer);  
125 -} // Here, some_integer goes out of scope but because it was a copy and on the  
126 - // stack nothing special happens… beside that stack space is freed.  
127 -  
128 -fn gives_ownership() -> String { // this will move the return value into the  
129 - // calling function.  
130 - let some_string = String::from("hello"); // some_string comes into scope  
131 - some_string  
132 -}  
133 -  
134 -fn takes_and_gives(a_string: String) -> String { // a_string comes into scope  
135 - a_string // and is returned and moved  
136 - // to the calling function.  
137 -} // a_string goes out of scope but nothing happens as it is moved.  
138 -  
139 -fn calculate_length(s: &String) -> usize { // s comes into scope. It is a  
140 - // reference. References do not  
141 - // take ownership of the underlying  
142 - // value which is the String in  
143 - // main.  
144 - s.len()  
145 -} // Here s goes out of scope but because it has no ownership of the String  
146 - // nothing happens.  
147 -  
148 -fn change(_some_string: &String) {  
149 - // the following would give this error:  
150 - // `_some_string` is a `&` reference, so the data it refers to cannot be  
151 - // borrowed as mutable  
152 - // _some_string.push_str(", world!");  
153 -}  
154 -  
155 -fn change_mutable(some_string: &mut String) {  
156 - some_string.push_str(", world");  
157 -}  
158 -  
159 -fn first_word(s: &String) -> &str {  
160 - let bytes = s.as_bytes();  
161 -  
162 - for (i, &item) in bytes.iter().enumerate() {  
163 - if item == b' ' {  
164 - return &s[..i];  
165 - }  
166 - }  
167 -  
168 - &s[..]  
169 -}  
170 -  
171 -// To make first_word work on either string literals (which are in fact string  
172 -// slices, s.o.) one would write first_word like this…  
173 -fn generic_first_word(s: &str) -> &str {  
174 - let bytes = s.as_bytes();  
175 -  
176 - for (i, &item) in bytes.iter().enumerate() {  
177 - if item == b' ' {  
178 - return &s[..i];  
179 - }  
180 - }  
181 -  
182 - &s[..]  
183 -}  
1 -[package]  
2 -name = "rectangles"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  
8 -  
9 -[dependencies]  
1 -//  
2 -// Examples related to structs…  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -  
22 -#[derive(Debug)]  
23 -struct Rectangle {  
24 - width: u32,  
25 - height: u32,  
26 -}  
27 -  
28 -impl Rectangle {  
29 - fn area(&self) -> u32 {  
30 - self.width * self.height  
31 - }  
32 -  
33 - fn can_hold(&self, inner: &Rectangle) -> bool {  
34 - self.width >= inner.width && self.height >= inner.height  
35 - }  
36 -  
37 - fn square(size: u32) -> Rectangle {  
38 - Rectangle { width: size, height: size }  
39 - }  
40 -}  
41 -  
42 -fn main() {  
43 - let width1 = 30;  
44 - let height1 = 50;  
45 -  
46 - println!(  
47 - "The area of the rectangle ist {} square pixels.",  
48 - area(width1, height1));  
49 -  
50 - let rect1 = (30, 50);  
51 -  
52 - println!(  
53 - "The area of the rectangle ist {} square pixels.",  
54 - _area(rect1));  
55 -  
56 - let rect1 = Rectangle { width: 30, height: 50 };  
57 -  
58 - println!(  
59 - "The area of the rectangle ist {} square pixels.",  
60 - __area(&rect1));  
61 -  
62 - println!("_rect1 is {:?}", rect1);  
63 -  
64 - println!(  
65 - "The area of the rectangle ist {} square pixels.",  
66 - rect1.area());  
67 -  
68 - let rect2 = Rectangle { width: 10, height: 40};  
69 - let rect3 = Rectangle { width: 60, height: 45};  
70 -  
71 - println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));  
72 - println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));  
73 -  
74 - let square1 = Rectangle::square(32);  
75 -  
76 - println!("Got the square rectange: {:?}", square1);  
77 -}  
78 -  
79 -fn area(width: u32, height: u32) -> u32 {  
80 - width * height  
81 -}  
82 -  
83 -fn _area(dimensions: (u32, u32)) -> u32 {  
84 - let (width, height) = dimensions;  
85 - width * height  
86 -}  
87 -  
88 -fn __area(rectangle: &Rectangle) -> u32 {  
89 - rectangle.width * rectangle.height  
90 -}  
1 -[package]  
2 -name = "recursion"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  
8 -  
9 -[dependencies]  
1 -//  
2 -// Try some recursion with pattern matching... especially in  
3 -// conjunction with match to get a similar behavious as in e.g.  
4 -// haskell...  
5 -//  
6 -// Georg Hopp <georg@steffers.org>  
7 -//  
8 -// Copyright © 2019 Georg Hopp  
9 -//  
10 -// This program is free software: you can redistribute it and/or modify  
11 -// it under the terms of the GNU General Public License as published by  
12 -// the Free Software Foundation, either version 3 of the License, or  
13 -// (at your option) any later version.  
14 -//  
15 -// This program is distributed in the hope that it will be useful,  
16 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
17 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
18 -// GNU General Public License for more details.  
19 -//  
20 -// You should have received a copy of the GNU General Public License  
21 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
22 -//  
23 -  
24 -// Borrowing rules do not apply here because everything lives on the stack.  
25 -fn faculty(x: u32) -> u32 {  
26 - match x {  
27 - 0 => 1,  
28 - _ => x * faculty(x - 1),  
29 - }  
30 -}  
31 -  
32 -// for a tail recursive version we need to pass the currently calculated  
33 -// faculty to an inner tail recursive function.  
34 -// This will probably be optimized better, because the compiler would be  
35 -// able to unroll the complete recursion.  
36 -fn tail_faculty(x: u32) -> u32 {  
37 - fn faculty(x: u32, f: u32) -> u32 {  
38 - match x {  
39 - 0 => f,  
40 - _ => faculty(x - 1, x * f),  
41 - }  
42 - };  
43 - faculty(x, 1)  
44 -}  
45 -  
46 -fn main() {  
47 - for i in 0..10 {  
48 - println!("Fakultät {} = {}", i, faculty(i));  
49 - println!("tail recursive Fakultät {} = {}", i, tail_faculty(i));  
50 - }  
51 -}  
1 -[package]  
2 -name = "restaurant"  
3 -version = "0.1.0"  
4 -authors = ["Georg Hopp <georg@steffers.org>"]  
5 -edition = "2018"  
6 -  
7 -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  
8 -  
9 -[dependencies]  
1 -//  
2 -// Move some restaurant stuff in a different file....  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -  
22 -pub mod hosting;  
23 -  
24 -mod serving {  
25 - fn take_order() {}  
26 - fn take_payment() {}  
27 -}  
1 -//  
2 -// Now also sepatate hosting....  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -  
22 -pub fn add_to_waitlist() {}  
23 -fn seat_at_table() {}  
1 -//  
2 -// Restaurant lib for demontrating rust modules.  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -  
22 -mod front_of_house;  
23 -  
24 -fn serve_order() {}  
25 -  
26 -mod back_of_house {  
27 - pub struct Breakfast {  
28 - pub toast: String,  
29 - seasonal_fruit: String,  
30 - }  
31 -  
32 - impl Breakfast {  
33 - pub fn summer(toast: &str) -> Breakfast {  
34 - Breakfast {  
35 - toast: String::from(toast),  
36 - seasonal_fruit: String::from("peaches"),  
37 - }  
38 - }  
39 - }  
40 -  
41 - pub enum Appetizer {  
42 - Soup,  
43 - Salad,  
44 - }  
45 -  
46 - fn fix_incorrect_order() {  
47 - cook_order();  
48 - super::serve_order();  
49 - }  
50 -  
51 - fn cook_order() {}  
52 -}  
53 -  
54 -// Either absolute:  
55 -// use crate::front_of_house::hosting;  
56 -// or relaive:  
57 -use front_of_house::hosting;  
58 -// we can also provide new names...  
59 -use crate::front_of_house::hosting as host;  
60 -// Public definitions braught into scope with use are  
61 -// private in this scope except we use «pub use»  
62 -pub use front_of_house::hosting as pubhost;  
63 -  
64 -pub fn eat_at_restaurant() {  
65 - // Absolute path  
66 - crate::front_of_house::hosting::add_to_waitlist();  
67 -  
68 - // Relative path  
69 - front_of_house::hosting::add_to_waitlist();  
70 -  
71 - // With use'd path  
72 - hosting::add_to_waitlist();  
73 -  
74 - // With renamed used path  
75 - host::add_to_waitlist();  
76 -  
77 - pubhost::add_to_waitlist();  
78 -  
79 - // Order a breakfast in the summer with Rye toast  
80 - let mut meal = back_of_house::Breakfast::summer("Rye");  
81 -  
82 - // Change our mind about what bread we'd like  
83 - meal.toast = String::from("Wheat");  
84 -  
85 - println!("I'd like {} toast please", meal.toast);  
86 -  
87 - // The next line won't compile if we uncomment it; we're not allowed  
88 - // to see or modify the seasonal fruit that comes with the meal  
89 - // meal.seasonal_fruit = String::from("blueberries");  
90 -  
91 - let order1 = back_of_house::Appetizer::Soup;  
92 - let order2 = back_of_house::Appetizer::Salad;  
93 -}  
@@ -20,13 +20,16 @@ @@ -20,13 +20,16 @@
20 // 20 //
21 extern crate xcb; 21 extern crate xcb;
22 22
  23 +use std::fmt::Debug;
23 use std::sync::Arc; 24 use std::sync::Arc;
24 -use std::ptr; //::{null, null_mut}; 25 +use std::ptr;
25 use std::thread; 26 use std::thread;
26 use std::sync::mpsc; 27 use std::sync::mpsc;
27 use std::ops::{Add, Sub, Div}; 28 use std::ops::{Add, Sub, Div};
28 29
29 -use crate::easel::{Easel, Canvas, Drawable, Coordinate, Coordinates}; 30 +use easel3d::easel::Easel;
  31 +use easel3d::easel::canvas::{Canvas, Vertex};
  32 +use easel3d::easel::drawable::Drawable;
30 33
31 #[derive(Clone)] 34 #[derive(Clone)]
32 pub struct XcbEasel (Arc<xcb::Connection>, i32); 35 pub struct XcbEasel (Arc<xcb::Connection>, i32);
@@ -62,6 +65,7 @@ impl XcbEasel { @@ -62,6 +65,7 @@ impl XcbEasel {
62 , height :u16) -> Option<XcbCanvas<'a, T>> 65 , height :u16) -> Option<XcbCanvas<'a, T>>
63 where T: Clone + From<i32> { 66 where T: Clone + From<i32> {
64 let Self(conn, _) = self; 67 let Self(conn, _) = self;
  68 + let size = width as usize * height as usize;
65 let conn = conn.clone(); 69 let conn = conn.clone();
66 let screen = match self.screen() { 70 let screen = match self.screen() {
67 None => return None, 71 None => return None,
@@ -85,8 +89,8 @@ impl XcbEasel { @@ -85,8 +89,8 @@ impl XcbEasel {
85 , &[ (xcb::GC_FOREGROUND, screen.white_pixel()) 89 , &[ (xcb::GC_FOREGROUND, screen.white_pixel())
86 , (xcb::GC_GRAPHICS_EXPOSURES, 0) ] ); 90 , (xcb::GC_GRAPHICS_EXPOSURES, 0) ] );
87 91
88 - let zbuf :Vec<T> = vec!(0.into(); (width * height) as usize);  
89 - let (shmid, shm) = getshm((width * height) as usize); 92 + let zbuf :Vec<T> = vec!(0.into(); size);
  93 + let (shmid, shm) = getshm(size);
90 xcb::shm::attach(&conn, shmseg, shmid as u32, false); 94 xcb::shm::attach(&conn, shmseg, shmid as u32, false);
91 unsafe { libc::shmctl(shmid, libc::IPC_RMID, ptr::null_mut()); } 95 unsafe { libc::shmctl(shmid, libc::IPC_RMID, ptr::null_mut()); }
92 96
@@ -138,7 +142,7 @@ impl Easel for XcbEasel {} @@ -138,7 +142,7 @@ impl Easel for XcbEasel {}
138 142
139 impl<'a, T> Canvas<T> for XcbCanvas<'a, T> 143 impl<'a, T> Canvas<T> for XcbCanvas<'a, T>
140 where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> 144 where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
141 - + Copy + From<i32> + PartialOrd { 145 + + Debug + Copy + From<i32> + PartialOrd {
142 fn init_events(&self) { 146 fn init_events(&self) {
143 let mask = [( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE 147 let mask = [( xcb::CW_EVENT_MASK, xcb::EVENT_MASK_EXPOSURE
144 | xcb::EVENT_MASK_KEY_PRESS 148 | xcb::EVENT_MASK_KEY_PRESS
@@ -233,12 +237,10 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> @@ -233,12 +237,10 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
233 } 237 }
234 } 238 }
235 239
236 - fn draw(&mut self, d :&dyn Drawable<T>, ofs :Coordinate<T>, color: u32) {  
237 - let Coordinates(c) = d.plot();  
238 - let Coordinate(xofs, yofs, _) = ofs;  
239 -  
240 - for Coordinate(x, y, zr) in c {  
241 - let idx :usize = ((y+yofs)*(self.width as i32)+x+xofs) as usize; 240 + fn draw(&mut self, d :&dyn Drawable<T>, color: u32) {
  241 + for c in d.plot() {
  242 + let (x, y, zr) = c.as_tuple();
  243 + let idx :usize = (y*(self.width as i32)+x) as usize;
242 if self.zbuf[idx] < zr { 244 if self.zbuf[idx] < zr {
243 self.zbuf[idx] = zr; 245 self.zbuf[idx] = zr;
244 self.shm[idx] = color; 246 self.shm[idx] = color;
@@ -246,15 +248,15 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T> @@ -246,15 +248,15 @@ where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>
246 } 248 }
247 } 249 }
248 250
249 - fn put_text(&self, ofs :Coordinate<T>, s :&str) {  
250 - let Coordinate(xofs, yofs, _) = ofs; 251 + fn put_text(&self, ofs :Vertex<T>, s :&str) {
  252 + let (xofs, yofs, _) = ofs.as_tuple();
251 xcb::xproto::image_text_8( &self.conn, self.pixmap, self.gc 253 xcb::xproto::image_text_8( &self.conn, self.pixmap, self.gc
252 , xofs as i16, yofs as i16, s ); 254 , xofs as i16, yofs as i16, s );
253 self.conn.flush(); 255 self.conn.flush();
254 } 256 }
255 257
256 - fn set_pixel(&mut self, c :Coordinate<T>, color :u32) {  
257 - let Coordinate(x, y, zr) = c; 258 + fn set_pixel(&mut self, c :Vertex<T>, color :u32) {
  259 + let (x, y, zr) = c.as_tuple();
258 let idx :usize = (y * (self.width as i32) + x) as usize; 260 let idx :usize = (y * (self.width as i32) + x) as usize;
259 261
260 if self.zbuf[idx] < zr { 262 if self.zbuf[idx] < zr {
  1 +//
  2 +// Test our fractional crate / module...
  3 +//
  4 +// Georg Hopp <georg@steffers.org>
  5 +//
  6 +// Copyright © 2019 Georg Hopp
  7 +//
  8 +// This program is free software: you can redistribute it and/or modify
  9 +// it under the terms of the GNU General Public License as published by
  10 +// the Free Software Foundation, either version 3 of the License, or
  11 +// (at your option) any later version.
  12 +//
  13 +// This program is distributed in the hope that it will be useful,
  14 +// but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 +// GNU General Public License for more details.
  17 +//
  18 +// You should have received a copy of the GNU General Public License
  19 +// along with this program. If not, see <http://www.gnu.org/licenses/>.
  20 +//
  21 +
  22 +use std::fmt::Debug;
  23 +use std::ops::{Add, Div, Mul, Neg, Sub};
  24 +use std::sync::mpsc;
  25 +use std::thread;
  26 +use std::time::{Duration, Instant};
  27 +
  28 +use easel3d::easel::canvas::{Vertex, Canvas};
  29 +use easel3d::easel::fillable::Fillable;
  30 +use easel3d::math::trigonometry::Trig;
  31 +use easel3d::math::vector::Vector;
  32 +use easel3d::math::transform::TMatrix;
  33 +use easel3d::space::camera::Camera;
  34 +use easel3d::space::light::DirectLight;
  35 +use easel3d::space::polyeder::Polyeder;
  36 +use easel3d::space::primitives::Primitives;
  37 +
  38 +mod easel3d_xcb;
  39 +
  40 +use easel3d_xcb::XcbEasel;
  41 +
  42 +fn democanvas<T>( xcb :&XcbEasel
  43 + , title :&'static str
  44 + , tx :mpsc::Sender<i32>
  45 + , _triangle :Polyeder<T>
  46 + , tetrahedron :Polyeder<T>
  47 + , cube :Polyeder<T>
  48 + , light :DirectLight<T> )
  49 + where T: 'static + Add<Output = T> + Sub<Output = T> + Neg<Output = T>
  50 + + Mul<Output = T> + Div<Output = T>
  51 + + Debug + Copy + Trig + Send + From<i32> + From<f64> + PartialOrd {
  52 +
  53 + let mut canvas = xcb.canvas(301, 301).unwrap();
  54 + let camera = Camera::<T>::new(&canvas, 45); // the orig. view angle
  55 + // was 50.
  56 +
  57 + canvas.set_title(title);
  58 + canvas.init_events();
  59 + canvas.start_events(tx.clone());
  60 +
  61 + thread::spawn(move || {
  62 + let start = Instant::now();
  63 + let step = Duration::from_millis(20);
  64 + let mut last = Instant::now();
  65 +
  66 + let t = TMatrix::translate(Vector(0.into() , 0.into() , 150.into()));
  67 +
  68 + loop {
  69 + let deg = ((start.elapsed() / 20).as_millis() % (4*360)) as i32;
  70 +
  71 + let rz = TMatrix::rotate_z(deg);
  72 + let rx = TMatrix::rotate_x(-deg*2);
  73 + let ry = TMatrix::rotate_y(-deg*2);
  74 +
  75 + let rot1 = TMatrix::combine(vec!(rz, rx, t));
  76 + let rot2 = TMatrix::combine(vec!(rz, ry, t));
  77 +
  78 + let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00)
  79 + , ( cube.transform(&rot2), 0x0000FF) );
  80 + //let objects = vec!( ( cube.transform(&rot2), 0x0000FF) );
  81 + //let objects = vec!( (tetrahedron.transform(&rot1), 0xFFFF00) );
  82 + //let objects = vec!( (triangle.transform(&rot1), 0xFFFF00) );
  83 +
  84 + let rlx = TMatrix::rotate_x(-deg/4);
  85 + let rly = TMatrix::rotate_y(-deg/1);
  86 + let tlight = light.transform(&TMatrix::combine(vec!(rlx, rly)));
  87 +
  88 + canvas.clear();
  89 +
  90 + for (o, color) in objects {
  91 + for (pg, c) in o.project(&camera, &tlight, color) {
  92 + (&pg).fill(&mut canvas, c);
  93 + }
  94 + }
  95 +
  96 + let passed = Instant::now() - last;
  97 + let f = (passed.as_nanos() / step.as_nanos()) as u32;
  98 +
  99 + if f > 1 {
  100 + println!("{} !!! Detected frame drop", title);
  101 + }
  102 +
  103 + last = last + step*(f + 1);
  104 + canvas.put_text( Vertex::new(10, 15, 0.into())
  105 + , &format!( "sleep: {:?}"
  106 + , last - Instant::now() ));
  107 + canvas.show();
  108 + thread::sleep(last - Instant::now());
  109 + }
  110 + });
  111 +}
  112 +
  113 +fn main() {
  114 + let xcb = XcbEasel::new().unwrap();
  115 + let (tx, rx) = mpsc::channel();
  116 +
  117 + democanvas( &xcb, "Something...(f64)", tx.clone()
  118 + , Polyeder::triangle(60.0)
  119 + , Polyeder::tetrahedron(100.0)
  120 + , Polyeder::cube(56.25)
  121 + , DirectLight::new(Vector(0.0, 0.0, 1.0)) );
  122 +
  123 + for x in rx {
  124 + match x {
  125 + 1 => break,
  126 + _ => {},
  127 + }
  128 + }
  129 +}
1 -/target  
2 -**/*.rs.bk  
3 -Cargo.lock  
4 -bin/  
5 -pkg/  
6 -wasm-pack/  
7 -wasm-pack.log  
1 -[package]  
2 -name = "wasm-game-of-life"  
3 -version = "0.1.0"  
4 -authors = ["hopp@silpion.de"]  
5 -edition = "2018"  
6 -  
7 -[lib]  
8 -crate-type = ["cdylib", "rlib"]  
9 -  
10 -[features]  
11 -default = ["console_error_panic_hook"]  
12 -  
13 -[dependencies]  
14 -wasm-bindgen = "0.2"  
15 -lazy_static = "1.4.0"  
16 -  
17 -# The `console_error_panic_hook` crate provides better debugging of panics by  
18 -# logging them with `console.error`. This is great for development, but requires  
19 -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for  
20 -# code size when deploying.  
21 -console_error_panic_hook = { version = "0.1.1", optional = true }  
22 -  
23 -# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size  
24 -# compared to the default allocator's ~10K. It is slower than the default  
25 -# allocator, however.  
26 -#  
27 -# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now.  
28 -wee_alloc = { version = "0.4.2", optional = true }  
29 -  
30 -[dev-dependencies]  
31 -wasm-bindgen-test = "0.2"  
32 -  
33 -[profile.release]  
34 -# Tell `rustc` to optimize for small code size.  
35 -opt-level = "s"  
1 -<div align="center">  
2 -  
3 - <h1><code>wasm-pack-template</code></h1>  
4 -  
5 - <strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong>  
6 -  
7 - <p>  
8 - <a href="https://travis-ci.org/rustwasm/wasm-pack-template"><img src="https://img.shields.io/travis/rustwasm/wasm-pack-template.svg?style=flat-square" alt="Build Status" /></a>  
9 - </p>  
10 -  
11 - <h3>  
12 - <a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a>  
13 - <span> | </span>  
14 - <a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>  
15 - </h3>  
16 -  
17 - <sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>  
18 -</div>  
19 -  
20 -## About  
21 -  
22 -[**📚 Read this template tutorial! 📚**][template-docs]  
23 -  
24 -This template is designed for compiling Rust libraries into WebAssembly and  
25 -publishing the resulting package to NPM.  
26 -  
27 -Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other  
28 -templates and usages of `wasm-pack`.  
29 -  
30 -[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html  
31 -[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html  
32 -  
33 -## 🚴 Usage  
34 -  
35 -### 🐑 Use `cargo generate` to Clone this Template  
36 -  
37 -[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)  
38 -  
39 -```  
40 -cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project  
41 -cd my-project  
42 -```  
43 -  
44 -### 🛠️ Build with `wasm-pack build`  
45 -  
46 -```  
47 -wasm-pack build  
48 -```  
49 -  
50 -### 🔬 Test in Headless Browsers with `wasm-pack test`  
51 -  
52 -```  
53 -wasm-pack test --headless --firefox  
54 -```  
55 -  
56 -### 🎁 Publish to NPM with `wasm-pack publish`  
57 -  
58 -```  
59 -wasm-pack publish  
60 -```  
61 -  
62 -## 🔋 Batteries Included  
63 -  
64 -* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating  
65 - between WebAssembly and JavaScript.  
66 -* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)  
67 - for logging panic messages to the developer console.  
68 -* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized  
69 - for small code size.  
1 -{  
2 - "lockfileVersion": 1  
3 -}  
1 -//  
2 -// This is an abstraction over a drawing environment.  
3 -// Future note: z-Buffer is described here:  
4 -// https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes  
5 -//  
6 -// Georg Hopp <georg@steffers.org>  
7 -//  
8 -// Copyright © 2019 Georg Hopp  
9 -//  
10 -// This program is free software: you can redistribute it and/or modify  
11 -// it under the terms of the GNU General Public License as published by  
12 -// the Free Software Foundation, either version 3 of the License, or  
13 -// (at your option) any later version.  
14 -//  
15 -// This program is distributed in the hope that it will be useful,  
16 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
17 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
18 -// GNU General Public License for more details.  
19 -//  
20 -// You should have received a copy of the GNU General Public License  
21 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
22 -//  
23 -use std::cmp;  
24 -use std::fmt::{Formatter, Debug, Display, Result};  
25 -use std::ops::{Add, Sub, Div};  
26 -use std::sync::mpsc;  
27 -  
28 -pub trait Easel {  
29 - //fn canvas(&mut self, width :u16, height :u16) -> Option<&dyn Canvas>;  
30 -}  
31 -  
32 -pub trait Canvas<T> {  
33 - fn init_events(&self);  
34 - fn start_events(&self, tx :mpsc::Sender<i32>);  
35 -  
36 - fn width(&self) -> u16;  
37 - fn height(&self) -> u16;  
38 -  
39 - fn clear(&mut self);  
40 - fn draw(&mut self, c :&dyn Drawable<T>, ofs :Coordinate<T>, color :u32);  
41 - fn put_text(&self, ofs :Coordinate<T>, s :&str);  
42 - fn set_pixel(&mut self, c :Coordinate<T>, color :u32);  
43 - fn show(&self);  
44 -}  
45 -  
46 -pub trait Drawable<T> {  
47 - fn plot(&self) -> Coordinates<T>;  
48 -}  
49 -  
50 -pub trait Fillable<T>  
51 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
52 - + Debug + Copy + From<i32> {  
53 - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32);  
54 -}  
55 -  
56 -#[derive(Debug, Clone, Copy)]  
57 -pub struct Coordinate<T>(pub i32, pub i32, pub T);  
58 -  
59 -#[derive(Debug, Clone)]  
60 -pub struct Coordinates<T>(pub Vec<Coordinate<T>>);  
61 -  
62 -#[derive(Debug, Clone, Copy)]  
63 -pub struct LineIterator<T> where T: Debug {  
64 - a :Option<Coordinate<T>>  
65 - , b :Coordinate<T>  
66 - , dx :i32  
67 - , dy :i32  
68 - , dz :T  
69 - , sx :i32  
70 - , sy :i32  
71 - , err :i32  
72 - , only_edges :bool  
73 -}  
74 -  
75 -impl<T> Iterator for LineIterator<T>  
76 -where T: Add<Output = T> + Debug + Copy + From<i32> {  
77 - type Item = Coordinate<T>;  
78 -  
79 - fn next(&mut self) -> Option<Self::Item> {  
80 - match self.a {  
81 - None => None,  
82 - Some(a) => {  
83 - let Coordinate(ax, ay, az) = a;  
84 - let Coordinate(bx, by, _) = self.b;  
85 -  
86 - if ax != bx || ay != by {  
87 - match (2 * self.err >= self.dy, 2 * self.err <= self.dx ) {  
88 - (true, false) => {  
89 - let r = self.a;  
90 - self.a = Some(Coordinate( ax + self.sx  
91 - , ay  
92 - , az + self.dz ));  
93 - self.err = self.err + self.dy;  
94 - if self.only_edges { self.next() } else { r }  
95 - },  
96 - (false, true) => {  
97 - let r = self.a;  
98 - self.a = Some(Coordinate( ax  
99 - , ay + self.sy  
100 - , az + self.dz ));  
101 - self.err = self.err + self.dx;  
102 - r  
103 - },  
104 - _ => {  
105 - let r = self.a;  
106 - self.a = Some(Coordinate( ax + self.sx  
107 - , ay + self.sy  
108 - , az + self.dz ));  
109 - self.err = self.err + self.dx + self.dy;  
110 - r  
111 - },  
112 - }  
113 - } else {  
114 - self.a = None;  
115 - Some(self.b)  
116 - }  
117 - }  
118 - }  
119 - }  
120 -}  
121 -  
122 -impl<T> Coordinate<T>  
123 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
124 - + Debug + Clone + Copy + From<i32> {  
125 - fn iter(self, b :&Self, only_edges :bool) -> LineIterator<T> {  
126 - let Coordinate(ax, ay, az) = self;  
127 - let Coordinate(bx, by, bz) = *b;  
128 -  
129 - let dx = (bx - ax).abs();  
130 - let dy = -(by - ay).abs();  
131 -  
132 - LineIterator { a: Some(self)  
133 - , b: *b  
134 - , dx: dx  
135 - , dy: dy  
136 - , dz: (bz - az) / cmp::max(dx, -dy).into()  
137 - , sx: if ax < bx { 1 } else { -1 }  
138 - , sy: if ay < by { 1 } else { -1 }  
139 - , err: dx + dy  
140 - , only_edges: only_edges  
141 - }  
142 - }  
143 -  
144 - fn line_iter(self, b :&Self) -> LineIterator<T> {  
145 - self.iter(b, false)  
146 - }  
147 -  
148 - fn line(self, b :&Self) -> Vec<Self> {  
149 - self.line_iter(b).collect()  
150 - }  
151 -  
152 - fn edge_iter(self, b :&Self) -> LineIterator<T> {  
153 - self.iter(b, true)  
154 - }  
155 -  
156 - fn edge(self, b :&Self) -> Vec<Self> {  
157 - self.edge_iter(b).collect()  
158 - }  
159 -  
160 - fn face(edges :&[Self]) -> Vec<Self> {  
161 - edges.to_vec()  
162 - }  
163 -}  
164 -  
165 -impl<T> Display for Coordinate<T> {  
166 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
167 - write!(f, "<{},{}>", self.0, self.1)  
168 - }  
169 -}  
170 -  
171 -impl<T> Display for Coordinates<T> where T: Copy {  
172 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
173 - let Coordinates(is) = self;  
174 -  
175 - let c = match is[..] {  
176 - [] => String::from(""),  
177 - [a] => format!("{}", a),  
178 - _ => {  
179 - let mut a = format!("{}", is[0]);  
180 - for i in is[1..].iter() {  
181 - a = a + &format!(",{}", i);  
182 - }  
183 - a  
184 - }  
185 - };  
186 -  
187 - write!(f, "Coordinates[{}]", c)  
188 - }  
189 -}  
190 -  
191 -  
192 -#[derive(Debug, Clone, Copy)]  
193 -pub struct Point<T>(pub Coordinate<T>);  
194 -  
195 -impl<T> Drawable<T> for Point<T> where T: Copy {  
196 - fn plot(&self) -> Coordinates<T> {  
197 - let Point(c) = *self;  
198 - Coordinates(vec!(c))  
199 - }  
200 -}  
201 -  
202 -impl<T> Display for Point<T> {  
203 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
204 - let Point(p) = self;  
205 - write!(f, "Point[{}]", p)  
206 - }  
207 -}  
208 -  
209 -#[derive(Debug, Clone, Copy)]  
210 -pub struct Line<T>(pub Coordinate<T>, pub Coordinate<T>);  
211 -  
212 -impl<T> Drawable<T> for Line<T>  
213 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
214 - + Debug + Clone + Copy + From<i32> {  
215 - fn plot(&self) -> Coordinates<T> {  
216 - let Line(a, b) = *self;  
217 - Coordinates(a.line(&b))  
218 - }  
219 -}  
220 -  
221 -impl<T> Display for Line<T> {  
222 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
223 - let Line(a, b) = self;  
224 - write!(f, "Line[{},{}]", a, b)  
225 - }  
226 -}  
227 -  
228 -#[derive(Debug, Clone)]  
229 -pub struct Polyline<T>(pub Coordinates<T>);  
230 -  
231 -impl<T> Drawable<T> for Polyline<T>  
232 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
233 - + Debug + Clone + Copy + From<i32> {  
234 - fn plot(&self) -> Coordinates<T> {  
235 - let Polyline(Coordinates(cs)) = self;  
236 -  
237 - match cs[..] {  
238 - [] => Coordinates(Vec::<Coordinate<T>>::new()),  
239 - [a] => Coordinates(vec!(a)),  
240 - [a, b] => Coordinates(a.line(&b)),  
241 - _ => {  
242 - let (a, b) = (cs[0], cs[1]);  
243 - let mut r = a.line(&b);  
244 - let mut i = b;  
245 - for j in cs[2..].iter() {  
246 - r.append(&mut i.line(j)[1..].to_vec());  
247 - i = *j;  
248 - }  
249 - Coordinates(r)  
250 - },  
251 - }  
252 - }  
253 -}  
254 -  
255 -impl<T> Display for Polyline<T> where T: Copy {  
256 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
257 - let Polyline(a) = self;  
258 - write!(f, "PLine[{}]", a)  
259 - }  
260 -}  
261 -  
262 -#[derive(Debug, Clone, Copy)]  
263 -enum Direction { Left, Right }  
264 -  
265 -#[derive(Debug, Clone)]  
266 -pub struct Polygon<T>(pub Coordinates<T>);  
267 -  
268 -#[derive(Debug, Clone)]  
269 -enum VertexIteratorMode { Vertex, Edge }  
270 -#[derive(Debug, Clone)]  
271 -pub struct VertexIterator<'a,T> where T: Debug {  
272 - p :&'a Polygon<T>,  
273 - top :usize,  
274 - current :Option<usize>,  
275 - edge :Option<LineIterator<T>>,  
276 - mode :VertexIteratorMode,  
277 - direction :Direction,  
278 -}  
279 -  
280 -impl<'a,T> VertexIterator<'a,T>  
281 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
282 - + Debug + Copy + From<i32> {  
283 - fn edge(p :&'a Polygon<T>, direction :Direction) -> Self {  
284 - let top = p.vert_min(direction);  
285 - let next = p.next_y(top, direction);  
286 - let edge = match next {  
287 - None => None,  
288 - Some(next) => Some(p.vertex(top).edge_iter(&p.vertex(next))),  
289 - };  
290 -  
291 - VertexIterator { p: p  
292 - , top: top  
293 - , current: next  
294 - , edge: edge  
295 - , mode: VertexIteratorMode::Edge  
296 - , direction: direction }  
297 - }  
298 -  
299 - fn vertex(p :&'a Polygon<T>, direction :Direction) -> Self {  
300 - let top = p.vert_min(direction);  
301 - let next = p.next_y(top, direction);  
302 -  
303 - VertexIterator { p: p  
304 - , top: top  
305 - , current: next  
306 - , edge: None  
307 - , mode: VertexIteratorMode::Vertex  
308 - , direction: direction }  
309 - }  
310 -  
311 - // if this yields "None" we are finished.  
312 - fn next_edge(&mut self) -> Option<LineIterator<T>> {  
313 - let current = self.current?;  
314 - let next = self.p.next_y(current, self.direction)?;  
315 - let mut edge = self.p.vertex(current).edge_iter(&self.p.vertex(next));  
316 -  
317 - match edge.next() {  
318 - // It should be impossible that a new edge iterator has no values  
319 - // at all… anyway, just in case I handle it here.  
320 - None => self.next_edge(),  
321 - Some(_) => {  
322 - self.current = Some(next);  
323 - self.edge = Some(edge);  
324 - self.edge  
325 - },  
326 - }  
327 - }  
328 -}  
329 -  
330 -impl<'a,T> Iterator for VertexIterator<'a,T>  
331 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
332 - + Debug + Copy + From<i32> {  
333 - type Item = Coordinate<T>;  
334 -  
335 - fn next(&mut self) -> Option<Self::Item> {  
336 - match self.mode {  
337 - VertexIteratorMode::Edge => {  
338 - // if for whatever reason edge is "None" finish this iterator.  
339 - let next = self.edge.as_mut()?.next();  
340 -  
341 - match next {  
342 - Some(_) => next,  
343 - None => {  
344 - self.next_edge()?;  
345 - self.next()  
346 - },  
347 - }  
348 - },  
349 - VertexIteratorMode::Vertex => {  
350 - let current = self.current?;  
351 - self.current = self.p.next_y(current, self.direction);  
352 - Some(self.p.vertex(current))  
353 - },  
354 - }  
355 - }  
356 -}  
357 -  
358 -impl<T> Polygon<T>  
359 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
360 - + Copy + Debug + From<i32> {  
361 - #[inline]  
362 - fn vertex(&self, v :usize) -> Coordinate<T> {  
363 - let Polygon(Coordinates(cs)) = self;  
364 - cs[v]  
365 - }  
366 -  
367 - fn vert_min<'a>(&'a self, d :Direction) -> usize {  
368 - let Polygon(Coordinates(cs)) = self;  
369 -  
370 - type ICoord<'a,T> = (usize, &'a Coordinate<T>);  
371 -  
372 - // TODO I guess the problem here is that it does not account for the  
373 - // same y vertex on the beggining and the end. So i guess correct  
374 - // would be finding the first one and then dependings on the  
375 - // given direction either search left or right for same y's.  
376 - let fold = |acc :Option<ICoord<'a,T>>, x :ICoord<'a,T>|  
377 - match acc {  
378 - None => Some(x),  
379 - Some(a) => {  
380 - let Coordinate(_, ay, _) = a.1;  
381 - let Coordinate(_, xy, _) = x.1;  
382 - if xy < ay {Some(x)} else {Some(a)}  
383 - },  
384 - };  
385 -  
386 - let mut min = cs.iter().enumerate().fold(None, fold).unwrap().0;  
387 - let mut next = self.step(min, d);  
388 -  
389 - while self.vertex(min).1 == self.vertex(next).1 {  
390 - min = next;  
391 - next = self.step(min, d);  
392 - }  
393 -  
394 - min  
395 - }  
396 -  
397 - fn left_edge(&self) -> VertexIterator<T> {  
398 - VertexIterator::edge(self, Direction::Left)  
399 - }  
400 -  
401 - fn right_edge(&self) -> VertexIterator<T> {  
402 - VertexIterator::edge(self, Direction::Right)  
403 - }  
404 -  
405 - fn left_vertices(&self) -> VertexIterator<T> {  
406 - VertexIterator::vertex(self, Direction::Left)  
407 - }  
408 -  
409 - fn right_vertices(&self) -> VertexIterator<T> {  
410 - VertexIterator::vertex(self, Direction::Right)  
411 - }  
412 -  
413 - fn left(&self, v :usize) -> usize {  
414 - let Polygon(Coordinates(cs)) = self;  
415 -  
416 - match v {  
417 - 0 => cs.len() - 1,  
418 - _ => v - 1,  
419 - }  
420 - }  
421 -  
422 - fn right(&self, v :usize) -> usize {  
423 - let Polygon(Coordinates(cs)) = self;  
424 -  
425 - (v + 1) % cs.len()  
426 - }  
427 -  
428 - fn step(&self, v :usize, d :Direction) -> usize {  
429 - match d {  
430 - Direction::Left => self.left(v),  
431 - Direction::Right => self.right(v),  
432 - }  
433 - }  
434 -  
435 - fn next_y(&self, c :usize, d :Direction) -> Option<usize> {  
436 - fn inner<T>( p :&Polygon<T>  
437 - , c :usize  
438 - , n :usize  
439 - , d :Direction) -> Option<usize>  
440 - where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
441 - + Copy + Debug + From<i32> {  
442 - if c == n {  
443 - None  
444 - } else {  
445 - let Coordinate(_, cy, _) = p.vertex(c);  
446 - let Coordinate(_, ny, _) = p.vertex(n);  
447 -  
448 - if ny < cy { None } else { Some(n) }  
449 - }  
450 - }  
451 -  
452 - inner(self, c, self.step(c, d), d)  
453 - }  
454 -  
455 - pub fn debug(&self) {  
456 - let mut left = self.left_vertices();  
457 - let mut right = self.right_vertices();  
458 -  
459 - if left.find(|l| right.find(|r| l.0 == r.0).is_some()).is_some() {  
460 - let left :Vec<Coordinate<T>> = self.left_vertices().collect();  
461 - let right :Vec<Coordinate<T>> = self.right_vertices().collect();  
462 -  
463 - println!("===");  
464 - println!("== poly : {:?}", self);  
465 - println!("== ltop : {:?}", self.vert_min(Direction::Left));  
466 - println!("== rtop : {:?}", self.vert_min(Direction::Right));  
467 - println!("== left : {:?}", left);  
468 - println!("== right : {:?}", right);  
469 - println!("===");  
470 - }  
471 - }  
472 -}  
473 -  
474 -impl<T> Drawable<T> for Polygon<T>  
475 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
476 - + Debug + Clone + Copy + From<i32> {  
477 - fn plot(&self) -> Coordinates<T> {  
478 - let Polygon(Coordinates(cs)) = self;  
479 -  
480 - match cs[..] {  
481 - [] => Coordinates(Vec::<Coordinate<T>>::new()),  
482 - [a] => Coordinates(vec!(a)),  
483 - [a, b] => Coordinates(a.line(&b)),  
484 - _ => {  
485 - let (a, b) = (cs[0], cs[1]);  
486 - let mut r = a.line(&b);  
487 - let mut i = b;  
488 - for j in cs[2..].iter() {  
489 - r.append(&mut i.line(j)[1..].to_vec());  
490 - i = *j;  
491 - }  
492 - let mut j = a.line(&i);  
493 - let l = j.len();  
494 - if l > 1 {  
495 - r.append(&mut j[1..l-1].to_vec());  
496 - }  
497 - Coordinates(r)  
498 - },  
499 - }  
500 - }  
501 -}  
502 -  
503 -impl<T> Fillable<T> for Polygon<T>  
504 -where T: Add<Output = T> + Sub<Output = T> + Div<Output = T>  
505 - + Debug + Clone + Copy + From<i32> {  
506 - fn fill(&self, canvas :&mut dyn Canvas<T>, color :u32) {  
507 - let scanlines = self.left_edge().zip(self.right_edge());  
508 -  
509 - for l in scanlines.flat_map(|(l, r)| l.line_iter(&r)) {  
510 - canvas.set_pixel(l, color);  
511 - }  
512 - }  
513 -}  
514 -  
515 -impl<T> Display for Polygon<T> where T: Copy {  
516 - fn fmt(&self, f: &mut Formatter<'_>) -> Result {  
517 - let Polygon(a) = self;  
518 - write!(f, "Poly[{}]", a)  
519 - }  
520 -}  
1 -//  
2 -// Basic geometric things...  
3 -//  
4 -// Georg Hopp <georg@steffers.org>  
5 -//  
6 -// Copyright © 2019 Georg Hopp  
7 -//  
8 -// This program is free software: you can redistribute it and/or modify  
9 -// it under the terms of the GNU General Public License as published by  
10 -// the Free Software Foundation, either version 3 of the License, or  
11 -// (at your option) any later version.  
12 -//  
13 -// This program is distributed in the hope that it will be useful,  
14 -// but WITHOUT ANY WARRANTY; without even the implied warranty of  
15 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  
16 -// GNU General Public License for more details.  
17 -//  
18 -// You should have received a copy of the GNU General Public License  
19 -// along with this program. If not, see <http://www.gnu.org/licenses/>.  
20 -//  
21 -use std::convert::{From, Into};  
22 -use std::ops::{Add,Sub,Neg,Mul,Div};  
23 -use std::fmt::Debug;  
24 -  
25 -use crate::easel::{Canvas, Coordinate, Coordinates, Polygon};  
26 -use crate::transform::{TMatrix, Transformable};  
27 -use crate::trigonometry::Trig;  
28 -use crate::vector::Vector;  
29 -  
30 -#[derive(Debug, Clone)]  
31 -pub struct Face<T>  
32 -where T: Add + Sub + Neg + Mul + Div + Copy + Trig {  
33 - corners :Vec<usize>,  
34 - normal :Option<Vector<T>>,  
35 -}  
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 -  
140 -#[derive(Debug)]  
141 -pub struct Polyeder<T>  
142 -where T: Add + Sub + Neg + Mul + Div + PartialEq + Copy + Trig {  
143 - points :Vec<Point<T>>,  
144 - faces :Vec<Face<T>>,  
145 -}  
146 -  
147 -pub trait Primitives<T>  
148 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
149 - fn transform(&self, m :&TMatrix<T>) -> Self;  
150 - fn project( &self  
151 - , camera :&Camera<T>  
152 - , light :&DirectLight<T>  
153 - , col :u32 ) -> Vec<(Polygon<T>, u32)>;  
154 -}  
155 -  
156 -#[derive(Debug, Clone, Copy)]  
157 -pub struct Camera<T>  
158 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
159 - width :T,  
160 - height :T,  
161 - distance :T,  
162 - project :TMatrix<T>,  
163 -}  
164 -  
165 -pub struct DirectLight<T>  
166 -where T: Add + Sub + Neg + Mul + Div + Debug + Copy + Trig + From<i32> {  
167 - direction: Vector<T>,  
168 -}  
169 -  
170 -impl<T> Camera<T>  
171 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
172 - + Mul<Output = T> + Div<Output = T>  
173 - + PartialEq + Debug + Copy + Trig + From<i32> {  
174 - // This code assumes that the size of the viewport is always  
175 - // equal to the size of the physical screen… e.g. window/canvas thus some  
176 - // effects can't be done. See book for examples with different viewport  
177 - // and screen sizes.  
178 - pub fn new(c :&dyn Canvas<T>, angle :i32) -> Self {  
179 - let width :T = (c.width() as i32).into();  
180 - let height :T = (c.height() as i32).into();  
181 - let d :T = 1.into();  
182 - let fov = T::cot(angle) * width;  
183 - let wh = width / 2.into();  
184 - let hh = height / 2.into();  
185 -  
186 - Camera { width: width  
187 - , height: height  
188 - , distance: d  
189 - , project: TMatrix::new(  
190 - ( fov, 0.into(), wh, 0.into())  
191 - , (0.into(), fov, hh, 0.into())  
192 - , (0.into(), 0.into(), d, 1.into())  
193 - , (0.into(), 0.into(), 1.into(), 0.into()) ) }  
194 - }  
195 -  
196 - pub fn get_distance(&self) -> T {  
197 - self.distance  
198 - }  
199 -  
200 - pub fn get_projection(&self) -> TMatrix<T> {  
201 - self.project  
202 - }  
203 -  
204 - pub fn project(&self, p :Point<T>) -> Point<T> {  
205 - p.transform(&self.project)  
206 - }  
207 -}  
208 -  
209 -impl<T> DirectLight<T>  
210 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
211 - + Mul<Output = T> + Div<Output = T>  
212 - + Debug + Copy + Trig + From<i32> {  
213 - pub fn new(v :Vector<T>) -> Self {  
214 - DirectLight{ direction: v }  
215 - }  
216 -  
217 - pub fn dir(&self) -> Vector<T> {  
218 - self.direction  
219 - }  
220 -}  
221 -  
222 -impl<T> Face<T>  
223 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
224 - + Mul<Output = T> + Div<Output = T>  
225 - + PartialEq + Debug + Copy + Trig + From<i32> {  
226 - fn new(corners :Vec<usize>, ps :&[Point<T>]) -> Self {  
227 - let mut f = Face{ corners: corners, normal: None };  
228 - f.update_normal(ps);  
229 - f  
230 - }  
231 -  
232 - fn update_normal(&mut self, ps :&[Point<T>]) {  
233 - let edge10 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[0]]).into();  
234 - let edge12 :Vector<T> = (ps[self.corners[1]] - ps[self.corners[2]]).into();  
235 - self.normal = Some(edge10 * edge12);  
236 - }  
237 -}  
238 -  
239 -impl<T> Polyeder<T>  
240 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
241 - + Mul<Output = T> + Div<Output = T>  
242 - + PartialEq + Debug + Copy + Trig + From<i32> {  
243 - fn update_normals(&mut self) {  
244 - for f in self.faces.iter_mut() {  
245 - f.update_normal(&self.points);  
246 - }  
247 - }  
248 -  
249 - // construct via cube, see polyhedra.pdf  
250 - pub fn tetrahedron(a :T) -> Polyeder<T> {  
251 - let f2 :T = 2.into();  
252 - let ch = a / (f2 * T::sqrt(f2).unwrap());  
253 -  
254 - let ps = vec!( Point::new(-ch, -ch, ch) // A  
255 - , Point::new(-ch, ch, -ch) // C  
256 - , Point::new( ch, -ch, -ch) // E  
257 - , Point::new( ch, ch, ch) ); // G  
258 -  
259 - // bottom: 1, 2, 3  
260 - let fs = vec!( Face::new(vec!(2, 1, 0), &ps) // bottom  
261 - , Face::new(vec!(3, 2, 0), &ps)  
262 - , Face::new(vec!(0, 1, 3), &ps)  
263 - , Face::new(vec!(1, 2, 3), &ps) );  
264 - //let fs = vec!( Face::new(vec!(0, 1, 2), &ps) // bottom  
265 - // , Face::new(vec!(0, 2, 3), &ps)  
266 - // , Face::new(vec!(3, 1, 0), &ps)  
267 - // , Face::new(vec!(3, 2, 1), &ps) );  
268 -  
269 - Polyeder{ points: ps, faces: fs }  
270 - }  
271 -  
272 - pub fn triangle(a :T) -> Polyeder<T> {  
273 - let f0 :T = 0.into();  
274 - let f3 :T = 3.into();  
275 - let f6 :T = 6.into();  
276 - let zi :T = T::sqrt(f3).unwrap() / f6 * a;  
277 - let zc :T = T::sqrt(f3).unwrap() / f3 * a;  
278 - let ah :T = a / 2.into();  
279 -  
280 - let ps = vec!( Point::new(-ah, f0, -zi)  
281 - , Point::new( f0, f0, zc)  
282 - , Point::new( ah, f0, -zi) );  
283 -  
284 - let fs = vec!(Face::new(vec!(0, 1, 2), &ps));  
285 -  
286 - Polyeder{ points: ps, faces: fs }  
287 - }  
288 -  
289 - pub fn cube(a :T) -> Polyeder<T> {  
290 - let ah :T = a / From::<i32>::from(2);  
291 -  
292 - let ps = vec!( Point::new(-ah, ah, -ah) // 0 => front 1  
293 - , Point::new(-ah, -ah, -ah) // 1 => front 2  
294 - , Point::new( ah, -ah, -ah) // 2 => front 3  
295 - , Point::new( ah, ah, -ah) // 3 => front 4  
296 - , Point::new(-ah, ah, ah) // 4 => back 1  
297 - , Point::new(-ah, -ah, ah) // 5 => back 2  
298 - , Point::new( ah, -ah, ah) // 6 => back 3  
299 - , Point::new( ah, ah, ah) ); // 7 => back 4  
300 -  
301 - let fs = vec!( Face::new(vec!(0, 1, 2, 3), &ps) // front  
302 - , Face::new(vec!(7, 6, 5, 4), &ps) // back  
303 - , Face::new(vec!(1, 5, 6, 2), &ps) // top  
304 - , Face::new(vec!(0, 3, 7, 4), &ps) // bottom  
305 - , Face::new(vec!(0, 4, 5, 1), &ps) // left  
306 - , Face::new(vec!(2, 6, 7, 3), &ps) ); // right  
307 -  
308 - Polyeder{ points: ps, faces: fs }  
309 - }  
310 -}  
311 -  
312 -impl<T> Primitives<T> for Polyeder<T>  
313 -where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>  
314 - + Mul<Output = T> + Div<Output = T>  
315 - + Debug + Copy + Trig + From<i32> + PartialOrd {  
316 - // TODO Maybe this should also be an instance of Transformable…  
317 - fn transform(&self, m :&TMatrix<T>) -> Self {  
318 - let Polyeder{ points: ps, faces: fs } = self;  
319 -  
320 - let mut p = Polyeder{  
321 - points: ps.iter().map(|p| p.transform(m)).collect()  
322 - , faces: fs.to_vec()  
323 - };  
324 -  
325 - // TODO alternatively we could rotate the normals too, but this cannot  
326 - // done with the original matrix… the question is, what is faster.  
327 - p.update_normals();  
328 - p  
329 - }  
330 -  
331 - fn project( &self  
332 - , camera :&Camera<T>  
333 - , light :&DirectLight<T>  
334 - , color :u32 ) -> Vec<(Polygon<T>, u32)> {  
335 - // Helper to create a Polygon from Coordinates…  
336 - // TODO probably there needs to be a Polygon constructor for this.  
337 - fn polygon<I, T>(c :I) -> Polygon<T>  
338 - where I: Iterator<Item = Coordinate<T>> {  
339 - Polygon(Coordinates(c.collect()))  
340 - }  
341 -  
342 - // this one does the projection... as the projection was the last  
343 - // matrix we do not need to do it here.  
344 - let to_coord = |p :&usize| {  
345 - let Point(v, _) = camera.project(self.points[*p]);  
346 - Coordinate(T::round(&v.x()), T::round(&v.y()), v.z() - 1.into())  
347 - };  
348 - let to_poly = |f :&Face<T>| {  
349 - let pg = polygon(f.corners.iter().map(to_coord));  
350 - let mut r :T = (((color >> 16) & 0xFF) as i32).into();  
351 - let mut g :T = (((color >> 8) & 0xFF) as i32).into();  
352 - let mut b :T = (((color ) & 0xFF) as i32).into();  
353 - let lf :T = match f.normal {  
354 - None => 1.into(),  
355 - Some(n) => n.dot(light.dir())  
356 - / (n.mag() * light.dir().mag()),  
357 - };  
358 -  
359 - // this "if" represents a first simple backface culling  
360 - // approach. We only return face that face towards us.  
361 - if lf < 0.into() {  
362 - r = r * -lf;  
363 - g = g * -lf;  
364 - b = b * -lf;  
365 -  
366 - let c :u32 = (r.round() as u32) << 16  
367 - | (g.round() as u32) << 8  
368 - | (b.round() as u32);  
369 -  
370 - Some((pg, c))  
371 - } else {  
372 - None  
373 - }};  
374 -  
375 - self.faces.iter().filter_map(to_poly).collect()  
376 - }  
377 -}  
1 -extern crate lazy_static;  
2 -  
3 -pub type Error = &'static str;  
4 -  
5 -pub mod easel;  
6 -pub mod transform;  
7 -pub mod trigonometry;  
8 -pub mod vector;  
9 -pub mod geometry;  
10 -  
11 -mod utils;  
12 -  
13 -use vector::Vector;  
14 -use easel::{Canvas, Coordinate, Drawable, Fillable};  
15 -use geometry::{Camera, DirectLight, Polyeder, Primitives};  
16 -use transform::{TMatrix};  
17 -  
18 -use std::fmt::{Display, Formatter, Result};  
19 -use std::sync::mpsc;  
20 -use std::time::Instant;  
21 -use wasm_bindgen::prelude::*;  
22 -  
23 -// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global  
24 -// allocator.  
25 -#[cfg(feature = "wee_alloc")]  
26 -#[global_allocator]  
27 -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;  
28 -  
29 -#[wasm_bindgen]  
30 -#[derive(Clone, Copy, Debug, PartialEq, Eq)]  
31 -pub struct Color(u8, u8, u8, u8);  
32 -  
33 -#[wasm_bindgen]  
34 -pub struct View3d { width :u16  
35 - , height :u16  
36 - , size :usize  
37 - , degree :i32  
38 - //, start :Instant  
39 - , tetrahedron :Polyeder<f64>  
40 - , cube :Polyeder<f64>  
41 - , camera :Option<Camera<f64>>  
42 - , light :DirectLight<f64>  
43 - , zbuf :Vec<f64>  
44 - , image :Vec<Color>  
45 -}  
46 -  
47 -#[wasm_bindgen]  
48 -impl View3d {  
49 - pub fn new(width :u16, height :u16) -> Self {  
50 - let size = width as usize * height as usize;  
51 - let light_vector = Vector(0.0, 0.0, 1.0);  
52 -  
53 - let mut view3d = Self { width: width  
54 - , height: height  
55 - , size: size  
56 - , degree: 0  
57 - //, start: Instant::now()  
58 - , tetrahedron: Polyeder::tetrahedron(100.0)  
59 - , cube: Polyeder::cube(56.25)  
60 - , camera: None  
61 - , light: DirectLight::new(light_vector)  
62 - , zbuf: vec!(0.0; size)  
63 - , image: vec!(Color(0, 0, 0, 0xFF); size)  
64 - };  
65 -  
66 - view3d.camera = Some(Camera::<f64>::new(&view3d, 45));  
67 - view3d  
68 - }  
69 -  
70 - pub fn width(&self) -> u16 {  
71 - self.width  
72 - }  
73 -  
74 - pub fn height(&self) -> u16 {  
75 - self.height  
76 - }  
77 -  
78 - pub fn update(&mut self) {  
79 - //let deg = ((self.start.elapsed() / 25).as_millis() % 360) as i32;  
80 - let t = TMatrix::translate(Vector(0.0, 0.0, 150.0));  
81 - let rz = TMatrix::rotate_z(self.degree);  
82 - let rx = TMatrix::rotate_x(-self.degree*2);  
83 - let ry = TMatrix::rotate_y(-self.degree*2);  
84 -  
85 - let rot1 = TMatrix::combine(vec!(rz, rx, t));  
86 - let rot2 = TMatrix::combine(vec!(rz, ry, t));  
87 -  
88 - let objects = vec!( (self.tetrahedron.transform(&rot1), 0xFFFF00)  
89 - , ( self.cube.transform(&rot2), 0x0000FF) );  
90 -  
91 - self.degree = (self.degree + 1) % 360;  
92 -  
93 - self.clear();  
94 -  
95 - match self.camera {  
96 - None => {},  
97 - Some(camera) => {  
98 - for (o, color) in objects {  
99 - for (pg, c) in o.project(&camera, &self.light, color) {  
100 - (&pg).fill(self, c);  
101 - }  
102 - }  
103 - },  
104 - }  
105 - }  
106 -  
107 - pub fn image(&self) -> *const Color {  
108 - self.image.as_ptr()  
109 - }  
110 -}  
111 -  
112 -impl Canvas<f64> for View3d {  
113 - fn width(&self) -> u16 {  
114 - self.width  
115 - }  
116 -  
117 - fn height(&self) -> u16 {  
118 - self.height  
119 - }  
120 -  
121 - fn clear(&mut self) {  
122 - self.zbuf = vec!(0.0; self.size);  
123 - self.image = vec!(Color(0, 0, 0, 0xFF); self.size);  
124 - }  
125 -  
126 - fn set_pixel(&mut self, c :Coordinate<f64>, color :u32) {  
127 - let Coordinate(x, y, zr) = c;  
128 - let idx :usize = (y * (self.width as i32) + x) as usize;  
129 -  
130 - let r = ((color >> 16) & 0xFF) as u8;  
131 - let g = ((color >> 8) & 0xFF) as u8;  
132 - let b = ( color & 0xFF) as u8;  
133 -  
134 - if self.zbuf[idx] < zr {  
135 - self.zbuf[idx] = zr;  
136 - self.image[idx] = Color(r, g, b, 0xFF);  
137 - }  
138 - }  
139 -  
140 - // Empty implementations for now… mostly not needed because it is  
141 - // done from JavaScript…  
142 - fn init_events(&self) {}  
143 - fn start_events(&self, _ :mpsc::Sender<i32>) {}  
144 - fn draw( &mut self, _ :&dyn Drawable<f64>, _ :Coordinate<f64>, _ :u32 ) {}  
145 - fn put_text(&self, _ :Coordinate<f64>, _ :&str) {}  
146 - fn show(&self) {}  
147 -}  
148 -  
149 -#[wasm_bindgen]  
150 -#[repr(u8)]  
151 -#[derive(Clone, Copy, Debug, PartialEq, Eq)]  
152 -pub enum Cell {  
153 - Dead = 0,  
154 - Alive = 1,  
155 -}  
156 -  
157 -#[wasm_bindgen]  
158 -pub struct Universe {  
159 - width :u32,  
160 - height :u32,  
161 - cells :Vec<Cell>,  
162 -}  
163 -  
164 -#[wasm_bindgen]  
165 -impl Universe {  
166 - pub fn new() -> Universe {  
167 - let width = 64;  
168 - let height = 64;  
169 -  
170 - let init_cells = |i :u32| {  
171 - if i % 2 == 0 || i % 7 == 0 { Cell::Alive } else { Cell::Dead }  
172 - };  
173 -  
174 - let cells = (0..width * height).map(init_cells).collect();  
175 -  
176 - Universe {  
177 - width: width,  
178 - height: height,  
179 - cells: cells,  
180 - }  
181 - }  
182 -  
183 - pub fn width(&self) -> u32 {  
184 - self.width  
185 - }  
186 -  
187 - pub fn height(&self) -> u32 {  
188 - self.height  
189 - }  
190 -  
191 - pub fn cells(&self) -> *const Cell {  
192 - self.cells.as_ptr()  
193 - }  
194 -  
195 - pub fn render(&self) -> String {  
196 - self.to_string()  
197 - }  
198 -  
199 - pub fn tick(&mut self) {  
200 - let mut next = self.cells.clone();  
201 -  
202 - for row in 0..self.height {  
203 - for col in 0..self.width {  
204 - let idx = self.get_index(row, col);  
205 - let cell = self.cells[idx];  
206 - let live_neighbors = self.live_neighbor_count(row, col);  
207 -  
208 - // Game of life rules....  
209 - let next_cell = match (cell, live_neighbors) {  
210 - (Cell::Alive, 2) |  
211 - (Cell::Alive, 3) => Cell::Alive,  
212 - (Cell::Alive, _) => Cell::Dead,  
213 - ( Cell::Dead, 3) => Cell::Alive,  
214 - ( otherwise, _) => otherwise,  
215 - };  
216 -  
217 - next[idx] = next_cell;  
218 - }  
219 - }  
220 -  
221 - self.cells = next;  
222 - }  
223 -  
224 - fn get_index(&self, row :u32, col :u32) -> usize {  
225 - (row * self.width + col) as usize  
226 - }  
227 -  
228 - fn live_neighbor_count(&self, row :u32, col :u32) -> u8 {  
229 - let mut count = 0;  
230 -  
231 - for delta_row in [self.height - 1, 0, 1].iter().cloned() {  
232 - for delta_col in [self.width - 1, 0, 1].iter().cloned() {  
233 - if delta_row == 0 && delta_col == 0 {  
234 - continue;  
235 - }  
236 -  
237 - let neighbor_row = (row + delta_row) % self.height;  
238 - let neighbor_col = (col + delta_col) % self.width;  
239 - let idx = self.get_index(neighbor_row, neighbor_col);  
240 - count += self.cells[idx] as u8;  
241 - }  
242 - }  
243 -  
244 - count  
245 - }  
246 -}  
247 -  
248 -impl Display for Universe {  
249 - fn fmt(&self, f :&mut Formatter) -> Result {  
250 - for line in self.cells.as_slice().chunks(self.width as usize) {  
251 - for &cell in line {  
252 - let symbol = match cell {  
253 - Cell::Dead => ' ',  
254 - Cell::Alive => '*',  
255 - };  
256 - write!(f, "{}", symbol)?;  
257 - }  
258 - write!(f, "\n")?;  
259 - }  
260 -  
261 - Ok(())  
262 - }  
263 -}  
Please register or login to post a comment