Загрузка данных


#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

#define DX 60
#define DY 40
#define A_PARAM 2.4

typedef double (*MathFunc)(double);

static double g_xMin    = -1.0;
static double g_xMax    =  5.0;
static double g_yMin    = -5.0;
static double g_yMax    =  5.0;
static double g_mx      =  1.0;
static double g_my      =  1.0;
static int    g_func    =  0;
static BOOL   g_running = TRUE;
static double g_vals[1001];

static double f1(double x)
{
    if (x + 1.0 < 0.0 || fabs(x) < 1e-9) return NAN;
    return sqrt(x + 1.0) - A_PARAM / x;
}

static double f2(double x)
{
    double c = cos(x);
    return c * c;
}

static MathFunc get_func(void) { return g_func == 0 ? f1 : f2; }

static int cmp_dbl(const void *a, const void *b)
{
    double da = *(const double *)a, db = *(const double *)b;
    return (da > db) - (da < db);
}

static void compute_scale(HWND hwnd, MathFunc fn)
{
    RECT rc; GetClientRect(hwnd, &rc);
    int W = rc.right, H = rc.bottom;
    int N = 1000, cnt = 0;
    double dx = (g_xMax - g_xMin) / N;
    double x = g_xMin;

    for (int i = 0; i <= N; i++, x += dx) {
        double y = fn(x);
        if (!isnan(y) && !isinf(y)) g_vals[cnt++] = y;
    }

    if (cnt < 2) { g_yMin = -1.0; g_yMax = 1.0; }
    else {
        qsort(g_vals, cnt, sizeof(double), cmp_dbl);
        double lo = g_vals[(int)(cnt * 0.10)];
        double hi = g_vals[(int)(cnt * 0.90)];
        if (hi <= lo) { hi = lo + 1.0; lo -= 1.0; }
        double pad = (hi - lo) * 0.10;
        g_yMin = lo - pad;
        g_yMax = hi + pad;
    }

    g_mx = (double)(W - 2 * DX) / (g_xMax - g_xMin);
    g_my = (double)(H - 2 * DY) / (g_yMax - g_yMin);
}

