by Mark Walters
Representing exact geographic locations on the earth, or geocoding, has become a popular topic lately. All the mapping service providers, such as Google, MapQuest, and Yahoo!, geocode addresses on their respective maps so you can easily see a specific location and get directions between multiple locations. With each of these services now providing public APIs, anyone can create mashups showcasing data of all types (such as photos, videos, and RSS feeds) on maps to link the data visually to a geographic location.
Allowing people to so easily associate data geographically has opened up new realms of information visualization on the web. RSS feeds not only provide news from around the world, but they can also display exactly where the news is coming from. Family and friends can follow along with you on your vacation as you post pictures and tag them with each city you visit. Geocoding opens up all kinds of possibilities.
Plotting the points in 2D on the maps provided by the different service providers is the most common way to view the information. But you can also view geodata on a globe of the earth in 3D via Adobe Flash by using the open-source 3D library Papervision3D.
Papervision3D is an open-source, real-time 3D engine for Flash. Using this library, you can get up to speed quickly and easily with a fully interactive 3D environment.
In this article, I show you how to use Papervision3D and the mapping API from Yahoo! and then combine them to display any location you enter on a 3D globe of the world.
Anxious to see what we're going to create? You can view the end result here.
First download the sample files (geoglobe.zip, 360 KB) so you can follow along and compare your code. Next, download the required libraries. You can download Papervision3D from Google Code. The current featured release is 1.5, but the beta of 2.0 is available in the Subversion (SVN) repository. For this article, we are using the beta (or GreatWhite as the Papervision3D team has coined it). We will also need the Tweener library to handle the rotations of the globe (use the "as3" directory as the source for the Tweener library).
Note: To learn more about Subversion, check out Subversive or Subclipse. Both are Eclipse plug-ins that can be used with Adobe Flex Builder to help you work with SVN more easily. I have always used Subclipse, but I recently found out that Subversive was migrated under the Eclipse umbrella and seems to be the SVN client of choice for Eclipse.
Once you've checked out the repositories as Flex library projects into Flex Builder, create a new Flex project and call it GeoGlobe. Now add the two previous libraries to the library path of the GeoGlobe project. To do this, right-click the GeoGlobe project and select Properties. Navigate to Flex Build Path and select the Library Path tab. Then click the Add Project button and select both libraries. Now you're ready to go.
Actually we'll just create the earth. I'll leave the heavens to you.
To get started with Papervision3D, you need to set up several things. First, you need to create a renderer, along with a scene, a camera, and a viewport. In the past, this was a repetitious, time-consuming task, but with the beta release, the Papervision3D team has created a BasicView class that sets everything up for you. All you need to do to get started is extend this class and start adding your own 3D geometry.
Let's create a GlobeView class that extends org.papervision3d.view.BasicView. This class will handle the creation of the globe and the markers to represent geographic locations.
The globe is the more important of the two. Create a new class and set it to extend org.papervision3d.objects.primitives.Sphere. All you need to do in this class is give the sphere a radius, segments, and a material. Set the radius to 320, the width segments to 24, and the height segments to 20. The more segments you give the sphere, the smoother the sphere will be. However, the more segments you give the sphere, the more the processor has to work. You need to balance the two, depending on the application you are creating.
The last property to set up is the material for the sphere. To accurately plot the latitude and longitude later, and to avoid distortion, you need a Mercator projection of the world. Mercator projections are cylindrical map projections that can be seamlessly wrapped around a sphere. The downloadable source files for this article contain one Mercator map. Feel free to find and try others to give the earth different appearances.
Now let's create the Marker class. The marker represents each geographic location on the map. I have created a simple cube as the marker, but you can create any type of 3D object to represent your marker. The Marker class extends org.papervision3d.objects.DisplayObject3D. The Marker class is actually a container of another 3D object; it does not extend the actual 3D object. This enables us to move the object up in the z direction within the container and then place the object based on the container's axis, which enables the object to sit above the surface of the globe rather than in the middle of it. Again, feel free to replace the marker object with any 3D object you want, but for now we'll use a cube.
For the GlobeView class, you need to create the globe and initialize the camera:
//Create a null object for the camera to copy.
cameraTarget = new DisplayObject3D();
scene.addChild( cameraTarget );
//Rotate the camera target to have the camera face America.
cameraTarget.yaw( 180 );
//Create the globe.
globe = new Globe();
scene.addChild( globe );
//Set the camera's focus and zoom.
camera.focus = 1100;
camera.zoom = 1;
Here we set the focus and zoom of the camera and created a target for the camera. The target, which is just an empty 3D display object, is used as a pseudo axis for the camera to rotate around. Papervision3D enables you to copy the position and transform settings of any 3D object and use them as the position and transform settings of any other 3D object. To do that, set the camera's transform setting to the target's transform setting and then move the camera backward a certain distance each time the scene is rendered. We move it back so that the camera is still far enough away from the globe to actually view it. If you didn't do that, the camera would be inside the globe along with the target.
Now let's set up the main Flex project application, GeoGlobe.mxml. Add a script tag and an event handler that listens for creationComplete. In the creationComplete handler, you want to create an instance of the GlobeView. You also need to set up an input text field and two buttons. The text field will expect a geographic location, and the two buttons add a marker to the globe at the specified location and clear the markers from the globe respectively.
We need a way to retrieve latitude and longitude points of any geographic location that is entered into the text field so we can accurately plot the locations on the globe. Luckily, this is a simple process with the help of one of the map services' APIs.
Google, MapQuest, and Yahoo! each provide an API for geocoding. I've chosen Yahoo! because they provide a direct URL that you can pass a free text location to and retrieve latitude and longitude values back. The location can be a city, state, city and state, country, or ZIP code. Once you hit the URL, you get back an XML file with details of that particular location. Two of the nodes list latitude and longitude.
To take advantage of this URL, you need to register with Yahoo! and get an application ID. The URL requires two query parameters: the location you would like to geocode and an appID.
Note: Once you get your Yahoo! application ID, make sure to enter it into the Geocoder class in the source code.
Retrieving the latitude and longitude of geographic locations is the easy part. Plotting them in the correct location can be tricky.
Let's look at what we have and what we will need to accomplish this task. We have a 3D sphere that has been mapped with a Mercator projection of the earth. We also have latitude and longitude points of any location on earth. What we need is an algorithm for converting these geographic locations to x, y, and z points on the globe.
Luckily, this algorithm already exists. The algorithm converts spherical coordinates to Cartesian coordinates:
x = r sin θ cos φ
y = r sin θ sin φ
z = r cos θ
where r is the radius; θ is theta, or the latitude; and φ is phi, or the longitude.
You don't need to be overly concerned with why or how the math works, just know that it does. What you do need to be aware of is that y and z will actually need to be swapped in the algorithm because the algorithm assumes z is in one direction while Papervision3D assumes it is in a different direction. The only other thing to be aware of is that you might need to offset the latitude and longitude by a certain number of degrees, depending on the placement of the map on the globe. Ours will need to have the latitude shifted 90 degrees and the longitude shifted 15 degrees.
Like I said, the math is the tricky part, but if you can get past that and accept that it works, you'll be much happier.
So now all you need to do is capture the text input from the text field and pass it to the map service API. From the API, you'll receive latitude and longitude points of the location. Now pass the latitude, longitude, and radius of the globe to the algorithm. The algorithm will provide x, y, and z coordinates of the location. You'll use these points to plot a marker on the globe.
Now you have a Flex application that can plot accurate latitude and longitude points on a 3D globe of the earth. This is a fairly complex topic, but if you've made it this far and have been either creating or looking at the GeoGlobe classes, you have the beginnings of a great application. Now consider adding photos and videos or even tracking your friends as they roam the world. Definitely dig into Papervision3D and the map service APIs to see what else they have to offer. Both go far deeper than any one article can cover.
Thanks to the team at Papervision3D, Carlos Ulloa, John Grden, and Ralph Hauwert, for reviewing this article and source code. Special thanks goes out to Carlos Ulloa for verifying the usage and explanation of the math in the article. I also want to thank Cheyenne Throckmorton for his detailed review with great technical insights on the article. Finally, a big thanks goes to James Hastings-Trew of Planetary Pixel Emporium for letting us use his fabulous earth texture map. — Mark Walters