计算机图形学作业( 二):使用Bresenham算法画直线和圆,并使用光栅化算法填充三角形

Bresenham算法画直线

原理

首先,观察下图:

在这里插入图片描述

设一条直线为y=mx+B,那么上图图中的参数为:

在这里插入图片描述

然后观察下图:

在这里插入图片描述

在图中,红色点为当前的点,我们要计算出下一个点是取高位的黄色点,还是低位的黄色点,就要比较这两个点谁距离直线最近,结合之前的图,可得:

在这里插入图片描述

如果d_{lower}-d_{upper}>0,则取上方的黄色点,否则取下方的黄色点。 设定一个参数p_i,如下图:

在这里插入图片描述

经过计算可得:

在这里插入图片描述

且有以下关系:

在这里插入图片描述

算法

绘制斜率在[0,1]范围内的直线算法如下:

在这里插入图片描述

拓展

由于使用Bresenham算法只能绘制斜率在[0,1]范围内的直线,那么要绘制其它斜率范围的直线,就要进行坐标平移、对称变换。

首先,我在代码中输入三个正整数点坐标,由于在OpenGL中坐标范围是 -1.0f~1.0f,所以我定义了一个函数normalize,负责把正整数转化为 -1.0f~1.0f 的浮点数。因为我的窗口大小是800*800,所以只需要写成以下形式:

1
2
3
4
float normalize(int input) {
	float result = float(input) / 800;
	return result;
}

然后,对于给出的两个点,我们要绘制这两点的直线,首先计算出它们的斜率,若斜率不存在,则固定横坐标,循环纵坐标画出一个个点;若斜率在[0,1]范围,则以Bresenham算法绘制;否则,按以下方法绘制直线:

  1. 找出这两点谁的横坐标较小,然后把横坐标较小的点平移到原点,横坐标较大的点平移到对应位置。
  2. 对横坐标较大的点做一系列变换(关于直线y=x或y=0等对称),使得两点斜率在[0,1]之内
  3. 使用Bresenham算法绘制出直线,然后把这条直线作步骤2相反的一系列变换,再加上步骤1的平移量即可。

结果

画出三角形并光栅化后,结果如下图所示:

在这里插入图片描述

使用光栅化算法填充三角形

光栅化算法有三种:

  1. Edge-walking
  2. Edge-equation
  3. Barycentric-coordinate based

我使用的算法是Edge-equation

算法伪代码

在这里插入图片描述

算法解释

  1. 根据三角形的三个点,计算三条边的一般式方程Ax+By+C=0,其中A=Y2-Y1,B=X1-X2,C=X2Y1-X1Y2。
  2. 将三条边“中心化”,取三角形的中点,即((X1+X2+X3)/3, (Y1+Y2+Y3)/3),分别代入三个直线方程,若最终结果小于0,则把该方程的三个参数A、B、C分别乘以-1。
  3. 计算三角形外接矩阵,该矩阵的两条边分别与X轴Y轴平行。即在三角形的三个顶点中,找到最小的x值leftX和最大的x值rightX,那么外接矩阵的横边就从leftX开始到rightX结束,同理竖边从bottomY开始到topY结束。
  4. 遍历外接矩阵的每一个点,每个点都代入三个直线方程,若结果都大于0,则该点在三角形内,画出该点。

结果

在这里插入图片描述

Bresenham算法画圆

原理

我是用八分法画圆,因为圆上的一点,可以有另外在圆上的7个对称点,我们只需要画八分之一的圆。如下图:

在这里插入图片描述

我们只需要画第一象限的上半部分的八分之一圆。画图时,计算出的点作对称变换就可得到其余7个对称点,最后就能获得一整个圆的所有点。用GL_POINTS即可画出圆。

具体推导方法我是参考了这篇博客https://blog.csdn.net/mayh554024289/article/details/44781531,故不再赘述。

算法

我们假设圆心在原点(若不在原点,只需要作简单平移变换即可),并且主要画第一象限的上半部分的八分之一圆,其余部分用对称方法解决。

  1. 取初始值x=0, y=radius, endX=radius/(float)sqrt(2), d=1.25-radius
  2. 如果d<=0,令(x+1, y)取代(x,y),并且d=d+2x+2;否则令(x+1, y-1)取代(x,y),并且d=d+2(x-y)+5。
  3. 画出当前(x,y)点和其余7个对称点。
  4. 当x<=endX,重复步骤2~3。

结果

画出的圆如下所示:

在这里插入图片描述

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
#include <iostream>
#include <algorithm>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"

CONST INT MAX_LENGTH = 240000;
CONST INT WINDOW_SIZE = 800;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void getLineVertex(int x1, int y1, int x2, int y2, float vertices[MAX_LENGTH], int* length);
void edge_equations(int point1[2], int point2[2], int point3[2], float vertices[MAX_LENGTH], int* length);
void getCircleVertex(int originPointX, int originPointY, int radius, float vertices[MAX_LENGTH], int* length);
float normalize(int input);
void initImGUI(GLFWwindow* window);
void createAndRenderLineImGUI(GLFWwindow* window, bool *show_window, int point1[2], int point2[2], int point3[2], bool *isDrawLine);
void createAndRenderCircleImGUI(GLFWwindow* window, bool *show_window, int point1[2], int *radius, bool *isDrawLine);
int myMin(int a, int b, int c);
int myMax(int a, int b, int c);

//顶点着色器可以向片段着色器传数据
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}
#include <iostream>
#include <algorithm>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"

CONST INT MAX_LENGTH = 240000;
CONST INT WINDOW_SIZE = 800;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void getLineVertex(int x1, int y1, int x2, int y2, float vertices[MAX_LENGTH], int* length);
void edge_equations(int point1[2], int point2[2], int point3[2], float vertices[MAX_LENGTH], int* length);
void getCircleVertex(int originPointX, int originPointY, int radius, float vertices[MAX_LENGTH], int* length);
float normalize(int input);
void initImGUI(GLFWwindow* window);
void createAndRenderLineImGUI(GLFWwindow* window, bool *show_window, int point1[2], int point2[2], int point3[2], bool *isDrawLine);
void createAndRenderCircleImGUI(GLFWwindow* window, bool *show_window, int point1[2], int *radius, bool *isDrawLine);
int myMin(int a, int b, int c);
int myMax(int a, int b, int c);

