国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【計算機圖形學 】掃描線多邊形填充算法 | OpenGL+鼠標交互

這篇具有很好參考價值的文章主要介紹了【計算機圖形學 】掃描線多邊形填充算法 | OpenGL+鼠標交互。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

其他計算機圖形學實驗

傳送門

前言

實現(xiàn)多邊形掃描線填充算法,并和鼠標進行交互。
具體原理略過,會貼上完整代碼,可直接運行。

環(huán)境:
vs2019,OpenGL的庫(可以搜索如何用vs使用OpenGL的庫,可以使用vs自帶的插件或者其他方法,很方便)

要點:
1.NET和AET的創(chuàng)建,改動
2.改變鼠標點擊和鼠標拖拽的響應事件。

最終效果:
用鼠標隨意畫頂點,然后展示填充過程
對應控制臺會輸出頂點坐標和個數(shù)
【計算機圖形學 】掃描線多邊形填充算法 | OpenGL+鼠標交互

思路借鑒

文章1
文章2

步驟

1.點的結構體

struct point
{
	float x, y;
	point(){}
	point(int xx, int yy):
		x(xx), y(yy) {}
};
vector<point> vertice; //頂點

2. AET 活性邊表、NET新邊表 的結構體

typedef struct XET
{
	float x;
	float dx;  // 從當前掃描線到下一條掃描線間x的增量,即斜率的倒數(shù)
	float ymax; //該邊所交的最高掃描線的坐標值ymax
	XET* next;
}AET, NET; //AET 活性邊表; NET新邊表

3. 掃描線算法實現(xiàn)

void PolyScan()
{
	/*得到最高點的y坐標*/
	int Max_Y = 0;
	for (int i = 0; i < vertice.size(); i++) 
		/*Max_Y = max(Max_Y, vertice[i].y);*/
		if (vertice[i].y > Max_Y)
			Max_Y = vertice[i].y;


	//初始化AET表
	AET* pAET = new AET;
	pAET->next = NULL;

	//初始化NET表
	NET* pNET[800]; //吊桶
	for (int i = 0; i <= Max_Y; i++)
	{
		pNET[i] = new NET;
		pNET[i]->next = NULL;;
	}

	//掃描并且建立NET表
	int len = vertice.size(); //頂點個數(shù)
	for (int i = 0; i <= Max_Y; i++)
	{
		for (int j = 0; j < len; j++) //掃描每個點
		{
			if (i == vertice[j].y)
			{
				//如果一個點和前一個點有一條邊相連,則該點和后面一個點也相連
				//!這個式子 便于最后一個頂點和第一個點相連 和 防止出現(xiàn)負數(shù)
				
				//判斷當前點的高低,使ymax、DX、DY的計算有變化
				if (vertice[(j - 1 + len) % len].y > vertice[j].y)
				{
					//前一個點在當前點的上方
					NET* p = new NET;
					p->x = vertice[j].x;
					p->ymax = vertice[(j - 1 + len) % len].y;//與當前掃描線相交的活性邊 的 最高點即為相鄰頂點的y
					float DX = vertice[(j - 1 + len) % len].x - vertice[j].x;
					float DY = vertice[(j - 1 + len) % len].y - vertice[j].y;
					p->dx = DX / DY;//dx為直線斜率的倒數(shù)
					p->next = pNET[i]->next;
					pNET[i]->next = p;
				}
				if (vertice[(j + 1) % len].y > vertice[j].y)
				{
					//后一個點在當前點的上方
					NET* p = new NET;
					p->x = vertice[j].x;
					p->ymax = vertice[(j + 1) % len].y;
					float DX = vertice[(j + 1) % len].x - vertice[j].x;
					float DY = vertice[(j + 1) % len].y - vertice[j].y;
					p->dx = DX / DY;//dx為直線斜率的倒數(shù)
					p->next = pNET[i]->next;
					pNET[i]->next = p;
				}
			}
		}
	}

	//建立并且更新活性邊表AET
	//各條掃描線i
	for (int i = 0; i <= Max_Y; i++)
	{
		/*把新邊表NET[i] 中的邊結點用插入排序法插入AET表,使之按x坐標遞增順序排列*/
		
		//計算每條掃描線上不同線產(chǎn)生的新的交點x,更新AET
		NET* p = pAET->next;
		while (p)
		{
			p->x = p->x + p->dx; //更新x坐標
			p = p->next;
		}

		//斷表排序,不再開辟空間 
		AET* tq = pAET;
		p = pAET->next;
		tq->next = NULL;
		while (p)//順著鏈表往下走
		{
			//找到第一個比它大的數(shù)字tq->next->next->x,則從p->next到tq->next都是比p->x小的
			while (tq->next != NULL && tq->next->x <= p->x)
				tq = tq->next;
			//插入p到tq和tq->next之間
			NET* t = p->next;
			p->next = tq->next;
			tq->next = p;
			p = t;

			tq = pAET;//回到頭
		}

		/*(改進算法) 取消求交,減少計算量*/
		//先從AET表中刪除ymax==i的結點****************************************/
		//像素的取舍問題,保證多邊形的“下閉上開”,避免填充擴大化(交點的個數(shù)應保證為偶數(shù)個)
		AET* q = pAET;
		p = q->next;
		while (p)
		{
			if (p->ymax == i)
			{
				q->next = p->next;
				delete p;
				p = q->next;
			}
			else
			{
				q = q->next;
				p = q->next;
			}
		}

		//若NET中有新點,將其用插入法插入AET,按x遞增的順序排列
		p = pNET[i]->next;
		q = pAET;
		while (p)
		{
			while (q->next && p->x >= q->next->x)
				q = q->next;
			//插入p
			NET* t = p->next;
			p->next = q->next;
			q->next = p;
			p = t;

			q = pAET;//回到頭
		}

		//配對后填充顏色
		p = pAET->next;
		while (p && p->next != NULL)
		{
			for (float j = p->x; j <= p->next->x; j++)
			{
				//掃描線畫點
				draw_a_point(j, i);
				//cout << "(" << j << ", " << i << ")" << endl;
			}
			p = p->next->next;//考慮端點情況
		}
	}
	glFlush();
}

