Загрузка данных
#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;
}