// Fourier フーリエ級数展開
#define _USE_MATH_DEFINES
#include <Windows.h>
#include <tchar.h>
#include <math.h>
#include <vector>
using namespace std;
#define APP_NAME TEXT("Fourier")
#define YMAX 4
// 関数プロトタイプ宣言
void Trace(LPCTSTR format, ...);
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam);
void OnPaint(HWND hWnd);
void DrawLine(HDC hdc, RECT rc, vector<double> &f, COLORREF color);
// 外部変数
vector<double> fs; // f(t) source
vector<double> fd; // f(t) destination
//==============================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
{
// ウィンドウクラスの登録
WNDCLASSEX wcx;
ZeroMemory(&wcx, sizeof wcx);
wcx.cbSize = sizeof wcx;
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = WndProc;
wcx.hInstance = hInstance;
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcx.lpszClassName = APP_NAME;
if (RegisterClassEx(&wcx) == 0) {
return 0;
}
// ウィンドウの作成
HWND hWnd = CreateWindow(
APP_NAME, APP_NAME,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);
if (hWnd == NULL) {
return 0;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// メッセージループ
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
void Trace(LPCTSTR format, ...)
{
va_list arg_ptr;
TCHAR buffer[256];
int size;
va_start(arg_ptr, format);
size = _vsntprintf_s(buffer, _countof(buffer), _TRUNCATE, format, arg_ptr);
va_end(arg_ptr);
OutputDebugString(buffer);
if (size < 0) {
OutputDebugString(_T("...\n"));
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_PAINT:
OnPaint(hWnd);
return 0;
case WM_SIZE:
OnSize(hWnd, wParam, lParam);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void OnSize(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
WORD width = LOWORD(lParam);
WORD height = HIWORD(lParam);
Trace(_T("OnSize %u %u %u\n"), wParam, width, height);
if (wParam == SIZE_MINIMIZED) return;
// f(t) source
fs.clear();
for (int x = 0; x <= width; x++) {
double t = (2.0 * x / width - 1) * M_PI;
// int y = x < width / 2 ? -1 : 1;
fs.push_back(t);
}
// a0
double sum = 0;
for (int x = 0; x < width; x++) {
sum += fs[x];
}
double a0 = sum * (2 * M_PI / width) / (2 * M_PI);
Trace(_T("a0=%f\n"), a0);
fd.clear();
for (int x = 0; x <= width; x++) {
fd.push_back(a0);
}
// an, bn
for (int n = 1; n <= 15; n++) {
double an = 0;
double bn = 0;
for (int x = 0; x < width; x++) {
double t = (2.0 * x / width - 1) * M_PI;
an += fs[x] * cos(n * t);
bn += fs[x] * sin(n * t);
}
an = an * (2 * M_PI / width) / M_PI;
bn = bn * (2 * M_PI / width) / M_PI;
Trace(_T("n=%d an=%f bn=%f\n"), n, an, bn);
for (int x = 0; x <= width; x++) {
double t = (2.0 * x / width - 1) * M_PI;
fd[x] += an * cos(n * t) + bn * sin(n * t);
}
}
}
void OnPaint(HWND hWnd)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rc;
GetClientRect(hWnd, &rc);
Trace(_T("OnPaint %d %d %d %d\n"), rc.left, rc.top, rc.right, rc.bottom);
// 軸
MoveToEx(hdc, 0, rc.bottom / 2, NULL);
LineTo(hdc, rc.right, rc.bottom / 2);
MoveToEx(hdc, rc.right / 2, 0, NULL);
LineTo(hdc, rc.right / 2, rc.bottom);
// f(t)
DrawLine(hdc, rc, fs, RGB(0,0,255));
DrawLine(hdc, rc, fd, RGB(255,0,0));
EndPaint(hWnd, &ps);
}
void DrawLine(HDC hdc, RECT rc, vector<double> &f, COLORREF color)
{
HPEN pen = CreatePen(PS_SOLID, 0, color);
HGDIOBJ penOld = SelectObject(hdc, pen);
MoveToEx(hdc, 0, int(rc.bottom * (YMAX - f[0]) / (YMAX * 2)), NULL);
for (int x = 1; x <= rc.right; x++) {
LineTo(hdc, x, int(rc.bottom * (YMAX - f[x]) / (YMAX * 2)));
}
penOld = SelectObject(hdc, penOld);
DeleteObject(pen);
}