Викиучебник 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