//顶点着色器可以向片段着色器传数据
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";

const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\0";

int main() {
	//初始化opengl窗口和配置
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* window = glfwCreateWindow(WINDOW_SIZE, WINDOW_SIZE, "LearnOpenGL", NULL, NULL);
	if (window == NULL) {
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	initImGUI(window);

	//顶点着色器
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);

	//片段着色器
	unsigned int fragmentShader;
	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);

	//着色器程序
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);

	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

	bool show_window = true;
	bool isDrawLine = true;

	int point1[2] = { -150, -150 };
	int point2[2] = { 150, -150 };
	int point3[2] = { 0, 150 };
	int radius = 100;
	int originPoint[2] = { 0, 0 };

	while (!glfwWindowShouldClose(window)) {
		float vertices[MAX_LENGTH] = { 0 }; // 注意索引从0开始! 
		int length = 0;

		//获取线段点数据
		if (isDrawLine) {
			getLineVertex(point1[0], point1[1], point2[0], point2[1], vertices, &length);
			getLineVertex(point2[0], point2[1], point3[0], point3[1], vertices, &length);
			getLineVertex(point1[0], point1[1], point3[0], point3[1], vertices, &length);
			edge_equations(point1, point2, point3, vertices, &length);
		}
		else {
			//获取圆数据
			getCircleVertex(originPoint[0], originPoint[1], radius, vertices, &length);
		}

		unsigned int VAO;
		unsigned int VBO;

		//必须先绑定VA0
		glGenVertexArrays(1, &VAO);
		glBindVertexArray(VAO);

		//再绑定VBO
		glGenBuffers(1, &VBO);
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

		//再设置属性
		//位置属性
		//属性位置值为0的顶点属性
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
		glEnableVertexAttribArray(0);

		glBindBuffer(GL_ARRAY_BUFFER, 0);


		processInput(window);

		//使用着色器程序
		glUseProgram(shaderProgram);

		glfwPollEvents();

		//清除屏幕
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		//画imGUI
		if (isDrawLine) {
			createAndRenderLineImGUI(window, &show_window, point1, point2, point3, &isDrawLine);
		}
		else {
			createAndRenderCircleImGUI(window, &show_window, originPoint, &radius, &isDrawLine);
		}


		//画线段
		//length是vertices的长度,而vertices三个元素为一个点
		//glBindVertexArray(VAO);
		glDrawArrays(GL_POINTS, 0, length / 3);

		glfwSwapBuffers(window);

		glDeleteVertexArrays(1, &VAO);
		glDeleteBuffers(1, &VBO);
	}

	

	glfwTerminate();

	return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
	glViewport(0, 0, width, height);
}

void processInput(GLFWwindow* window) {
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, true);
	}
}

void getLineVertex(int x1, int y1, int x2, int y2, float vertices[MAX_LENGTH], int* length) {
	int x, y, endx, endy;
	float slope;	//斜率
	bool isSlopeExist = true;
	//确定起初点
	if (x1 < x2) {
		x = x1;
		y = y1;
		endx = x2;
		endy = y2;
	}
	else {
		x = x2;
		y = y2;
		endx = x1;
		endy = y1;
	}

	//计算斜率
	if (x == endx) {
		//斜率不存在
		isSlopeExist = false;
	}
	else {
		slope = ((float)endy - (float)y) / ((float)endx - (float)x);
	}

	//初始点
	vertices[*length] = normalize(x);
	(*length)++;
	vertices[*length] = normalize(y);
	(*length)++;
	vertices[*length] = 0.0f;
	(*length)++;

	if (isSlopeExist == false) {
		//斜率不存在时
		int first;
		int last;
		if (y < endy) {
			first = y;
			last = endy;
		}
		else {
			first = endy;
			last = y;
		}
		for (int i = first; i <= last; i++) {
			vertices[*length] = normalize(x);
			(*length)++;
			vertices[*length] = normalize(i);
			(*length)++;
			vertices[*length] = 0.0f;
			(*length)++;
		}
	}
	else {
		//对称变换前,先把起始点移到原点,其它点移到对应位置
		int moveX = x;
		int moveY = y;
		x = x - moveX;
		y = y - moveY;
		endx = endx - moveX;
		endy = endy - moveY;

		//对称变换
		//利用对称变换,将画其他斜率线段转化为画斜率 0 <=  <= 1的线段
		if (slope > 1) {
			//第一象限上半部分
			//起点不动,互换终点的x y
			int temp = endy;
			endy = endx;
			endx = temp;
		}
		else if (slope < 0 && slope >= -1) {
			//第二象限上半部分
			//起点不动,终点的y变相反数
			endy = -endy;
		}
		else if (slope < -1) {
			//第二象限下半部分
			//起点不动,终点的y变相反数,然后互换终点的x y
			endy = -endy;
			int temp = endy;
			endy = endx;
			endx = temp;
		}

		int deltaX = abs(endx - x);
		int deltaY = abs(endy - y);
		int p = 2 * deltaY - deltaX;

		//只能画斜率 0 <=  <= 1的线段 
		while (x <= endx) {
			if (p <= 0) {
				x = x + 1;
				y = y;
				p = p + 2 * deltaY;
			}
			else {
				x = x + 1;
				y = y + 1;
				p = p + 2 * deltaY - 2 * deltaX;
			}

			//利用对称变换,将斜率 0 <=  <= 1的线段上的点转化为原来斜率线段上的点
			if (slope > 1) {
				//第一象限上半部分
				int temp = y;
				y = x;
				x = temp;
			}
			else if (slope < 0 && slope >= -1) {
				//第二象限上半部分
				//起点不动,终点的y变相反数
				y = -y;
			}
			else if (slope < -1) {
				//第二象限下半部分
				//起点不动,互换x y, y变相反数
				int temp = y;
				y = x;
				x = temp;

				y = -y;
			}

			//对称变换后,先把起始点移到原本位置,然后画出来
			x = x + moveX;
			y = y + moveY;

			vertices[*length] = normalize(x);
			(*length)++;
			vertices[*length] = normalize(y);
			(*length)++;
			vertices[*length] = 0.0f;
			(*length)++;

			//画图后,再恢复起始点
			x = x - moveX;
			y = y - moveY;

			//利用对称变换,恢复原来的点到斜率 0 <=  <= 1的线段上,继续计算下一个点
			if (slope > 1) {
				//第一象限上半部分
				int temp = y;
				y = x;
				x = temp;
			}
			else if (slope < 0 && slope >= -1) {
				//第二象限上半部分
				//起点不动,终点的y变相反数
				y = -y;
			}
			else if (slope < -1) {
				//第二象限下半部分
				//起点不动,y变相反数,互换x y
				y = -y;

				int temp = y;
				y = x;
				x = temp;
			}

		}
	}

}

