【EasyX】快速入门——静态图形篇

1.基本说明

EasyX 是针对 C++ 的图形库,可以帮助 C/C++ 初学者快速上手图形和游戏编程。

比如,可以基于 EasyX 图形库很快的用几何图形画一个房子,或者一辆移动的小车,可以编写俄罗斯方块、贪吃蛇、黑白棋等小游戏,可以练习图形学的各种算法,等等。

许多人学编程都是从 C 语言入门的,而现状是:

  1. 有些学校以 Turbo C 为环境学习 C 语言,只是 Turbo C 实在太老了,复制粘贴都很不方便。
  2. 有些学校直接拿 VC 来讲 C 语言,因为 VC 的编辑和调试环境都很优秀,并且 VC 有适合教学的免费版本。可惜在 VC 里面只能做一些文字性的练习题,想画条直线或一个圆都很难,例如需要注册窗口类、建消息循环等等,初学者会受严重打击的。初学编程想要绘图就得用 TC,很是无奈。
  3. 还有计算机图形学,这门课程的重点是绘图算法,而不是 Windows 编程。所以,许多老师不得不用 TC 教学,因为 Windows 绘图太复杂了,会偏离教学的重点。新的图形学的书有不少是用的 OpenGL,可是门槛依然很高。

于是就有了这个 EasyX 库。如果您刚开始学 C 语言,或者您是一位教 C 语言的老师,再或者您在教计算机图形学,那么这个库一定会让您兴奋的。

2.系统支持

操作系统:Windows XP(sp3) 及以上操作系统。
编译环境:Visual C++ 6.0,Visual Studio 2008 至 Visual Studio 2022 (x86 & x64)。

3.安装——EasyX Graphics Library for C++

请下载最新版 EasyX 安装程序,直接运行,并跟随提示安装即可。

安装程序会自动检测您已经安装的 VC 版本,并根据您的选择将对应的 .h 和 .lib 文件安装至 VC 的 include 和 lib 文件夹内。安装程序不会修改注册表或者您本机的其它任何文件。

4.如何学习easyx 

其实学习easyx的最好的方法就是看它的文档——EasyX 文档 - 基本说明 

5.第一个程序

首先我们要知道easyx是使用C++语言的,所以我们创建的源文件应该是.cpp后缀的

同样我们使用的不是<stdio.h>的头文件了,我们使用的是<easyx.h>的文件,就像下面这样子

6.easyx快速入门之路(有点漫长,请耐心走完哦)

6.1.initgraph函数

这个函数用于初始化绘图窗口。

 

6.2.closegraph函数 

创建了窗体,我们肯定要关闭窗体

这个函数用于关闭绘图窗口。

我们直接上例子

#include<easyx.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	closegraph();
	return 0;
}

运行一下,我们发现窗体一闪而过,这是因为创建绘图窗体之后又立马关闭了,那怎么办呢?

我们可以使用getchar()暂时阻塞程序,等待用户按键后再关闭

getchar在<stdio.h>里面

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	getchar();
	closegraph();
	return 0;
}

 

 我们可以看到一个黑色的绘图窗体,按回车键就关闭了窗体

6.3circle函数

该函数使用当前画线样式绘制无填充的圆。

我们看个例子 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	circle(0, 0, 300);
	getchar();
	closegraph();
	return 0;
}

我丢,这个圆心怎么在窗体的最左上方?这是因为easyx的坐标系统的原因

6.4easyx的坐标系统

我们先看看官网怎么说

 再看看图

 我们之前画的圆形的圆心是(0,0),是逻辑坐标的默认值,所以圆心自然在左上方了

逻辑坐标的原点是可以移动的,我们可以修改逻辑坐标的原点移动到窗体的中间

6.5setorigin函数

我们举个例子

学会了这个,我们再去修改那个绘制圆的函数

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	circle(0, 0, 300);
	getchar();
	closegraph();
	return 0;
}

 我们看到啊,终于圆心位于正中央了!!

6.7setaspectratio函数

我们虽然把逻辑坐标的圆心改到了最中间的位置,但是y轴的方向和我们熟悉的轴线完全不一样。因此我们有必要去修改一下y轴的方向

 我们再完善一下上面那个代码

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	circle(0, 0, 300);
	getchar();
	closegraph();
	return 0;
}

 6.8putpixel函数

