#!/usr/bin/env texlua

-- $Id: test-luagraphlib.lua 3 2024-02-16 00:36:49Z reinhard $

-- Copyright (C) 2020 Reinhard Kotucha <reinhard.kotucha@web.de>
-- 
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License
-- as published by the Free Software Foundation; either version 2
-- of the License, or (at your option) any later version.
-- 
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
-- 
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-- MA 02110-1301, USA.

require('luagraphlib')
luagraphlib.import()

local fmt = string.format
local pi  = math.pi
local sin = math.sin
local cos = math.cos
local arc_tan = math.atan
local sqrt = math.sqrt

local color = dofile(kpse.find_file('namedcolors.lua'))

-- gray color model
local gray  = color.gray

-- rgb color model
local rgb   = color.rgb
local x11   = color.rgb.x11
local svg   = color.rgb.svg

-- cmyk color model
local cmyk  = color.cmyk
local dvips = color.cmyk.dvips
local hks   = color.cmyk.hks


function lines ()
  setlinewidth(sp(65536)) -- 1 pt
  moveto(0,0)
  lineto(50,50)
  lineto(100,0)
  stroke()
end


function units ()
  setlinewidth(2.3)

  local unittab = {
    { len = pt(1),   text = '1$\\,$pt' }, 
    { len = bp(1),   text = '1$\\,$bp' },
    { len = dd(1),   text = '1$\\,$dd' },
    { len = nd(1),   text = '1$\\,$nd' },
    { len = mm(1),   text = '1$\\,$mm' },
    { len = pc(1),   text = '1$\\,$pc' },
    { len = cc(1),   text = '1$\\,$cc' },
    { len = nc(1),   text = '1$\\,$nc' },
    { len = cm(1),   text = '1$\\,$cm' },
    { len = inch(1), text = '1$\\,$inch' },
  }

  for i,unit in ipairs (unittab) do
    gsave()
      translate (0, i*5 + 3)
      text(unit.text, {align='left'})
      moveto(12, 1)
      rlineto(unit.len, 0)
      stroke()
    grestore()
  end
end


function polar_star ()
  local function star (r)
    local theta = 144
    moveto(cartesian(r, 90))
    for i=0, 4 do
      lineto(cartesian(r, i*theta + 90))
    end
    closepath()
  end
  
  setstrokecolor(dvips.BrickRed)
  setfillcolor(svg.LightGoldenrod)
  
  translate(25,25)
  star(20)
  paint()

  translate(50,0)
  star(20)
  paint('eofill')
end


function arcs ()
  local r = 10
  gsave()
    setfillcolor(svg.PaleTurquoise)
    setstrokecolor(dvips.MidnightBlue)
    moveto(0, r)
    arc(r, r, r, 180, 270)
    lineto(100-r, 0)
    arc(100-r, r, r, 270, 360)
    lineto(100, 50-r)
    arc(100-r, 50-r, r, 0, 90)
    lineto(r, 50)
    arc(r, 50-r, r, 90, 180)
    closepath()
    paint()
  grestore()

  local r = 20
  
  moveto(50,25)
  setstrokecolor(dvips.BrickRed)
  setfillcolor(svg.Goldenrod)

  rlineto(cartesian(r, -100))
  arc(50, 25, r, -100, 230)
  scalepath(1, 0.5, 50, 25)
  closepath()
  paint()
end


function negative_arcs ()
  local r1 = 10
  local r2 = 20

  translate(50,25)
  setstrokecolor(dvips.BrickRed)
  setfillcolor(svg.Goldenrod)
 
  moveto(r2, 0)
  arc(0, 0, r2, 0, 90)
  lineto(0, r1)
  arcn (0, 0, 10, 90, 0)
  closepath()
  paint()
end


function ellipses ()
  setlinewidth(3)
  
  moveto(25,25)
  circle(10)
  closepath()
  stroke()

  gsave()
    translate(50,25)
    moveto(0,0)
    circle(10)
    closepath()
    scale(.7,1)
    stroke()
  grestore()

  setstrokecolor(dvips.MidnightBlue)
  translate(75,25)
  moveto(0,0)
  circle(10)
  closepath()
  scalepath(.7,1)
  gsave()
    setstrokecolor(dvips.BrickRed)
    stroke()
  grestore()
  translate(5,0)
  stroke()
  
  moveto(0,0)
  rectclip(-10,0,20,20)
  translate(-5,0)
  setstrokecolor(dvips.BrickRed)
  moveto(0,0)
  circle(10)
  scalepath(.7,1)
  closepath()
  stroke()
