Event Details API location coordinates
Hmm, the points in the event details are actually weird. My first thought was that these are relative values, but this wouldn’t make sense too.
Currently I’m under the impression that those coordinates are supposed to be inside map_rect, which sits inside continent_rect on the map, but I didn’t put a lot of effort into trying to verify that (None)
Yep, thats the impression i have too after further investigation:
15: {
map_name: "Queensdale",
min_level: 1,
max_level: 17,
default_floor: 1,
floors: [0, 1, 2],
region_id: 4,
region_name: "Kryta",
continent_id: 1,
continent_name: "Tyria",
map_rect: [
[-43008, -27648],
[43008, 30720]
],
continent_rect: [
[9856, 11648],
[13440, 14080]
]
}
D77349CE-E422-469E-905B-827AA138D88F: {
name: "Stop the elder earth elemental from destroying the dam.",
level: 4,
map_id: 15,
flags: [ ],
location: {
type: "sphere",
center: [-28975, 27321.2, -785.732],
radius: 2000,
rotation: 0
}
}
….but: currently i don’t use the map_rect at all, nor do i have an idea how to translate the coords :o
Yes, math hard. Cliff?
Those coordinates ([-28975, 27321.2, -785.732]) look like what the in-game coordinates look like.
In-game, coordinates are calculated from the center of the map, where a negative on the Z axis is above sea level (Z is jumping). Moving West from the center of the map is negative on the X axis and moving South from the center of the map is negative on the Y axis. This is why there are negative coordinates.
The map_rect appears to be the [south east corner], [north west corner] coordinates. From what I’ve recorded, Queensdale is around that size (86016w, 58368h). Using map_rect, you can find the center and from that, place the event coordinate.
The continent_rect appears to be [x, y], [x + width, y + height] in pixels based on the world map when fully zoomed in. Using this, you should be able to calculate the center along with map_rect to place the coordinate on the map.
I haven’t played with these APIs yet, so I’m judging everything based on the Queensdale example above, and what I’ve personally recorded using in-game coordinates.
(edited by Healix.5819)
It’s basic algebra and coordinate translation.
Attachments:
Got it working by doing some percentage calulcations to calculate the continent coordinates from the map coordinates:
https://github.com/Goddchen/GuildWars2-API-Explorer/blob/master/GuildWars2APIExplorer/src/main/java/de/goddchen/android/gw2/api/fragments/ContinentFragment.java#L132
Yep, you’re using the exact same equations I posted.
I was using a numpy matrix, but even if I only built it once per map your pile of random characters is a lot faster.
All condensed in one ugly block of code so I don’t have to look at it so much:
def continent_coords(continent_rect, map_rect, point, game=False):
return (
(point[0]-map_rect[0][0])/(map_rect[1][0]-map_rect[0][0])*(continent_rect[1][0]-continent_rect[0][0])+continent_rect[0][0],
((-point[1] if game else point[1])-map_rect[0][1])/(map_rect[1][1]-map_rect[0][1])*(continent_rect[1][1]-continent_rect[0][1])+continent_rect[0][1]
)
On caveat that I forgot about, ozma caught me on it in a PM: the Y coordinates are inverted between map and continent. So you have to take the complement of the delta ( 1 – delta ) in the Y equation.
This attachment shows just the final equations for X and Y without the derivation I showed above.
(How do you show an image inside your post? The IMG tags don’t seem to work.)
Attachments:
(edited by Dr Ishmael.9685)
Looking through the Event Details API the coordinate system used is different then the one used by the Map API coordinates. Is there a conversion equation/system to convert the coordinates given in the Event Details API to the one used by the Map API coordinates?
Example:
[-9463.6,
-40310.2,
-785.799]
to something like
[20002.2,
16128.5]
(a random event coord and a random POI coord used as examples)
Thanks for any help
Covered over here:
The third number is the Z-coordinate, which doesn’t matter for plotting on a 2D map.
Thanks for the equation, can you provide an example of it being used as I’m having a hard time assigning variables to known numbers?
Event info :
“location”: “type” : “poly”, " center " : [ xxx , xxx , xxx ] …
Map info :
“map_rect”: [ [ xxx, xxx ], [ xxx, xxx ] ] …
“continent_rect”:[ [ xxx,xxx ],[ xxx , xxx ] ] …
Map Event location :
event_center_x = location.center [ 0 ] ;
event_center_y = location.center [ 1 ] ;
percentageX = (event_center_x – map_rect [ 0 ] [ 0 ] ) / (map_rect [ 1 ] [ 0 ] – map_rect [ 0 ] [ 0 ] );
percentageY = 1-(event_center_y – map_rect [ 0 ] [ 1 ] ) / (map_rect [ 1 ] [ 1 ] – map_rect [ 0 ] [ 1 ] );
continentX = (continent_rect [ 0 ] [ 0 ] + (continent_rect [ 1 ] [ 0 ] – continent_rect [ 0 ] [ 0 ] ) * percentageX);
continentY = (continent_rect [ 0 ] [ 1 ] + (continent_rect [ 1 ] [ 1 ] – continent_rect [ 0 ] [ 1 ] ) * percentageY);
// the coords for the event
event_coords = FromPixelToCoords([continentX, continentY], map.GetMaxZoom()); // map.GetMaxZoom() is set to 7 for Gw2 Map
(edited by The Last Engineer.6492)
This is a short sample to convert Pixel To coordinates :
public class APIProjection
{
private readonly double PixelTileSize = 256d;
private readonly double DegreesToRadiansRatio = 180d / Math.PI;
private readonly Point PixelGlobeCenter;
private readonly double XPixelsToDegreesRatio;
private readonly double YPixelsToRadiansRatio;
public APIProjection(double zoomLevel)
{
var pixelGlobeSize = this.PixelTileSize * Math.Pow(2d, zoomLevel);
this.XPixelsToDegreesRatio = pixelGlobeSize / 360d;
this.YPixelsToRadiansRatio = pixelGlobeSize / (2d * Math.PI);
var halfPixelGlobeSize = Convert.ToSingle(pixelGlobeSize / 2d);
this.PixelGlobeCenter = new Point(
halfPixelGlobeSize, halfPixelGlobeSize);
}
public Location FromPixelToCoordinates(Point pixel)
{
var longitude = (pixel.X - this.PixelGlobeCenter.X) /
this.XPixelsToDegreesRatio;
var latitude = (2 * Math.Atan(Math.Exp(
(pixel.Y - this.PixelGlobeCenter.Y) / -this.YPixelsToRadiansRatio))
- Math.PI / 2) * DegreesToRadiansRatio;
return new Location(
Convert.ToSingle(latitude),
Convert.ToSingle(longitude));
}
}
The third number is the Z-coordinate, which doesn’t matter for plotting on a 2D map.
Isn’t that the center of the sphere (if applies) so that you would draw a spherical segment on the map?
This is a short sample to convert Pixel To coordinates
If you work with leaflet.js, the similar methods are L.Map.project() and L.Map.unproject() btw. http://leafletjs.com/reference.html#map-conversion-methods
While we’re at it: i’m trying to do the same with the gmaps API – they have a simple example there. However, translating latlng to pixel works fine with that, but i believe i’m too dumb to figure out how to translate back from pixel to latlng – the example function doesn’t seem to work as expected. There are a gazillion threads on the net, asking how that works, most answers are just RTFM like or “yay, solved!” with no comment on the final solution.
So, anyone please?
https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
(edited by smiley.1438)
the pixel globe size is provided by the Gw2 API.
That’s the texture_dims defined in v1/map_floor.json?continent_id=1&floor=1
"texture_dims": [32768, 32768]
you are able to compute it by doing that :
pixelTileSize = 256
pixelGlobeSize = pixelTileSize * (2 ^ 7) = 32768 (7 is the max zoom level).
PixelGlobeCenter = [16384, 16384] ( [32768/2, 32768/2] )
For the location :
"coord":[19765.9,16239.2]
you can do this as below :
longitude = (coord[0] - 16384) / (32768 / 360);
latitude = (2 * arctan( e^( (coord[1] - 16384) / -(32768 / (2 * PI))))- PI / 2) * (180/PI);
Details :
coord[x, y] is the item location.
degreesToRadiansRatio = 180/PI
pixelTileSize = 256
pixelGlobeSize = pixelTileSize * 2^maxZoomLevel
XPixelsToDegreesRatio = pixelGlobeSize / 360
YPixelsToRadiansRatio = pixelGlobeSize / (2 * PI)
pixelGlobeCenter = [pixelGlobeSize /2, pixelGlobeSize /2]
xDiff = coord[0] - pixelGlobeCenter[0]
yDiff = coord[1] - pixelGlobeCenter[1]
longitude = xDiff / XPixelsToDegreesRatio
latitude = (2 * arctan(e^(yDiff / -YPixelsToRadiansRatio)) - PI / 2) * degreesToRadiansRatio
(edited by The Last Engineer.6492)
Event info :
“location”: “type” : “poly”, " center " : [ xxx , xxx , xxx ] …
Map info :
“map_rect”: [ [ xxx, xxx ], [ xxx, xxx ] ] …
“continent_rect”:[ [ xxx,xxx ],[ xxx , xxx ] ] …Map Event location :
event_center_x = location.center [ 0 ] ;
event_center_y = location.center [ 1 ] ;
percentageX = (event_center_x – map_rect [ 0 ] [ 0 ] ) / (map_rect [ 1 ] [ 0 ] – map_rect [ 0 ] [ 0 ] );
percentageY = 1-(event_center_y – map_rect [ 0 ] [ 1 ] ) / (map_rect [ 1 ] [ 1 ] – map_rect [ 0 ] [ 1 ] );
continentX = (continent_rect [ 0 ] [ 0 ] + (continent_rect [ 1 ] [ 0 ] – continent_rect [ 0 ] [ 0 ] ) * percentageX);
continentY = (continent_rect [ 0 ] [ 1 ] + (continent_rect [ 1 ] [ 1 ] – continent_rect [ 0 ] [ 1 ] ) * percentageY);
// the coords for the event
event_coords = FromPixelToCoords([continentX, continentY], map.GetMaxZoom()); // map.GetMaxZoom() is set to 7 for Gw2 Map
Thank you, this was exactly what I was looking for
you can do this as below :
longitude = (coord[0] - 16384) / (32768 / 360); latitude = 2 * arctan( e ^ ( ( coord[1] - 16384 ) / -(32768 / (2 * PI)) ) - PI / 2 ) * (180/PI);
Thanks so much for this, i got it working now – the hint about the map size was essential, but a few missing brackets made me crazy…
http://gw2.chillerlan.net/examples/gw2maps-gmaps-simple.html
so it looks like this now:
function fromPointToLatLng(point, max_zoom) {
var size = (1 << max_zoom) * 256,
lat = (2 * Math.atan(Math.exp((point.y - size/2) / -(size/(2 * Math.PI)))) - (Math.PI / 2)) * (180/Math.PI),
lng = (point.x - size/2) * (360/size);
return new google.maps.LatLng(lat, lng);
}
and LatLng to pixel conversion:
function fromLatLngToPoint(ll, max_zoom){
var point = new google.maps.Point(0, 0),
origin = new google.maps.Point(128, 128),
tiles = 1 << max_zoom,
bound = function(value, min, max){
if (min != null) value = Math.max(value, min);
if (max != null) value = Math.min(value, max);
return value;
},
sin_y = bound(Math.sin(ll.lat() * (Math.PI / 180)), -0.9999, 0.9999);
point.x = origin.x + ll.lng() * (256 / 360);
point.y = origin.y + 0.5 * Math.log((1 + sin_y) / (1 - sin_y)) * -(256 / (2 * Math.PI));
return new google.maps.Point(Math.floor(point.x * tiles), Math.floor(point.y * tiles));
}
(edited by smiley.1438)
I guess I am not fully understanding what map_rect and continent_rect are in the map_floor API.
In my mind, content_rect should always be [[0,0],[32768,32768]], but for Queensdale it is [[9856,11648],[13440,14080]].
I know I am looking at this from the wrong perspective, but I need to understand how and why. If anyone has any guidance I would really appreciate it.
continent_rect (and clamped_view) are the map bounds corners in absolute pixels within the worldmap (usually given by the texture_dims), where x/y 0 is the top left corner.
see that part of my parser for the use of that.
For the map_rect see a few postings above
(edited by smiley.1438)
I made a silly picture
All events are within map_rect of their respective map.
All maps are within continent_rect of their continent.
To figure out where something is on the continent you need to know their place within map_rect on the map, then fit map_rect inside continent_rect on the continent.
To figure out where something is on the continent you need to know their place within map_rect on the map, then fit map_rect inside continent_rect on the continent.
In fact we wouldn’t need to mess around with the map_rect at all if the data was consistent. Why can’t the events in the event_details.json have absolute coordinates like the POIs ’n stuff in the floor.json?
(i have currently ~400 extra lines of code just to clean up the inconsitent mess of the API o.O)
(edited by smiley.1438)
Thanks, I finally got it! My math was working at some point, but the inverted nature of the Y axis was causing me troubles as well and I just couldn’t understand why it was so close, but still wrong. By now I know by heart where on the map Barthol’s event starts and my little pointer was not in the sweet spot. Then I did the (1-delta) and voila!! That is exactly where Barthol sits waiting for you go talk to him!
Thank you very much, I really appreciate the time you took to explain what continent_rect meant. I just never figured out that continent_rect and map_rect were exactly the same rectangle within different coordinate systems.
Oh, and I agree that the lack of consistency in the coordinate systems is puzzling, especially given the fact that the exact same API where you get map_rect and continent_rect you also get coordinates already in their absolute representation for the continent, while the event details API has coordinates which depend on rectangles which are not even present there.
Anyway, it is what it is and we just have to know how it works. Thanks for all the clarification.
SICK KITTEN!
http://gw2.chillerlan.net/examples/gw2maps-jquery.html
:D
IAll condensed in one ugly block of code so I don’t have to look at it so much
Ugly function is ugly:
function recalcEventCoords(cr, mr, p){ // continent_rect, map_rect, point
return [(cr[0][0]+(cr[1][0]-cr[0][0])*(p[0]-mr[0][0])/(mr[1][0]-mr[0][0])),(cr[0][1]+(cr[1][1]-cr[0][1])*(1-(p[1]-mr[0][1])/(mr[1][1]-mr[0][1])))]
}
(edited by smiley.1438)
Hi all,
- positionPoint is x,y event center location.
- positionToPixelRatio : 1/24
- Mumble : use left handed coordinate system, you have to use the x,z coordinates (not x,y). The x,y,z coords are in meter so you have to convert it to inches knowing that 1 meter = 39.3700787 inches.
According to Cliff :
Some implementation notes:
The coordinate system used by mumble is slightly different than the game. GW2 uses inches (don’t ask), but mumble uses meters. So you’ll need to convert the coordinates back to inches for use with the map API.
The coordinates in inches are : {x*39.3700787, z*39.3700787}. After that, you may apply these expressions below :
(these expressions can be used for mumble and events)
xPixelCoord = ContinentRectangle [ 0 ] [ 0 ] + (positionPoint.X – MapRectangle [ 0 ][ 0 ]) * poistionToPixelRatio
yPixelCoord = ContinentRectangle[ 0 ] [ 1 ] + (MapRectangle [ 1 ] [ 1 ] – positionPoint.Y) * poistionToPixelRatio
LatLng = FromPixelToCoordinate(xPixelCoord , yPixelCoord, maxZoomLevel)
If you need the current map zoom. You have to apply a projection.
You need the continent’s MaxZoom level and you can compute the projection like this :
- DeltaZoom : Continent’s max zoom level – current map Zoom.
- Projection : 2^(DeltaZoom).
- XPixelCoord = XPixelCoord / Projection, YPixelCoord = YPixelCoord / Projection
(edited by The Last Engineer.6492)