这个函数用于画点。

我们先了解下面这些颜色,更多的颜色表示我们不急 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	putpixel(0, 0, RED);
	putpixel(200, 200, YELLOW);
	putpixel(200, -200, CYAN);
	putpixel(-200, -200, GREEN);
	putpixel(-200, 200, WHITE);
	getchar();
	closegraph();
	return 0;
}

WHAT?点呢?不要慌张,因为一个点是一个像素大小,我们很难看见它们 

我们让效果更明显一点,我们随机生成100个点,x,y的坐标取值范围如下

 我们让效果更明显一点,我们随机生成100个点

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	int x, y;
	for (int i = 0; i < 1000; ++i)
	{
		x = rand() % (800 + 1) - 400;
		y = rand() % (600 + 1) - 300;
		putpixel(x, y, WHITE);
	}
	getchar();
	closegraph();
	return 0;
}

这个效果就非常明显了哈! 

6.9line函数

这个函数用于画直线。

举个例子 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	line(-200, 200, 200, -200);
	line(-200, -200, 200, 200);
	getchar();
	closegraph();
	return 0;
}

 6.10画多个圆

我们学会了用circle来画圆形,那我们加大一点难度

代码: 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	for (int r = 10; r <= 300; r += 10)
	{
		circle(0, 0, r);
	}
	getchar();
	closegraph();
	return 0;
}

 6.11rectangle函数

这个函数用于画无填充的矩形。

示例 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	rectangle(-200, 100, 200, -100);
	getchar();
	closegraph();
	return 0;
}

 看效果

 6.12ellipse函数

这个函数用于画无填充的椭圆。

举例: 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	ellipse(-200, 100, 200, -100);
	getchar();
	closegraph();
	return 0;
}

6.12roundrect函数 

这个函数用于画无填充的圆角矩形。

圆角矩形的样子如下 

 

我们举例

代码

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	roundrect(-200, 100, 200, -100,200,100);
	getchar();
	closegraph();
	return 0;
}

6.13pie函数

 绘制扇形

 注意是顺时针旋转单位为弧度

举例

代码

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	pie(-200, 100, 200, -100,0,PI/4);
	getchar();
	closegraph();
	return 0;
}

6.14arc函数 

绘制圆弧

举例

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	arc(-200, 100, 200, -100,0,PI/4);
	getchar();
	closegraph();
	return 0;
}

 7.绘制多边形

基本的函数我们掌握了,我们就玩点进阶的吧!

7.1绘制三角形

我们举个例子

代码

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	line(0, 200, 200, -200);
	line(200, -200, -200, -200);
	line(-200, -200, 0, 200);
	getchar();
	closegraph();
	return 0;
}

7.2polygon函数 

如果我们绘制多边形都要像上面那样子,就会很复杂,不过好在easyx有一个函数来帮我们绘制多边形,那就是polygon函数

我们看看这个POINT是个什么东西 

 举例

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	// 方法 1
	POINT pts[] = { {50, 200}, {200, 200}, {200, 50} };
	polygon(pts, 3);

	// 方法 2
	int pts2[] = { 0, 0,  100, 200,  200, 50 };
	polygon((POINT*)pts2, 3);

	getchar();
	closegraph();
	return 0;
}

 

7.3绘制矩形

 我们可以使用polygon函数来绘制矩形

假如我们要绘制下面这样一个图像

代码 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	// 方法 1
	POINT pts[] = { {-200,100}, {200, 100}, {200, -100},{-200,-100 } };
	polygon(pts, 4);
	getchar();
	closegraph();
	return 0;
}

7.4绘制梯形 

代码:

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	// 方法 1
	POINT pts[] = { {-100,100}, {100, 100}, {200, -100},{-200,-100 } };
	polygon(pts, 4);
	getchar();
	closegraph();
	return 0;
}

 7.5绘制五边形

绘制五边形比前面绘制四边形多了一个棘手的问题,就是我们很难确定五个点的坐标?

那我们可以使用三角函数来得到坐标

我们看看P1和P2是怎么求的

这个时候,敏锐的同学就会发现 我们可以通过一个循环来得到五个点的坐标,起始角度是90度,每次循环增加360/5=72度,就可以得到五个点的坐标