end

  
function rectangle ()
  setlinewidth(pt(0.4))
  moveto(50,25)
  rlineto(10,0)
  rlineto(0,10)
  stroke()
end


function fill_stroke ()
  setlinewidth(3)
  setstrokecolor(hks[47])
  setfillcolor(dvips.Goldenrod)

  gsave()
    translate(25,25)
    moveto(0,0)
    circle(10)
    closepath()
    paint()
    translate(0, -3)
    text('1', {scale=2.5})
  grestore()
  
  gsave()
    translate(50,25)
    moveto(0,0)
    circle(10)
    gsave()
      closepath()
      setstrokecolor(rgb.hks[47])
      fill()
      translate(0, -3)
      text('2', {scale=2.5})
    grestore()
    closepath()
    stroke()  
  grestore()

  gsave()
    translate(75,25)
    moveto(0,0)
    circle(10)
    gsave()
      closepath()
      stroke()  
    grestore()
    closepath()
    fill()
    translate(0, -3)
    text('3', {scale=2.5})
  grestore()
end  


function grid (x, y, w, h)
  translate(x,y)

  gsave()
    rectclip(0, 0, w, h)
    setstrokecolor(rgb.grid)
  
    setlinewidth(0.1)
    for i=0, w do
      moveto(i,0)
      rlineto(0,h)
    end
    for i=0, h do
      moveto(0,i)
      rlineto(w,0)
    end
    stroke()
    
    setlinewidth(0.25)
    for i=0, w, 5 do
      moveto(i,0)
      rlineto(0,h)
    end
    for i=0, h, 5 do
      moveto(0,i)
      rlineto(w,0)
    end
    stroke()
  
    setlinewidth(0.4)
  
    for i=0, w, 10 do
      moveto(i,0)
      rlineto(0,h)
    end
    for i=0, h, 10 do
      moveto(0,i)
      rlineto(w,0)
    end
    stroke()

    setstrokecolor(gray.black)
    setlinewidth(0)
  
    for i=0, w, 10 do
      moveto(i,0)
      rlineto(0,h)
    end
    for i=0, h, 10 do
      moveto(0,i)
      rlineto(w,0)
    end
    stroke()
  grestore()

  setlinewidth(0.3)
  rect(0,0,w,h)
  stroke()
  
  for i=0, w, 10 do
    gsave()
      translate(i, -4)
      text(i)
    grestore()
  end

  for i=0, h, 10 do
    gsave()
      translate(-1, i-1)
      text(i, {align='right'})
    grestore()
  end
end


function text_scaling ()
  translate(7,7)
  grid(0,0,90,40)
  
  setlinewidth(.5)
  gsave()
  setstrokecolor(svg.DarkGreen)
    moveto(50,5)
    rlineto(0,30)
    stroke()
  grestore()
  
  gsave()
    translate(50,25)
    text('scale = 3', {scale=3})

    translate(0,-10)
    gsave()
      text('extend = 3', {extend=3})
    grestore()
    
    translate(0,-10)
    text('left aligned, slant = 0.1',  {align='left',  slant=.1})
    text('right aligned, slant = -0.1', {align='right', slant=-.1})
  grestore()
end


function bezier_curves ()
  local radius = 30
  setlinewidth(pt(.4))
  setstrokecolor(gray.gray)
  setlinecap('round')

  gsave()
    moveto(25,5)
    setfillcolor(gray.black)
    circle(1)
    fill()
  grestore()

  gsave()
    moveto(95,45)
    setfillcolor(gray.black)
    circle(1)
    fill()
  grestore()

  gsave()
    moveto(95,45)
    rlineto(-15,0)
    gsave()
      setfillcolor(gray.black)
      circle(1)
      fill()
    grestore()
    stroke()
  grestore()
    
  for phi = 0, 135, 15 do
    setlinewidth(pt(.4))
    moveto(25,5)
    rlineto(cartesian(radius,phi))
    gsave()
      setfillcolor{phi/180, 0, 1-phi/120}
      setlinewidth(pt(.4))
      circle(1)
      fill()
    grestore()
    setstrokecolor(gray.gray)
    stroke()
    setlinewidth(pt(.4))
    setstrokecolor{phi/180, 0, 1-phi/120}
    moveto(25,5)
    local x1, x2 = cartesian(radius,phi)
    rcurveto(x1, x2, 55, 40, 70, 40)
    stroke()
  end
