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

【学Rust写CAD】24 扫描渐变(sweep_gradient.rs)

源码

// src/color/sweep_gradient.rs
use crate::fixed::Fixed;

/// 用于处理扫描渐变的数据结构
pub struct SweepGradientSource {
    /// 固定点矩阵,用于图形变换
    pub matrix: Matrix2D<Fixed>,
    /// 时间/渐变参数的偏置调整
    pub t_bias: f32,
    /// 时间/渐变参数的缩放因子
    pub t_scale: f32,
    /// 颜色查找表(256个32位颜色值)
    pub lut: [u32; 256],
}

impl SweepGradientSource {
    // This implementation is taken from Skia
    pub fn eval<S:Spread>(&self, x: u16, y: u16, spread: Spread) -> u32 {
        let p = self.matrix.transform(x, y);
        // XXX: this is slow and bad
        // the derivation is from pixman radial_get_scanline_narrow
        // " Mathematically the gradient can be defined as the family of circles
        //
        //    ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
        //
        // excluding those circles whose radius would be < 0."
        // i.e. anywhere where r < 0 we return 0 (transparent black).
        let px = p.x as f32 / 65536.;
        let py = p.y as f32 / 65536.;

        let xabs = px.abs();
        let yabs = py.abs();

        let slope = xabs.min(yabs)/xabs.max(yabs);
        let s = slope * slope;

        // Use a 7th degree polynomial to approximate atan.
        // This was generated using sollya.gforge.inria.fr.
        // A float optimized polynomial was generated using the following command.
        // P1 = fpminimax((1/(2*Pi))*atan(x),[|1,3,5,7|],[|24...|],[2^(-40),1],relative);
        let mut phi = slope
                * (0.15912117063999176025390625     + s
                * (-5.185396969318389892578125e-2   + s
                * (2.476101927459239959716796875e-2 + s
                * (-7.0547382347285747528076171875e-3))));

        if xabs < yabs {
            phi = 1.0/4.0 - phi;
        }
        if px < 0.0 {
            phi = 1.0/2.0 - phi;
        }
        if py < 0.0 {
            phi = 1.0 - phi;
        }
        if phi != phi {  // Check for NaN
            phi = 0.0;
        }
        let r = phi;

        let t = r * self.t_scale - self.t_bias;

        let result = self.lut[S::spread.apply((t * 255.) as i32, spread) as usize];
        result
    }
}

代码分析

这段代码实现了一个扫描渐变(Sweep Gradient)的数据结构和计算方法。扫描渐变是一种颜色沿着圆周方向渐变的着色效果。

数据结构
pub struct SweepGradientSource {
    pub matrix: Matrix2D<Fixed>,  // 用于图形变换的固定点矩阵
    pub t_bias: f32,              // 时间/渐变参数的偏置调整
    pub t_scale: f32,             // 时间/渐变参数的缩放因子
    pub lut: [u32; 256],          // 颜色查找表(256个32位颜色值)
}
主要方法 eval

eval 方法计算在给定坐标 (x,y) 处的颜色值:

  1. 坐标变换:
  • 使用矩阵变换将输入坐标 (x,y) 转换为新的坐标 p
  1. 计算角度:
  • 将坐标转换为浮点数 (px, py)

  • 计算绝对值和斜率

  • 使用7次多项式近似计算反正切函数(atan),这是为了性能优化

  1. 角度调整:
  • 根据坐标所在象限调整角度值 phi

  • 处理 NaN 情况

  1. 渐变参数计算:
  • 计算渐变参数 t = r * t_scale - t_bias

  • 使用 spread 方法处理超出范围的 t 值

  • 从颜色查找表(LUT)中获取最终颜色

技术细节

  • 该实现参考了Skia图形库的实现

  • 使用多项式近似代替精确的三角函数计算以提高性能

  • 颜色查找表(LUT)有256个条目,对应256种可能的渐变位置

  • Spread 类型参数控制如何处理超出范围的渐变参数

数学原理

渐变可以定义为一系列圆的族 ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂),排除那些半径小于0的圆。

这段代码实现了扫描渐变效果,它通过计算每个像素相对于中心点的角度来确定其在渐变中的位置,然后从预计算的颜色查找表中获取对应的颜色值。

http://www.dtcms.com/a/107700.html

相关文章:

  • 嵌入式c学习第十一天
  • CMake 中的置变量
  • 在服务器里面磁盘分区很简单吗?
  • 51单片机的五类指令(三)——逻辑操作类指令
  • 【图形API】片段着色器自动计算LOD
  • 蓝桥杯嵌入式16届—— LED模块
  • 【ABAP】REST/HTTP技术(一)
  • 进程间的通信
  • 批量删除 txt/html/json/xml/csv 等文本文件中的重复行
  • 2025年Axure RP9无法免费使用Axure Cloud的解决方案
  • IEOSE北京国际教育留学展 留学盛宴4月亮相国会
  • c++进阶之----orderedmap和unorderedmap
  • 不同向量数据库(FAISS / Pinecone / Weaviate)在 RAG 中的优缺点
  • 生成式AI应用带来持续升级的网络安全风险
  • Linux系统CentOS 6.3安装图文详解
  • 嵌入式调试进阶:从手动到自动的HardFault破案指南
  • qt实现功率谱和瀑布图
  • Kubernetes APIServer 可观测最佳实践
  • Telnet协议详解:本质与操作逻辑
  • 路由协议分类精讲
  • TrollStore(巨魔商店)介绍及操作手册
  • C 标准库 - `<ctype.h>`
  • Vue el-table-column内el-tooltip识别换行符 \n
  • Mysql的安装
  • java 使用 spring AI 实战MCP
  • centos-LLM+EmbeddingModel+VectorDB-简单模型
  • Aliee,Bengio and Theis:细胞数据上的因果机器学习
  • 代理模式-spring关键设计模式,bean的增强,AOP的实现
  • Spring SpringBoot 细节总结
  • 【ROS】 CMakeLists 文件详解