注意:sin和cos用的是弧度制,所以代码要用弧度制来

 代码:

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	double theta = PI / 2;//起始角度
	double delta = 2 * PI / 5;//每次循环增加的角度
	int r = 200;
	POINT points[5];
	for (int i = 0; i < 5; ++i)
	{
		points[i].x = cos(theta + i * delta) * r;
		points[i].y = sin(theta + i * delta) * r;
	}
	polygon(points, 5);
	getchar();
	closegraph();
	return 0;
}

7.6绘制不规则的图形 

我们可以使用polygon函数来绘制不规则图形

 例如我们可以绘制像下面这样一个多边形

代码

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	POINT points[8] = { {-400,0},{-200,200},{0,50},{200,200},
							{400,0},{200,150},{0,0},{-200,150} };
	polygon(points, 8);
	getchar();
	closegraph();
	return 0;
}

呢我们能不能画一个W呢?

答案是polygon函数不能,因为polygon函数会按顺序依次连接各个点最后会绘制一条P1到P5的线

7.7polyline函数

既然我们不能使用polygon来描绘出不封闭的图形W,我们可以使用polyline函数来绘制,这个函数和polygon的唯一区别就是它不会自动连接首尾两个点,

我们接着画上面那个W图形

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);//翻转y轴的方向
	POINT points[5] = { {-400,200},{-200,-200},{0,100},{200,-200},
							{400,200} };
	polyline(points, 5);
	getchar();
	closegraph();
	return 0;
}

8.形状的样式 

前面我们学习了一系列图形的函数,但是我们发现,它们都是白色的单一线条,那我们如何让这些图形丰富起来呢?

8.1仅描边图形样式

我们先复习一下画圆的代码

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	circle(0, 0, 300);
	getchar();
	closegraph();
	return 0;
}

我们可以发现它是仅由一条白线组成,而且圆的内部没有填充任何颜色

我们将图形边缘的线条称为图形的描边,描边的颜色默认为白色,包括我们之前学习的所有绘制图形的函数,都是如此。

8.2setlinecolor函数 

我们不想让描边的颜色是白色,我们可以使用setlinecolor函数来设置描边的颜色

我们来使用一下

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setlinecolor(RED);
	circle(0, 0, 300);
	getchar();
	closegraph();
	return 0;
}

 很好,描边变红色了。

8.3setlinestyle函数

我们觉得感觉样式也太单调了,那我们可以使用setlinestyle函数来改变描边的样式

这个函数用于设置当前设备画线样式

我们现在先重点关注前两个参数

先看第一个参数 ,参数 style 指定了画线样式,该样式由直线样式、端点样式、连接样式三类组成。可以是其中一类或多类的组合。同一类型中只能指定一个样式。

8.3.1线形样式

 掩码宏表示对应样式组所占用的所有位。例如,对于一个已经混合了多种样式的 style 变量,如果希望仅将直线样式修改为点划线,可以这么做:

style = (style & ~PS_STYLE_MASK) | PS_DASHDOT;

我们举个例子

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setlinestyle(PS_SOLID);
	circle(0, 0, 50);

	setlinestyle(PS_DASH);
	circle(0, 0, 100);

	setlinestyle(PS_DOT);
	circle(0, 0, 150);

	setlinestyle(PS_DASHDOT);
	circle(0, 0, 200);

	setlinestyle(PS_DASHDOTDOT);
	circle(0, 0, 250);

	setlinestyle(PS_NULL);
	circle(0, 0, 300);


	getchar();
	closegraph();
	return 0;
}

我丢,这谁看得清楚啊

这个时候,我们就可以使用第二个参数来设置线条的粗细

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setlinestyle(PS_SOLID,4);
	circle(0, 0, 50);

	setlinestyle(PS_DASH,4);
	circle(0, 0, 100);

	setlinestyle(PS_DOT,4);
	circle(0, 0, 150);

	setlinestyle(PS_DASHDOT,4);
	circle(0, 0, 200);

	setlinestyle(PS_DASHDOTDOT,4);
	circle(0, 0, 250);

	setlinestyle(PS_NULL,4);
	circle(0, 0, 300);


	getchar();
	closegraph();
	return 0;
}

 怎么样?够清晰了吧!

8.3.2端点样式

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);
	setlinestyle(PS_ENDCAP_ROUND, 16);
	line(-300, 200, 300, 200);

	setlinestyle(PS_ENDCAP_SQUARE, 16);
	line(-300, 150, 300, 150);

	setlinestyle(PS_ENDCAP_SQUARE, 16);
	line(-300, 100, 300, 100);

	getchar();
	closegraph();
	return 0;
}

 8.3.3连接样式

 代码

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);
	setlinestyle(PS_JOIN_BEVEL,64);
	POINT point1[3] = { {-150,100},{0,200},{150,100} };
	polyline(point1, 3);

	setlinestyle(PS_JOIN_MITER,64);
	POINT point2[3] = { {-150,0},{0,100},{150,0} };
	polyline(point2, 3);

	setlinestyle(PS_JOIN_ROUND,64);
	POINT point3[3] = { {-150,-100},{0,0},{150,-100} };
	polyline(point3, 3);

	getchar();
	closegraph();
	return 0;
}

 8.4.仅填充图形样式

在之前学习的封闭图形的时候,我们发现里面都是空的,那么我们可以来进行填充

这些函数和使用描边绘制图形函数基本一模一样,唯一的区别就是在函数名前加solid

例如我们要绘制有填充的图形样式,就要使用solidcircle函数

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);
	solidcircle(0, 0, 100);

	getchar();
	closegraph();
	return 0;
}

我们发现这个默认填充颜色是白色,那我们如何修改这个填充颜色呢?

8.4.1setfillcolor函数 

这个函数是来设置填充颜色的

我们可以对上面的代码进行改进

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);

	setfillcolor(YELLOW);
	solidcircle(0, 0, 100);

	getchar();
	closegraph();
	return 0;
}

8.5描边加填充图形样式 

前面我们学习了仅描边或者仅填充的样式,那如果我既想让它有描边样式,又有填充样式,我们该怎么办呢

很简单,仅在函数名前加fill

代码 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);

	setlinecolor(RED);
	setlinestyle(PS_DASH, 12);
	setfillcolor(YELLOW);
	fillcircle(0, 0, 200);

	getchar();
	closegraph();
	return 0;
}

 8.6设置背景色——setbkcolor

例如,我们想把我们的背景设置为白色

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);

	setbkcolor(WHITE);

	getchar();
	closegraph();
	return 0;
}

什么,怎么还是黑色的?

我们看看文档

我靠,原来如此

我们改进一下

8.7cleardevice函数

使用这个函数,代表之前绘制的一切东西都会被清空 

有了这个我们就能对上面的进行改进了

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);

	setbkcolor(WHITE);
	cleardevice();

	getchar();
	closegraph();
	return 0;
}

我靠,成功了!! 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);

	setbkcolor(WHITE);
	cleardevice();

	setfillcolor(BLUE);
	solidcircle(0, 0, 300);

	getchar();
	closegraph();
	return 0;
}

9.颜色模型 

在此之前,我们用的颜色都是easyx已经定义好的颜色

但是这些颜色还是具有很多局限性的,无法表示更多丰富多彩的颜色样式

9.1RGB颜色模型

不知道大家有没有近距离的观察过屏幕,我们就会发现屏幕居然是由很多红点,绿点,蓝点组成的,其他颜色均是由这三种颜色混合而成的。其实啊,这个是因为显示器使用了人眼的三原色原理

我们将每种原色从弱到强分为256等分 

这个时候我们将不同比例的原色进行混合,就可以形成各种各样的颜色

此外,颜色值也可以使用三原色份数的十六进制数进行组合表示

 那么,我们在代码中怎么使用RGB颜色模型呢?

在easyx中,提供了一个名为RGB的函数

有人就好奇了,这个BYTE是个啥?我们看

又有人好奇了这个COLORREF是个啥?

很好!!接下来我们就来使用这个函数

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体

	setbkcolor(RGB(134, 172, 242));
	cleardevice();

	getchar();
	closegraph();
	return 0;
}

成功啦!!哈哈 

9.2.HSV颜色模型

我们看下面这个

我们把三原色放在圆形的三等分点处,然后按与三原色的距离来分配不同颜色的比例,就能得到像下面这样一个色环