end


function colors ()
  rect(0,0,100,50)
  setfillcolor(gray.lightgray)
  fill()

  local function label (s)
    gsave()
      translate(1,4)
      text(s, {align='left',
               extend=1.333,
               textcolor=dvips.BrickRed,
              }
      )
    grestore()
  end
  
  translate(2,35)
  local RGB = {
    {1,1,1},
    {1,1,0},
    {0,1,1},
    {0,1,0},
    {1,0,1},
    {1,0,0},
    {0,0,1},
    {0,0,0},
  }
  for i, color in ipairs(RGB) do
    rect((i-1)*5,0, 5,10)
    setfillcolor(color)
    fill()
  end
  label ('RGB')
  
  translate(0,-10)
  local CMYK = {
    {0,0,0,0},
    {0,0,1,0},
    {1,0,0,0},
    {1,0,1,0},
    {0,1,0,0},
    {0,1,1,0},
    {1,1,0,0},
    {0,0,0,1},
  }
  for i,color in ipairs(CMYK) do
    rect((i-1)*5,0, 5,10)
    setfillcolor(color)
    fill()
  end
  label ('CMYK')

  translate(0,-10)
  for i=1, 8 do
    rect((i-1)*5,0, 5,10)
    setfillcolor{1 - (i-1)/7}
    fill()
  end
  label ('Gray')

  translate(0,-10)
  for i, color in ipairs(RGB) do
    rect((i-1)*5,0, 5,10)
    setfillcolor{.3*color[1] + .59*color[2] + .11*color[3]}
    fill()
  end
  label ('NTSC gray')
end


function framed_text ()
  grid(7,7,90,40)
  setlinewidth(.2)

  setstrokecolor(dvips.BrickRed)
  setfillcolor(svg.LightGoldenrod)

  
  gsave()
    translate(45,5)
    text('left aligned',
         { align = 'left',
           slant = -.1,
           sep   = 2,
           fillcolor=svg.LightGoldenrod,
           strokecolor=dvips.BrickRed,
           textcolor=gray.black,
           framed=true,
         }
    )
    text('right aligned',
         { align = 'right',
           slant = .1,
           sep   = 2,
           linewidth = 0.4,
           fillcolor   = svg.LightGoldenrod,
           strokecolor = dvips.BrickRed,
           textcolor   = gray.black,
           framed=true,
         })
  grestore()

  gsave()
    translate(45,10)
    text('extended',
         { extend=3,
           sep=2,
           fillcolor   = svg.LightGoldenrod,
           strokecolor = dvips.BrickRed,
           textcolor   = gray.black,
           framed=true,
    })
  grestore()

  ------------------

  gsave()
    translate(5,35)
    text('without strut:',
         {align = 'left',
          sep   = 2,
          fillcolor=gray.white,
          textcolor=gray.black,
          framed=true,
    })
  grestore()
  
  gsave()
    translate(5,30)
    text('AAA',
         {align = 'left',
          sep   = 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
    })
  grestore()
 
  gsave()
    translate(17,30)
    text('xxx',
         {align = 'left',
          sep   = 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
    })
  grestore()

  gsave()
    translate(26,30)
    text('yyy',
         {align = 'left',
          sep   = 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
    })
  grestore()

  gsave()
    translate(5,25)
    text('with strut:',
         {align = 'left',
          sep   = 2,
          fillcolor=gray.white,
          textcolor=gray.black,
          framed=true,
    })
  grestore()

  gsave()
    translate(5,20)
    text('AAA',
         {align = 'left',
          sep   = 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
          strut='Ay',
    })
  grestore()

  gsave()
    translate(17,20)
    text('xxx',
         {align = 'left',
          sep   = 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
          strut='Ay',
    })
  grestore()

  gsave()
    translate(26,20)
    text('yyy',
         {align = 'left',
          sep   = 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
          strut='Ay',
    })
  grestore()

  ------------------
  
  gsave()
    translate(55,35)
    text('without strut:',
         {align = 'left',
          radius = 2,
          fillcolor=gray.white,
          textcolor=gray.black,
          framed=true,
    })
  grestore()

  gsave()
    translate(55,30)
    text('AAA',
         {align = 'left',
          radius= 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
    })
  grestore()
 
  gsave()
    translate(67,30)
    text('xxx',
         {align = 'left',
          radius= 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
    })
  grestore()

  gsave()
    translate(76,30)
    text('yyy',
         {align = 'left',
          radius= 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
    })
  grestore()

  gsave()
    translate(55,25)
    text('with strut:',
         {align = 'left',
          radius= 2,
          fillcolor=gray.white,
          textcolor=gray.black,
          framed=true,
    })
  grestore()

  gsave()
    translate(55,20)
    text('AAA',
         {align = 'left',
          radius= 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
          strut='Ay',
    })
  grestore()

  gsave()
    translate(67,20)
    text('xxx',
         {align = 'left',
          radius= 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
          strut='Ay',
    })
  grestore()

  gsave()
    translate(76,20)
    text('yyy',
         {align = 'left',
          radius= 2,
          fillcolor=svg.LightGoldenrod,
          strokecolor=dvips.BrickRed,
          textcolor=gray.black,
          framed=true,
          strut='Ay',
    })
  grestore()
