[计算机图形学经典算法] 直线段和圆弧在屏幕上的绘制 (附matlab代码)

标签: 计算机图形学

刚学习了计算机图形学这门课程,为奠定根基的算法所倾倒,特此记录一二。

直线—中点 Bresenham 算法

DDA算法在效率上较低的原因是需要计算 k,并以之作为累加项。一个直观的改进方式,是在整个运算过程中将涉及到的数值乘以 dx (或dy),转化为整型进行运算。

中点 Bresenham 算法采用一种不同的观点来解决这一问题-判别式。我们先考虑一般的直线方程,在图形学中我们一般给出的已知条件是两个端点:
这里写图片描述

此判别方程的意义,在于直线上的所有点均使 F(x,y)=0。

现在,我们考虑离散的情形,在|k| < 1时,为判断如下图所示的与P相邻的像素点Pd和Pu中的哪一个归属于直线,我们取两者的中点M作为判决依据。将其坐标代入判别式
(1) F(M) < 0, 取上方点 Pu
(2) F(M) > 0, 取下方点 Pd

这里写图片描述

因此,若(Xi, Yi)为直线上的点,在判定下一个点(Xi+1,Yi+1)并在(Xi+1,Yi+1)和(Xi+1,Yi)中进行选择时,可以根据中点坐标(Xi+1,Yi+0.5)代入判别式进行判定。
F(Xi,Yi) = a Yi + b Xi + c = 0
F(Xi+1,Yi+0.5) = a Yi + 0.5a + b Xi + b +c
= 0.5a + b
(1) F(M) = 0.5a + b < 0, 取上方点 Pu (Xi+1,Yi+1)
(2) F(M) = 0.5a + b > 0, 取下方点 Pd (Xi+1,Yi)

两个问题:

(1) F(Xi,Yi)=0 不一定总能满足,如何解决?
(2) 尽管 a, b, c 均为整数(?),仍有一个0.5为小数。
问题(2)容易解决,仅需在计算过程中乘2即可;
问题(1)则较为麻烦。我们知道在起始点时,F(Xi,Yi)=0 总是成立的,在后续计算中我们将偏差 F(Xi,Yi)=di 累计表达为 F(Xi,Yi)-di=0,再累积起来通过一个变量来考虑的。然而,因为前面的推导基于 +1(x方向) 和 +0.5(y方向),所以对该变量要进行调整。具体通过递推完成。

递推式

因为不能保证各像素点处的F(Xi,Yi)=0,因此只能从起始点处考虑 F(X0,Y0)=0,然后依次考虑F(X0+1,Y0+0.5), F(X0+2,Y0+?),… 此处我们可以看出,必须要分两种情况。
当 F(X0+1,Y0+0.5) < 0,选择(Xi+1,Yi+1)时,再判断的下一个中点应为(Xi+2,Yi+1.5);
当 F(X0+1,Y0+0.5) > 0,选择(Xi+1,Yi)时,再判断的下一个中点应为(Xi+2,Yi+0.5);
注意每一步只有两种可能,所以这个模式是重复出现的,换句话说可用迭代的方式实现两个中点间的递推关系。

累积误差项的递推(di+1 < 0)
这里写图片描述
累积误差项的递推关系,反映了相邻中点间的递推关系。

补充细节:

这里写图片描述

算法整体描述:

  • 计算初始值△x、△y、d=△x-2△y、x=x0、y=y0。
  • 绘制点(x,y)。判断d的符号。若d<0,则(x,y)更新为(x+1,y+1),d更新为d+2△x-2△y;否则(x,y)更新为(x+1,y), d更新为d-2△y。
    (这种递推关系类似数学归纳法,相邻中点间构建关系)
  • 当直线没有画完时,重复上一步骤,否则结束。

例题:

这里写图片描述

matlab代码

% P,Q为直线段端点,pixs_line为计算出的像素点
function pixs_line = bresenham_line(P,Q)

% 判断斜率 k 是否绝对值小于1
% 如果斜率大于1, X,Y坐标互换
if abs(Q(2)-P(2)) > abs(Q(1)-P(1))  
    P = [P(2) P(1)];  Q = [Q(2),Q(1)];
end

% 初始化变量
n = abs(Q(1)-P(1)) + 1; 
pixs_line = zeros(n,2);
pixs_line(1,1:2) = [P(1) P(2)];

%中点 Bresenham 算法扫描转换
dx = Q(1) - P(1);  dy = Q(2) - P(2);
d = dx - 2*dy;  % 计算中点
for i = 2:n
    pixs_line(i,1) = P(1) + i - 1;
    if d < 0
        pixs_line(i,2) = pixs_line(i-1,2) + 1;
        d = d + 2*dx - 2*dy;
    else 
        pixs_line(i,2) = pixs_line(i-1,2);
        d = d - 2*dy;
    end
