turtle

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2021 License: MIT Imports: 7 Imported by: 0

README

go-turtle

Turtle graphics in Go.

A couple of showcase scripts are in the samples folder.

Moving around:

sample world

A conveniently 4K shaped image:

hilbert curve times 19

And another to be safe:

dragon level 12

Turtle

A minimal Turtle agent, moving on a cartesian plane.

The orientation is in degrees. Right rotates clockwise, Left counter-clockwise.

Use it to simulate the movements of the turtle without the drawing overhead.

// create a new turtle
t := turtle.New()

// move it just like you expect
t.Forward(5)
t.Left(45)
t.Forward(5)
t.Right(45)
t.Backward(5)

// get the X, Y, Deg data as needed
fmt.Println(t.X, t.Y, t.Deg)
// 3.5355339059327378 3.5355339059327373 0

// teleport around
t.SetPos(4, 4)
t.SetHeading(120)

// vaguely nice printing
fmt.Println("T:", t)
// T: (   4.0000,    4.0000) ^  120.0000

TurtleDraw

Has the same interface of Turtle, but draws. Each TurtleDraw is attached to a World.

Create a new world to draw in: an uniform image of the requested size (width, height) with SoftBlack background is generated.

w := turtle.NewWorld(900, 600)

The background color can be set:

w := turtle.NewWorldWithColor(900, 600, turtle.Yellow)

An existing image can be used as base:

img := image.NewRGBA(image.Rect(0, 0, 900, 600))
draw.Draw(img, img.Bounds(), &image.Uniform{turtle.Cyan}, image.Point{0, 0}, draw.Src)
wi := turtle.NewWorldWithImage(img)

Create a TurtleDraw attached to the World:

// create a turtle attached to w
td := turtle.NewTurtleDraw(w)

// position/orientation
td.SetPos(100, 300)
td.SetHeading(turtle.North + 80)

// line style
td.SetColor(turtle.Blue)
td.SetSize(4)

// start drawing
td.PenDown()

// same interface as Turtle
td.Forward(100)
td.Left(160)
td.Forward(100)

Save the current image:

err := w.SaveImage("world.png")
if err != nil {
    fmt.Println("Could not save the image: ", err)
}

Close the world (there are two open internal channels).

w.Close()

// this is an error: the turtle tries to send the line
// to the world input channel that has been closed
// td.Forward(50)

You can create as many turtles as you want. The Hilbert script shows an example where multiple turtles are created and placed, and then are all controlled at once to generate the same pattern in different locations. In this way, the expensive computation to generate the Hilbert fractal instructions is only done once.

When drawing, a turtle sends the line to the world on a channel and blocks until it is done.

Instructions

A simple struct is defined to pack the information needed to carry out an action.

type CmdType byte
const (
	CmdForward CmdType = iota
	CmdBackward
	CmdLeft
	CmdRight
)

type Instruction struct {
	Cmd    CmdType
	Amount float64
}

Which can be directly sent to a turtle:

td.DoInstruction(i)

Fractals

Turtle graphics are very useful to draw fractals.

The fractal package provides some functions to draw fractals, as a Lindenmayer system.

The functions generate Instructions on a channel, that can be executed as needed.

In the sample folder, there is a script that provides a CLI to generate nice images.

Constants

A few standard colors:

Black     = color.RGBA{0, 0, 0, 255}
SoftBlack = color.RGBA{10, 10, 10, 255}
White     = color.RGBA{255, 255, 255, 255}

Red   = color.RGBA{255, 0, 0, 255}
Green = color.RGBA{0, 255, 0, 255}
Blue  = color.RGBA{0, 0, 255, 255}

Cyan    = color.RGBA{0, 255, 255, 255}
Magenta = color.RGBA{255, 0, 255, 255}
Yellow  = color.RGBA{255, 255, 0, 255}

DarkOrange = color.RGBA{150, 75, 0, 255} // It's just so warm and relaxing

Cardinal directions:

East  = 0.0
North = 90.0
West  = 180.0
South = 270.0

Implementation notes

Note on float64

A lot of inputs to the API are actually float64, so when using a variable instead of an untyped const the compiler will complain if the var is int.

So this works as the var has type float:

segLen := 150.0
td.Forward(segLen)

and this does not:

segLen := 150
td.Forward(segLen)
// cannot use segLen (variable of type int) as float64 value
// in argument to td.Forward (compile)

This works magically because in Go constants are neat.

td.Forward(150)
Drawing pixels

When drawing points of odd size, the square is centered on the position. When drawing points of even size, the square is shifted to the top and right. The red points are drawn with y=0, along the bottom border of the image.

drawing pixels of even size

To draw a single point, just call forward with 0 dist:

td.Forward(0)
Channels and line drawing

The world draws the Line it receives on the DrawLineCh channel, so you can technically draw a line directly with that skipping the turtles altogether, and everything should work.

TODO - Ideas

  • Hilbert sample!
  • More colors!

Contributing

This was a side project to another one I was doing to learn Go, so all improvements and suggestions for a better code are welcome.

Documentation

Index

Constants

View Source
const (
	East  = 0.0
	North = 90.0
	West  = 180.0
	South = 270.0
)

Standard directions.

Variables

View Source
var (
	Black     = color.RGBA{0, 0, 0, 255}
	SoftBlack = color.RGBA{10, 10, 10, 255}
	White     = color.RGBA{255, 255, 255, 255}

	Red   = color.RGBA{255, 0, 0, 255}
	Green = color.RGBA{0, 255, 0, 255}
	Blue  = color.RGBA{0, 0, 255, 255}

	Cyan    = color.RGBA{0, 255, 255, 255}
	Magenta = color.RGBA{255, 0, 255, 255}
	Yellow  = color.RGBA{255, 255, 0, 255}

	// I just love this one
	DarkOrange = color.RGBA{150, 75, 0, 255}
)