end


function dashpatterns ()
  gsave()
    rectclip(0,0,100,100)
    setlinewidth(1)
  
    for i=5, 15 do
      setdash({1,1,3,1}, i)
      moveto(0,   i*2)
      lineto(100, i*2)
      stroke()
    end

    for i=20, 30 do
      setlinecap('round')
      setdash({0,2,2,2}, i)
      gsave()
      setstrokecolor(dvips.BrickRed)
        moveto(-6,  i*2)
        lineto(106, i*2)
        stroke()
      grestore()
      moveto(0,   i*2)
      lineto(100, i*2)
      stroke()
    end

    for i=35, 45 do
      setlinecap('round')
      setdash({0,2,0,2}, i)
      gsave()
        setstrokecolor(dvips.BrickRed)
        moveto(-4,  i*2)
        lineto(104, i*2)
        stroke()
      grestore()
      moveto(0,   i*2)
      lineto(100, i*2)
      stroke()
    end
    grestore()
end


local function clockface (r)
  moveto(0,0)
  circle(r)  -- outer circle
  setstrokecolor{0}
  setfillcolor{1}
  paint('eofill')

  r = r * .93

  gsave()
    setlinewidth(.03*r) -- second ticks
    for i=0, 59 do
      moveto(r,0)
      lineto(.9*r,0)
      stroke()
      rotate(6)
    end
  grestore()
    
  gsave()
    setlinewidth(.05*r) -- 5 second ticks
    for i=0, 11 do
      moveto(r,0)
      lineto(.83*r,0)
      stroke()
      rotate(30)
    end
  grestore()
end

local function hands (r, t)
  local hour=t.hour%12 + t.min/60
  
  gsave() -- hour
    setlinewidth(.08*r)
    moveto(-.08*r,0)
    lineto(.6*r,0)
    rotate(90-hour*360/12)
    stroke()
  grestore()
  
  gsave() -- minute
    setlinewidth(.05*r)
    moveto(-.08*r,0)
    lineto(.8*r,0)
    rotate(90-t.min*6)
    stroke()
  grestore()
  
  gsave() -- second
    rotate(90-t.sec*6)
    setlinewidth(.02*r)
    moveto(-.1*r,0); lineto(.5*r,0)
    moveto(.7*r,0);  lineto(.96*r,0)
    setstrokecolor{.5, 0, 0}
    stroke()
      
    gsave() -- small circle
      setlinewidth(.04*r)
      translate(.6*r,0)
      moveto(0, 0)
      circle(.1*r)
      setstrokecolor{.5, 0, 0}
      stroke()
    grestore()
  grestore()
