2015-04-24

Get a region's map tile URLs

Earlier today I found myself in a position of needing to grab a handful of map tiles from the Second Life map API. There's an image that needs making that requires a number of map images so grabbing them from that API made sense.

To help do this job, and to help work out what the URLs are for a given region, I knocked up this script:
//////////////////////////////////////////////////////////////////////
// Z&A Get Region Map Tile URLs
// By Antony Fairport
//
// Z&A Get Region Map Tile URLs - Get the map tile URLs for a given
// region; either the current region or one spoken by the object owner
// on channel 1.
//
// Revision history:
// ------------------------------------------------------------
//
// 2015-04-23
// Initial revision.
//////////////////////////////////////////////////////////////////////
// Globals.
key kRequest;
//////////////////////////////////////////////////////////////////////
// Get the size of a tile, in regions, at a given zoom level.
integer TileSize( integer iZoom )
{
return (integer) llPow( 2, iZoom - 1 );
}
//////////////////////////////////////////////////////////////////////
// Calculate the position of the tile to grab given the region we're
// after and the zoom level we want.
integer CalcPos( float nSimPos, integer iZoom )
{
integer iGridPos = (integer) ( nSimPos / 256.0 );
return iGridPos - ( iGridPos % TileSize( iZoom ) );
}
//////////////////////////////////////////////////////////////////////
// Get the URL for the tile that contains the region at the given
// position, at the given zoom level.
string RegionMapURL( vector vSimPos, integer iZoom )
{
return "http://map.secondlife.com/map-" + ( (string) iZoom ) + "-" +
( (string) CalcPos( vSimPos.x, iZoom ) ) +
"-" +
( (string) CalcPos( vSimPos.y, iZoom ) ) +
"-objects.jpg";
}
//////////////////////////////////////////////////////////////////////
// Tell the asker all the URLs for all the zoom levels.
TellURLs( key kAsker, vector vPos )
{
integer iZoom;
for ( iZoom = 1; iZoom <= 8; iZoom++ )
{
string sSize = (string) TileSize( iZoom );
llRegionSayTo( kAsker, 0,
"Zoom " + ( (string) iZoom ) + " (" + sSize + "x" + sSize + "): " +
RegionMapURL( vPos, iZoom ) );
}
}
//////////////////////////////////////////////////////////////////////
// Default state.
default
{
//////////////////////////////////////////////////////////////////
// Start listening on channel 1 for region names.
state_entry()
{
llListen( 1, "", llGetOwner(), "" );
}
//////////////////////////////////////////////////////////////////
// React to any touch.
touch_start( integer _ )
{
TellURLs( llDetectedKey( 0 ), llGetRegionCorner() );
}
//////////////////////////////////////////////////////////////////
// Listen for a region name.
listen( integer channel, string name, key id, string message )
{
if ( channel == 1 )
{
kRequest = llRequestSimulatorData( message, DATA_SIM_POS );
}
}
//////////////////////////////////////////////////////////////////
// React to an incoming data server event.
dataserver( key queryid, string data )
{
// A query we last sent?
if ( queryid == kRequest )
{
// It is. Tell the owner the URLs for the region at that pos.
TellURLs( llGetOwner(), (vector) data );
}
}
//////////////////////////////////////////////////////////////////
// React to changes.
changed( integer change )
{
// Owner changed?
if ( change & CHANGED_OWNER )
{
// Yes. Reset all the things.
llResetScript();
}
}
}

Just drop it into a prim and touch the prim to get all the URLs for all the map tiles, at all zoom levels, for the current region. Alternatively, say the name of a region on channel 1 to have it do the same for that region (the script is coded to only listen to the owner).

The output looks like this:


Using a variation on this script I was able to create the image I needed without too much effort (in my case I needed to get the tiles in a specific area, at a specific zoom level, so I could paste them together to make a bigger map).

I'm starting to wonder now if using something like this, in combination with media-on-a-prim, could be used to make an in-world interactive map (yes, I know, you could just browse maps.secondlife.com on a prim but where's the fun in that?).

Potential idle-time project at some point.

No comments:

Post a Comment