During the summer of 2002, I took to the road, driving across the United States in order to find out if all those maps we buy are really representative of the world that is out there. As I drove, I would occasionally mark locations in my GPS unit to remember places that I'd been.
As part of an initiative to plot other geographical data, I developed a command line PHP tool that could handle ArcView ASCII-exported shape files. Primed with the GPS data I'd captured during my drive and tweaked slightly to produce ideal output, the images below represent three stages in the PHP / GIS tool development: the completed composite, the completed path example without state outlines, and the simple datapoint plot with state outlines.
<?php /* CreateGraphic Version 1.1 (07/12/2003 - 23:28:16) -- added progress bar and automatic image flipping -- tweaked database data to CONUS and fixed San Luis Obispo Version 1.2 (07/13/2003 - 01:50:55) -- eliminated imagesetpixel() call. why mark a spot twice? -- imagefilledellipse() call now, coverage areas more apparent. -- added lat/long lines and markers Version 1.2rs (07/14/2003 - 14:35:32) -- working with pubacc_rs "Receive Sites" database, there are approx 6.5:1 receivers to transmitters Version 2.0 (07/14/2003 - 15:23:15) (07/15/2003 - 09:40:52) -- adding state-level outlines using U.S. Census Bureau TIGER Database -- http://www.census.gov/geo/www/cob/bdy_files.html Version 2.1 (07/15/2003 - 12:59:26) -- switched to imagepolygon() function to draw state-level outlines. Version 2.1mv (07/16/2003 - 00:19:16) -- special fork to plot Way Out West GPS data. (c)2003 Max Vilimpoc, all rights reserved. Boundaries of image -- CONUS No ITFS stations below 24 deg. North latitude (Key West, FL @ 24o33') above 49 deg. North latitude (Bowbells, ND @ 48o43') east of 67 deg. West longitude (East Machias, ME @ 67o24') west of 125 deg. West longitude (Coos Bay, OR @ 124o14') */ function DMS($d_decimal, &$dd, &$dm, $o) { $dd = (int) substr($d_decimal, 2, $o); $dm = (int) floor(substr($d_decimal, 2+$o, 2) * 60 / 100); } function Rasterize() { global $long_d, $long_m, $lat_d, $lat_m, $pos_x, $pos_y, $im_width, $im_height; // so many globals.... $pos_x = (($long_d - 67 + 2) * 60 + $long_m) - 1; // -67degree minima, +120minute border, -1pixel (0,0) $pos_y = (($lat_d - 24 + 2) * 60 + $lat_m) - 1; $pos_x = $im_width - $pos_x; // flip image horizontally $pos_y = $im_height - $pos_y; // flip image vertically } $im_width = (125 - 67 + 1 + 4) * 60; // 3,780 px wide // accuracy of one minute. $im_height = (49 - 24 + 1 + 4) * 60; // 1,800 px tall // 6,804,000 8b; 20,412,000 24b; print "creating chart----$im_width x $im_height\n"; $map = @imagecreatetruecolor($im_width, $im_height) or die ("Cannot initialize new GD image stream!\n"); /* screen colors $m_itfs = imagecolorallocate($map, 255, 135, 17); $m_grid = imagecolorallocate($map, 0, 96, 0); $m_states = imagecolorallocate($map, 64, 64, 255); $m_text = imagecolorallocate($map, 255, 255, 0); $m_path = imagecolorallocate($map, 0, 255, 0); */ // print colors $m_bgcolor = imagecolorallocate($map, 255, 255, 255); imagefill($map, 0, 0, $m_bgcolor); $m_itfs = imagecolorallocate($map, 0, 0, 0); $m_grid = imagecolorallocate($map, 96, 96, 96); $m_states = imagecolorallocate($map, 32, 32, 32); $m_text = imagecolorallocate($map, 0, 0, 0); $m_path = imagecolorallocate($map, 0, 0, 0); $verdana = $_ENV["windir"] . "\\Fonts\\verdana.ttf"; $fontsize = 28; print "adding latitude and longitude lines\n"; // $lat = array(24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50); $lat = array(24, 28, 32, 36, 40, 44, 48); foreach($lat as $v) { $text = $v; $v = ($im_height - (($v - 24 + 2) * 60) + 2); // print $v . "\n"; imagefilledrectangle($map, 0, $v, $im_width, $v+3, $m_grid); imagettftext($map, $fontsize, 0, 30, $v - 14, $m_grid, $verdana, $text); } unset($lat); // $long = array(67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97, 100, 103, 106, 109, 112, 115, 118, 121, 124); $long = array(68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124); foreach($long as $v) { $text = $v; $v = ($im_width - (($v - 67 + 2) * 60) + 2); // print $v . "\n"; imagefilledrectangle($map, $v, 0, $v+3, $im_height, $m_grid); $bbox = imagettfbbox($fontsize, 0, $verdana, $text); $text_width = max($bbox[4] - $bbox[6], $bbox[2] - $bbox[0]); imagettftext($map, $fontsize, 0, $v - ($text_width + 15), 40, $m_grid, $verdana, $text); } unset($long); print "creating state-level outlines----\n"; $filelist = fopen("census.gov.cartographics/filelist.txt", "r"); while ($file = trim(fgets($filelist, 255))) { print "processing $file\n"; $afp = fopen("census.gov.cartographics/$file", "r"); while(!feof($afp)) { $line = fgets($afp, 255); // clear that first line of the record; if (stristr($line, "END")) break; // if we're at the end of file, break. $npoints = 0; // else, start a new shape. unset($shape); while ($line = fgets($afp, 255)) { if (stristr($line, "END")) break; $long = substr($line, 7, 7); $order = substr($line, 27, 1); DMS($long, $long_d, $long_m, $order); $lat = substr($line, 35, 6); DMS($lat, $lat_d, $lat_m, 2); Rasterize(); if (($pos_x == $shape[($npoints*2)-2]) && ($pos_y == $shape[($npoints*2)-1])) { // print "duplicate.\n"; continue; } $shape[] = $pos_x; $shape[] = $pos_y; $npoints++; } imagesetthickness($map, 4); if (count($shape) > 3) imagepolygon($map, $shape, $npoints, $m_states); } fclose($afp); } fclose($filelist); $afp = fopen("vilimpoc.trip.cartographics/Way-Out-West-Waypoints.txt", "r"); // format: -83.02842,40.10968,002, $num_rows = 204; $percent_int = 0; $target = 0; // load progress-bar triggers. $npoints = 0; print "processing Way Out West GPS data----\n"; print "0----1----2----3----4----5----6----7----8----9----| (x10%)\n"; while($row = fgetcsv($afp, 255)) { $percent_int++; $long_d = (int) floor($row[0]); $long_m = (int) floor(($row[0] - floor($row[0])) * 60); $lat_d = (int) floor($row[1]); $lat_m = (int) floor(($row[1] - floor($row[1])) * 60); Rasterize(); $path[] = $pos_x; $path[] = $pos_y; $npoints++; imagesetthickness($map, 1); imagefilledellipse($map, $pos_x, $pos_y, 13, 13, $m_itfs); if (stristr($row[3], "*")) { $bbox = imagettfbbox($fontsize, 0, $verdana, $row[2]); $text_width = max($bbox[4] - $bbox[6], $bbox[2] - $bbox[0]); $text_height = max($bbox[1] - $bbox[7], $bbox[3] - $bbox[5]); print "$row[2]: $text_width x $text_height\n"; imagettftext($map, $fontsize, 0, $pos_x + 10, $pos_y + (int)($text_height / 2), $m_text, $verdana, $row[2]); } $percent_f = ((int)floor(($percent_int / $num_rows) * 100)); // generate progress-bar trigger; if ($percent_f == $target) { print "*"; $target += 2; // move target forward by 2%. } } print "\n"; print "drawing trip path----\n"; imagesetthickness($map, 3); for ($i = 0; $i < ($npoints-1); $i++) { imageline($map, $path[$i*2], $path[$i*2+1], $path[$i*2+2], $path[$i*2+3], $m_path); } print "saving chart.\n"; // imagejpeg($map, "itfs-map.jpeg", 50); imagepng($map, "vilimpoc.trip.cartographics/wow-waypoints-map+path-print.png"); ?>