【学Rust写CAD】14线性插值函数(加入color.rs)

news/2025/3/31 5:53:58/

lerp 函数源码

rust">/// 颜色线性插值/// t 取值范围 0..256,0 表示完全使用当前颜色(self),256 表示完全使用目标颜色(end)#[inline]pub fn lerp(self, end: Color, t: u32) -> Color {let mask = 0xff00ff;// 提取目标颜色的蓝色和红色分量let brb = end.0 & 0xff00ff;// 提取目标颜色的alpha和绿色分量let bag = (end.0 >> 8) & 0xff00ff;// 提取当前颜色的蓝色和红色分量let arb = self.0 & 0xff00ff;// 提取当前颜色的alpha和绿色分量let aag = (self.0 >> 8) & 0xff00ff;// 计算分量差值let drb = brb.wrapping_sub(arb);let dag = bag.wrapping_sub(aag);// 应用插值系数let drb = drb.wrapping_mul(t) >> 8;let dag = dag.wrapping_mul(t) >> 8;// 计算最终分量值let rb = arb + drb;let ag = aag + dag;// 组合并返回结果颜色Color((rb & mask) | ((ag << 8) & !mask))}

颜色线性插值(Lerp)解释

这段代码实现了两个颜色之间的线性插值(linear interpolation),通常称为lerp。这是一种在两个值之间进行平滑过渡的技术,在这里用于颜色过渡。

工作原理
  1. 输入参数:
  • self: 起始颜色

  • end: 目标颜色

  • t: 插值系数,范围0-256(0=完全使用起始颜色,256=完全使用目标颜色)

  1. 颜色分量分离:
  • 将颜色值拆分为蓝色/红色分量和alpha/绿色分量

使用掩码0xff00ff来提取这些分量(因为颜色通常以ARGB格式存储)

  1. 差值计算:

计算目标颜色和起始颜色在各分量上的差值

  • 使用wrapping_sub处理可能的溢出
  1. 应用插值系数:
  • 将差值乘以插值系数t,然后右移8位(相当于除以256)

  • 这实现了按比例混合两个颜色

  1. 组合结果:
  • 将插值后的分量重新组合成最终颜色

  • 使用掩码确保各分量在正确的位置

为什么这样实现

这种实现方式有几个优点:

  • 使用位操作而不是浮点运算,效率更高

  • 同时处理两个颜色分量(蓝色/红色和alpha/绿色),减少操作次数

  • 使用包装算术(wrapping)避免溢出检查,提高性能

示例

如果起始颜色是红色(0xFF0000),目标颜色是蓝色(0x0000FF),当t=128时:

结果会是紫色(0x800080),正好在红色和蓝色中间

这种技术广泛应用于图形渲染、动画过渡和颜色渐变等场景。

测试代码

测试代码包括多种边界情况和典型场景的测试:

rust">#[cfg(test)]
mod tests {use super::Color;#[test]fn test_lerp() {// 测试相同颜色插值let white = Color(0xFFFFFFFF);for i in 0..=256 {assert_eq!(white.lerp(white, i).0, 0xFFFFFFFF, "相同颜色插值失败,i={}", i);}// 测试从黑到白插值let black = Color(0xFF000000);let white = Color(0xFFFFFFFF);assert_eq!(black.lerp(white, 0).0, 0xFF000000, "t=0应返回起始颜色");assert_eq!(black.lerp(white, 256).0, 0xFFFFFFFF, "t=256应返回目标颜色");assert_eq!(black.lerp(white, 128).0, 0xFF7F7F7F, "中间值不正确");// 测试红色到蓝色插值let red = Color(0xFFFF0000);let blue = Color(0xFF0000FF);assert_eq!(red.lerp(blue, 0).0, 0xFFFF0000);assert_eq!(red.lerp(blue, 256).0, 0xFF0000FF);assert_eq!(red.lerp(blue, 128).0, 0xFF7F007F);// 测试透明度变化let opaque = Color(0xFF123456);let transparent = Color(0x00123456);assert_eq!(opaque.lerp(transparent, 128).0, 0x7F123456);// 测试边界情况let color1 = Color(0x12345678);let color2 = Color(0x87654321);assert_eq!(color1.lerp(color2, 0).0, color1.0);assert_eq!(color1.lerp(color2, 256).0, color2.0);// 测试所有分量同时变化let start = Color(0x00000000);let end = Color(0x01020304);assert_eq!(start.lerp(end, 64).0, 0x00404040); // 1/4 of end color}#[test]fn test_lerp_edge_cases() {// 测试t值超出范围的情况(虽然参数是u32,但实际只使用低9位)let c1 = Color(0x00000000);let c2 = Color(0xFFFFFFFF);assert_eq!(c1.lerp(c2, 257).0, c1.lerp(c2, 1).0); // 257 & 0xFF = 1assert_eq!(c1.lerp(c2, 512).0, c1.lerp(c2, 0).0); // 512 & 0xFF = 0// 测试颜色值溢出情况let low = Color(0x00000000);let high = Color(0xFFFFFFFF);assert_eq!(low.lerp(high, 255).0, 0xFFFEFEFE);}
}
测试说明
  1. 基本测试:
  • 相同颜色插值结果应该不变

  • 从黑到白插值的边界和中间值

  • 从红到蓝插值的典型场景

  1. 透明度测试:
  • 测试alpha通道的插值是否正确

