計算機圖形學實驗(三) 梁友棟-Barskey線段裁剪和多邊形裁剪算法實現

梁友棟-Barskey裁剪算法

直接上代碼吧:

// ConsoleApplication2.cpp: 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include<gl/GLUT.H>
#include<cmath>
#include<iostream>
#include"node.h"
using namespace std;
void Initial(void)//初始化函數 
{
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//白色背景,前3個是RGB,最後是Alpha值,用來控制透明,1.0表示完全不透明
	glMatrixMode(GL_MODELVIEW);//OpenGL按照三維方式來處理圖像,所以需要一個投影變換將三維圖形投影到顯示器的二維空間中
	glLoadIdentity();
	gluOrtho2D(0.0, 400, 0.0, 400.0);//指定使用正投影將一個x座標在0~200,y座標0~150範圍內的矩形座標區域投影到顯示器窗口

}
bool ClipT(float p, float q, float *u1, float *u2)
{
	float r;
	if (p < 0)
	{
		r = q / p;
		
		if (r > *u2)
			return false;
		if (r > *u1)
			* u1 = r;
	}
	else if (p > 0)
	{
		r = q / p;
		if (r < *u1)
			return false;
		if (r < *u2)
			*u2 = r;
	}
	else
		return (q >= 0);
	return true;
}
void LB_LineClip(float x1, float y1, float x2, float y2, float XL, float XR, float YB, float YT)
{
	float dx, dy, u1, u2;
	 u1 = 0, u2 = 1;
	dx = x2 - x1;
	dy = y2 - y1;
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色  
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 0.0, 0.0);
	glViewport(0, 0, 400, 400);
	glBegin(GL_LINES);
	glVertex2f(x1, y1);
	glVertex2f(x2, y2);
	glEnd();
	//glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色   
	//glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 1.0, 1.0);
	glViewport(0, 0, 400, 400);
	glBegin(GL_LINES);
	glVertex2f(XL,YB);
	glVertex2f(XL,YT);
	glVertex2f(XL,YT);
	glVertex2f(XR,YT);
	glVertex2f(XR, YT);
	glVertex2f(XR, YB);
	glVertex2f(XL, YB);
	glVertex2f(XR, YB);
	if (ClipT(-dx, x1 - XL, &u1, &u2))
		if (ClipT(dx, XR - x1, &u1, &u2))
			if (ClipT(-dy, y1 - YB, &u1, &u2))
				if (ClipT(dy, YT - y1, &u1, &u2))
				{

					glVertex2f(x1 + u1 * dx, y1 + u1 * dy);
					glVertex2f(x1 + u2 * dx, y1 + u2 * dy);
					

				}
	glEnd();
	glFlush();
}
node* Sutherland(node *m1, node *m2, side ClipBoundary, int Inlength, int &Outlength)
{
	node S, P, ip;
	int j;
	Outlength = 0;
	S = m1[Inlength - 1];
	for (j = 0; j < Inlength; j++)
	{
		P = m1[j];
		if (Inside(P, ClipBoundary))
		{
			if (Inside(S, ClipBoundary))
				Output(P, Outlength, m2);
			else
			{
				Intersect(S, P, ClipBoundary, ip);
				Output(ip, Outlength, m2);
				Output(P, Outlength, m2);
			}
		}
		else if (Inside(S, ClipBoundary))
		{
			Intersect(S, P, ClipBoundary, ip);
			Output(ip, Outlength, m2);
		}
		S = P;
	}

	return m2;
}
void drawFront(node m1[],node m2[],int length1,int length2)
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色   
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 1.0, 0.0);
	glViewport(0, 0, 400, 400);
	glBegin(GL_LINES);
	for (int i = 0; i < length1 - 1; i++)
	{
		glVertex2d(m1[i].x, m1[i].y);
		glVertex2d(m1[i+1].x, m1[i+1].y);
	}
	glVertex2d(m1[length1-1].x, m1[length1-1].y);
	glVertex2d(m1[0].x, m1[0].y);
	glEnd();
	glColor3f(0.0, 1.0, 0.0);
	glBegin(GL_LINES);
	for (int i = 0; i < length2 - 1; i++)
	{
		glVertex2d(m2[i].x, m2[i].y);
		glVertex2d(m2[i + 1].x, m2[i + 1].y);
	}
	glVertex2d(m2[length2 - 1].x, m2[length2 - 1].y);
	glVertex2d(m2[0].x, m2[0].y);

	glEnd();
	glFlush();
}
void drawBack()
{
	
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色   
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 1.0, 0.0);	
	glViewport(0, 0, 400, 400);
	glBegin(GL_LINES);
	node *m1=new node[100],*m2=new node[100],*r1=new node[100],*r2=new node[100],*r3=new node[100],*r4=new node[100];
	node n1(100, 100), n2(100, 200), n3(200, 200), n4(200, 100), n5(50, 150), n6(150, 220),n7(150,150);
    node ploy[3] = { n5,n6,n7};
	side s1(n2, n1), s2(n1, n4), s3(n4, n3), s4(n3, n2);
	m1 = &ploy[0];
	int nodeNum = 0;
	r1=Sutherland(m1,m2,s1,3,nodeNum);//用第一條邊裁剪剩下的圖形
	m2 = new node();
	r2 = Sutherland(r1, m2, s2, nodeNum, nodeNum);//用第二條邊裁剪剩下的圖形
	m2 = new node();
	r3 = Sutherland(r2, m2, s3, nodeNum, nodeNum); //用第三條邊裁剪剩下的
	m2 = new node();
	r4 = Sutherland(r3, m2, s4, nodeNum, nodeNum);//最後一條邊裁剪後剩下的
	//r1 = r2 = r3 = m1=r4=NULL;
	//delete r1, r2, r3, m1,r4;
	for (int i = 0; i < nodeNum - 1; i++)//畫出被裁減後的圖形
	{  
		glVertex2d(m2[i].x, m2[i].y);
		glVertex2d(m2[i + 1].x, m2[i + 1].y);
	}
	glVertex2d(m2[nodeNum - 1].x, m2[nodeNum - 1].y);
	glVertex2d(m2[0].x, m2[0].y);
	//glVertex2d(100, 200);
	//glVertex2d(200, 300);
	//cout << m2[0].x << " " << m2[0].y;
	glEnd();
	glFlush();
	
}
node *nn = new node[100];
int nodeNumber = 0;
void draw()
{
	node n1(100, 100), n2(100, 200), n3(200, 200), n4(200, 100), n5(50, 150), n6(150, 220), n7(150, 150);
	node ploy[3] = { n5,n6,n7 };
	node ploy2[4] = { n1,n2,n3,n4 };
	drawFront(ploy,ploy2,3,4);
	
	/*result=Bezier(nodeNumber,&nn[0]);
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色   
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 1.0, 0.0);
	glViewport(0, 0, 400, 400);
	 glBegin(GL_POINTS);
	for (int i = 0; i < 100; i++)
	{  
		glVertex2f(result[i].x, result[i].y);
		
		//cout <<result[i].x<<" "<<result[i].y<<"\n";
	}
	//result = NULL;
	//delete result;
	glEnd();
	glColor3f(0.0, 1.0, 1.0);
	glViewport(0, 0, 400, 400);
	glBegin(GL_LINES);
	for (int i = 0; i < nodeNumber-1; i++)
	{
		glVertex2f(nn[i].x, nn[i].y);
		glVertex2f(nn[i+1].x, nn[i+1].y);
	}
	glEnd();
	glFlush();*/

}
//鼠標響應函數
void mouseClick(int btn, int state, int x, int y)
{
	
	if (btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
	node temp(x, 400-y);
	nn[nodeNumber] = temp;
	nodeNumber++;
	glColor3f(0.0, 1.0, 1.0);
	glViewport(0, 0, 400, 400);
	glBegin(GL_POINTS);
	glVertex2d(x,400-y);
	glEnd();
	glFlush();
	}
	if (btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN) 
	{
		node *result = new node[1000];
		//drawFront(ploy,ploy2,3,4);

		result = Bezier(nodeNumber, nn);
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色   
		//glClear(GL_COLOR_BUFFER_BIT);
		glColor3f(1.0, 1.0, 0.0);
		glViewport(0, 0, 400, 400);
		glBegin(GL_POINTS);
		for (int i = 0; i < 1000; i++)
		{
			glVertex2f(result[i].x, result[i].y);

			//cout <<result[i].x<<" "<<result[i].y<<"\n";
		}
		//result = NULL;
		//delete result;
		glEnd();
		glColor3f(0.0, 1.0, 1.0);
		glViewport(0, 0, 400, 400);
		glBegin(GL_LINES);
		for (int i = 0; i < nodeNumber - 1; i++)
		{
			glVertex2f(nn[i].x, nn[i].y);
			glVertex2f(nn[i + 1].x, nn[i + 1].y);
		}
		//result = NULL;
		nn = NULL;
		nn = new node[100];
		nodeNumber = 0;
		glEnd();
		glFlush();
		

	}
}
//鼠標移動函數
void display()
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//繪圖顏色爲黑色   
    //glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 0.0);
	glViewport(0, 0, 400, 400);
	LB_LineClip(50, 150, 200, 250, 100, 300, 20, 200);
}
int main(int argc, char * argv[])//這是使用glut庫函數進行窗口管理
{
	glutInit(&argc, argv);//使用glut庫需要進行初始化
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);//設定窗口顯示模式,顏色模型和緩存,這裏是RGB顏色模型和單緩存
	glutInitWindowPosition(100, 100);//設定窗口的初始位置,屏幕左上角爲原點,單位爲像素
	glutInitWindowSize(400, 400);//設定窗口的大小

	glutCreateWindow("裁剪線段圖形");//創建一個窗口,參數是窗口標題名 
	Initial();
	glutDisplayFunc(&display);//將myDisplay指定爲當前窗口的顯示內容函數*/
	
	glutCreateWindow("初始圖形");//創建一個窗口,參數是窗口標題名 
	Initial();
	glutDisplayFunc(&draw);//將myDisplay指定爲當前窗口的顯示內容函數*/

	glutCreateWindow("裁剪後的圖");//創建一個窗口,參數是窗口標題名 
	Initial();
	glutDisplayFunc(&drawBack);//將myDisplay指定爲當前窗口的顯示內容函數							 
	glutMainLoop();//使窗口框架運行起來,使顯示回調函數開始工作
	return 0;
}

