Julia set: Difference between revisions
No edit summary |
|||
Line 10: | Line 10: | ||
<lang cpp> |
<lang cpp> |
||
#include <windows.h> |
#include <windows.h> |
||
#include <ctime> |
|||
#include <string> |
#include <string> |
||
#include <complex> |
#include <complex> |
||
Line 139: | Line 138: | ||
}; |
}; |
||
int main( int argc, char* argv[] ) { |
int main( int argc, char* argv[] ) { |
||
srand( static_cast<unsigned>( time( 0 ) ) ); |
|||
std::complex<long double> c; |
std::complex<long double> c; |
||
long double factor = FCT / BMP_SIZE; |
long double factor = FCT / BMP_SIZE; |
Revision as of 12:11, 3 April 2016
Generate and draw a Julia set.
- Cf
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>
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 java.awt.*; import java.awt.image.BufferedImage; import javax.swing.*;
public class JuliaSet extends JPanel {
private final int maxIter = 300; private final double zoom = 1; private double cY, cX;
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);
cX = -0.7; cY = 0.27015; double moveX = 0, moveY = 0; double zx, zy;
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 = (y - h / 2) / (0.5 * zoom * h) + moveY; float i = maxIter; 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((maxIter / 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>
Julia
<lang julia>using Images
w, h = 800, 600 img = Array(UInt8, h, w, 3)
maxIter = 50 c = -0.8+0.156im
function hsv2rgb(h, s, v)
c = v * s x = c * (1 - abs(((h/60) % 2) - 1)) m = v - c
r,g,b = if h < 60 (c, x, 0) elseif h < 120 (x, c, 0) elseif h < 180 (0, c, x) elseif h < 240 (0, x, c) elseif h < 300 (x, 0, c) else (c, 0, x) end
r = round(UInt8, (r + m) * 255) g = round(UInt8, (g + m) * 255) b = round(UInt8, (b + m) * 255)
b,g,r
end
for x in 1:w
for y in 1:h i = maxIter z = Complex((x - w/2) / w * 3, (y - h/2) / h * 2) while abs(z) < 2 && (i -= 1) > 0 z = z*z + c end r,g,b = hsv2rgb(i / maxIter * 360, 1, i > 1 ? 1 : 0) img[y,x,1] = r img[y,x,2] = g img[y,x,3] = b end
end
save("JuliaSet.png", colorim(img, "RGB"))</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>
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 ) {
for ^$w -> $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 * 360, 1, ?$i).reverse; } }
}
sub hsv2rgb ( $h, $s, $v ){
my $c = $v * $s; my $x = $c * (1 - abs( (($h/60) % 2) - 1 ) ); my $m = $v - $c; my ($r, $g, $b) = do given $h { when 0..^60 { $c, $x, 0 } when 60..^120 { $x, $c, 0 } when 120..^180 { 0, $c, $x } when 180..^240 { 0, $x, $c } when 240..^300 { $x, 0, $c } when 300..^360 { $c, 0, $x } } ( $r, $g, $b ) = map { (($_+$m) * 255).Int }, $r, $g, $b;
}</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>
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>