Ruler And Compass 1

Ruler And Compass 1,第1张

正在自学Direct2D,于是决定写一个 小 程序:尺规作图。


实现功能:

  1. 绘制一个点
  2. 选择两点绘制一条直线
  3. 选择一点为圆心,再选一点为圆上的点,绘制一个圆
  4. 绘制一条直线上的一点
  5. 绘制一个圆上的一点
  6. 绘制两条直线的交点
  7. 绘制一条直线和一个圆的其中一个交点
  8. 绘制两个圆的其中一个交点
  9. 拖动一个点
  10. 拖动一个直线上的点时使它在直线上移动
  11. 拖动一个圆上的点时使它在圆上移动
  12. 拖动一个点时递归地改变与这个点有关的图形
  13. 交点不能移动

本次实现了功能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中...

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/579914.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-11
下一篇 2022-04-11

发表评论

登录后才能评论

评论列表(0条)

保存