Викиучебник
ruwikibooks
https://ru.wikibooks.org/wiki/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0
MediaWiki 1.47.0-wmf.14
first-letter
Медиа
Служебная
Обсуждение
Участник
Обсуждение участника
Викиучебник
Обсуждение Викиучебника
Файл
Обсуждение файла
MediaWiki
Обсуждение MediaWiki
Шаблон
Обсуждение шаблона
Справка
Обсуждение справки
Категория
Обсуждение категории
Полка
Обсуждение полки
Импортировано
Обсуждение импортированного
Рецепт
Обсуждение рецепта
Задача
Обсуждение задачи
TimedText
TimedText talk
Модуль
Обсуждение модуля
Event
Event talk
Множество Мандельброта
0
19810
269747
269739
2026-08-05T17:22:59Z
Aokoroko
47596
/* Примеры программ */
269747
wikitext
text/x-wiki
{{Название учебника
| Категория = Программирование, Математика
| Тип = Одностраничный
| Готовность = 25%
}}
[[Файл:Mandelset hires.png|thumb|300px|Множество Мандельброта]]{{Wikipedia}}
'''Мно́жество Мандельбро́та''' — это множество таких точек ''c'' на комплексной плоскости, для которых рекуррентное соотношение <math>z_{n+1} = {z_n}^2 + c</math> при <math>z_0 = 0</math> задаёт ограниченную последовательность. То есть, это множество таких ''c'', для которых существует такое действительное ''R'', что неравенство |''z''<sub>''n''</sub>|<''R'' выполняется при всех натуральных ''n''.
== Построение множества ==
Несложно доказать, что как только модуль ''z''<sub>''n''</sub> окажется больше 2 (или, в терминах действительной и мнимой частей, ''x''<sub>''n''</sub><sup>2</sup>+''y''<sub>''n''</sub><sup>2</sup>>4), последовательность станет стремиться к бесконечности. В случае |''c''|≤2 это можно доказать с помощью метода математической индукции. При |''c''|>2 точка ''c'' заведомо не принадлежит множеству Мандельброта, что также можно вывести методом индукции, используя равенство ''z''<sub>0</sub>=0. (Хотя в этом случае может существовать другое ''z''<sub>0</sub>, для которого соответствующая последовательность ограничена по модулю, но для некоторого ''n'' выполняется неравенство |''z''<sub>''n''</sub>|>2.)
Сравнение |''z''<sub>''n''</sub>| с этим числом (в англоязычной литературе его называют «bail-out») позволяет выделять точки, не попадающие внутрь множества. Для точек, лежащих внутри множества, последовательность не будет иметь тенденции к бесконечности и никогда не достигнет этого числа, поэтому после определённого числа итераций расчёт необходимо принудительно завершить. Максимальное число итераций, после которых число считается попавшим внутрь множества, задается в программе.
Изображение, полученное таким способом, является лишь приближением к реальному множеству Мандельброта. Более качественные результаты можно получать, увеличивая максимальное количество итераций, однако при этом пропорционально вырастает и время расчётов.
=== Примеры программ ===
==== Консольный рендерер Мандельброта с методом возмущений и предела 10<sup>−308</sup> (на языке программирования [[C++]]) ====
Ключевые особенности
* Расчёт опорной траектории на 1000 бит всего один раз.
* Реактивный расчёт миллиарда пикселей на аппаратном double.
* Расчет можно выполнить существенно быстрее, если использовать билинейную аппроксимацию.
* При использовании чисел с плавающей запятой двойной точности (порядка 10⁻¹⁵) теория возмущений позволяет приблизиться к уровню 10⁻³⁰⁸ - не дальше.
* Революционный алгоритм Reference Reset to Zero.
* Настоящий SSAA 8x8 для идеально сглаженного изображения без алиасинга.
* Параллелизм OpenMP для высокоскоростного многопоточного рендеринга.
<syntaxhighlight lang="c++">
#include <atomic>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <mpfr.h>
#include <omp.h>
using std::vector;
using std::min;
const char * CENTER_RE = "-1.99999543561201124623198345433951143502785679245726844745821388800402678499411681518036306219179273434395557574279985918047221291197081186140687781560831995";
const char * CENTER_IM = "-0.00000000000000000000000026198152173811047783694060060607013913873144250985383083459221663448338433592617272786772587281530484110756597337683912309313885172";
const char * VIEW_SIZE = "1.15e-119";
const int WIDTH = 2160;
const int HEIGHT = 2160;
const int AA = 8;
const int MAX_ITER = 50000;
const double ESCAPE_RADIUS_SQUARED = 50000.0;
const int PALETTE_FRAME = 200;
const char * OUTPUT_FILE = "Mandelbrot Set Image 112.bmp";
const mpfr_prec_t PRECISION_BITS = 1000;
const int REF_SIZE = MAX_ITER + 200;
struct Complex {
double re;
double im;
};
#pragma pack(push, 1)
struct BMPHeader {
uint16_t type{0x4D42};
uint32_t size{0};
uint32_t reserved{0};
uint32_t offBits{54};
uint32_t structSize{40};
int32_t width{0};
int32_t height{0};
uint16_t planes{1};
uint16_t bitCount{24};
uint32_t compression{0};
uint32_t sizeImage{0};
int32_t xPixelsPerMeter{2834};
int32_t yPixelsPerMeter{2834};
uint32_t colorsUsed{0};
uint32_t colorsImportant{0};
};
#pragma pack(pop)
int main() {
const double startTime = omp_get_wtime();
const long rawWidth = static_cast<long>(WIDTH) * AA;
const long rawHeight = static_cast<long>(HEIGHT) * AA;
mpfr_t centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp;
mpfr_inits2(PRECISION_BITS, centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp, static_cast<mpfr_ptr>(nullptr));
mpfr_set_str(centerRe, CENTER_RE, 10, MPFR_RNDN);
mpfr_set_str(centerIm, CENTER_IM, 10, MPFR_RNDN);
mpfr_set_str(viewSizeMp, VIEW_SIZE, 10, MPFR_RNDN);
const double sampleStep = mpfr_get_d(viewSizeMp, MPFR_RNDN) / rawWidth;
vector<Complex> referenceOrbit;
referenceOrbit.reserve(REF_SIZE);
mpfr_set_ui(zReMp, 0, MPFR_RNDN);
mpfr_set_ui(zImMp, 0, MPFR_RNDN);
for (int iter = 0; iter < REF_SIZE - 1; ++iter) {
Complex z{mpfr_get_d(zReMp, MPFR_RNDN), mpfr_get_d(zImMp, MPFR_RNDN)};
referenceOrbit.push_back(z);
if (z.re * z.re + z.im * z.im > ESCAPE_RADIUS_SQUARED) {
break;
}
mpfr_mul(tmp1, zReMp, zImMp, MPFR_RNDN);
mpfr_sqr(tmp2, zReMp, MPFR_RNDN);
mpfr_sqr(zReMp, zImMp, MPFR_RNDN);
mpfr_sub(zReMp, tmp2, zReMp, MPFR_RNDN);
mpfr_add(zReMp, zReMp, centerRe, MPFR_RNDN);
mpfr_mul_2ui(tmp1, tmp1, 1, MPFR_RNDN);
mpfr_add(zImMp, tmp1, centerIm, MPFR_RNDN);
}
const int referenceLength = static_cast<int>(referenceOrbit.size());
mpfr_clears(centerRe, centerIm, zReMp, zImMp, tmp1, tmp2, viewSizeMp, static_cast<mpfr_ptr>(nullptr));
std::fprintf(stderr, "Reference orbit: %d points\n", referenceLength);
std::fprintf(stderr, "Precomputing skip100 matrices...\n");
vector<Complex> coeff_A(REF_SIZE, {1.0, 0.0});
vector<Complex> coeff_B(REF_SIZE, {0.0, 0.0});
vector<double> rad_R(REF_SIZE, 2.0);
vector<double> aS_squared(REF_SIZE, 0.0);
for (int i = 0; i < referenceLength; ++i) {
double r2 = referenceOrbit[i].re * referenceOrbit[i].re + referenceOrbit[i].im * referenceOrbit[i].im;
aS_squared[i] = (r2 < ESCAPE_RADIUS_SQUARED) ? r2 : 0.0;
}
const int loop_limit = min(static_cast<int>(MAX_ITER), referenceLength - 105);
#pragma omp parallel for
for (int i = 0; i < loop_limit; ++i) {
double min_r2 = ESCAPE_RADIUS_SQUARED;
for (int k = 0; k < 100; ++k) {
if (i + k >= referenceLength) break;
if (aS_squared[i + k] < min_r2) min_r2 = aS_squared[i + k];
}
rad_R[i] = std::sqrt(min_r2);
for (int k = 0; k < 100; ++k) {
if (i + k >= referenceLength) break;
double r_re = referenceOrbit[i + k].re;
double r_im = referenceOrbit[i + k].im;
double next_A_re = 2.0 * (r_re * coeff_A[i].re - r_im * coeff_A[i].im);
double next_A_im = 2.0 * (r_re * coeff_A[i].im + r_im * coeff_A[i].re);
double next_B_re = 2.0 * (r_re * coeff_B[i].re - r_im * coeff_B[i].im) + 1.0;
double next_B_im = 2.0 * (r_re * coeff_B[i].im + r_im * coeff_B[i].re);
coeff_A[i].re = next_A_re; coeff_A[i].im = next_A_im;
coeff_B[i].re = next_B_re; coeff_B[i].im = next_B_im;
}
}
const double PI = 3.14159265358979323846;
uint8_t palette[256][3];
for (int i = 0; i < 255; ++i) {
palette[i][0] = static_cast<uint8_t>(std::lround(127.0 + 127.0 * std::cos(2.0 * PI * i / 255.0)));
palette[i][1] = static_cast<uint8_t>(std::lround(127.0 + 127.0 * std::sin(2.0 * PI * i / 255.0)));
palette[i][2] = palette[i][1];
}
palette[255][0] = 255; palette[255][1] = 255; palette[255][2] = 255;
const int rowBytes = (WIDTH * 3 + 3) & ~3;
vector<uint8_t> image(static_cast<size_t>(rowBytes) * HEIGHT, 0);
std::atomic<int> completedRows{0};
const Complex * reference = referenceOrbit.data();
#pragma omp parallel for schedule(dynamic)
for (int y = 0; y < HEIGHT; ++y) {
uint8_t * row = image.data() + static_cast<size_t>(y) * rowBytes;
for (int x = 0; x < WIDTH; ++x) {
unsigned blueSum = 0; unsigned greenSum = 0; unsigned redSum = 0;
for (int sampleY = 0; sampleY < AA; ++sampleY) {
const double deltaCIm = (static_cast<long>(y) * AA + sampleY - rawHeight / 2) * sampleStep;
for (int sampleX = 0; sampleX < AA; ++sampleX) {
const double deltaCRe = (static_cast<long>(x) * AA + sampleX - rawWidth / 2) * sampleStep;
double deltaRe = 0.0; double deltaIm = 0.0;
double zRe = 0.0; double zIm = 0.0;
int referenceIndex = 0;
int iter = 0;
while (iter < MAX_ITER) {
if (zRe * zRe + zIm * zIm >= ESCAPE_RADIUS_SQUARED) {
break;
}
double eps_abs2 = deltaRe * deltaRe + deltaIm * deltaIm;
double limit_r2 = 1e-60 * rad_R[referenceIndex] * rad_R[referenceIndex];
if (eps_abs2 < limit_r2 && (referenceIndex + 100 < loop_limit) && (iter + 100 < MAX_ITER)) {
double backup_deltaRe = deltaRe; double backup_deltaIm = deltaIm;
int backup_refIdx = referenceIndex; int backup_iter = iter;
double next_eps_re = (coeff_A[referenceIndex].re * deltaRe - coeff_A[referenceIndex].im * deltaIm) +
(coeff_B[referenceIndex].re * deltaCRe - coeff_B[referenceIndex].im * deltaCIm);
double next_eps_im = (coeff_A[referenceIndex].re * deltaIm + coeff_A[referenceIndex].im * deltaRe) +
(coeff_B[referenceIndex].re * deltaCIm + coeff_B[referenceIndex].im * deltaCRe);
deltaRe = next_eps_re; deltaIm = next_eps_im;
referenceIndex += 100; iter += 100;
zRe = reference[referenceIndex].re + deltaRe;
zIm = reference[referenceIndex].im + deltaIm;
if (zRe * zRe + zIm * zIm >= ESCAPE_RADIUS_SQUARED) {
deltaRe = backup_deltaRe; deltaIm = backup_deltaIm;
referenceIndex = backup_refIdx; iter = backup_iter;
} else {
continue;
}
}
const double a = 2.0 * reference[referenceIndex].re + deltaRe;
const double b = 2.0 * reference[referenceIndex].im + deltaIm;
const double nextDeltaRe = a * deltaRe - b * deltaIm + deltaCRe;
deltaIm = a * deltaIm + b * deltaRe + deltaCIm;
deltaRe = nextDeltaRe;
++referenceIndex; ++iter;
zRe = reference[referenceIndex].re + deltaRe;
zIm = reference[referenceIndex].im + deltaIm;
if (zRe * zRe + zIm * zIm < deltaRe * deltaRe + deltaIm * deltaIm || referenceIndex >= loop_limit) {
deltaRe = zRe; deltaIm = zIm; referenceIndex = 0;
}
}
const int remaining = MAX_ITER - iter;
const uint8_t colorIndex = (remaining == 0) ? 255 : static_cast<uint8_t>(remaining % 254);
const int paletteIndex = (colorIndex == 255) ? 255 : (colorIndex - PALETTE_FRAME + 255) % 255;
blueSum += palette[paletteIndex][0];
greenSum += palette[paletteIndex][1];
redSum += palette[paletteIndex][2];
}
}
const int samples = AA * AA;
row[x * 3 + 0] = static_cast<uint8_t>(blueSum / samples);
row[x * 3 + 1] = static_cast<uint8_t>(greenSum / samples);
row[x * 3 + 2] = static_cast<uint8_t>(redSum / samples);
}
const int done = ++completedRows;
if (done % 50 == 0 || done == HEIGHT) {
std::fprintf(stderr, "\rProgress: %d/%d rows (%.1f%%)", done, HEIGHT, 100.0 * done / HEIGHT);
}
}
BMPHeader header;
header.width = WIDTH; header.height = HEIGHT;
header.sizeImage = static_cast<uint32_t>(image.size());
header.size = header.sizeImage + 54;
FILE * file = std::fopen(OUTPUT_FILE, "wb");
if (!file) { std::perror(OUTPUT_FILE); return 1; }
std::fwrite(&header, sizeof(header), 1, file);
std::fwrite(image.data(), 1, image.size(), file);
std::fclose(file);
std::fprintf(stderr, "\nDone! Saved to %s in %.2f seconds.\n", OUTPUT_FILE, omp_get_wtime() - startTime);
return 0;
}
</syntaxhighlight>
==== Пример программы построения множества (на языке программирования [[Паскаль (язык программирования)|паскаль]]) ====
<syntaxhighlight lang="pascal">
uses
System.Drawing,
System.Windows.Forms,
System.Threading,
FormsABC;
procedure DrawMandelbrot(g: Graphics; w,h: integer; scale: real; dx,dy: integer);
const max = 10;
begin
for var ix:=0 to w-1 do
for var iy:=0 to h-1 do
begin
var x := 0.0;
var y := 0.0;
var cx := scale * (ix - dx);
var cy := scale * (iy - dy);
var i := 1;
while i<255 do
begin
var x1 := x*x-y*y+cx;
var y1 := 2*x*y+cy;
x := x1;
y := y1;
if (abs(x)>max) and (abs(y)>max) then break;
i += 1;
end;
if i>=255 then
g.FillRectangle(Brushes.Red,ix,iy,1,1)
else
g.FillRectangle(new SolidBrush(Color.FromArgb(255,255-i,255-i)),ix,iy,1,1)
end;
end;
var
Scale := new RealField('Масштаб: ');
l1 := new FlowBreak;
dx := new IntegerField('dx: ');
l2 := new FlowBreak;
dy := new IntegerField('dy: ');
l3 := new FlowBreak(20);
b := new Button(' Нарисовать ');
p: PaintBox;
procedure Draw;
begin
var g := p.Graphics;
DrawMandelbrot(g,p.Width,p.Height,Scale.Value,dx.Value,dy.Value);
p.Invalidate;
end;
procedure My(o: Object);
begin
Draw;
end;
procedure Click;
begin
ThreadPool.QueueUserWorkItem(My);
end;
begin
MainForm.Title := 'Множество Мандельброта';
MainForm.SetSize(700, 600);
MainPanel.Dock := Dockstyle.Left;
MainPanel.Width := 120;
Scale.Value := 0.0035;
dx.Value := 430;
dy.Value := 280;
b.Click += Click;
ParentControl := MainForm;
p := new PaintBox;
p.Dock := DockStyle.Fill;
ThreadPool.QueueUserWorkItem(My);
end.
</syntaxhighlight>
==== Пример программы построения множества (на языке программирования [[C++]] с использованием SFML) ====
<syntaxhighlight lang="c++">
///Heared.hpp
#pragma once
#include <SFML\Graphics.hpp>
//#include <boost\math\bindings\rr.hpp>
typedef long double TYPE;
template<typename T>
struct Complex
{
T re;
T im;
Complex operator += (const Complex & other)
{
re += other.re;
im += other.im;
return *this;
}
Complex operator + (const Complex & other)
{
Complex c(*this);
return c += other;
}
Complex operator *= (const Complex & other)
{
Complex c;
c.re = re * other.re - im * other.im;
c.im = re * other.im + im * other.re;
*this = c;
return *this;
}
Complex operator * (const Complex & other)
{
Complex c(*this);
return c *= other;
}
Complex operator = (const Complex & other)
{
re = other.re;
im = other.im;
return *this;
}
Complex(): re((T)0), im((T)0)
{
}
Complex(const Complex& other) : re(other.re), im(other.im)
{
}
Complex(const T& re, const T& im) : re(re), im(im)
{
}
Complex(const T& re) : re(re), im((T)0)
{
}
T module_sqr()const
{
return re * re + im * im;
}
};
//void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y);
///draw.cpp
#include "Header.hpp"
void step_clr(sf::Color & clr)
{
clr.r = clr.r + 5 < 0x100 ? clr.r + 5 : 0xff;
clr.g = clr.g + 3 < 0x100 ? clr.g + 5 : 0xff;
clr.b = clr.b + 2 < 0x100 ? clr.b + 5 : 0xff;
}
void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y)
{
const TYPE epsilon = 0.005;
sf::Vector2i sizewindow((int)((x.y - x.x) / epsilon), (int)((y.y - y.x) / epsilon));
sf::RenderWindow window(sf::VideoMode(sizewindow.x, sizewindow.y), "Mandelbroth");
sf::Image im;
const int max_it = 250;
const int infinity_sqr = 10000;
im.create(sizewindow.x, sizewindow.y);
sf::Color clr;
int xim = 0, yim = 0;
for (TYPE currx = x.x; currx <= x.y; currx += epsilon, ++xim)
{
yim = 0;
while (xim >= sizewindow.x)
--xim;
for (TYPE curry = y.x; curry <= y.y; curry += epsilon, ++yim)
{
while (yim >= sizewindow.y)
--yim;
clr = sf::Color::Black;
Complex<TYPE> curr;
im.setPixel(xim, yim, sf::Color::Black);
for (int i = 0; i < max_it; ++i)
{
if (curr.module_sqr() >= infinity_sqr)
{
im.setPixel(xim, yim, clr);
break;
}
curr = curr * curr + Complex<TYPE>(currx, curry);
step_clr(clr);
}
}
}
sf::Sprite s;
sf::Texture t;
t.loadFromImage(im);
s.setTexture(t);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(s);
window.display();
}
}
///main.cpp
#include "Header.hpp"
#include "draw.cpp"
#include <iostream>
int main()
{
TYPE x1, x2, y1, y2;
//std::cin >> x1 >> x2 >> y1 >> y2;
x1 = -2.5;
x2 = 2;
y1 = -1.5;
y2 = 1.5;
drawM(sf::Vector2<TYPE>(x1, x2), sf::Vector2<TYPE>(y1, y2));
}
</syntaxhighlight>
=== Добавление цвета ===
[[Файл:Mandel zoom 11 satellite double spiral.jpg|thumb|Фрагмент границы множества Мандельброта в цветном варианте]]
Строго математически, изображения множеств Мандельброта и Жюлиа должны быть чёрно-белыми. Точка либо попадает внутрь множества, либо нет. Несмотря на это, с помощью компьютера мы можем построить и цветные изображения. Самым распространённым способом является раскрашивание точек снаружи множества в цвет, соответствующий количеству итераций, за которое точка уходит в «бесконечность» или, с точки зрения программы, на определённое расстояние от нуля.
Порядок определения, попадает ли точка ''z''<sub>0</sub> внутрь множества (традиционно закрашиваемого чёрным цветом) или нет (закрашивается цветом, зависящим от скорости движения к бесконечности) следующий: на каждой итерации для ''z''<sub>''n''</sub>=''x''<sub>''n''</sub>+''y<sub>''n''</sub>·i'' вычисляется значение модуля <math>|z_n| = \sqrt{x_n^2 + y_n^2}</math>, которое затем сравнивается с «границей бесконечности» (обычно берётся значение, равное 2). Здесь важно обратить внимание, что уже на данном этапе можно ввести определённую оптимизацию вычислений, если проверять не <math>\sqrt{x_n^2 + y_n^2} > 2</math>, а <math>x_n^2 + y_n^2 > 4</math>, что значительно снизит время расчётов.
Таким образом, если |''z''<sub>''n''</sub>|<sup>2</sup> ≤ 4 при любом числе итераций (на практике — при всех вычисленных итерациях), то цвет точки чёрный, в противном случае он зависит от последнего значения ''n'', при котором |''z''<sub>''n''</sub>|<sup>2</sup> ≤ 4. Значение ''n'', фактически, обозначает скорость движения ''z''<sub>''n''</sub> в бесконечность, и может быть просто индексом в таблице цветов, или использоваться как параметр в более сложном алгоритме.
Данный алгоритм определяет, что если точка удаляется больше чем на 2 от начала координат, то она лежит снаружи множества Мандельброта. Для того, чтобы определить, что точка лежит внутри множества есть много способов. Самое простое решение — ограничить количество итераций неким максимумом. Если точка не вышла за указанную границу, можно считать, что она находится внутри множества.
Точкам около границы множества нужно больше итераций для ухода в бесконечность. Поэтому такие области прорисовываются заметно дольше. Чем дальше от границ множества, тем выше скорость ухода в бесконечность. Для таких точек требуется меньше итераций.
==== Пример добавления цвета (на PHP) ====
<syntaxhighlight lang="php">
<?php
// Default: http://<host>/<dir>/<filename>.php?iter1=64&width=600&height=400&coef=32
function BN($n, $l, $r) {return $n>$l && $n<=$r;}
function SQR($a) {return $a*$a;}
define("COEF", $_GET["coef"]);
$iter1 = $_GET["iter1"];
$width = $_GET["width"];
$height = $_GET["height"];
header("Content-type: image/png");
$img = imagecreatetruecolor($width, $height);
$iter2 = 0.01/($width/300);
$yy = -1;
for ($y = -1; $y < 1; $y = $y + $iter2) {
$yy++; $xx=-1;
for($x = -2; $x < 1; $x = $x + $iter2) {
$xx++;
$Cx = $x;
$Cy = $y;
$X = $x;
$Y = $y;
$ix = 0;
$iy = 0;
$n = 0;
while ((SQR($ix) + SQR($iy) < 4) and ($n < $iter1)) {
$ix = SQR($X) - SQR($Y) + $Cx;
$iy = 2*$X*$Y + $Cy;
$X = $ix;
$Y = $iy;
$n++;
}
if(BN($n,0,7)) $col = imagecolorallocate($img,COEF*$n,0,0);
elseif(BN($n,7,14)) $col = imagecolorallocate($img,COEF*$n,COEF*$n,0);
elseif(BN($n,14,21))$col = imagecolorallocate($img,COEF*$n,0,COEF*$n);
elseif(BN($n,21,28))$col = imagecolorallocate($img,0,COEF*$n,0);
elseif(BN($n,28,35))$col = imagecolorallocate($img,COEF*$n,COEF*$n,0);
elseif(BN($n,35,42))$col = imagecolorallocate($img,0,COEF*$n,COEF*$n);
elseif(BN($n,42,49))$col = imagecolorallocate($img,0,0,COEF*$n);
elseif(BN($n,49,56))$col = imagecolorallocate($img,COEF*$n,0,COEF*$n);
elseif(BN($n,56,64))$col = imagecolorallocate($img,0,COEF*$n,COEF*$n);
imagesetpixel($img, $xx, $yy, $col);
}
}
imagepng($img);
imagedestroy($img);
?>
</syntaxhighlight>
==== Пример добавления цвета (на C++) ====
<syntaxhighlight lang="c++">
///draw.cpp
#include "Header.hpp"
void step_clr(float & red, float & green, float & blue)
{
red = (int)(red + 5) < 0xff ? red + 5 : 0xff;
if((int)red == 0xff)
green = (int)(green + 3.5) < 0xff ? green + 3.5 : 0xff;
if((int)green == 0xff)
blue = (int)(blue + 2.2) < 0xff ? blue + 2.2 : 0xff;
}
void drawM(sf::Vector2<TYPE> x, sf::Vector2<TYPE> y)
{
const TYPE epsilon = 0.005;
sf::Vector2i sizewindow((int)((x.y - x.x) / epsilon), (int)((y.y - y.x) / epsilon));
sf::RenderWindow window(sf::VideoMode(sizewindow.x, sizewindow.y), "Mandelbroth");
sf::Image im;
const int max_it = 250;
const int infinity_sqr = 10000;
im.create(sizewindow.x, sizewindow.y);
sf::Color clr;
int xim = 0, yim = 0;
for (TYPE currx = x.x; currx <= x.y; currx += epsilon, ++xim)
{
yim = 0;
while (xim >= sizewindow.x)
--xim;
for (TYPE curry = y.x; curry <= y.y; curry += epsilon, ++yim)
{
while (yim >= sizewindow.y)
--yim;
clr = sf::Color::Black;
Complex<TYPE> curr;
float red = 0, green = 0, blue = 0;
im.setPixel(xim, yim, sf::Color::Black);
for (int i = 0; i < max_it; ++i)
{
if (curr.module_sqr() >= infinity_sqr)
{
clr = sf::Color(red, green, blue);
im.setPixel(xim, yim, clr);
break;
}
curr = curr * curr + Complex<TYPE>(currx, curry);
step_clr(red, green, blue);
}
}
}
sf::Sprite s;
sf::Texture t;
t.loadFromImage(im);
s.setTexture(t);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(s);
window.display();
}
}
</syntaxhighlight>
mqotb9gwkxhfibka9x27w0jwatjefkz
АОН/Свободный аэростат
0
20828
269744
269690
2026-08-05T12:26:05Z
Leksey
3027
НЛГ-31
269744
wikitext
text/x-wiki
{{АОН страница}}{{Википедия|Воздушный шар}}
Свободный аэростат это официальное название обычного воздушного шара. Прежде всего под ним мы понимаем тепловой аэростат — самый распространённый и доступный для граждан в России тип аэростата.
;Газовое воздухоплавание
Другие аэростаты (газовые а также розьеры) практически не встречаются (даже можно сказать более категорично — их нет вообще) в России. В первую очередь по причине высокой стоимости гелия, который требуется для их наполнения, а также высокой цены на сами воздушные суда такой конструкции (производителей в России нет). На водороде же пилотируемые полеты в России не выполняются (в отличие от Европы). Да и дефицит "газовых" пилотов тоже влияет на ситуацию.
== Регулирование коммерческих полетов ==
Зарубежное регулирование описано на странице [[АОН/Свободный_аэростат/Коммерческие_полеты|Коммерческие_полеты]]
==Коммерческие полеты==
{{Основная статья|АОН/Свободный аэростат/Коммерческие полеты}}
Воздушные шары достаточно распространены в России как туристическое средство и доступны по цене для полета в группе (незнакомых между собой людей). Стоимость же эксклюзивных полетов аэростатов для пары людей или компании в два-три раза дороже чем полет для одного человека в группе.
Почти в каждом регионе есть воздухоплавательные клубы, оказывающие услуги туристического полета для всех желающих.
==Обучение на аэростат==
Авиационные учебные центры что обучают на аэростат перечислены вот тут - [[АОН/АУЦ/Список|Список]].
== Производители ==
В России есть несколько производителей тепловых аэростатов. Основными из них являются Русбал (типовые аэростаты) и Аэронатс.
;Иностранные производители:
*[[w:en:Ultramagic|Ultramagic]] (Испания)
*[[w:en:Kubicek Balloons|Kubicek Balloons]] (Чехия)
*[[w:en:Cameron Balloons|Cameron Balloons]] (Британия)
== Регулирование ==
В части регулирования этот вид ВС ничем не отличается от самолётов или планеров. Требования всё те же самые.
== Разработка аэростатов ==
нормы проектирования свободных аэростатов изложены в [[АОН/НЛГ-31|НЛГ-31]].
== Литература ==
По-видимому, самый полный и актуальный учебник, изданный на бумаге это «Всё о монгольфьерах» авторства Александра Таланова главного конструктора Русбала.
На английском языке существует бесплатное издание [[АОН/FAA|FAA]] - Balloon Flying Handbook<ref>{{Cite web|url=https://www.faa.gov/regulations_policies/handbooks_manuals/aviation/Balloon_Flying_Handbook|title=Balloon Flying Handbook (FAA-H-8083-11B)}}</ref>.
== Общественная организация ==
Развитием воздухоплавания в России занимается [[Федерация воздухоплавательного спорта|Федерация воздухоплавательного спорта России]].
== См. также ==
* [[АОН/Свободный аэростат/ТО|ТО свободного аэростата]]
* [[АОН/Свободный аэростат/Коммерческие полеты|Коммерческие полеты на аэростате]]
== Ссылки ==
*[https://flymonitor.ru/ Основной интернет-ресурс по аэростатам в России]
*[https://www.youtube.com/watch?v=XzbJ3XdLsQg&list=PLclQIRD3hHNgiz-vCjSVKKS1Ewi9PvySh Учебный видеокурс об аэростатах]
{{АОН}}
dueyft8oudr4uvd0eyvg33lu4q8qxsk
269746
269744
2026-08-05T12:40:11Z
Leksey
3027
СТ
269746
wikitext
text/x-wiki
{{АОН страница}}{{Википедия|Воздушный шар}}
Свободный аэростат это официальное название обычного воздушного шара. Прежде всего под ним мы понимаем тепловой аэростат — самый распространённый и доступный для граждан в России тип аэростата.
;Газовое воздухоплавание
Другие аэростаты (газовые а также розьеры) практически не встречаются (даже можно сказать более категорично — их нет вообще) в России. В первую очередь по причине высокой стоимости гелия, который требуется для их наполнения, а также высокой цены на сами воздушные суда такой конструкции (производителей в России нет). На водороде же пилотируемые полеты в России не выполняются (в отличие от Европы). Да и дефицит "газовых" пилотов тоже влияет на ситуацию.
== Регулирование коммерческих полетов ==
Зарубежное регулирование описано на странице [[АОН/Свободный_аэростат/Коммерческие_полеты|Коммерческие_полеты]]
==Коммерческие полеты==
{{Основная статья|АОН/Свободный аэростат/Коммерческие полеты}}
Воздушные шары достаточно распространены в России как туристическое средство и доступны по цене для полета в группе (незнакомых между собой людей). Стоимость же эксклюзивных полетов аэростатов для пары людей или компании в два-три раза дороже чем полет для одного человека в группе.
Почти в каждом регионе есть воздухоплавательные клубы, оказывающие услуги туристического полета для всех желающих.
==Обучение на аэростат==
Авиационные учебные центры что обучают на аэростат перечислены вот тут - [[АОН/АУЦ/Список|Список]].
== Производители ==
В России есть несколько производителей тепловых аэростатов. Основными из них являются Русбал (типовые аэростаты) и Аэронатс.
;Иностранные производители:
*[[w:en:Ultramagic|Ultramagic]] (Испания)
*[[w:en:Kubicek Balloons|Kubicek Balloons]] (Чехия)
*[[w:en:Cameron Balloons|Cameron Balloons]] (Британия)
== Регулирование ==
В части регулирования этот вид ВС ничем не отличается от самолётов или планеров. Требования всё те же самые.
== Разработка аэростатов ==
Нормы проектирования свободных аэростатов, которые должны получить [[АОН/Сертификат типа|сертификат типа]] изложены в [[АОН/НЛГ-31|НЛГ-31]].
== Литература ==
По-видимому, самый полный и актуальный учебник, изданный на бумаге это «Всё о монгольфьерах» авторства Александра Таланова главного конструктора Русбала.
На английском языке существует бесплатное издание [[АОН/FAA|FAA]] - Balloon Flying Handbook<ref>{{Cite web|url=https://www.faa.gov/regulations_policies/handbooks_manuals/aviation/Balloon_Flying_Handbook|title=Balloon Flying Handbook (FAA-H-8083-11B)}}</ref>.
== Общественная организация ==
Развитием воздухоплавания в России занимается [[Федерация воздухоплавательного спорта|Федерация воздухоплавательного спорта России]].
== См. также ==
* [[АОН/Свободный аэростат/ТО|ТО свободного аэростата]]
* [[АОН/Свободный аэростат/Коммерческие полеты|Коммерческие полеты на аэростате]]
== Ссылки ==
*[https://flymonitor.ru/ Основной интернет-ресурс по аэростатам в России]
*[https://www.youtube.com/watch?v=XzbJ3XdLsQg&list=PLclQIRD3hHNgiz-vCjSVKKS1Ewi9PvySh Учебный видеокурс об аэростатах]
{{АОН}}
ai6a9nytlj1cucu4im5t8mza0einkvk
АОН/НЛГ-31
0
35804
269745
269446
2026-08-05T12:35:35Z
Leksey
3027
Дополнение
269745
wikitext
text/x-wiki
{{АОН Страница}}
'''{{SUBPAGENAME}}''' (АП-31 или "авиационные правила") — нормы проектирования свободных аэростатов. Согласно их разрабатываются конструкции свободных аэростатов, которые могут получить сертификат типа.
==См. также==
* [[АОН/Свободный аэростат|Свободный аэростат]]
== Ссылки ==
* [https://bazanpa.ru/rosaviatsiia-prikaz-n1100-p-ot04122023-h6320816/ НОРМЫ ЛЕТНОЙ ГОДНОСТИ СВОБОДНЫХ ПИЛОТИРУЕМЫХ АЭРОСТАТОВ. ГАЗОВЫЕ АЭРОСТАТЫ НЛГ 31 ГА]
* [[АОН/Авиационные правила|Авиационные правила]]
==Примечания==
{{Примечания}}
{{АОН}}
h0fx0eqmdhijjomzm7as0v7kdb22ray