我们发现,每一个角度都代表一种颜色,这个就叫色相,此外,HSV颜色模型还提供了两个参数,用于控制颜色的鲜艳程度和明暗程度,它们分别为饱和度和明度。

例如,我们选取色相为240度,就是蓝色,选取不同饱和度,明度,我们得到的颜色也不同

 饱和度下降,越靠近白色,明度下降,越靠近黑色,明度有时候也叫亮度,所以HSV和HSB是一个东西

但是显示屏是使用三原色原理制作的,HSV模型无法使用于显示屏

但是我们可以使用HSV模式选好颜色,再将其转换为RGB模式,就可以显示在屏幕上

9.2.1.HSVtoRGB函数

该函数将HSV颜色转换为RGB颜色

我们可以使用在线拾色器选取一个颜色,然后将其转换为RGB颜色

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体

	setbkcolor(HSVtoRGB(219,0.45,0.95));
	cleardevice();

	getchar();
	closegraph();
	return 0;
}

9.3.绘制彩虹窗体 

我们怎么做才能得到彩虹色的背景呢?

其实很简单,我们只需要环绕色环转一圈即可

也就是色相从0开始到360度逐渐递增变化,明度饱和度选100%就可以了

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体

	float dH = 360.0 / 600.0;
	float h = 0;
	for (int y = 0; y < 600; ++y)
	{
		setlinecolor(HSVtoRGB(h, 1, 1));
		line(0, y, 800, y);
		h += dH;
	}

	getchar();
	closegraph();
	return 0;
}

9.4.绘制蓝天,彩虹 

我们想画下面这样子的图

那我们要怎么做呢?

我们线画渐变色的蓝天吧!很简单,把图拆分为600条线(因为宽是600像素)

 看代码

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	
	float s = 0.76;
	float ds = s/600;
	
	for (int y = 0; y < 600; ++y)
	{
		setlinecolor(HSVtoRGB(216, s, 0.95));
		line(0, y, 800, y);
		s -= ds;
	}

	getchar();
	closegraph();
	return 0;
}

我丢,这么美 ,得抓紧画彩虹了,彩虹很简单

我们看代码 

#include<easyx.h>
#include<stdio.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	
	float s = 0.76;
	float ds = s/600;
	
	for (int y = 0; y < 600; ++y)
	{
		setlinecolor(HSVtoRGB(216, s, 0.95));
		line(0, y, 800, y);
		s -= ds;
	}
	float h = 0;
	float dh = 360.0 / 100.0;
	for (int r = 300; r >= 200; --r)
	{
		setlinecolor(HSVtoRGB(h, 1, 1));
		circle(400, 600, r);
		h += dh;
	}
	getchar();
	closegraph();
	return 0;
}

10.剪切区域 

我们希望能用圆形画出像下面这样一朵花

很明显,这是许多个等半径的圆形组成的,圆心都位于内部圆形的六等分处,我们就可以使用三角函数来得到圆心的坐标

我们直接上代码 

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);//设置逻辑坐标的原点
	setaspectratio(1, -1);
	
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 10);
	
	int r = 150;
	circle(0, 0, r);

	for (int i = 0; i < 6; ++i)
	{
		int x = cos(i * (2 * PI / 6)) * r;
		int y=sin(i * (2 * PI / 6)) * r;
		circle(x,y,r);
	}

	getchar();
	closegraph();
	return 0;
}

这不就是小case吗!!!哈哈哈

现在我们有新需求,我们只要中间这个圆形,其他的不要

那我们怎么做呢?

这就需要学习新知识了——剪切区域

10.1剪切区域

我们在绘制前设置剪切区域,绘制在剪切区域的图形将被保留,绘制在剪切区域的图形将被抛弃

注意:必须先建立剪切区域,再调用绘图函数

回到上面那个问题,我们可以先建立一个剪切区域

这样子白色部分的将被保留,其他的将被删除

10.2.创建区域

我们怎么创建剪切区域呢?

easyx并没有直接提供创建区域的函数,因此我们需要借助Windows GDI

我们一个一个来好好看看

 

我们发现,这些函数和它们对应的图形绘制函数的参数形式一模一样 ,实际上,它们分别和对应的绘制函数的用法也是一模一样的

注意:剪切区域是以物理坐标为坐标系的

由于没有直接绘制圆形的函数,我们可以使用绘制椭圆的

