Blog Entry © Sunday, January 25, 2026, by James Pate Williams, Jr., Schwarzschild Solution of Einstein’s General Relativity Gravitational Field Equation

Blog Entry © Wednesday, October 29, 2025, by James Pate Williams, Jr. Hydrogenic Atomic Spectral Lines

// HydrogenSpectralLines.cpp : Defines the entry point for the application.
//

#include "pch.h"
#include "framework.h"
#include "HydrogenSpectralLines.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
WCHAR buffer[32768], line[128], line1[128], line2[512];
double c = 299792458;
double h = 4.135667696e-15;

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_HYDROGENSPECTRALLINES, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_HYDROGENSPECTRALLINES));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex = { };

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HYDROGENSPECTRALLINES));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_HYDROGENSPECTRALLINES);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

#define IDC_COMPUTE_BUTTON  1010
#define IDC_CANCEL_BUTTON   1020
#define IDC_CLEAR_BUTTON    1030
#define IDC_EDIT_MULTILINE  1040

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HFONT hFont = nullptr;
    static HWND hCombo1 = nullptr;
    static HWND hCombo2 = nullptr;
    static HWND hCombo3 = nullptr;
    static HWND hCombo4 = nullptr;
    static HWND hEditMultiline = nullptr;

    switch (message)
    {
    case WM_CREATE:
        CreateWindowEx(0, L"STATIC", L"Series:", WS_CHILD | WS_VISIBLE,
            10, 10, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
        hCombo1 = CreateWindowEx(0, L"COMBOBOX", nullptr,
            WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL |
            ES_AUTOVSCROLL, 120, 10, 200, 100, hWnd, nullptr, hInst, nullptr);
        CreateWindowEx(0, L"STATIC", L"n2:", WS_CHILD | WS_VISIBLE,
            10, 40, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
        hCombo2 = CreateWindowEx(0, L"COMBOBOX", nullptr,
            WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL |
            ES_AUTOVSCROLL, 120, 40, 120, 150, hWnd, nullptr, hInst, nullptr);
        CreateWindowEx(0, L"STATIC", L"atom:", WS_CHILD | WS_VISIBLE,
            10, 70, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
        hCombo3 = CreateWindowEx(0, L"COMBOBOX", nullptr,
            WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL |
            ES_AUTOVSCROLL, 120, 70, 120, 150, hWnd, nullptr, hInst, nullptr);
        CreateWindowEx(0, L"STATIC", L"formula:", WS_CHILD | WS_VISIBLE,
            10, 100, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL);
        hCombo4 = CreateWindowEx(0, L"COMBOBOX", nullptr,
            WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST | WS_VSCROLL |
            ES_AUTOVSCROLL, 120, 100, 120, 150, hWnd, nullptr, hInst, nullptr);
        CreateWindowEx(0, L"BUTTON", L"Compute", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            10, 140, 80, 30, hWnd, (HMENU)IDC_COMPUTE_BUTTON, hInst, NULL);
        CreateWindowEx(0, L"BUTTON", L"Cancel", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            10, 180, 80, 30, hWnd, (HMENU)IDC_CANCEL_BUTTON, hInst, NULL);
        CreateWindowEx(0, L"BUTTON", L"Clear", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            10, 220, 80, 30, hWnd, (HMENU)IDC_CLEAR_BUTTON, hInst, NULL);
        hFont = CreateFont(16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
            UNICODE, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
            DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Courier New");
        hEditMultiline = CreateWindowEx(
            WS_EX_CLIENTEDGE,                       // Extended style for sunken border
            TEXT("EDIT"),                           // Class name
            TEXT(""),                               // Initial text (can be blank)
            WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_AUTOHSCROLL |
            ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | WS_HSCROLL | WS_VSCROLL,
            340, 10, 640, 400,                      // Position and size
            hWnd,                                   // Parent window handle
            (HMENU)IDC_EDIT_MULTILINE,              // Unique control ID
            hInst,                                  // Application instance
            NULL                                    // Extra parameter
        );
        SendMessage(hCombo1, WM_SETFONT, (WPARAM)hFont, 0);
        SendMessage(hCombo2, WM_SETFONT, (WPARAM)hFont, 0);
        SendMessage(hCombo3, WM_SETFONT, (WPARAM)hFont, 0);
        SendMessage(hCombo4, WM_SETFONT, (WPARAM)hFont, 0);
        SendMessage(hEditMultiline, WM_SETFONT, (WPARAM)hFont, 0);
        SendMessage(hCombo1, CB_ADDSTRING, 0, (LPARAM)L"Lyman    n1 = 1 n2 >= 2");
        SendMessage(hCombo1, CB_ADDSTRING, 0, (LPARAM)L"Balmer   n1 = 2 n2 >= 3");
        SendMessage(hCombo1, CB_ADDSTRING, 0, (LPARAM)L"Paschen  n1 = 3 n2 >= 4");
        SendMessage(hCombo1, CB_ADDSTRING, 0, (LPARAM)L"Brackett n1 = 4 n2 >= 5");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"2");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"3");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"4");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"5");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"6");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"7");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"8");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"9");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"10");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"11");
        SendMessage(hCombo2, CB_ADDSTRING, 0, (LPARAM)L"12");
        SendMessage(hCombo1, CB_SETCURSEL, 0, 0);
        SendMessage(hCombo3, CB_ADDSTRING, 0, (LPARAM)L"hydrogen");
        SendMessage(hCombo3, CB_ADDSTRING, 0, (LPARAM)L"helium+");
        SendMessage(hCombo3, CB_ADDSTRING, 0, (LPARAM)L"lithium++");
        SendMessage(hCombo4, CB_ADDSTRING, 0, (LPARAM)L"energy eV");
        SendMessage(hCombo4, CB_ADDSTRING, 0, (LPARAM)L"frequency Hz");
        SendMessage(hCombo4, CB_ADDSTRING, 0, (LPARAM)L"wavelength A");
        SendMessage(hCombo1, CB_SETCURSEL, 0, 0);
        SendMessage(hCombo2, CB_SETCURSEL, 0, 0);
        SendMessage(hCombo3, CB_SETCURSEL, 0, 0);
        SendMessage(hCombo4, CB_SETCURSEL, 0, 0);
        buffer[0] = L'\0';
        break;
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDC_COMPUTE_BUTTON:
            {
                int n1 = 0, n2 = 0;
                WCHAR series[16] = { 0 };

                if (hCombo1)
                {
                    GetWindowText(hCombo1, line, 128);
                }

                if (std::wcsstr(line, L"Lyman"))
                {
                    wcscpy_s(series, L"Lyman");
                    n1 = 1;
                }
                
                else if (std::wcsstr(line, L"Balmer"))
                {
                    wcscpy_s(series, L"Balmer");
                    n1 = 2;
                }

                else if (std::wcsstr(line, L"Paschen"))
                {
                    wcscpy_s(series, L"Paschen");
                    n1 = 3;
                }

                else if (std::wcsstr(line, L"Brackett"))
                {
                    wcscpy_s(series, L"Brackett");
                    n1 = 4;
                }

                if (hCombo2)
                {
                    GetWindowText(hCombo2, line, 128);
                    std::wstring n2Str(line);
                    n2 = stoi(n2Str);
                }

                if (n2 < n1 + 1)
                {
                    MessageBox(hWnd, L"n2 must be greater than equal n1 + 1",
                        L"Warning", MB_OK | MB_ICONWARNING);
                    break;
                }

                double Z = 1.0;
                GetWindowText(hCombo3, line, 128);

                if (wcscmp(line, L"hydrogen") == 0)
                {
                    Z = 1.0;
                }

                else if (wcscmp(line, L"helium+") == 0)
                {
                    Z = 2.0;
                }

                else if (wcscmp(line, L"lithium++") == 0)
                {
                    Z = 3.0;
                }

                double deltaE = -13.6 * Z * Z * (1.0 / (n1 * n1) - 1.0 / (n2 * n2));
                double nu = deltaE / h;
                double lambda = c / nu / 1.0e-10;
                double number = deltaE;
    
                GetWindowText(hCombo4, line1, 128);

                if (wcscmp(line1, L"energy eV") == 0)
                {
                    number = deltaE;
                }

                else if (wcscmp(line1, L"frequency Hz") == 0)
                {
                    number = nu;
                }

                else if (wcscmp(line1, L"wavelength A") == 0)
                {
                    number = lambda;
                }

                swprintf_s(line2, L"%s\t%s\t%s\t%d\t%d\t%lf\r\n",
                    series, line, line1, n1, n2, number);
                wcscat_s(buffer, line2);

                if (hEditMultiline)
                {
                    SetWindowText(hEditMultiline, buffer);
                }

                break;
            }
            case IDC_CLEAR_BUTTON:
                buffer[0] = '\0';
                SetWindowText(hEditMultiline, buffer);
                break;
            case IDC_CANCEL_BUTTON:
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

