I have an application which hosts a Google Earth Plugin instance and I'm interested in getting the current scale of the map and use it in my application.
I know I can use the GEOptions
and set the Scale Legend visibility, but I want to use the actual scale value in my application and I couldn't find an API for it.
Is there a way to do this?
If not, how can i calculate the current scale, using perhaps the current view?
I have an application which hosts a Google Earth Plugin instance and I'm interested in getting the current scale of the map and use it in my application.
I know I can use the GEOptions
and set the Scale Legend visibility, but I want to use the actual scale value in my application and I couldn't find an API for it.
Is there a way to do this?
If not, how can i calculate the current scale, using perhaps the current view?
Share Improve this question edited Dec 21, 2012 at 22:59 Fraser 17.1k8 gold badges57 silver badges110 bronze badges asked Mar 14, 2012 at 17:42 user1269711user1269711 211 silver badge2 bronze badges2 Answers
Reset to default 5I use the below function to get an approximate scale from the Google Earth plugin API. This is calculated based on the camera's altitude from the ground. The tilt, pan, etc of globe will not affect the value returned. This is a simple function that works well if you only need a general idea of the actual map scale between the camera and the ground. Even when the camera is tilted looking into the horizon, this will still use the calculation as if the camera were looking straight down.
When the camera is tilted there is no single scale that can be calculated because the scale changes at any given point on the visible map. Two points in the distance have a different amount of distance per pixel on the screen vs the distance between two points near the camera. The scale legend is really an approximation as well because the distance only is accurate on a specific portion of the visible map.
function getScale() {
var camera = ge.getView().copyAsCamera(ge.ALTITUDE_RELATIVE_TO_GROUND),
eyeAlt,
scale;
eyeAlt = camera.getAltitude();
scale = Math.round(eyeAlt * 10.5);
return scale;
}
The scale legend itself is pretty ambiguous, since Google Earth is a globe in 3D, and perspective obviously isn't a projection that preserves distances (or even ratios between distances). This is less of an issue when looking straight down and fairly close to the surface of the earth, but as soon as the view is tilted, the land closer to the camera is going to have a very different scale than the land at the horizon.
At that point it makes more sense to ask about the current scale at a certain point on the screen. There is no direct API for this, but you can always find lat/lng coordinates for any two points on the screen and then find the distance between them.
GEView.hitTest is probably the easiest way of doing this. You can specify where the hit test should be done in pixels or as a fraction of the size of the plugin, offset from the edges of its DOM container. So if you wanted km/pixel near the middle of the view, for instance, you could: take the width and height of the plugin, divide them by two, then offset in each direction by 10 pixels, do the hittest query, find the distance between the returned coordinates, then finally divide by 10. How you actually offset those pixels is, again, up to where exactly you want to measure the scale (and note that if your hit test misses the earth, you'll get a null return value).
Warning: this is a very quickly thrown together bit of code (using the distance calculation from this thread). Please test thoroughly before using anywhere, but it should look something like this:
function getSomethingResemblingScale() {
var earthDiv = document.getElementById('map3d');
var hw = earthDiv.offsetWidth / 2;
var hh = earthDiv.offsetHeight / 2;
var view = ge.getView();
var hitTest1 = view.hitTest(hw - 5, ge.UNITS_PIXELS, hh, ge.UNITS_PIXELS, ge.HIT_TEST_TERRAIN);
var hitTest2 = view.hitTest(hw + 5, ge.UNITS_PIXELS, hh, ge.UNITS_PIXELS, ge.HIT_TEST_TERRAIN);
var dist = calcDistance(hitTest1.getLatitude(), hitTest1.getLongitude(), hitTest2.getLatitude(), hitTest2.getLongitude());
console.log('scale: ' + (dist/10) + ' km/pixel');
}
function calcDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = (lat2-lat1) * (Math.PI / 180);
var dLon = (lon2-lon1) * (Math.PI / 180);
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1*(Math.PI / 180)) * Math.cos(lat2*(Math.PI / 180)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
return d;
}