I need to create pushpins for the below input.
var Countries = ["Austria", "Brazil", "India", "Germany", "USA", "Malaysia"];
Microsoft.Maps.SpatialDataService.GeoDataAPIManager.getBoundary(Countries, geoDataRequestOptions, map,
(data) => {
var value = data.location;
if (data.results.length > 0 && data.results[0].Polygons !== null) {
var polygons = data.results[0].Polygons;
var dataBounds = Microsoft.Maps.LocationRect.fromShapes(data.results[0].Polygons);
var loc = new Microsoft.Maps.Location(dataBounds.center.latitude, dataBounds.center.longitude);
var pin = new Microsoft.Maps.Pushpin(loc, {
icon: svgIcon,
anchor: new Microsoft.Maps.Point(20 / 2, 20 / 2)
});
map.entities.push(pin);
locs.push(pin);
map.setView({ bounds: Microsoft.Maps.LocationRect.fromLocations(locs), padding: 80 });
}
});
}, 3000);
I am using GeoDataAPIManager to get the boundary polygons and get the center of the polygon to generate a pushpin. But when loading countries like Malaysia or USA, the pushpins are placed in the sea, as the getboundary() returns multiple polygons and getting the center of the polygon returns the center between the two boundaries which results in the pushpin placed in the sea.
Let me know if there is any alternate way to create the pushpin or to get the center of the polygon.
I already tried the spatial.Math module to get the center.
This is a common occurrence when working with polygons as their shape can be such that their center is not within the actually geometry. There are several different ways to do this.
Method 1: This method will fall back to the nearest point to the calculated center that's on the edge of the polygon.
Calculate centroid/center either using math library or rough center by using bounding box center.
Check to see if the point intersects the polygon, if not, calculate the closest point on the edge of the polygon (shortest distance), then use that point as your center.
Method 2: Focus just on the largest polygon.
If the geometry is a MultiPolygon, calculate the area and grab the polygon with the largest area. For the USA, this would give you the polygon for the mainland which is likely desired.
Try method 1, using just the largest polygon.
Method 3: Attempt to calculate a visual center using external library.
Convert the polygon to GeoJSON using the GeoJSON module in Bing Maps: https://www.bing.com/api/maps/sdkrelease/mapcontrol/isdk/geojsonwritetogeojson
Pass the geojson geometry into this library to calculate the visual center. https://github.com/mapbox/polylabel
Related
In the Google Maps API it allows you to set the bounds of a map given a list of coordinates. That's awesome. My issue is that it gives a little bit of breathing room on the sides. I'm trying to get the bounding box I'm looking at to be barely containing the bounds.
For example, I want to view California so I set the bounds to be the Northeast and Southwest corners. Instead of showing just California though, I get all of Oregon and half of Mexico.
Here's what I'm currently doing:
var geo_region = {
northeast: {
lat: 42.0095169
lng: -114.131211
}
southwest: {
lat: 32.528832
lng: -124.482003
}
}
var map_bounds = new google.maps.LatLngBounds();
map_bounds.extend(new google.maps.LatLng(geo_region.northeast.lat, geo_region.northeast.lng));
map_bounds.extend(new google.maps.LatLng(geo_region.southwest.lat, geo_region.southwest.lng));
var plot_map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
plot_map.fitBounds(map_bounds);
EDIT:
A clearer example might be Wyoming since it's such a nice rectangle. If my map dimensions are the same ratio as Wyoming, I only want it to show me Wyoming.
EDIT:
Somebody suggested that I offset the bounds manually so I grabbed some data on the offsets that Google is using but I can't figure out what their formula is for deciding those offsets so I'm a long ways away from being able to do that. I even used the viewport coordinates from Google's Geocoding API but those didn't help much either.
Here's my data: https://docs.google.com/a/dovidev.com/spreadsheets/d/1HZLdDt5uiGwEtY0NbX0pfkmYVuUDndptm_-kzq0vh_w/edit?usp=sharing
This cannot be done EXACTLY because of the way google's zoom level's work. Google sets the bounds of the area but zooms in as closely as possible without cutting anything out. Because the zoom levels are incremental and their increments are so large, this often means that you'll end up with a lot of extra space.
When I tried to zoom in even once from what I thought was grossly oversized, I found that parts of the bounds had been cut off.
And thus we see that Google is already getting it as tight as it can be.
By using the Bezier curve polyline draw function provided by nicoabie I was able to draw a curved line from one point on the map to another. The problem is that this function does not take in to account the fact that when a point is past the maximum coordinate mark it is not necessarily on the other side of the map, since it wraps around.
For example, drawing a curved line from Seattle to Tokyo. A regular polyline would go across the Pacific ocean, but the the curved line draws east across the whole globe.
geodesic: true does not work in this case since the line must have a consistent curvature.
My question is: can a consistently curved line be drawn that takes in to account map wrapping?
Use the option third "nowrap" argument of the google.maps.LatLng class to force all the relevant points to have the same sign (set it to true, it defaults to false).
gmarkers[10].setPosition(new google.maps.LatLng(35.689488,139.69170)); // Tokyo
gmarkers[0].setPosition(new google.maps.LatLng(47.60621,(360-122.332071),true)); // Seattle
boundsCenter.setPosition(new google.maps.LatLng(36.096756,(360-178.986565),true)); // control point 1
gmarkers[6].setPosition(new google.maps.LatLng(48.511996,180)); // control point 2
var curvedLine = new GmapsCubicBezier(gmarkers[0].getPosition().lat(), gmarkers[0].getPosition().lng(), boundsCenter.getPosition().lat(), boundsCenter.getPosition().lng(), gmarkers[6].getPosition().lat(), gmarkers[6].getPosition().lng(), gmarkers[10].getPosition().lat(), gmarkers[10].getPosition().lng(), 0.01, map);
working fiddle
I know the center coordinates and an array of all coordinates of a polygon.
How can I find out which coordinate is the furthest coordinate for the center point with Javascript?
Center of bounds:
lat: -13.647141573542923lng: 109.75651876851946
Coordinates of the 4 polygon paths:
"lat:-9.10209673872643 , lng: 108.10546875"
"lat:-16.97274101999901 , lng: 91.58203125"
"lat:-17.644022027872722 , lng: 120.234375"
"lat:-8.407168163601074 , lng: 120.41015625"
The canonical way of doing things:
Figure out how to calculate distances with longitutdes/latitudes. A quick Google search, for example, brings up this.
Iterate over all points p_i and calculate the distance d_i to the center point.
The point p_k with d_k = max_j d_j will be the point you are looking for.
For distance calculation keep in mind that you can save yourself any operation that won't change the information "further away than", i.e. in euclidic coordinates you could save yourself taking the square root. Also multiplications by any constant can be omitted for this (as long as you don't need to actually know the distance, but only the information which point is the furthest away).
I have markers dotted around a map, and a radius (circle overlay) on a marker marking your location (which changes every time you move).
Is there any way I can check to see if the other markers come inside the circle?
UPDATE
I got around this by looping through each other marker, and using the geometry library calculating the distance between your marker and the other marker and then a simple if statement to see if it's less than 100 meters.
function checkAllChests() {
var Current = 0;
$.each(treasureArray, function() {
//var thisLocation = treasureArray[Current].getPosition();
var distanceBetween = Math.ceil(google.maps.geometry.spherical.computeDistanceBetween(treasureArray[Current].getPosition(), marker_me.getPosition()));
if(distanceBetween < 100) {
alert('CAN OPEN THIS CHEST');
}
Current++;
});
}
I'd like to note that the above code uses jQuery, so if you aren't using jQuery it won't work.
Here's a way to add a contains method to the google.maps.Circle class. It first uses the bounding box to exclude a point if it's not even in the bounding box. If it is in the bounding box, then it compares the distance from the point to the center with the radius, and returns true only if the distance is shorter than the radius.
Once you add the javascript below, you can call the contains() method on your circle object.
google.maps.Circle.prototype.contains = function(latLng) {
return this.getBounds().contains(latLng) && google.maps.geometry.spherical.computeDistanceBetween(this.getCenter(), latLng) <= this.getRadius();
}
I have polyline in my map. I want to know the pixel (screen) xy-coordinates, when user clicks the polyline. Click event only returns the LatLng object, so does anyone have a clue how to get the pixel coordinates from latLng?
I would appreciate very much if someone could help me!
If you have the LatLng object, you can use the google map projection object to transform it into tile coordinates and then into pixel coordinates:
For the docs on the projection class:
https://developers.google.com/maps/documentation/javascript/reference#Projection
Google's example explaining how to transform a LatLng into a pixel coordinate:
https://developers.google.com/maps/documentation/javascript/examples/map-coordinates?csw=1
There's one catch. The above will give you the pixel coordinates inside google's map div (which you may want depending on your needs). If you want the pixels relative to the top left corner of the screen, there's one more step. You need to do the same projection on the the viewport's top left corner and subtract the two. This will give you the pixel coordinates of the LatLng point.
The code I finally used looked like this (note that "latLng" is an input):
var numTiles = 1 << map.getZoom();
var projection = map.getProjection();
var worldCoordinate = projection.fromLatLngToPoint(latLng);
var pixelCoordinate = new google.maps.Point(
worldCoordinate.x * numTiles,
worldCoordinate.y * numTiles);
var topLeft = new google.maps.LatLng(
map.getBounds().getNorthEast().lat(),
map.getBounds().getSouthWest().lng()
);
var topLeftWorldCoordinate = projection.fromLatLngToPoint(topLeft);
var topLeftPixelCoordinate = new google.maps.Point(
topLeftWorldCoordinate.x * numTiles,
topLeftWorldCoordinate.y * numTiles);
return new google.maps.Point(
pixelCoordinate.x - topLeftPixelCoordinate.x,
pixelCoordinate.y - topLeftPixelCoordinate.y
)