Category talk:Jq-turtle: Difference between revisions

From Rosetta Code
Content added Content deleted
(minx maxx miny maxy)
 
Line 10: Line 10:


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


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


def turtleUp: .up=true;
def turtleUp: .up=true;
def turtleDown: .up=false;
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
# Move to $xy = [$x,$y] without changing orientation
def turtleMove($xy):
def turtleMove($xy):
$xy as [$x, $y]
$xy as [$x, $y]
| .svg += "M \($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,
# Move to $xy = [$x,$y] in SVG co-ordinates and change orientation to ($angle % 360) degrees,
Line 43: Line 56:
then $xy as [$x, $y]
then $xy as [$x, $y]
| .svg += "M \($x),\($y)"
| .svg += "M \($x),\($y)"
| .x = $x | .y = $y
| minmax
else .
else .
end
end
| .angle = ($angle % 360);
| .angle = ($angle % 360);



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


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


def turtleArcRight($r):
def turtleArcRight($r):
if .angle== 0 then .svg += " a\($r),\($r) 0 0 1 \($r),\($r)" # checked
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)" # checked
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)" # checked
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)" # checked
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
else "turtleArcRight at \(.angle) not yet supported" | error
end
end
| minmax
| turtleRotate(-90);
| turtleRotate(-90);


def turtleArcLeft($r):
def turtleArcLeft($r):
if .angle== 0 then .svg += " a\($r),\($r) 0 0 0 \($r),-\($r)" # check
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)" # check
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)" # check
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)"
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
else "turtleArcRight at \(.angle) not yet supported" | error
end
end
| minmax
| turtleRotate(90);
| turtleRotate(90);


############################################################################


def svg($size):
def svg($size):
Line 94: Line 116:
.,
.,
"</svg>";
"</svg>";

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


def draw($size):
def draw($size):
path("none"; "red"; 1) | svg($size) ;
path("none"; "red"; 1) | svg($size);
</pre>
</pre>

Latest revision as of 23:39, 16 January 2022

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;
def cosDegrees: a2radians|cos;
def sinDegrees: a2radians|sin;

# $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);