加個有關函數的頭文件:
#pragma once
#pragma once
struct node//點結構 
{
	double x;
	double y;
	node()
	{
		x = 0.0;
		y = 0.0;
	}
	node(double xx, double yy)
	{
		x = xx;
		y = yy;
	}
	/*node & operator=(const node& a)
   {
		node m;
		m.x = a.x;
		m.y = a.y;
		return m;
    }*/
};

struct side//邊結構
{
	node a;
	node b;
	side(node aa, node bb)
	{
		a.x = aa.x;
		a.y = aa.y;
		b.y = bb.y;
		b.x = bb.x;
	}
	side(int n)
	{
		a.x = 0;
		a.y = 0;
		b.x = 0;
		b.y = 0;
	}
	side()
	{
		a.x = 0;
		a.y = 0;
		b.x = 0;
		b.y = 0;
	}
};

double sideYmax(side mside)
{
	if (mside.a.y < mside.b.y)
		return mside.b.y;
	else
		return mside.a.y;
}
bool Inside(node &TestPt, side ClipBoundray)
{
	if (ClipBoundray.b.x > ClipBoundray.a.x)//裁剪邊爲窗口下邊
	{
		if (TestPt.y >= ClipBoundray.a.y)
			return TRUE;
	}
	else if (ClipBoundray.b.x < ClipBoundray.a.x)//裁剪邊爲窗口下邊
	{
		if (TestPt.y <= ClipBoundray.a.y)
			return TRUE;
	}
	else if (ClipBoundray.b.y > ClipBoundray.a.y)
		{
			if (TestPt.x <= ClipBoundray.a.x)
				return TRUE;
		}
	else if (ClipBoundray.b.y < ClipBoundray.a.y)
		{
			if (TestPt.x >= ClipBoundray.a.x)
				return TRUE;
		}
		return FALSE;
}
void Intersect(node &S,node &P,side ClipBoundary,node &IntersectPt)//求兩條邊的交點
{
	if (ClipBoundary.a.y == ClipBoundary.b.y)
	{
		IntersectPt.y = ClipBoundary.a.y;
		IntersectPt.x = S.x + (ClipBoundary.a.y - S.y)*(P.x - S.x) / (P.y - S.y);
	}
	else
	{
		IntersectPt.x = ClipBoundary.a.x;
		IntersectPt.y = S.y + (ClipBoundary.a.x - S.x)*(P.y - S.y) / (P.x - S.x);
	}
}
void  Output(node P, int &Outlength, node *m2)
{
	m2[Outlength] = P;
	Outlength++;
}
node *Bnode(float t, int nodeNumber,node *n)//求出點集第幾次後的在t分段上的點
{

	node *temp=new node[nodeNumber-1];
	for (int i = 0; i < nodeNumber-1; i++)
	{
		temp[i].x = (1 - t)*n[i].x + t * n[i + 1].x;
		temp[i].y = (1 - t)*n[i].y + t * n[i + 1].y;
	}
	if (nodeNumber == 2)
		return temp;
	else
		return Bnode(t,nodeNumber-1,temp);
}
node * Bezier(int nodeNumber,node * n)
{
	float t = 0.0; int i = 0;
	node *result = new node[1000];
	for (t; t < 1; t = t + 0.001)
	{
		result[i].x = Bnode(t, nodeNumber, n)[0].x;
		result[i].y = Bnode(t, nodeNumber, n)[0].y;
		//result[i] = Bnode(t, nodeNumber, n)[0];
		i++;
		//cout << result[i].x << " " << result[i].y<<"\n";
	}
	return result;
}
顯示效果

圖形學裁剪

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章