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