Skip to content

Instantly share code, notes, and snippets.

@irgendwr
Last active February 12, 2020 16:46
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save irgendwr/897c7ba73ab50957c7fe1bde33c7478a to your computer and use it in GitHub Desktop.
Visual representation of the Mandelbrot set in SWI Prolog.
% Jonas Boegle - https://github.com/irgendwr
:- use_module(library(pce)).
% draw(+Width, +Height, +Xoffset, +Yoffset, +Scale)
% Draws a mandelbrot set with a given size, x-/y-offset and Scale factor.
draw(Width, Height, Xoffset, Yoffset, Scale) :-
% create a new display and open it
new(Display, window('mhh, lecker Mandelbrot - Jonas @irgendwr :)')),
send(Display, size, size(Width, Height)),
send(Display, background, colour(white)),
send(Display, display, new(_, text('Wird berechnet...')), point(150, 150)),
send(Display, open),
% create new image
new(Img, image(@nil, Width, Height, pixmap)),
new(Bmp, bitmap(Img)),
send(Display, display, Bmp, point(0, 0)),
% draw the object on the display
draw_mandelbrot(Img, Width, Height, Xoffset, Yoffset, Scale),
send(Bmp, flush),
% if desired save the display as .jpg
write_ln('Save the graphics (y/n): '),
get_single_char(A),
put_code(A), nl,
( A =:= 121 -> % ascii(y) = 121
(
atomic_list_concat([Scale, '_', Xoffset, '_', Yoffset, '_', Width, 'x', Height, '.jpg'], FileName),
send(Img, save, FileName, jpeg)
);
true
),
% free objects,
free(Bmp),
free(Img),
free(Display),
!.
% draw_mandelbrot(+Imgage, +Width, +Height, +Xoffset, +Yoffset, +Scale)
% Draws a mandelbrot set with a given size, x-/y-offset and Scale factor.
draw_mandelbrot(Imgage, Width, Height, Xoffset, Yoffset, Scale) :-
% max. number of iterations
MaxIterations is 600,
MaxI is Width-1,
MaxJ is Height-1,
% 0 to Size-1 for X
forall(between(0, MaxI, I), (
% 0 to Size-1 for Y
forall(between(0, MaxJ, J), (
% calculate center, apply Scale factor and offset
X is ((I-(Width/2)) / Scale) - Xoffset,
Y is ((J-(Height/2)) / Scale) - Yoffset,
% calculate iterations
calculate(X, Y, 0, 0, MaxIterations, Result),
% get colour
getRGB(MaxIterations, Result, R,G,B),
% set pixel
send(Imgage, pixel(I, J, colour(@default, R, G, B)))
))
)).
calculate(X, Y, ZX, ZY, Iteration, FinalIteration) :-
ZX * ZX + ZY * ZY < 4, % could complex number be in mandelbrot set?
Iteration > 0, % is iteration lower than max. iteration?
!, % don't backtrace
% magic calculations
Tmp is ZX * ZX - ZY * ZY + X,
ZY2 is 2 * ZX * ZY + Y,
Iteration2 is Iteration - 1,
% continue
calculate(X, Y, Tmp, ZY2, Iteration2, FinalIteration).
% we've either reached max. iteration (Iteration = 0)
% or complex number is not in mandelbrot set (Iteration = how many iterations it took to find out)
calculate(_, _, _, _, Iteration, Iteration).
% getRGB(+MaxIterations, +Iterations, -R, -G, -B)
% returns the RGB colour for a given number of iterations
getRGB(MaxIterations, Iterations, R, G, B) :-
Hue is Iterations/MaxIterations*360*2,
Brightness is (1 - (1/(Iterations+1))) * 0.8,
hsv2rgb(Hue, 1, Brightness, R1, G1, B1),
R is floor(R1 * 65535),
G is floor(G1 * 65535),
B is floor(B1 * 65535).
% hsv2rgb(?H, ?S, ?B, ?R, ?G, ?B).
% Converts between the HSV and RGB colour models.
% Either H,S,V or R,B,G should be instantiated.
hsv2rgb(_, 0, V, V, V, V). % zero saturation => gray
hsv2rgb(H, S, V, R, G, B) :-
S \= 0, % saturation is not zero?
H2 is (floor(H) mod 360) / 60, % Hue can have 360 degrees, divided by 60 leaves 6 sectors (0-5),
I is floor(H2),
F is H2 - I, % factorial part of h
P is V * (1 - S),
Q is V * (1 - S * F),
T is V * (1 - S * (1 - F)),
hsvSector2rgb(I, V, P, Q, T, R, G, B).
% hsvSector2rgb(+I, +V, +P, +Q, +T, -R, -G, -B)
hsvSector2rgb(0, V, P, _, T, V, T, P).
hsvSector2rgb(1, V, P, Q, _, Q, V, P).
hsvSector2rgb(2, V, P, _, T, P, V, T).
hsvSector2rgb(3, V, P, Q, _, P, Q, V).
hsvSector2rgb(4, V, P, _, T, T, P, V).
hsvSector2rgb(5, V, P, Q, _, V, P, Q).
:- draw(
960, 540, % width/height
1.4, % X offset
0.0007, % Y offset
2000000 % Scale
).
% :- draw(512,512, 0.75, 0, 200).
% :- draw(512,512, 1.4, 0, 500).
% :- draw(512,512, 1.4, 0, 1000).
% :- draw(512,512, 1.4, 0, 2000).
% :- draw(512,512, 1.4, 0, 10000).
% :- draw(512,512, 1.4, 0, 20000).
% :- draw(512,512, 1.4, 0, 100000). <==
% :- draw(512,512, 1.4, 0, 200000).
% :- draw(512,512, 1.4, 0.0008, 500000).
% :- draw(512,512, 1.4, 0.0008, 500000).
% :- draw(512,512, 1.4, 0.0007, 2000000).
% high quality (2k 16:9)
% draw(3840,, 1.4, 0.0007, 2000000).
% draw(3840,2160, 1.4, 0.0007, 5000000).
% draw(3840,2160, 1.4, 0.0007, 10000000).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment