💾 Archived View for thrig.me › art › orbits › orbit.go captured on 2024-08-31 at 14:18:01.
⬅️ Previous capture (2023-05-24)
-=-=-=-=-=-=-
// orbits of color package main import ( "fmt" "image" "image/color" "image/draw" "image/gif" "log" "math" "math/rand" "os" "time" ) type Orbit struct { a float64 b float64 afuzz float64 bfuzz float64 xmid int ymid int iters int } var palette = []color.Color{ color.White, color.Black, color.NRGBA{255, 114, 114, 255}, color.NRGBA{255, 203, 114, 255}, color.NRGBA{255, 255, 114, 255}, color.NRGBA{57, 128, 57, 255}, color.NRGBA{114, 114, 255, 255}, color.NRGBA{99, 58, 130, 255}, color.NRGBA{238, 237, 238, 255}, color.NRGBA{78, 78, 78, 255}, color.NRGBA{99, 99, 99, 255}, color.NRGBA{130, 130, 130, 255}, color.NRGBA{156, 156, 156, 255}, color.NRGBA{208, 208, 208, 255}, color.NRGBA{237, 237, 237, 255}, color.NRGBA{239, 239, 239, 255}, } const ( fg_color = 0 bg_color = 1 cidx1 = 2 cidx2 = 3 cidx3 = 4 cidx4 = 5 cidx5 = 6 cidx6 = 7 cidx7 = 8 ) func irand(max int) int { return int(rand.Int63n(int64(max))) } func one_in(n int) bool { x := rand.Int63n(int64(n)) if x > 0 { return false } else { return true } } func make_orbit() Orbit { orb := Orbit{ a: 200 + rand.Float64()*800, afuzz: rand.Float64() * 2.0, bfuzz: rand.Float64() * 3.0, xmid: irand(1128 * 2), ymid: irand(752 * 2), iters: 120 + irand(640), } // not too eccentric an orbit? usually. if one_in(20) { orb.b = 200 + rand.Float64()*800 } else { orb.b = orb.a + rand.Float64()*100.0 + rand.Float64()*100.0 - 100.0 } // iters probably needs to scale with the size of the orbit, // otherwise small get overdrawn size := orb.a * orb.b // NOTE needs a floor to prevent feeding irand a 0 value orb.iters = irand(500 + int(size/1000)) return orb } // for 0 <= time <= 2*pi to sketch the whole thing func xyell(time, a, b float64) (x, y float64) { x = a * math.Cos(time) y = b * math.Sin(time) return x, y } func main() { rand.Seed(time.Now().UTC().UnixNano()) with_gif("out.gif") fmt.Fprintf(os.Stderr, "ok\n") // KLUGE for "fmt" import } func with_gif(file string) { out, err := os.Create(file) if err != nil { log.Fatal(err) } defer out.Close() xsize := 1128 ysize := 752 rect := image.Rect(0, 0, xsize, ysize) canvas := image.NewPaletted(rect, palette) draw.Draw(canvas, canvas.Bounds(), &image.Uniform{palette[bg_color]}, image.ZP, draw.Src) // NOTE the shapes may not actually be on-screen, so one // optimization would be to calclate for only those that do // present something within the canvas done := 0 for { if done == 17 { break } orb := make_orbit() for i := 0; i < orb.iters; i++ { t := rand.Float64() * math.Pi * 2 //xf, yf := xyell(t, orb.a+rand.Float64()*orb.afuzz, orb.b+rand.Float64()*orb.bfuzz) xf, yf := xyell(t, orb.a, orb.b) x := int(xf) y := int(yf) canvas.SetColorIndex(x+orb.xmid, y+orb.ymid, uint8(irand(7)+2)) if one_in(30) { orb.xmid++ } } done++ } // some background noise for i := 0; i < 200; i++ { canvas.SetColorIndex(irand(xsize), irand(ysize), uint8(irand(7)+9)) } options := &gif.Options{ NumColors: len(palette), } gif.Encode(out, canvas, options) }