10.3设置剪切区域——setcliprgn函数

小兄弟,光创建了区域还不行,我们还得把它设置成剪切区域才行!!!

而setcliprgn刚好是用来干这个活的

很好,万事具备,只欠东风,我们开写

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);
	setaspectratio(1, -1);
	
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 10);
	
	int r = 150;
	HRGN rgn = CreateEllipticRgn(250, 150, 550, 450);//创建区域
	setcliprgn(rgn);//将创建的区域设置为剪切区域

	circle(0, 0, r);

	for (int i = 0; i < 6; ++i)
	{
		int x = cos(i * (2 * PI / 6)) * r;
		int y=sin(i * (2 * PI / 6)) * r;
		circle(x,y,r);
	}

	setcliprgn(NULL);//将剪切区域设为空
	DeleteObject(rgn);//销毁区域

	getchar();
	closegraph();
	return 0;
}

注意绘图完成后,要将剪切区域设为空,并且要删除创建的区域

我靠,就这?太简单了吧!!别急,更厉害的还在后面,加油吧,少年

10.4.CombineRgn函数

区域之间可以进行集合运算并组合 ,我们可以使用CombineRgn函数来组合区域,这个函数也不是easyx自带的,所以用的也是物理坐标

这个函数是让源区域1和源区域2按照某种组合模式(第四个参数)进行组合得到新的剪切区域

组合模式如下

第一个参数是没有什么太大的意义的,但是它必须是一个存在的区域,它是用来承接组合后的区域的

接下来我们就举几个例子来看看怎么使用组合区域

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);
	setaspectratio(1, -1);
	
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 10);
	
	int r = 150;
	HRGN rgn1 = CreateEllipticRgn(250, 250, 550, 550);//创建区域
	HRGN rgn2 = CreateEllipticRgn(250, 100, 550, 400);//创建区域
	HRGN rgn = CreateEllipticRgn(0,0,0,0);//创建区域
	
	CombineRgn(rgn, rgn1, rgn2, RGN_AND);
	setcliprgn(rgn);

	circle(0, 0, r);

	for (int i = 0; i < 6; ++i)
	{
		int x = cos(i * (2 * PI / 6)) * r;
		int y=sin(i * (2 * PI / 6)) * r;
		circle(x,y,r);
	}

	setcliprgn(NULL);//将剪切区域设为空
	DeleteObject(rgn);//销毁区域
	DeleteObject(rgn1);//销毁区域
	DeleteObject(rgn2);//销毁区域

	getchar();
	closegraph();
	return 0;
}

 

我们接下来看并集的

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);
	setaspectratio(1, -1);
	
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 10);
	
	int r = 150;
	HRGN rgn1 = CreateEllipticRgn(250, 250, 550, 550);//创建区域
	HRGN rgn2 = CreateEllipticRgn(250, 100, 550, 400);//创建区域
	HRGN rgn = CreateEllipticRgn(0,0,0,0);//创建区域
	
	CombineRgn(rgn, rgn1, rgn2, RGN_OR);
	setcliprgn(rgn);

	circle(0, 0, r);

	for (int i = 0; i < 6; ++i)
	{
		int x = cos(i * (2 * PI / 6)) * r;
		int y=sin(i * (2 * PI / 6)) * r;
		circle(x,y,r);
	}

	setcliprgn(NULL);//将剪切区域设为空
	DeleteObject(rgn);//销毁区域
	DeleteObject(rgn1);//销毁区域
	DeleteObject(rgn2);//销毁区域

	getchar();
	closegraph();
	return 0;
}

 

我们看看并集排除重叠区域

#define PI 3.14
#include<easyx.h>
#include<stdio.h>
#include<math.h>
int main()
{
	initgraph(800, 600);//创建了800*600像素的窗体
	setorigin(400, 300);
	setaspectratio(1, -1);
	
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID, 10);
	
	int r = 150;
	HRGN rgn1 = CreateEllipticRgn(250, 250, 550, 550);//创建区域
	HRGN rgn2 = CreateEllipticRgn(250, 100, 550, 400);//创建区域
	HRGN rgn = CreateEllipticRgn(0,0,0,0);//创建区域
	
	CombineRgn(rgn, rgn1, rgn2, RGN_XOR);
	setcliprgn(rgn);

	circle(0, 0, r);

	for (int i = 0; i < 6; ++i)
	{
		int x = cos(i * (2 * PI / 6)) * r;
		int y=sin(i * (2 * PI / 6)) * r;
		circle(x,y,r);
	}

	setcliprgn(NULL);//将剪切区域设为空
	DeleteObject(rgn);//销毁区域
	DeleteObject(rgn1);//销毁区域
	DeleteObject(rgn2);//销毁区域

	getchar();
	closegraph();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/629836.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

