【图形学】直线光栅化算法(DDA算法,Bresenham算法和中点算法)

news2024/9/28 3:30:30

在数学上,直线就是由无穷多个点组成的, 在计算机屏幕显示的话, 需要做一些处理,对于光栅显示器,就是用有限多个点去逼近直线, 我们需要知道每一个像素点的坐标(都是整数)
在这里插入图片描述

数学上直线的方程如下 y = k x + b y=kx+b y=kx+b,给定直线的起点坐标 P 0 ( x 0 , y 0 ) P_0(x_0,y_0) P0(x0,y0)终点坐标 P 1 ( x 1 , y 1 ) P_1(x_1,y_1) P1(x1,y1)水平方向的位移 Δ x = x 1 − x 0 \Delta x=x_1-x_0 Δx=x1x0垂直方向的位移 Δ y = y 1 − y 0 \Delta y=y_1-y_0 Δy=y1y0 在直线的光栅化算法中要通过 Δ x 和 Δ y \Delta x 和 \Delta y ΔxΔy 的大小来确定绘图的主位移方向,主位移方向执行 ± 1 \pm1 ±1

条件主方向
Δ x > Δ y \Delta x>\Delta y Δx>Δyx方向
Δ x = Δ y \Delta x=\Delta y Δx=Δyx方向或y方向
Δ x < Δ y \Delta x<\Delta y Δx<Δyy方向

DDA算法

