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)
Related
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.
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 am writing a python script that will map some points and curved on a map based on data that I receive. I am attempting to get the center coordinates of a arc/circle using any of the data that I receive below. I am having a hard time wrapping my brain around it.
Point1 Lat and Lon
Point2 Lat and Lon
Starting Angle
Ending Angle
Radius Of the Circle
I do realize that I don't need all of this data to solve this.
I also have a flag that tells me if its a left or right hand turn.
Would getting the x and y cords be possible to calculate with the information I am receiving above.
I already have a function that is ran in javascript to draw the arc.
function drawArc(center, initialBearing, finalBearing, radius) {{
var d2r = Math.PI / 180; // degrees to radians
var r2d = 180 / Math.PI; // radians to degrees
var points = 32;
// find the raidus in lat/lon
var rlat = (radius / EarthRadiusMeters) * r2d;
var rlng = rlat / Math.cos(center.lat() * d2r);
var extp = new Array();
if (initialBearing > finalBearing) finalBearing += 360;
var deltaBearing = finalBearing - initialBearing;
deltaBearing = deltaBearing/points;
for (var i=0; (i < points+1); i++)
{{
extp.push(center.DestinationPoint(initialBearing + i*deltaBearing, radius));
bounds.extend(extp[extp.length-1]);
}}
return extp;
}}
I cant for the life of me find a good way to get the x and y coordinates of the center of the circle.
Given a point (Px, Py), that point's starting angle (Pa), and the radius (r), you can calculate the center (Cx, Cy) like so:
Cx = Px - r * cos(Pa)
Cy = Py - r * sin(Pa)
For example, if you want the center of the arc with a point at (1, 2) which is at Pi/3 radians (60 degrees) on a circle with radius 3, you can calculate the center like so:
Cx = 1 - 3 * cos(Pi/4) = 1 - 3 * 0.5 = 1 - 1.5 = -0.5
Cy = 1 - 3 * sin(Pi/4) = 1 - 3 * sqrt(2)/2 = -1.1213
C = (-0.5, -1.1213)
There are similar formulas you could use given other information as well. For example, you could calculate the center given a "first" and "second" point, the radius, and the "turn direction" (left or right). It is fairly simple trigonometry to derive these equations.
AFAIK, center point doesn't depend on the parameters of the circle. It's XY coordinates on the canvas. It can be anywhere or oftener in the middle of the picture to look nicer.
Look here:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import cairo, math
radius=100
starting_angle = math.radians(210) # angle in radians
ending_angle = math.radians(330)
WIDTH, HEIGHT = radius*2+20, radius*2+20 # Canvas size
x=WIDTH/2 # X position
y=HEIGHT/2 # Y position
surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
context = cairo.Context (surface)
# Background Neutral Gray ----------
context.set_source_rgb(0.25, 0.25, 0.25)
context.rectangle(0, 0, WIDTH, HEIGHT)
context.fill()
# Red Sector -------------------
context.set_source_rgb(1, 0, 0) # rgb color red
context.arc(x, y, radius, starting_angle, ending_angle)
context.line_to (x, y)
context.fill()
surface.write_to_png ("img.png") # Output to PNG
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.
Is there a way to translate into javascript a piece of code that will allow me to show map pins around a point taking in consideration a radius ?
var data=[
{long:3,lat:2},
{long:5,lat:2},
{long:2,lat:3}
];
aCoord={long:1,lat:2};
for(var i=0;i<data.length;i++){
if (data[i] is 30 kms far from aCoord)
myMap.addPin(data[i]);
}
myMap.autozoom();
Thank you,
Regards
I came up with this example so you have an idea on how to calculate the points. You'll need to figure out how to do any necessary conversions for lat/lon.
/**
* Returns coordinates for N points around a circle with a given radius from
* the center.
*
* center: array [x, y]
* radius: int
* num_points: int
*/
function get_points_on_circle(center, radius, num_points) {
if (!num_points) num_points = 10;
var interval = Math.PI * 2 / num_points;
points = [];
i = -1;
while (++i < num_points) {
var theta = interval * i,
point = [Math.cos(theta) * radius + center[0], Math.sin(theta) * radius + center[1]];
points.push(point);
}
return points;
}
// Sample usage
var center = [250, 250],
radius = 100,
num_points = 10;
var points = get_points_on_circle(center, radius, num_points);
Test it out (uses Raphael for plotting)
If you are interested in learning a little about the logic:
A radian is a unit of measure for angles. There are a total of 2*PI radians in a circle. Using that fact, you can calculate the angle interval of any number of points on a circle by performing 2*PI/num_points.
When you know the angle interval, you can calculate the angle (theta) of a point on a circle. Once you have theta (the angle), you have polar coordinates (radius,angle). For that to be of any use to us in this problem, you need to convert the polar coordinates into Cartesian coordinates (x,y). You can do that by using the following formulas:
x = cos(theta) * radius
y = sin(theta) * radius
That's pretty much it in a nutshell.