4. 改變鼠標響應函數(shù)

void mymouse(int button, int state, int x, int y)
{
	//左鍵
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		draw_a_point(x, window_height - y);

		point p(x, window_height - y);
		vertice.push_back(p);
		cout << "頂點" << vertice.size() << ": (" << x << ", " << window_height - y << ")" << endl;
	}
	//右鍵
	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
	{
		glClearColor(1, 1, 1, 1);//設置繪制窗口顏色為白色
		glColor3f(0, 1, 1);

		//繪制多邊形
		glBegin(GL_LINES);	
		for (int i = 0; i < vertice.size(); i++)
		{
			if (i == vertice.size() - 1)//畫完最后一個點,使其閉合
			{
				glVertex2f(vertice[0].x, vertice[0].y);
				glVertex2f(vertice[i].x, vertice[i].y);
			}
			else
			{
				glVertex2f(vertice[i].x, vertice[i].y);
				glVertex2f(vertice[i + 1].x, vertice[i + 1].y);
			}
		}
		glEnd();
		glFlush();
	}

	//鼠標中間
	if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
	{
		//cout << "center: (" << x << ", " << y << ")" << endl;
		//BoundaryFill4(x, window_height - y);
		//BoundaryFill4_Stack(x, window_height - y);

		cout << "多邊形頂點個數(shù)為" << vertice.size() << "。 " << "開始掃描線填充。" << endl;
		PolyScan();
	}
}

完整代碼

//掃描線算法
#include<iostream>
#include<gl/glut.h>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
const int window_width = 800, window_height = 600;
const int maxn = 99999;

struct point
{
	float x, y;
	point(){}
	point(int xx, int yy):
		x(xx), y(yy) {}
};
vector<point> vertice; //頂點

typedef struct XET
{
	float x;
	float dx;  // 從當前掃描線到下一條掃描線間x的增量,即斜率的倒數(shù)
	float ymax; //該邊所交的最高掃描線的坐標值ymax
	XET* next;
}AET, NET; //AET 活性邊表; NET新邊表

void draw_a_point(int x, int y);
void PolyScan();
void mymouse(int button, int state, int x, int y);
void display();