end


function clock ()
  setfillcolor{.9}
  rect(5,5,180,90)
  fill()
  
  local function label (location, t)
    gsave()
      translate(0,25)
      text('{\\bf '..location..'}',
        { scale=2.5,
          textcolor = dvips.BrickRed,
          framed=false,
      })
    grestore()
    gsave()
      translate(0,-30)
      local dow = {'So','Mo','Di','Mi','Do','Fr','Sa'}
      text(fmt('\\sf %s\\smash{\\hbox{,}} %d.$\\,$%d.$\\,$%d',
               dow[t.wday], t.day, t.month, t.year),
        { scale=1.5,
          sep=3,
          strut='0',
          textcolor = gray.black,
          strokecolor = gray.black,
          fillcolor = gray.white,
          framed=true,
      })
    grestore()
  end
  
  local r = 20 -- clock radius
  
  local t=(os.date('*t', os.time()))

  translate(190/2,50)

  label('Paris', t)
  clockface(r)
  hands(r,t)

  local t=(os.date('*t', os.time() - 3600*6))

  translate(-55,0)
  label('New$\\,$York', t)
  clockface(r)
  hands(r,t)
  
  translate(110,0)

  local t=(os.date('*t', os.time() + 3600*8))

  label('Tokyo', t)
  clockface(r)
  hands(r,t)
end


function metartest_1()
  gsave()
    setlinewidth(pt(0.4))

    for i=0, 24 do
      moveto (i*150/24,0)
      lineto (i*150/24,80)
      stroke()
      gsave()
        translate(i*150/24, -3.5)
        text (i)
      grestore()
    end

    for i=0, 16 do
      moveto (0, 5*i)
      lineto (150, 5*i)
      stroke()
      gsave()
        translate(155, 5*i - pt(3))
        text (i, {align='r'})
      grestore()
    end
  
    setlinewidth(pt(3))
  
    to_path(datafile('data/metar.data', 1, 3))

    scalepath(150/24, 5)

    gsave()
      setlinecap('round')
      setlinejoin('round')
      setstrokecolor(svg.Goldenrod)
      setstrokecolor(dvips.BrickRed)
      setlinewidth(pt(.6))
      stroke()
    grestore()

    gsave()
      smooth()
      setlinewidth(pt(.8))
      setstrokecolor({.5,.5,1})
      setstrokecolor(dvips.MidnightBlue)
      stroke()
    grestore()
  grestore()
end


