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


#include <iostream>
#include <vector>
#include <cmath>
#include <fstream>
#include <cstdint>
#include <string>

// Структуры BMP без выравнивания
#pragma pack(push, 1)

struct BMPFileHeader {
    uint16_t file_type{0x4D42}; // BM
    uint32_t file_size{0};
    uint16_t reserved1{0};
    uint16_t reserved2{0};
    uint32_t offset_data{54};
};

struct BMPInfoHeader {
    uint32_t size{40};
    int32_t width{0};
    int32_t height{0};
    uint16_t planes{1};
    uint16_t bit_count{24};
    uint32_t compression{0};
    uint32_t size_image{0};
    int32_t x_pixels_per_meter{0};
    int32_t y_pixels_per_meter{0};
    uint32_t colors_used{0};
    uint32_t colors_important{0};
};

#pragma pack(pop)

// =====================================
// Класс изображения
// =====================================

class Image {
private:
    int width;
    int height;
    std::vector<uint8_t> pixels;

public:
    Image(int w, int h)
        : width(w), height(h), pixels(w * h * 3, 0) {}

    void setPixel(int x, int y, uint32_t color) {
        if (x < 0 || x >= width || y < 0 || y >= height)
            return;

        int index = (y * width + x) * 3;

        pixels[index]     = color & 0xFF;          // Blue
        pixels[index + 1] = (color >> 8) & 0xFF;  // Green
        pixels[index + 2] = (color >> 16) & 0xFF; // Red
    }

    // Алгоритм Брезенхема
    void drawLine(int x0, int y0, int x1, int y1, uint32_t color) {
        int dx = std::abs(x1 - x0);
        int sx = x0 < x1 ? 1 : -1;

        int dy = -std::abs(y1 - y0);
        int sy = y0 < y1 ? 1 : -1;

        int err = dx + dy;

        while (true) {
            setPixel(x0, y0, color);

            if (x0 == x1 && y0 == y1)
                break;

            int e2 = 2 * err;

            if (e2 >= dy) {
                err += dy;
                x0 += sx;
            }

            if (e2 <= dx) {
                err += dx;
                y0 += sy;
            }
        }
    }

    void save(const std::string& filename) {
        std::ofstream file(filename, std::ios::binary);

        if (!file) {
            std::cerr << "Ошибка создания файла: "
                      << filename << std::endl;
            return;
        }

        BMPFileHeader fileHeader;
        BMPInfoHeader infoHeader;

        // BMP требует выравнивание строк по 4 байта
        int rowStride = width * 3;
        int padding = (4 - (rowStride % 4)) % 4;
        int paddedRowSize = rowStride + padding;

        infoHeader.width = width;
        infoHeader.height = height;
        infoHeader.size_image = paddedRowSize * height;

        fileHeader.file_size =
            sizeof(BMPFileHeader) +
            sizeof(BMPInfoHeader) +
            infoHeader.size_image;

        // Заголовки
        file.write(reinterpret_cast<const char*>(&fileHeader),
                   sizeof(fileHeader));

        file.write(reinterpret_cast<const char*>(&infoHeader),
                   sizeof(infoHeader));

        // Пустые байты для padding
        uint8_t pad[3] = {0, 0, 0};

        // BMP хранится снизу вверх
        for (int y = height - 1; y >= 0; --y) {

            const uint8_t* row =
                &pixels[y * width * 3];

            file.write(reinterpret_cast<const char*>(row),
                       rowStride);

            file.write(reinterpret_cast<const char*>(pad),
                       padding);
        }

        file.close();

        std::cout << "Файл сохранен: "
                  << filename << std::endl;
    }
};

// =====================================
// Дракон Хартера-Хейтуэя
// =====================================

void drawDragon(
    float x1,
    float y1,
    float x2,
    float y2,
    int turn,
    int iter,
    Image& img
) {
    if (iter == 0) {
        img.drawLine(
            static_cast<int>(x1),
            static_cast<int>(y1),
            static_cast<int>(x2),
            static_cast<int>(y2),
            0x00FFCC
        );

        return;
    }

    float xn =
        (x1 + x2) / 2.0f +
        turn * (y2 - y1) / 2.0f;

    float yn =
        (y1 + y2) / 2.0f -
        turn * (x2 - x1) / 2.0f;

    drawDragon(
        x1, y1,
        xn, yn,
        1,
        iter - 1,
        img
    );

    drawDragon(
        xn, yn,
        x2, y2,
        -1,
        iter - 1,
        img
    );
}

// =====================================
// Кривая Коха
// =====================================

void drawKoch(
    float x1,
    float y1,
    float x5,
    float y5,
    int iter,
    Image& img
) {
    if (iter == 0) {
        img.drawLine(
            static_cast<int>(x1),
            static_cast<int>(y1),
            static_cast<int>(x5),
            static_cast<int>(y5),
            0xFF55FF
        );

        return;
    }

    float x2 = x1 + (x5 - x1) / 3.0f;
    float y2 = y1 + (y5 - y1) / 3.0f;

    float x4 = x1 + 2.0f * (x5 - x1) / 3.0f;
    float y4 = y1 + 2.0f * (y5 - y1) / 3.0f;

    float cos60 = 0.5f;
    float sin60 = 0.8660254f;

    float x3 =
        x2 +
        (x4 - x2) * cos60 -
        (y4 - y2) * sin60;

    float y3 =
        y2 +
        (x4 - x2) * sin60 +
        (y4 - y2) * cos60;

    drawKoch(x1, y1, x2, y2, iter - 1, img);
    drawKoch(x2, y2, x3, y3, iter - 1, img);
    drawKoch(x3, y3, x4, y4, iter - 1, img);
    drawKoch(x4, y4, x5, y5, iter - 1, img);
}

// =====================================
// main
// =====================================

int main() {

    // Для Windows-консоли
    setlocale(LC_ALL, "Russian");

    int iterations;

    std::cout
        << "Введите количество итераций: ";

    std::cin >> iterations;

    if (iterations < 0) {
        std::cout
            << "Ошибка: число не может быть отрицательным!"
            << std::endl;

        return 1;
    }

    const int size = 1600;

    // =========================
    // Дракон
    // =========================

    Image dragonImg(size, size);

    float d_x1 = size * 0.30f;
    float d_y1 = size * 0.40f;

    float d_x2 = size * 0.70f;
    float d_y2 = size * 0.65f;

    std::cout
        << "Генерация дракона..."
        << std::endl;

    drawDragon(
        d_x1,
        d_y1,
        d_x2,
        d_y2,
        1,
        iterations,
        dragonImg
    );

    dragonImg.save("dragon.bmp");

    // =========================
    // Кривая Коха
    // =========================

    Image kochImg(size, size);

    float k_x1 = size * 0.10f;
    float k_y1 = size * 0.30f;

    float k_x2 = size * 0.90f;
    float k_y2 = size * 0.30f;

    std::cout
        << "Генерация кривой Коха..."
        << std::endl;

    drawKoch(
        k_x1,
        k_y1,
        k_x2,
        k_y2,
        iterations,
        kochImg
    );

    kochImg.save("koch.bmp");

    std::cout
        << "Готово!"
        << std::endl;

    return 0;
}