Blog Entry © Thursday, September 11, 2025, by James Pate Wiliams, Jr. Modeling the Friedmann Equation in the Early Universe

Blog Entry © Sunday, August 24, 2025, by James Pate Williams, Jr. Corrections to New Quantum Chemical Total Molecular Ground-State Energies for the Helium Hydride Cation (a Hetero Nuclear molecule) and the Hydrogen Molecule (a Homo Nuclear Molecule)

Blog Entry © Friday, August 22, 2025, by James Pate Williams, Jr. New Quantum Chemical Total Molecular Ground-State Energies for the Helium Hydride Cation (a Hetero Nuclear molecule) and the Hydrogen Molecule (a Homo Nuclear Molecule)

Blog Entry © Monday, August 18, 2025, by James Pate Williams, Jr. Curve Fitting Contracted Gaussian Type 1s Orbitals (CGTO-1s) to a Slater Type 1s Orbital

Blog Entry © Saturday, August 16, 2025, by James Pate Williams, Jr. Some More Elementary Quantum Chemistry

Newtonian Gravity and Cosmology © Friday, July 18, 2025, by James Pate Williams, Jr. in Conjunction with the Microsoft Copilot AI

Some General Relativity Mathematics by James Pate Williams, Jr. (c) July 13, 2025

// SomeRelativityMath.cpp : Defines the entry point for the application.
// https://arxiv.org/pdf/2506.09946

