中点画圆算法

       如同光栅画线算法,我们在每一个步中以单位间隔取样并确定离指定圆近期的像素位置。对于给定半径r和屏幕中心(xc,yc),能够先使用算法计算圆心在坐标原点(0,
0)的圆的像素位置,然后通过将xc加到x且yc加到y。从而把计算出的每一个位置(x,y)移动到其适当的屏幕位置。在第一象限中,圆弧段从x
= 0到x = y,曲线的斜率从0变化到-1.0。

因此,能够在该八分圆上的正x方向取单位步长。并使用决策參数来确定每一步两个可能的y位置中,哪一个更接近于圆的位置。然后,其它七个八分圆中的位置可由对称性得到。

为了应用中点画圆算法。我们定义一个圆函数:

半径为r的圆边界上不论什么一点(x, y)满足方程fcirc(x,y) = 0。假设点在圆的内部,则圆函数为负值;如果点在圆的外部,则圆函数为正值。总之。不论什么点(x, y)的相对位置可由圆函数的符号来决定:

(3.30)式中的圆函数在每一个取样步上对接近圆周的两个像素的中点进行測试。

因此,在中点算法中圆函数是决策參数,而且能够类似画线算法为这个函数设置增量运算。

图3.19给出了取样位置xk+1上两个候选像素间的中点。

如果刚在(xk,yk)绘制了一个像素,下一步须要确定是像素位置(xk+1,yk)

还是(xk+1,yk-1)更接近于圆。

我们的决策參数是圆函数方程(3.29 )在这两个像素的中点求值而得到的:

 

假如pk < 0。那么这个中点位于圆内。扫描线yk上的像素接近于圆周边界。否则,中点位于圆外或在圆周边界上。我们选择扫描线yk-1的像素。

兴许的决策參数能够使用增量运算得到。我们对取样位置xk+1= xk+2处的圆函数求值。能够得到下一个决策參数的循环表达式:

当中。yk+1是yk或是yk-1,取决于pk的符号。

为了得到pk+1增量可能是2xk+1+1(假设pk为负)或是2xk+1+1-2yk+1

和2yk+1的求值也能够通过增量的方式进行,即

在起始位置(0, r)处。这两个项的值分别为0和2r 。

2xk+1项的每一个兴许值能够通过对前一值加2或是对2yk+1的前一值减2而得到。

对圆函数在起始位置(x0,y0) = (0,r)处求值,就能够得到初始决策參数:

假如将半径r指定为整数,就能够对p0进行简单的取整:

由于全部的增量都是整数。

如果以整数屏幕坐标指定圆參数,那么如同Bresenham画线算法中一样。中点方法使用整数加减来计算沿圆周的像素位置。我们可将中点画圆算法的步骤概括例如以下:

中点画圆算法的步骤

1.输入圆半径r和圆心(xc,yc),并得到圆周(圆心在原点)上的第一个点:

2.计算决策參数的初始值:

3.在每一个xk位置,从k = 0開始,完毕下列測试:假如pk
< 0。圆心在(0, 0)的圆的下一个点为(xk+1,yk)而且

否则,圆的下一个点是(xk+1,yk-1)。而且

当中2xk+1= 2xk+2且2yk+1= 2yk-2。

4.确定在其它七个八分圆中的对称点。

5.将每一个计算出的像素位置移动到圆心在(xc,yc)的圆路径上,并画坐标值:

6.反复步骤3到步骤5,直至x >= y。





例3.2使用中点画圆算法绘图

给定圆半径r = 10,我们将演示中点画圆算法。确定在第一象限从x = 0到x = y沿八分圆的像素位置。决策參数的初始值为

对于中心在坐标原点的圆,初始点(x0,y0) = (0,10),计算决策參数的初始增量项:

使用中点画圆算法计算的后继决策參数值和沿圆路径的位置为

下列程序段给出了用于实现中点画圆算法的过程。半径值和圆心坐标传递给过程circleMidpoint。

然后计算第一个八分圆上的一个像素位置并传递给过程circlePlotPoints。该过程通过重复调用setPixel函数在帧缓存中该像素及与其对称的全部像素位置来设定圆的颜色,setPixel由OpenGL画点函数实现。