3.边界测试:

  • 确保t=0和t=256时返回正确的颜色

  • 测试t值超出范围时的行为(虽然参数是u32,但实现只使用低9位)

  1. 分量测试:
  • 测试所有颜色分量同时变化的情况

  • 测试颜色值溢出的处理

  1. 特殊场景:
  • 测试包装算术(wrapping)的正确性

这些测试覆盖了正常使用场景和边界情况,可以验证lerp方法的正确性。


http://www.ppmy.cn/news/1583753.html

相关文章

[计算机网络]网络I/O模型

欢迎来到啾啾的博客&#x1f431;。 这是一个致力于构建完善的Java程序员知识体系的博客&#x1f4da;&#xff0c;记录学习的点滴&#xff0c;分享工作的思考、实用的技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 欢迎评论交流&#xff0c;感谢您的阅读&#x1f604;。…

Go File容器化部署方案:本地快速搭建与无公网IP远程传输文件指南

文章目录 前言1. 安装Docker2. Go File使用演示3. 安装cpolar内网穿透4. 配置Go File公网地址5. 配置Go File固定公网地址 前言 在这个信息大爆炸的时代&#xff0c;谁还没遇到过这样的尴尬场面呢&#xff1f;当你正在办公室埋头苦干时&#xff0c;手机突然跳出一条紧急邮件&a…

TCP的长连接和短连接,以及它们分别适用于什么场合

TCP长连接与短连接详解 一、核心概念对比 特性长连接&#xff08;Persistent Connection&#xff09;短连接&#xff08;Short-lived Connection&#xff09;连接生命周期一次建立后长期保持&#xff0c;多次数据交互复用同一连接每次数据交互均需新建连接&#xff0c;完成后…

内网渗透-DLL和C语言加载木马

免杀进阶技术 1、DLL的定义与使用 DLL:Dynamic Link library,动态链接库&#xff0c;是一个无法自己运行&#xff0c;需要额外的命令或程序来对其接口进行调用&#xff08;类方法、函数&#xff09;。 (1)在DevCpp中创建一个DLL项目 (2)在dllmain.c中定义源代码函数接口 #i…

CLion配置问题解决

课程笔记 https://www.yuque.com/bigdata-caoyu/newcpp CLion 激活码不可用 https://blog.csdn.net/qq_41973721/article/details/142407716 主机名&#xff1a;localhost 端口号&#xff1a;80 不为以下设置代理&#xff1a;*.github.com,plugins.jetbrains.com 插件无法下…

OkHttp 的证书设置

在 Android 开发中&#xff0c;通过 OkHttp 自定义 SSLSocketFactory 和 X509TrustManager 可以有效增强 HTTPS 通信的安全性&#xff0c;防止中间人攻击&#xff08;如抓包工具 Charles/Fiddler 的拦截&#xff09;。以下是实现防抓包的关键技术方案&#xff1a; 一、Okhttp设…

在 Ubuntu 下通过 Docker 部署 Nginx 服务器

1. Docker 和 Nginx 简介以及实验环境 Docker 是一个开源的容器化平台&#xff0c;允许开发者将应用程序及其依赖项打包成一个轻量级的、可移植的容器。通过 Docker&#xff0c;开发者可以在任何支持 Docker 的环境中运行应用&#xff0c;从而实现一致的开发和生产环境。Docke…

什么是区块链dapp开发?它能做什么?

区块链DApp&#xff08;去中心化应用&#xff09;作为区块链技术的核心落地场景&#xff0c;正在重构数字经济的底层逻辑。其核心特征包括去中心化架构&#xff08;数据存储于分布式网络节点而非中心化服务器&#xff09;智能合约驱动&#xff08;业务逻辑通过链上代码自动执行…