直线的斜截式方程用微分的形式表示为 d y d x = Δ y Δ x = k \frac{dy}{dx}=\frac{\Delta y}{\Delta x}=k dxdy=ΔxΔy=k
那么可以得到直线上的像素点 P i + 1 和 P i P_{i+1}和P_{i} Pi+1Pi的递推关系
{ x i + 1 = x i + Δ x y i + 1 = y i + Δ y = y i + k Δ x \begin{cases} x_{i+1}=x_i+\Delta x \\ y_{i+1}=y_i +\Delta y=y_i+k\Delta x \end{cases} {xi+1=xi+Δxyi+1=yi+Δy=yi+kΔx
以斜率 0 ≤ k < 1 0\leq k <1 0k<1为例,有 Δ x > Δ y \Delta x>\Delta y Δx>Δy ,主方向是x,那么上面的式子就变成了
{ x i + 1 = x i + 1 y i + 1 = y i + k \begin{cases} x_{i+1}=x_i+1 \\ y_{i+1}=y_i +k \end{cases} {xi+1=xi+1yi+1=yi+k
设点 E ( x i + 1 , y i + k ) E(x_i+1,y_i+k) E(xi+1,yi+k)是理想直线和线 x i + 1 = x i + 1 的交点 x_{i+1}=x_i+1的交点 xi+1=xi+1的交点那么用来逼近这个点的可能的像素点有两个 D ( x i + 1 , y i + 1 ) 和 C ( x i + 1 , y i ) D(x_i+1,yi+1)和C(x_i+1,y_i) D(xi+1,yi+1)C(xi+1,yi)具体选择那个,就根据k的值确定(? y i + k y_i +k yi+k四舍五入? y i + 1 = i n t ( y_{i+1}=int( yi+1=int(y_i+k+0.5 ) ) ))
在这里插入图片描述

下面给出DDA算法画任意斜率直线的主要代码

void CLine::DrawLine(CDC* pDC)
{
    int dx = m_p2.x - m_p1.x;//m_p1,m_p2(CPoint)
    int dy = m_p2.y - m_p1.y;
    double k = (double)(dy) / (double)(dx);  //斜率

    //确定主方向
    int e = abs(k) > 1 ? abs(dy) : abs(dx);
    double xadd = (double)(dx) / (double)(e);
    double yadd = (double)(dy) / (double)(e);
    double x = (double)(m_p1.x);
    double y = (double)(m_p1.y);
    for (int i = 0; i <= e; i++) {
        pDC->SetPixel((int)(x + 0.5), (int)(y + 0.5), RGB(0, 0, 0));
        x += xadd;
        y += yadd;
    }
}

Bresenham算法

在这里插入图片描述

Bresenham算法在主位移方向上也是移动一个单位,另一个方向移动0还是1取决于像素点和理想直线的距离d
还是以斜率 0 ≤ k < 1 0\le k <1 0k<1为例,x方向是主位移方向,点 Q ( x i + 1 , y i + 1 ) Q(x_{i+1},y_{i+1}) Q(xi+1,yi+1)是理想直线和 x i + 1 = x i + 1 x_{i+1}=x_i+1 xi+1=xi+1的交点,两个可能的像素的 P u p ( x i , y i + 1 ) 和 P d o w n ( x i , y i ) P_{up}(x_i,y_i+1) 和P_{down}(x_i,y_i) Pup(xi,yi+1)Pdown(xi,yi),选那一个就取决于Q点和 P d o w n P_{down} Pdown的距离 d i + 1 d_{i+1} di+1,对于误差项d的计算向x方向递增1个单位就有 d i + 1 = d i + k d_{i+1}=d_i+k di+1=di+k,如果向y方向递增一个单位就还要减1。
d 0 = 0 y i + 1 = { y i + 1 , d i + 1 ≥ 0.5 y i , d i + 1 < 0.5 d_0=0 \\ \\ y_{i+1}=\begin{cases} y_{i}+1 ,d_{i+1}\geq 0.5\\ y_i,d_{i+1}<0.5 \end{cases} d0=0yi+1={yi+1,di+10.5yi,di+1<0.5
不过通常不是用误差项d进行计算,取一个变量e, e 0 = − Δ x e_0=-\Delta x e0=Δx,沿x方向每递增一个单位就有 e i + 1 = e i + 2 Δ y e_{i+1}=e_i+2\Delta y ei+1=ei+y,当 e i + 1 ≥ 0 e_{i+1}\geq 0 ei+10时下一个像素点就是( x i + 1 , y i + 1 x_i+1,y_i+1 xi+1,yi+1),并且要更新 e i + 1 = e i + 1 − 2 Δ x e_{i+1}=e_{i+1}-2\Delta x ei+1=ei+1x;否则下一个像素点就是( x i + 1 , y i x_i+1,y_i xi+1,yi)。

原始的Bresenham只能画指向第一象限并且斜率小于1的直线,但实际有这么多种情况,但是别慌,可以利用直线的对称性解决。
在这里插入图片描述

对于相同象限, 斜率不同的情况, 其实就是将斜率在0到1之间的线作关于函数y = x 对称而得到。对应到代码中就是将所有的y和所有的x调换位置。比如, e 0 = − Δ y e_0=-\Delta y e0=Δy e i + 1 = e i + 2 Δ x e_{i+1}=e_i+2\Delta x ei+1=ei+x,当 e i + 1 ≥ 0 e_{i+1}\geq 0 ei+10时下一个像素点就是( x i + 1 , y i + 1 x_i+1,y_i+1 xi+1,yi+1),并且要更新 e i + 1 = e i + 1 − 2 Δ y e_{i+1}=e_{i+1}-2\Delta y ei+1=ei+1y;否则下一个像素点就是( x i + 1 , y i x_i+1,y_i xi+1,yi)。
下面给出通用的Bresenham算法

void CLine::DrawLine(CDC* pDC)
{
    int dx = abs(m_p2.x - m_p1.x);//m_p1,m_p2(CPoint)
    int dy = abs(m_p2.y - m_p1.y);
    double k = (double)(dy) / (double)(dx);  //斜率
	BOOL wayChange = FALSE;//主方向是否发生改变,默认是x方向
	int e,mainway,subway;
	e = -dx;
	mainway = dx;
	subway = dy;
	int addx, addy;
	addx = (m_p2.x > m_p1.x) ? 1 : ((m_p2.x < m_p1.x) ? -1 : 0);
	addy = (m_p2.y > m_p1.y) ? 1 : ((m_p2.y < m_p1.y) ? -1 : 0);
	if (dy > dx) {//主方向是y
		mainway = dy;
		subway = dx;
		wayChange = TRUE;
	}
	CPoint p = m_p1;
	for (int i = 0; i <= mainway; i++) {
		pDC->SetPixel(p, RGB(0, 255, 0));
		if (wayChange)
			p.y += addy;
		else
			p.x += addx;
		e += 2 * subway;
		if (e >= 0) {
			if (wayChange)
				p.x += addx;
			else
				p.y += addy;
			e -= 2 * mainway;
		}
	}
}

中点算法

以第一象限斜率 0 ≤ k < 1 0\leq k<1 0k<1的直线为例。
直线的隐函数方程可以表示为 F ( x , y ) = y − k x − b = 0 F(x,y)=y-kx-b=0 F(x,y)=ykxb=0
在这里插入图片描述

A ( x i , y i ) , C ( x i + 1 , y i + 1 ) , D ( x i + 1 , y i ) , E ( x i + 1 , y i + 0 , 5 ) A(x_i,y_i),C(x_i+1,y_i+1),D(x_i+1,y_i),E(x_i+1,y_i+0,5) A(xi,yi),C(xi+1,yi+1),D(xi+1,yi),E(xi+1,yi+0,5)
将点E带入直线的隐函数方程有 d i = F ( x i + 1 , y i + 0.5 ) = y i + 0.5 − k ( x i + 1 ) − b d_i=F(x_i+1,y_i+0.5)=\\y_i+0.5-k(x_i+1)-b di=F(xi+1,yi+0.5)=yi+0.5k(xi+1)b
同判断 d i d_i di的正负就可以知道点E在直线的下方还是上方,从而确定选择点C还是选择点D
y i + 1 = { y i + 1 d i < 0 y i d i ≥ 0 \begin{equation} y_{i+1}=\left\{ \begin{aligned} y_i+1\quad d_i<0\\ y_i\quad d_i \geq0 \end{aligned} \right . \end{equation} yi+1={yi+1di<0yidi0
接下来就是求中点误差项d的递推公式
d 0 = 0.5 − k 当 d i < 0 时选择了点 C ( x i + 1 , y i + 1 ) 下一步要进行判断的中点就是 M ( x i + 2 , y i + 1.5 ) , 带入直线方程就是 d i + 1 = d i + 1 − k 当 d i > = 0 时选择了点 D ( x i + 1 , y i ) , 下一步要进行判断的中点就是 M ( x i + 2 , y i + 0.5 ) 带到直线方程就是 d i + 1 = d i − k d_0=0.5-k\\当d_i<0时选择了点C(x_i+1,y_i+1)下一步要进行判断的中点就是M(x_i+2,y_i+1.5),带入直线方程就是d_{i+1}=d_i+1-k 当d_i>=0时选择了点D(x_i+1,y_i),下一步要进行判断的中点就是M(x_i+2,y_i+0.5)带到直线方程就是d_{i+1}=d_i-k d0=0.5kdi<0时选择了点C(xi+1,yi+1)下一步要进行判断的中点就是M(xi+2,yi+1.5),带入直线方程就是di+1=di+1kdi>=0时选择了点D(xi+1,yi),下一步要进行判断的中点就是M(xi+2,yi+0.5)带到直线方程就是di+1=dik
求出来了中点误差项,但这并不是我们想要的,因为这个递推是中有小数(0.5,k),我们需要的是进行整数运算。
这里引入新的值e
e 0 = Δ x − 2 Δ y 当 e i < 0 时 e i + 1 = e i + 2 Δ x − 2 Δ y 当 e i ≥ 0 时 e i + 1 = e i − 2 Δ y e_0= \Delta x-2\Delta y\\当e_i<0时e_{i+1}=e_i+2\Delta x-2\Delta y\\当e_i\geq0时e_{i+1}=e_i-2\Delta y e0=Δxyei<0ei+1=ei+xyei0ei+1=eiy

下面是通用的中点算法

void CLine::DrawLine(CDC* pDC)
{
	int dx = abs(m_p2.x - m_p1.x);//m_p1,m_p2(CPoint)
	int dy = abs(m_p2.y - m_p1.y);
	BOOL wayChange = FALSE;//主方向是否发生改
	int e, mainway, subway;
	
	mainway = dx;
	subway = dy;
	int addx, addy;
	addx = (m_p2.x > m_p1.x) ? 1 : ((m_p2.x < m_p1.x) ? -1 : 0);
	addy = (m_p2.y > m_p1.y) ? 1 : ((m_p2.y < m_p1.y) ? -1 : 0);
	if (dy > dx) {//主方向是y
		mainway = dy;
		subway = dx;
		wayChange = TRUE;
	}
	e =mainway-2*subway;
	CPoint p = m_p1;
	for (int i = 0; i < mainway; i++) {
		pDC->SetPixel(p, RGB(0, 255, 0));
		if (wayChange)
			p.y += addy;
		else
			p.x += addx;
		e -= 2 * subway;
		if (e <  0) {
			if (wayChange)
				p.x += addx;
			else
				p.y += addy;
			e += (2 * mainway - 2 * subway);
		}
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1396664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker部署的gitlab升级指南(15.11.X容器里升级PostgreSQL到13.8)

一、确定当前版本 #进入当前版本容器产看gitlab版本 docker exec -it gitlab cat /opt/gitlab/embedded/service/gitlab-rails/VERSION#显示版本如下 14.4.0二、备份数据&#xff0c;防止升级发生意外 #执行备份命令 docker exec -ti gitlab gitlab-rake gitlab:backup:creat…

MT6789(G99)性能参数/datasheet_MTK联发科4G处理器

联发科MT6789将4G智能手机带入下一代。基于高效率的台积电N6 (6nm级)芯片生产工艺&#xff0c;该芯片可全天候实现出色的游戏&#xff0c;加上大摄像头&#xff0c;快速显示&#xff0c;流畅的流媒体和可靠的全球连接。合作伙伴可以定制联发科Helio G99平台&#xff0c;以满足其…

Python高级编程之IO模型与协程

更多Python学习内容&#xff1a;ipengtao.com 在Python高级编程中&#xff0c;IO模型和协程是两个重要的概念&#xff0c;它们在处理输入输出以及异步编程方面发挥着关键作用。本文将介绍Python中的不同IO模型以及协程的概念、原理和用法&#xff0c;并提供丰富的示例代码来帮助…

go语言(七)----slice的声明方式

1、声明方式一 //声明一个slice1是一个切片&#xff0c;但是并没有给slice分配空间var slice1 []intslice1 make([]int,3)2、声明方式二 声明一个slice切片&#xff0c;同时给slice分配空间&#xff0c;3个空间&#xff0c;初始化值是0var slice1 []int make([]int,3)3、声…

ChatGPT 报错“Oops!We ran into an issue while signing you in…”如何解决?

ChatGPT报错&#xff1a;“Oops&#xff01;We ran into an issue while signing you in, please take abreak and try again soon.” 说明&#xff1a;哎呀&#xff01;我们在登录时遇到了一个问题&#xff0c;请稍作休息并尽快再试一次。 原因&#xff1a; 看到这个提示时&a…

杂记 | 在Linux上使用Docker-compose安装单机版Milvus向量数据库并配置访问控制和可视化面板(Attu)

文章目录 01 Milvus向量数据库简介02 安装前的准备03 安装3.1 创建milvus工作目录3.2 下载并编辑docker-compose.yml3.3 下载milvus.yml文件3.4 启动milvus 04 访问可视化面板并修改密码 01 Milvus向量数据库简介 Milvus是一款开源的向量数据库&#xff0c;它专为AI应用设计&a…

市场监管总局发布区块链和分布式记账技术6项标准,中创积极推动区块链产业发展!

近日&#xff0c;市场监管总局&#xff08;国家标准委&#xff09;批准发布一批重要国家标准&#xff0c;涉及生产生活、绿色可持续等多个领域&#xff0c;这些标准将在引领产业发展、促进绿色转型、助力对外贸易、推动城乡建设、提升生活品质等方面发挥重要作用。 其中一项标…

msvcr100.dll缺失的6种详细有效解决方法

msvcr100.dll究竟是什么文件&#xff1f;为什么会丢失&#xff1f;丢失后会对计算机产生什么影响&#xff1f;本文将详细介绍msvcr100.dll的定义、作用和影响&#xff0c;并给出6个解决msvcr100.dll丢失的方法。 一、msvcr100.dll是什么文件&#xff1f; msvcr100.dll是Micro…

跑通 yolov5-7.0 项目之训练自己的数据集

yolov5 一、yolov5 源码下载二、配置环境&#xff0c;跑通项目三、训练自己的数据集1、获取验证码数据2、标注图片&#xff0c;准备数据集3、开始训练自己的数据集1、train.py 训练数据集2、val.py 验证测试你的模型3、detect.py 正式用你的模型 四、遇到的报错、踩坑1、import…

MySQL的基本查询(附案例)

目录 前言 Create&#xff08;创建&#xff09; 单行数据全列插入&#xff1a; 多行数据指定列插入&#xff1a; 插入否则更新&#xff1a; 替换&#xff1a; Retrieve&#xff08;读取&#xff09; SELECT 列&#xff1a; 全列查询&#xff1a; 指定列查询&#xff1a…

DETR 个人理解

DETR 个人理解 目录 DETR 个人理解 概念说明 transformer网络结构 整体流程 损失计算 整体理解 结果说明 论文 代码 参考链接 个人拙见&#xff0c;仅供参考&#xff0c;欢迎指正交流 这篇论文还是挺重要的&#xff0c;因为是transforms用于目标检测的第一篇论文&am…

LiveGBS流媒体平台GB/T28181常见问题-多个网段如何注册LiveGBS多网段设备收流多个专线不同地址网段收流内外网同时收流

LiveGBS常见问题多个网段如何注册LiveGBS多网段设备收流多个专线不同地址网段收流内外网同时收流 1、背景2、设备接入播放2.1、查看通道2.2、直播播放 3、默认收流地址配置4、其它网络设备收流配置5、搭建GB28181视频直播平台 1、背景 服务器部署的时候&#xff0c;可能有多个…

VIM工程的编译 / VI的快捷键记录

文章目录 VIM工程的编译 / VI的快捷键记录概述笔记工程的编译工程的编译 - 命令行vim工程的编译 - GUI版vim备注VIM的帮助文件位置VIM官方教程vim 常用快捷键启动vi时, 指定要编辑哪个文件正常模式光标的移动退出不保存 退出保存只保存不退出另存到指定文件移动到行首移动到行尾…

cmseasy业务逻辑漏洞

这个cmseasy靶场似乎感觉有点意思&#xff1f; 1.任意修改用户密码 首先肯定先是注册一个账号&#xff08;账号test&#xff0c;密码admin&#xff09;&#xff0c;去找到他的找回密码这里 随便填点数字&#xff08;这个用户名与他的邮箱还是要对应的&#xff09;&#…

基于Springboot+vue鲜花商城系统(前后端分离)

该项目完全免费 项目技术栈&#xff1a; 前端&#xff1a;vueelementUIecharts 后端&#xff1a;SpringbootmybatisMySQL 项目主要功能&#xff1a; 商品信息 商品分类 角色管理 公告管理 轮播图管理 订单管理 收货地址管理 日志管理 部分功能截图&#xff1a;

GaussDB与openGauss有什么相同和不同?

众所周知&#xff0c;GaussDB是华为自主创新研发的分布式关系型数据库&#xff0c;为企业提供功能全面、稳定可靠、扩展性强、性能优越的企业级数据库服务&#xff0c;openGauss是开源数据库&#xff0c;两者之间又是什么样的关系&#xff0c;有什么相同和不同&#xff0c;让我…

【unity学习笔记】语音驱动blendershape

1.导入插件 https://assetstore.unity.com/packages/tools/animation/salsa-lipsync-suite-148442 1.选择小人&#xff0c;点击添加组件 分别加入组件&#xff1a; SALSA EmoteR Eyes Queue Processor&#xff08;必须加此脚本&#xff09;&#xff1a;控制前三个组件的脚本。…

Win10下在Qt项目中配置SQlite3环境

资源下载 官网资源&#xff1a;SQLite Download Page 1、sqlite.h sqlite-amalgamation-3450000.zip (2.60 MiB) 2、sqlite3.def&#xff0c;sqlite3.dll sqlite-dll-win-x64-3450000.zip (1.25 MiB) 3、 win10下安装sqlite3所需要文件 sqlite-tools-win-x64-3450000.zipht…

2024年香港优才计划新政策变化!看清利弊再做申请!

2024年香港优才计划新政策变化&#xff01;看清利弊再做申请&#xff01; 2024年香港优才计划申请新政策变化如下&#xff1a; 变化一&#xff1a;高管加分条件更明确&#xff0c;但条件更严 以前&#xff1a;默认自己在公司处于中高层管理岗&#xff0c;给自己加高管分。 现在…

【我与Java的成长记】之多态,重载与重写详解

系列文章目录 能看懂文字就能明白系列 C语言笔记传送门 Java笔记传送门 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言一、多态的概…