当前位置: 首页 > article >正文

2.13 转换矩阵

转换矩阵引用了库nalgebra,使用时研究具体实现。

use std::ops;

use nalgebra::Perspective3;

use crate::Scalar;

use super::{Aabb, LineSegment, Point, Triangle, Vector};

/// An affine transform
#[repr(C)]
#[derive(Debug, Clone, Copy, Default)]
pub struct Transform(nalgebra::Transform<f64, nalgebra::TAffine, 3>);

impl Transform {
    /// Construct an identity transform
    pub fn identity() -> Self {
        Self(nalgebra::Transform::identity())
    }

    /// Construct a translation
    pub fn translation(offset: impl Into<Vector<3>>) -> Self {
        let offset = offset.into();

        Self(nalgebra::Transform::from_matrix_unchecked(
            nalgebra::OMatrix::new_translation(&offset.to_na()),
        ))
    }

    /// Construct a rotation
    ///
    /// The direction of the vector defines the rotation axis. Its length
    /// defines the angle of the rotation.
    pub fn rotation(axis_angle: impl Into<Vector<3>>) -> Self {
        let axis_angle = axis_angle.into();

        Self(nalgebra::Transform::from_matrix_unchecked(
            nalgebra::OMatrix::<_, nalgebra::Const<4>, _>::new_rotation(
                axis_angle.to_na(),
            ),
        ))
    }

    /// Construct a scaling
    pub fn scale(scaling_factor: f64) -> Self {
        Self(nalgebra::Transform::from_matrix_unchecked(
            nalgebra::OMatrix::new_scaling(scaling_factor),
        ))
    }

    /// # Extract the "right" vector from the rotational component
    pub fn right(&self) -> Vector<3> {
        let d = self.data();
        Vector::from([d[0], d[1], d[2]])
    }

    /// # Extract the "up" vector from the rotational component
    pub fn up(&self) -> Vector<3> {
        let d = self.data();
        Vector::from([d[4], d[5], d[6]])
    }

    /// Transform the given point
    pub fn transform_point(&self, point: &Point<3>) -> Point<3> {
        Point::from(self.0.transform_point(&point.to_na()))
    }

    /// Inverse transform given point
    pub fn inverse_transform_point(&self, point: &Point<3>) -> Point<3> {
        Point::from(self.0.inverse_transform_point(&point.to_na()))
    }

    /// Transform the given vector
    pub fn transform_vector(&self, vector: &Vector<3>) -> Vector<3> {
        Vector::from(self.0.transform_vector(&vector.to_na()))
    }

    /// Transform the given segment
    pub fn transform_segment(
        &self,
        segment: &LineSegment<3>,
    ) -> LineSegment<3> {
        let [a, b] = &segment.points;
        LineSegment::from([self.transform_point(a), self.transform_point(b)])
    }

    /// Transform the given triangle
    pub fn transform_triangle(&self, triangle: &Triangle<3>) -> Triangle<3> {
        let [a, b, c] = &triangle.points;
        Triangle::from([
            self.transform_point(a),
            self.transform_point(b),
            self.transform_point(c),
        ])
    }

    /// Inverse transform
    pub fn inverse(&self) -> Self {
        Self(self.0.inverse())
    }

    /// Transpose transform
    pub fn transpose(&self) -> Self {
        Self(nalgebra::Transform::from_matrix_unchecked(
            self.0.to_homogeneous().transpose(),
        ))
    }

    /// Project transform according to camera specification, return data as an array.
    /// Used primarily for graphics code.
    pub fn project_to_array(
        &self,
        aspect_ratio: f64,
        fovy: f64,
        znear: f64,
        zfar: f64,
    ) -> [Scalar; 16] {
        let projection = Perspective3::new(aspect_ratio, fovy, znear, zfar);

        let mut array = [0.; 16];
        array.copy_from_slice(
            (projection.to_projective() * self.0).matrix().as_slice(),
        );

        array.map(Scalar::from)
    }

