# Category talk:Jq-turtle

turtle.jq - turtle graphics with some ancillary SVG convenience functions.

To include these turtle graphics definitions, download the page contents (minus this preamble) into a file and include it using an appropriate `include` directive, e.g.

```include "turtle" {search: "."};
```

For an illustration of how to use the functions defined here, see Koch_curve.

```# The turtle's state: {svg, up, angle, x, y, minx, maxx, miny, maxy}

# Angle:
# => =   0 degrees
# ^  =  90 degrees
# <= = 180 degrees
# v  = 270 degrees

def pi: 4 * (1|atan);
def a2radians: 2 * pi * ./360;

# \$start : [\$x, \$y]
def turtle(\$start):
def mm: .minx = .x | .miny = .y | .maxx = .x | .maxy = .y;
\$start
| if type == "array"
then "M \(\$start|join(","))"
else turtle([0,0])
end
| {svg: ., up:true, angle:0, x: \$start[0], y: \$start[1] }
| mm ;

def turtleUp: .up=true;
def turtleDown: .up=false;

def minmax:
.minx = ([.minx, .x]|min)
| .miny = ([.miny, .y]|min)
| .maxx = ([.maxx, .x]|max)
| .maxy = ([.maxy, .y]|max) ;

# Move to \$xy = [\$x,\$y] without changing orientation
def turtleMove(\$xy):
\$xy as [\$x, \$y]
| .x = \$x | .y = \$y
| .svg += "M \(\$x),\(\$y)"
| minmax;

# Move to \$xy = [\$x,\$y] in SVG co-ordinates and change orientation to (\$angle % 360) degrees,
# but if \$xy is not an array, then just adjust the orientation.
def turtleMove(\$xy; \$angle):
if \$xy|type == "array"
then \$xy as [\$x, \$y]
| .svg += "M \(\$x),\(\$y)"
| .x = \$x | .y = \$y
| minmax
else .
end
| .angle = (\$angle % 360);

def turtleForward(\$d):
def rnd: 1000*.|round/1000;
if .up
then if   .angle==  0 then .svg += " m \(\$d),0"   | .x += \$d
elif .angle== 90 then .svg += " m 0,-\(\$d)"  | .y -= \$d
elif .angle==180 then .svg += " m -\(\$d),0"  | .x -= \$d
elif .angle==270 then .svg += " m 0,\(\$d)"   | .y += \$d
else (\$d * (.angle|cosDegrees)) as \$dx
|    (\$d * (.angle|sinDegrees) * -1) as \$dy
| .svg += " m\(\$dx|rnd),\(\$dy|rnd)\n"
| .x += \$dx
| .y += \$dy
end
else if   .angle==  0 then .svg += " h \(\$d)"   | .x += \$d
elif .angle== 90 then .svg += " v -\(\$d)"  | .y -= \$d
elif .angle==180 then .svg += " h -\(\$d)"  | .x -= \$d
elif .angle==270 then .svg += " v \(\$d)"	  | .y += \$d
else (\$d * (.angle|cosDegrees)) as \$dx
|    (\$d * (.angle|sinDegrees) * -1) as \$dy
| .svg += " l\(\$dx|rnd),\(\$dy|rnd)\n"
| .x += \$dx
| .y += \$dy
end
end
| minmax;

def turtleRotate(\$angle): .angle = (360 + (.angle + \$angle)) % 360;

def turtleArcRight(\$r):
if   .angle==  0 then .svg += " a\(\$r),\(\$r) 0 0 1 \(\$r),\(\$r)"  | .x += \$r | .y += \$r
elif .angle== 90 then .svg += " a\(\$r),\(\$r) 0 0 1 \(\$r),-\(\$r)" | .x += \$r | .y -= \$r
elif .angle==180 then .svg += " a\(\$r),\(\$r) 0 0 1 -\(\$r),-\(\$r)"| .x -= \$r | .y -= \$r
elif .angle==270 then .svg += " a\(\$r),\(\$r) 0 0 1 -\(\$r),\(\$r)" | .x -= \$r | .y += \$r
else "turtleArcRight at \(.angle) not yet supported" | error
end
| minmax
| turtleRotate(-90);

def turtleArcLeft(\$r):
if   .angle==  0 then .svg += " a\(\$r),\(\$r) 0 0 0 \(\$r),-\(\$r)" | .x += \$r | .y -= \$r
elif .angle== 90 then .svg += " a\(\$r),\(\$r) 0 0 0 -\(\$r),-\(\$r)"| .x -= \$r | .y -= \$r
elif .angle==180 then .svg += " a\(\$r),\(\$r) 0 0 0 -\(\$r),\(\$r)" | .x -= \$r | .y += \$r
elif .angle==270 then .svg += " a\(\$r),\(\$r) 0 0 0 \(\$r),\(\$r)"  | .x += \$r | .y += \$r
else "turtleArcRight at \(.angle) not yet supported" | error
end
| minmax
| turtleRotate(90);

def svg(\$size):
"<svg viewBox=\"0 0 \(\$size) \(\$size)\" xmlns=\"http://www.w3.org/2000/svg\">",
.,
"</svg>";

def path(\$fill; \$stroke; \$width):
"<path fill=\"\(\$fill)\" stroke=\"\(\$stroke)\" stroke-width=\"\(\$width)\" d=\"\(.svg)\" />";

def draw(\$size):
path("none"; "red"; 1) | svg(\$size);
```