#include "stdafx.h"
#include "GL/glut.h"
#include "stdlib.h"
#include "math.h"
#include "iostream"
using namespace std; const GLdouble twoPi = 6.283185; GLsizei winWidth = 400, winHeight = 300; // 屏幕显示宽高.
class screenPt {
public:
screenPt(){
x = y = 0;
}
GLint x, y; void setCoords(GLint xCoordValue, GLint yCorrdValue){
x = xCoordValue;
y = yCorrdValue;
}
GLint getx() const{
return x;
}
GLint gety() const{
return y;
}
void incrementx(){
x++;
}
void incrementy(){
y--;
}
}; void init( )
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 200.0, 0.0, 150.0);
} void setPixel(GLint xCoord, GLint yCoord){
glBegin(GL_POINTS);
glVertex2i(xCoord, yCoord);
glEnd();
} void circleMidpoint(GLint xc, GLint yc, GLint radius){
screenPt circPt;
GLint p = 1 - radius;//中点參数初值
circPt.setCoords(0, radius);//Set coords for top point of circle
void circlePlotPoints(GLint, GLint, screenPt);
/*Plot the initial point in each circle quadrant*/
circlePlotPoints(xc, yc, circPt);
/*Calculate next point and plot in each octant*/
while (circPt.getx() < circPt.gety()){
circPt.incrementx();
if (p < 0)
p += 2 * circPt.getx() + 1;
else{
circPt.incrementy();
p += 2 * (circPt.getx() - circPt.gety()) + 1;
}
circlePlotPoints(xc, yc, circPt);
}
} void circlePlotPoints(GLint xc, GLint yc, screenPt circPt)
{
setPixel(xc + circPt.getx(), yc + circPt.gety());
setPixel(xc - circPt.getx(), yc + circPt.gety());
setPixel(xc + circPt.getx(), yc - circPt.gety());
setPixel(xc - circPt.getx(), yc - circPt.gety());
setPixel(xc + circPt.gety(), yc + circPt.getx());
setPixel(xc - circPt.gety(), yc + circPt.getx());
setPixel(xc + circPt.gety(), yc - circPt.getx());
setPixel(xc - circPt.gety(), yc - circPt.getx());
} void pieChart( )
{
screenPt circCtr, piePt;
GLint radius = winWidth / 4; // Circle radius.
circCtr.x = winWidth / 2; // Circle center position.
circCtr.y = winHeight / 2;
circleMidpoint(circCtr.x, circCtr.y, radius); // 调用中点画圆方法
} void displayFcn( )
{
glClear(GL_COLOR_BUFFER_BIT); // Clear display window.
glColor3f(0.0, 0.0, 1.0); // Set circle color to blue.
pieChart();
glFlush();
} void winReshpeFcn(GLint newWidth, GLint newHeight)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, GLdouble(newWidth), 0.0, GLdouble(newHeight));
glClear(GL_COLOR_BUFFER_BIT);
/* Reset display-window size parameters. */
winWidth = newWidth;
winHeight = newHeight;
}
int _tmain(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(winWidth, winHeight);
glutCreateWindow("Pie Chart");
init();
glutDisplayFunc(displayFcn);
glutReshapeFunc(winReshpeFcn);
glutMainLoop();
}