    /// Return a copy of the inner nalgebra transform
    pub fn get_inner(&self) -> nalgebra::Transform<f64, nalgebra::TAffine, 3> {
        self.0
    }

    /// Transform the given axis-aligned bounding box
    pub fn transform_aabb(&self, aabb: &Aabb<3>) -> Aabb<3> {
        Aabb {
            min: self.transform_point(&aabb.min),
            max: self.transform_point(&aabb.max),
        }
    }

    /// Exposes the data of this Transform as a slice of f64.
    pub fn data(&self) -> &[f64] {
        self.0.matrix().data.as_slice()
    }

    /// Extract the rotation component of this transform
    pub fn extract_rotation(&self) -> Self {
        Self(nalgebra::Transform::from_matrix_unchecked(
            self.0.matrix().fixed_resize::<3, 3>(0.).to_homogeneous(),
        ))
    }

    /// Extract the translation component of this transform
    pub fn extract_translation(&self) -> Self {
        *self * self.extract_rotation().inverse()
    }
}

impl ops::Mul<Self> for Transform {
    type Output = Self;

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

#[cfg(test)]
mod tests {
    use approx::assert_abs_diff_eq;

    use crate::{Scalar, Vector};

    use super::Transform;

    #[test]
    fn extract_rotation_translation() {
        let rotation =
            Transform::rotation(Vector::unit_z() * (Scalar::PI / 2.));
        let translation = Transform::translation([1., 2., 3.]);

        assert_abs_diff_eq!(
            (translation * rotation).extract_rotation().data(),
            rotation.data(),
            epsilon = 1e-8,
        );

        assert_abs_diff_eq!(
            (translation * rotation).extract_translation().data(),
            translation.data(),
            epsilon = 1e-8,
        );

        assert_abs_diff_eq!(
            (rotation * translation).extract_rotation().data(),
            rotation.data(),
            epsilon = 1e-8,
        );

        assert_abs_diff_eq!(
            (rotation * translation).extract_translation().data(),
            Transform::translation([-2., 1., 3.]).data(),
            epsilon = 1e-8,
        );
    }
}


http://www.kler.cn/a/405126.html

相关文章:

  • MybatisPlus之1:快速入门
  • 【代码pycharm】动手学深度学习v2-04 数据操作 + 数据预处理
  • JMeter监听器与压测监控之 InfluxDB
  • Qt桌面应用开发 第五天(常用控件 自定义控件)
  • bash笔记
  • 网络蠕虫病毒研究
  • 【数据库知识】mysql进阶-Mysql数据库的主从复制
  • Spring Boot核心概念:日志管理
  • SAP FICO 资产会计AA后台配置 (上)
  • PHP顺序查找和二分查找(也叫做折半查找)算法
  • Block Successive Upper Bound Minimization Method(BSUM)算法
  • Android 使用 LiveData/OnCheckedChangeListener 来监听变量变化
  • C++ 并发专题 - 线程安全的单例模式
  • Apache Maven简介
  • 给机器装上“脑子”—— 一文带你玩转机器学习
  • 博导的角度看,EtherNet/IP转Profinet网关的技术实现和区别
  • 基于Java Springboot社区便民服务管理系统
  • 移动零
  • CircuitBreaker机制详解:Elasticsearch中的资源管理
  • 【GIT】TortoiseGit的变基(Rebase)操作
  • Easyexcel(1-注解使用)
  • 什么是MuLogin虚拟浏览器配置文件?它们有什么作用?
  • MongoDB 监控:确保数据库性能和可靠性
  • 【postgresql初级使用】逻辑复制是对数据库对象进行复制,非常灵活的完成数据归集与分发
  • SpringBoot3+Vue3开发图书馆管理系统
  • ZYNQ-7020嵌入式系统学习笔记(1)——使用ARM核配置UART发送Helloworld