#include "pch.h"
#include "framework.h"
#include "SomeRelativityMath.h"
#include <stdio.h>
#include <vector>

#define MAX_LOADSTRING 100

typedef struct tagPoint2d
{
    double x, y;
} POINT2D, * PPOINT2D;

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
char text[8192];
std::vector<POINT2D> points1, points2;
std::vector<POINT2D> points3, points4;

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    DrawGraph(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_SOMERELATIVITYMATH, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SOMERELATIVITYMATH));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex = { 0 };

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SOMERELATIVITYMATH));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_SOMERELATIVITYMATH);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

static void FindMinMax(
    double& xMin, double& xMax,
    double& yMin, double& yMax)
{
    // uses global 2D double points structure

    xMin = yMin = DBL_MAX;
    xMax = yMax = DBL_MIN;

    for (size_t i = 0; i < points1.size(); i++)
    {
        POINT2D pt = points1[i];
        double x = pt.x;
        double y = pt.y;

        if (x < xMin)
            xMin = x;
        if (x > xMax)
            xMax = x;
        if (y < yMin)
            yMin = y;
        if (y > yMax)
            yMax = y;
    }

    for (size_t i = 0; i < points2.size(); i++)
    {
        POINT2D pt = points2[i];
        double x = pt.x;
        double y = pt.y;

        if (x < xMin)
            xMin = x;
        if (x > xMax)
            xMax = x;
        if (y < yMin)
            yMin = y;
        if (y > yMax)
            yMax = y;
    }

    for (size_t i = 0; i < points3.size(); i++)
    {
        POINT2D pt = points3[i];
        double x = pt.x;
        double y = pt.y;

        if (x < xMin)
            xMin = x;
        if (x > xMax)
            xMax = x;
        if (y < yMin)
            yMin = y;
        if (y > yMax)
            yMax = y;
    }

    for (size_t i = 0; i < points4.size(); i++)
    {
        POINT2D pt = points4[i];
        double x = pt.x;
        double y = pt.y;

        if (x < xMin)
            xMin = x;
        if (x > xMax)
            xMax = x;
        if (y < yMin)
            yMin = y;
        if (y > yMax)
            yMax = y;
    }
}

