计算机图形学实验二——二维图形几何变换及裁剪

Posted 大灬白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机图形学实验二——二维图形几何变换及裁剪相关的知识,希望对你有一定的参考价值。

【实验名称】 二维图形几何变换及裁剪
【实验目的】
1. 通过实验,进一步理解和掌握二维几何图形的基本变换及复合变换的原理;
2. 理解和掌握cohen-sutherland裁剪算法的基本思想。
【实验原理】
1.平移变换、旋转变换、比例变换、对称变换的变换矩阵;
绕任意点旋转、相对任意点缩放的变换矩阵;
相对于任意参考点(xF,yF)的二维几何变换,基本思路是,将图形经过平移,使参考点与原点重合,此时相对于参考点的变换变成相对于原点的基本几何变换,最后再平移,使参考点回到原来的位置。
(1)相对于(xF,yF)点的比例变换,变换矩阵如下:

(2) 相对于(xF,yF)点的旋转变换,变换矩阵如下:

2.Cohen-Sutherland端点编码算法
(1)若线段P1P2两端点的四位编码均为0,则两端点均在窗口内,该线段完全可见,显示该线段,算法结束;
(2) 若线段P1P2两端点的四位编码按位“与”结果为非0,则该线段完全不可见,算法结束。
(3)若线段两端点的四位编码按位“与”结果为0, 找到P1P2在窗口外的一个端点P1(或P2),用窗口相应的边与P1P2的交点取代该端点P1(或P2), 返回(1)步。
【实验内容】
1.显示一个飞机:(飞机各顶点的坐标存放在数组中)
(1)按比例缩小或放大.缩放比例由键盘输入,缩放的参考点由用户确定;

#include <graphics.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
//f[20][2]中存放的是飞机的关键点
Int f[15][2] = 
{285,70,310,100,310,185,430,240,440,260,310,225,310,355,345,400,225,400,260,355,260,225,130,260,140,240,260,185,260,100};
int b;
float k;
int n = 15;
int a[15][2];
void DDALine( int x0,int y0,int x1,int y1 )
{
    //DDA画直线算法
	int dx,dy,epsl,k;
	float x,y,xIncre,yIncre;
	dx = x1 - x0;
	dy = y1 - y0;
	x = x0;
	y = y0;
	if( abs(dx) > abs(dy) )
        epsl = abs(dx);
    else
        epsl = abs(dy);
	xIncre = (float)dx / (float)epsl;
	yIncre = (float)dy / (float)epsl;
	for( k = 0; k <= epsl; k++ )
	{
		putpixel((int)(x+0.5),(int)(y+0.5),GREEN);
		x += xIncre;
		y += yIncre;
	}
 
}
void Draw()
{
	int i,j,p,q;
	int gdriver = DETECT,gmode;
    printf("请输入参考点(X,Y):\\n");
	scanf("%d %d",&p,&q);
	printf( "请输入放大倍数(缩小0.5倍也是可以的):" );
	scanf( "%f",&k );
    for( i = 0; i < n; i++ )
	{
	    //a[i][0]中存的是x
	    //a[i][1]中存的是y
	    a[i][0] = ((f[i][0] - p) * k) + p;
	    a[i][1] = ((f[i][1] - q) * k) + q;
    }
	initgraph( 960,540 );
	for( j = 0; j < 1000; j++ )
		for( i = 0; i < 1000; i++ )
            putpixel( i,j,WHITE );//首先生成一个960*540大小的窗口,并置成白色
	for( i = 0; i < n - 1; i++ )
        //DDA画直线,首先将飞机的点顺时针按序连成线
		DDALine( a[i][0],a[i][1],a[i+1][0],a[i+1][1] );
	DDALine( a[0][0],a[0][1],a[n-1][0],a[n-1][1] );
}

void change()
{
	int i,j,k,s,dx,dy,temp;
	int x0,y0,x1,y1,x2,y2;
	for( i = 0; i < n; i++ )
	{
		if( i == n - 1 )
		{
			x0 = a[i][0];
			y0 = a[i][1];
			x1 = a[0][0];
			y1 = a[0][1];
		}
		else
		{
			x0 = a[i][0];
			y0 = a[i][1];
			x1 = a[i+1][0];
			y1 = a[i+1][1];
		}
		dx = x0 - x1;
		dy = y0 - y1;
		if( y0 > y1 )
		{
			temp = x0;
              x0 = x1;
			  x1 = temp;
            temp = y0;
			  y0 = y1;
			  y1 = temp;
		}
		for( j = y0; j < y1; j++ )
		{
			s = int( (j - y0) * dx / dy ) + x0;//求交点坐标
			for( k = s; k < 1000; k++ )
			{
					if( getpixel( k,j ) == WHITE )
                        putpixel( k,j,BLACK);
					else if( getpixel(k,j) == BLACK)
					    putpixel( k,j,WHITE );
					else
					    putpixel( k,j,GREEN);
			}
       }
	}
}
 
 
int main()
{
	Draw();
	change();
	getch();
	return 0;
}

运行截图:

(2)旋转.由键盘输入旋转角度和旋转中心;

#include <graphics.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
//f[20][2]中存放的是飞机的关键点
int f[15][2] = 
{285,70,310,100,310,185,430,240,440,260,310,225,310,355,345,400,225,400,260,355,260,225,130,260,140,240,260,185,260,100};
int b;
float k;
int n = 15;
int a[15][2];
void DDALine( int x0,int y0,int x1,int y1 )
{
    //DDA画直线算法
	int dx,dy,epsl,k;
	float x,y,xIncre,yIncre;
	dx = x1 - x0;
	dy = y1 - y0;
	x = x0;
	y = y0;
	if( abs(dx) > abs(dy) )
        epsl = abs(dx);
    else
        epsl = abs(dy);
	xIncre = (float)dx / (float)epsl;
	yIncre = (float)dy / (float)epsl;
	for( k = 0; k <= epsl; k++ )
	{
		putpixel((int)(x+0.5),(int)(y+0.5),GREEN);
		x += xIncre;
		y += yIncre;
	}
 
}
void Rotate()
{
	int i,j,d,p,q;
	int gdriver = DETECT,gmode;
    printf("请输入旋转度数:");
	scanf("%d",&d);
	printf("\\n请输入旋转中心:");
	scanf("%d %d",&p,&q);
       	for( i = 0; i < n; i++ )
	{
	    //a[i][0]中存的是x
	    //a[i][1]中存的是y
	    a[i][0] = (f[i][0] - p) * cos(d*1.0) - (f[i][1] - q) * sin(d*1.0) + p;
	    a[i][1] = (f[i][0] - p) * sin(d*1.0) + (f[i][1] - q) * cos(d*1.0) + q;
    }
	initgraph( 960,540 );
	for( j = 0; j < 1000; j++ )
		for( i = 0; i < 1000; i++ )
            putpixel( i,j,WHITE );//首先生成一个960*540大小的窗口,并置成白色
	for( i = 0; i < n - 1; i++ )
        //DDA画直线,首先将飞机的点顺时针按序连成线
		DDALine( a[i][0],a[i][1],a[i+1][0],a[i+1][1] );
	DDALine( a[0][0],a[0][1],a[n-1][0],a[n-1][1] );
}
 


void change()
{
	int i,j,k,s,dx,dy,temp;
	int x0,y0,x1,y1,x2,y2;
	for( i = 0; i < n; i++ )
	{
		if( i == n - 1 )
		{
			x0 = a[i][0];
			y0 = a[i][1];
			x1 = a[0][0];
			y1 = a[0][1];
		}
		else
		{
			x0 = a[i][0];
			y0 = a[i][1];
			x1 = a[i+1][0];
			y1 = a[i+1][1];
		}
		dx = x0 - x1;
		dy = y0 - y1;
		if( y0 > y1 )
		{
			temp = x0;
              x0 = x1;
			  x1 = temp;
            temp = y0;
			  y0 = y1;
			  y1 = temp;
		}
		for( j = y0; j < y1; j++ )
		{
			s = int( (j - y0) * dx / dy ) + x0;//求交点坐标
			for( k = s; k < 1000; k++ )
			{
					if( getpixel( k,j ) == WHITE )
                        putpixel( k,j,BLACK);
					else if( getpixel(k,j) == BLACK)
					    putpixel( k,j,WHITE );
					else
					    putpixel( k,j,GREEN);
			}
       }
	}
}
 
 
int main()
{
	Rotate();
	change();
	getch();
	return 0;
}

运行截图:

2.编码实现Cohen-Sutherland端点编码算法(用矩形窗口裁剪一条直线段)
(选做)关于任意一条水平线(或垂直线)对称
(选做) 任意画出一个多边形,由用户确定一个矩形裁剪窗口的位置和大小,保留窗口里的图形,抹去其余部分;

#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#define LEFT 1//0001
#define RIGHT 2//0010
#define BOTTOM 4//0100
#define TOP 8//1000
int XL = 100,XR = 400,YB =300,YT = 100;
int encode(int x,int y)
{ 
     int c=0;
	 if(x<XL) c=c|LEFT;
	 else if(x>XR) c=c|RIGHT;
	 if(y>YB) c=c|BOTTOM;
	 else if(y<YT) c=c|TOP;
	 return c;
}
 
// 使用中点算法画任意斜率的直线(包括起始点,不包括终止点)
void DisplayLine(int x1, int y1, int x2, int y2, int color)
{
	int x = x1, y = y1;
	int a = y1 - y2, b = x2 - x1;//a,b分别为x和y的增量
	//考虑四种情况,分别计算增量
	int cx = (b >= 0 ? 1 : (b = -b, -1));
	int cy = (a <= 0 ? 1 : (a = -a, -1));
 
	putpixel(x, y, color);
 
	int d, d1, d2;
	if (-a <= b

以上是关于计算机图形学实验二——二维图形几何变换及裁剪的主要内容,如果未能解决你的问题,请参考以下文章

计算机图形学 开源的库都有哪些,主要用于二维

WPF的三维变换应用

图形学计算机图形学知识点提纲3

opengl算法学习---消隐

shader入门,图形学心得

opengl算法学习---图形几何变换