void edge_equations(int point1[2], int point2[2], int point3[2], float vertices[MAX_LENGTH], int* length) {
	//求3条直线一般方程Ax+By+C=0的参数
	//序号12为point1和point2的参数,序号23为point2和point3的参数,序号13为point1和point3的参数
	int A12, B12, C12;
	int A23, B23, C23;
	int A13, B13, C13;
	A12 = point2[1] - point1[1];
	B12 = point1[0] - point2[0];
	C12 = point2[0] * point1[1] - point1[0] * point2[1];
	A23 = point3[1] - point2[1];
	B23 = point2[0] - point3[0];
	C23 = point3[0] * point2[1] - point2[0] * point3[1];
	A13 = point3[1] - point1[1];
	B13 = point1[0] - point3[0];
	C13 = point3[0] * point1[1] - point1[0] * point3[1];

	//将三角形中点带入各直线,若结果小于0,则将参数A、B、C都乘以-1。 
	float middleX = ((float)point1[0] + (float)point2[0] + (float)point3[0]) / 3;
	float middleY = ((float)point1[1] + (float)point2[1] + (float)point3[1]) / 3;
	float temp = A12 * middleX + B12 * middleY + C12;
	if (temp < 0) {
		A12 = -A12;
		B12 = -B12;
		C12 = -C12;
	}
	temp = A23 * middleX + B23 * middleY + C23;
	if (temp < 0) {
		A23 = -A23;
		B23 = -B23;
		C23 = -C23;
	}
	temp = A13 * middleX + B13 * middleY + C13;
	if (temp < 0) {
		A13 = -A13;
		B13 = -B13;
		C13 = -C13;
	}

	//计算两条边分别于x轴和y轴平行的外接矩形
	int leftX = myMin(point1[0], point2[0], point3[0]);
	int rightX = myMax(point1[0], point2[0], point3[0]);
	int topY = myMax(point1[1], point2[1], point3[1]);
	int bottomY = myMin(point1[1], point2[1], point3[1]);

	//遍历矩形,处理后的一般方程,三角形中的任意一个点代入3条曲线,都会使Ax+By+C的结果都大于0
	for (int i = leftX; i <= rightX; i = i + 1) {
		for (int j = bottomY; j <= topY; j = j + 1) {
			if (A12 * i + B12 * j + C12 > 0 &&
				A23 * i + B23 * j + C23 > 0 &&
				A13 * i + B13 * j + C13 > 0) {
				//防止数组越界
				if ((*length) >= MAX_LENGTH - 3) break;

				vertices[(*length)++] = normalize(i);
				vertices[(*length)++] = normalize(j);
				vertices[(*length)++] = 0.0f;	
			}
		}
	}
}