static void DrawFormattedText(HDC hdc, char text[], RECT rect)
{
    // Draw the text with formatting options
    DrawTextA(hdc, text, -1, &rect, DT_SINGLELINE | DT_NOCLIP);
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
    {
        double P1 = 0, P2 = 0, P3 = 0, P4 = 0;
        int numberPts = 1024;
        double x0 = 1, h = 0.5 / numberPts, x = x0;

        points1.resize(numberPts);
        points2.resize(numberPts);
        points3.resize(numberPts);
        points4.resize(numberPts);

        for (int i = 0; i < numberPts; i++)
        {
            P1 = x + 1.0;
            P2 = 3.0 * x * x + 4.0 * x + 2.0;
            P3 = 15.0 * x * x * x + 16.0 * x * x + 6.0 * x;
            P4 = 105.0 * x * x * x * x + 156.0 * x * x * x +
                94.0 * x * x + 24.0 * x;
            POINT2D pt = { 0 };
            pt.x = x;
            pt.y = log(P1);
            points1[i] = pt;
            pt.y = log(P2);
            points2[i] = pt;
            pt.y = log(P3);
            points3[i] = pt;
            pt.y = log(P4);
            points4[i] = pt;
            x += h;
        }
        break;
    }
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
    {
        double h = 0, pi = 0, plm = 0, theta = 0;
        double xMax = 0, xMin = 0, yMax = 0, yMin = 0;
        FindMinMax(xMin, xMax, yMin, yMax);
        float xSpan = (float)(xMax - xMin);
        float ySpan = (float)(yMax - yMin);
        RECT rect = { };
        GetClientRect(hWnd, &rect);
        float width = (float)(rect.right - rect.left + 1);
        float height = (float)(rect.bottom - rect.top - 32 + 1);
        float sx0 = 2.0f * width / 16.0f;
        float sx1 = 14.0f * width / 16.0f;
        float sy0 = 2.0f * height / 16.0f;
        float sy1 = 14.0f * height / 16.0f;
        float deltaX = xSpan / 8.0f;
        float deltaY = ySpan / 8.0f;
        float xSlope = (sx1 - sx0) / xSpan;
        float xInter = (float)(sx0 - xSlope * xMin);
        float ySlope = (sy0 - sy1) / ySpan;
        float yInter = (float)(sy0 - ySlope * yMax);
        float px = 0, py = 0, sx = 0, sy = 0;
        PAINTSTRUCT ps;
        POINT wPt = { };
        HDC hdc = BeginPaint(hWnd, &ps);
        int i = 0;
        float x = (float)xMin;
        float y = (float)yMax;
        px = x;
        py = y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        MoveToEx(hdc, (int)sx, (int)sy0, &wPt);
        char buffer[128] = { };

        while (i <= 8)
        {
            sx = xSlope * x + xInter;
            wPt.x = wPt.y = 0;
            MoveToEx(hdc, (int)sx, (int)sy0, &wPt);
            LineTo(hdc, (int)sx, (int)sy1);

            sprintf_s(buffer, "%3.2f", x);
            SIZE size = { };
            GetTextExtentPoint32A(
                hdc,
                buffer,
                strlen(buffer),
                &size);
            RECT textRect = { };
            textRect.left = (long)(sx - size.cx / 2.0f);
            textRect.right = (long)(sx + size.cx / 2.0f);
            textRect.top = (long)sy1;
            textRect.bottom = (long)(sy1 + size.cy / 2.0f);
            DrawFormattedText(hdc, buffer, textRect);
            x += deltaX;
            i++;
        }

        i = 0;
        y = (float)yMin;

        while (i <= 8)
        {
            sy = ySlope * y + yInter;
            wPt.x = wPt.y = 0;
            MoveToEx(hdc, (int)sx0, (int)sy, &wPt);
            LineTo(hdc, (int)sx, (int)sy);

            if (i != 0)
            {
                sprintf_s(buffer, "%3.1f", y);
                SIZE size = { };
                GetTextExtentPoint32A(
                    hdc,
                    buffer,
                    strlen(buffer),
                    &size);
                RECT textRect = { };
                textRect.left = (long)(sx0 - size.cx - size.cx / 5.0f);
                textRect.right = (long)(sx0 - size.cx / 2.0f);
                textRect.top = (long)(sy - size.cy / 2.0f);
                textRect.bottom = (long)(sy + size.cy / 2.0f);
                DrawFormattedText(hdc, buffer, textRect);
            }

            y += deltaY;
            i++;
        }

        HGDIOBJ rPenNew = NULL;
        HGDIOBJ hPenOld = NULL;
        rPenNew = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
        hPenOld = SelectObject(hdc, rPenNew);

        px = (float)points1[0].x;
        py = (float)points1[0].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        for (size_t j = 1; j < points1.size(); j++)
        {
            px = (float)points1[j].x;
            py = (float)points1[j].y;
            sx = xSlope * px + xInter;
            sy = ySlope * py + yInter;
            LineTo(hdc, (int)sx, (int)sy);
        }

        SelectObject(hdc, hPenOld);
        DeleteObject(rPenNew);

        HGDIOBJ gPenNew = CreatePen(PS_SOLID, 2, RGB(0, 255, 0));
        hPenOld = SelectObject(hdc, gPenNew);

        px = (float)points2[0].x;
        py = (float)points2[0].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        for (size_t j = 1; j < points2.size(); j++)
        {
            px = (float)points2[j].x;
            py = (float)points2[j].y;
            sx = xSlope * px + xInter;
            sy = ySlope * py + yInter;
            LineTo(hdc, (int)sx, (int)sy);
        }

        SelectObject(hdc, hPenOld);
        DeleteObject(gPenNew);

        HGDIOBJ bPenNew = CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
        hPenOld = SelectObject(hdc, bPenNew);

        px = (float)points3[0].x;
        py = (float)points3[0].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        for (size_t j = 1; j < points3.size(); j++)
        {
            px = (float)points3[j].x;
            py = (float)points3[j].y;
            sx = xSlope * px + xInter;
            sy = ySlope * py + yInter;
            LineTo(hdc, (int)sx, (int)sy);
        }

        SelectObject(hdc, hPenOld);
        DeleteObject(bPenNew);

        HGDIOBJ pPenNew = CreatePen(PS_SOLID, 2, RGB(128, 0, 128));
        hPenOld = SelectObject(hdc, pPenNew);

        px = (float)points4[0].x;
        py = (float)points4[0].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        for (size_t j = 1; j < points4.size(); j++)
        {
            px = (float)points4[j].x;
            py = (float)points4[j].y;
            sx = xSlope * px + xInter;
            sy = ySlope * py + yInter;
            LineTo(hdc, (int)sx, (int)sy);
        }

        SelectObject(hdc, hPenOld);
        DeleteObject(pPenNew);

        EndPaint(hWnd, &ps);
    }
    break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

static INT_PTR CALLBACK DrawGraph(
    HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    char line[256] = { };
    switch (message)
    {
    case WM_INITDIALOG:
        GetWindowTextA(hDlg, line, 256);
        strcat_s(text, 8192, " ");
        strcat_s(text, 8192, line);
        SetWindowTextA(hDlg, text);
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    case WM_PAINT:
        double h = 0, pi = 0, plm = 0, theta = 0;
        double xMax = 0, xMin = 0, yMax = 0, yMin = 0;
        FindMinMax(xMin, xMax, yMin, yMax);
        float xSpan = (float)(xMax - xMin);
        float ySpan = (float)(yMax - yMin);
        RECT rect = { };
        GetClientRect(hDlg, &rect);
        float width = (float)(rect.right - rect.left + 1);
        float height = (float)(rect.bottom - rect.top - 32 + 1);
        float sx0 = 2.0f * width / 16.0f;
        float sx1 = 14.0f * width / 16.0f;
        float sy0 = 2.0f * height / 16.0f;
        float sy1 = 14.0f * height / 16.0f;
        float deltaX = xSpan / 8.0f;
        float deltaY = ySpan / 8.0f;
        float xSlope = (sx1 - sx0) / xSpan;
        float xInter = (float)(sx0 - xSlope * xMin);
        float ySlope = (sy0 - sy1) / ySpan;
        float yInter = (float)(sy0 - ySlope * yMax);
        float px = 0, py = 0, sx = 0, sy = 0;
        PAINTSTRUCT ps;
        POINT wPt = { };
        HDC hdc = BeginPaint(hDlg, &ps);
        int i = 0;
        float x = (float)xMin;
        float y = (float)yMax;
        px = x;
        py = y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        MoveToEx(hdc, (int)sx, (int)sy0, &wPt);
        char buffer[128] = { };

        while (i <= 8)
        {
            sx = xSlope * x + xInter;
            wPt.x = wPt.y = 0;
            MoveToEx(hdc, (int)sx, (int)sy0, &wPt);
            LineTo(hdc, (int)sx, (int)sy1);

            sprintf_s(buffer, "%3.0f", x);
            SIZE size = { };
            GetTextExtentPoint32A(
                hdc,
                buffer,
                strlen(buffer),
                &size);
            RECT textRect = { };
            textRect.left = (long)(sx - size.cx / 2.0f);
            textRect.right = (long)(sx + size.cx / 2.0f);
            textRect.top = (long)sy1;
            textRect.bottom = (long)(sy1 + size.cy / 2.0f);
            DrawFormattedText(hdc, buffer, textRect);
            x += deltaX;
            i++;
        }

        i = 0;
        y = (float)yMin;

        while (i <= 8)
        {
            sy = ySlope * y + yInter;
            wPt.x = wPt.y = 0;
            MoveToEx(hdc, (int)sx0, (int)sy, &wPt);
            LineTo(hdc, (int)sx, (int)sy);

            if (i != 0)
            {
                sprintf_s(buffer, "%3.0f", y);
                SIZE size = { };
                GetTextExtentPoint32A(
                    hdc,
                    buffer,
                    strlen(buffer),
                    &size);
                RECT textRect = { };
                textRect.left = (long)(sx0 - size.cx - size.cx / 5.0f);
                textRect.right = (long)(sx0 - size.cx / 2.0f);
                textRect.top = (long)(sy - size.cy / 2.0f);
                textRect.bottom = (long)(sy + size.cy / 2.0f);
                DrawFormattedText(hdc, buffer, textRect);
            }

            y += deltaY;
            i++;
        }

        HGDIOBJ rPenNew = NULL;
        HGDIOBJ hPenOld = NULL;
        rPenNew = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
        hPenOld = SelectObject(hdc, rPenNew);

        px = (float)points1[1].x;
        py = (float)points1[1].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        for (size_t j = 1; j < points1.size(); j++)
        {
            px = (float)points1[j].x;
            py = (float)points1[j].y;
            sx = xSlope * px + xInter;
            sy = ySlope * py + yInter;
            LineTo(hdc, (int)sx, (int)sy);
        }

        SelectObject(hdc, hPenOld);
        DeleteObject(rPenNew);

        px = (float)points2[1].x;
        py = (float)points2[1].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        HGDIOBJ gPenNew = CreatePen(PS_SOLID, 2, RGB(0, 255, 0));
        hPenOld = SelectObject(hdc, gPenNew);
        px = (float)points2[1].x;
        py = (float)points2[1].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        for (size_t j = 1; j < points2.size(); j++)
        {
            px = (float)points2[j].x;
            py = (float)points2[j].y;
            sx = xSlope * px + xInter;
            sy = ySlope * py + yInter;
            LineTo(hdc, (int)sx, (int)sy);
        }

        SelectObject(hdc, hPenOld);
        DeleteObject(gPenNew);

        px = (float)points3[1].x;
        py = (float)points3[1].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        HGDIOBJ bPenNew = CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
        hPenOld = SelectObject(hdc, bPenNew);
        px = (float)points3[1].x;
        py = (float)points3[1].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        for (size_t j = 1; j < points3.size(); j++)
        {
            px = (float)points3[j].x;
            py = (float)points3[j].y;
            sx = xSlope * px + xInter;
            sy = ySlope * py + yInter;
            LineTo(hdc, (int)sx, (int)sy);
        }

        SelectObject(hdc, hPenOld);
        DeleteObject(bPenNew);

        px = (float)points4[1].x;
        py = (float)points4[1].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        HGDIOBJ tPenNew = CreatePen(PS_SOLID, 2, RGB(128, 0, 128));
        hPenOld = SelectObject(hdc, tPenNew);
        px = (float)points4[1].x;
        py = (float)points4[1].y;
        sx = xSlope * px + xInter;
        sy = ySlope * py + yInter;
        wPt.x = wPt.y = 0;
        MoveToEx(hdc, (int)sx, (int)sy, &wPt);

        for (size_t j = 1; j < points4.size(); j++)
        {
            px = (float)points4[j].x;
            py = (float)points4[j].y;
            sx = xSlope * px + xInter;
            sy = ySlope * py + yInter;
            LineTo(hdc, (int)sx, (int)sy);
        }

        SelectObject(hdc, hPenOld);
        DeleteObject(tPenNew);

        EndPaint(hDlg, &ps);
        return (INT_PTR)FALSE;
        break;
    }

    return (INT_PTR)FALSE;
}