量角器
2021-11-23 ~ 2021-11-26
(0)
编写过程
该程序借鉴了以前编写的时钟罗盘,以及参考官网上窗口技巧实现圆形窗口。实现了一个简单的量角器程序,可以通过量角器测量一些简单图形的角度弧度等信息。
编写灵感
我在绘制图形时,需要使用 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);
}
添加评论
取消回复