void getCircleVertex(int originPointX, int originPointY, int radius, float vertices[MAX_LENGTH], int* length) {
	//移到原点,记录偏移量
	int moveX = originPointX;
	int moveY = originPointY;

	int x = 0;
	int y = radius;
	int end = (int)(radius * 1.0 / (float)sqrt(2));
	float d = 1.25 - radius;

	//加入初始点及对称的其它7个点
	while (x <= end) {
		//加入新点及对称的其它7个点
		vertices[(*length)++] = normalize(x + moveX);
		vertices[(*length)++] = normalize(y + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(y + moveX);
		vertices[(*length)++] = normalize(-x + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(-x + moveX);
		vertices[(*length)++] = normalize(-y + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(-y + moveX);
		vertices[(*length)++] = normalize(x + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(y + moveX);
		vertices[(*length)++] = normalize(x + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(x + moveX);
		vertices[(*length)++] = normalize(-y + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(-y + moveX);
		vertices[(*length)++] = normalize(-x + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(-x + moveX);
		vertices[(*length)++] = normalize(y + moveY);
		vertices[(*length)++] = 0.0f;	
		vertices[(*length)++] = normalize(x + moveX);
		vertices[(*length)++] = normalize(y + moveY);
		vertices[(*length)++] = 0.0f;
		
		
		if (d <= 0) {
			x = x + 1;
			y = y;
			d = d + 2 * x + 2;	
		}
		else {
			x = x + 1;
			y = y - 1;
			d = d + 2 * (x - y) + 5;
		}
	}
}

float normalize(int input) {
	float result = float(input) / WINDOW_SIZE;
	return result;
}

void initImGUI(GLFWwindow* window) {
	//创建并绑定ImGui
	const char* glsl_version = "#version 130";
	IMGUI_CHECKVERSION();
	ImGui::CreateContext();
	ImGuiIO& io = ImGui::GetIO(); (void)io;
	ImGui::StyleColorsDark();
	ImGui_ImplGlfw_InitForOpenGL(window, true);
	ImGui_ImplOpenGL3_Init(glsl_version);
}

void createAndRenderLineImGUI(GLFWwindow* window, bool *show_window, int point1[2], int point2[2], int point3[2], bool *isDrawLine) {
	//创建imgui
	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplGlfw_NewFrame();
	ImGui::NewFrame();

	ImGui::Begin("Edit points", show_window, ImGuiWindowFlags_MenuBar);
	//ImGui::ColorEdit3("top color", (float*)&topColor);
	ImGui::Text("input 3 points");
	ImGui::SliderInt2("point1", point1, -180, 180);
	ImGui::SliderInt2("point2", point2, -180, 180);
	ImGui::SliderInt2("point3", point3, -180, 180);
	if (ImGui::Button("Draw Circle"))
		(*isDrawLine) = false;
	ImGui::End();

	ImGui::Render();
	int display_w, display_h;
	glfwMakeContextCurrent(window);
	glfwGetFramebufferSize(window, &display_w, &display_h);
	glViewport(0, 0, display_w, display_h);
	ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}

void createAndRenderCircleImGUI(GLFWwindow* window, bool *show_window, int point[2], int *radius, bool *isDrawLine) {
	//创建imgui
	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplGlfw_NewFrame();
	ImGui::NewFrame();

	ImGui::Begin("Edit points", show_window, ImGuiWindowFlags_MenuBar);
	ImGui::Text("input 3 points");
	ImGui::SliderInt2("point1", point, -WINDOW_SIZE, WINDOW_SIZE);
	ImGui::SliderInt("point1", radius, 0, WINDOW_SIZE);
	if (ImGui::Button("Draw Line"))
		(*isDrawLine) = true;
	ImGui::End();

	ImGui::Render();
	int display_w, display_h;
	glfwMakeContextCurrent(window);
	glfwGetFramebufferSize(window, &display_w, &display_h);
	glViewport(0, 0, display_w, display_h);
	ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}

int myMin(int a, int b, int c) {
	if (a < b) {
		if (a < c) {
			return a;
		}
		else {
			return c;
		}
	}
	else {
		if (b < c) {
			return b;
		}
		else {
			return c;
		}
	}
}

int myMax(int a, int b, int c) {
	if (a > b) {
		if (a > c) {
			return a;
		}
		else {
			return c;
		}
	}
	else {
		if (b > c) {
			return b;
		}
		else {
			return c;
		}
	}
}
"; const char* fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "void main()\n" "{\n" "FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" "}
#include <iostream>
#include <algorithm>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"

CONST INT MAX_LENGTH = 240000;
CONST INT WINDOW_SIZE = 800;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
void getLineVertex(int x1, int y1, int x2, int y2, float vertices[MAX_LENGTH], int* length);
void edge_equations(int point1[2], int point2[2], int point3[2], float vertices[MAX_LENGTH], int* length);
void getCircleVertex(int originPointX, int originPointY, int radius, float vertices[MAX_LENGTH], int* length);
float normalize(int input);
void initImGUI(GLFWwindow* window);
void createAndRenderLineImGUI(GLFWwindow* window, bool *show_window, int point1[2], int point2[2], int point3[2], bool *isDrawLine);
void createAndRenderCircleImGUI(GLFWwindow* window, bool *show_window, int point1[2], int *radius, bool *isDrawLine);
int myMin(int a, int b, int c);
int myMax(int a, int b, int c);

//顶点着色器可以向片段着色器传数据
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
"gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";

const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
"FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\0";

int main() {
	//初始化opengl窗口和配置
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	GLFWwindow* window = glfwCreateWindow(WINDOW_SIZE, WINDOW_SIZE, "LearnOpenGL", NULL, NULL);
	if (window == NULL) {
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
		std::cout << "Failed to initialize GLAD" << std::endl;
		return -1;
	}

	initImGUI(window);

	//顶点着色器
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);

	//片段着色器
	unsigned int fragmentShader;
	fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentShader);

	//着色器程序
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentShader);
	glLinkProgram(shaderProgram);

	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);

	bool show_window = true;
	bool isDrawLine = true;

	int point1[2] = { -150, -150 };
	int point2[2] = { 150, -150 };
	int point3[2] = { 0, 150 };
	int radius = 100;
	int originPoint[2] = { 0, 0 };

	while (!glfwWindowShouldClose(window)) {
		float vertices[MAX_LENGTH] = { 0 }; // 注意索引从0开始! 
		int length = 0;

		//获取线段点数据
		if (isDrawLine) {
			getLineVertex(point1[0], point1[1], point2[0], point2[1], vertices, &length);
			getLineVertex(point2[0], point2[1], point3[0], point3[1], vertices, &length);
			getLineVertex(point1[0], point1[1], point3[0], point3[1], vertices, &length);
			edge_equations(point1, point2, point3, vertices, &length);
		}
		else {
			//获取圆数据
			getCircleVertex(originPoint[0], originPoint[1], radius, vertices, &length);
		}

		unsigned int VAO;
		unsigned int VBO;

		//必须先绑定VA0
		glGenVertexArrays(1, &VAO);
		glBindVertexArray(VAO);

		//再绑定VBO
		glGenBuffers(1, &VBO);
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

		//再设置属性
		//位置属性
		//属性位置值为0的顶点属性
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
		glEnableVertexAttribArray(0);

		glBindBuffer(GL_ARRAY_BUFFER, 0);


		processInput(window);

		//使用着色器程序
		glUseProgram(shaderProgram);

		glfwPollEvents();

		//清除屏幕
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		//画imGUI
		if (isDrawLine) {
			createAndRenderLineImGUI(window, &show_window, point1, point2, point3, &isDrawLine);
		}
		else {
			createAndRenderCircleImGUI(window, &show_window, originPoint, &radius, &isDrawLine);
		}


		//画线段
		//length是vertices的长度,而vertices三个元素为一个点
		//glBindVertexArray(VAO);
		glDrawArrays(GL_POINTS, 0, length / 3);

		glfwSwapBuffers(window);

		glDeleteVertexArrays(1, &VAO);
		glDeleteBuffers(1, &VBO);
	}

	

	glfwTerminate();

	return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
	glViewport(0, 0, width, height);
}

void processInput(GLFWwindow* window) {
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		glfwSetWindowShouldClose(window, true);
	}
}

void getLineVertex(int x1, int y1, int x2, int y2, float vertices[MAX_LENGTH], int* length) {
	int x, y, endx, endy;
	float slope;	//斜率
	bool isSlopeExist = true;
	//确定起初点
	if (x1 < x2) {
		x = x1;
		y = y1;
		endx = x2;
		endy = y2;
	}
	else {
		x = x2;
		y = y2;
		endx = x1;
		endy = y1;
	}

	//计算斜率
	if (x == endx) {
		//斜率不存在
		isSlopeExist = false;
	}
	else {
		slope = ((float)endy - (float)y) / ((float)endx - (float)x);
	}

	//初始点
	vertices[*length] = normalize(x);
	(*length)++;
	vertices[*length] = normalize(y);
	(*length)++;
	vertices[*length] = 0.0f;
	(*length)++;

	if (isSlopeExist == false) {
		//斜率不存在时
		int first;
		int last;
		if (y < endy) {
			first = y;
			last = endy;
		}
		else {
			first = endy;
			last = y;
		}
		for (int i = first; i <= last; i++) {
			vertices[*length] = normalize(x);
			(*length)++;
			vertices[*length] = normalize(i);
			(*length)++;
			vertices[*length] = 0.0f;
			(*length)++;
		}
	}
	else {
		//对称变换前,先把起始点移到原点,其它点移到对应位置
		int moveX = x;
		int moveY = y;
		x = x - moveX;
		y = y - moveY;
		endx = endx - moveX;
		endy = endy - moveY;

		//对称变换
		//利用对称变换,将画其他斜率线段转化为画斜率 0 <=  <= 1的线段
		if (slope > 1) {
			//第一象限上半部分
			//起点不动,互换终点的x y
			int temp = endy;
			endy = endx;
			endx = temp;
		}
		else if (slope < 0 && slope >= -1) {
			//第二象限上半部分
			//起点不动,终点的y变相反数
			endy = -endy;
		}
		else if (slope < -1) {
			//第二象限下半部分
			//起点不动,终点的y变相反数,然后互换终点的x y
			endy = -endy;
			int temp = endy;
			endy = endx;
			endx = temp;
		}

		int deltaX = abs(endx - x);
		int deltaY = abs(endy - y);
		int p = 2 * deltaY - deltaX;

		//只能画斜率 0 <=  <= 1的线段 
		while (x <= endx) {
			if (p <= 0) {
				x = x + 1;
				y = y;
				p = p + 2 * deltaY;
			}
			else {
				x = x + 1;
				y = y + 1;
				p = p + 2 * deltaY - 2 * deltaX;
			}

			//利用对称变换,将斜率 0 <=  <= 1的线段上的点转化为原来斜率线段上的点
			if (slope > 1) {
				//第一象限上半部分
				int temp = y;
				y = x;
				x = temp;
			}
			else if (slope < 0 && slope >= -1) {
				//第二象限上半部分
				//起点不动,终点的y变相反数
				y = -y;
			}
			else if (slope < -1) {
				//第二象限下半部分
				//起点不动,互换x y, y变相反数
				int temp = y;
				y = x;
				x = temp;

				y = -y;
			}

			//对称变换后,先把起始点移到原本位置,然后画出来
			x = x + moveX;
			y = y + moveY;

			vertices[*length] = normalize(x);
			(*length)++;
			vertices[*length] = normalize(y);
			(*length)++;
			vertices[*length] = 0.0f;
			(*length)++;

			//画图后,再恢复起始点
			x = x - moveX;
			y = y - moveY;

			//利用对称变换,恢复原来的点到斜率 0 <=  <= 1的线段上,继续计算下一个点
			if (slope > 1) {
				//第一象限上半部分
				int temp = y;
				y = x;
				x = temp;
			}
			else if (slope < 0 && slope >= -1) {
				//第二象限上半部分
				//起点不动,终点的y变相反数
				y = -y;
			}
			else if (slope < -1) {
				//第二象限下半部分
				//起点不动,y变相反数,互换x y
				y = -y;

				int temp = y;
				y = x;
				x = temp;
			}

		}
	}

}

void edge_equations(int point1[2], int point2[2], int point3[2], float vertices[MAX_LENGTH], int* length) {
	//求3条直线一般方程Ax+By+C=0的参数
	//序号12为point1和point2的参数,序号23为point2和point3的参数,序号13为point1和point3的参数
	int A12, B12, C12;
	int A23, B23, C23;
	int A13, B13, C13;
	A12 = point2[1] - point1[1];
	B12 = point1[0] - point2[0];
	C12 = point2[0] * point1[1] - point1[0] * point2[1];
	A23 = point3[1] - point2[1];
	B23 = point2[0] - point3[0];
	C23 = point3[0] * point2[1] - point2[0] * point3[1];
	A13 = point3[1] - point1[1];
	B13 = point1[0] - point3[0];
	C13 = point3[0] * point1[1] - point1[0] * point3[1];

	//将三角形中点带入各直线,若结果小于0,则将参数A、B、C都乘以-1。 
	float middleX = ((float)point1[0] + (float)point2[0] + (float)point3[0]) / 3;
	float middleY = ((float)point1[1] + (float)point2[1] + (float)point3[1]) / 3;
	float temp = A12 * middleX + B12 * middleY + C12;
	if (temp < 0) {
		A12 = -A12;
		B12 = -B12;
		C12 = -C12;
	}
	temp = A23 * middleX + B23 * middleY + C23;
	if (temp < 0) {
		A23 = -A23;
		B23 = -B23;
		C23 = -C23;
	}
	temp = A13 * middleX + B13 * middleY + C13;
	if (temp < 0) {
		A13 = -A13;
		B13 = -B13;
		C13 = -C13;
	}

	//计算两条边分别于x轴和y轴平行的外接矩形
	int leftX = myMin(point1[0], point2[0], point3[0]);
	int rightX = myMax(point1[0], point2[0], point3[0]);
	int topY = myMax(point1[1], point2[1], point3[1]);
	int bottomY = myMin(point1[1], point2[1], point3[1]);

	//遍历矩形,处理后的一般方程,三角形中的任意一个点代入3条曲线,都会使Ax+By+C的结果都大于0
	for (int i = leftX; i <= rightX; i = i + 1) {
		for (int j = bottomY; j <= topY; j = j + 1) {
			if (A12 * i + B12 * j + C12 > 0 &&
				A23 * i + B23 * j + C23 > 0 &&
				A13 * i + B13 * j + C13 > 0) {
				//防止数组越界
				if ((*length) >= MAX_LENGTH - 3) break;

				vertices[(*length)++] = normalize(i);
				vertices[(*length)++] = normalize(j);
				vertices[(*length)++] = 0.0f;	
			}
		}
	}
}

void getCircleVertex(int originPointX, int originPointY, int radius, float vertices[MAX_LENGTH], int* length) {
	//移到原点,记录偏移量
	int moveX = originPointX;
	int moveY = originPointY;

	int x = 0;
	int y = radius;
	int end = (int)(radius * 1.0 / (float)sqrt(2));
	float d = 1.25 - radius;

	//加入初始点及对称的其它7个点
	while (x <= end) {
		//加入新点及对称的其它7个点
		vertices[(*length)++] = normalize(x + moveX);
		vertices[(*length)++] = normalize(y + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(y + moveX);
		vertices[(*length)++] = normalize(-x + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(-x + moveX);
		vertices[(*length)++] = normalize(-y + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(-y + moveX);
		vertices[(*length)++] = normalize(x + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(y + moveX);
		vertices[(*length)++] = normalize(x + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(x + moveX);
		vertices[(*length)++] = normalize(-y + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(-y + moveX);
		vertices[(*length)++] = normalize(-x + moveY);
		vertices[(*length)++] = 0.0f;
		vertices[(*length)++] = normalize(-x + moveX);
		vertices[(*length)++] = normalize(y + moveY);
		vertices[(*length)++] = 0.0f;	
		vertices[(*length)++] = normalize(x + moveX);
		vertices[(*length)++] = normalize(y + moveY);
		vertices[(*length)++] = 0.0f;
		
		
		if (d <= 0) {
			x = x + 1;
			y = y;
			d = d + 2 * x + 2;	
		}
		else {
			x = x + 1;
			y = y - 1;
			d = d + 2 * (x - y) + 5;
		}
	}
}

float normalize(int input) {
	float result = float(input) / WINDOW_SIZE;
	return result;
}

void initImGUI(GLFWwindow* window) {
	//创建并绑定ImGui
	const char* glsl_version = "#version 130";
	IMGUI_CHECKVERSION();
	ImGui::CreateContext();
	ImGuiIO& io = ImGui::GetIO(); (void)io;
	ImGui::StyleColorsDark();
	ImGui_ImplGlfw_InitForOpenGL(window, true);
	ImGui_ImplOpenGL3_Init(glsl_version);
}

void createAndRenderLineImGUI(GLFWwindow* window, bool *show_window, int point1[2], int point2[2], int point3[2], bool *isDrawLine) {
	//创建imgui
	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplGlfw_NewFrame();
	ImGui::NewFrame();

	ImGui::Begin("Edit points", show_window, ImGuiWindowFlags_MenuBar);
	//ImGui::ColorEdit3("top color", (float*)&topColor);
	ImGui::Text("input 3 points");
	ImGui::SliderInt2("point1", point1, -180, 180);
	ImGui::SliderInt2("point2", point2, -180, 180);
	ImGui::SliderInt2("point3", point3, -180, 180);
	if (ImGui::Button("Draw Circle"))
		(*isDrawLine) = false;
	ImGui::End();

	ImGui::Render();
	int display_w, display_h;
	glfwMakeContextCurrent(window);
	glfwGetFramebufferSize(window, &display_w, &display_h);
	glViewport(0, 0, display_w, display_h);
	ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}

void createAndRenderCircleImGUI(GLFWwindow* window, bool *show_window, int point[2], int *radius, bool *isDrawLine) {
	//创建imgui
	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplGlfw_NewFrame();
	ImGui::NewFrame();

	ImGui::Begin("Edit points", show_window, ImGuiWindowFlags_MenuBar);
	ImGui::Text("input 3 points");
	ImGui::SliderInt2("point1", point, -WINDOW_SIZE, WINDOW_SIZE);
	ImGui::SliderInt("point1", radius, 0, WINDOW_SIZE);
	if (ImGui::Button("Draw Line"))
		(*isDrawLine) = true;
	ImGui::End();

	ImGui::Render();
	int display_w, display_h;
	glfwMakeContextCurrent(window);
	glfwGetFramebufferSize(window, &display_w, &display_h);
	glViewport(0, 0, display_w, display_h);
	ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}

int myMin(int a, int b, int c) {
	if (a < b) {
		if (a < c) {
			return a;
		}
		else {
			return c;
		}
	}
	else {
		if (b < c) {
			return b;
		}
		else {
			return c;
		}
	}
}

int myMax(int a, int b, int c) {
	if (a > b) {
		if (a > c) {
			return a;
		}
		else {
			return c;
		}
	}
	else {
		if (b > c) {
			return b;
		}
		else {
			return c;
		}
	}
}
"; int main() { //初始化opengl窗口和配置 glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow* window = glfwCreateWindow(WINDOW_SIZE, WINDOW_SIZE, "LearnOpenGL", NULL, NULL); if (window == NULL) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; return -1; } initImGUI(window); //顶点着色器 unsigned int vertexShader; vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); //片段着色器 unsigned int fragmentShader; fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); //着色器程序 unsigned int shaderProgram; shaderProgram = glCreateProgram(); glAttachShader(shaderProgram, vertexShader); glAttachShader(shaderProgram, fragmentShader); glLinkProgram(shaderProgram); glDeleteShader(vertexShader); glDeleteShader(fragmentShader); bool show_window = true; bool isDrawLine = true; int point1[2] = { -150, -150 }; int point2[2] = { 150, -150 }; int point3[2] = { 0, 150 }; int radius = 100; int originPoint[2] = { 0, 0 }; while (!glfwWindowShouldClose(window)) { float vertices[MAX_LENGTH] = { 0 }; // 注意索引从0开始! int length = 0; //获取线段点数据 if (isDrawLine) { getLineVertex(point1[0], point1[1], point2[0], point2[1], vertices, &length); getLineVertex(point2[0], point2[1], point3[0], point3[1], vertices, &length); getLineVertex(point1[0], point1[1], point3[0], point3[1], vertices, &length); edge_equations(point1, point2, point3, vertices, &length); } else { //获取圆数据 getCircleVertex(originPoint[0], originPoint[1], radius, vertices, &length); } unsigned int VAO; unsigned int VBO; //必须先绑定VA0 glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); //再绑定VBO glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); //再设置属性 //位置属性 //属性位置值为0的顶点属性 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); processInput(window); //使用着色器程序 glUseProgram(shaderProgram); glfwPollEvents(); //清除屏幕 glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); //画imGUI if (isDrawLine) { createAndRenderLineImGUI(window, &show_window, point1, point2, point3, &isDrawLine); } else { createAndRenderCircleImGUI(window, &show_window, originPoint, &radius, &isDrawLine); } //画线段 //length是vertices的长度,而vertices三个元素为一个点 //glBindVertexArray(VAO); glDrawArrays(GL_POINTS, 0, length / 3); glfwSwapBuffers(window); glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); } glfwTerminate(); return 0; } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } } void getLineVertex(int x1, int y1, int x2, int y2, float vertices[MAX_LENGTH], int* length) { int x, y, endx, endy; float slope; //斜率 bool isSlopeExist = true; //确定起初点 if (x1 < x2) { x = x1; y = y1; endx = x2; endy = y2; } else { x = x2; y = y2; endx = x1; endy = y1; } //计算斜率 if (x == endx) { //斜率不存在 isSlopeExist = false; } else { slope = ((float)endy - (float)y) / ((float)endx - (float)x); } //初始点 vertices[*length] = normalize(x); (*length)++; vertices[*length] = normalize(y); (*length)++; vertices[*length] = 0.0f; (*length)++; if (isSlopeExist == false) { //斜率不存在时 int first; int last; if (y < endy) { first = y; last = endy; } else { first = endy; last = y; } for (int i = first; i <= last; i++) { vertices[*length] = normalize(x); (*length)++; vertices[*length] = normalize(i); (*length)++; vertices[*length] = 0.0f; (*length)++; } } else { //对称变换前,先把起始点移到原点,其它点移到对应位置 int moveX = x; int moveY = y; x = x - moveX; y = y - moveY; endx = endx - moveX; endy = endy - moveY; //对称变换 //利用对称变换,将画其他斜率线段转化为画斜率 0 <= <= 1的线段 if (slope > 1) { //第一象限上半部分 //起点不动,互换终点的x y int temp = endy; endy = endx; endx = temp; } else if (slope < 0 && slope >= -1) { //第二象限上半部分 //起点不动,终点的y变相反数 endy = -endy; } else if (slope < -1) { //第二象限下半部分 //起点不动,终点的y变相反数,然后互换终点的x y endy = -endy; int temp = endy; endy = endx; endx = temp; } int deltaX = abs(endx - x); int deltaY = abs(endy - y); int p = 2 * deltaY - deltaX; //只能画斜率 0 <= <= 1的线段 while (x <= endx) { if (p <= 0) { x = x + 1; y = y; p = p + 2 * deltaY; } else { x = x + 1; y = y + 1; p = p + 2 * deltaY - 2 * deltaX; } //利用对称变换,将斜率 0 <= <= 1的线段上的点转化为原来斜率线段上的点 if (slope > 1) { //第一象限上半部分 int temp = y; y = x; x = temp; } else if (slope < 0 && slope >= -1) { //第二象限上半部分 //起点不动,终点的y变相反数 y = -y; } else if (slope < -1) { //第二象限下半部分 //起点不动,互换x y, y变相反数 int temp = y; y = x; x = temp; y = -y; } //对称变换后,先把起始点移到原本位置,然后画出来 x = x + moveX; y = y + moveY; vertices[*length] = normalize(x); (*length)++; vertices[*length] = normalize(y); (*length)++; vertices[*length] = 0.0f; (*length)++; //画图后,再恢复起始点 x = x - moveX; y = y - moveY; //利用对称变换,恢复原来的点到斜率 0 <= <= 1的线段上,继续计算下一个点 if (slope > 1) { //第一象限上半部分 int temp = y; y = x; x = temp; } else if (slope < 0 && slope >= -1) { //第二象限上半部分 //起点不动,终点的y变相反数 y = -y; } else if (slope < -1) { //第二象限下半部分 //起点不动,y变相反数,互换x y y = -y; int temp = y; y = x; x = temp; } } } } void edge_equations(int point1[2], int point2[2], int point3[2], float vertices[MAX_LENGTH], int* length) { //求3条直线一般方程Ax+By+C=0的参数 //序号12为point1和point2的参数,序号23为point2和point3的参数,序号13为point1和point3的参数 int A12, B12, C12; int A23, B23, C23; int A13, B13, C13; A12 = point2[1] - point1[1]; B12 = point1[0] - point2[0]; C12 = point2[0] * point1[1] - point1[0] * point2[1]; A23 = point3[1] - point2[1]; B23 = point2[0] - point3[0]; C23 = point3[0] * point2[1] - point2[0] * point3[1]; A13 = point3[1] - point1[1]; B13 = point1[0] - point3[0]; C13 = point3[0] * point1[1] - point1[0] * point3[1]; //将三角形中点带入各直线,若结果小于0,则将参数A、B、C都乘以-1。 float middleX = ((float)point1[0] + (float)point2[0] + (float)point3[0]) / 3; float middleY = ((float)point1[1] + (float)point2[1] + (float)point3[1]) / 3; float temp = A12 * middleX + B12 * middleY + C12; if (temp < 0) { A12 = -A12; B12 = -B12; C12 = -C12; } temp = A23 * middleX + B23 * middleY + C23; if (temp < 0) { A23 = -A23; B23 = -B23; C23 = -C23; } temp = A13 * middleX + B13 * middleY + C13; if (temp < 0) { A13 = -A13; B13 = -B13; C13 = -C13; } //计算两条边分别于x轴和y轴平行的外接矩形 int leftX = myMin(point1[0], point2[0], point3[0]); int rightX = myMax(point1[0], point2[0], point3[0]); int topY = myMax(point1[1], point2[1], point3[1]); int bottomY = myMin(point1[1], point2[1], point3[1]); //遍历矩形,处理后的一般方程,三角形中的任意一个点代入3条曲线,都会使Ax+By+C的结果都大于0 for (int i = leftX; i <= rightX; i = i + 1) { for (int j = bottomY; j <= topY; j = j + 1) { if (A12 * i + B12 * j + C12 > 0 && A23 * i + B23 * j + C23 > 0 && A13 * i + B13 * j + C13 > 0) { //防止数组越界 if ((*length) >= MAX_LENGTH - 3) break; vertices[(*length)++] = normalize(i); vertices[(*length)++] = normalize(j); vertices[(*length)++] = 0.0f; } } } } void getCircleVertex(int originPointX, int originPointY, int radius, float vertices[MAX_LENGTH], int* length) { //移到原点,记录偏移量 int moveX = originPointX; int moveY = originPointY; int x = 0; int y = radius; int end = (int)(radius * 1.0 / (float)sqrt(2)); float d = 1.25 - radius; //加入初始点及对称的其它7个点 while (x <= end) { //加入新点及对称的其它7个点 vertices[(*length)++] = normalize(x + moveX); vertices[(*length)++] = normalize(y + moveY); vertices[(*length)++] = 0.0f; vertices[(*length)++] = normalize(y + moveX); vertices[(*length)++] = normalize(-x + moveY); vertices[(*length)++] = 0.0f; vertices[(*length)++] = normalize(-x + moveX); vertices[(*length)++] = normalize(-y + moveY); vertices[(*length)++] = 0.0f; vertices[(*length)++] = normalize(-y + moveX); vertices[(*length)++] = normalize(x + moveY); vertices[(*length)++] = 0.0f; vertices[(*length)++] = normalize(y + moveX); vertices[(*length)++] = normalize(x + moveY); vertices[(*length)++] = 0.0f; vertices[(*length)++] = normalize(x + moveX); vertices[(*length)++] = normalize(-y + moveY); vertices[(*length)++] = 0.0f; vertices[(*length)++] = normalize(-y + moveX); vertices[(*length)++] = normalize(-x + moveY); vertices[(*length)++] = 0.0f; vertices[(*length)++] = normalize(-x + moveX); vertices[(*length)++] = normalize(y + moveY); vertices[(*length)++] = 0.0f; vertices[(*length)++] = normalize(x + moveX); vertices[(*length)++] = normalize(y + moveY); vertices[(*length)++] = 0.0f; if (d <= 0) { x = x + 1; y = y; d = d + 2 * x + 2; } else { x = x + 1; y = y - 1; d = d + 2 * (x - y) + 5; } } } float normalize(int input) { float result = float(input) / WINDOW_SIZE; return result; } void initImGUI(GLFWwindow* window) { //创建并绑定ImGui const char* glsl_version = "#version 130"; IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; ImGui::StyleColorsDark(); ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init(glsl_version); } void createAndRenderLineImGUI(GLFWwindow* window, bool *show_window, int point1[2], int point2[2], int point3[2], bool *isDrawLine) { //创建imgui ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ImGui::Begin("Edit points", show_window, ImGuiWindowFlags_MenuBar); //ImGui::ColorEdit3("top color", (float*)&topColor); ImGui::Text("input 3 points"); ImGui::SliderInt2("point1", point1, -180, 180); ImGui::SliderInt2("point2", point2, -180, 180); ImGui::SliderInt2("point3", point3, -180, 180); if (ImGui::Button("Draw Circle")) (*isDrawLine) = false; ImGui::End(); ImGui::Render(); int display_w, display_h; glfwMakeContextCurrent(window); glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } void createAndRenderCircleImGUI(GLFWwindow* window, bool *show_window, int point[2], int *radius, bool *isDrawLine) { //创建imgui ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ImGui::Begin("Edit points", show_window, ImGuiWindowFlags_MenuBar); ImGui::Text("input 3 points"); ImGui::SliderInt2("point1", point, -WINDOW_SIZE, WINDOW_SIZE); ImGui::SliderInt("point1", radius, 0, WINDOW_SIZE); if (ImGui::Button("Draw Line")) (*isDrawLine) = true; ImGui::End(); ImGui::Render(); int display_w, display_h; glfwMakeContextCurrent(window); glfwGetFramebufferSize(window, &display_w, &display_h); glViewport(0, 0, display_w, display_h); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } int myMin(int a, int b, int c) { if (a < b) { if (a < c) { return a; } else { return c; } } else { if (b < c) { return b; } else { return c; } } } int myMax(int a, int b, int c) { if (a > b) { if (a > c) { return a; } else { return c; } } else { if (b > c) { return b; } else { return c; } } }
坚持原创技术分享,您的支持将鼓励我继续创作!