计算机图形学(二)输出图元_6_OpenGL曲线函数_2_中点画圆算法的更多相关文章

  1. 计算机图形学之扫描转换直线-DDA,Bresenham,中点画线算法

    1.DDA算法 DDA(Digital Differential Analyer):数字微分法 DDA算法思想:增量思想 公式推导: 效率:采用了浮点加法和浮点显示是需要取整 代码: void lin ...

  2. 计算机图形学DDA画线法+中点画线法+Bresenham画线法

    #include <cstdio> #include <cstring> #include <conio.h> #include <graphics.h> ...

  3. 计算机图形学:贝塞尔曲线(Bezier Curve)

    计算机图形学:贝塞尔曲线(Bezier Curve) 贝塞尔能由贝塞尔样条组合而成,也可产生更高维的贝塞尔曲面.

  4. [计算机图形学] 基于C#窗口的Bresenham直线扫描算法、种子填充法、扫描线填充法模拟软件设计(二)

    上一节链接:http://www.cnblogs.com/zjutlitao/p/4116783.html 前言: 在上一节中我们已经大致介绍了该软件的是什么.可以干什么以及界面的大致样子.此外还详细 ...

  5. 计算机图形学学习方法和相关书籍,做游戏,GIS,虚拟现实,三维引擎的都能够看看.

    本书參照<<图形学扫盲>> 整理的,原文内容引子: http://www.cppblog.com/lai3d/archive/2008/12/30/70796.html 前言: ...

  6. [图形学] 计算机图形学 with OpenGL开篇

    <计算机图形学>(第四版)正在学习中,学习目的是为了在Unity中使用shader实现不同的渲染效果. 希望在这里能把学习过程中学到的知识和遇到的问题记录下来. 工作环境是:Xcode 8 ...

  7. 学习shader之前必须知道的东西之计算机图形学-渲染管线

    引言 shader到底是干什么用的?shader的工作原理是什么? 其实当我们对这个问题还很懵懂的时候,就已经开始急不可耐的要四处搜寻有关shader的资料,恨不得立刻上手写一个出来.但看了一些资料甚 ...

  8. 学习shader之前必须知道的东西之计算机图形学(一)渲染管线

    引言 shader到底是干什么用的?shader的工作原理是什么? 其实当我们对这个问题还很懵懂的时候,就已经开始急不可耐的要四处搜寻有关shader的资料,恨不得立刻上手写一个出来.但看了一些资料甚 ...

  9. 计算机图形学 opengl版本 第三版------胡事民 第三章更多的绘图工具

    opengl  计算机图形学 第三版   第二部分   第三章更多的绘图工具 3.1   概述 第2章中  我们绘图使用的是屏幕窗口的基础坐标系    以像素为单位 屏幕坐标从左下角x从0延伸到scr ...

随机推荐

  1. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛 B题 跳一跳,很简单的(字符串Hash + 树上路径倍增)

    题目链接  2018广东工业大学校赛  Problem B 考虑到每条边的权值变化$26$个时刻之后一定会回到原来的状态. 那么预处理出前$26$个时刻每棵树的形态,对每棵树做一遍字符串哈希. 查询的 ...

  2. c++ —— .bat 对拍

    #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #i ...

  3. [Luogu1429]平面最近点对(加强版)

    题目大意: 平面最近点对. 思路: 分治. 首先将所有点排序 每次把当前区间分为两半,递归求解两个区间内部的情况,然后枚举区间两边的点. #include<cmath> #include& ...

  4. 导出/导入Eclipse的workspace配置(备份Eclipse配置)

    设置好workspace配置后可以将配置保存为 *.epf 文件. 进入 File -> Export : 选择 General -> Preferences ,下一步: 选择 Expor ...

  5. Android 使用SQLite本地数据库

    参考:http://blog.csdn.net/jianghuiquan/article/details/8569252 在Android平台上,集成了一个嵌入式关系型数据库—SQLite.以SQLi ...

  6. [置顶] kubernetes--优雅删除资源对象

    当用户请求删除含有pod的资源对象时(如RC.deployment等),K8S为了让应用程序优雅关闭(即让应用程序完成正在处理的请求后,再关闭软件),K8S提供两种信息通知: 1).默认:K8S通知n ...

  7. Java算法题:兔子问题

    题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第四个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少? 解题思路: public int exp(int ...

  8. ElasticSearch的内存设置

    编辑ElasticSearch中bin目录下 vi elasticsearch中 加上   export ES_HEAP_SIZE=24g 修改配置文件 config/elasticsearch.ya ...

  9. linux的chown命令

    chown将指定文件的拥有者改为指定的用户或组,用户可以是用户名或者用户ID:组可以是组名或者组ID:文件是以空格分开的要改变权限的文件列表,支持通配符.系统管理员经常使用chown命令,在将文件拷贝 ...

  10. 简单的图片处理servlet

    好久没写博客了.近期做了一个比較有趣的商城项目,里面的业务还真的非常复杂,好在做了特殊的处理之后商城也能正常的使用了. 可是没中不足的就是图片目录和项目掺杂在一块,实在有些难以维护.之后找了点资料就搞 ...