'
' Shape.Arrow.Make
'
' SELF: {
'   pt0: Origin
'   pt1: Destination
'   w: Width [number]
' }
'
' Returns: Polygon
'
' Requires: AV 3.2 or later
'
' 7 June 2001 W. A. Huber
'
' Comments: The width argument is a relative width:
' it expands (or shrinks) the width of the basic
' arrow; it is an aspect ratio.
'
' Example of field calculator use:
' av.run("Shape.Arrow.Make", {[x0]@[y0], [x1]@[y1], [width]})
'=============================================================='
'
' Check argument validity.
'
if (SELF = NIL or SELF.Is(List).Not or (SELF.Count<>3)) then
  return Polygon.MakeNull
end
'
' Check component types.
'

lClassArgs = {point, point, number}
for each i in 0..2
  if (SELF.Get(i).Is(lClassArgs.Get(i)).Not) then
    return Polygon.MakeNull
  end
end
'--------------------------------------------------------------'
'
' Create a basic arrow originating at (0,0), pointing
' at (1,0), of width 0.1. All the coordinates are
' parameterized to enable dynamic modification of the
' arrow shape.
'
' As an optimization, you can create this arrow once,
' save it in a public variable, and access it directly
' each time it is needed.
'
'
' Initialize basic arrow parameters.
'

xHead = 0.80     ' Where the arrow head begins
xHeadWidth = 2.0 ' Relative width of the arrow head
xW2 = 0.05       ' Half the width of the arrow
'
' Create the lower half of the arrow, which is symmetric
' about the x axis.
'

lPtArrow = {0@(-xW2), xHead@(-xW2), xHead@(-xW2*xHeadWidth), 1@0}
'
' Create the upper half by symmetry.
'

for each i in lPtArrow.Count-2..0
  lPtArrow.Add(lPtArrow.Get(i) * (1@(-1)))
end
'
' Make it into a polygon.
'

plyArrow = Polygon.Make({lPtArrow})
'--------------------------------------------------------------'
'
' *** Begin here if you already have created plyArrow and do
' not want to check argument validity. ***
'
' Rename the arguments for ease of reading.
'

pt0 = SELF.Get(0)
pt1 = SELF.Get(1)
'
' (For constant width arrows, set w proportional to 1/pt1.Distance(pt0),
' making sure first to check that this distance is nonzero.)
'

w = SELF.Get(2)
'
' Create an affine transformation that will carry the
' basic arrow into the desired one.
' (For information on affine transformations, please see
' http://www.quantdec.com/GIS/affine.htm )
'

ptV = pt1 - pt0
u = ptV.GetX
v = ptV.GetY
theXForm = Transform2D.Make.SetMatrixElements(
  {u, -v*w, pt0.GetX,
   v, u*w, pt0.GetY,
   0, 0, 1}
)
return plyArrow.Transform(theXForm)
' end of script