int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(100, 50);
	glutInitWindowSize(window_width, window_height);
	glutCreateWindow("掃描線填充");

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, window_width, 0, window_height);

	glClearColor(1, 1, 1, 1);
	glClear(GL_COLOR_BUFFER_BIT);

	glutMouseFunc(&mymouse);
	glutDisplayFunc(&display);

	glutMainLoop();
	return 0;
}

//畫點函數(shù)
void draw_a_point(int x, int y)
{
	glBegin(GL_POINTS);
	glColor3f(0, 1, 1);
	glVertex2f(x, y);
	glEnd();
	glFlush();
}

void PolyScan()
{
	/*得到最高點的y坐標*/
	int Max_Y = 0;
	for (int i = 0; i < vertice.size(); i++) 
		/*Max_Y = max(Max_Y, vertice[i].y);*/
		if (vertice[i].y > Max_Y)
			Max_Y = vertice[i].y;


	//初始化AET表
	AET* pAET = new AET;
	pAET->next = NULL;

	//初始化NET表
	NET* pNET[800]; //吊桶
	for (int i = 0; i <= Max_Y; i++)
	{
		pNET[i] = new NET;
		pNET[i]->next = NULL;;
	}

	//掃描并且建立NET表
	int len = vertice.size(); //頂點個數(shù)
	for (int i = 0; i <= Max_Y; i++)
	{
		for (int j = 0; j < len; j++) //掃描每個點
		{
			if (i == vertice[j].y)
			{
				//如果一個點和前一個點有一條邊相連,則該點和后面一個點也相連
				//!這個式子 便于最后一個頂點和第一個點相連 和 防止出現(xiàn)負數(shù)
				
				//判斷當前點的高低,使ymax、DX、DY的計算有變化
				if (vertice[(j - 1 + len) % len].y > vertice[j].y)
				{
					//前一個點在當前點的上方
					NET* p = new NET;
					p->x = vertice[j].x;
					p->ymax = vertice[(j - 1 + len) % len].y;//與當前掃描線相交的活性邊 的 最高點即為相鄰頂點的y
					float DX = vertice[(j - 1 + len) % len].x - vertice[j].x;
					float DY = vertice[(j - 1 + len) % len].y - vertice[j].y;
					p->dx = DX / DY;//dx為直線斜率的倒數(shù)
					p->next = pNET[i]->next;
					pNET[i]->next = p;
				}
				if (vertice[(j + 1) % len].y > vertice[j].y)
				{
					//后一個點在當前點的上方
					NET* p = new NET;
					p->x = vertice[j].x;
					p->ymax = vertice[(j + 1) % len].y;
					float DX = vertice[(j + 1) % len].x - vertice[j].x;
					float DY = vertice[(j + 1) % len].y - vertice[j].y;
					p->dx = DX / DY;//dx為直線斜率的倒數(shù)
					p->next = pNET[i]->next;
					pNET[i]->next = p;
				}
			}
		}
	}

	//建立并且更新活性邊表AET
	//各條掃描線i
	for (int i = 0; i <= Max_Y; i++)
	{
		/*把新邊表NET[i] 中的邊結點用插入排序法插入AET表,使之按x坐標遞增順序排列*/
		
		//計算每條掃描線上不同線產(chǎn)生的新的交點x,更新AET
		NET* p = pAET->next;
		while (p)
		{
			p->x = p->x + p->dx; //更新x坐標
			p = p->next;
		}

		//斷表排序,不再開辟空間 
		AET* tq = pAET;
		p = pAET->next;
		tq->next = NULL;
		while (p)//順著鏈表往下走
		{
			//找到第一個比它大的數(shù)字tq->next->next->x,則從p->next到tq->next都是比p->x小的
			while (tq->next != NULL && tq->next->x <= p->x)
				tq = tq->next;
			//插入p到tq和tq->next之間
			NET* t = p->next;
			p->next = tq->next;
			tq->next = p;
			p = t;

			tq = pAET;//回到頭
		}

		/*(改進算法) 取消求交,減少計算量*/
		//先從AET表中刪除ymax==i的結點****************************************/
		//像素的取舍問題,保證多邊形的“下閉上開”,避免填充擴大化(交點的個數(shù)應保證為偶數(shù)個)
		AET* q = pAET;
		p = q->next;
		while (p)
		{
			if (p->ymax == i)
			{
				q->next = p->next;
				delete p;
				p = q->next;
			}
			else
			{
				q = q->next;
				p = q->next;
			}
		}

		//若NET中有新點,將其用插入法插入AET,按x遞增的順序排列
		p = pNET[i]->next;
		q = pAET;
		while (p)
		{
			while (q->next && p->x >= q->next->x)
				q = q->next;
			//插入p
			NET* t = p->next;
			p->next = q->next;
			q->next = p;
			p = t;

			q = pAET;//回到頭
		}

		//配對后填充顏色
		p = pAET->next;
		while (p && p->next != NULL)
		{
			for (float j = p->x; j <= p->next->x; j++)
			{
				//掃描線畫點
				draw_a_point(j, i);
				//cout << "(" << j << ", " << i << ")" << endl;
			}
			p = p->next->next;//考慮端點情況
		}
	}
	glFlush();
}
void mymouse(int button, int state, int x, int y)
{
	//左鍵
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		draw_a_point(x, window_height - y);

		point p(x, window_height - y);
		vertice.push_back(p);
		cout << "頂點" << vertice.size() << ": (" << x << ", " << window_height - y << ")" << endl;
	}
	//右鍵
	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
	{
		glClearColor(1, 1, 1, 1);//設置繪制窗口顏色為白色
		glColor3f(0, 1, 1);

		//繪制多邊形
		glBegin(GL_LINES);	
		for (int i = 0; i < vertice.size(); i++)
		{
			if (i == vertice.size() - 1)//畫完最后一個點,使其閉合
			{
				glVertex2f(vertice[0].x, vertice[0].y);
				glVertex2f(vertice[i].x, vertice[i].y);
			}
			else
			{
				glVertex2f(vertice[i].x, vertice[i].y);
				glVertex2f(vertice[i + 1].x, vertice[i + 1].y);
			}
		}
		glEnd();
		glFlush();
	}

	//鼠標中間
	if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
	{
		//cout << "center: (" << x << ", " << y << ")" << endl;
		//BoundaryFill4(x, window_height - y);
		//BoundaryFill4_Stack(x, window_height - y);

		cout << "多邊形頂點個數(shù)為" << vertice.size() << "。 " << "開始掃描線填充。" << endl;
		PolyScan();
	}
}
void display()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(0.0, 0.4, 0.2);
	glPointSize(1);
	glBegin(GL_POINTS);
	PolyScan();
	glEnd();
	glFlush();
}