类和对象的特性

1.检查错误。 代码&#xff1a; #include <iostream>using namespace std;class Time { private:/* data */ public:Time(/* args */);~Time();void set_time(void);void show_time(void);int hour;int minute;int sec; };Time::Time(/* args */) { }Time::~Time() { }T…

Java环境搭配(一)JDK下载以及介绍、path环境变量配置

目录 JDK Development Kit &#xff08;JDK&#xff09; 下载 JDK介绍 &#xff1a; JDK 包括以下主要组件 配置path环境变量 在cmd上打印Helloworld JDK Development Kit &#xff08;JDK&#xff09; 下载 下载官方地址 www.oracle.com 进入网址后&#xff1a; 点击产…

指针在函数的应用(C++)

一、传递地址 实参传递进函数体内后&#xff0c;生成的是实参的副本&#xff0c;在函数内改变副本的值并不影响实参。指针传递参数时&#xff0c;指针变量产生了副本&#xff0c;但副本与原变量指向的内存区域是同一个。改变指针副本指向的变量&#xff0c;就是改变原指针变量指…

快速查看字符对应的ASCII码

1、借助gdb查看 打印字符串用双引号括起来打印单个字符用单引号括起来x 表示十六机制d 表示十进制t 表示二进制 2、借助二进制查看软件 第一步&#xff1a;把要查看的字符保存到文本文件中第二步&#xff1a;借助二进制查看工具&#xff08;比如&#xff1a;Hex Editor Neo&am…

字节跳动在2024年春季火山引擎Force原动力大会上隆重推出了“豆包大模型”家族

此次大会以AI为主题&#xff0c;聚焦大模型的应用与发展&#xff0c;旨在引领AI技术的落地和推动各行各业的数字化转型。 字节跳动官网&#xff1a;https://www.bytedance.com/zh/ 豆包官网&#xff1a;https://www.doubao.com/chat/ 更多消息&#xff1a;https://heehel.co…

Redis实战—验证码登录注册

目录 基于Session Controller层 Service层 ServiceImpl层 ​编辑校验登录状态 ThreadLocal 登录拦截器 添加拦截器到Config Controller层实现 基于Redis ServiceImpl 新增刷新拦截器 添加拦截器到Config 基于Session Controller层 /*** 发送手机验证码*/PostMappi…

ROS 手眼标定 realsense435i+ur5e

手眼标定的原理 基坐标系&#xff08;base_tree&#xff09;和相机&#xff08;camera_tree&#xff09;两个坐标系属于不同的tree&#xff0c;通过将标签贴到手上&#xff0c;相机识别出标签的position和orention&#xff0c;并通过easy_handeye标定包得到tool0(机械手)&…

Java面试八股之HashMap和HashTable有什么区别

Java中HashMap和HashTable有什么区别 线程安全性&#xff1a; HashMap&#xff1a;非线程安全。在多线程环境下&#xff0c;如果没有采取适当的同步措施&#xff0c;直接并发访问可能会导致数据不一致、死锁等问题。如果需要在多线程环境中安全地使用HashMap&#xff0c;通常…

中国开源 AI 大模型之光-InternLM2

今天给大家带来 AI 大模型领域的国产之光 - InternLM2&#xff0c;在10B量级开源大模型领域取得了全球 Top 3 的成绩&#xff0c;仅次于 Meta 发布的 Llama-3&#xff0c;在国内则是第一名的存在&#xff01; 简介 InternLM2是由上海人工智能实验室和商汤科技联合研发的一款大型…

【软件测试】需求概念|软件的⽣命周期|开发模型|测试模型

