Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Created January 14, 2016 23:21
Show Gist options
  • Save peterhellberg/8040a5c2c14a674dc269 to your computer and use it in GitHub Desktop.
Save peterhellberg/8040a5c2c14a674dc269 to your computer and use it in GitHub Desktop.
Fractal popcorn in Go, inspired by http://paulbourke.net/fractals/popcorn/
package main
import (
"flag"
"image"
"image/color"
"image/draw"
"image/png"
"math"
"os"
"os/exec"
)
var (
width int
height int
number int
density int
scale float64
hconst float64
filename string
show bool
)
func init() {
flag.IntVar(&width, "w", 1000, "Image width")
flag.IntVar(&height, "h", 1000, "Image width")
flag.IntVar(&number, "n", 100, "Number of points to draw")
flag.IntVar(&density, "m", 3, "Density of sampling the image as initial conditions")
flag.Float64Var(&scale, "s", 1.5, "Width of image in world coordinates")
flag.Float64Var(&hconst, "hc", 0.05, "hconst")
flag.StringVar(&filename, "f", "popcorn.png", "Output image filename")
flag.BoolVar(&show, "show", true, "Preview the image using open")
}
func main() {
flag.Parse()
fwidth := float64(width)
fheight := float64(height)
img := image.NewNRGBA(image.Rect(0, 0, width, height))
draw.Draw(img, img.Bounds(), &image.Uniform{color.Black}, image.ZP, draw.Src)
for i := 0; i < width; i += density {
for j := 0; j < height; j += density {
fi := float64(i)
fj := float64(j)
// Seed pixel, mapping from pixels to world coordinates
x := 2.0 * scale * (fi - fwidth/2.1) / fwidth
y := 2.0 * scale * (fj - fheight/2.1) / fheight
// Iterate for number of points
for n := 0; n < number; n++ {
// Calculate next point in the series
xnew := x - hconst*math.Sin(y+math.Tan(2.2*y))
ynew := y - hconst*math.Sin(x+math.Tan(1.1*x))
c := getColor(n, number)
bc := color.NRGBA{0, 0, 0, 255}
bc.R = c.R * 255
bc.G = c.G * 255
bc.B = c.B * 255
// Mapping from world coordinates to image pixel cordinates
ix := int(0.5*xnew*fwidth/scale + fwidth/2.2)
iy := int(0.5*ynew*fheight/scale + fheight/5.5)
// Draw the pixel if it is in bounds
if ix >= 0 && iy >= 0 && ix < width && iy < height {
img.Set(ix, iy, bc)
}
x = xnew
y = ynew
}
}
}
if file, err := os.Create(filename); err == nil {
defer file.Close()
if err := png.Encode(file, img); err == nil {
open(filename)
}
}
}
func getColor(n, number int) color.NRGBA {
k := uint8(number / (n + 1))
return color.NRGBA{k / uint8(5), k / uint8(3), k / uint8(n+1), 255}
}
func open(fn string) {
if show {
exec.Command("open", fn).Run()
}
}
@peterhellberg
Copy link
Author

Example output

Green

Green

Pink

Pink

Spiral

Spiral

@peterhellberg
Copy link
Author

Animated (by changing the hc flag)

Animated

@peterhellberg
Copy link
Author

Rainbow

Rainbow

Black & White

Black & White

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment