mandelbrot-set/MandelbrotSet/Program.cs
2023-04-19 16:23:59 +02:00

174 lines
6.7 KiB
C#

using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Numerics;
using System.Windows.Forms;
namespace MandelbrotSet
{
class Program
{
#region Params
private static int MaxIterations = 96; // int: Höhe des Ausgabebilds in Pixeln. Nicht größer als 20000 setzen!
private static int Height = 1000; // int: Höhe des Ausgabebilds in Pixeln. Nicht größer als 20000 setzen!
private static int Width;// int: Breite des Ausgabebilds in Pixeln. Nicht größer als 20000 setzen!
private static string Filename = "plot"; // Dateiname
private const double Xmin = -2.0; // double: Untere Grenze des Definitionsbereichs des Plots
private const double Xmax = 1.0; // double: Obere Grenze des Definitionsbereichs des Plots
private const double Ymin = -1.0; // double: Untere Grenze des Wertebereichs des Plots
private const double Ymax = 1.0; // double: Obere Grenze des Wertebereichs des Plots
private const double HueFactor = 360.0;
private const double Mathwidth = Xmax - Xmin;
private const double Mathheight = Ymax - Ymin;
private static Color Corecolor { get; } = Color.Black;
#endregion
private static BigInteger _pixelsDrawn;
private static Bitmap _map;
static Program()
{
_pixelsDrawn = 0;
}
static void Main(string[] args)
{
if (args.Length >= 1)
{
Filename = args[0];
if (args.Length >= 2)
{
if (int.TryParse(args[1], out var newHeight))
{
Height = newHeight;
Console.WriteLine($"Parameter Höhe wurde auf {Height} gesetzt!.");
}
else
{
Console.WriteLine($"\"{args[1]}\" ist keine gültige Höhenangabe!");
Console.WriteLine($"Parameter Höhe wurde auf Standardwert ({Height}) zurückgesetzt!.");
}
if (args.Length >= 3)
{
if (int.TryParse(args[2], out var newMaxIterations))
{
MaxIterations = newMaxIterations;
Console.WriteLine($"Parameter Iterationen wurde auf {MaxIterations} gesetzt!.");
}
else
{
Console.WriteLine($"\"{args[2]}\" ist keine gültige Iterationsangabe!");
Console.WriteLine($"Parameter Iterationen wurde auf Standardwert ({MaxIterations}) zurückgesetzt!.");
}
}
}
}
Filename = $"{Filename}-{Height}px-{MaxIterations}it.bmp";
Console.WriteLine($"Parameter Dateiname wurde auf \"{Filename}\" gesetzt!.");
Width = Height * 3 / 2;
try
{
_map = new Bitmap(Width, Height);
}
catch (Exception e)
{
Console.WriteLine("Bitmap kann nicht erstellt werden: " + e.Message);
return;
}
Stopwatch watch;
Console.WriteLine("Beginning Task...\n├─── Drawing Mandelbrot...");
watch = Stopwatch.StartNew();
DrawMandelbrot();
Console.WriteLine($"│ └─── Mandelbrot drawn!\nDEBUG: { _pixelsDrawn.ToString()} pixels were drawn.\nSuccessfully rendered in {((double)watch.ElapsedMilliseconds / 1000.0).ToString()} seconds!\n├─── Saving bitmap...");
watch = Stopwatch.StartNew();
_map.Save(Filename);
Console.WriteLine($"│ ├─── Saved as \"{Filename}\"!\n│ Successfully saved in {((double)watch.ElapsedMilliseconds / 1000.0).ToString()} seconds!\nFinished Task!");
Process.Start(Filename);
}
private static int Constrain(int value, int min, int max) => value < min ? min : (value > max ? max : value);
private static Color ColorFromHue(double hue)
{
double r, g, b, x;
int R, G, B;
hue %= 360.0;
x = 1.0 - Math.Abs(hue / 60.0 % 2.0 - 1);
#region COLOR MODE
if (hue < 60.0)
{
r = 1.0; g = x; b = 0.0;
}
else if (hue < 120.0)
{
r = x; g = 1.0; b = 0.0;
}
else if (hue < 180.0)
{
r = 0.0; g = 1.0; b = x;
}
else if (hue < 240.0)
{
r = 0.0; g = x; b = 1.0;
}
else if (hue < 300.0)
{
r = x; g = 0.0; b = 1.0;
}
else
{
r = 1.0; g = 0.0; b = x;
}
#endregion
R = Constrain((int)Math.Round(r * 255), 0, 255);
G = Constrain((int)Math.Round(g * 255), 0, 255);
B = Constrain((int)Math.Round(b * 255), 0, 255);
return Color.FromArgb(R, G, B);
}
static double XtoMath(int xb) => Xmin + xb * Mathwidth / Width;
static double YtoMath(int yb) => Ymax - yb * Mathheight / Height;
private static void DrawMandelbrot()
{
int y, x, iterations;
double xd, yd;
for (y = 0; y < Height; y++)
{
if (y % 100 == 99) Console.WriteLine($"│ ├─── Progress: {(double)(y + 1) * 100.0 / (double)Height}%");
yd = YtoMath(y);
for (x = 0; x < Width; x++)
{
xd = XtoMath(x);
iterations = MandelbrotIterations(new Complex(xd, yd), Complex.Zero);
if (iterations == -1)
{
_map.SetPixel(x, y, Corecolor);
_pixelsDrawn++;
continue;
}
_map.SetPixel(x, y, ColorFromHue(((double)iterations / (double)MaxIterations) * HueFactor));
_pixelsDrawn++;
}
}
}
private static Complex NextItem(Complex point, Complex z) => new Complex(z.Real * z.Real - z.Imaginary * z.Imaginary + point.Real, 2.0 * z.Real * z.Imaginary + point.Imaginary);
private static int MandelbrotIterations(Complex point, Complex z, int depth = 0)
{
if (depth > MaxIterations) return -1;
if (z.Magnitude >= 2.0) return depth;
return MandelbrotIterations(point, NextItem(point, z), depth + 1);
}
}
}