總結

掃描線算法部分,建立NET 和 建立并且更新活性邊表AET 這兩個地方比較復雜,可以帶入圖中多想文章來源地址http://www.zghlxwxcb.cn/news/detail-400768.html

到了這里,關于【計算機圖形學 】掃描線多邊形填充算法 | OpenGL+鼠標交互的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 淺談掃描線

    淺談掃描線

    掃描線一般運用在圖形上面,它和它的字面意思非常相似,就是拿一根線,在圖形上面掃來掃去。我們一般用它來解決圖形的面積,周長,二位數(shù)點等問題。 在二維坐標系上,給出多個矩形的左下以及右上坐標,求出所有矩形構成的圖形的面積。 我們當然知道,如果數(shù)據(jù)范

    2024年02月07日
    瀏覽(23)
  • 計算機圖形學 第4章 多邊形填充

    計算機圖形學 第4章 多邊形填充

    了解掃描轉換的基本概念。 熟練掌握多邊形有效邊表填充算法。 掌握多邊形邊緣填充算法。 熟練掌握區(qū)域四鄰接點和八鄰接點區(qū)域填充算法。 掌握區(qū)域掃描線種子填充算法。 無論使用哪種著色模式,都意味著要使用指定顏色為多邊形 邊界內(nèi) 的每一個像素著色。 多邊形的

    2024年02月02日
    瀏覽(93)
  • 【單調(diào)隊列】 單調(diào)隊列的“掃描線”理解

    【單調(diào)隊列】 單調(diào)隊列的“掃描線”理解

    ?? “如果一個選手比你小還比你強,你就可以退役了?!薄獑握{(diào)隊列的原理 比你強,而且比你影響時間更長。 某種意義上,數(shù)學思維是生活中的思考的延伸。 ??算法學習筆記(66): 單調(diào)隊列。引用 Pecco 的算法筆記。 ??在這里給出一種掃描線的理解。 ??我們以滑動

    2024年02月12日
    瀏覽(20)
  • 【W(wǎng)eiler-Atherton算法】 計算機圖形學多邊形裁剪算法

    【W(wǎng)eiler-Atherton算法】 計算機圖形學多邊形裁剪算法

    源代碼: https://github.com/ricar0/Weiler-Atherton-Alogrithm/tree/master 通常來說就是利用多邊形來裁剪多邊形的一種方法,一般情況下是利用矩形來裁剪凹凸多邊形 凸多邊形 凹多邊形 上面紅色劃線部分就是裁剪出的部分 OPENGL基礎語法 基本上就是一些畫線和畫多邊形的操作,難度較低

    2023年04月09日
    瀏覽(90)
  • 計算機圖形硬件(二) 5 - 2 光柵掃描系統(tǒng)

    計算機圖形硬件(二) 5 - 2 光柵掃描系統(tǒng)

    2.1視頻控制器 圖2.17給出了常用的光柵系統(tǒng)組織。緩存使用系統(tǒng)存儲器的固定區(qū)域且由視頻控制器直接訪問。 ?????????幀緩存的位置及相應的屏幕位置均使用笛卡兒(Cartesian)坐標。應用程序使用圖形軟件包的命令來設定顯示對象相對于笛卡兒坐標系原點的坐標位置。盡管

    2024年02月11日
    瀏覽(19)
  • 計算機圖形學05:中點BH算法對任意斜率的直線掃描轉換方法

    計算機圖形學05:中點BH算法對任意斜率的直線掃描轉換方法

    作者 :非妃是公主 專欄 :《計算機圖形學》 博客地址 :https://blog.csdn.net/myf_666 個性簽:順境不惰,逆境不餒,以心制境,萬事可成?!鴩?專欄名稱 專欄地址 軟件工程 專欄——軟件工程 計算機圖形學 專欄——計算機圖形學 操作系統(tǒng) 專欄——操作系統(tǒng) 軟件測試 專

    2024年02月02日
    瀏覽(23)
  • 【計算機圖形學】二維圖形裁剪算法

    【計算機圖形學】二維圖形裁剪算法

    Cohen-Sutherland算法 Cohen-Sutherland是最早最流行的算法。 核心思想:通過 編碼測試 來減少計算交點的次數(shù)。(編碼算法) 1. 區(qū)域碼: 線段端點以區(qū)域賦值以四位二進制碼。 編碼順序:四位從右到左分別為:左邊界、右邊界、下邊界、上邊界。 編碼值:落在相應位置為1,否則

    2024年02月02日
    瀏覽(20)
  • 初識計算機圖形學

    初識計算機圖形學

    筆記來源:【老奇】陰差陽錯 撼動世界的游戲引擎 詳見本人博客: 1.Transformation 2.梳理從MVP變換到光柵化的過程 MVP變換將空間中3D物體投影到2D屏幕 詳見本人博客: 1.Rasterization(光柵化) 2.梳理從MVP變換到光柵化的過程 場景是一個個由三角面組成的模型 將模型投射到像素就

    2024年01月21日
    瀏覽(22)
  • 計算機圖形與圖像技術

    計算機圖形與圖像技術

    可以使用Python、Java等語言。 下圖中,圖中各事物比例失調(diào) 如何使用代碼去掉某個人(不允許使用摳圖工具)? ????????像素(Pixel)是“圖像元素”的縮寫, 指的是圖像的最小單位 。 它是構成數(shù)碼圖像或屏幕顯示圖像的基本單元,代表了圖像中的一個小點或一個小方塊

    2024年02月07日
    瀏覽(29)
  • 計算機圖形學——大作業(yè)

    計算機圖形學——大作業(yè)

    繪制一個簡單的三維場景,可以是室內(nèi):臥室,辦公室,教室,也可以是室外:運動場,公園等,加上光照效果,簡單的紋理映射,透視投影;不能過于簡單;可以加動畫、鼠標和鍵盤交互。 ??? 上交材料: project和word文檔(具體內(nèi)容展示,思路和心得) 首先初始化窗口,

    2024年02月11日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包