I have a initial Lat/Lng derive from click event in google maps.
Using that Lat/Lng, I want to be able to construct a rectangle polygon that is 2km by 2km. Since I already have a lat/lng, I attempted to find SE corners of a rectangle - using computeOffset.
var initial_pos = new google.maps.LatLng(lat, lng)
var south = spherical.computeOffset(initial_pos, 2000, 135);
var east = spherical.computeOffset(initial_pos, 2000, 90);
var bounds = new google.maps.LatLngBounds(
initial_pos, south, east
);
var rectangle = new google.maps.Rectangle({
map:map,
bounds: bounds
});
You are right. To draw a rectangle you will need the bounds, which can be derived from two diagonally opposite vertices of the rectangle to be drawn. Let's say you have NW (NorthWest) corner and you are trying to draw a square of side s. You may then find out LatLng of the SE corner, using computeOffset, with distance as s*√2 (in meters) and heading as 135 (degrees).
Following are suggestions on the currently posted source code:
You should calculate a new position only once. Since this position is diagonally opposite, distance should be 2000*1.414. Also, note that the bounds is not initialized with LatLng. They are initialized with four variables. north and south are Lat values. east & west are Lng values. Here are my code change suggestions. Please try them. Please treat this as pseudo code and suite appropriate changes as needed.(Following code is now updated during my edit and should work. Ensure that libraries=geometry is added in the script tag, e.g.
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=API_KEY&libraries=geometry&callback=initGMap">
</script>)
var initial_pos = new google.maps.LatLng(18.39,77.12);
// initialize initial_pos variable based on click event or so
var calculated_pos = google.maps.geometry.spherical.computeOffset(initial_pos, 200*1.414, 135);
var rectangle = new google.maps.Rectangle({
map: map,
bounds:{
north: initial_pos.lat(),
south: calculated_pos.lat(),
west: initial_pos.lng(),
east: calculated_pos.lng()
}
});
Related
I am working on an user interface that shows many pins on a map.
During the development I am randomly generating 1500 map pins just to be placed on the map to test look/feel/performance etc. issues.
The code which does that looks like this:
for (var i = 0; i <= 1500; i += 1) {
$scope.mapPins.push({
latitude: (Math.random() * 2) + 51,
longitude: (Math.random() * 4) + 3,
icon: themeImages[Math.floor(Math.random() * themeImages.length)],
title: 'Sample title',
infoContent: 'Sample content'
});
}
Naturally the area of the pins covered is a rectangle for latitudes 51-53 and longitudes 3-7. For those who are wondering where it is, it is the area roughly around Netherlands.
Now, there's a little problem that the Netherlands is not a rectangular area and a lot of these coordinates fall over the sea and I would like my coordinates to be only on the land.
Is there a witty mathematical way how I can pool coordinates from a non-rectangular area?
Of course I could make a google.maps polygon object that covers a nonrectangular shape and then via google api test every random generated pin whether it falls within the bounds of this shape etc, but that would be an overkill for UI design phase. Basically my question is whether there is a neat mathematical trick that would allow me to randomly generate coordinates from a non-rectangular space.
Leave your code as it is, the rectangle is the bounding box over your area of interest.
Then add a line
if (isPointInpolygon(polygon, longitudeOrX, latitudeOrY) {
// use this location
}
now you only need to search for a point in polygon function, which is easy to find.
you can directly use the coordinates in (long, lat) order, longitude is related to x coordinate, lat to y.
The polygon has to be filled with the coordinates of the country not insode the water.
If you have islands, then maybe you need multiple such polygons, then iterate over all.
Not to be a stickler but you're actually generating 1501 map pins :)
It is very unlikely that you'll find a simpler solution than using a simple pointinpolygon check.
Use the Google Maps Drawing library (https://developers.google.com/maps/documentation/javascript/drawing#using_the_library) to draw a polygon around the boundary of the Netherlands and save it however you want (e.g., in database, or just copy the string that defines the boundary's coordinates).
Then in your script above, define the google maps polygon (similar to what is done here in the official docs: https://developers.google.com/maps/documentation/javascript/shapes#polygons), then use the containsLocation method in the Google Maps Geometry library (https://developers.google.com/maps/documentation/javascript/examples/poly-containsLocation) to check if your random map pins lie within the boundaries of the Netherlands before adding them to the map.
For example:
var netherlandsCoords = [
// comma-separated list of coordinates defining the Netherlands boundary
];
var netherlandsBoundary = new google.maps.Polygon({
path: netherlandsCoords
});
for (var i = 0; i <= 1500; i += 1) {
var lat = (Math.random() * 2) + 51;
var lng = (Math.random() * 4) + 3;
var latlng = new google.maps.LatLng(lat, lng);
if (google.maps.geometry.poly.containsLocation(latlng, netherlandsBoundary)) {
$scope.mapPins.push({
latitude: lat,
longitude: lng,
icon: themeImages[Math.floor(Math.random() * themeImages.length)],
title: 'Sample title',
infoContent: 'Sample content'
});
}
}
I am trying to request an image from the Google Static Maps API with the borders of the map specified by a pair of latitude and longitude coordinates. I've tried centering on the center of the two coordinates, but there doesn't seem to be any parameter for doing this with the Static API. Does anyone know how to do this?
Note: this is for a desktop application, and I am not using the Javascript API.
The thing is that you cannot base the request on the map's corners because 1. zoom levels are discrete values and 2. the amount of latitude that a pixel represents varies with latitude. So, to display 2 degrees you'll need a given map height near the equator and a different height, (greater), near the poles. Are you willing to display maps of different heights in order to fit always 2 degrees?
If so, you can use the MercatorProjection object from my other post, and use the following function to calculate the necessary map size:
<script src="MercatorProjection.js"></script>
function getMapSize(center,zoom){
var proj = new MercatorProjection();
var scale = Math.pow(2,zoom);
var centerPx = proj.fromLatLngToPoint(center);
var SW = new google.maps.LatLng(center.lat()-1,center.lng()-1);
var southzWestPx = proj.fromLatLngToPoint(SW);
var NE = new google.maps.LatLng(center.lat()+1,center.lng()+1);
var northEastPx = proj.fromLatLngToPoint(NE);
// Then you can calculate the necessary width and height of the map:
var mapWidth = Math.round((northEastPx.x - southzWestPx.x) * scale);
var mapHeight = Math.round((southzWestPx.y - northEastPx.y) * scale);
}
With center = new google.maps.LatLng(49.141404, -121.960988) and zoom = 7 you get that you need a map of (W x H) 182 x 278 pixels in order to display 2 x 2 degrees.
I am reading this: http://www.panoramio.com/api/widget/api.html#photo-widget to build a JavaScript photo widget.
Under Request -> request object table, it is written:
name: rect
example value: {'sw': {'lat': -30, 'lng': 10.5}, 'ne': {'lat': 50.5, 'lng': 30}}
meaning: This option is only valid for requests where you do not use the ids option. It indicates that only photos that are in a certain area are to be shown. The area is given as a latitude-longitude rectangle, with sw at the south-west corner and ne at the north-east corner. Each corner has a lat field for the latitude, in degrees, and a lng field for the longitude, in degrees. Northern latitudes and eastern longitudes are positive, and southern latitudes and western longitudes are negative. Note that the south-west corner may be more "eastern" than the north-east corner if the selected rectangle crosses the 180° meridian
But usually we are only given one latitude point, and one longitude point.
What kind of expressions should I write to build the four points as stated above, to cover the pictures around the area given two points I have in hand?
For example, I have in Paris:
lat: 48.8566667
lng: 2.3509871
I want to cover pictures around it 10km rectangle.
Thanks.
Here's the answer I got from Panoramio Forum by QuentinUK.
Can't do a 10km distance because this implies a circular region. It can only do rectangular.
So you might as well approximate (best is use Vincenty's formulae) and calculate an angle +/- around the point.
function requestAroundLatLong(lat,lng,km){
// angle per km = 360 / (2 * pi * 6378) = 0.0089833458
var angle=km* 0.0089833458;
var myRequest = new panoramio.PhotoRequest({
'rect': {'sw': {'lat': lat-angle, 'lng': lng-angle}, 'ne': {'lat': lat+angle, 'lng': lng+angle}}
});
return myRequest;
}
var widget = new panoramio.PhotoWidget('wapiblock', requestAroundLatLong(48.8566667, 2.3509871,10), myOptions);
If you want to use REST api:
var Lattitude = "48.8566667";
var Longitude = "2.3509871";
var angle = km * 0.0089833458;
testo.Text = "<script src=\"http://www.panoramio.com/map/get_panoramas.php?order=popularity&set=full&from=0&to=14&minx=" + clon - angle + "&miny=" + clat - angle + "&maxx=" + clon + angle + "&maxy=" + clat + angle + "&callback=mostrareFotos&size=medium\" type=\"text/javascript\"></script>";
I have a problem with creating an overlay with a polygon that contains
multiple polylines.
I want to create a polygon with holes cut out for certain countries (to show
which areas are off limits). I do this by creating a polygone with multiple
polylines.
The first polyline was created to cover the entire visible area of the map.
i started off with this:
To get around only spanning one region-180/180
var outer:Array = [ new LatLng(90, -180),
new LatLng(90, 180),
new LatLng(-90, 180),
new LatLng(-90, -180),
new LatLng(90, -180)]
donut = new Polygon([],
new PolygonOptions({
strokeStyle: new StrokeStyle({
thickness: 0}),
fillStyle: new FillStyle({
color: 0x000000,
alpha: 0.5})
}));
donut.setPolyline(0, outer)
map.addOverlay(donut);
Obviously this has a problem with only spanning one lot of lat/lng. And when
zoomed out, this doesnt work. To get around this i tried getting the bounds
of the map, toSpan() and getNorth(),getSouth() and so on. These didnt return
a true span of the visible map - as it maxed out at 180/360.
My solution was to use fromViewportToLatLng() of the pixel points of the
map, and set the opt_nowrap to 'true'
var pnw:LatLng = map.fromViewportToLatLng(new Point(0, 0), true)
var pse:LatLng = map.fromViewportToLatLng(new Point(map.width, map.height),
true)
This produced results similar to this
Lat Lng North West (89.77386689378173, -614.3294000000001)
LatLng South East (-89.07253945829217, 370.0455999999999)
From here i can then correctly set the polyline (on map move and zoom
events) to cover the entire map, no matter how many spans of longitude
occur:
outer = [
new LatLng(pnw.lat(), pnw.lng(), true),
new LatLng(pnw.lat(), pse.lng(), true),
new LatLng(pse.lat(), pse.lng(), true),
new LatLng(pse.lat(), pnw.lng(), true),
new LatLng(pnw.lat(), pnw.lng(), true)
]
donut.setPolyline(0, outer)
*So far so good. *
Now, i want to add the donut holes to my polygon, again adding polylines to
the donut polygon.
private var australia:Array = [
new LatLng(-9.7716, 143.0241),
new LatLng(-23.4610, 158.1852),
new LatLng(-45.1338, 147.1549),
new LatLng(-35.2615, 111.5153),
new LatLng(-20.6921, 113.0094),
new LatLng(-10.0746, 130.3239),
new LatLng(-9.7716, 143.0241)
]
private var nz:Array = [
new LatLng(-33.5951, 165.8254),
new LatLng(-33.5951, 179.7341),
new LatLng(-48.3845, 179.7341),
new LatLng(-48.3845, 165.8254),
new LatLng(-33.5951, 165.8254)
]
private var hawaii:Array = [
new LatLng(21.8000, -160.4347),
new LatLng(22.5477, -159.7975),
new LatLng(21.4067, -156.3533),
new LatLng(19.5336, -154.4197),
new LatLng(18.6511, -155.6392),
new LatLng(20.6633, -157.8639),
new LatLng(21.8000, -160.4347)
]
donut.setPolyline(1, hawaii)
donut.setPolyline(2, nz)
donut.setPolyline(3, australia)
The problem lies when the meridian line is visible in the map viewport. This
problem is more evident when zommed in, as the donut hole polylines jump
from the visible viewport to the other side of a lat long span.
Sometimes the outer array doesnt even correctly render, causing the donut
polygon to essentialy invert (polygons over the countries, rather than
cutouts)
I realise this is a tough one to visualise. I have attached the .as + .fla
file in case anyone wants to test it out.
http://www.digital.leskiwis.com/maps/MapTest.zip
So you're trying to make a big polygon with holes cut out for Australia, nz, Hawaii,...? Your code for adding the polylines seems wrong to me. I'd start with the big square:
var outer:Array = [ new LatLng(90, -180),
new LatLng(90, 180),
new LatLng(-90, 180),
new LatLng(-90, -180),
new LatLng(90, -180)]
donut = new Polygon([outer],
new PolygonOptions({
strokeStyle: new StrokeStyle({
thickness: 0}),
fillStyle: new FillStyle({
color: 0x000000,
alpha: 0.5})
}));
Then add your holes
//define au, nz, hi
//...
//the 0th polyline is already the outer edge...
donut.setPolyline(1, hi);
donut.setPolyline(2, nz);
donut.setPolyline(3, au);
Now you dounut is a big rectangle with 3 holes.
Then add it to the map:
map.addOverlay(donut);
I've worked with lots of polygons that crossed hemispheres and meridians in Google Maps before, you don't have to mess with the viewport or zoom region or anything like that. As long as you're defining the polygon the way you think you are, GM will draw it correctly in any bounding rect (even if you are zoomed in so far that no edge of the polygon is visible).
The other thing I see is that the giant polygon you're making to cover the whole world is a little ambiguous: For example 90,-180 and 90,180 are the same point (the north pole) a line connecting those coordinates would have 0 length. Doing stuff at the poles is kinda effed in Mercator. Any possibility of cutting it off a 89° N? I think that would make your outer polygon more happy.
I have divided the my google map display in to numbers of parts, Now I want of find it out if any markers are positioned inside a/any particulate cell.
Any Help ?
Farther Explained :
I have got the map bounds by
map.getBounds();
method and then farther divide it into numbers of sub-bounds.
also I have putted markers as
map.addOverlay(markerObject);
Now , I want find if of the cells (which I got by dividing the map by bounds) is containing any markers or not .
I have divide the entire map bounds into numbers of sub bounds
So keep all markers in array. Each marker has a method called get_position( ). After you have finished division of map bound into small sub bounds, you just need to iterate over the sub bounds and check whenever the marker within it.
PS. Also take a look on it, in some cases could be useful.
Suppose you on sub bound cell:
var sub_bounds = new Array();
// here you've pushed into an array the sub bounds
for ( var i = 0; i<sub_bounds.length; ++i)
{
for ( var j = 0; j < markers.length; ++j)
{
var lat = markers[j].get_position( ).lat;
var lng = markers[j].get_position( ).lng;
if ( sub_bounds[i].sw.lat<lat && lat<sub_bounds[i].ne.lat &&
sub_bounds[i].sw.lng<lng && lng<sub_bounds[i].ne.lng)
// marker within cell, do whatever you need to do
}
}
Here is an alternative to the above solution without re-iteration:
First - how big are your sub_bounds? Say 10 latitude and longitude degrees each.
Second - The position of the marker is (floor(marker.lat / 10), floor(marker.lng / 10))
Third - Each marker is added to the map and dropped in a bucket for that subdomain.
so (40, -78) would lie in bucket (4,7) i.e. bucket["4~7"]
Correction: would lie in bucket (4,-7) i.e. bucket["4~-7"]
which would contain all markers between 40 and 50 lat and -70 and -80 lng.
You can use GLatLngBounds as the object that holds all these markers in each bucket, which would give you a good set of methods to use, such as calculating center of the bucket depending on the markers currently in it.
Probably the best solution is given here: how to find out whether a point is inside a polygone:
How to detect that a point is inside a Polygon using Google Maps?