main.rs 9.96 KB
//
// Test our fractional crate / module...
//
// Georg Hopp <georg@steffers.org>
//
// Copyright © 2019 Georg Hopp
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// 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::cmp;
use std::convert::{TryFrom, TryInto, Into};
use std::f64::consts::PI as FPI;
use std::fmt::Display;
use std::num::TryFromIntError;
use std::ops::{Add,Sub,Neg,Mul,Div};

use fractional::continuous::Continuous;
use fractional::fractional::{Fractional, from_vector};
use fractional::trigonometry::Trig;
use fractional::vector::{Vector};
use fractional::transform::{TMatrix, translate, rotate_x, rotate_y, rotate_z, rotate_v};

// Tail recursive Bresenham line with integer incremental error.
fn line(a :(u32, u32), b :(u32, u32)) -> Vec<(u32, u32)>{
    fn inner( v :&mut [(u32, u32)]
            , bx :u32, by :u32
            , dx :i32, dy :i32
            , sx :i32, sy :i32
            , err :i32) {
        let (x, y) = v[0];

        if x != bx || y != by {
            let (x, y, err) = match (2*err as i32 >= dy, 2*err as i32 <= dx) {
                (true, false) => ((x as i32 + sx) as u32, y, err + dy),
                (false, true) => (x, (y as i32 + sy) as u32, err + dx),
                _             => ( (x as i32 + sx) as u32
                                 , (y as i32 + sy) as u32
                                 , err + dx + dy ),
            };
            v[1] = (x, y);
            inner(&mut v[1..], bx, by, dx, dy, sx, sy, err);
        }
    }

    let (ax, ay) = a;
    let (bx, by) = b;

    let dx      = (bx as i32 - ax as i32).abs();
    let sx :i32 = if ax < bx { 1 } else { -1 };
    let dy      = -(by as i32 - ay as i32).abs();
    let sy :i32 = if ay < by { 1 } else { -1 };

    let mut v :Vec<(u32, u32)> = vec!((0, 0); cmp::max(dx, -dy) as usize + 1);
    v[0] = (ax, ay);
    inner(&mut v, bx, by, dx, dy, sx, sy, dx + dy);
    v
}

fn mean(v: &Vec<i64>) -> Result<Fractional, TryFromIntError> {
    let r = v.iter().fold(0, |acc, x| acc + x);
    let l = i64::try_from(v.len())?;
    Ok(Fractional(r, l))
}

fn common_fractional() {
    let a = vec![3, 6, 1, 9];
    let b = from_vector(&a);
    let c = mean(&a).unwrap(); // This might fail if the len of the
                               // vector (usize) does not fit into i32.
    let cr :f64 = c.try_into().unwrap();

    println!("         [i32] : {:?}", a);
    println!("  [Fractional] : {:?}", b);
    println!(" mean of [i32] : {}"  , c);
    println!("        as f64 : {}"  , cr);
    println!("  again as f64 : {}"  , TryInto::<f64>::try_into(c).unwrap());
}

fn continuous() {
    let d = Fractional(45, 16);
    let e = Fractional(16, 45);

    let dc :Continuous = (&d).into();
    let ec :Continuous = (&e).into();

    println!("cont frac of d : {} => {:?}", d, dc);
    println!("cont frac of e : {} => {:?}", e, ec);
    println!("   reverted dc : {:?} {}", dc, Into::<Fractional>::into(&dc));
    println!("   reverted ec : {:?} {}", ec, Into::<Fractional>::into(&ec));
}

fn sqrt() {
    let f       = Fractional(-9, 4);
    let fr :f64 = f.try_into().unwrap();
    let sq      = f.sqrt();
    let _sq     = fr.sqrt();

    println!("{:>14} : {:?} / {}", format!("sqrt {}", f), sq, _sq);

    for f in [ Fractional(9, 4)
             , Fractional(45, 16)
             , Fractional(16, 45)
             , Fractional(9, 3) ].iter() {
        let fr  :f64 = (*f).try_into().unwrap();
        let sq       = f.sqrt().unwrap();
        let sqr :f64 = sq.try_into().unwrap();
        let _sqr     = fr.sqrt();

        println!("{:>14} : {} {} / {}", format!("sqrt {}", f), sq, sqr, _sqr);
    }
}

fn pi() {
    let pi              = Fractional::pi();
    let pir :f64        = pi.try_into().unwrap();
    let pit :(i32, i32) = pi.try_into().unwrap();
    let pi2r :f64       = (pi * pi).try_into().unwrap();

    println!("        Rust π : {}"     , FPI);
    println!("             π : {} {}"  , pi, pir);
    println!("    π as tuple : {:?}"   , pit);
    println!("       Rust π² : {}"     , FPI * FPI);
    println!("            π² : {} {}"  , pi * pi, pi2r);
}

fn _sin() {
    for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
             , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
        let s       = Fractional::sin(*d as i32);
        let sr :f64 = s.try_into().unwrap();
        let _s      = f64::sin(*d as f64 * FPI / 180.0);

        println!("{:>14} : {} {} / {}", format!("sin {}", d), s, sr, _s);
    }
}

fn _tan() {
    for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
             , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
        let t       = Fractional::tan(*d as i32);
        let tr :f64 = t.try_into().unwrap();
        let _t      = f64::tan(*d as f64 * FPI / 180.0);

        println!("{:>14} : {} {} / {}", format!("tan {}", d), t, tr, _t);
    }
}

fn _cos() {
    for d in [ 0, 30, 45, 90, 135, 180, 225, 270, 315
             , 9, 17, 31, 73, 89, 123, 213, 312, 876 ].iter() {
        let c       = Fractional::cos(*d as i32);
        let cr :f64 = c.try_into().unwrap();
        let _c      = f64::cos(*d as f64 * FPI / 180.0);

        println!("{:>14} : {} {} / {}", format!("cos {}", d), c, cr, _c);
    }
}

