1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
use super::implicit_base::ImplicitModuleBase;
use super::{ImplicitModule, ScalarParameter};

use std::rc::Rc;
use std::cell::RefCell;

pub struct ImplicitTriangle {
    base: ImplicitModuleBase,
    source: ScalarParameter,
    period: ScalarParameter,
    offset: ScalarParameter,
}

impl ImplicitTriangle {
    pub fn with_period_offset(period: f64, offset: f64) -> ImplicitTriangle {
        ImplicitTriangle {
            base: Default::default(),
            source: ScalarParameter::Value(0.0),
            period: ScalarParameter::Value(period),
            offset: ScalarParameter::Value(offset),
        }
    }

    pub fn set_source_module(&mut self, m: Rc<RefCell<ImplicitModule>>) {
        self.source = ScalarParameter::Source(m);
    }
    pub fn set_source_value(&mut self, v: f64) {
        self.source = ScalarParameter::Value(v);
    }

    pub fn set_period_module(&mut self, m: Rc<RefCell<ImplicitModule>>) {
        self.period = ScalarParameter::Source(m);
    }
    pub fn set_period_value(&mut self, v: f64) {
        self.period = ScalarParameter::Value(v);
    }

    pub fn set_offset_module(&mut self, m: Rc<RefCell<ImplicitModule>>) {
        self.offset = ScalarParameter::Source(m);
    }
    pub fn set_offset_value(&mut self, v: f64) {
        self.offset = ScalarParameter::Value(v);
    }
}

impl ImplicitModule for ImplicitTriangle {
    fn get_2d(&mut self, x: f64, y: f64) -> f64 {
        let val = self.source.get_2d(x, y);
        let period = self.period.get_2d(x, y);
        let offset = self.offset.get_2d(x, y);
		get(val, period, offset)
    }
    fn get_3d(&mut self, x: f64, y: f64, z: f64) -> f64 {
        let val = self.source.get_3d(x, y, z);
        let period = self.period.get_3d(x, y, z);
        let offset = self.offset.get_3d(x, y, z);
		get(val, period, offset)
    }
    fn get_4d(&mut self, x: f64, y: f64, z: f64, w: f64) -> f64 {
        let val = self.source.get_4d(x, y, z, w);
        let period = self.period.get_4d(x, y, z, w);
        let offset = self.offset.get_4d(x, y, z, w);
		get(val, period, offset)        
    }
    fn get_6d(&mut self, x: f64, y: f64, z: f64, w: f64, u: f64, v: f64) -> f64 {
        let val = self.source.get_6d(x, y, z, w, u, v);
        let period = self.period.get_6d(x, y, z, w, u, v);
        let offset = self.offset.get_6d(x, y, z, w, u, v);
		get(val, period, offset)
    }

    fn spacing(&self) -> f64 {
        self.base.spacing
    }
    fn set_deriv_spacing(&mut self, s: f64) {
        self.base.spacing = s;
    }
}

#[inline(always)]
fn get(val: f64, period: f64, offset: f64) -> f64 {
	    if offset >= 1.0 {
            sawtooth(val, period)
        } else if offset <= 0.0 {
            1.0 - sawtooth(val, period)
        } else {
            let s1 = if (offset - sawtooth(val, period)) >= 0.0 {
                1.0
            } else {
                0.0
            };
            let s2 = if ((1.0 - offset) - (sawtooth(-val, period))) >= 0.0 {
                1.0
            } else {
                0.0
            };
            sawtooth(val, period) * s1 / offset + sawtooth(-val, period) * s2 / (1.0 - offset)
        }
}

#[inline(always)]
fn sawtooth(x: f64, p: f64) -> f64 {
    (2.0 * (x / p - (0.5 + x / p).floor())) * 0.5 + 0.5
}