简单

行远必自迩,登高必自卑

量角器

编写过程

该程序借鉴了以前编写的时钟罗盘,以及参考官网上窗口技巧实现圆形窗口。实现了一个简单的量角器程序,可以通过量角器测量一些简单图形的角度弧度等信息。

编写灵感

我在绘制图形时,需要使用 arc 这个函数,但是该函数的参数获取比较麻烦,需要获得的弧的起始角度和终止角度。那这个角度如何获取呢,其实办法有很多,例如将要绘制的图像导入到 CAD 中直接就可以量,也可以用量角器量,或者手机下载软件来量,但是最终的麻烦程度超过了写一个程序所需要的时间。所以我索性编写了一个量角器,来解决编写程序过程中遇到的麻烦。程序本来就是来解决麻烦的,而不是制造麻烦的。

使用方式

鼠标左键长按到红色的圈上可以实现量角器的拖拽,左键点击外边红色的圈可以实现量测,右键点击红色的圈退出程序。

截图

量角器

源码

///////////////////////////////////////////////////
// 程序名称:量角器
// 编译环境:Mictosoft Visual Studio 2013, EasyX_20211109
// 作    者:luoyh <2864292458@qq.com>
// 学    校:河南理工大学
// 最后修改:2021-11-23
//

#include <graphics.h>
#include <conio.h>
#include<math.h>

#define PI acos(-1.0)
#define Width 600
#define Height 600

bool SetWindowTransparent(HWND hwnd, COLORREF crkcolor, BYTE bAlpha, DWORD dwFlags);
void SetWindowsForm(HWND hWnd);
// str代表绘制的字符串
// variable 代表每次的变量
// fors 每次需要循环的次数总数
// R 该圈的半径
// Long 刻度的长度
void DrawCircle(TCHAR str[25], int variable, int fors, int R);				// 绘制一圈字符	
void DrawKD(int variable, int fors, int R, int Long);						// 绘制刻度
void DrawProtractor();														// 绘制量角器					
void OutputDegrees(int x, int y);											// 输出刻度
double Distance(int x, int y);
double Azimuth(int star_x, int star_y, int end_x, int end_y);				// 计算方位角
void RadianToAngle(double Radian, int *Degree, int *Minute, int *Seconds);	// 弧度转角度

int main()
{
	initgraph(Width, Height);			// 初始化图形窗口
	HWND hWnd = GetHWnd();				// 获取窗口句柄
	SetWindowsForm(hWnd);				// 设置为窗口为圆形并透明
	DrawProtractor();					// 绘画量角器

	ExMessage m;						// 定义鼠标消息
	while (true)
	{
		m = getmessage(EM_MOUSE);		// 获取一条鼠标消息
		switch (m.message)
		{
		case WM_LBUTTONDOWN:
			// 如果左键按下,欺骗 windows 点在了标题栏上
			PostMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(m.x, m.y));
			if (Distance(m.x, m.y) >= (Height / 2 - 29) && Distance(m.x, m.y) <= (Height / 2 - 15))
			{
				cleardevice();
				DrawProtractor();
				OutputDegrees(m.x, m.y);
			}
			break;
		case WM_RBUTTONUP:				// 按鼠标右键退出程序
			closegraph();
			return 0;
		}
	}
}

bool SetWindowTransparent(HWND hwnd, COLORREF crkcolor, BYTE bAlpha, DWORD dwFlags)
{
	HINSTANCE hm = GetModuleHandle(_T("USER32.DLL"));
	if (hm)
	{
		FARPROC fun = GetProcAddress(hm, "SetLayeredWindowAttributes");
		bool (WINAPI *SetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD) = (bool (WINAPI*) (HWND, COLORREF, BYTE, DWORD))fun;
		if (SetLayeredWindowAttributes)
		{
			LONG ret = GetWindowLong(hwnd, GWL_EXSTYLE);
			ret |= WS_EX_LAYERED;
			SetWindowLong(hwnd, GWL_EXSTYLE, ret);
			SetLayeredWindowAttributes(hwnd, crkcolor, bAlpha, dwFlags);
		}
		FreeLibrary(hm);
		return true;
	}
	else
	{
		return false;
	}
}

void SetWindowsForm(HWND hWnd)
{
	setbkcolor(WHITE);
	cleardevice();
	// 获取窗口边框宽高
	RECT rcClient, rcWind;
	GetClientRect(hWnd, &rcClient);
	GetWindowRect(hWnd, &rcWind);
	int cx = ((rcWind.right - rcWind.left) - rcClient.right) / 2;
	int cy = ((rcWind.bottom - rcWind.top + GetSystemMetrics(SM_CYCAPTION)) - rcClient.bottom) / 2;
	// 设置圆形区域
	HRGN rgn = CreateEllipticRgn(0 + cx, 0 + cy, Width + cx, Height + cy);
	SetWindowRgn(hWnd, rgn, true);
	SetWindowTransparent(hWnd, WHITE, 100, 0x1);
	SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}

void DrawCircle(TCHAR str[25], int variable, int fors, int R)
{
	settextcolor(RED);
	double a, x0, y0, w, h, x1, y1;
	int x, y;
	settextstyle(22, 0, L"微软雅黑", variable * 3600 / fors, variable * 3600 / fors, 0, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH);
	a = variable * PI * 2 / fors;
	w = textwidth(str);																			// 计算字符串宽 w、高 h
	h = textheight(str);
	x1 = R * cos(a);																			// 计算输出字符串的左上角位置
	y1 = R * sin(a);
	x0 = x1 * cos(-a) - y1 * sin(-a);															// 将字符串绕原点顺时针旋转 a 弧度
	y0 = y1 * cos(-a) + x1 * sin(-a);
	x0 -= w / 2;																				// 将字符串向左上偏移 w/2、h/2
	y0 += h / 2;																				// 绘图坐标向下为正
	x = (int)(x0 * cos(a) - y0 * sin(a));														// 将字符串绕原点逆时针旋转 a 弧度
	y = (int)(y0 * cos(a) + x0 * sin(a));
	outtextxy(int(Width / 2 + x + 0.5), int(Height / 2 - y + 0.5), str);						// 绘图坐标向下为正
}