fn _vector1() {
    let v1 = Vector(1.into(), 2.into(), 3.into());
    let v2 = Vector(2.into(), 2.into(), 3.into());
    let s :Fractional = 3.into();

    _vector(v1, v2, s);
}

fn _vector2() {
    let v1 = Vector(1.0, 2.0, 3.0);
    let v2 = Vector(2.0, 2.0, 3.0);
    let s = 3.0;

    _vector(v1, v2, s);
}

fn _vector<T>(v1 :Vector<T>, v2 :Vector<T>, s :T)
    where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
           + Mul<Output = T> + Div<Output = T> + Trig + Copy + Display {
    println!("{:>14} : {}", "Vector v1", v1);
    println!("{:>14} : {}", "Vector v2", v2);
    println!("{:>14} : {}", "abs v1", v1.abs());
    println!("{:>14} : {}", "-v1", -v1);
    println!("{:>14} : {}", "v1 + v1", v1 + v1);
    println!("{:>14} : {}", "v1 - v1", v1 - v1);
    println!("{:>14} : {}", "v2 - v1", v2 - v1);
    println!("{:>14} : {}", format!("v1 * {}", s), v1.mul(&s));
    println!("{:>14} : {}", "norm v1", v1.norm());
    println!("{:>14} : {}", "abs norm v1", v1.norm().abs());
    println!("{:>14} : {}", "abs v1", v1.abs());
    println!("{:>14} : {}", "norm * abs", v1.norm().mul(&v1.abs()));
    println!("{:>14} : {}", "distance v1 v2", v1.distance(v2));
    println!("{:>14} : {}", "distance v2 v1", v2.distance(v1));
    println!("{:>14} : {}", "v1 dot v2", v1.dot(v2));
    println!("{:>14} : {}", "v2 dot v1", v2.dot(v1));
    println!("{:>14} : {}", "v1 * v2", v1 * v2);
    println!("{:>14} : {}", "v2 * v1", v2 * v1);
}

fn _transform1() {
    let v  = Vector(Fractional(1,1), Fractional(1,1), Fractional(1,1));
    let v1 = Vector(Fractional(1,1), Fractional(2,1), Fractional(3,1));
    let v2 = Vector(Fractional(1,1), Fractional(1,1), Fractional(0,1));
    let v3 = Vector(Fractional(1,1), Fractional(0,1), Fractional(1,1));

    _transform(v, v1, v2, v3);
}

fn _transform2() {
    let v  = Vector(1.0, 1.0, 1.0);
    let v1 = Vector(1.0, 2.0, 3.0);
    let v2 = Vector(1.0, 1.0, 0.0);
    let v3 = Vector(1.0, 0.0, 1.0);

    _transform(v, v1, v2, v3);
}

fn _transform<T>(v :Vector<T>, v1 :Vector<T>, v2 :Vector<T>, v3 :Vector<T>)
    where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
           + Mul<Output = T> + Div<Output = T> + Trig
           + From<i32> + Copy + Display {

    println!("{:>14} : {}", "Vector v1", v1);
    println!("{:>14} : {}", "translate v1", translate(v).apply(&v1));
    println!();

    fn _rot<T>( o :&str , n :&str , v :&Vector<T>
              , fs :&[&dyn Fn(i32) -> TMatrix<T>] )
        where T: Add<Output = T> + Sub<Output = T> + Neg<Output = T>
               + Mul<Output = T> + Div<Output = T> + Trig
               + From<i32> + Copy + Display {

        for d in [ 30, 45, 60, 90, 120, 135, 150, 180
                 , 210, 225, 240, 270, 300, 315, 330 ].iter() {
            let mi = fs.iter().map(|f| f(*d as i32));
            println!( "{:>14} : {}"
                    , format!("{} {} {}", o, d, n)
                    , TMatrix::combine(mi).apply(v) );
        }
    }

    println!("{:>14} : {}", "Vector v2", v2);
    _rot("rot_x", "v2", &v2, &[&rotate_x]);
    println!();
    _rot("rot_y", "v2", &v2, &[&rotate_y]);
    println!();
    _rot("rot_xy", "v2", &v2, &[&rotate_x, &rotate_y]);
    println!();
    println!("{:>14} : {}", "Vector v3", v3);
    _rot("rot_z", "v3", &v3, &[&rotate_z]);
    println!();

    for d in [ 30, 45, 60, 90, 120, 135, 150, 180
             , 210, 225, 240, 270, 300, 315, 330 ].iter() {
        println!( "{:>14} : {}"
                , format!("rot_v {} v2", d)
                , rotate_v(&v, *d as i32).apply(&v2));
    }
}

fn _line() {
    println!("{:>14} : {:?}", "Line", line((0,1), (6,4)));
    println!("{:>14} : {:?}", "Line", line((0,4), (6,1)));
    println!("{:>14} : {:?}", "Line", line((6,1), (0,4)));
    println!("{:>14} : {:?}", "Line", line((6,4), (0,1)));
    println!("{:>14} : {:?}", "Line", line((0,1), (6,8)));
    println!("{:>14} : {:?}", "Line", line((0,8), (6,1)));
    println!("{:>14} : {:?}", "Line", line((6,1), (0,8)));
    println!("{:>14} : {:?}", "Line", line((6,8), (0,1)));
}

fn main() {
    common_fractional();
    println!();
    continuous();
    println!();
    sqrt();
    println!();
    pi();
    println!();
    _sin();
    println!();
    _cos();
    println!();
    _tan();
    println!();
    _vector1();
    println!();
    _vector2();
    println!();
    _transform1();
    println!();
    _transform2();
    println!();
    _line();
}