end

% k 的绝对值大于1时的特殊处理
if abs(Q(2)-P(2)) > abs(Q(1)-P(1))
    pixs_line = fliplr(pixs_line);
end

这里写图片描述

圆形—中点Bresenham算法

中点Bresenham画圆算法的主要想法,仍然是构造判别式,然后从起始点开始,依次代入邻近点的的像素中点,并根据判别式的值判定邻近点的归属。

下面列出中点 Bresenham 画圆算法的几个要点:

  • 构造判别式;
  • 记录一个误差项 di;
  • 建立递推式,分别针对取上、下两个像素的不同情形;
  • (运算过程的整数化,其它一些算法细节)

构造判别式

这里写图片描述

误差项 di

这里写图片描述

构造递推式

这里写图片描述

算法描述

  1. 输入圆的半径 R。
  2. 计算初始值d=1-R、x=0、y=R。
  3. 绘制点(x,y)及其在八分圆中的另外七个对称点。
  4. 判断d的符号。若d < 0,则先将d更新为d+2x+3,再将(x,y)更新为(x+1,y);否则先将d更新为d+2(x-y)+5,再将(x,y)更新为(x+1,y-1)。
  5. 当x < y时,重复步骤3和4。否则结束。

例题

这里写图片描述

这里写图片描述

function [X,Y]=Bresenhamcircle(x0,y0,r)
X=ones(1,1000);
Y=X;                                      %坐标向量,用于存储绘制的点的坐标
x1=X;x2=X;x3=X;x4=X;x5=X;x6=X;x7=X;x8=X;
y1=Y;y2=Y;y3=Y;y4=Y;y5=Y;y6=Y;y7=Y;y8=Y;  %将圆对称划分为8个部分,分别用xi,yi记录坐标
D=ones(1,1002);                           %判别向量
i=1;
x1(1)=x0;x2(1)=x0+r;x3(1)=x2(1);x4(1)=x0;x5(1)=x4(1);x6(1)=x0-r;x7(1)=x6(1);x8(1)=x1(1);
y1(1)=y0+r;y2(1)=y0;y3(1)=y2(1);y4(1)=y0-r;y5(1)=y4(1);y6(1)=y0;y7(1)=y6(1);y8(1)=y1(1);     %初始条件
xd=2^(1/2)/2*r+x0;
while x1(i)<xd
    i=i+1;
    x1(i)=x1(i-1)+1;y2(i)=y2(i-1)+1;y3(i)=y3(i-1)-1; x4(i)=x4(i-1)+1; x5(i)=x5(i-1)-1;y6(i)=y6(i-1)-1;y7(i)=y7(i-1)+1; x8(i)=x8(i-1)-1;         %计长方向总加1
    D(i)=2*(y1(i-1)-y0-(r^2-(x1(i)-x0)^2)^(1/2))-1;
    if D(i)<0
        y1(i)=y1(i-1);x2(i)=x2(i-1);x3(i)=x3(i-1);y4(i)=y4(i-1);y5(i)=y5(i-1);x6(i)=x6(i-1);x7(i)=x7(i-1); y8(i)=y8(i-1);
    end
    if D(i)>=0
        y1(i)=y1(i-1)-1;x2(i)=x2(i-1)-1;x3(i)=x3(i-1)-1;y4(i)=y4(i-1)+1;y5(i)=y5(i-1)+1;x6(i)=x6(i-1)+1;x7(i)=x7(i-1)+1; y8(i)=y8(i-1)-1;
    end
end
X(1:i)=x1(1:i);X(i+1:2*i)=x2(1:i);X(2*i+1:3*i)=x3(1:i);X(3*i+1:4*i)=x4(1:i);X(4*i+1:5*i)=x5(1:i);X(5*i+1:6*i)=x6(1:i);X(6*i+1:7*i)=x7(1:i);X(7*i+1:8*i)=x8(1:i);
Y(1:i)=y1(1:i);Y(i+1:2*i)=y2(1:i);Y(2*i+1:3*i)=y3(1:i);Y(3*i+1:4*i)=y4(1:i);Y(4*i+1:5*i)=y5(1:i);Y(5*i+1:6*i)=y6(1:i);Y(6*i+1:7*i)=y7(1:i);Y(7*i+1:8*i)=y8(1:i);
X=X(1:8*i);Y=Y(1:8*i);
a=0:pi/2000:2*pi;
x=x0+r*cos(a);
y=y0+r*sin(a);
plot(x,y,'k');
legend('实际图像');hold on;
plot(X,Y,'r.');
hold off;
end