void DrawKD(int variable, int fors, int R, int Long)
{
	setlinecolor(RED);
	setlinestyle(PS_SOLID | PS_ENDCAP_SQUARE, 1);
	double a, x0, y0, x1, y1;
	double star_x, star_y;
	double end_x, end_y;
	a = variable * PI * 2 / fors;
	x1 = R * cos(a);
	y1 = R * sin(a);
	x0 = x1 * cos(-a) - y1 * sin(-a);
	y0 = y1 * cos(-a) + x1 * sin(-a);
	star_x = (x0 * cos(a) - y0 * sin(a));
	star_y = (y0 * cos(a) + x0 * sin(a));
	x1 = (R - Long) * cos(a);
	y1 = (R - Long) * sin(a);
	x0 = x1 * cos(-a) - y1 * sin(-a);
	y0 = y1 * cos(-a) + x1 * sin(-a);
	end_x = (x0 * cos(a) - y0 * sin(a));
	end_y = (y0 * cos(a) + x0 * sin(a));
	line((int)(Width / 2 + star_x), (int)(Width / 2 + star_y), (int)(Width / 2 + end_x), (int)(Width / 2 + end_y));
}

void DrawProtractor()
{
	setlinestyle(PS_SOLID, 2);
	setlinecolor(BLACK);
	circle(Width / 2, Height / 2, Height / 2 - 10);
	setlinestyle(PS_SOLID, 30);
	setlinecolor(LIGHTRED);
	circle(Width / 2, Height / 2, 90);
	setlinestyle(PS_SOLID, 14);
	circle(Width / 2, Height / 2, Height / 2 - 22);
	setlinecolor(BLACK);
	setlinestyle(PS_SOLID | PS_ENDCAP_SQUARE, 1);
	line(10, Height / 2, Width / 2 - 2, Height / 2);
	line(Width / 2 + 2, Height / 2, Width - 10, Height / 2);
	line(Width / 2, Height / 2 - 50, Width / 2, Height / 2 - 2);
	line(Width / 2, Height / 2 + 2, Width / 2, Height / 2 + 50);
	circle(Width / 2, Height / 2, 2);
	circle(Width / 2, Height / 2, 150);
	circle(Width / 2, Height / 2, 50);

	TCHAR str[25];
	for (int i = 0; i < 360; i++)
	{
		if (i % 10 == 0)
		{
			DrawKD(i / 10, 36, Height / 2 - 30, 30);
			DrawKD(i / 10, 36, 165, 30);
			DrawKD(i / 10, 36, 65, 15);
			_stprintf_s(str, _T("%d"), i);
			DrawCircle(str, i / 10, 36, Height / 2 - 75);
			continue;
		}
		if (i % 5 == 0)
		{
			DrawKD(i / 5, 72, Height / 2 - 30, 15);
			continue;
		}
		DrawKD(i, 360, Height / 2 - 30, 10);
	}
}

double Distance(int x, int y)
{
	return sqrt((double)((Width / 2.0 - x) * (Width / 2.0 - x) + (Height / 2.0 - y) * (Height / 2.0 - y)));
}

void OutputDegrees(int x, int y)
{
	setlinecolor(RED);
	setlinestyle(PS_SOLID | PS_ENDCAP_SQUARE, 1);
	line(x, y, Width / 2, Height / 2);
	double Radian = Azimuth(x, y, Width / 2, Height / 2);
	int Degree, Minute, Seconds;
	RadianToAngle(Radian, &Degree, &Minute, &Seconds);
	TCHAR str[20];
	settextcolor(BLACK);
	settextstyle(22, 0, L"微软雅黑", 0, 0, 0, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH);
	_stprintf_s(str, _T("%d°%d′%d″"), Degree, Minute, Seconds);
	setbkmode(TRANSPARENT);
	outtextxy(Width / 2 + 5, Height / 2 - 20, str);
	_stprintf_s(str, _T("%lfπ"), Radian);
	outtextxy(Width / 2 + 5, Height / 2, str);
}

double Azimuth(int star_x, int star_y, int end_x, int end_y)
{
	double radian, x, y;
	y = end_y - star_y;
	x = end_x - star_x;
	if (y == 0 && end_x > star_x) radian = PI;
	else if (y == 0 && end_x < star_x) radian = 0;
	else if (x == 0 && end_y > star_y) radian = PI / 2;
	else if (x == 0 && end_y < star_y) radian = 3 * PI / 2;
	else if (x > 0 && y > 0) radian = PI - atan(fabs(y) / fabs(x));
	else if (x < 0 && y > 0) radian = atan(fabs(y) / fabs(x));
	else if (x < 0 && y < 0) radian = 2 * PI - atan(fabs(y) / fabs(x));
	else if (x > 0 && y < 0) radian = PI + atan(fabs(y) / fabs(x));
	return radian;
}

void RadianToAngle(double Radian, int *Degree, int *Minute, int *Seconds)
{
	*Degree = int(Radian * 180 / PI);
	*Minute = int((Radian * 180 / PI - *Degree) * 60);
	*Seconds = int(((Radian * 180 / PI - *Degree) * 60 - *Minute) * 60);
}
分享到

添加评论