x-graphics 0.2.1

Graphics framework for X
Documentation
use std::ops::Mul;

use windows::Foundation::Numerics::Matrix3x2;

use crate::{geometry::FRect, matrix::MatrixBackend, Float};

#[derive(Clone, Debug, PartialEq)]
pub struct D2DMatrix {
    pub matrix: Matrix3x2,
}

impl Mul for D2DMatrix {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self::Output {
        Self {
            matrix: self.matrix * rhs.matrix,
        }
    }
}

impl MatrixBackend for D2DMatrix {
    fn identity() -> Self {
        Self {
            matrix: Matrix3x2::identity(),
        }
    }

    fn from_row(scx: Float, sky: Float, skx: Float, scy: Float, tx: Float, ty: Float) -> Self {
        Self {
            matrix: Matrix3x2 {
                M11: scx,
                M12: sky,
                M21: skx,
                M22: scy,
                M31: tx,
                M32: ty,
            },
        }
    }

    fn from_translate(x: Float, y: Float) -> Self {
        Self {
            matrix: Matrix3x2::translation(x, y),
        }
    }

    fn from_scale(x: Float, y: Float) -> Self {
        Self {
            matrix: Matrix3x2 {
                M11: x,
                M22: y,
                ..Default::default()
            },
        }
    }

    fn from_rotate(angle: Float) -> Self {
        Self {
            matrix: Matrix3x2::rotation(angle, 0.0, 0.0),
        }
    }

    fn pre_rotate(&mut self, angle: Float) {
        self.matrix = self.matrix * Self::rotate_matrix(angle);
    }

    fn pre_scale(&mut self, x: Float, y: Float) {
        self.matrix = self.matrix * Self::scale_matrix(x, y);
    }

    fn pre_translate(&mut self, x: Float, y: Float) {
        self.matrix = self.matrix * Matrix3x2::translation(x, y);
    }

    fn post_rotate(&mut self, angle: Float) {
        self.matrix = Self::rotate_matrix(angle) * self.matrix;
    }

    fn post_scale(&mut self, x: Float, y: Float) {
        self.matrix = Self::scale_matrix(x, y) * self.matrix;
    }

    fn post_translate(&mut self, x: Float, y: Float) {
        self.matrix = Matrix3x2::translation(x, y) * self.matrix;
    }

    fn map_rect(&self, rect: FRect) -> FRect {
        let (x1, y1) = self.map_point(rect.point.x, rect.point.y);
        let (x2, y2) = self.map_point(rect.point.x + rect.size.width, rect.point.y);
        let (x3, y3) = self.map_point(rect.point.x, rect.point.y + rect.size.height);
        let (x4, y4) = self.map_point(rect.point.x + rect.size.width, rect.point.y + rect.size.height);
        let min_x = x1.min(x2).min(x3).min(x4);
        let min_y = y1.min(y2).min(y3).min(y4);
        let max_x = x1.max(x2).max(x3).max(x4);
        let max_y = y1.max(y2).max(y3).max(y4);
        FRect::new(min_x, min_y, max_x - min_x, max_y - min_y)
    }
}

impl D2DMatrix {
    pub(super) fn from_matrix(matrix: Matrix3x2) -> Self {
        Self {
            matrix,
        }
    }

    pub(super) fn scale_matrix(x: Float, y: Float) -> Matrix3x2 {
        Matrix3x2 {
            M11: x,
            M22: y,
            ..Default::default()
        }
    }

    pub(super) fn rotate_matrix(angle: Float) -> Matrix3x2 {
        let cos_theta = angle.cos();
        let sin_theta = angle.sin();
        Matrix3x2 {
            M11: cos_theta,
            M12: sin_theta,
            M21: -sin_theta,
            M22: cos_theta,
            ..Default::default()
        }
    }

    fn map_point(&self, x: Float, y: Float) -> (Float, Float) {
        let mapped_x = self.matrix.M11 * x + self.matrix.M21 * y + self.matrix.M31;
        let mapped_y = self.matrix.M12 * x + self.matrix.M22 * y + self.matrix.M32;
        (mapped_x, mapped_y)
    }
}