PHP DevCenter

oreilly.comSafari Books Online.Conferences.

We've expanded our LAMP news coverage and improved our search! Search for all things LAMP across O'Reilly!

Search
Search Tips

advertisement

Listen Print Subscribe to PHP Subscribe to Newsletters

Trip Mapping with PHP
Pages: 1, 2

Map



We need a map on which to draw red lines. The Institute for the Study of the Continents at Cornell University has an Interactive Mapping Tool that we can use. Adjusting the map extent and turning on state borders produces the map shown in Figure 1.


Figure 1 - a US map with state borders

To turn longitude and latitude into a spot in the image, you need to translate a coordinate from longitude and latitude into x and y coordinates. The map in Figure 1 runs from -125 degrees longitude to -67 degrees longitude and is 602 pixels wide. This means that -125 degrees longitude has an x coordinate of 0, and -67 degrees longitude has an x coordinate of 601. Since 602 pixels represent 58 degrees of longitude, 1 degree of longitude corresponds to about 10.4 pixels (602 / 58). In latitude, the map runs from 23 degrees to 50 degrees and is 324 pixels high. Twelve pixels represent 1 degree of latitude (324 / (50 - 23)).

Using this logic, the latlon_to_pix() function translates latitude and longitude to x and y coordinates. The range of x and y coordinates in the image are set in $x_min, $x_max, $y_min, and $y_max. The range of latitude and longitude are set in $lon_min, $lon_max, $lat_min, and $lat_max. To simplify calculations, the latitude signs have been switched from negative to positive.

function latlon_to_pix($lat,$lon) {
	$lat = abs($lat);
	$lon = abs($lon);

	$x_min   = 0;  $x_max   = 602;
	$y_min   = 0;  $y_max   = 324;
	$lon_min = 67; $lon_max = 125;
	$lat_min = 23; $lat_max = 50;

	$x = $x_min + ($x_max - $x_min) * 
		( 1 - ($lon - $lon_min) / ($lon_max - $lon_min) );
	$y = $y_max - ($y_max - $y_min) * 
		( ($lat - $lat_min) / ($lat_max - $lat_min) );
	return array(intval($x),intval($y));
}

Drawing

With the data in the database and an appropriate map, you have all of the ingredients to create the image. The image display code follows. If it's not passed any ZIP codes, it displays a form to gather them.

// parse any ZIP codes in $_REQUEST['zip'] into an array
$zips = preg_split('/[^0-9]+/',$_REQUEST['zip'], 
                   -1, PREG_SPLIT_NO_EMPTY);

if (count($zips)) {
	$dbh = DB::connect('mysql://test:@localhost/test') 
		or die($php_errormsg);
	DB::isError($dbh) and die(print_r($dbh));

	$im = imagecreatefromjpeg('us.jpg');
	$red = imagecolorallocate($im,255,0,0);
	imagesetthickness($im,5);
	$x1 = $y1 = null;
	foreach ($zips as $zip) {
		$row = $dbh->getRow(
			'SELECT lat,lon FROM zcta WHERE zip LIKE ?',
			array($zip));
		DB::isError($row)
			and die("Can't get coordinates for $zip");
		is_null($row)
			and die("No coordinates for $zip");
		list($x,$y) = latlon_to_pix($row[0],$row[1]);
		if (is_null($x1) && is_null($y1)) {
			$x1 =$x; $y1 = $y;
		} else {
			imageline($im,$x1,$y1,$x,$y,$red);
			$x1 = $x; $y1 = $y;
		}
	}
	header('Content-type: image/jpeg');
	imagejpeg($im);
	imagedestroy($im);
} else {
	print<<<_HTML_
<form method="post" action="$_SERVER[PHP_SELF]">
Enter some ZIP Codes to have the path between them mapped:
<br>
<textarea name="zip" rows="4" cols="40"></textarea>
<br>
<input type="submit" value="Map It!">
</form>
_HTML_;
}

If $_REQUEST['zip'] contains ZIP codes (parsed by preg_split()), then $dbh and $im will contain a database connection and an image handle, respectively. Using imagecreatefromjpeg() loads us.jpg and returns a handle so you can draw lines on the image. After adding red to the color palette with imagecolorallocate(), call imagesetthickness() so that the lines drawn are bold on the map. Then, loop through each ZIP code and retrieve its latitude and longitude from the database. If $row contains latitude and longitude coordinates, translate them to x and y coordinates with latlon_to_pix() and draw a line with imageline(). Each time through the loop, the newly generated x and y coordinates are saved in $x1 and $y1. These become the starting point of the line the next time through the loop. The first time through the loop, no line is drawn, but the coordinates are saved for the next iteration.

After all the lines are drawn, header() tells the browser to expect a JPEG image. imagejpeg() sends the image data to the browser. imagedestroy() frees the memory allocated for the image.


Figure 2 - our circuitous tripometer

The map shown in Figure 2 is a trip from ZIP code 19151 (Philadelphia, PA) to 60615 (Chicago, IL) to 33433 (Boca Raton, FL) to 98052 (Redmond, WA) to 95472 (Sebastopol, CA). The ZIP codes, their longitudes, latitudes, x, and y coordinates are:

ZIP code Longitude Latitude x y
19151-75.2539.97516120
60615-87.6041.8038898
33433-80.1526.34465283
98052-122.1247.672927
95472-122.8338.3922139

The Census data file contains lots of additional information that might make interesting extensions to this program, such as drawing circles with diameters proportional to the population at each ZIP code. You could also calculate the total distance traveled using the code at http://px.sklar.com/code.html?id=88.

David Sklar is an independent consultant in New York City, the author of O'Reilly's Learning PHP 5, and a coauthor of PHP Cookbook.


O'Reilly & Associates will soon release (November 2002) PHP Cookbook .

  • Beta Sample Chapter 8, Web Basics, is available free online.

  • You can also look at the Full Description of the book.

  • For more information, or to order the book, click here.


Return to the PHP DevCenter.




Tagged Articles

Post to del.icio.us

This article has been tagged:

gis

Articles that share the tag gis:

An Introduction to Open Source Geospatial Tools (56 tags)

Build AJAX-Based Web Maps Using ka-Map (28 tags)

Hacking Maps with the Google Maps API (18 tags)

The Geospatial Web: A Call to Action (16 tags)

Mapping and Markup, Part 1 (10 tags)

View All

php

Articles that share the tag php:

Understanding MVC in PHP (477 tags)

The PHP Scalability Myth (123 tags)

The Dynamic Duo of PEAR::DB and Smarty (53 tags)

PHP Form Handling (43 tags)

Very Dynamic Web Interfaces (39 tags)

View All

map

Articles that share the tag map:

Hacking Maps with the Google Maps API (10 tags)

An Introduction to Open Source Geospatial Tools (5 tags)

Trip Mapping with PHP (5 tags)

Build AJAX-Based Web Maps Using ka-Map (4 tags)

Historical Maps Online (2 tags)

View All

tutorial

Articles that share the tag tutorial:

Rolling with Ruby on Rails (1417 tags)

A Simpler Ajax Path (135 tags)

Ajax on Rails (88 tags)

Rolling with Ruby on Rails, Part 2 (66 tags)

Very Dynamic Web Interfaces (66 tags)

View All

webdev

Articles that share the tag webdev:

Rolling with Ruby on Rails (351 tags)

Very Dynamic Web Interfaces (163 tags)

Understanding MVC in PHP (96 tags)

A Simpler Ajax Path (93 tags)

Ajax on Rails (61 tags)

View All

Sponsored Resources

  • Inside Lightroom
Advertisement

Sponsored by:

O'Reilly Media

©2009, O'Reilly Media, Inc.
(707) 827-7000 / (800) 998-9938
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
About O'Reilly
Academic Solutions
Authors
Contacts
Customer Service
Jobs
Newsletters
O'Reilly Labs
Press Room
Privacy Policy
RSS Feeds
Terms of Service
User Groups
Writing for O'Reilly
Content Archive
Business Technology
Computer Technology
Google
Microsoft
Mobile
Network
Operating System
Digital Photography
Programming
Software
Web
Web Design
More O'Reilly Sites
O'Reilly Radar
Ignite
Tools of Change for Publishing
Digital Media
Inside iPhone
O'Reilly FYI
makezine.com
craftzine.com
hackszine.com
perl.com
xml.com

Partner Sites
InsideRIA
java.net
O'Reilly Insights on Forbes.com