############################################################################
#
#	File:     gtrace.icn
#
#	Subject:  Procedures to process graphic traces
#
#	Author:   Ralph E. Griswold
#
#	Date:     November 19, 1997
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#  As used here, the term "trace" refers to a sequence of points that
#  generally consists of locations on a curve or other geometrical object.
#  These procedures process such traces in various ways.
#
############################################################################
#
#  See also:  gtraces.doc
#
############################################################################
#
#  Links:  calls, numbers, gobject
#
############################################################################

link calls
link numbers
link gobject

#  list_coords(call) lists the coordinates of the trace produced by
#  invoke(call)

procedure list_coords(call, p, w)
   local point

   /p := 6
   /w := 20

   every point := invoke(call) do
      write(decipos(point.x, p, w), decipos(point.y, p, w))

end

#
#  point_list(call, i) returns a list of the points in the trace produced
#  by invoke(call).  If i is nonnull, the list is limited to i points.

procedure point_list(call, i)
   local plist

   plist := []

   if \i then {
      every put(plist, invoke(call)) \ i
      }
   else {
      every put(plist, invoke(call))
      }

   return plist

end

#
#  coord_list(call, i) returns a list of the x,y coordinates in the trace
#  produced by invoke(call).  If i is nonnull, the list is limited
#  to i points.

procedure coord_list(call, limit)
   local clist

   clist := []

   if \limit then {
      every put(clist, !(invoke(call))) \ (limit * 2)
      }
   else {
      every put(clist, !(invoke(call)))
      }

   return clist

end

#  read_trace(f) produces a trace from the coordinate file f

procedure read_trace(f)
   local line
   static schar

   initial schar := &digits ++ '.'

   while line := read(f) do
      line ? {
         suspend Point(
            tab(upto(schar)) & tab(many(schar)),
            tab(upto(schar)) & tab(many(schar))
            )
         }

end

#  write_trace(header, call) writes a trace file from the trace of call.

procedure write_trace(header, call)
   local point

   write(header, ":")

   every point := invoke(call) do
      write(point.x, " ", point.y)

end

#  compose_trace(call_1, call_2) composes the trace for call_1 with the
#  trace for call_2; that is, the trace for call_1 is passed through
#  call_2.  For example, if call_1 traces a circle and call_2 draws a
#  star, the result is a star on each point of the circle.
#
#  The procedure assumes that the first two arguments to call_2 are
#  the x and y coordinates of the point in which it is interested
#  (standard trace format).

procedure compose_trace(trace, call_1, call_2)
   local point

   every point := invoke(call_1) do {
      call_2.args[1] := point.x		# set the origin for call_2
      call_2.args[2] := point.y
      suspend invoke(call_2)
      }

end

#  tcompress(call, i) discards all but the ith points on the trace
#  produced by call.  The first point of the trace is the first
#  point of the trace produced by calls.

procedure tcompress(call, i)
   local j, point

   j := 0

   every point := invoke(call) do {
      if j % i = 0 then suspend point
      i +:= 1
      }

end

#  interp_call(call) inserts a point midway on a line between every two points
#  on the trace produced by call.

procedure interp_trace(call)
   local point, last_point

   every point := invoke(call) do {
      if \last_point then {
         suspend last_point
         suspend Point(
            (point.x - last_point.x) / 2,
            (point.y - last_point.y) / 2
            )
         }
      last_point := point
      }

   suspend last_point

end

#  coord2point(cl) creates a list of points from a list of coordinates.
#  It destroys cl.

procedure coord2point(cl)
   local pl

   pl := []

   while put(pl, Point(get(cl), get(cl)))

   return pl

end

#  point2coord(pl) creates a list of coordinates from a list of points.
#  It does not destroy pl.

procedure point2coord(pl)
   local cl

   cl := []

   every put(cl, !!pl)

   return cl

end
