Загрузка данных
// ============================================================================
// БЛОК 1: ПОДКЛЮЧЕНИЕ БИБЛИОТЕК, КОНСТАНТЫ И ГЛОБАЛЬНЫЕ НАСТРОЙКИ
// ============================================================================
#include <windows.h>
#include <iostream>
#include <cmath>
using namespace std;
// Константа Пи для тригонометрических расчетов
const double PI = 3.14159265358979323846;
// Глобальные переменные для передачи настроек из консоли в графическое окно
int g_choice = 1;
int g_iterations = 0;
// ============================================================================
// БЛОК 2: МЕТОДЫ ПОСТРОЕНИЯ СНЕЖИНКИ КОХА
// ============================================================================
// Рекурсивная функция для построения одной линии (стороны) Коха
void drawKochLine(HDC hdc, double x1, double y1, double x2, double y2, int order) {
if (order == 0) {
// Базовый случай: итерации закончились, просто рисуем прямую линию
MoveToEx(hdc, round(x1), round(y1), NULL);
LineTo(hdc, round(x2), round(y2));
} else {
// Вычисляем координаты точек деления отрезка на 3 равные части
double xA = x1 + (x2 - x1) / 3.0;
double yA = y1 + (y2 - y1) / 3.0;
double xB = x1 + 2.0 * (x2 - x1) / 3.0;
double yB = y1 + 2.0 * (y2 - y1) / 3.0;
// Вычисляем координаты вершины треугольного выступа (поворот на 60 градусов)
double angle = 60.0 * PI / 180.0;
double xC = xA + (xB - xA) * cos(angle) + (yB - yA) * sin(angle);
double yC = yA - (xB - xA) * sin(angle) + (yB - yA) * cos(angle);
// Рекурсивный вызов для 4-х новых получившихся мини-отрезков
drawKochLine(hdc, x1, y1, xA, yA, order - 1);
drawKochLine(hdc, xA, yA, xC, yC, order - 1);
drawKochLine(hdc, xC, yC, xB, yB, order - 1);
drawKochLine(hdc, xB, yB, x2, y2, order - 1);
}
}
// Функция сборки полноценной снежинки из 3-х базовых сторон
void drawSnowflake(HDC hdc, int order) {
// Начальные координаты вершин правильного треугольника
double x1 = 200, y1 = 150;
double x2 = 600, y2 = 150;
double x3 = 400, y3 = 150 + 400 * sin(60.0 * PI / 180.0);
// Запуск процесса для каждой из трех сторон
drawKochLine(hdc, x1, y1, x2, y2, order);
drawKochLine(hdc, x2, y2, x3, y3, order);
drawKochLine(hdc, x3, y3, x1, y1, order);
}
// ============================================================================
// БЛОК 3: МЕТОДЫ ПОСТРОЕНИЯ КРИВОЙ СЕРПИНСКОГО
// ============================================================================
// Вспомогательная функция движения "черепашки" вперед с рисованием линии
void moveForward(HDC hdc, double &x, double &y, double angle, double distance) {
double x_new = x + distance * cos(angle * PI / 180.0);
double y_new = y - distance * sin(angle * PI / 180.0); // Минус, так как в Win32 ось Y идет вниз
MoveToEx(hdc, round(x), round(y), NULL);
LineTo(hdc, round(x_new), round(y_new));
// Обновляем текущее положение
x = x_new;
y = y_new;
}
// Рекурсивное построение извилистой кривой Серпинского
void drawSierpinskiCurve(HDC hdc, double &x, double &y, double &angle, int order, double distance, int sign) {
if (order == 0) {
moveForward(hdc, x, y, angle, distance);
} else {
// Поворот и рекурсивный шаг с инверсией направления (sign), чтобы фрактал не замыкался в спираль
angle += 60 * sign;
drawSierpinskiCurve(hdc, x, y, angle, order - 1, distance / 2, -sign);
angle -= 60 * sign;
drawSierpinskiCurve(hdc, x, y, angle, order - 1, distance / 2, sign);
angle -= 60 * sign;
drawSierpinskiCurve(hdc, x, y, angle, order - 1, distance / 2, -sign);
angle += 60 * sign;
}
}
// ============================================================================
// БЛОК 4: ГРАФИЧЕСКИЙ ДВИЖОК WINDOWS (ОБРАБОТКА И ОТРИСОВКА ОКНА)
// ============================================================================
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// Создаем черное перо для рисования линий толщиной в 1 пиксель
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
SelectObject(hdc, hPen);
// Отрисовка фрактала в зависимости от выбора пользователя
if (g_choice == 1) {
drawSnowflake(hdc, g_iterations);
} else if (g_choice == 2) {
// Стартовая позиция, угол и базовый размер для кривой Серпинского
double x = 200;
double y = 500;
double angle = 0;
double size = 400;
// Корректировка угла для сохранения правильной ориентации при нечетных итерациях
if (g_iterations % 2 != 0) {
angle += 60;
drawSierpinskiCurve(hdc, x, y, angle, g_iterations, size, -1);
} else {
drawSierpinskiCurve(hdc, x, y, angle, g_iterations, size, 1);
}
}
DeleteObject(hPen);
EndPaint(hwnd, &ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
// ============================================================================
// БЛОК 5: ГЛАВНЫЙ СИНХРОНИЗИРУЮЩИЙ МОДУЛЬ (ИНТЕРФЕЙС И ЗАПУСК)
// ============================================================================
int main() {
setlocale(LC_ALL, "Russian");
// 1. Консольное меню для ввода параметров пользователем
cout << "=== Программа построения фракталов (Win32) ===" << endl;
cout << "1. Снежинка Коха" << endl;
cout << "2. Кривая Серпинского" << endl;
cout << "Выберите фрактал (1 или 2): ";
cin >> g_choice;
if (g_choice != 1 && g_choice != 2) {
cout << "Ошибка: неверный выбор фрактала!" << endl;
return 1;
}
cout << "Введите количество итераций (рекомендуется от 0 до 5): ";
cin >> g_iterations;
if (g_iterations < 0) {
cout << "Ошибка: число итераций не может быть отрицательным!" << endl;
return 1;
}
cout << "\n[Успешно] Графическое окно запускается. Консоль можно сдвинуть." << endl;
// 2. Стандартная процедура создания окна Windows приложения
HINSTANCE hInstance = GetModuleHandle(NULL);
const wchar_t CLASS_NAME[] = L"FractalWindowClass";
WNDCLASSW wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // Установка белого фона
RegisterClassW(&wc);
// Создаем окно размером 800x600 пикселей
HWND hwnd = CreateWindowExW(
0, CLASS_NAME, L"Визуализация фракталов (Снежинка Коха / Кривая Серпинского)",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL
);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
// 3. Бесконечный цикл обработки системных сообщений окна
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}