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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
//! Transformation context
use crate::{
math::{abs_transform, get_scale, identity, Matrix2d, Scalar, Vec2d},
DrawState, Viewport,
};
/// Drawing 2d context.
#[derive(Copy, Clone)]
pub struct Context {
/// Viewport information.
pub viewport: Option<Viewport>,
/// View transformation.
pub view: Matrix2d,
/// Current transformation.
pub transform: Matrix2d,
/// Current draw state settings.
pub draw_state: DrawState,
}
impl Context {
/// Creates a new drawing context.
#[inline(always)]
pub fn new() -> Context {
Context {
view: identity(),
transform: identity(),
draw_state: Default::default(),
viewport: None,
}
}
/// Creates a new context with absolute transform in point coordinates.
///
/// This function assumes the default coordinate system
/// being centered with x axis pointing to the right
/// and y axis pointing up.
///
/// Returns a drawing context
/// with origin in the upper left corner
/// and x axis pointing to the right
/// and y axis pointing down.
#[inline(always)]
pub fn new_viewport(viewport: Viewport) -> Context {
let mat = viewport.abs_transform();
Context {
view: mat,
transform: mat,
draw_state: Default::default(),
viewport: Some(viewport),
}
}
/// Creates a new drawing context in absolute coordinates.
///
/// This function assumes the default coordinate system
/// being centered with x axis pointing to the right
/// and y axis pointing up.
///
/// Returns a drawing context
/// with origin in the upper left corner
/// and x axis pointing to the right
/// and y axis pointing down.
#[inline(always)]
pub fn new_abs(w: Scalar, h: Scalar) -> Context {
let mat = abs_transform(w, h);
Context {
view: mat,
transform: mat,
draw_state: Default::default(),
viewport: None,
}
}
/// Moves the current transform to the view coordinate system.
///
/// This is usually [0.0, 0.0] in the upper left corner
/// with the x axis pointing to the right
/// and the y axis pointing down.
#[inline(always)]
pub fn view(mut self) -> Self {
self.transform = self.view;
self
}
/// Moves the current transform to the default coordinate system.
///
/// This is usually [0.0, 0.0] in the center
/// with the x axis pointing to the right
/// and the y axis pointing up.
#[inline(always)]
pub fn reset(mut self) -> Self {
self.transform = identity();
self
}
/// Stores the current transform as new view.
#[inline(always)]
pub fn store_view(mut self) -> Self {
self.view = self.transform;
self
}
/// Computes the current view size.
#[inline(always)]
pub fn get_view_size(&self) -> Vec2d {
let scale = get_scale(self.view);
[2.0 / scale[0], 2.0 / scale[1]]
}
}
impl Default for Context {
fn default() -> Context {
Context::new()
}
}
#[cfg(test)]
mod test {
use super::Context;
#[test]
fn test_context() {
use crate::Transformed;
let c = Context::new();
{
let d = c.trans(20.0, 40.0);
let d = d.trans(10.0, 10.0);
let transform = d.transform;
assert_eq!(transform[0][2], 30.0);
assert_eq!(transform[1][2], 50.0);
}
let transform = c.transform;
assert_eq!(transform[0][2], 0.0);
assert_eq!(transform[1][2], 0.0);
let c = c.rot_deg(90.0);
let transform = c.transform;
assert!((transform[0][0] - 0.0).abs() < 0.00001);
assert!((transform[0][1] + 1.0).abs() < 0.00001);
}
#[test]
fn test_scale() {
use crate::Transformed;
let c = Context::new();
let c = c.scale(2.0, 3.0);
let transform = c.transform;
assert!((transform[0][0] - 2.0).abs() < 0.00001);
assert!((transform[1][1] - 3.0).abs() < 0.00001);
}
}