static void Render(HWND hwnd, HDC hdc, MathFunc fn)
{
    RECT rc; GetClientRect(hwnd, &rc);
    int W = rc.right, H = rc.bottom;

    HBRUSH hBg = CreateSolidBrush(RGB(255, 255, 255));
    FillRect(hdc, &rc, hBg);
    DeleteObject(hBg);
    SetBkMode(hdc, TRANSPARENT);

    compute_scale(hwnd, fn);

    int osx = (g_yMin < 0.0 && g_yMax > 0.0)
        ? (int)(H - DY - g_my * (0.0 - g_yMin))
        : (g_yMin >= 0.0 ? H - DY : DY);

    int osy = (g_xMin < 0.0 && g_xMax > 0.0)
        ? (int)(DX + g_mx * (0.0 - g_xMin))
        : (g_xMin >= 0.0 ? DX : W - DX);

    HPEN pGrid = CreatePen(PS_DOT, 1, RGB(190, 190, 190));
    HPEN pOld  = (HPEN)SelectObject(hdc, pGrid);
    SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
    SetTextColor(hdc, RGB(80, 80, 80));

    char buf[32];
    double stepX = (g_xMax - g_xMin) / 10.0;
    double stepY = (g_yMax - g_yMin) / 10.0;

    double xv = g_xMin;
    for (int i = 0; i <= 10; i++, xv += stepX) {
        int    px = (int)(DX + g_mx * (xv - g_xMin));
        MoveToEx(hdc, px, DY, NULL);
        LineTo(hdc, px, H - DY);
        sprintf(buf, "%.1f", xv);
        int ty = osx + 8;
        if (ty > H - 18) ty = H - 18;
        if (ty < 4)      ty = 4;
        TextOutA(hdc, px - 14, ty, buf, (int)strlen(buf));
    }

    double yv = g_yMin;
    for (int i = 0; i <= 10; i++, yv += stepY) {
        int    py = (int)(H - DY - g_my * (yv - g_yMin));
        MoveToEx(hdc, DX, py, NULL);
        LineTo(hdc, W - DX, py);
        sprintf(buf, "%.2f", yv);
        int tx = osy + 6;
        if (tx > W - 55) tx = W - 55;
        if (tx < 2)      tx = 2;
        TextOutA(hdc, tx, py - 8, buf, (int)strlen(buf));
    }

    SelectObject(hdc, pOld);
    DeleteObject(pGrid);

    HPEN pAxis = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
    SelectObject(hdc, pAxis);

    MoveToEx(hdc, DX, osx, NULL);
    LineTo(hdc, W - DX, osx);
    MoveToEx(hdc, W - DX, osx, NULL); LineTo(hdc, W - DX - 10, osx - 5);
    MoveToEx(hdc, W - DX, osx, NULL); LineTo(hdc, W - DX - 10, osx + 5);
    TextOutA(hdc, W - DX + 4, osx - 10, "X", 1);

    MoveToEx(hdc, osy, H - DY, NULL);
    LineTo(hdc, osy, DY);
    MoveToEx(hdc, osy, DY, NULL); LineTo(hdc, osy - 5, DY + 10);
    MoveToEx(hdc, osy, DY, NULL); LineTo(hdc, osy + 5, DY + 10);
    TextOutA(hdc, osy + 6, DY - 16, "Y", 1);

    SelectObject(hdc, pOld);
    DeleteObject(pAxis);

    HRGN hClipRgn = CreateRectRgn(DX, DY, W - DX, H - DY);
    SelectClipRgn(hdc, hClipRgn);

    COLORREF col = (g_func == 0) ? RGB(0, 90, 200) : RGB(200, 0, 60);
    HPEN pCurve  = CreatePen(PS_SOLID, 2, col);
    SelectObject(hdc, pCurve);

    int N = (W - 2 * DX) * 3;
    if (N < 1500) N = 1500;

    int    first   = 1;
    double prev_py = 0.0;
    double dx = (g_xMax - g_xMin) / (double)N;
    double x = g_xMin;

    for (int i = 0; i <= N; i++, x += dx) {
        double y = fn(x);

        if (isnan(y) || isinf(y)) { first = 1; continue; }

        int px = (int)(DX + g_mx * (x - g_xMin));
        int py = (int)(H - DY - g_my * (y - g_yMin));

        if (!first && fabs((double)py - prev_py) > H * 0.75) { first = 1; }

        if (first) { MoveToEx(hdc, px, py, NULL); first = 0; }
        else        LineTo(hdc, px, py);

        prev_py = (double)py;
    }

    SelectObject(hdc, pOld);
    DeleteObject(pCurve);

    SelectClipRgn(hdc, NULL);
    DeleteObject(hClipRgn);

    SetTextColor(hdc, col);
    const char *fname = (g_func == 0)
        ? "f1(x) = sqrt(x+1) - 2.4/x"
        : "f2(x) = cos^2(x)";
    TextOutA(hdc, DX + 4, DY + 4, fname, (int)strlen(fname));

    SetTextColor(hdc, RGB(100, 100, 100));
    const char *hint = "+/- : masshtab    Left/Right : sdvig    Tab : smena funkcii    Esc : vyhod";
    TextOutA(hdc, DX, H - DY + 10, hint, (int)strlen(hint));

    char info[64];
    sprintf(info, "X: [%.2f, %.2f]", g_xMin, g_xMax);
    SetTextColor(hdc, RGB(60, 60, 60));
    TextOutA(hdc, W - 180, DY + 4, info, (int)strlen(info));
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    switch (msg) {
    case WM_KEYDOWN: {
        switch (wp) {
        case VK_LEFT: {
            double w = g_xMax - g_xMin;
            g_xMin -= 1.0;
            if (g_func == 0 && g_xMin < -1.0) {
                g_xMin = -1.0;
            }
            g_xMax = g_xMin + w;
            break;
        }
        case VK_RIGHT: {
            double w = g_xMax - g_xMin;
            g_xMin += 1.0;
            g_xMax = g_xMin + w;
            break;
        }
        case VK_ADD:    case VK_OEM_PLUS:
            if (g_xMax - g_xMin > 1.0) {
                g_xMin += 0.5;
                g_xMax -= 0.5;
            }
            break;
        case VK_SUBTRACT: case VK_OEM_MINUS:
            g_xMin -= 0.5;
            if (g_func == 0 && g_xMin < -1.0) {
                g_xMin = -1.0;
            }
            g_xMax += 0.5;
            break;
        case VK_TAB: {
            g_func = 1 - g_func;
            if (g_func == 0 && g_xMin < -1.0) {
                g_xMin = -1.0;
                g_xMax =  5.0;
            }
            break;
        }
        case VK_ESCAPE: DestroyWindow(hwnd); return 0;
        }
        InvalidateRect(hwnd, NULL, TRUE);
        break;
    }
    case WM_PAINT: {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        Render(hwnd, hdc, get_func());
        EndPaint(hwnd, &ps);
        break;
    }
    case WM_SIZE:
        InvalidateRect(hwnd, NULL, TRUE);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        g_running = FALSE;
        break;
    default:
        return DefWindowProcW(hwnd, msg, wp, lp);
    }
    return 0;
}

int main(void)
{
    printf("=== Lab. rabota No8. Variant 16 ===\n");
    printf("  f1(x) = sqrt(x+1) - %.1f/x\n", A_PARAM);
    printf("  f2(x) = cos^2(x)\n\n");

    while (1) {
        printf("Vvedite nachalo intervala po osi X (ne menshe -1): ");
        if (scanf("%lf", &g_xMin) != 1) { printf("Oshibka vvoda.\n"); return 1; }
        if (g_xMin < -1.0) { printf("Oshibka: nachalo ne mozhet byt menshe -1!\n"); continue; }
        printf("Vvedite konec  intervala po osi X: ");
        if (scanf("%lf", &g_xMax) != 1) { printf("Oshibka vvoda.\n"); return 1; }
        if (g_xMin < g_xMax) break;
        printf("Oshibka: nachalo dolzhno byt menshe konca!\n");
    }

    printf("\n+/-: masshtab | Left/Right: sdvig | Tab: smena func | Esc: vyhod\n\n");

    HINSTANCE hInst  = GetModuleHandleW(NULL);
    WNDCLASSW wc     = {0};
    wc.lpfnWndProc   = WndProc;
    wc.hInstance     = hInst;
    wc.lpszClassName = L"Lab8Graph";
    wc.hCursor       = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    RegisterClassW(&wc);

    HWND hwnd = CreateWindowExW(
        0, L"Lab8Graph",
        L"Lab. rabota No8 - Postroenie grafikov (Variant 16)",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        0, 0,
        GetSystemMetrics(SM_CXSCREEN),
        GetSystemMetrics(SM_CYSCREEN),
        NULL, NULL, hInst, NULL
    );
    if (!hwnd) return 1;

    ShowWindow(hwnd, SW_SHOWMAXIMIZED);
    UpdateWindow(hwnd);

    MSG msg;
    while (g_running && GetMessageW(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
    return 0;
}