目录 推荐 一、什么是需求 1.1 ⽤⼾需求 1.2 软件需求 二、开发模型 2.1 什么是“模型” 2.2 软件的⽣命周期 2.3 常⻅开发模型 2.3.1 瀑布模型 2.3.2 螺旋模型 2.3.3 增量模型、迭代模型 2.3.4 敏捷模型 2.4 测试模型 2.4.1 V模型 2.4.2 W模型(双V模型&#xff0…

安装ArcGIS失败,提示无效驱动器Error1327.Invalid Drive G错误

安装ArcGIS的时候&#xff0c;出现图中错误该怎么解决呢&#xff1f; Error 1327.Invalid Drive:G:\ 即错误代码&#xff1a;1327。无效驱动器G盘 出现以上问题的原因是 注册表中包含了该硬盘驱动器或网络驱动器的引用 但是在我的电脑中又没有该盘符 一般是已经卸载或者更换…

NSSCTF | [SWPUCTF 2021 新生赛]easyupload2.0

先传一个普通的一句话木马试一试 GIF89a <?php eval($_POST[shell]);?> 可以看到回显&#xff0c;不允许上传php文件。 使用Burpsuite抓包只修改ContentType后发现也不能绕过&#xff0c;说明服务器使用了黑名单后缀限制&#xff0c;那么我们可以使用其他的后缀代替ph…

dubbo复习:(3) 服务超时时间配置

在dubbo admin中 可以进行类似如下配置 configVersion: v2.7 enabled: true configs:- side: consumeraddresses:- 0.0.0.0parameters:timeout: 55这样配置之后&#xff0c;当服务端响应超过55毫秒时&#xff0c;在服务消费者的控制台就会看到超时信息

鸿蒙应用布局ArkUI:【其他常用布局容器和组件】介绍

其他常用布局容器和组件 创建轮播&#xff08;Swiper&#xff09;实现轮播图功能 开发前请熟悉鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。 栅格布局&#xff08;GridRow/GridCol&#xff09;和Grid布局类似…

TiDB学习1:TiDB体系架构概览

目录 1. TiDB体系结构 2. TiDBsever 3. TiKV 4. PD(Placement Driver) 5. TiFlash 1. TiDB体系结构 水平扩容或者缩容金融级高可用实时 HTAP云原生的分布式数据库兼容MySQ 5.7 协议 2. TiDBsever 处理客户端的连接SQL语句的解析和编译关系型数据与 kv 的转化(insert语句)S…

2024自学网络安全的三个必经阶段(含路线图)_网络安全自学路线

一、为什么选择网络安全&#xff1f; 这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来3-5年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏入…

Postman基础功能-返回值获取

大家好&#xff0c;之前给大家分享关于Postman的接口关联&#xff0c;我们平时在做接口测试时&#xff0c;请求接口返回的数据都是很复杂的 JSON 数据&#xff0c;有着多层嵌套&#xff0c;这样的数据层级在 Postman 中要怎么获取呢&#xff1f; 接下来给大家展示几个获取 JSO…

腾讯中视频项目,日均收益1000+,简单搬运无限做,执行就有收入

兄弟们今天给大家分享的项目-腾讯视频的中视频计划项目&#xff0c;项目简单&#xff0c;低门槛&#xff0c;不需要考虑带货等问题&#xff0c;是2024年目前最火的变现赛道了。 因为目前来说的话&#xff0c;腾讯视频中视频是刚开始启动&#xff0c;是项目的红利期&#xff0c;…

在抖音做电商,没有货源,不懂直播怎么办?分享一种解决方案!

大家好&#xff0c;我是电商糖果 糖果做电商的时间也挺久了&#xff0c;天猫&#xff0c;京东&#xff0c;闲鱼都搞过。 从学校进入社会工作&#xff0c;创业&#xff0c;一直都是围绕电商打转。 做的时间久了&#xff0c;好像只会做这一件事儿了。 2020年开始专攻抖音小店&…

Galxe已投资Pencils Protocol,投资者阵营正不断扩大

近日&#xff0c;Scroll 生态项目 Penpad 将品牌进一步升级为 Pencils Protocol&#xff0c;全新升级后其不仅对 LaunchPad 平台进行了功能上的升级&#xff0c;同时其也进一步引入了 Staking、Vault 以及 Shop 等玩法&#xff0c;这也让 Pencils Protocol 的叙事方向不再仅限于…