正在自学Direct2D,于是决定写一个 小 程序:尺规作图。
实现功能:
- 绘制一个点
- 选择两点绘制一条直线
- 选择一点为圆心,再选一点为圆上的点,绘制一个圆
- 绘制一条直线上的一点
- 绘制一个圆上的一点
- 绘制两条直线的交点
- 绘制一条直线和一个圆的其中一个交点
- 绘制两个圆的其中一个交点
- 拖动一个点
- 拖动一个直线上的点时使它在直线上移动
- 拖动一个圆上的点时使它在圆上移动
- 拖动一个点时递归地改变与这个点有关的图形
- 交点不能移动
本次实现了功能1,9
includes(以后可能有改变,下同)#include
#include
#include
#include
#include
#pragma comment(lib, "d2d1")
点、直线和圆的表示方法
GRAPH *gg;
struct LINES {
LINES *l;
float k;
float b;
int p;
};
struct CIRCLES {
CIRCLES *c;
int p;
float r;
};
struct GRAPH {
int i;
D2D1_POINT_2F p;
GRAPH *g;
LINES *l;
CIRCLES *c;
};
三种结构都是链表,实际上是邻接链表。
GRAPH
|
GRAPH-LINES-LINES-...-nullptr
-CIRCLES-CIRCLES-...-nullptr
|
GRAPH-LINES-...-nullptr
-CIRCLES-...-nullptr
|
.
.
.
|
nullptr
gg链表第一元素,不储存信息
GRAPH::p点的坐标(DIP,device-independence pixel)
GRAPH::*g指向下一个GRAPH
添加点GRAPH *gp;
int gi;
void AddPoint(D2D1_POINT_2F p) {
gi += 1;
gp->g = new GRAPH;
gp = gp->g;
gp->c = nullptr;
gp->g = nullptr;
gp->l = nullptr;
gp->i = gi;
gp->p = p;
}
gp链表最后一元素,不储存信息
gi点的序号
创建主窗口WNDCLASSW gwc;
HWND ghw;
RECT grc;
float gs;
ID2D1Factory *gf;
ID2D1HwndRenderTarget *grt;
ID2D1SolidColorBrush *gb;
HRESULT hr;
gwc用于注册窗口
ghw主窗口handle
grcClientRect
gsPixel/DIP=DPI/96
gf,grt,gb,hr没什么好说的
BOOL Create(
HINSTANCE hi, int cs
) {
hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&gf
);
if (FAILED(hr)) {
MessageBoxW(
NULL,
L"Error Create Factory",
L"Error",
0
);
return FALSE;
}
gg = new GRAPH;
gg->c = nullptr;
gg->g = nullptr;
gg->l = nullptr;
gg->i = 0;
gg->p = {};
gp = gg;
gwc.lpfnWndProc = WindowProc;
gwc.hInstance = hi;
gwc.lpszClassName
= L"Ruler And Compass Main Window";
RegisterClassW(&gwc);
ghw = CreateWindowExW(
0,
gwc.lpszClassName,
L"Ruler And Compass",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, NULL, hi, NULL
);
if (!ghw) {
gf->Release();
MessageBoxW(
NULL, L"Error Create Window",
L"Error", 0
);
return FALSE;
}
ShowWindow(ghw, cs);
GetClientRect(ghw, &grc);
hr = gf->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
ghw,
D2D1::SizeU(
grc.right,
grc.bottom)
),
&grt
);
if (FAILED(hr)) {
gf->Release();
MessageBoxW(
NULL,
L"Error Create Render Target",
L"Error", 0
);
return FALSE;
}
hr = grt->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&gb
);
if (FAILED(hr)) {
gf->Release();
grt->Release();
MessageBoxW(
NULL,
L"Error Create Brush",
L"Error", 0
);
return FALSE;
}
float d;
d = GetDpiForWindow(ghw);
gs = d / 96.0f;
return TRUE;
}
int WINAPI wWinMain(
HINSTANCE hi,
HINSTANCE phi,
PWSTR cl,
int cs
) {
AllocConsole();
if (!Create(hi, cs)) {
return -1;
}
ShowWindow(ghw, cs);
AddPoint(D2D1::Point2F(100, 100));
AddPoint(D2D1::Point2F(200, 300));
MSG msg = {};
while (GetMessageW(&msg, ghw, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
gf->Release();
grt->Release();
gb->Release();
return 0;
}
WindowProc
LRESULT CALLBACK WindowProc(
HWND hw, UINT msg,
WPARAM wp, LPARAM lp
) {
switch (msg) {
case WM_QUIT:
DestroyWindow(hw);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
return OnPaint();
case WM_LBUTTONDOWN:
return OnLButtonDown(lp);
case WM_MOUSEMOVE:
return OnMouseMove(lp);
case WM_LBUTTONUP:
return OnLButtonUp();
case WM_SIZE:
return OnSize();
}
return DefWindowProc(hw, msg, wp, lp);
}
ptd(Pixel转DIP)
D2D1_POINT_2F ptd(int x, int y) {
D2D1_POINT_2F r;
r.x = x / gs;
r.y = y / gs;
return r;
}
OnLButtonDown(选中一个点)
GRAPH *gslt;
gslt被选中的点
LRESULT OnLButtonDown(LPARAM lp) {
int x, y;
float t1, t2;
x = GET_X_LPARAM(lp);
y = GET_Y_LPARAM(lp);
D2D1_POINT_2F p;
p = ptd(x, y);
_cprintf("(%.1f,%.1f)\n", p.x, p.y);
GRAPH *i = gg->g;
while (i) {
t1 = p.x - i->p.x;
t1 *= t1;
t2 = p.y - i->p.y;
t2 *= t2;
t1 += t2;
if (t1 <= 100) {
gslt = i;
break;
}
i = i->g;
}
return 0;
}
OnMouseMove(改变点的坐标)
LRESULT OnMouseMove(
LPARAM lp
) {
if (!gslt) return 0;
int x, y;
x = GET_X_LPARAM(lp);
y = GET_Y_LPARAM(lp);
D2D1_POINT_2F p;
p = ptd(x, y);
gslt->p = p;
InvalidateRect(ghw, NULL, FALSE);
return 0;
}
OnLButtonUp(取消选中点)
HRESULT OnLButtonUp() {
gslt = nullptr;
return 0;
}
OnPaint(绘制)
LRESULT OnPaint() {
if (!gf || !grt || !gb) return 0;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(ghw, &ps);
grt->BeginDraw();
grt->Clear(
D2D1::ColorF(D2D1::ColorF::White)
);
//DrawNet();
GRAPH *i = gg->g;
while (i) {
grt->FillEllipse(
D2D1::Ellipse(
i->p,
10, 10
),
gb
);
i = i->g;
}
hr = grt->EndDraw();
EndPaint(ghw, &ps);
if (FAILED(hr)
|| hr == D2DERR_RECREATE_TARGET) {
return -1;
}
return 0;
}
OnSize(这是个坑,没有这一步,图像会变形,也会影响检测是否点到了点)
LRESULT OnSize() {
if (grt) {
GetClientRect(ghw, &grc);
grt->Resize(D2D1::SizeU(
grc.right,
grc.bottom));
InvalidateRect(ghw, NULL, FALSE);
}
return 0;
}
至此,效果:
持续code中...
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)