Julia set: Difference between revisions
(→{{header|Elixir}}: add Emacs Lisp) |
|||
Line 1,274: | Line 1,274: | ||
showGraphic toColor 640 480 -0.7 0.27015 1.0 5000 |
showGraphic toColor 640 480 -0.7 0.27015 1.0 5000 |
||
</lang> |
</lang> |
||
=={{header|Fortran}}== |
|||
<lang fortran> PROGRAM JULIA |
|||
INTEGER NMAP,NROW,NCOL |
|||
DOUBLE PRECISION SR, SI |
|||
PARAMETER(NMAP=11,NROW=40,NCOL=80,SR=-0.798D0,SI=0.1618D0) |
|||
CHARACTER*1 MAP(NMAP) |
|||
DATA MAP /' ','.',':','-','=','+','*','#','%','$','@'/ |
|||
DOUBLE PRECISION X(NCOL), Y(NROW), ZR, ZI, TT |
|||
INTEGER IR, IC, I, J, MX |
|||
CHARACTER*1 CLR, LINE(NCOL) |
|||
MX = (NMAP-1)*5 |
|||
CALL LINSPACE( NCOL, X, -1.5D0, 1.5D0 ) |
|||
CALL LINSPACE( NROW, Y, -1.0D0, 1.0D0 ) |
|||
WRITE (*,*) SR, SI, MX |
|||
DO 110 IR=1,NROW |
|||
DO 100 IC=1,NCOL |
|||
ZR = X(IC) |
|||
ZI = Y(IR) |
|||
I = 1 |
|||
CLR = ' ' |
|||
10 CONTINUE |
|||
TT = ZR*ZR - ZI*ZI + SR |
|||
ZI = ZR*ZI*2.0D0 + SI |
|||
ZR = TT |
|||
IF ( 4.0D0 .LT. (ZR*ZR + ZI*ZI) ) THEN |
|||
CLR = MAP(MOD(I,NMAP-1)+1) |
|||
GOTO 20 |
|||
END IF |
|||
I = I + 1 |
|||
IF ( MX .GT. I ) GOTO 10 |
|||
20 CONTINUE |
|||
LINE(IC) = CLR |
|||
100 CONTINUE |
|||
WRITE(*,*) (LINE(J),J=1,NCOL) |
|||
110 CONTINUE |
|||
STOP |
|||
END |
|||
SUBROUTINE LINSPACE( N, A, S, F ) |
|||
INTEGER N |
|||
DOUBLE PRECISION A(N), S, F |
|||
INTEGER I |
|||
DOUBLE PRECISION D |
|||
D = (F-S)/DBLE(N-1) |
|||
A(1) = S |
|||
DO 10 I=2,N |
|||
A(I) = A(I-1) + D |
|||
10 CONTINUE |
|||
RETURN |
|||
END</lang> |
|||
{{out}} |
|||
<pre> |
|||
-0.79800000000000004 0.16180000000000000 50 |
|||
.......................:::::::::::::::::::::::::::::::::::::::::::.............. |
|||
..................:::::::::::::::::::::::::::::::::::::::::::::::::::........... |
|||
...............::::::::::::::::::::---------------::::::::::::::::::::::........ |
|||
............:::::::::::::::::::-------==+#+==---------::::::::::::::::::::...... |
|||
..........::::::::::::::::::--------===* *#+===----------::::::::::::::::::..... |
|||
........::::::::::::::::::--------===+#-$. $*====-----------:::::::::::::::::... |
|||
......:::::::::::::::::----------===+*#: $# #*++===-----------::::::::::::::::.. |
|||
....:::::::::::::::::-----------==++*#$:*++ %**++++===-----------::::::::::::::. |
|||
...::::::::::::::::-----------==+**#.#=%: -*$%#%#**#+=======--------:::::::::::: |
|||
..:::::::::::::::----------===+*+ . = -::#==%*+ * #+++===========----::::::::: |
|||
.::::::::::::::-------=======++*%$ $ . =.$% :- -%*+++++====+++*#==----:::::: |
|||
::::::::::::-----==========+++*#. %*% =+#=- $.# $$%*++++**#*#$+ +==-----:::: |
|||
::::::::::----=+++======+++++*#:. -% . + $$ -:%#***# .# ##+===-----:: |
|||
:::::::-----=+*-$#***********##. -$#++#$% $ * %%%% - % .% %*+===----: |
|||
:::::-----===+# = %%% $%#**###%%$ $ - $=- =+ + .$ : $ #:$*+++=---- |
|||
:::-----====+*-%$+%$.=# :.%%%%$-% + +...:-=* +.:+ * - -$###%*=-- |
|||
::-----===+**= .. # $ =:$$ . +:. $ .-+#$- +=+ -::=$: + .=+== |
|||
-----==+++*# $ -= : + #..:=: :#%.*.$$$$ = - $** #*. $ ** ++ + |
|||
---=+#****#% = #===+# # --=*:* *+* %$%##%$=:% % %%$=.= -$#%+ + #- |
|||
-==+#%*-##$ % -..:-+*%. *+++*%: +-.%-$%#**% #- . .% % =-$-# # ##*+= |
|||
=+*## # #-$-= % %. . -# %**#%$-%.-+ :%*+++* .%*+-:..- % $##-*%#+==- |
|||
-# + +%#$- =.=$%% % %:=$%##%$% *+* *:*=-- # #+===# = %#****#+=--- |
|||
+ ++ ** $ .*# **$ - = $$$$.*.%#: :=:..# + : =- $ #*+++==----- |
|||
==+=. + :$=::- +=+ -$#+-. $ .:+ . $$:= $ # .. =**+===-----:: |
|||
--=*%###$- - * +:.+ *=-:...+ + %-$%%%%.: #=.$%+$%-*+====-----::: |
|||
----=+++*$:# $ : $. + += -=$ - $ $%%###**#%$ %%% = #+===-----::::: |
|||
:----===+*% %. % - %%%% * $ %$#++#$- .##***********#$-*+=-----::::::: |
|||
::-----===+## #. #***#%:- $$ + . %- .:#*+++++======+++=----:::::::::: |
|||
::::-----==+ +$#*#**++++*%$$ #.$ -=#+= %*% .#*+++==========-----:::::::::::: |
|||
::::::----==#*+++====+++++*%- -: %$.= . $ $%*++=======-------::::::::::::::. |
|||
:::::::::----===========+++# * +*%==#::- = . +*+===----------:::::::::::::::.. |
|||
::::::::::::--------=======+#**#%#%$*- :%=#.#**+==-----------::::::::::::::::... |
|||
.::::::::::::::-----------===++++**% ++*:$#*++==-----------:::::::::::::::::.... |
|||
..::::::::::::::::-----------===++*# #$ :#*+===----------:::::::::::::::::...... |
|||
...:::::::::::::::::-----------====*$ .$-#+===--------::::::::::::::::::........ |
|||
.....::::::::::::::::::----------===+#* *===--------::::::::::::::::::.......... |
|||
......::::::::::::::::::::---------==+#+==-------:::::::::::::::::::............ |
|||
........::::::::::::::::::::::---------------::::::::::::::::::::............... |
|||
...........:::::::::::::::::::::::::::::::::::::::::::::::::::.................. |
|||
..............:::::::::::::::::::::::::::::::::::::::::::....................... |
|||
</pre> |
|||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
Revision as of 18:59, 9 July 2022
You are encouraged to solve this task according to the task description, using any language you may know.
- Task
Generate and draw a Julia set.
- Related tasks
Ada
<lang Ada>with Ada.Numerics.Generic_Complex_Types;
with SDL.Video.Windows.Makers; with SDL.Video.Renderers.Makers; with SDL.Video.Palettes; with SDL.Events.Events;
procedure Julia_Set is
Width : constant := 1_200; Height : constant := 900;
type Real is new Float; package Complex_Real is new Ada.Numerics.Generic_Complex_Types (Real); use Complex_Real;
Iter : constant := 100; C : constant Complex := (Re => -0.70000, Im => 0.27015); Move : constant Complex := (Re => 0.000, Im => 0.000); Zoom : constant := 0.800;
Window : SDL.Video.Windows.Window; Renderer : SDL.Video.Renderers.Renderer; Event : SDL.Events.Events.Events;
function Map (Width, Height : in Integer; X, Y : in Integer) return Complex is C : Complex; L : constant Real := Real (Integer'Max (Width, Height)); begin C := (2.0 * Real (X - Width / 2) / (L * Zoom), 2.0 * Real (Y - Height / 2) / (L * Zoom)); return C + Move; end Map;
procedure Draw_Julia_Set is use type SDL.C.int; use SDL.Video.Palettes; Z : Complex; begin for Y in 0 .. Height loop for X in 0 .. Width loop Z := Map (Width, Height, X, Y); for N in 1 .. Iter loop Z := Z ** 2 + C; if abs (Z) > 2.0 then Renderer.Set_Draw_Colour ((Red => 2 * Colour_Component (N), Green => 255 - 2 * Colour_Component (N), Blue => 150, Alpha => 255)); Renderer.Draw (Point => (X => SDL.C.int (X), Y => SDL.C.int (Y))); exit; end if; end loop; end loop; end loop; end Draw_Julia_Set;
procedure Wait is use type SDL.Events.Event_Types; begin loop while SDL.Events.Events.Poll (Event) loop if Event.Common.Event_Type = SDL.Events.Quit then return; end if; end loop; end loop; end Wait;
begin
if not SDL.Initialise (Flags => SDL.Enable_Screen) then return; end if;
SDL.Video.Windows.Makers.Create (Win => Window, Title => "Julia set", Position => SDL.Natural_Coordinates'(X => 10, Y => 10), Size => SDL.Positive_Sizes'(Width, Height), Flags => 0); SDL.Video.Renderers.Makers.Create (Renderer, Window.Get_Surface); Renderer.Set_Draw_Colour ((0, 0, 0, 255)); Renderer.Fill (Rectangle => (0, 0, Width, Height));
Draw_Julia_Set; Window.Update_Surface;
Wait; Window.Finalize; SDL.Finalise;
end Julia_Set;</lang>
ALGOL 68
(which is itself a translation of COBOL).
Uses the Algol 68G specific argc and argv procedures. Note argv( 1 ) is the path of the Algol 68G interpreter and argv( 2 ) is the source being executed.
<lang algol68>BEGIN
REAL c real, c imaginary; STRING real and imaginary := IF argc < 3 THEN "-0.8" ELSE argv( 3 ) FI + " " + IF argc < 4 THEN "0.156" ELSE argv( 4 ) FI + " " ; FILE numbers; associate( numbers, real and imaginary ); get( numbers, ( c real, c imaginary ) ); print( ( fixed( c real, -8, 4 ), fixed( c imaginary, -8, 4 ), newline ) ); FOR v FROM -100 BY 10 TO 100 DO FOR h FROM -280 BY 10 TO 280 DO REAL x := h / 200; REAL y := v / 100; CHAR plot char := "#"; FOR i TO 50 WHILE REAL z real = ( x * x ) - ( y * y ) + c real; REAL z imaginary = ( x * y * 2 ) + c imaginary; IF z real * z real <= 10000 THEN TRUE ELSE plot char := " "; FALSE FI DO x := z real; y := z imaginary OD; print( ( plot char ) ) OD; print( ( newline ) ) OD
END</lang>
- Output:
-0.8000 0.1560 # # # # #### #### ###### ######## # ## ######## ## # # ######## ## # ######### # # ##### # # ######## ### ######## # # ### # ## # # #### ##### # ##### # ##### #### # # ## # ### # # ######## ### ######## # # ##### # # ######### # ## ######## # # ## ######## ## # ######## ###### #### #### # # # #
Amazing Hopper
Program made with the Basic-Hopper embedded version, using the tag "#hl {}". The generated file is binary, and the graph can be made with Matlab's "imshow" function.
<lang basic>
- !/usr/bin/hopper
- include <hopper.h>
main:
hxres = 500 // horizontal resolution hyres = 500 // vertical resolution
itermax = 100 // maximum iters to do
brk_out = 64 // |z|^2 greater than this is a breakout magnify = 1 // 10 is standard magnification, but if > 2, resolution should be greater than 500
cr = -0.8 // real part of c in z^2=z^2+c ci = 0.156 // imaginary part of c in z^2=z^2+c
julia=0,{hxres,hyres}nanarray(julia)
{","}toksep
- hl{ // tag "high-level", Basic language embebed in Hopper
hy=1 while(hy<=hyres) hx=1 while(hx<=hxres) y = 4*((((hyres+1-hy-0.5)/hyres)-0.5)/magnify) x = 4*((((hx-0.5)/hxres)-0.5)/magnify) zm = 0 iter=1
while(iter<=(itermax-1)) xx = sqrdiff(x,y)+cr //(x*x)-(y*y)+cr y = (2.0*x*y)+ci x = xx zsq = sqradd(x,y) //(x*x)+(y*y)
if (zsq>zm) zm=zsq endif if (zsq>brk_out) break endif iter += 1 wend
if (iter>=itermax) julia[hy,hx]=1
else julia[hy,hx]=0
endif
hx+=1 wend hy+=1 wend } toc(t1,t2) {julia,"julia.dat"}save
exit(0) </lang>
AWK
<lang AWK>
- syntax: GAWK -f JULIA_SET.AWK [real imaginary]
BEGIN {
c_real = (ARGV[1] != "") ? ARGV[1] : -0.8 c_imaginary = (ARGV[2] != "") ? ARGV[2] : 0.156 printf("%s %s\n",c_real,c_imaginary) for (v=-100; v<=100; v+=10) { for (h=-280; h<=280; h+=10) { x = h / 200 y = v / 100 plot_char = "#" for (i=1; i<=50; i++) { z_real = x * x - y * y + c_real z_imaginary = x * y * 2 + c_imaginary if (z_real ^ 2 > 10000) { plot_char = " " break } x = z_real y = z_imaginary } printf("%1s",plot_char) } printf("\n") } exit(0)
} </lang>
- Output:
-0.8 0.156 # # # # #### #### ###### ######## # ## ######## ## # # ######## ## # ######### # # ##### # # ######## ### ######## # # ### # ## # # #### ##### # ##### # ##### #### # # ## # ### # # ######## ### ######## # # ##### # # ######### # ## ######## # # ## ######## ## # ######## ###### #### #### # # # #
BASIC
QBasic
<lang QBasic>escala = 1 / 81 zeroX = 160 zeroY = 100 maxiter = 32
CR = -.798 CI = .1618
SCREEN 13 FOR x = 0 TO 2 * zeroX - 1
FOR y = 0 TO 2 * zeroY - 1 zreal = (x - zeroX) * escala zimag = (zeroY - y) * escala FOR iter = 1 TO maxiter BR = CR + zreal * zreal - zimag * zimag zimag = CI + 2 * zreal * zimag zreal = BR IF zreal * zreal + zimag * zimag > 4 THEN PSET (x, y), 1 + (iter MOD 16) EXIT FOR END IF NEXT iter NEXT y
NEXT x END</lang>
True BASIC
<lang qbasic>LIBRARY "GraphLib.tru"
LET escala = 1/81 LET zerox = 160 LET zeroy = 100 LET maxiter = 32 LET cr = -.798 LET ci = .1618
SET WINDOW -10, 640, -10, 320 FOR x = 0 TO 2*zerox-1
FOR y = 0 TO 2*zeroy-1 LET zreal = (x-zerox)*escala LET zimag = (zeroy-y)*escala FOR iter = 1 TO maxiter LET br = cr+zreal*zreal-zimag*zimag LET zimag = ci+2*zreal*zimag LET zreal = br IF zreal*zreal+zimag*zimag > 4 THEN SET COLOR 4*t_palette+(REMAINDER(iter,16)) PLOT POINTS: x,y EXIT FOR END IF NEXT iter NEXT y
NEXT x END</lang>
Yabasic
<lang yabasic>escala = 1/120 zeroX = 320 zeroY = 240 maxiter = 32
CR = -.798 CI = .1618
clear screen open window 640, 480 for x = 0 to 2*zeroX - 1
for y = 0 to 2*zeroY - 1 zreal = (x - zeroX) * escala zimag = (zeroY - y) * escala for iter = 1 to maxiter BR = CR + zreal*zreal - zimag*zimag zimag = CI + 2*zreal*zimag zreal = BR if zreal*zreal + zimag*zimag > 4 then dot x, y break end if next iter next y
next x end</lang>
GW-BASIC
<lang gwbasic>10 SCALE# = 1/81 : ZEROX = 160 20 ZEROY = 100 : MAXIT = 32 30 CR# = -.798 : CI# = .1618 40 SCREEN 1 50 FOR X = 0 TO 2*ZEROX - 1 60 FOR Y = 0 TO 2*ZEROY - 1 70 ZR# = (X-ZEROX)*SCALE# 80 ZI# = (ZEROY-Y)*SCALE# 90 FOR I = 1 TO MAXIT 100 BR# = CR# + ZR#*ZR# - ZI#*ZI# 110 ZI# = CI# + 2*ZR#*ZI# 120 ZR# = BR# 130 IF ZR#*ZR# + ZI#*ZI# > 4! THEN GOTO 160 140 NEXT I 150 GOTO 170 160 PSET (X, Y), 1 + (I MOD 3) 170 NEXT Y 180 NEXT X</lang>
Locomotive Basic
Adapted from the Mandelbrot Locomotive Basic program. This program is meant for use in CPCBasic specifically, where it draws a 16-color 640x400 image in less than a minute. (Real CPC hardware would take far longer than that and has lower resolution.) <lang locobasic>1 MODE 3 ' Note the CPCBasic-only screen mode! 2 FOR xp = 0 TO 639 3 FOR yp = 0 TO 399 4 x0 = -0.512511498387847167 : y0 = 0.521295573094847167 5 x = xp / 213 - 1.5 : y = yp / 200 - 1 6 iteration = 0 7 maxIteration = 100 8 WHILE (x * x + y * y <= (2 * 2) AND iteration < maxIteration) 9 xtemp = x * x - y * y + x0 10 y = 2 * x * y + y0 11 x = xtemp 12 iteration = iteration + 1 13 WEND 14 IF iteration <> maxIteration THEN c = iteration ELSE c = 0 15 PLOT xp, yp, c MOD 16 16 NEXT 17 NEXT</lang>
Sinclair ZX81 BASIC
I don't know exactly how long this takes to run; but I left it for about three and a half hours and when I came back it had already finished. If you can't wait to see the results, I've posted a screenshot here. I also haven't tested it with only 1k of RAM—but I suspect it needs at least 2k.
You can try changing lines 10 and 20 to run the program with different values of the complex constant C+D, or lines 50 and 60 to zoom in. <lang basic> 10 LET C=-.8
20 LET D=.156 30 FOR V=43 TO 0 STEP -1 40 FOR H=0 TO 63 50 LET X=(H-32)/21 60 LET Y=(V-22)/21 70 FOR A=1 TO 50 80 LET R=X*X-Y*Y+C 90 LET I=2*X*Y+D
100 IF R*R>1000 THEN GOTO 150 110 LET X=R 120 LET Y=I 130 NEXT A 140 PLOT H,V 150 NEXT H 160 NEXT V</lang>
ZX Spectrum Basic
Higher resolution is obtainable, if you have the time to wait for it. <lang zxbasic> 10 LET creal=-0.8
20 LET cimag=0.156 30 FOR v=-16 TO 16 40 FOR h=-64 TO 64 50 LET x=h/40 60 LET y=v/20 70 FOR i=1 TO 50 80 LET zreal=x*x-y*y+creal 90 LET zimag=x*y*2+cimag
100 IF zreal*zreal>1000 THEN GO TO 150 110 LET x=zreal 120 LET y=zimag 130 NEXT i 140 PLOT h+100,150-v 150 NEXT h 160 NEXT v</lang>
- Output:
Screenshot here.
C
Interactive implementation which takes the following 6 parameters as input :
<executable name> <width of graphics window> <height of graphics window> <real part of complex number> <imag part of complex number> <limiting radius> <Number of iterations to be tested>
Prints out usage on incorrect invocation. Requires the WinBGIm library. <lang C>
- include<graphics.h>
- include<stdlib.h>
- include<math.h>
typedef struct{ double x,y; }complex;
complex add(complex a,complex b){ complex c; c.x = a.x + b.x; c.y = a.y + b.y; return c; }
complex sqr(complex a){ complex c; c.x = a.x*a.x - a.y*a.y; c.y = 2*a.x*a.y; return c; }
double mod(complex a){ return sqrt(a.x*a.x + a.y*a.y); }
complex mapPoint(int width,int height,double radius,int x,int y){ complex c; int l = (width<height)?width:height;
c.x = 2*radius*(x - width/2.0)/l; c.y = 2*radius*(y - height/2.0)/l;
return c; }
void juliaSet(int width,int height,complex c,double radius,int n){ int x,y,i; complex z0,z1;
for(x=0;x<=width;x++) for(y=0;y<=height;y++){ z0 = mapPoint(width,height,radius,x,y); for(i=1;i<=n;i++){ z1 = add(sqr(z0),c); if(mod(z1)>radius){ putpixel(x,y,i%15+1); break; } z0 = z1; } if(i>n) putpixel(x,y,0); } }
int main(int argC, char* argV[]) { int width, height; complex c;
if(argC != 7) printf("Usage : %s <width and height of screen, real and imaginary parts of c, limit radius and iterations>"); else{ width = atoi(argV[1]); height = atoi(argV[2]);
c.x = atof(argV[3]); c.y = atof(argV[4]);
initwindow(width,height,"Julia Set"); juliaSet(width,height,c,atof(argV[5]),atoi(argV[6]));
getch(); }
return 0; } </lang>
C#
<lang csharp>using System.Drawing; // Note: You have to add the System.Drawing assembly // (right-click "references," Add Reference, Assemblies, Framework, // System.Drawing, OK) using System.Linq;
namespace RosettaJuliaSet {
class Program { static void Main(string[] args) { const int w = 800; const int h = 600; const int zoom = 1; const int maxiter = 255; const int moveX = 0; const int moveY = 0; const double cX = -0.7; const double cY = 0.27015; double zx, zy, tmp; int i;
var colors = (from c in Enumerable.Range(0, 256) select Color.FromArgb((c >> 5) * 36, (c >> 3 & 7) * 36, (c & 3) * 85)).ToArray();
var bitmap = new Bitmap(w, h); for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { zx = 1.5 * (x - w / 2) / (0.5 * zoom * w) + moveX; zy = 1.0 * (y - h / 2) / (0.5 * zoom * h) + moveY; i = maxiter; while (zx * zx + zy * zy < 4 && i > 1) { tmp = zx * zx - zy * zy + cX; zy = 2.0 * zx * zy + cY; zx = tmp; i -= 1; } bitmap.SetPixel(x, y, colors[i]); } } bitmap.Save("julia-set.png"); } }
} </lang>
C# also makes it relatively easy to do a multi-threaded version, which should run faster than the above:
<lang csharp>
public struct CalculatedPoint { public int x; public int y; public int i; }
static void MultiThreaded() { const int w = 800; const int h = 600; const int zoom = 1; const int maxiter = 255; const int moveX = 0; const int moveY = 0; const double cX = -0.7; const double cY = 0.27015;
// Precalculate a pallette of 256 colors var colors = (from c in Enumerable.Range(0, 256) select Color.FromArgb((c >> 5) * 36, (c >> 3 & 7) * 36, (c & 3) * 85)).ToArray();
// The "AsParallel" below invokes PLINQ, making evaluation parallel using as many cores as // are available. var calculatedPoints = Enumerable.Range(0, w * h).AsParallel().Select(xy => { double zx, zy, tmp; int x, y; int i = maxiter; y = xy / w; x = xy % w; zx = 1.5 * (x - w / 2) / (0.5 * zoom * w) + moveX; zy = 1.0 * (y - h / 2) / (0.5 * zoom * h) + moveY; while (zx * zx + zy * zy < 4 && i > 1) { tmp = zx * zx - zy * zy + cX; zy = 2.0 * zx * zy + cY; zx = tmp; i -= 1; } return new CalculatedPoint { x = x, y = y, i = i }; });
// Bitmap is not multi-threaded, so main thread needs to read in the results as they // come in and plot the pixels. var bitmap = new Bitmap(w, h); foreach (CalculatedPoint cp in calculatedPoints) bitmap.SetPixel(cp.x, cp.y, colors[cp.i]); bitmap.Save("julia-set-multi.png"); }</lang>
C++
<lang cpp>
- include <windows.h>
- include <string>
- include <complex>
const int BMP_SIZE = 600, ITERATIONS = 512; const long double FCT = 2.85, hFCT = FCT / 2.0;
class myBitmap { public:
myBitmap() : pen( NULL ), brush( NULL ), clr( 0 ), wid( 1 ) {} ~myBitmap() { DeleteObject( pen ); DeleteObject( brush ); DeleteDC( hdc ); DeleteObject( bmp ); } bool create( int w, int h ) { BITMAPINFO bi; ZeroMemory( &bi, sizeof( bi ) ); bi.bmiHeader.biSize = sizeof( bi.bmiHeader ); bi.bmiHeader.biBitCount = sizeof( DWORD ) * 8; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biWidth = w; bi.bmiHeader.biHeight = -h; HDC dc = GetDC( GetConsoleWindow() ); bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 ); if( !bmp ) return false; hdc = CreateCompatibleDC( dc ); SelectObject( hdc, bmp ); ReleaseDC( GetConsoleWindow(), dc ); width = w; height = h; return true; } void clear( BYTE clr = 0 ) { memset( pBits, clr, width * height * sizeof( DWORD ) ); } void setBrushColor( DWORD bClr ) { if( brush ) DeleteObject( brush ); brush = CreateSolidBrush( bClr ); SelectObject( hdc, brush ); } void setPenColor( DWORD c ) { clr = c; createPen(); } void setPenWidth( int w ) { wid = w; createPen(); } void saveBitmap( std::string path ) { BITMAPFILEHEADER fileheader; BITMAPINFO infoheader; BITMAP bitmap; DWORD wb; GetObject( bmp, sizeof( bitmap ), &bitmap ); DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight]; ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) ); ZeroMemory( &infoheader, sizeof( BITMAPINFO ) ); ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) ); infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8; infoheader.bmiHeader.biCompression = BI_RGB; infoheader.bmiHeader.biPlanes = 1; infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader ); infoheader.bmiHeader.biHeight = bitmap.bmHeight; infoheader.bmiHeader.biWidth = bitmap.bmWidth; infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ); fileheader.bfType = 0x4D42; fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER ); fileheader.bfSize = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage; GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS ); HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL ); WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL ); WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL ); CloseHandle( file ); delete [] dwpBits; } HDC getDC() const { return hdc; } int getWidth() const { return width; } int getHeight() const { return height; } DWORD* bits() const { return ( DWORD* )pBits; }
private:
void createPen() { if( pen ) DeleteObject( pen ); pen = CreatePen( PS_SOLID, wid, clr ); SelectObject( hdc, pen ); } HBITMAP bmp; HDC hdc; HPEN pen; HBRUSH brush; void *pBits; int width, height, wid; DWORD clr;
}; class julia { public:
void draw( std::complex<long double> k ) { bmp.create( BMP_SIZE, BMP_SIZE ); DWORD* bits = bmp.bits(); int res, pos; std::complex<long double> c, factor( FCT / BMP_SIZE, FCT / BMP_SIZE ) ;
for( int y = 0; y < BMP_SIZE; y++ ) { pos = y * BMP_SIZE;
c.imag( ( factor.imag() * y ) + -hFCT );
for( int x = 0; x < BMP_SIZE; x++ ) { c.real( factor.real() * x + -hFCT ); res = inSet( c, k ); if( res ) { int n_res = res % 255; if( res < ( ITERATIONS >> 1 ) ) res = RGB( n_res << 2, n_res << 3, n_res << 4 ); else res = RGB( n_res << 4, n_res << 2, n_res << 5 ); } bits[pos++] = res; } } bmp.saveBitmap( "./js.bmp" ); }
private:
int inSet( std::complex<long double> z, std::complex<long double> c ) { long double dist;//, three = 3.0; for( int ec = 0; ec < ITERATIONS; ec++ ) { z = z * z; z = z + c; dist = ( z.imag() * z.imag() ) + ( z.real() * z.real() ); if( dist > 3 ) return( ec ); } return 0; } myBitmap bmp;
}; int main( int argc, char* argv[] ) {
std::complex<long double> c; long double factor = FCT / BMP_SIZE; c.imag( ( factor * 184 ) + -1.4 ); c.real( ( factor * 307 ) + -2.0 ); julia j; j.draw( c ); return 0;
} </lang>
COBOL
Plots—in ASCII or EBCDIC art—a Julia set for the function f(z) = z2 + c, based on a value of c input by the user (real part then imaginary part, pressing the carriage return key after each). The sample output is for the inputs -0.8 and 0.156. <lang cobol>IDENTIFICATION DIVISION. PROGRAM-ID. JULIA-SET-PROGRAM. DATA DIVISION. WORKING-STORAGE SECTION. 01 WS-COMPLEX-CONSTANT.
05 C-REAL PIC S9V999. 05 C-IMAGINARY PIC S9V999.
01 WS-ARGAND-PLANE.
05 X PIC S9(9)V999. 05 Y PIC S9(9)V999.
01 WS-COMPLEX-VARIABLE.
05 Z-REAL PIC S9(9)V999. 05 Z-IMAGINARY PIC S9(9)V999.
01 WS-TEMPORARY-RESULTS.
05 X-SQUARED PIC S9(9)V999. 05 Y-SQUARED PIC S9(9)V999. 05 X-TIMES-Y PIC S9(9)V999. 05 Z-REAL-SQUARED PIC S9(9)V999.
01 WS-LOOP-COUNTERS.
05 HORIZONTAL PIC 999. 05 VERTICAL PIC 999. 05 ITERATIONS PIC 99.
77 WS-PLOT-CHARACTER PIC X. PROCEDURE DIVISION. INPUT-COMPLEX-CONSTANT-PARAGRAPH.
ACCEPT C-REAL FROM CONSOLE. ACCEPT C-IMAGINARY FROM CONSOLE.
CONTROL-PARAGRAPH.
PERFORM OUTER-LOOP-PARAGRAPH VARYING VERTICAL FROM 1 BY 10 UNTIL VERTICAL IS GREATER THAN 320. STOP RUN.
OUTER-LOOP-PARAGRAPH.
PERFORM COMPUTATION-PARAGRAPH VARYING HORIZONTAL FROM 1 BY 10 UNTIL HORIZONTAL IS GREATER THAN 560. DISPLAY UPON CONSOLE.
COMPUTATION-PARAGRAPH.
SUBTRACT 280 FROM HORIZONTAL GIVING X. SUBTRACT 160 FROM VERTICAL GIVING Y. DIVIDE X BY 200 GIVING X. DIVIDE Y BY 100 GIVING Y. MOVE '#' TO WS-PLOT-CHARACTER. PERFORM COMPLEX-MULTIPLICATION-PARAGRAPH VARYING ITERATIONS FROM 1 BY 1 UNTIL ITERATIONS IS GREATER THAN 50 OR WS-PLOT-CHARACTER IS EQUAL TO SPACE. DISPLAY WS-PLOT-CHARACTER UPON CONSOLE WITH NO ADVANCING.
COMPLEX-MULTIPLICATION-PARAGRAPH.
MULTIPLY X BY X GIVING X-SQUARED. MULTIPLY Y BY Y GIVING Y-SQUARED. SUBTRACT Y-SQUARED FROM X-SQUARED GIVING Z-REAL. ADD C-REAL TO Z-REAL. MULTIPLY X BY Y GIVING X-TIMES-Y. MULTIPLY X-TIMES-Y BY 2 GIVING Z-IMAGINARY. ADD C-IMAGINARY TO Z-IMAGINARY. MULTIPLY Z-REAL BY Z-REAL GIVING Z-REAL-SQUARED. IF Z-REAL-SQUARED IS GREATER THAN 10000 THEN MOVE SPACE TO WS-PLOT-CHARACTER. MOVE Z-REAL TO X. MOVE Z-IMAGINARY TO Y.</lang>
- Output:
### ## ## # ### #### # ################ ### # # # ############### # ####### ## ##### ######## # # ##### ## ######## ### ######## # ### ### # ## # ## # #### # # # #### # #### ### # # # ### # # ######### # ## ###### # ######### # ######### ###### # ### ### ## ## ############ # # # ######### ## ## # ##### #### # # ### #
Crystal
<lang ruby>require "complex"
def julia(c_real, c_imag)
puts Complex.new(c_real, c_imag) -1.0.step(to: 1.0, by: 0.04) do |v| puts -1.4.step(to: 1.4, by: 0.02).map{|h| judge(c_real, c_imag, h, v)}.join end
end
def judge(c_real, c_imag, x, y)
50.times do z_real = (x * x - y * y) + c_real z_imag = x * y * 2 + c_imag return " " if z_real**2 > 10000 x, y = z_real, z_imag end "#"
end
julia(-0.8, 0.156) </lang>
- Output:
-0.8 + 0.156i # # ## ####### ## #### ## # #### ## # # # ### ### # ## # # ###### ########## # # # # ###### ########## # # ### ### # ############ ###### # ################ ################### # # ### # ################ #################### ## # ### ## ## ############################## ### #### # ####### ### # ## ## # ##################### # #### ## #### ### ########### ###### # # ##### ##################### # # ## ###################### ### ####### #### # ####################### # ### ############ ### ## ## ## ## ## ################# ######################## ### ########### ## ### ## ################# ## ###### # # ################### # ##### ## ######## # ### # ###### ############ ## ## # ### ############## # ## ### ## # #### # # ## ### ## ########### ## #### ############# ## # ## ### ## ## ####### ## ##### ######### ############# ### # # ####### # # ### ############# ######### ##### ## ####### ## ## ### ## # ## ############# #### ## ########### ## ### ## # # #### # ## ### ## # ############## ### # ## ## ############ ###### # ### # ######## ## ##### # ################### # # ###### ## ################# ### ### ## ########### ### ######################## ################# ## ## ## ## ## ### ############ ### # ####################### # #### ####### ### ###################### ## # # ##################### ##### # # ###### ########### ### #### ## #### # ##################### # ## ## # ### ####### # #### ### ############################## ## ## ### # ## #################### ################ # ### # # ################### ################ # ###### ############ # ### ### # # ########## ###### # # # # ########## ###### # # ## # ### ### # # # ## #### # ## #### ## ####### ## # #
Delphi
<lang Delphi> program Julia_set;
{$APPTYPE CONSOLE}
uses
System.SysUtils, Winapi.Windows, Vcl.Graphics;
var
Colors: array[0..255] of TColor; w, h, zoom, maxiter, moveX, moveY: Integer; cX, cY, zx, zy, tmp: Double; i: Integer; bitmap: TBitmap; x, y: Integer;
begin
w := 800; h := 600; zoom := 1; maxiter := 255; moveX := 0; moveY := 0; cX := -0.7; cY := 0.27015; bitmap := TBitmap.Create(); bitmap.SetSize(w, h); bitmap.Canvas.Brush.Color := clwhite; bitmap.Canvas.FillRect(bitmap.Canvas.ClipRect);
for i := 0 to 255 do Colors[i] := RGB((i shr 5) * 36, ((i shr 3) and 7) * 36, (i and 3) * 85);
for x := 0 to w - 1 do begin for y := 0 to h - 1 do begin zx := 1.5 * (x - w / 2) / (0.5 * zoom * w) + moveX; zy := 1.0 * (y - h / 2) / (0.5 * zoom * h) + moveY; i := maxiter; while (zx * zx + zy * zy < 4) and (i > 1) do begin tmp := zx * zx - zy * zy + cX; zy := 2.0 * zx * zy + cY; zx := tmp; i := i - 1; end; bitmap.Canvas.Pixels[x, y] := colors[i]; end; end;
bitmap.SaveToFile('julia-set.bmp'); bitmap.Free;
end. </lang>
EasyLang
<lang>cx = -0.7 cy = 0.27015 for y range 300
for x range 300 zx = (x - 150) / 100 zy = (y - 150) / 150 color3 0 0 0 for iter range 128 if zx * zx + zy * zy > 4 color3 iter / 16 0 0 break 1 . h = zx * zx - zy * zy + cx zy = 2 * zx * zy + cy zx = h . move x / 3 y / 3 rect 0.4 0.4 .
.</lang>
Elixir
<lang elixir>defmodule Julia do
def set(c_real, c_imag) do IO.puts "#{c_real}, #{c_imag}" vlist = Enum.take_every(-100..100, 4) hlist = Enum.take_every(-280..280, 4) Enum.each(vlist, fn v -> Enum.map(hlist, fn h -> loop(c_real, c_imag, h/200, v/100, "#", 0) end) |> IO.puts end) end defp loop(_, _, _, _, char, i) when i>=50, do: char defp loop(_, _, _, _, " ", _), do: " " defp loop(c_real, c_imag, x, y, char, i) do z_real = (x * x - y * y) + c_real z_imag = x * y * 2 + c_imag char = if z_real * z_real > 10000, do: " ", else: char loop(c_real, c_imag, z_real, z_imag, char, i+1) end
end
c_real = if r=Enum.at(System.argv, 0), do: Float.parse(r) |> elem(0), else: -0.8 c_imag = if c=Enum.at(System.argv, 1), do: Float.parse(c) |> elem(0), else: 0.156 Julia.set(c_real, c_imag)</lang>
- Output:
-0.8, 0.156 # # ## ####### ## #### ## # #### ## # # # ### ### # ## # # ###### ########## # # # # ###### ########## # # ### ### # ############ ###### # ################ ################### # # ### # ################ #################### ## # ### ## ## ############################## ### #### # ####### ### # ## ## # ##################### # #### ## #### ### ########### ###### # # ##### ##################### # # ## ###################### ### ####### #### # ####################### # ### ############ ### ## ## ## ## ## ################# ######################## ### ########### ## ### ### ################# ## ###### # # ################### # ##### ## ######## # ### # ###### ############ ## ## # ### ############## # ## ### ## # #### # # ## ### ## ########### ## #### ############# ## # ## ### ## ## ####### ## ##### ######### ############# ### # # ####### # # ### ############# ######### ##### ## ####### ## ## ### ## # ## ############# #### ## ########### ## ### ## # # #### # ## ### ## # ############## ### # ## ## ############ ###### # ### # ######## ## ##### # ################### # # ###### ## ################# ### ### ## ########### ### ######################## ################# ## ## ## ## ## ### ############ ### # ####################### # #### ####### ### ###################### ## # # ##################### ##### # # ###### ########### ### #### ## #### # ##################### # ## ## # ### ####### # #### ### ############################## ## ## ### # ## #################### ################ # ### # # ################### ################ # ###### ############ # ### ### # # ########## ###### # # # # ########## ###### # # ## # ### ### # # # ## #### # ## #### ## ####### ## # #
Emacs Lisp
<lang lisp>; === Graphical Julia set display in Emacs =====================
(setq julia-size (cons 300 200)) (setq xmin -1.5) (setq xmax 1.5) (setq ymin -1) (setq ymax 1) (setq julia0 (cons -0.512511498387847167 0.521295573094847167)) (setq max-iter 100)
(defun julia-iter-point (x y)
"Run the actual iteration for each point." (let ((xp x) (yp y) (it 0) (xt 0)) (while (and (< (+ (* xp xp) (* yp yp)) 4) (< it max-iter)) (setq xt (+ (* xp xp) (* -1 yp yp) (car julia0))) (setq yp (+ (* 2 xp yp) (cdr julia0))) (setq xp xt) (setq it (1+ it))) it))
(defun julia-iter (p)
"Return string for point based on whether inside/outside the set." (let ((it (julia-iter-point (car p) (cdr p)))) (if (= it max-iter) "*" (if (cl-oddp it) "+" "-"))))
(defun julia-pos (x y)
"Convert screen coordinates to input coordinates." (let ((xp (+ xmin (* (- xmax xmin) (/ (float x) (car julia-size))))) (yp (+ ymin (* (- ymax ymin) (/ (float y) (cdr julia-size)))))) (cons xp yp)))
(defun string-to-image (str)
"Convert image data string to XPM image with three colors." (create-image (concat (format "/* XPM */
static char * julia[] = { \"%i %i 3 1\", \"+ c #ff0000\", \"- c #0000ff\", \"* c #000000\"," (car julia-size) (cdr julia-size))
str "};") 'xpm t))
(defun julia-pic ()
"Plot the Julia set in color." (setq all "") (dotimes (y (cdr julia-size)) (setq line "") (dotimes (x (car julia-size)) (setq line (concat line (julia-iter (julia-pos x y))))) (setq all (concat all "\"" line "\",\n"))) (insert-image (string-to-image all)))
(julia-pic)</lang>
F#
Basic generation code <lang fsharp> let getJuliaValues width height centerX centerY zoom maxIter =
let initzx x = 1.5 * float(x - width/2) / (0.5 * zoom * float(width)) let initzy y = 1.0 * float(y - height/2) / (0.5 * zoom * float(height)) let calc y x = let rec loop i zx zy = if i=maxIter then 0 elif zx*zx + zy*zy >= 4.0 then i else loop (i + 1) (zx*zx - zy*zy + centerX) (2.0*zx*zy + centerY) loop 0 (initzx x) (initzy y) [0..height-1] |> List.map(fun y->[0..width-1] |> List.map (calc y))
</lang>
Text display <lang fsharp> getJuliaValues 80 25 -0.7 0.27015 1.0 50 |> List.map(fun row-> row |> List.map (function | 0 ->" " |_->".") |> String.concat "") |> List.iter (printfn "%s") </lang>
- Output:
................................................................................ .......................................... ..................................... ........................................ ..................................... ......................................... ................................... ...................................... .................................. ................................... ..... ........................... .................................. . . . ...... . ........... ................................... ..... .. ...... . . .......... ................. ....... ............. .. .... . ........ ................. . . ... ............ . .. .... .............. . . .. . . . . ................. .. . .. ...... ....... .. . .... .... . .. ...... ....... .. . .. ................ .. . . . .. . . ............. ..... .. . ............ ... . . ................ ......... . .... .. ............. ....... ................ ........... . . ...... .. ..... .................................. ............ . ...... . . . ................................. ............................ ..... .................................. ................................... ..................................... .................................... ........................................ ...................................... ....................................... ...................................... ......................................... ................................................................................
Graphic Display <lang fsharp> open System.Drawing open System.Windows.Forms
let showGraphic (colorForIter: int -> Color) width height centerX centerY zoom maxIter =
new Form() |> fun frm -> frm.Width <- width frm.Height <- height frm.BackgroundImage <- new Bitmap(width,height) |> fun bmp -> getJuliaValues width height centerX centerY zoom maxIter |> List.mapi (fun y row->row |> List.mapi (fun x v->((x,y),v))) |> List.collect id |> List.iter (fun ((x,y),v) -> bmp.SetPixel(x,y,(colorForIter v))) bmp frm.Show()
let toColor = (function | 0 -> (0,0,0) | n -> ((31 &&& n) |> fun x->(0, 18 + x * 5, 36 + x * 7))) >> Color.FromArgb
showGraphic toColor 640 480 -0.7 0.27015 1.0 5000 </lang>
Fortran
<lang fortran> PROGRAM JULIA
INTEGER NMAP,NROW,NCOL DOUBLE PRECISION SR, SI PARAMETER(NMAP=11,NROW=40,NCOL=80,SR=-0.798D0,SI=0.1618D0) CHARACTER*1 MAP(NMAP) DATA MAP /' ','.',':','-','=','+','*','#','%','$','@'/ DOUBLE PRECISION X(NCOL), Y(NROW), ZR, ZI, TT INTEGER IR, IC, I, J, MX CHARACTER*1 CLR, LINE(NCOL)
MX = (NMAP-1)*5 CALL LINSPACE( NCOL, X, -1.5D0, 1.5D0 ) CALL LINSPACE( NROW, Y, -1.0D0, 1.0D0 )
WRITE (*,*) SR, SI, MX
DO 110 IR=1,NROW DO 100 IC=1,NCOL ZR = X(IC) ZI = Y(IR) I = 1 CLR = ' ' 10 CONTINUE TT = ZR*ZR - ZI*ZI + SR ZI = ZR*ZI*2.0D0 + SI ZR = TT IF ( 4.0D0 .LT. (ZR*ZR + ZI*ZI) ) THEN CLR = MAP(MOD(I,NMAP-1)+1) GOTO 20 END IF I = I + 1 IF ( MX .GT. I ) GOTO 10 20 CONTINUE LINE(IC) = CLR 100 CONTINUE WRITE(*,*) (LINE(J),J=1,NCOL) 110 CONTINUE STOP END
SUBROUTINE LINSPACE( N, A, S, F ) INTEGER N DOUBLE PRECISION A(N), S, F INTEGER I DOUBLE PRECISION D D = (F-S)/DBLE(N-1) A(1) = S DO 10 I=2,N A(I) = A(I-1) + D 10 CONTINUE RETURN END</lang>
- Output:
-0.79800000000000004 0.16180000000000000 50 .......................:::::::::::::::::::::::::::::::::::::::::::.............. ..................:::::::::::::::::::::::::::::::::::::::::::::::::::........... ...............::::::::::::::::::::---------------::::::::::::::::::::::........ ............:::::::::::::::::::-------==+#+==---------::::::::::::::::::::...... ..........::::::::::::::::::--------===* *#+===----------::::::::::::::::::..... ........::::::::::::::::::--------===+#-$. $*====-----------:::::::::::::::::... ......:::::::::::::::::----------===+*#: $# #*++===-----------::::::::::::::::.. ....:::::::::::::::::-----------==++*#$:*++ %**++++===-----------::::::::::::::. ...::::::::::::::::-----------==+**#.#=%: -*$%#%#**#+=======--------:::::::::::: ..:::::::::::::::----------===+*+ . = -::#==%*+ * #+++===========----::::::::: .::::::::::::::-------=======++*%$ $ . =.$% :- -%*+++++====+++*#==----:::::: ::::::::::::-----==========+++*#. %*% =+#=- $.# $$%*++++**#*#$+ +==-----:::: ::::::::::----=+++======+++++*#:. -% . + $$ -:%#***# .# ##+===-----:: :::::::-----=+*-$#***********##. -$#++#$% $ * %%%% - % .% %*+===----: :::::-----===+# = %%% $%#**###%%$ $ - $=- =+ + .$ : $ #:$*+++=---- :::-----====+*-%$+%$.=# :.%%%%$-% + +...:-=* +.:+ * - -$###%*=-- ::-----===+**= .. # $ =:$$ . +:. $ .-+#$- +=+ -::=$: + .=+== -----==+++*# $ -= : + #..:=: :#%.*.$$$$ = - $** #*. $ ** ++ + ---=+#****#% = #===+# # --=*:* *+* %$%##%$=:% % %%$=.= -$#%+ + #- -==+#%*-##$ % -..:-+*%. *+++*%: +-.%-$%#**% #- . .% % =-$-# # ##*+= =+*## # #-$-= % %. . -# %**#%$-%.-+ :%*+++* .%*+-:..- % $##-*%#+==- -# + +%#$- =.=$%% % %:=$%##%$% *+* *:*=-- # #+===# = %#****#+=--- + ++ ** $ .*# **$ - = $$$$.*.%#: :=:..# + : =- $ #*+++==----- ==+=. + :$=::- +=+ -$#+-. $ .:+ . $$:= $ # .. =**+===-----:: --=*%###$- - * +:.+ *=-:...+ + %-$%%%%.: #=.$%+$%-*+====-----::: ----=+++*$:# $ : $. + += -=$ - $ $%%###**#%$ %%% = #+===-----::::: :----===+*% %. % - %%%% * $ %$#++#$- .##***********#$-*+=-----::::::: ::-----===+## #. #***#%:- $$ + . %- .:#*+++++======+++=----:::::::::: ::::-----==+ +$#*#**++++*%$$ #.$ -=#+= %*% .#*+++==========-----:::::::::::: ::::::----==#*+++====+++++*%- -: %$.= . $ $%*++=======-------::::::::::::::. :::::::::----===========+++# * +*%==#::- = . +*+===----------:::::::::::::::.. ::::::::::::--------=======+#**#%#%$*- :%=#.#**+==-----------::::::::::::::::... .::::::::::::::-----------===++++**% ++*:$#*++==-----------:::::::::::::::::.... ..::::::::::::::::-----------===++*# #$ :#*+===----------:::::::::::::::::...... ...:::::::::::::::::-----------====*$ .$-#+===--------::::::::::::::::::........ .....::::::::::::::::::----------===+#* *===--------::::::::::::::::::.......... ......::::::::::::::::::::---------==+#+==-------:::::::::::::::::::............ ........::::::::::::::::::::::---------------::::::::::::::::::::............... ...........:::::::::::::::::::::::::::::::::::::::::::::::::::.................. ..............:::::::::::::::::::::::::::::::::::::::::::.......................
FreeBASIC
<lang freebasic>
- define pix 1./120
- define zero_x 320
- define zero_y 240
- define maxiter 250
type complex
r as double i as double
end type
operator + (x as complex, y as complex) as complex
dim as complex ret ret.r = x.r + y.r ret.i = x.i + y.i return ret
end operator
operator * (x as complex, y as complex) as complex
dim as complex ret ret.r = x.r*y.r - x.i*y.i ret.i = x.r*y.i + x.i*y.r return ret
end operator
operator abs ( x as complex ) as double
return sqr(x.r*x.r + x.i*x.i)
end operator
dim as complex c, z dim as integer x, y, iter
input "Real part of c? ", c.r input "Imaginary part of c? ", c.i
screen 12
for x=0 to 639
for y=0 to 479 z.r = (x-zero_x)*pix z.i = (y-zero_y)*pix for iter=0 to maxiter z = z*z + c if abs(z)>2 then pset(x,y),iter mod 16 goto cont end if next iter pset(x,y),1 cont: next y
next x
while inkey="" wend end</lang>
Fōrmulæ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website, However they run on execution servers. By default remote servers are used, but they are limited in memory and processing power, since they are intended for demonstration and casual use. A local server can be downloaded and installed, it has no limitations (it runs in your own computer). Because of that, example programs can be fully visualized and edited, but some of them will not run if they require a moderate or heavy computation/memory resources, and no local server is being used.
In this page you can see the program(s) related to this task and their results.
Go
Using the Goroutines results in a performance improvement of about three times on my four-core machine. <lang Go>package main
import ( "image" "image/color" "image/png" "log" "os" "sync" )
func main() { const ( width, height = 800.0, 600.0 maxIter = 255 cX, cY = -0.7, 0.27015 fileName = "julia.png" ) img := image.NewNRGBA(image.Rect(0, 0, width, height))
var wg sync.WaitGroup wg.Add(width) for x := 0; x < width; x++ { thisx := float64(x) go func() { var tmp, zx, zy float64 var i uint8 for y := 0.0; y < height; y++ { zx = 1.5 * (thisx - width/2) / (0.5 * width) zy = (y - height/2) / (0.5 * height) i = maxIter for zx*zx+zy*zy < 4.0 && i > 0 { tmp = zx*zx - zy*zy + cX zy = 2.0*zx*zy + cY zx = tmp i-- } img.Set(int(thisx), int(y), color.RGBA{i, i, i << 3, 255}) } wg.Done() }() } wg.Wait() imgFile, err := os.Create(fileName) if err != nil { log.Fatal(err) } defer imgFile.Close() if err := png.Encode(imgFile, img); err != nil { imgFile.Close() log.Fatal(err) } }</lang>
Haskell
<lang haskell>import System.Environment (getArgs)
plotChar :: Int -> Float -> Float -> Float -> Float -> Char plotChar iter cReal cImag y x
| zReal^2 > 10000 = ' ' | iter == 1 = '#' | otherwise = plotChar (pred iter) cReal cImag zImag zReal where zReal = x * x - y * y + cReal zImag = x * y * 2 + cImag
parseArgs :: [String] -> (Float, Float) parseArgs [] = (-0.8, 0.156) parseArgs [cReal, cImag] = (read cReal :: Float, read cImag :: Float) parseArgs _ = error "Invalid arguments"
main :: IO () main = do
args <- getArgs let (cReal, cImag) = parseArgs args print (cReal, cImag) mapM_ putStrLn $ [-100,-96..100] >>= \y -> [[-280,-276..280] >>= \x -> [plotChar 50 cReal cImag (y/100) (x/200)]]
</lang>
- Output:
(-0.8,0.156) # # ## ####### ## #### ## # #### ## # # # ### ### # ## # # ###### ########## # # # # ###### ########## # # ### ### # ############ ###### # ################ ################### # # ### # ################ #################### ## # ### ## ## ############################## ### #### # ####### ### # ## ## # ##################### # #### ## #### ### ########### ###### # # ##### ##################### # # ## ###################### ### ####### #### # ####################### # ### ############ ### ## ## ## ## ## ################# ######################## ### ########### ## ### ### ################# ## ###### # # ################### # ##### ## ######## # ### # ###### ############ ## ## # ### ############## # ## ### ## # #### # # ## ### ## ########### ## #### ############# ## # ## ### ## ## ####### ## ##### ######### ############# ### # # ####### # # ### ############# ######### ##### ## ####### ## ## ### ## # ## ############# #### ## ########### ## ### ## # # #### # ## ### ## # ############## ### # ## ## ############ ###### # ### # ######## ## ##### # ################### # # ###### ## ################# ### ### ## ########### ### ######################## ################# ## ## ## ## ## ### ############ ### # ####################### # #### ####### ### ###################### ## # # ##################### ##### # # ###### ########### ### #### ## #### # ##################### # ## ## # ### ####### # #### ### ############################## ## ## ### # ## #################### ################ # ### # # ################### ################ # ###### ############ # ### ### # # ########## ###### # # # # ########## ###### # # ## # ### ### # # # ## #### # ## #### ## ####### ## # #
<lang haskell>{-# LANGUAGE LambdaCase #-}
getJuliaValues :: Float -> Float -> Float -> Float -> Float -> Int -> Int getJuliaValues width height centerX centerY zoom maxIter =
[0..pred height] >>= \h -> [[0..pred width] >>= \w -> [calc h w]] where initzx x = 1.5 * (x - width / 2) / (0.5 * zoom * width) initzy y = 1.0 * (y - height / 2) / (0.5 * zoom * height) calc y x = loop 0 (initzx x) (initzy y) where loop i zx zy | zx * zx + zy * zy >= 4.0 = i | i == maxIter = 0 | otherwise = loop (succ i) (zx*zx - zy*zy + centerX) (2.0*zx*zy + centerY)
main :: IO () main = mapM_ (putStrLn . fmap (\case 0 -> '#'; _ -> ' ')) (getJuliaValues 140 50 (-0.8) 0.156 1.0 50) </lang>
- Output:
# # # ####### # ## ## ## # #### ## # # # ###### #### ### # ## ###### ######## # # ##### ########## # # # ## # # ########### #### ### # ### ########### ################## # # ### # ############### ########### ####### ## ### ## # ############################ ## ##### ######## ### # ## # # ################### #### ## # #### ### ################# # ## # # #################### # # # ## ################### # ### ##### #### ##################### # # ### ########### # # ## # # # ## ################## ###################### ### ########### ## ###### ############### ## ###### ##################### ###### ## ######## # ### # ### # # ########### # ## # ### ############ ### ### ## # ### # ## ### ## # ### ########## # #### ############ # # ## ## ### ## ####### ## # #### ########## ############ ## ####### ## ############ ########## #### # ## ####### ## ### ## ## # # ############ #### # ########## ### # ## ### ## # ### # ## ### ### ############ ### # ## # ########### # # ### # ### # ######## ## ###### ##################### ###### ## ############### ###### ## ########### ### ###################### ################## ## # # # ## # # ########### ### # # ##################### #### ##### ### # ################### ## # # # #################### # # ## # ################# ### #### # ## #### ################### # # ## # ### ######## ##### ## ############################ # ## ### ## ####### ########### ############### # ### # # ################## ########### ### # ### #### ########### # # ## # # # ########## ##### # # ######## ###### ## # ### #### ###### # # # ## #### # ## ## ## # ####### # # #
J
<lang j>load '~addons/graphics/fvj4/complex_dynamics.ijs' pal2=: 255,~0,<.(254$1 0.8 0.6)*Hue 5r6*(i.%<:)254 g=: [: %: 0.3746j0.102863 0.132565j0.389103 _0.373935j_0.353777 1&p. view_image pal2;b=:g escapetc (10 255) 500 zl_clur _1.5 1.5j1.5</lang>
See also: Fractals Visualization and J, 4th edition, Part 1 (by Clifford A. Reiter), Chapter 6
See http://webbox.lafayette.edu/~reiterc/mvp/ec_julia/index.html for some other examples. (That said, note that this is a link into a small college site and it might drift over time. In the past, for example, you would have had to use 'www' where it currently says 'webbox')
Java
<lang java>import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage;
public class JuliaSet extends JPanel {
private static final int MAX_ITERATIONS = 300; private static final double ZOOM = 1; private static final double CX = -0.7; private static final double CY = 0.27015; private static final double MOVE_X = 0; private static final double MOVE_Y = 0;
public JuliaSet() { setPreferredSize(new Dimension(800, 600)); setBackground(Color.white); }
void drawJuliaSet(Graphics2D g) { int w = getWidth(); int h = getHeight(); BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { double zx = 1.5 * (x - w / 2) / (0.5 * ZOOM * w) + MOVE_X; double zy = (y - h / 2) / (0.5 * ZOOM * h) + MOVE_Y; float i = MAX_ITERATIONS; while (zx * zx + zy * zy < 4 && i > 0) { double tmp = zx * zx - zy * zy + CX; zy = 2.0 * zx * zy + CY; zx = tmp; i--; } int c = Color.HSBtoRGB((MAX_ITERATIONS / i) % 1, 1, i > 0 ? 1 : 0); image.setRGB(x, y, c); } } g.drawImage(image, 0, 0, null); }
@Override public void paintComponent(Graphics gg) { super.paintComponent(gg); Graphics2D g = (Graphics2D) gg; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); drawJuliaSet(g); }
public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setTitle("Julia Set"); f.setResizable(false); f.add(new JuliaSet(), BorderLayout.CENTER); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); }
}</lang> To multi-thread, simply swap the for loop for a parallel IntStream. <lang java> import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.util.stream.IntStream;
public class JuliaSet extends JPanel {
private static final int MAX_ITERATIONS = 300; private static final double ZOOM = 1; private static final double CX = -0.7; private static final double CY = 0.27015; private static final double MOVE_X = 0; private static final double MOVE_Y = 0;
public JuliaSet() { setPreferredSize(new Dimension(800, 600)); setBackground(Color.white); }
void drawJuliaSet(Graphics2D g) { int w = getWidth(); int h = getHeight(); BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
IntStream.range(0, w).parallel().forEach(x -> { IntStream.range(0, h).parallel().forEach(y -> { double zx = 1.5 * (x - w / 2) / (0.5 * ZOOM * w) + MOVE_X; double zy = (y - h / 2) / (0.5 * ZOOM * h) + MOVE_Y; float i = MAX_ITERATIONS; while (zx * zx + zy * zy < 4 && i > 0) { double tmp = zx * zx - zy * zy + CX; zy = 2.0 * zx * zy + CY; zx = tmp; i--; } int c = Color.HSBtoRGB((MAX_ITERATIONS / i) % 1, 1, i > 0 ? 1 : 0); image.setRGB(x, y, c); }); }); g.drawImage(image, 0, 0, null); }
@Override public void paintComponent(Graphics gg) { super.paintComponent(gg); Graphics2D g = (Graphics2D) gg; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); drawJuliaSet(g); }
public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setTitle("Julia Set"); f.setResizable(false); f.add(new JuliaSet(), BorderLayout.CENTER); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); }
} </lang>
JavaScript
take a look here. <lang javascript> var maxIterations = 450, minX = -.5, maxX = .5,
minY = -.5, maxY = .5, wid, hei, ctx, jsX = 0.285, jsY = 0.01;
function remap( x, t1, t2, s1, s2 ) {
var f = ( x - t1 ) / ( t2 - t1 ), g = f * ( s2 - s1 ) + s1; return g;
} function getColor( c ) {
var r, g, b, p = c / 32, l = ~~( p * 6 ), o = p * 6 - l, q = 1 - o;
switch( l % 6 ) { case 0: r = 1; g = o; b = 0; break; case 1: r = q; g = 1; b = 0; break; case 2: r = 0; g = 1; b = o; break; case 3: r = 0; g = q; b = 1; break; case 4: r = o; g = 0; b = 1; break; case 5: r = 1; g = 0; b = q; break; } var c = "#" + ( "00" + ( ~~( r * 255 ) ).toString( 16 ) ).slice( -2 ) + ( "00" + ( ~~( g * 255 ) ).toString( 16 ) ).slice( -2 ) + ( "00" + ( ~~( b * 255 ) ).toString( 16 ) ).slice( -2 ); return (c);
} function drawFractal() {
var a, as, za, b, bs, zb, cnt, clr for( var j = 0; j < hei; j++ ) { for( var i = 0; i < wid; i++ ) { a = remap( i, 0, wid, minX, maxX ) b = remap( j, 0, hei, minY, maxY ) cnt = 0; while( ++cnt < maxIterations ) { za = a * a; zb = b * b; if( za + zb > 4 ) break; as = za - zb; bs = 2 * a * b; a = as + jsX; b = bs + jsY; } if( cnt < maxIterations ) { ctx.fillStyle = getColor( cnt ); } ctx.fillRect( i, j, 1, 1 ); } }
} function init() {
var canvas = document.createElement( "canvas" ); wid = hei = 800; canvas.width = wid; canvas.height = hei; ctx = canvas.getContext( "2d" ); ctx.fillStyle = "black"; ctx.fillRect( 0, 0, wid, hei ); document.body.appendChild( canvas ); drawFractal();
} </lang>
jq
<lang jq># Example values:
- $re : -0.8
- $im : 0.156
{} | range(-100; 101; 10) as $v | (( range (-280; 281; 10) as $h
| .x = $h / 200 | .y = $v / 100 | .plot = "#" | .i = 0 | until (.i == 50 or .plot == "."; .i += 1 | .z_real = ((.x * .x) - (.y * .y) + $re) | .z_imag = ((.x * .y * 2) + $im) | if pow(.z_real; 2) > 10000 then .plot = " " else .x = .z_real | .y = .z_imag end ) | .plot ), "\n")</lang>
With the above program in a file called julia.jq, the following invocation of jq 1.5 produces the same output as shown in the awk entry on this page:
jq -nrj -f julia.jq --argjson re -0.8 --argjson im 0.156
(If your jq does not support the --argjson options, then use --arg instead, and add the `tonumber` conversions at the beginning of the program.)
Julia
The following code creates the fractal as a ppm file named julia.ppm. There is no need of an external library to create this image since the ppm format is straightforward to generate.
<lang julia> function iter(z,c)
n = 0 while (abs2(z)<4) z = z^2+c ; n+=1 end return n
end
coord(i,j,w,h,a,b) = 2*a*(i-1)/(w-1) - a + im * (2*b*(j-1)/(h-1) - b)
palette(n) = string(min(3n,255)," ", min(n,255)," ", 0);
julia(c) = (w,h,a,b,i,j) -> palette(iter(coord(i,j,w,h,a,b), c))
writeppm(f; width=600,height=300,a=2,b=1,file="julia.ppm") =
open(file, "w") do out write(out, string("P3\n", width, " ", height, "\n255\n")) writedlm(out, [f(width,height,a,b,i,j) for j = 1:height, i = 1:width], '\n') end
</lang>
We can then produce a 600x300 ppm image of the Julia set associated to the parameter -0.786+0.147i as follows.
writeppm(julia(-0.786+0.147im))
The following code makes use of the library Images to build a png image.
<lang julia>using Images
@inline function hsv2rgb(h, s, v)
c = v * s x = c * (1 - abs(((h/60) % 2) - 1)) m = v - c
if h < 60 r,g,b = (c, x, 0) elseif h < 120 r,g,b = (x, c, 0) elseif h < 180 r,g,b = (0, c, x) elseif h < 240 r,g,b = (0, x, c) elseif h < 300 r,g,b = (x, 0, c) else r,g,b = (c, 0, x) end
(r + m), (b + m), (g + m)
end
function julia_set(c = -0.7+0.27015im)
w, h = 800, 800
zoom = 0.7 # the zoom factor moveX = 0 # the amount of shift on the x axis moveY = 0 # the amount of shift on the y axis
L = 2 # the maximum value of |z| I = 255 # the maximum number of iterations
img = zeros(RGB{Float64}, h, w)
for x in 1:w, y in 1:h n = 0 z = Complex( (2*x - w) / (w * zoom) + moveX, (2*y - h) / (h * zoom) + moveY ) while abs(z) < L && (n += 1) < I z = z^2 + c end v = (I - n) / I r,g,b = hsv2rgb(v*360, 1, v) img[y,x] = RGB{Float64}(r, g, b) end
save("julia_set.png", img)
end
julia_set()</lang>
Kotlin
<lang scala> import java.awt.* import java.awt.image.BufferedImage import javax.swing.JFrame import javax.swing.JPanel
class JuliaPanel : JPanel() {
init { preferredSize = Dimension(800, 600) background = Color.white }
private val maxIterations = 300 private val zoom = 1 private val moveX = 0.0 private val moveY = 0.0 private val cX = -0.7 private val cY = 0.27015
public override fun paintComponent(graphics: Graphics) { super.paintComponent(graphics) with(graphics as Graphics2D) { setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) val image = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB) (0 until width).forEach { x -> (0 until height).forEach { y -> var zx = 1.5 * (x - width / 2) / (0.5 * zoom * width) + moveX var zy = (y - height / 2) / (0.5 * zoom * height) + moveY var i = maxIterations.toFloat() while (zx * zx + zy * zy < 4 && i > 0) { val tmp = zx * zx - zy * zy + cX zy = 2.0 * zx * zy + cY zx = tmp i-- } image.setRGB(x, y, Color.HSBtoRGB(maxIterations / i % 1, 1f, (if (i > 0) 1 else 0).toFloat())) } } drawImage(image, 0, 0, null) } }
}
fun main() {
with(JFrame()) { defaultCloseOperation = JFrame.EXIT_ON_CLOSE title = "Julia Set" isResizable = false add(JuliaPanel(), BorderLayout.CENTER) pack() setLocationRelativeTo(null) isVisible = true }
}</lang>
Lua
<lang lua>local cmap = { [0]=" ", ".", ":", "-", "=", "+", "*", "#", "%", "$", "@" } for y = -1.0, 1.0, 0.05 do
for x = -1.5, 1.5, 0.025 do local zr, zi, i = x, y, 0 while i < 100 do zr, zi = zr*zr - zi*zi - 0.79, zr * zi * 2 + 0.15 if (zr*zr + zi*zi > 4) then break else i = i + 1 end end io.write(cmap[math.floor(i/10)]) end print()
end</lang>
- Output:
.: =@=:.#: %@=:@%@ ..::::#. :.+=-:+@--% =+- .#+@@::::@-....--@:.@..$@ .@*:.**=@=::::...=@@@*@@::@-# :-:::*@@@-:::::--@@%@*+=+::%+:. -@+ %@-=@@@==*@**=*@:%#*@@%@@@@@@@*@@#:-. @:.@@@+:- - .$-==@%**@@==--*@@@@====@@@-#=@@@%@: -@+:%@@:::. @@:@. .@ @*:=*@%@@@@*++@%@@@@#-#*-::::=:::*@@#+. .+%@%*@$=+:%%@@=-- $-$-..@@#*:@... + .:=#@@@@@%@@@@@*$#@=:::@::::::::::-+%@.....%@@@@*+##@@=*@@@# ..:@=:::.*@%@=@#%*+:.@. ..:@@$@@@@%**%==+=*$:::::::::::::::::-+@....@@$@#*@+@@:=::::=- +:@= .::@@#-:%*@=*@@-=@@=*@@@.......@-@+@*@@*+@=--==:::::::::::::@$=*---@=....=@=@@=-*=:::::::-@.-@@*#@. -+@*@@=+@@@*%::::::::@+*$@......@=+@+@@@@@@--@=@::......:-@@===+*--#@....::@@@@@::...:@=@=+.:@@:::-.%@ : .+. =#@@@@@+#@:::::::::::::-=@-.......:*==*#@@@#@@:::.......:-+=-=+%===@::...:::-#%#@+:...@-:::::##@$.@$- @@-$=@==@+...-+@@+@==@::::::::-#@@----@=.......::=%@@@@@@@%=::.......=@----@@#-::::::::@==@+@@+-...+@==@=$-@@ -$@.$@##:::::-@...:+@#%#-:::...::@===%+=-=+-:.......:::@@#@@@#*==*:.......-@=-:::::::::::::@#+@@@@@#= .+. : @%.-:::@@:.+=@=@:...::@@@@@::....@#--*+===@@-:......::@=@--@@@@@@+@+=@......@$*+@::::::::%*@@@+=@@*@+- .@#*@@-.@-:::::::=*-=@@=@=....=@---*=$@:::::::::::::==--=@+*@@*@+@-@.......@@@*=@@=-@@*=@*%:-#@@::. =@:+ -=::::=:@@+@*#@$@@....@+-:::::::::::::::::$*=+==%**%@@@@$@@:.. .@.:+*%#@=@%@*.:::=@:.. #@@@*=@@##+*@@@@%.....@%+-::::::::::@:::=@#$*@@@@@%@@@@@#=:. + ...@:*#@@..-$-$ --=@@%%:+=$@*%@%+. .+#@@*:::=::::-*#-#@@@@%@++*@@@@%@*=:*@ @. .@:@@ .:::@@%:+@- :@%@@@=#-@@@====@@@@*--==@@**%@==-$. - -:+@@@.:@ .-:#@@*@@@@@@@%@@*#%:@*=**@*==@@@=-@% +@- .:+%::+=+*@%@@--:::::-@@@*:::-: #-@::@@*@@@=...::::=@=**.:*@. @$..@.:@--....-@::::@@+#. -+= %--@+:-=+.: .#::::.. @%@:=@% :#.:=@= :.
Mathematica/Wolfram Language
Mathematica provides built-in functions for Julia sets. Generate the set of points for the -0.77 +0.22 I Julia set with step sizes of 0.01 <lang Mathematica>JuliaSetPoints[-0.77 + 0.22 I, "ClosenessTolerance" -> 0.01]</lang> Visualize the same Julia set <lang Mathematica>JuliaSetPlot[-0.77 + 0.22 I]</lang>
Nim
<lang Nim>import lenientops import imageman
const
W = 800 H = 600 Zoom = 1 MaxIter = 255 MoveX = 0 MoveY = 0 Cx = -0.7 Cy = 0.27015
var colors: array[256, ColorRGBU] for n in byte.low..byte.high:
colors[n] = ColorRGBU [n shr 5 * 36, (n shr 3 and 7) * 36, (n and 3) * 85]
var image = initImage[ColorRGBU](W, H)
for x in 0..<W:
for y in 0..<H: var zx = 1.5 * (x - W / 2) / (0.5 * Zoom * W) + MoveX var zy = 1.0 * (y - H / 2) / (0.5 * Zoom * H) + MoveY var i = MaxIter while zx * zx + zy * zy < 4 and i > 1: (zy, zx) = (2.0 * zx * zy + Cy, zx * zx - zy * zy + Cx) dec i image[x, y] = colors[i]
- Save into a PNG file.
image.savePNG("julia.png", compression = 9)</lang>
Perl
<lang perl>use Imager;
my($w, $h, $zoom) = (800, 600, 1); my $img = Imager->new(xsize => $w, ysize => $h, channels => 3);
my $maxIter = 255; my ($cX, $cY) = (-0.7, 0.27015); my ($moveX, $moveY) = (0, 0);
my $color = Imager::Color->new('#000000');
foreach my $x (0 .. $w - 1) {
foreach my $y (0 .. $h - 1) { my $zx = (1.5 * ($x - $w / 2) / (0.5 * $zoom * $w) + $moveX); my $zy = (($y - $h / 2) / (0.5 * $zoom * $h) + $moveY); my $i = $maxIter; while ($zx**2 + $zy**2 < 4 and --$i >= 0) { ($zy, $zx) = (2 * $zx * $zy + $cY, $zx**2 - $zy**2 + $cX); } $color->set(hsv => [$i / $maxIter * 360, 1, $i > 0 ? 1 : 0]); $img->setpixel(x => $x, y => $y, color => $color); }
}
$img->write(file => 'julia_set.png');</lang>
Phix
Interactive gui (zoom/pan incomplete).
-- -- demo\rosetta\Julia_set.exw -- ========================== -- -- Interactive gui (zoom/pan incomplete). -- --with javascript_semantics -- not quite yet: without js -- [DEV] IupValuator, IupImageRGB include pGUI.e constant title = "Julia set" Ihandle dlg, cxv, cxl, cyv, cyl, ispin, pspin, clrzn, label, bb, redraw atom cX = -0.7, cY = -0.353777 integer iter = 255, pwr = 2, zoom = 1, -- (not yet used/to do) moveX = 0, -- drag?? (to do) moveY = 0 constant clrzns = {{8,32,16}, {2,4,8}, {1,1,8}} sequence colourisation = clrzns[1] function julia(integer width, integer height) atom tpt25 = time()+0.25 sequence img = repeat(repeat(0,width),height) for x=1 to width do for y=1 to height do atom zx := 1.5*((x-1)-width/2)/(0.5*zoom*width)+moveX, zy := 1.0*((y-1)-height/2)/(0.5*zoom*height)+moveY; integer i := iter; while ((zx*zx+zy*zy)<4) and (i>1) do atom pn = power(zx*zx+zy*zy,pwr/2), pa = pwr*atan2(zy, zx) zx = pn*cos(pa)+cX zy = pn*sin(pa)+cY i -= 1; end while -- img[y,x] = {i*2,i*4,i*8} -- (experiment thusly) img[y,x] = sq_mul(i,colourisation) end for if time()>tpt25 then IupSetStrAttribute(dlg, "TITLE", "%s (generating - %3.2f%%)",{title,x/width*100}) IupFlush() tpt25 = time()+0.25 end if end for img = flatten(img) Ihandle new_img = IupImageRGB(width, height, img) return new_img end function function redraw_cb(Ihandln /*redraw*/) Ihandln image = IupGetAttributeHandle(label, "IMAGE") IupSetAttributeHandle(label, "IMAGE", NULL) image = IupDestroy(image) IupSetAttribute(redraw,"ACTIVE","NO") IupRefreshChildren(bb) integer {w,h} = IupGetIntInt(bb, "RASTERSIZE") image = julia(w,h) IupSetAttribute(redraw,"ACTIVE","YES") IupUnmap(label) IupSetAttribute(label,"RASTERSIZE",NULL) IupSetAttributeHandle(label, "IMAGE", image) IupMap(label) IupRefresh(label) IupSetStrAttribute(dlg, "TITLE", title) return IUP_DEFAULT end function constant cb_redraw = Icallback("redraw_cb") function valuechanged_cb(Ihandle ih) atom a = IupGetFloat(ih, "VALUE") switch ih do case cxv: cX = a IupSetStrAttribute(cxl,"TITLE","cY: %f",{cX}) case cyv: cY = a IupSetStrAttribute(cyl,"TITLE","cY: %f",{cY}) case ispin: iter = a case pspin: pwr = a case clrzn: colourisation = clrzns[a] end switch return IUP_DEFAULT end function constant cb_valuechanged = Icallback("valuechanged_cb") procedure create_dlg() Ihandle lx1 = IupLabel("+") cxl = IupLabel(sprintf("cX: %f",cX)) Ihandle lx2 = IupLabel("-"), hx1 = IupHbox({lx1, IupFill(), cxl, IupFill(), lx2}) cxv = IupValuator(NULL,"MIN=-2.5, MAX=+1") Ihandle bxv = IupVbox({hx1, cxv}) Ihandle ly1 = IupLabel("+") cyl = IupLabel(sprintf("cY: %f",cY)) Ihandle ly2 = IupLabel("-"), hx2 = IupHbox({ly1, IupFill(), cyl, IupFill(), ly2}) cyv = IupValuator(NULL,"MIN=-1, MAX=+1") Ihandle byv = IupVbox({hx2, cyv}) IupSetCallback(cxv, "VALUECHANGED_CB", cb_valuechanged) IupSetCallback(cyv, "VALUECHANGED_CB", cb_valuechanged) IupSetFloat(cxv, "VALUE", cX) IupSetFloat(cyv, "VALUE", cY) Ihandle ilbl = IupLabel("iter'ns:","PADDING=0x3") ispin = IupText("VALUECHANGED_CB", cb_valuechanged, "SPIN=Yes, SPINMIN=1, SPINMAX=500, RASTERSIZE=48x") IupSetInt(ispin,"VALUE",iter) Ihandle ibox = IupHbox({IupFill(),ilbl,ispin,IupFill()}) Ihandle plbl = IupLabel("power:","PADDING=0x3") pspin = IupText("VALUECHANGED_CB", cb_valuechanged, "SPIN=Yes, SPINMIN=2, SPINMAX=6, RASTERSIZE=48x") IupSetInt(pspin,"VALUE",pwr) Ihandle pbox = IupHbox({IupFill(),plbl,pspin,IupFill()}) Ihandle clbl = IupLabel("colourization:","PADDING=0x3") clrzn = IupList("DROPDOWN=YES") for i=1 to length(clrzns) do IupSetStrAttributeId(clrzn,"",i,sprint(clrzns[i])) end for IupSetInt(clrzn,"VISIBLEITEMS",length(clrzns)+1) IupSetInt(clrzn,"VALUE",1) IupSetCallback(clrzn, "VALUECHANGED_CB", cb_valuechanged) Ihandle cbox = IupHbox({IupFill(),IupVbox({clbl,clrzn}),IupFill()}) redraw = IupButton("redraw",cb_redraw) Ihandle rbox = IupHbox({IupFill(),redraw,IupFill()},"EXPAND=YES, MARGIN=10x20") Ihandle params = IupVbox({bxv,byv,ibox,pbox,cbox,rbox}, "GAP=5, EXPAND=NO, EXPANDCHILDREN=YES, MARGIN=3x3") label = IupLabel("please wait...","ALIGNMENT=ACENTER:ACENTER, RASTERSIZE=800x600") bb = IupBackgroundBox(IupHbox({IupVbox({label,IupFill()}),IupFill()}),"EXPAND=YES, SHRINK=YES") dlg = IupDialog(IupHbox({params,bb})) IupSetAttribute(dlg, "TITLE", title) end procedure procedure main() IupOpen() create_dlg() IupShow(dlg) {} = redraw_cb(NULL) if platform()!=JS then IupMainLoop() IupClose() end if end procedure main()
PHP
Click here to see a sample image created using this script. <lang PHP> set_time_limit(300); header("Content-Type: image/png");
class Julia {
static private $started = false;
public static function start() { if (!self::$started) { self::$started = true; new self; } }
const AXIS_REAL = 0; const AXIS_IMAGINARY = 1; const C = [-0.75, 0.1]; const RADII = [1, 0.5]; const CENTER = [0, 0]; const MAX_ITERATIONS = 100; const TICK_SPACING = 0.001;
private $maxDistance; private $imageResource; private $whiteColorResource; private $z0 = [];
private function __construct() { $this->maxDistance = max($this->distance(self::C), 2); $this->imageResource = imagecreate( $this->coordinateToPixel(self::RADII[self::AXIS_REAL], self::AXIS_REAL), $this->coordinateToPixel(self::RADII[self::AXIS_IMAGINARY], self::AXIS_IMAGINARY) ); imagecolorallocate($this->imageResource, 0, 0, 0); $this->whiteColorResource = imagecolorallocate($this->imageResource, 255, 255, 255);
for ($x = self::CENTER[self::AXIS_REAL] - self::RADII[self::AXIS_REAL]; $x <= self::CENTER[self::AXIS_REAL] + self::RADII[self::AXIS_REAL]; $x += self::TICK_SPACING) { $z0[self::AXIS_REAL] = $x;
for ($y = self::CENTER[self::AXIS_IMAGINARY] - self::RADII[self::AXIS_IMAGINARY]; $y <= self::CENTER[self::AXIS_IMAGINARY] + self::RADII[self::AXIS_IMAGINARY]; $y += self::TICK_SPACING) { $z0[self::AXIS_IMAGINARY] = $y; $iterations = 1; do { $z0 = $this->q($z0); $iterations++; } while($iterations < self::MAX_ITERATIONS && $this->distance($z0) <= $this->maxDistance);
if ($iterations !== self::MAX_ITERATIONS) { imagesetpixel( $this->imageResource, $this->coordinateToPixel($x, self::AXIS_REAL), $this->coordinateToPixel($y, self::AXIS_IMAGINARY), $this->whiteColorResource ); } $z0[self::AXIS_REAL] = $x; } } }
public function __destruct() { imagepng($this->imageResource); imagedestroy($this->imageResource); }
private function q($z) { return [ ($z[self::AXIS_REAL] ** 2) - ($z[self::AXIS_IMAGINARY] ** 2) + self::C[self::AXIS_REAL],
(2 * $z[self::AXIS_REAL] * $z[self::AXIS_IMAGINARY]) + self::C[self::AXIS_IMAGINARY] ];
}
private function distance($z) { return sqrt( ($z[self::AXIS_REAL] ** 2) + ($z[self::AXIS_IMAGINARY] ** 2) ); }
private function coordinateToPixel($coordinate, $axis) { return ($coordinate + self::RADII[$axis]) * (self::TICK_SPACING ** -1); } }
Julia::start(); </lang>
Processing
<lang java> float cX = -0.7; float cY = 0.27015; float zx, zy; float maxIter = 300;
void setup() {
size(640, 480);
}
void draw() {
for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { zx = 1.5 * (x - width / 2) / (0.5 * width); zy = (y - height / 2) / (0.5 * height); float i = maxIter; while (zx * zx + zy * zy < 4 && i > 0) { float tmp = zx * zx - zy * zy + cX; zy = 2.0 * zx * zy + cY; zx = tmp; i -= 1; } colorMode(HSB); color c = color(i / maxIter * 255, 255, i > 1 ? 255 : 0); set(x, y, c); } } noLoop();
} </lang>
Processing Python mode
<lang python>from __future__ import division
cX = -0.7 cY = 0.27015 maxIter = 300
def setup():
size(640, 480)
def draw():
for x in range(width): for y in range(height): zx = 1.5 * (x - width / 2) / (0.5 * width) zy = (y - height / 2) / (0.5 * height) i = maxIter while zx * zx + zy * zy < 4 and i > 0: tmp = zx * zx - zy * zy + cX zy = 2.0 * zx * zy + cY zx = tmp i -= 1 colorMode(HSB) c = color(i / maxIter * 255, 255, 255 if i > 1 else 0) set(x, y, c)</lang> noLoop()
Python
Naive approach
<lang python>from PIL import Image
if __name__ == "__main__": w, h, zoom = 800,600,1 bitmap = Image.new("RGB", (w, h), "white") pix = bitmap.load()
cX, cY = -0.7, 0.27015 moveX, moveY = 0.0, 0.0 maxIter = 255
for x in range(w): for y in range(h): zx = 1.5*(x - w/2)/(0.5*zoom*w) + moveX zy = 1.0*(y - h/2)/(0.5*zoom*h) + moveY i = maxIter while zx*zx + zy*zy < 4 and i > 1: tmp = zx*zx - zy*zy + cX zy,zx = 2.0*zx*zy + cY, tmp i -= 1 # convert byte to RGB (3 bytes), kinda magic to get nice colors pix[x][y] = (i << 21) + (i << 10) + i*8
bitmap.show()</lang>
Vectorized
Efficient version using vectorized operations in NumPy.
Example output. <lang python>""" Solution from: https://codereview.stackexchange.com/questions/210271/generating-julia-set """ from functools import partial from numbers import Complex from typing import Callable
import matplotlib.pyplot as plt import numpy as np
def douady_hubbard_polynomial(z: Complex,
c: Complex) -> Complex: """ Monic and centered quadratic complex polynomial https://en.wikipedia.org/wiki/Complex_quadratic_polynomial#Map """ return z ** 2 + c
def julia_set(mapping: Callable[[Complex], Complex],
*, min_coordinate: Complex, max_coordinate: Complex, width: int, height: int, iterations_count: int = 256, threshold: float = 2.) -> np.ndarray: """ As described in https://en.wikipedia.org/wiki/Julia_set :param mapping: function defining Julia set :param min_coordinate: bottom-left complex plane coordinate :param max_coordinate: upper-right complex plane coordinate :param height: pixels in vertical axis :param width: pixels in horizontal axis :param iterations_count: number of iterations :param threshold: if the magnitude of z becomes greater than the threshold we assume that it will diverge to infinity :return: 2D pixels array of intensities """ im, re = np.ogrid[min_coordinate.imag: max_coordinate.imag: height * 1j, min_coordinate.real: max_coordinate.real: width * 1j] z = (re + 1j * im).flatten()
live, = np.indices(z.shape) # indexes of pixels that have not escaped iterations = np.empty_like(z, dtype=int)
for i in range(iterations_count): z_live = z[live] = mapping(z[live]) escaped = abs(z_live) > threshold iterations[live[escaped]] = i live = live[~escaped] if live.size == 0: break else: iterations[live] = iterations_count
return iterations.reshape((height, width))
if __name__ == '__main__':
mapping = partial(douady_hubbard_polynomial, c=-0.7 + 0.27015j) # type: Callable[[Complex], Complex]
image = julia_set(mapping, min_coordinate=-1.5 - 1j, max_coordinate=1.5 + 1j, width=800, height=600) plt.axis('off') plt.imshow(image, cmap='nipy_spectral_r', origin='lower') plt.show()
</lang>
Racket
<lang racket>
- Based on Mandelbrot code (GPL) from
- https://github.com/hebr3/Mandelbrot-Set-Racket/blob/master/Mandelbrot.v6.rkt
- Julia set algoithm (and coloring) from
- http://lodev.org/cgtutor/juliamandelbrot.html
- HSV code (GPL) based on
- https://github.com/takikawa/pict-utils/blob/master/pict-utils/hsv.rkt
- lang racket
- Required to generate image
(require picturing-programs)
- CONSTANTS - NUMBERS
(define DEPTH 300) (define WIDTH 800) (define HEIGHT 600)
- Structures
(struct posn [x y] #:transparent)
- CONSTANTS - GRAPHIC
(define BACKGROUND (rectangle WIDTH HEIGHT 'solid 'grey)) (define jcnst (posn -0.7 0.27015))
- PROCEDURES
- make an RGB color from HSV values
(define (make-color/hsv hue saturation value)
(define chroma (* saturation value)) (define hue* (/ (remainder* hue (* 2 pi)) (/ pi 3))) (define X (* chroma (- 1 (abs (- (remainder* hue* 2) 1))))) (define-values (r1 g1 b1) (cond [(and (<= 0 hue*) (< hue* 1)) (values chroma X 0)] [(and (<= 1 hue*) (< hue* 2)) (values X chroma 0)] [(and (<= 2 hue*) (< hue* 3)) (values 0 chroma X)] [(and (<= 3 hue*) (< hue* 4)) (values 0 X chroma)] [(and (<= 4 hue*) (< hue* 5)) (values X 0 chroma)] [(and (<= 5 hue*) (< hue* 6)) (values chroma 0 X)])) (define m (- value chroma)) (apply make-color (map (λ (x) (exact-round (* 255 (+ x m)))) (list r1 g1 b1))))
- general remainder
(define (remainder* n1 n2)
(define num-divides (/ n1 n2)) (- n1 (* (floor num-divides) n2)))
- Posn -> Number
- Returns the magnitude of the posn
(define (posn-mag pt)
(let ([pt-x (posn-x pt)] [pt-y (posn-y pt)]) (sqrt (+ (* pt-x pt-x) (* pt-y pt-y)))))
- Posn Posn -> Posn
- Posn addition
(define (posn+ pt1 pt2)
(let ([pt1-x (posn-x pt1)] [pt1-y (posn-y pt1)] [pt2-x (posn-x pt2)] [pt2-y (posn-y pt2)]) (posn (+ pt1-x pt2-x) (+ pt1-y pt2-y))))
- Posn Posn -> Posn
- Posn multiplication
(define (posn* pt1 pt2)
(let ([x1 (posn-x pt1)] [y1 (posn-y pt1)] [x2 (posn-x pt2)] [y2 (posn-y pt2)]) (posn (- (* x1 x2) (* y1 y2)) (+ (* x1 y2) (* x2 y1)))))
- Posn -> Posn
- Posn square
(define (posn-sqr pt)
(posn* pt pt))
- Posn -> Number
- Returns the julia set escape number for a given complex number
- given in rectangular coordinates.
(define (julia-set-number start)
(define (iter result count) (cond [(> (posn-mag result) 2) (sub1 count)] [(> count DEPTH) DEPTH] [else (iter (posn+ jcnst (posn-sqr result)) (add1 count))])) (iter start 1))
- Number -> Number
- Returns the scaled location of a point
(define (scaled-x x)
(/ (* 1.5 (- x (/ WIDTH 2))) (* 0.5 WIDTH)))
(define (scaled-y y)
(/ (- y (/ HEIGHT 2)) (* 0.5 HEIGHT)))
- Generates image
(define M-Image
(map-image (λ (x y c) (let* ([ref (julia-set-number (posn (scaled-x x) (scaled-y y)))]) (cond [(= ref DEPTH) (name->color 'black)] [else (make-color/hsv (* 2 (* pi (/ ref DEPTH))) 1 1)]) )) BACKGROUND))
M-Image ;show image if using drracket
(save-image M-Image "julias.png") </lang>
Raku
(formerly Perl 6)
with the pallette swapped, just because.
<lang perl6>use Image::PNG::Portable;
my ($w, $h) = 800, 600; my $out = Image::PNG::Portable.new: :width($w), :height($h);
my $maxIter = 255; my $c = -0.7 + 0.27015i;
julia($out);
$out.write: 'Julia-set-perl6.png';
sub julia ( $png ) {
^$w .race.map: -> $x { for ^$h -> $y { my $z = Complex.new(($x - $w / 2) / $w * 3, ($y - $h / 2) / $h * 2); my $i = $maxIter; while (abs($z) < 2 and --$i) { $z = $z*$z + $c; } $png.set: $x, $y, |hsv2rgb($i / $maxIter, 1, ?$i).reverse; } }
}
sub hsv2rgb ( $h, $s, $v ){
my $c = $v * $s; my $x = $c * (1 - abs( (($h*6) % 2) - 1 ) ); my $m = $v - $c; [(do given $h { when 0..^1/6 { $c, $x, 0 } when 1/6..^1/3 { $x, $c, 0 } when 1/3..^1/2 { 0, $c, $x } when 1/2..^2/3 { 0, $x, $c } when 2/3..^5/6 { $x, 0, $c } when 5/6..1 { $c, 0, $x } } ).map: ((*+$m) * 255).Int]
}</lang>
REXX
- which is a
<lang rexx>/*REXX program displays an ASCII plot (character plot) of a Julia set. */ parse arg real imag fine . /*obtain optional arguments from the CL*/ if real== | real=="," then real= -0.8 /*Not specified? Then use the default.*/ if imag== | imag=="," then imag= 0.156 /* " " " " " " */ if fine== | fine=="," then fine= 50 /* " " " " " " */ _=scrsize(); parse var _ sd sw; sd=sd-4; sw=sw-1 /*obtain useable area for the terminal.*/
/*$: the plot line that is constructed*/ do v= -sd%2 to sd%2; $= /*step through vertical axis values.*/ do h= -sw%2 to sw%2 /* " " horizontal " " */ x=h/sw*2 /*calculate the initial X value. */ y=v/sd*2 /* " " " Y " */ @='■'; do fine /*FINE: is the "fineness" for the plot.*/ zr=x*x - y*y + real /*calculate a new real Julia point.*/ zi=x*y*2 + imag /* " " " imaginal " " */ if zr**2>10000 then do; @=' '; leave; end /*is ZR too large? */ x=zr; y=zi /*use this new point.*/ end /*50*/ $=$ || @ /*append the plot char to the plot line*/ end /*h*/ if $\= then say strip($, 'T') /*only display a plot line if non-blank*/ end /*v*/ /*stick a fork in it, we're all done. */</lang>
This REXX program makes use of scrsize REXX program (or BIF) which is used to determine the screen size of the terminal (console),
and the plot size is adjusted according.
The SCRSIZE.REX REXX program is included here ──► SCRSIZE.REX.
(final) output when using the default input (screen size was 200x420):
(Shown at 1/6 size.)
- output when using the input of: -0.8 0.156 50
■■ ■ ■ ■■ ■■ ■■■■■■■ ■ ■■■■ ■■■ ■■■■ ■■■■■ ■■ ■■■■ ■■ ■■■ ■■■■■ ■■■ ■■■■ ■■■■■■ ■■ ■ ■■■ ■■■■ ■■ ■■■■■■■ ■ ■ ■■■■■■■■ ■■■■■■■■■■■■■■■■■■■ ■■ ■■■ ■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■ ■ ■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■ ■■■■■ ■■■■■■■■■■ ■■■■■■■■■■■ ■ ■■■ ■■■■■■■■■■ ■■■■ ■ ■■■■■■■■■■■■ ■ ■■■■ ■ ■ ■■■■■■■■■■ ■ ■ ■■■■■■■■■ ■ ■ ■ ■■■■■■■■■■■■ ■■ ■■■■■■ ■■■ ■■ ■■■■■■■■ ■■■ ■■■■■■■ ■■ ■ ■ ■■ ■ ■■■■■■■■■ ■ ■■■ ■■ ■■■■■ ■■■■ ■■ ■■■■■■■ ■■ ■■■■■■■■■ ■■■■■ ■ ■■■■■■■■■■■■■■ ■■■ ■■■■■ ■■■■■■ ■ ■■ ■■ ■■■■■■■■■■ ■ ■■■ ■■■■■ ■■ ■ ■■ ■■■ ■■■■■■■■■■■ ■■■ ■■■■■ ■■■■■■■■ ■ ■■■■ ■ ■ ■ ■■ ■ ■ ■ ■■■ ■■■ ■■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■ ■ ■■■ ■■■■ ■■ ■■■■■■ ■ ■ ■■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■■ ■■■ ■ ■■■■ ■■■■■■ ■ ■ ■ ■ ■■■■■■ ■■ ■ ■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■■ ■ ■■■■■ ■■■■■ ■■■■■■ ■■ ■■■ ■■■■■■ ■■■ ■■■■■■■■■ ■■■■ ■ ■■■■■■■■■■■■■■■■■■■ ■■■■ ■ ■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■ ■■ ■ ■■ ■■■■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■■■ ■■ ■■■■ ■■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■ ■ ■■■ ■■ ■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■ ■■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■■■■■■■■ ■ ■■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■ ■■■ ■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■ ■ ■■■■■■■■■■■■■■■ ■■■■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■ ■ ■■■■■■■■ ■■■ ■■■■■■■■■■■ ■ ■ ■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■ ■■ ■■ ■ ■ ■ ■ ■■■ ■ ■■ ■■■■■■■■■■■ ■■■■■■■■ ■ ■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■■■■■■■■■■■■■■■■■ ■ ■ ■■■ ■■■■■■■■■■■■■■■■■■ ■■■■■■ ■■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■■■ ■ ■■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■■■ ■■■■■■■ ■ ■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■■ ■ ■■ ■■■ ■■ ■■■■■■■■■■■■■■ ■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■ ■ ■■■■■■■ ■■■■■■■■ ■■■ ■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■ ■■■■■■■■■■■■■■■ ■■■■ ■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■■■■■■■■■■ ■■■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■ ■■■■■■■■■■■■■ ■■ ■■■ ■■ ■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■ ■■■ ■ ■ ■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■ ■■■■■ ■■■■■■ ■ ■ ■■ ■■■ ■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■ ■ ■ ■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■■■■■■■■ ■■ ■■■■■ ■■ ■ ■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■ ■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■■■■■■■■ ■■■■ ■■■■■■■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■ ■ ■ ■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■ ■■ ■ ■■ ■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■■■■ ■■ ■ ■■ ■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■ ■■■■ ■■■ ■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■ ■■ ■■■ ■■■■■■■ ■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■■ ■ ■■ ■ ■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■■■■■ ■■■ ■ ■■ ■■■■■ ■■■■■■■■ ■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■ ■ ■■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■ ■■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■ ■ ■ ■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■■■■■ ■ ■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■ ■■■ ■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■ ■■■■■■■■■■■ ■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■ ■■■■■ ■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■ ■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■ ■ ■■■■■■■■■■ ■■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■ ■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■■ ■■■■■ ■■■■■■■ ■■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■ ■■■■■■■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■ ■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■ ■ ■■■■■■■■■■■ ■■■■■■■■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■ ■■■ ■■■■■■■■ ■■■ ■ ■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■ ■■■■■■■■■■ ■■■■■■■ ■■ ■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■ ■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■ ■■ ■■■■■■■■ ■ ■■■■■■■■■■■ ■■■■■■■■ ■ ■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■ ■■■■■■ ■■■ ■■■■ ■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■ ■■■■■■■■■■ ■■■■■■■■■■■■■ ■■■■■■■■ ■■■■■ ■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■ ■■■ ■■■■■■■■■■■■■■■■ ■ ■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■■■■■■■■ ■ ■■■■■■■■■■■■■ ■■■■■■■ ■ ■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■ ■■ ■■■■■■■■■■■■■■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■■■ ■■■■■ ■■■ ■■■■■■■■ ■■■■■■■■■■■ ■■■■■■■■■ ■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■■ ■ ■■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■ ■■ ■■ ■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■ ■■■■ ■■■■■■■■■ ■■■■■■■■■■ ■■■■■■■■■■■ ■ ■ ■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■ ■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■ ■ ■■■■■■■■ ■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■ ■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■ ■■ ■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■ ■■ ■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■ ■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■ ■■■■■■■■ ■ ■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■ ■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■ ■ ■ ■■■■■■■■■■■ ■■■■■■■■■■ ■■■■■■■■■ ■■■■ ■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■ ■■ ■■ ■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■■■■ ■ ■■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■ ■■■■■■■■■ ■■■■■■■■■■■ ■■■■■■■■ ■■■ ■■■■■ ■■■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■■■■■■■■■■■■■■ ■■ ■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■ ■ ■■■■■■■ ■■■■■■■■■■■■■ ■ ■■■■■■■■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■ ■ ■■■■■■■■■■■■■■■■ ■■■ ■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■ ■■■■■ ■■■■■■■■ ■■■■■■■■■■■■■ ■■■■■■■■■■ ■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■ ■■■■ ■■■ ■■■■■■ ■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■ ■ ■■■■■■■■ ■■■■■■■■■■■ ■ ■■■■■■■■ ■■ ■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■ ■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■ ■■■■■■■ ■■■■■■■■■■ ■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■ ■ ■■■ ■■■■■■■■ ■■■ ■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■■■■■■■■ ■■■■■■■■■■■ ■ ■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■ ■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■■■■■■■ ■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■■ ■■■■■■■ ■■■■■ ■■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■ ■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■■ ■■■■■■■■■■ ■ ■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■ ■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■ ■■■■■ ■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■ ■■■■■■■■■■■ ■ ■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■ ■■■ ■■ ■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■ ■ ■■■■■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■ ■ ■ ■■■■■■■■■■■■■■■■■■■ ■ ■■■ ■■ ■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■■ ■ ■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■ ■■■■■■■■ ■■■■■ ■■ ■ ■■■ ■■■■■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■ ■ ■■ ■ ■■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■ ■■■■■■■ ■■■ ■■ ■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■ ■■■ ■■■■ ■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■ ■■ ■ ■■ ■■■■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■ ■■■■■ ■■ ■ ■■ ■■■ ■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■■ ■■■■ ■ ■ ■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■■■■■■■ ■■■■ ■■■■■■■■ ■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■ ■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■ ■ ■■ ■■■■■ ■■ ■■■■■■■■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■ ■ ■ ■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■ ■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■■ ■ ■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■ ■■■ ■■ ■ ■ ■■■■■■ ■■■■■ ■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■ ■ ■ ■■■ ■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■ ■■ ■■■ ■■ ■■■■■■■■■■■■■ ■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■ ■■■ ■■■■■■■■■■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■ ■■■■ ■■■■■■■■■■■■■■■ ■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■ ■ ■■■ ■■■■■■■■ ■■■■■■■ ■ ■ ■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■ ■■■■■■■■■■■■■■ ■■ ■■■ ■■ ■ ■■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■ ■ ■■■■■■■ ■■■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■■ ■ ■■■ ■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■■ ■■■ ■■■■■■ ■■■■■■■■■■■■■■■■■■ ■■■ ■ ■ ■■■■■■■■■■■■■■■■■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■ ■ ■■■■■■■■ ■■■■■■■■■■■ ■■ ■ ■■■ ■ ■ ■ ■ ■■ ■■ ■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■■■ ■ ■ ■■■■■■■■■■■ ■■■ ■■■■■■■■ ■ ■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■ ■■■■ ■■■■■■■■■■■■■■■ ■ ■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■ ■■■ ■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■■ ■■ ■ ■■ ■ ■■■■■■■■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■■ ■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■ ■■ ■■ ■■■ ■ ■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■■ ■■■■ ■■ ■■■■ ■■■■■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■■■■■■■ ■■ ■ ■■ ■■■■■■■■■■■■■■■■■■ ■■■■■■■■■■■■■■■■ ■ ■■■■ ■■■■■■■■■■■■■■■■■■■ ■ ■■■■ ■■■■■■■■■ ■■■ ■■■■■■ ■■■ ■■ ■■■■■■ ■■■■■ ■■■■■ ■ ■■ ■ ■ ■■ ■■■■■■■■■■■■■■■■■ ■■■■■■■■■■ ■ ■■ ■■■■■■ ■ ■ ■ ■ ■■■■■■ ■■■■ ■ ■■■ ■■■ ■ ■ ■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■■ ■ ■ ■■■■■■ ■■ ■■■■ ■■■ ■ ■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■■ ■■■ ■■■ ■ ■ ■ ■■ ■ ■ ■ ■■■■ ■ ■■■■■■■■ ■■■■■ ■■■ ■■■■■■■■■■■ ■■■ ■■ ■ ■■ ■■■■■ ■■■ ■ ■■■■■■■■■■ ■■ ■■ ■ ■■■■■■ ■■■■■ ■■■ ■■■■■■■■■■■■■■ ■ ■■■■■ ■■■■■■■■■ ■■ ■■■■■■■ ■■ ■■■■ ■■■■■ ■■ ■■■ ■ ■■■■■■■■■ ■ ■■ ■ ■ ■■ ■■■■■■■ ■■■ ■■■■■■■■ ■■ ■■■ ■■■■■■ ■■ ■■■■■■■■■■■■ ■ ■ ■ ■■■■■■■■■ ■ ■ ■■■■■■■■■■ ■ ■ ■■■■ ■ ■■■■■■■■■■■■ ■ ■■■■ ■■■■■■■■■■ ■■■ ■ ■■■■■■■■■■■ ■■■■■■■■■■ ■■■■■ ■■■■■■■■■■■■■■■ ■ ■■■■■■■■■■■■■ ■■■■■■■■■■■■■■ ■ ■ ■■■■■ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ■■■ ■ ■■■■■■■■■■■■■■ ■■■■■■■■■■■ ■■■ ■■ ■■■■■■■■■■■■■■■■■■■ ■■■■■■■■ ■ ■ ■■■■■■■ ■■ ■■■■ ■■■ ■ ■■ ■■■■■■ ■■■■ ■■■ ■■■■■ ■■■ ■■ ■■■■ ■■ ■■■■■ ■■■■ ■■■ ■■■■ ■ ■■■■■■■ ■■ ■■ ■ ■ ■■
Other outputs are shown in this Rosetta Code task's discussion page.
Ring
<lang ring>
- Project : Julia Set
load "guilib.ring"
new qapp
{ win1 = new qwidget() { setwindowtitle("Julia set") setgeometry(100,100,500,400) label1 = new qlabel(win1) { setgeometry(10,10,400,400) settext("") } new qpushbutton(win1) { setgeometry(150,300,100,30) settext("draw") setclickevent("draw()") } show() } exec() }
func draw
p1 = new qpicture() color = new qcolor() { setrgb(0,0,255,255) } pen = new qpen() { setcolor(color) setwidth(1) } paint = new qpainter() { begin(p1) setpen(pen)
creal=-0.8 cimag=0.156 for v=-16 to 16 for h=-64 to 64 x=h/40 y=v/20 for i=1 to 50 flag = 1 zreal=x*x-y*y+creal zimag=x*y*2+cimag if zreal*zreal>1000 flag = 0 loop ok x=zreal y=zimag next if flag = 1 drawpoint(h+100,150-v) ok next next endpaint() } label1 { setpicture(p1) show() }
</lang>
Ruby
<lang ruby>def julia(c_real, c_imag)
puts Complex(c_real, c_imag) -1.0.step(1.0, 0.04) do |v| puts -1.4.step(1.4, 0.02).map{|h| judge(c_real, c_imag, h, v)}.join end
end
def judge(c_real, c_imag, x, y)
50.times do z_real = (x * x - y * y) + c_real z_imag = x * y * 2 + c_imag return " " if z_real**2 > 10000 x, y = z_real, z_imag end "#"
end
julia(-0.8, 0.156)</lang>
- Output:
-0.8+0.156i # # ## ####### ## #### ## # #### ## # # # ### ### # ## # # ###### ########## # # # # ###### ########## # # ### ### # ############ ###### # ################ ################### # # ### # ################ #################### ## # ### ## ## ############################## ### #### # ####### ### # ## ## # ##################### # #### ## #### ### ########### ###### # # ##### ##################### # # ## ###################### ### ####### #### # ####################### # ### ############ ### ## ## ## ## ## ################# ######################## ### ########### ## ### ### ################# ## ###### # # ################### # ##### ## ######## # ### # ###### ############ ## ## # ### ############## # ## ### ## # #### # # ## ### ## ########### ## #### ############# ## # ## ### ## ## ####### ## ##### ######### ############# ### # # ####### # # ### ############# ######### ##### ## ####### ## ## ### ## # ## ############# #### ## ########### ## ### ## # # #### # ## ### ## # ############## ### # ## ## ############ ###### # ### # ######## ## ##### # ################### # # ###### ## ################# ### ### ## ########### ### ######################## ################# ## ## ## ## ## ### ############ ### # ####################### # #### ####### ### ###################### ## # # ##################### ##### # # ###### ########### ### #### ## #### # ##################### # ## ## # ### ####### # #### ### ############################## ## ## ### # ## #################### ################ # ### # # ################### ################ # ###### ############ # ### ### # # ########## ###### # # # # ########## ###### # # ## # ### ### # # # ## #### # ## #### ## ####### ## # #
JRubyArt is a port of Processing to the ruby language, here we target same Julia Set as Processing for comparison, produces a colored output <lang ruby>
- frozen_string_literal: true
attr_reader :max_iter CONST = Complex(-0.7, 0.27015)
def setup
sketch_title 'Julia Set' @max_iter = 360 color_mode HSB, 360, 100, 100 load_pixels
end
def draw
grid(width, height) do |x, y| i = max_iter z = Complex(map1d(x, 0..width, -1.4..1.4), map1d(y, 0..height, -1.0..1.0)) while z.abs < 2 && i -= 1 z *= z z += CONST end pixels[x + width * y] = color((360 * i) / max_iter, 100, i) end update_pixels fill 0 text CONST.to_s, 530, 400 no_loop
end </lang>
Rust
<lang rust>extern crate image;
use image::{ImageBuffer, Pixel, Rgb};
fn main() {
// 4 : 3 ratio is nice let width = 8000; let height = 6000;
let mut img = ImageBuffer::new(width as u32, height as u32);
// constants to tweak for appearance let cx = -0.9; let cy = 0.27015; let iterations = 110;
for x in 0..width { for y in 0..height { let inner_height = height as f32; let inner_width = width as f32; let inner_y = y as f32; let inner_x = x as f32;
let mut zx = 3.0 * (inner_x - 0.5 * inner_width) / (inner_width); let mut zy = 2.0 * (inner_y - 0.5 * inner_height) / (inner_height);
let mut i = iterations;
while zx * zx + zy * zy < 4.0 && i > 1 { let tmp = zx * zx - zy * zy + cx; zy = 2.0 * zx * zy + cy; zx = tmp; i -= 1; }
// guesswork to make the rgb color values look okay let r = (i << 3) as u8; let g = (i << 5) as u8; let b = (i << 4) as u8; let pixel = Rgb::from_channels(r, g, b, 0); img.put_pixel(x as u32, y as u32, pixel); } }
let _ = img.save("output.png");
}</lang>
Scala
Java Swing Interoperability
<lang Scala>import java.awt._ import java.awt.image.BufferedImage
import javax.swing._
object JuliaSet extends App {
SwingUtilities.invokeLater(() => new JFrame("Julia Set") {
class JuliaSet() extends JPanel { private val (maxIter, zoom) = (300, 1)
override def paintComponent(gg: Graphics): Unit = { val g = gg.asInstanceOf[Graphics2D]
def drawJuliaSet(g: Graphics2D): Unit = { val (w, h) = (getWidth, getHeight) val image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB) val (cX, cY) = (-0.7, 0.27015) val moveX, moveY = 0 var zx, zy = 0.0
for (x <- 0 until w; y <- 0 until h) { zx = 1.5 * (x - w / 2) / (0.5 * zoom * w) + moveX zy = (y - h / 2) / (0.5 * zoom * h) + moveY var i: Float = maxIter while (zx * zx + zy * zy < 4 && i > 0) { val tmp = zx * zx - zy * zy + cX zy = 2.0 * zx * zy + cY zx = tmp i -= 1 } val c = Color.HSBtoRGB((maxIter / i) % 1, 1, if (i > 0) 1 else 0) image.setRGB(x, y, c) } g.drawImage(image, 0, 0, null) }
super.paintComponent(gg) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) drawJuliaSet(g) }
setBackground(Color.white) setPreferredSize(new Dimension(800, 600)) }
add(new JuliaSet, BorderLayout.CENTER) pack() setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE) setLocationRelativeTo(null) setResizable(false) setVisible(true) } )
}</lang>
Sidef
<lang ruby>require('Imager')
var (w, h) = (640, 480) var img = %s'Imager'.new(xsize => w, ysize => h, channels => 3)
var maxIter = 50 var c = Complex(-0.388, 0.613)
var color = %s'Imager::Color'.new('#000000')
for x,y in (^w ~X ^h) {
var i = maxIter var z = Complex((x - w/2) / w * 3, (y - h/2) / h * 2) while (z.abs < 2 && --i) { z = (z*z + c) } color.set(hsv => [i / maxIter * 360, 1, i]) img.setpixel(x => x, y => y, color => color)
}
img.write(file => "JuliaSet_sidef.png")</lang>
This version generates an ASCII representation: <lang ruby>var (w, h) = (141, 50)
var maxIter = 40 var c = Complex(-0.8, 0.156)
for y in ^h {
for x in ^w { var i = maxIter var z = Complex(3 * (x - w/2) / w, 2 * (y - h/2) / h) while (z.abs < 2 && --i) { z = (z*z + c) } print (i > 0 ? ' ' : '#') } print "\n"
}</lang>
- Output:
## ## ####### ######## # ## # ### ## # # ##### #### ## ## # ###### ########## # ######## ########## # ## ###### ######################## ### ################ ################### ## ## # ### # # ##################################### # ### ## # # ############################# ########### # ###### ### # # ## ########################### # ######## ################# # # # #### ##################### ### #### ##################### ### ############ ###################### # # ### ################ ### # # # ### # ################# ###################### ## ########### # ## ###### ########################### #################### ###### ## ########## ### # ### # ## ################ ## ###### ################# ######## ## # ###### ## ## #### ## # # ########### # #### ############# #### ### ####### ########### ## ###### ########## ############ ## # ########## # ## ############ ########## ###### ## ########### ####### ### #### ############# #### # ########### # # ### #### ## ## ###### # ## ######## ################# ###### ## ################ ## # ### # ### ########## ## ###### #################### ########################### ###### ## # ########### ## ###################### ################# # ### # # # ### ################ ### # # ###################### ############ ### ##################### #### ### ##################### #### # # # ################# ######## # ########################### ## # # ### ###### # ########### ############################# # # ## ### # ##################################### # # ### # ## ## ################### ################ ### ######################## ###### ## # ########## ######## # ########## ###### # ## ## #### ##### # # ## ### # ## # ######## ####### ## ##
Wren
<lang ecmascript>import "graphics" for Canvas, Color import "dome" for Window
var MaxIters = 300 var Zoom = 1 var MoveX = 0 var MoveY = 0 var CX = -0.7 var CY = 0.27015
class JuliaSet {
construct new(width, height) { Window.title = "Julia Set" Window.resize(width, height) Canvas.resize(width, height) _w = width _h = height }
init() { Canvas.cls(Color.white) createJulia() }
createJulia() { for (x in 0..._w) { for (y in 0..._h) { var zx = 1.5 * (x - _w / 2) / (0.5 * Zoom * _w) + MoveX var zy = (y - _h / 2) / (0.5 * Zoom * _h) + MoveY var i = MaxIters while (zx * zx + zy * zy < 4 && i > 0) { var tmp = zx * zx - zy * zy + CX zy = 2 * zx * zy + CY zx = tmp i = i - 1 } var c = Color.rgb(i % 256, i % 256, (i*8) % 256) Canvas.pset(x, y, c) } } }
update() {}
draw(alpha) {}
}
var Game = JuliaSet.new(800, 600)</lang>
zkl
Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl
<lang zkl>fcn juliaSet{
w,h,zoom:=800,600, 1; bitmap:=PPM(w,h,0xFF|FF|FF); // White background
cX,cY:=-0.7, 0.27015; moveX,moveY:=0.0, 0.0; maxIter:=255;
foreach x,y in (w,h){ zx:=1.5*(x - w/2)/(0.5*zoom*w) + moveX; zy:=1.0*(y - h/2)/(0.5*zoom*h) + moveY; i:=maxIter; while(zx*zx + zy*zy < 4 and i > 1){
tmp:=zx*zx - zy*zy + cX; zy,zx=2.0*zx*zy + cY, tmp; i-=1;
} // convert byte to RGB (3 bytes), kinda magic to get nice colors bitmap[x,y]=i.shiftLeft(21) + i.shiftLeft(10) + i*8; }
bitmap.writeJPGFile("juliaSet.jpg",True);
}();</lang>
- Programming Tasks
- Solutions by Programming Task
- Ada
- SDLAda
- ALGOL 68
- Amazing Hopper
- AWK
- BASIC
- QBasic
- True BASIC
- Yabasic
- GW-BASIC
- Locomotive Basic
- Sinclair ZX81 BASIC
- ZX Spectrum Basic
- C
- C sharp
- C++
- COBOL
- Crystal
- Delphi
- Winapi.Windows
- Vcl.Graphics
- EasyLang
- Elixir
- Emacs Lisp
- F Sharp
- Fortran
- FreeBASIC
- Fōrmulæ
- Go
- Haskell
- J
- Java
- JavaScript
- Jq
- Julia
- Kotlin
- Lua
- Mathematica
- Wolfram Language
- Nim
- Imageman
- Perl
- Phix
- Phix/pGUI
- PHP
- Processing
- Processing Python mode
- Python
- Racket
- Pages with broken file links
- Raku
- REXX
- Ring
- Ruby
- RubyGems
- JRubyArt
- Rust
- Scala
- Sidef
- Wren
- DOME
- Zkl