Standard colors.

Functions

func Deg2rad

func Deg2rad(deg float64) float64

Convert degrees to radians.

func Rad2deg

func Rad2deg(rad float64) float64

Convert radians to degrees.

Types

type CmdType added in v0.3.0

type CmdType byte

Possible commands to send inside an Instruction.

const (
	CmdForward CmdType = iota
	CmdBackward
	CmdLeft
	CmdRight
)

type Instruction added in v0.3.0

type Instruction struct {
	Cmd    CmdType
	Amount float64
}

An action for the turtle.

type Line

type Line struct {
	X0, Y0 float64
	X1, Y1 float64
	// contains filtered or unexported fields
}

A simple Line with a Pen to send around channels.

type Pen

type Pen struct {
	Color color.Color // Line color.
	Size  int         // Line width.
	On    bool        // State of the Pen.
}

A simple Pen.

func NewPen

func NewPen() *Pen

Create a new Pen.

func (*Pen) PenDown

func (p *Pen) PenDown()

Start writing.

func (*Pen) PenToggle added in v0.2.0

func (p *Pen) PenToggle()

Toggle the pen state.

func (*Pen) PenUp

func (p *Pen) PenUp()

Stop writing.

func (*Pen) SetColor

func (p *Pen) SetColor(c color.Color)

Change the Pen color.

func (*Pen) SetSize

func (p *Pen) SetSize(s int)

Change the Pen size.

func (*Pen) String

func (p *Pen) String() string

Write the Pen state.

Implements: fmt.Stringer

type Turtle

type Turtle struct {
	X, Y float64 // Position.
	Deg  float64 // Orientation in degrees.
}

A minimal Turtle agent, moving on a cartesian plane.

https://en.wikipedia.org/wiki/Turtle_graphics

func New

func New() *Turtle

Create a new Turtle.

func (*Turtle) Backward

func (t *Turtle) Backward(dist float64)

Move the Turtle backward by dist.

func (*Turtle) DoInstruction added in v0.3.0

func (t *Turtle) DoInstruction(i Instruction)

Execute the received instruction.

func (*Turtle) Forward

func (t *Turtle) Forward(dist float64)

Move the Turtle forward by dist.

func (*Turtle) Left

func (t *Turtle) Left(deg float64)

Rotate the Turtle counter clockwise by deg degrees.

func (*Turtle) Right

func (t *Turtle) Right(deg float64)

Rotate the Turtle clockwise by deg degrees.

func (*Turtle) SetHeading

func (t *Turtle) SetHeading(deg float64)

Orient the Turtle towards deg.

func (*Turtle) SetPos

func (t *Turtle) SetPos(x, y float64)

Teleport the Turtle to (x, y).

func (*Turtle) String

func (t *Turtle) String() string

Write the Turtle state.

Implements: fmt.Stringer

type TurtleDraw

type TurtleDraw struct {
	Turtle // Turtle agent to move around.
	Pen    // Pen used when drawing.

	W *World // World to draw on.
}

A drawing Turtle.

func NewTurtleDraw

func NewTurtleDraw(w *World) *TurtleDraw

Create a new TurtleDraw, attached to the World w.

func (*TurtleDraw) Backward

func (td *TurtleDraw) Backward(dist float64)

Move the turtle backward and draw the line if the Pen is On.

func (*TurtleDraw) DoInstruction added in v0.3.0

func (td *TurtleDraw) DoInstruction(i Instruction)

Execute the received instruction.

func (*TurtleDraw) Forward

func (td *TurtleDraw) Forward(dist float64)

Move the turtle forward and draw the line if the Pen is On.

func (*TurtleDraw) SetPos

func (td *TurtleDraw) SetPos(x, y float64)

Teleport the Turtle to (x, y) and draw the line if the Pen is On.

func (*TurtleDraw) String

func (td *TurtleDraw) String() string

Write the TurtleDraw state.

Implements: fmt.Stringer

type World

type World struct {
	Image         *image.RGBA
	Width, Height int

	DrawLineCh chan Line
	// contains filtered or unexported fields
}

A world to draw on.

func NewWorld

func NewWorld(width, height int) *World

Create a new World of the requested size.

func NewWorldWithColor added in v0.2.0

func NewWorldWithColor(width, height int, c color.Color) *World

Create a new World of the requested size and background color.

func NewWorldWithImage added in v0.2.0

func NewWorldWithImage(m *image.RGBA) *World

Create a new World attached to an image.

func (*World) Close

func (w *World) Close()

Close the world channels, and stop the listen goroutine.

func (*World) ResetImage added in v0.2.0

func (w *World) ResetImage()

Reset the current image, keep the current size, default background color.

func (*World) ResetImageWithImage added in v0.2.0

func (w *World) ResetImageWithImage(m *image.RGBA)

Reset the current image to the provided one.

func (*World) ResetImageWithSize added in v0.2.0

func (w *World) ResetImageWithSize(width, height int)

Reset the current image, changing the size, default background color.

func (*World) ResetImageWithSizeColor added in v0.2.0

func (w *World) ResetImageWithSizeColor(width, height int, c color.Color)

Reset the current image, changing the size and background color.

func (*World) SaveImage

func (w *World) SaveImage(filePath string) error

Save output

Directories

Path Synopsis
samples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL