💾 Archived View for thrig.me › blog › 2023 › 05 › 16 › circle.go captured on 2023-05-24 at 18:07:05.

View Raw

More Information

-=-=-=-=-=-=-

// circle - draw circle like things

package main

import (
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/gif"
	"log"
	"math"
	"math/rand"
	"os"
	"time"
)

type Circle struct {
	x int
	y int
	r int
	c uint8

	h1 int // derived from y, radius, to find where circle is
}

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},
	/*
	   color.NRGBA{239,239,239, 255},
	   color.NRGBA{237,237,237, 255},
	   color.NRGBA{208,208,208, 255},
	   color.NRGBA{156,156,156, 255},
	   color.NRGBA{130,130,130, 255},
	   color.NRGBA{99,99,99, 255},
	   color.NRGBA{78,78,78, 255},
	*/

	/*
	   //color.NRGBA{0, 105, 148, 255},
	   color.NRGBA{0x00, 0x8D, 0xC7, 255},
	   color.NRGBA{0x00, 0xB1, 0xFA, 255},
	*/
}

const (
	fg_color = 0
	bg_color = 1
	cidx1    = 2
	cidx2    = 3
	cidx3    = 4
	cidx4    = 5
	cidx5    = 6
	cidx6    = 7
	cidx7    = 8
	//bg_color = 0
	//fg_color = 1
	//bl_color = 2
)

func cdhline(canvas *image.Paletted, c uint8, space, x1, x2, y int) {
	for x := x1; x <= x2; x += space {
		canvas.SetColorIndex(x, y, c)
	}
}

func chline(canvas *image.Paletted, c uint8, x1, x2, y int) {
	for x := x1; x <= x2; x++ {
		canvas.SetColorIndex(x, y, c)
	}
}

func chline2(canvas *image.Paletted, c uint8, x1, x2, y int) {
	x1 = x1 + irand(13) - 1
	x2 = x2 + irand(21) - 7
	for x := x1; x <= x2; x += 4 {
		canvas.SetColorIndex(x, y, c)
	}
}

func wcdhline(canvas *image.Paletted, c uint8, space, x1, x2, y int) {
	//x1 = x1 + irand(3) - 1
	x2 = x2 + irand(7) - 3
	for x := x1; x <= x2; x += space {
		canvas.SetColorIndex(x, y, c)
		canvas.SetColorIndex(x-1, y, c)
		canvas.SetColorIndex(x-1, y+1, c)
		canvas.SetColorIndex(x, y+1, c)

		canvas.SetColorIndex(x-1, y-1, c)
		canvas.SetColorIndex(x-2, y, c)
		canvas.SetColorIndex(x-2, y+2, c)
		canvas.SetColorIndex(x-1, y+2, c)

		canvas.SetColorIndex(x-2, y-2, c)
		canvas.SetColorIndex(x-4, y-1, c)
		canvas.SetColorIndex(x-3, y+3, c)
		canvas.SetColorIndex(x-2, y+3, c)
	}
}

func circle_fill(canvas *image.Paletted, circ *Circle, c uint8) {
	fmt.Fprintf(os.Stderr, "dbg y=%v r=%v %v\n", circ.y, circ.r, circ.y-circ.r)
	for y := 0; y <= circ.r; y++ {
		angle := math.Asin(float64(y) / float64(circ.r))
		x := int(math.Cos(angle) * float64(circ.r))

		start := circ.x - x
		end := circ.x + x
		chline(canvas, c, start, end, circ.y+y)
		chline(canvas, c, start, end, circ.y-y)
	}
}

func hline(canvas *image.Paletted, x1, x2, y int) {
	for x := x1; x <= x2; x++ {
		canvas.SetColorIndex(x, y, fg_color)
	}
}

func irand(max int) int {
	return int(rand.Int63n(int64(max)))
}

func main() {
	rand.Seed(time.Now().UTC().UnixNano())
	with_gif("out.gif")
	fmt.Fprintf(os.Stderr, "ok\n") // KLUGE for "fmt" import
}

func make_circle(x, y, r int, c uint8) Circle {
	circ := Circle{
		x: x,
		y: y,
		r: r,
		c: c,
	}
	circ.h1 = y - r
	// we really only need half the circle to find it
	//circ.h2 = y + r
	return circ
}

func rad2deg(radians float64) float64 {
	return radians * 180 / math.Pi
}

func with_gif(file string) {
	out, err := os.Create(file)
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()

	xsize := 320
	ysize := 240

	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)

	var circles []Circle
	circles = append(circles, make_circle(160, 120, 104, fg_color))

	var cnum uint8 = cidx1
	counter := -1

	// with image-global horizontal lines of some spacing...
	for y := 0; y < ysize; y += 9 {
		for _, circ := range circles {
			if y >= circ.h1 && y <= circ.y { // half-circle intersects?
				opp := circ.y - y
				angle := math.Asin(float64(opp) / float64(circ.r))
				adj := int(math.Cos(angle) * float64(circ.r))

				start := circ.x - adj
				end := circ.x + adj

				cdhline(canvas, cnum, 3, start, end, circ.y-opp) // top half
				chline2(canvas, cnum+7, start, end, circ.y+opp + 3)
				counter++

				if counter&1 == 1 {
					cnum++
					if cnum > cidx7 {
						cnum = cidx1
					}
				}

			} else {
				//cdhline(canvas, fg_color, 1, 0, xsize, y)
			}
		}
	}

	//cdhline(canvas, 4, 5,  0, xsize, 116)

	//dot := make_circle(130, 70, 16)
	//circle_fill(canvas, &dot, bg_color)

	options := &gif.Options{
		NumColors: len(palette),
	}
	gif.Encode(out, canvas, options)
}