I am trying to convert a location to a point on image. I am using fabricjs to draw the map, the map object I made out of an image of the earth. I convert the image to an array, where land is 1 and 0 is water.
My problem is that I cant convert the location to a point properly.
I am using this formula which works, but not for the image I am using.
function getMapCoordsByLatAndLng(latitude, longitude, mapWidth, mapHeight){
var x = (longitude + 180 )* (mapWidth / 360);
var latRad = latitude* Math.PI /180;
var mercN = Math.log(Math.tan(( Math.PI /4)+(latRad/2)));
var y = (mapHeight / 2) - ( mapWidth *mercN/(2 * Math.PI));
return {
x: x,
y: y
};
}
Here is my result for now.
I have used two locations - Los Angeles and Sydney. As you can see the coordinates on the map are not correct.
Here is a fiddle with all the code.
Edit:
I ended up following a suggestion to use equirectangular projection instead of mercator one.
Thus the algorythm for finding the coordinates on the canvas changed.
function getMapCoords(latitude, longitude, mapWidth, mapHeight){
return {
x: parseInt((longitude + 180.0) * (mapWidth / 360.0)),
y: parseInt(((latitude * -1.0) + 90.0) * (mapHeight / 180.0))
}
}
I have updated my code and the result can be found here.
Your map is off and the coordinates for Sydney are plain wrong.
With better coordinates:
Seems image has more than 360 degrees. You need to slice it properly.
Then divide by 360.
Or if you want to use it as it is, you need to add offsets.
Related
I am working on an expo react-native project, in which I am trying to set a compass pointed to a different fixed location (instead of true north). Any tips on how I can achieve this?
Is there a way to change the "true north" to a custom one (giving a latitude and longitude)? Or a way in which I can set a custom location using latitude and longitude, following which I can have my compass pointed to that lat & long which constantly updates (such as that used by Location.watchPositionAsync)?
Any help on this would be greatly appreciated! I have noticed that no one else has asked this question, so I hope that the solution can help others too.
You need to get your location
Then calculate the angle to the desired latitude and then point to the angle
Here is a formula for calculating the angle between two points
function angleFromCoordinate(lat1,lon1,lat2,lon2) {
var p1 = {
x: lat1,
y: lon1
};
var p2 = {
x: lat2,
y: lon2
};
// angle in radians
var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
// angle in degrees
var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
console.log(angleDeg);
return angleDeg;
}
I plan to build an online map for markers (pins) of a game and I don't manage to set the correct latitude of my markers.
Original map is a square of 2048*2048px
Then I got markers (many thousands)
Map coordinates are set with a x, y notation from 0 to 100.
0, 0 is the top left corner and 100, 100 is the bottom right corner of the map.
x=50, y=50 is lat = 0°, lng = 0° (the center of the picture).
To convert from my notation to longitude I use this JS function, it works well :
function longitude(x)
{
var lng = 0
if (x < 50) // Negative Longitude (West)
{
lng = (x - 50) / 50 * 180;
}
else // Positive Longitude (East)
{
lng = (50 - x) / 50 * 180;
}
return lng
}
But for latitude it don't work because those engines use a Mercator projection and me not.
If someone have the correct formula, it would be greatly appreciated :(
Welcome to SO!
If you are using Leaflet, you should specify the map option crs and use L.CRS.Simple:
A simple CRS that maps longitude and latitude into x and y directly. May be used for maps of flat surfaces (e.g. game maps). Note that the y axis should still be inverted (going from bottom to top).
This will avoid the Web Mercator projection, especially the latitude which is a special computation as you figured out (see the linked Wikipedia article for the equation).
Then you are left with correctly mapping your x and y coordinates to your need, especially in respect with your map image.
For instance, assuming you set your map image as:
L.imageOverlay("imageUrl", [[0, 0], [256, 256]]).addTo(map);
(so that it fits the equivalent of 1 tile at zoom level 0)
Then you could have a conversion like:
function longitude(x) {
return x / 100 * 256;
}
function latitude(y) {
return 256 - y / 100 * 256; // Still need to revert y.
}
I have seen some questions with similar titles, but they seem to be referring to x and y pixel coordinates.
I am asking about the actual tile numbers of x and y from Google Maps getTile() function:
To clarify the question...
Given the x, y, and zoom parameters in the getTile() function, how can I find the latitude and longitude bounds of the tile?
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
var x = coord.x,
y = coord.y,
url = "http://mt1.google.com/vt/lyrs=y&x="+x+"&y="+y+"&z="+zoom;
//other stuff
}
The only reason at the moment that I need this is that I want to determine the maximum zoom level at this tile projection. From this link: Maximum Zoom, it states that in order to find the maximum zoom, I will need a latitude and longitude value using getMaxZoomAtLatLng(). So if I can get the bounds, then I can use any latitude and longitude points within the bounds to find my max Zoom.
Alternatives I have thought of were creating an image and checking if the src url had an error (this seems like a terrible idea to me, as I would be making many bad requests just to check if imagery existed).
var img = new Image;
img.onload = function() {/*imagery exists*/ }
img.onerror = function() {/*past maximum zoom*/ }
img.src = url;
EDIT:
After further investigation, I realize that the getMaxZoomAtLatLng() function is using an ajax call which will not fit into my plans. But I still am interested in how to find the latitude and longitude boundaries of a given tile ( that could be useful for other applications ).
Assuming a basic google-map using mercator-projection and a tileSize of 256x256:
The number of tiles on each(x-axis and y-axis) is Math.pow(2,zoom), so on zoom 0 the map is using 1 tile, on zoom 1 4 tiles, on zoom 2 16 tiles and so on.
First calculate the southWest/northeast-points of the tile.
the size of a tile (in points) is 256/Math.pow(2,zoom)
southWest-point:
x = tile.x * tileSizeInPoints
y = (tile.y * tileSizeInPoints) + tileSizeInPoints
northEast-point:
x = (tile.x * tileSizeInPoints) + tileSizeInPoints
y = tile.y * tileSizeInPoints
These points must be translated to LatLngs. When you use a map you may use the method fromLatLngToPoint of the maps projection.
For a custom implementation take a look at https://developers.google.com/maps/documentation/javascript/examples/map-coordinates.
A possible API-independant implementation:
MERCATOR={
fromLatLngToPoint:function(latLng){
var siny = Math.min(Math.max(Math.sin(latLng.lat* (Math.PI / 180)),
-.9999),
.9999);
return {
x: 128 + latLng.lng * (256/360),
y: 128 + 0.5 * Math.log((1 + siny) / (1 - siny)) * -(256 / (2 * Math.PI))
};
},
fromPointToLatLng: function(point){
return {
lat: (2 * Math.atan(Math.exp((point.y - 128) / -(256 / (2 * Math.PI)))) -
Math.PI / 2)/ (Math.PI / 180),
lng: (point.x - 128) / (256 / 360)
};
},
getTileAtLatLng:function(latLng,zoom){
var t=Math.pow(2,zoom),
s=256/t,
p=this.fromLatLngToPoint(latLng);
return {x:Math.floor(p.x/s),y:Math.floor(p.y/s),z:zoom};
},
getTileBounds:function(tile){
tile=this.normalizeTile(tile);
var t=Math.pow(2,tile.z),
s=256/t,
sw={x:tile.x*s,
y:(tile.y*s)+s},
ne={x:tile.x*s+s,
y:(tile.y*s)};
return{sw:this.fromPointToLatLng(sw),
ne:this.fromPointToLatLng(ne)
}
},
normalizeTile:function(tile){
var t=Math.pow(2,tile.z);
tile.x=((tile.x%t)+t)%t;
tile.y=((tile.y%t)+t)%t;
return tile;
}
}
call MERCATOR.getTileBounds() by supplying a single object as argument with the following format:
{
x:tileIndexX,
y:tileIndexY,
z:zoom
}
Demo: http://jsfiddle.net/doktormolle/55Nke/
I think Google maps tiling system is similar to the Bings maps tiling system. The tiles start from the upper left in the lower right and each tile is 256x256:http://msdn.microsoft.com/en-us/library/bb259689.aspx.
Not sure if this entirely helps with the bounds, but to find an easy display of the tile coordinates I went here:
https://developers.google.com/maps/documentation/javascript/examples/map-coordinates
And to typescript on the line:
const chicago = new google.maps.LatLng(-33.76781028848151, 150.73644505329204
);
Change the lat/long to wherever you want... And they have a nice UI that calculates all the changes on zoom.
I need use mercator projection to point the places by latitude and logitude in my svg application.I have serached a lot and i got these links,
http://en.wikipedia.org/wiki/Mercator_projection
Covert latitude/longitude point to a pixels (x,y) on mercator projection
CODE
//this lat and long is for chicago
var latitude = 41.850033; // (φ)
var longitude = -87.65005229999997; // (λ)
var PI = 3.14;
var mapWidth = 750;
var mapHeight = 380;
// get x value
var x = (mapWidth * (180+longitude) / 360) % mapWidth + (mapWidth / 2);
// convert from degrees to radians
var latRad = latitude * PI / 180;
// get y value
var mercN = Math.log(Math.tan((PI / 4) + (latRad / 2)));
var y = (mapHeight / 2) - (mapWidth * mercN / (2 * PI));
I've used this code in my application, but it doesn't work for me.
Please help to get x and y position from the latitude and longitude.
Any Suggestions should be appreciated.
You forgot the top left and bottom right corner of the map and the factor to multiply the x,y coordinates to give the correct map projection. You can use a fixed map coordinate, i.e. a factor or you can compute the bounding box:Convert lat/lon to pixel coordinate? and then compute the world width and height that fits the map's width and height.
I have a lat/long coordinate point and I'm drawing a polygon (hexagon) around it on a Google map. Here's my code to calculate the hexagon coordinates:
for (var i = 0; i < 6; i++) {
x = lat + r * Math.sin(i * 2 * Math.PI / 6);
y = lng + r * Math.cos(i * 2 * Math.PI / 6);
}
This calculates all coordinates in a regular hexagon and I can draw it on the map without a problem if its center is near (0 lat, 0 long). The problem is when I want to draw it far from (0, 0) this gets into an elongated shape. I'm guessing it's because the earth is not flat and Google maps takes that into account. So I probably need to change the radius in my calculation to reflect this, has anyone any idea how it is done?
Examples of various regular polygons far from (0,0)