############################################################################
#
#	File:     tgrtrack.icn
#
#	Subject:  Program to translate "track log" files into TIGER chains
#
#	Author:   William S. Evans and Gregg M. Townsend
#
#	Date:     June 9, 2000
#
############################################################################
#
#  tgrtrack reads a fixed field length file containing track data from
#  a GPS receiver and outputs a "line chain" (.lch) format file (see
#  tgrprep) that can then be viewed using tgrmap.
#
#  Usage:  tgrtrack file
#
#	Input is a text file of coordinates such as those from a GPS
#	receiver.  Lines ending with two decimal values are interpreted
#	as specifying latitude and longitude in that order.
#	Lines without data indicate breaks between paths.
#
#	Output is a line chain file
#
############################################################################
#
#  Links:  numbers, strings
#
############################################################################

link numbers
link strings

global deltas
global curlon, curlat
global maxlon, minlon, maxlat, minlat

procedure main(args)
   local n, trackfile

   *args = 1 | stop("usage: ", &progname, " GPStrackfile")
   trackfile := open(args[1]) | stop("can't open ", args[1])
   n := llrange(trackfile)
   write("        ", rz(convertLon(minlon)), rz(convertLat(maxlat)))
   write("        ", rz(convertLon(maxlon)), rz(convertLat(minlat)))
   writeLCH(trackfile)
   return
end

procedure convertLat(n)
#  convert latitude from decimal degrees to fraction of semicircle
#  south of North Pole, as 0000000 to 9999999.
   static m
   initial m := 9999999 / 180.0
   return round(m * (90.0 - n))
end

procedure convertLon(n)
#  convert longitude to fraction of circle east of Greenwich,
#  as 0000000 to 9999999.
   static m
   initial m := 9999999 / 360.0

   n := real(n)
   if n < 0 then
      n +:= 360.0
   return round(m * n)
end


procedure writeLCH(trackfile)
   local x, y, line, n, trackPts, dim, startlon, startlat, lon, lat, w

   n := 1
   trackPts := 0
   deltas := ""

   seek(trackfile, 1) | fail
   repeat {
      line := read(trackfile) | "stop"
      every put(w := [], words(line))
      if (lat := real(w[-2])) & (lon := real(w[-1])) &
         (-90. <= lat <= 90.) & (-180. <= lon <= 180.) then {
            y := convertLat(lat)
            x := convertLon(lon)
            if (trackPts = 0) then {	# starting a new track
               deltas := ""
               startlon := minlon := maxlon := curlon := x
               startlat := minlat := maxlat := curlat := y
               }
            else {
               drawto(x, y)
               }
            trackPts +:= 1
            }
         else {
            if trackPts >= 2 then {
               dim := startlon - minlon
               dim <:= maxlon - startlon
               dim <:= startlat - minlat
               dim <:= maxlat - startlat
               dim >:= 9999
               write("T000|GPS Track ", n, "|", right(dim, 4),
                     rz(startlon), rz(startlat), deltas)
               n +:= 1
               }
            trackPts := 0
            }
      if w[1] == "stop" then break
      }
   return
end

procedure drawto(lon, lat)
   local dlon, dlat

   dlon := lon - curlon
   dlat := lat - curlat

   if abs(dlon | dlat) >= 5000 then {
      drawto(curlon + dlon / 2, curlat + dlat / 2)
      drawto(lon, lat)
      }
   else {
      deltas ||:= rz(dlon + 5000, 4)
      deltas ||:= rz(dlat + 5000, 4)
      curlon := lon
      curlat := lat
      minlon >:= lon
      maxlon <:= lon
      minlat >:= lat
      maxlat <:= lat
      }
   return
end


procedure rz(v, n)
#  right-justify value in n digits with zero fill
   /n := 7
   return right(v, n, "0")
end


procedure llrange(f)
#  scan f to set min/max lon/lat, returning record count
   local line, n, lon, lat, w

   minlon := +180.0
   maxlon := -180.0
   minlat := +90.0
   maxlat := -90.0
   n := 0

   seek(f, 1)
   while line := read(f) do line ? {
      every put(w := [], words(line))
      if (lat := real(w[-2])) & (lon := real(w[-1])) &
         (-90. <= lat <= 90.) & (-180. <= lon <= 180.) then {
            minlon >:= lon
            maxlon <:= lon 
            minlat >:= lat 
            maxlat <:= lat
            }
      }
   return n
end