这里写图片描述

版权声明:本文为soulmeetliang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/soulmeetliang/article/details/79177920

智能推荐

计算机图形学-基于OpenGL的直线段的裁剪算法

计算机图形学-基于OpenGL的直线段的裁剪算法 在Opengl应用框架下实现C-S裁剪算法或L-B裁剪算法。完成一个四边形对两条线段的裁剪:四边形的左上角和右下角顶点分别为(100,100),(300,200),线段1的两个端点为(150,50),(250,150)。集成开发环境为vs2013。 实验代码-Cohen-Sutherland裁剪算法 效果预览...

Mybatis源码的下载,搭建以及阅读源码的姿势

源码下载 mybatis的源码是在github上开源的,所以直接从github上搜索下载即可。 如上图,第一个就是mybatis3的源码项目,下面几个也是项目中常用的依赖项目,分页插件pagehelper,SSM项目需要引入的依赖mybatis-spring,mybatis-plus项目等。 当前最新版本是v3.5.5,可以选择合适的版本下载。我本地选择的是v3.5.4版本,小版本之间没有太大差异...

spring cloud + redis RedisTemplate Api搭建简单Demo

简介 Redis是一种NoSQL数据库,即非关系型数据库。redis是一个key-value存储系统。它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,r...

c++在windows、linux下获取指定文件夹下所有文件名的方法

一般来说,获取指定文件夹下的所有文件名,用python是较为方便的,直接: import os files_name = os.listdir(“一个路径”) 但也有c++程序偶尔也有这个需求,下面就直接上c++在windows和linux去读取文件夹下文件名的方法,不同的系统代码上有一些差别 Windows(vs) vs的环境,主要是用到了头文件<io.h>,...

计算机图形学实验一绘制任意斜率的直线段

一、实验目的 (1)掌握任意斜率直线段的重点 Bresenham 扫描转换算法; (2)掌握 Cline 直线类的设计方法; (3)掌握状态栏编程方法。 二、实验步骤 (1)创建MFC应用程序 (2)定义CLine类   添加消息处理的处理程序   三、实验结果   四、实验体会 在本次实验中,通过不断的探索和实践,我学会了如何创建一个MFC应用程序,将理论运用于实践...

猜你喜欢

CSS盒模型

盒子模型 盒子模型是什么 CSS盒子模型就是在CSS技术所使用的一种思维模型。CSS假定所有的HTML文档元素都生成一个描述该元素在HTML文档布局中所占空间的矩形元素框,可以形象地将其看作是一个盒子。通过定义一系列与盒子相关的属性,可极大地丰富和促进各个盒子乃至整个HTML文档的表现效果和布局结构。CSS盒子模型由内容区、填充、边框和空白边四部分组成。内容区是盒子模型的中心,呈现盒子的主要信息内...

通用分页

通用分页 我们从数据库里面拿到的数据要进行分页首先需要连接到数据库 这些类是不能少的;这是获得数据库对象的类 pageBean 首先我们需要把想要分页的属性进行一个封装,一个分页的工具类 BookDao 然后我们需要一个dao方法 ,就以BookDao 为案列 我们需要继承baseDao通用dao方法进行一个分页实现(BaseDao在后面) BaseDao 这个是通用的dao方法 实体类进行分页实...

VS2013调试X64平台时出现MSVSMON.EXE failed to start的问题

1.问题 vs2013突然有一天调试X64平台程序时出现“Visual Studio Remote Debugging Monitor(MSVSMON.EXE)failed to start”的问题,如下图所示。如果切换为X86平台可以编译通过。网上搜了好多方法都没有解决问题。              ...

HTTP与HTTPS的区别

原创 天才程序YUAN 最后发布于2020-03-22 00:00:29 阅读数 886 收藏 发布于2020-03-22 00:00:29 分类专栏: 实习 收起 《计算机网络自顶向下方法》学习专栏 涵盖《计算机网络自顶向下方法》的知识点,实验和经典习题。按内容可分为计算机网络概述、应用层、传输层、网络层和数据链路层。实验包括HTTP 代理服务器的设计与实现、GBN 协议的设计与实现、利用 Wi...

【Docker】win10上修改docker的镜像文件存储位置(九)- 通过WSL2修改

闲话少说 软件版本 window 10 v1909 小版本号 Docker Desktop Installer v20.10.0( 细致版本看下图) 安装过程所遇 官网下载的docker.exe直接安装即可,安装中间选项,直接安装的C盘下(C:\Program Files\Docker),由上面的docker info可看出,docker的默认路径(/var/lib/docker)跟linux一样...