function antenna ()
  translate(65,65)
  scale(1.2, 1.2)
  setlinewidth(pt(1))
  setlinejoin('round')
  setstrokecolor(gray.black)
  
  local function dB_to_polar (data)
    local fixed = {}

    for _,coords in ipairs(data) do
      fixed[#fixed+1] = {40 + coords[1], coords[2]}
    end
    return fixed
  end

  local patternfillcolor = {0.85}
  local textscale = 0.8
  moveto(0,0)
  circle(40)
  stroke()

  to_path(polar_to_cartesian(
            dB_to_polar(
              readdatafile('data/ant/rfi15_915h.data',
                           function (a) return a[2], a[1] end))))
  closepath()
  setstrokecolor(dvips.BrickRed)
  setfillcolor(patternfillcolor)
  paint()
  
  setstrokecolor(gray.black)
  setlinewidth(pt(0.4))
  for i = 10, 30, 10 do
    moveto(0,0)
    circle(i)
    stroke()
  end

  for phi = 0, 350, 10 do
    gsave()
    rotate(phi)
    translate(45, 0)
    rotate(-90)
    text('\\phantom{$^\\circ$}'..phi..'$^\\circ$',
         {
           scale = textscale,
         }
    )
    grestore()
  end
  
  for phi = 15, 360, 15 do
    moveto(cartesian(5, phi))
    lineto(cartesian(40, phi))
    stroke()
  end
  
  for phi = 45, 360, 45 do
    moveto(cartesian(0, phi))
    lineto(cartesian(40, phi))
    stroke()
  end
  
  for phi = 1, 360 do
    moveto(cartesian(40, phi))
    lineto(cartesian(42, phi))
    stroke()
  end
  
  for phi = 5, 360, 5 do
    moveto(cartesian(40, phi))
    lineto(cartesian(43, phi))
    stroke()
  end
  
  for phi = 10, 360, 10 do
    moveto(cartesian(40, phi))
    lineto(cartesian(44, phi))
    stroke()
  end

  setstrokecolor(gray.black)
  setlinewidth(pt(0.4))
  for i = 10, 30, 10 do
    moveto(0,0)
    circle(i)
    stroke()
  end

  for phi = 0, 350, 10 do
    gsave()
    rotate(phi)
    translate(45, 0)
    rotate(-90)
    text('\\phantom{$^\\circ$}'..phi..'$^\\circ$',
         {
           scale = textscale,
         }
    )
    grestore()
  end
  
  for phi = 15, 360, 15 do
    moveto(cartesian(5, phi))
    lineto(cartesian(40, phi))
    stroke()
  end
  
  for phi = 45, 360, 45 do
    moveto(cartesian(0, phi))
    lineto(cartesian(40, phi))
    stroke()
  end
  
  for phi = 1, 360 do
    moveto(cartesian(40, phi))
    lineto(cartesian(42, phi))
    stroke()
  end
  
  for phi = 5, 360, 5 do
    moveto(cartesian(40, phi))
    lineto(cartesian(43, phi))
    stroke()
  end
  
  for phi = 10, 360, 10 do
    moveto(cartesian(40, phi))
    lineto(cartesian(44, phi))
    stroke()
  end

  for _,dB in ipairs{10, 20, 30} do
    gsave()
      translate(dB, 0)
      translate(1, 0)
      rotate(270)
      text('$-'..40-dB..'\\,$dB',
           {
             scale = textscale,
             sep = 1,
             framed = true,
             fillcolor = patternfillcolor,
             strokecolor = patternfillcolor,
           }
      )
    grestore()
  end
end


function squares ()
  local function is_odd (n)
    if n%2 == 1 then return true end
  end
  local off = 0

  for i = 0, 9 do
    for k = 0, 5 do
      if is_odd(i) then off = 6 end
      rect (k*20+off, i*10, 10, 10)
      fill()
      off = 0
    end
  end
  
  setlinewidth(.5)
  for i = 0, 10 do
    moveto(0, i*10) 
    lineto(116, i*10) 
    stroke()
  end
end


function jiggling ()
  local function is_odd (n)
    if n%2 == 1 then return true end
  end
  
  local function wrect (x, y)
    rect(x*4, y*4, 4, 4)
    rectn(x*4+1, y*4+1, 2, 2)
    fill()
  end

  local function brect (x, y)
    rect(x*4+1, y*4+1, 2, 2)
  end

  for x=0, 24 do
    if is_odd(x) then
      for y=0, 24 do
        if is_odd(y) then
          wrect(x, y)
        else
          brect(x, y)
        end
      end
    else
      for y=0, 24 do
        if is_odd(y) then
          brect(x, y)
        else
          wrect(x, y)
        end
      end
    end
  end
end


function arrowheads ()
  local ahead1 = arrowshape { len = 10, wd = 3, inset = 1, offset = 7 }
  local ahead2 = arrowshape { len = 10, wd = 3, inset = 1 }
  local ahead3 = arrowshape { len = 10, wd = 3, inset = 3 }
  local ahead4 = arrowshape { len =  8, wd = 4 }
  local ahead5 = arrowshape { len =  3, wd = 2 }
  local ahead5 = arrowshape { len =  3, inset = 0.75 }
  grid (0, 0, 100, 50)
  gsave()
    ahead1 (10, 10, 0)
    ahead1 (30, 10, 30)
    ahead3 (50, 10, 45)
    ahead4 (70, 10, 45)
    ahead5 (90, 10, 45)
    for ang = 1, 12 do
      ahead2 (40, 30, ang*30)
    end
    for ang = 1, 12 do
      ahead3 (70, 30, ang*30)
    end
  grestore()
end  


-- Local Variables:
--  mode: Lua
--  TeX-engine: luatex
--  lua-indent-level: 2
--  indent-tabs-mode: nil
--  coding: utf-8-unix
-- End:
-- vim:set tabstop=2 expandtab: