Author: Makc
Date: July 25th 2008
version: 3.0.2
Globes become popular visualization tool for all kinds of spatial data. In this tutorial, you will learn how to make simple globle with markers on its surface using Sphere primitive and Sprite2D objects.
You should at least complete our simplest tutorial and one about sprites.
The main part of globe is Earth model, obviously. To make one, we will simply grab code from 1st tutorial above and apply Earth map in equirectangular projection as a texture:
This “Earth” sucks, and the first thing we will do is blow quality settings a bit by passing additional parameters to Sphere constructor:
var radius:Number = 100, quality:Number = 15; var sphere:Sphere = new Sphere ("mySphere", radius, quality, quality);
Next, we will modify the code by placing this “Earth” into wrapper TransformGroup, to combine it with other objects (such as markers) into single object you can move and rotate as a whole later:
// creation of transform group to hold sphere and markers var globe:TransformGroup = new TransformGroup; // creation of the Earth model var radius:Number = 100, quality:Number = 15; var sphere:Sphere = new Sphere ("mySphere", radius, quality, quality); sphere.appearance = new Appearance (new BitmapMaterial (new Texture (0,0))); sphere.rotateY += (360 / quality + 180); // adding globe to the scene globe.addChild (sphere); scene.root.addChild (globe);
Note misterious sphere rotation bit. This correction is dictated by the way sphere vertices are built, and was first suggested by trope. Let's take a look at result:
As you see, radius to zero coordinates point now coincides with local X axis, and radius to North pole now coincides with local Y axis direction.
Now it's time to write a function to place a marker into specified location. Usually geographic location is described using latitude and longitude. Together with radius, they are sort of spherical coordinate system. In sandy, location is specified using cartesian system, so we have to perform conversion. Lucky us, the math here is wellknown and simple enough; with adjustments for coordinate axis orientation in mind, we end up with following code:
function addMarker (lat:Number, lon:Number, marker:MovieClip):void { // convert coordinates to radians lat *= Math.PI / 180; lon *= Math.PI / 180; // make an object to hold our marker var markerObject:Sprite2D = new Sprite2D ("marker", marker, 0); markerObject.autoCenter = false; // place it in globe transform group globe.addChild (markerObject); markerObject.x = radius * Math.cos (lon) * Math.cos (lat); markerObject.z = radius * Math.sin (lon) * Math.cos (lat); markerObject.y = radius * Math.sin (lat); }
Note that we set autoCenter property on Sprite2D to false to have it precisely positioned regardless of content, and passed 0 as a scale to turn off any scaling.
To test our code, we will place few markers where errors could be easily seen, if any, e.g. at some islands (you would know you made a mistake if your marker lands in a middle of the ocean). Since we are looking at the Western hemisphere at the moment, I chose Havana and Kingston to be my victims:
// add some markers addMarker (23.13, -82.38, new Havana); addMarker (17.98, -76.80, new Kingston);
Let's see what we've got so far:
Just so that whole thing would look a bit more complete, we will place a camera at different angle and add some interactivity:
// move camera up scene.camera.y = 200; scene.camera.lookAt (0, 0, 0); // add interactivity function rotateGlobe (e:MouseEvent):void { globe.rotateY = 0.1 * (stage.mouseX - 275); scene.render(); } stage.addEventListener (MouseEvent.MOUSE_MOVE, rotateGlobe); rotateGlobe (null);
So, we have this now (move mouse around):