Trying to make the similar effect on my Googlemaps map.
This is using Ionic Native Google Maps plugin.
I currently have the following code.
Points are used to create an overlaying polygon across the whole map, and then I am using the drawCircle function to draw a circle by adding lat / lng points to the array extp.push({lat: ey,lng: ex});
points = [
{lat: 85,lng: 90},
{lat: 85,lng: 0.1},
{lat: 85,lng: -90},
{lat: 85,lng: -179.9},
{lat: 0,lng: -179.9},
{lat: -85,lng: -179.9},
{lat: -85,lng: -90},
{lat: -85,lng: 0.1},
{lat: -85,lng: 90},
{lat: -85,lng: 179.9},
{lat: 0,lng: 179.9},
{lat: 85,lng: 179.9} ];
drawCircle(point, radius, dir) {
let lat;
let lng;
var d2r = Math.PI / 180; // degrees to radians
var r2d = 180 / Math.PI; // radians to degrees
var earthsradius = 3963; // 3963 is the radius of the earth in miles or 6371 in km
var points = 32;
// find the raidus in lat/lon
var rlat = (radius / earthsradius) * r2d;
var rlng = rlat / Math.cos(point.lat() * d2r);
var extp = new Array();
if (dir==1) {var start=0;var end=points+1} // one extra here makes sure we connect the ends
else {var start=points+1;var end=0}
for (var i=start; (dir==1 ? i < end : i > end); i=i+dir) {
var theta = Math.PI * (i / (points/2));
let ey = point.lng() + (rlng * Math.cos(theta)); // center a + radius x * cos(theta)
let ex = point.lat() + (rlat * Math.sin(theta)); // center b + radius y * sin(theta)
extp.push({lat: ey,lng: ex});
}
return extp;
}
Loading the map here
this.map.on(GoogleMapsEvent.MAP_READY).subscribe(() => {
console.log('Map is ready!');
this.geolocation.getCurrentPosition({enableHighAccuracy: true}).then((resp) => {
console.log(resp.coords.latitude);
console.log(resp.coords.longitude);
this.myLat = resp.coords.latitude;
this.myLong = resp.coords.longitude;
let loc: LatLng;
loc = new LatLng (resp.coords.latitude, resp.coords.longitude);
this.map.addPolygon({
'points': this.points,
'strokeColor': "blue",
'holes': this.drawCircle(loc,10,-1), //when adding this I lose the overlay and the hole is not drawn. When I remove it, it starts to work again but without a hole.
'strokeWidth': 4,
'fillColor': "#222222"
});
this.map.moveCamera({
'target': loc,
'zoom': 14
});
this.map.addMarker({
'position': loc,
'title': "Hello GoogleMap for Cordova!",
'icon' : 'https://image.flaticon.com/icons/svg/147/147144.svg'
});
}).catch((error) => {
console.log('Error getting location', error);
});
});
you can make hole by using ctx.clip() function.
1.make a canvas with full width,height.
2.fill canvas with "argb(100,255,0,0)".
3.use arc() and clip() to make a hole.
4.set strokeStyle to "argb(255,255,0,0)".
5.use arc() and stroke() to make red outline.
this is how to make a hole.
Related
I have plotted few markers and a polygon objects on Here Map.
I want to know the distance between the polygon and marker. Marker that is very nearer to polygon is what I want to figure out.
Here map has a distance function, but its only working to calculate distance between 2 markers.
Here is the function that I used to calculate distance PaohaIsland.getGeometry().distance(yosmitePark.getGeometry()) Where PaohaIsland is marker Object and yosmitePark is polygon object
var map;
function loadMap(){
platform = new H.service.Platform({
'apikey': HEREMAP_KEY
});
// Obtain the default map types from the platform object:
var defaultLayers = platform.createDefaultLayers();
// Instantiate (and display) a map object:
map = new H.Map(
document.getElementById('mapContainer'),
defaultLayers.vector.normal.map,
{
center: { lat: 37.278419, lng: -119.674072,
pixelRatio: window.devicePixelRatio || 1 },
zoom: 8
}
);
// Enable the event system on the map instance:
var mapEvents = new H.mapevents.MapEvents(map);
var behavior = new H.mapevents.Behavior(mapEvents);
behavior.enable(H.mapevents.Behavior.WHEELZOOM);
}
function addPolygonToMap() {
var lineString2 = new H.geo.LineString();
lineString2.pushPoint({lat:37.278419,lng:-119.674072});
lineString2.pushPoint({lat:37.335224,lng:-119.30603});
lineString2.pushPoint({lat:37.529331,lng:-119.198914});
lineString2.pushPoint({lat:37.522789,lng:-118.99292});
lineString2.pushPoint({lat:37.627281,lng:-118.87207});
lineString2.pushPoint({lat:37.80978,lng:-119.053337});
lineString2.pushPoint({lat:38.01347,lng:-119.143982});
lineString2.pushPoint({lat:37.965851,lng:-119.770203});
lineString2.pushPoint({lat:37.898689,lng:-120.18219});
lineString2.pushPoint({lat:37.867802,lng:-120.341492});
lineString2.pushPoint({lat:37.746819,lng:-120.239861});
lineString2.pushPoint({lat:37.51844,lng:-120.07782});
lineString2.pushPoint({lat:37.278419,lng:-119.674072});
var yosmitePark = new H.map.Polygon(lineString2, {
style: {
strokeColor: '#829',
lineWidth: 8
}
});
map.addObject(yosmitePark);
var lakeMcClure = new H.map.Marker({
lat: 37.6373862,
lng: -120.3448606
});
lakeMcClure.setData("lakeMcClure");
var Stockton = new H.map.Marker({
lat: 37.9729404,
lng: -121.4419639
});
Stockton.setData("Stockton");
var Monolake = new H.map.Marker({
lat: 38.0067483,
lng: -119.1013779
});
Monolake.setData("Monolake");
var PaohaIsland = new H.map.Marker({
lat: 38.000514,
lng: -119.0416587
});
PaohaIsland.setData("PaohaIsland");
var WalkerLake = new H.map.Marker({
lat: 38.7010578,
lng: -118.878652
});
WalkerLake.setData("WalkerLake");
var Bakersfield = new H.map.Marker({
lat: 35.3208963,
lng: -119.1587737
});
Bakersfield.setData("Bakersfield");
var SanFrancisco = new H.map.Marker({
lat: 37.7576793,
lng: -122.5076405
});
SanFrancisco.setData("SanFrancisco");
map.addObjects([lakeMcClure,Stockton,Monolake,PaohaIsland,WalkerLake,Bakersfield,SanFrancisco]);
var mapObj = map.getObjects();
console.log(yosmitePark.getGeometry());
console.log(PaohaIsland.getGeometry().distance(yosmitePark.getGeometry()));
}
There is no method in the API to calculate distance from point to polygon.
In order to achieve this, you can calculate distance from the point to each segment of the polygon's exterior LineString and then choose the smallest calculated value:
function distanceToGeoPolygon(geoPoint, geoPolygon) {
let lineString = geoPolygon.getExterior(),
minDistance = Infinity;
// check distance for each LineString segment of the polygon
for (let i = 0; i < lineString.getPointCount() - 1; i++) {
let segmentStart = lineString.extractPoint(i),
segmentEnd = lineString.extractPoint(i + 1),
distance = distanceToSegment(geoPoint, segmentStart, segmentEnd);
// set new min distance
if (distance <= minDistance) {
minDistance = distance;
}
}
return minDistance;
}
here is method to calculate distance from point to segment:
function distanceToSegment(point, segmentStart, segmentEnd) {
// first we find the intersecting point of line which
// crosses the given point and is vertical to segment (start - end)
let y0 = point.lat,
x0 = point.lng,
y1 = segmentStart.lat,
x1 = segmentStart.lng,
y2 = segmentEnd.lat,
x2 = segmentEnd.lng,
a = (y2 - y1) / (x2 - x1),
b = y1 - a * x1,
b0 = y0 + 1/a * x0,
xi = a * (b0 - b) / ((a * a) + 1),
yi = a * xi + b,
intersectingPoint = new H.geo.Point(yi, xi);
// if calculated intersecting point is within the segment,
// calculate distance between intersecting point and given point
if ( (xi > x1 && xi < x2 || xi > x2 && xi < x1) &&
(yi > y1 && yi < y2 || yi > y2 && yi < y1) ) {
return point.distance(intersectingPoint)
} else {
// else calculate distance between segment edges and given point
// and return the smaller one
return Math.min(point.distance(segmentStart), point.distance(segmentEnd));
}
}
test:
// test: (result is 14359)
console.log(distanceToGeoPolygon(lakeMcClure.getGeometry(), yosmitePark.getGeometry()));
Note: Above script returns positive numbers for points inside polygon too. If you don't want that, you can use H.Map#getObjectsWithin to verify if given Marker object (must be placed on map) is inside geo polygon (in your case I assume you don't need it).
Here is working jsfiddle example. It logs distance in the console after clicking on Marker object.
I can't manage with drawing rectangle between two cities. I've searched everywhere on the Internet and can't find out why my polygon is drawn on Google Maps as parallelogram even so on 2d plane (not earth plane) this rectangle is drawn properly.
What I noticed is that the curvature sides of parallelogram depends on where cities are placed on map. If two cities are placed vis-a-vis then my function draw rectangle successfully. But If they are placed diagonally then my function draw parallelogram. The result should be rotated rectangle with height as distance between two cities and width as kilometers that user chooses.
Here is my function that should draw rectangle between two cities. As args we need to give position of first city ($x1 is lat, $y1 is lng), position of second city and as third arg a radius in kilometers ($l1) from center point of rectangle.
function getPolygon($x1,$y1,$x2,$y2,$l1){
var $l1 = $l1*0.010526; //approx kilometers
var $distanceV = [($x2 - $x1), ($y2 - $y1)];
var $vlen = Math.sqrt(Math.pow($distanceV[0], 2) +
Math.pow($distanceV[1],2));
if($vlen == 0)
return [[0,0],[0,0],[0,0],[0,0]];
var $l2 = $vlen;
var $normalized = [($distanceV[0] / $vlen), ($distanceV[1] / $vlen)];
var $rotated = [(-1 * $normalized[1]), ($normalized[0])];
var $p1 = [($x1 - $rotated[0] * $l1 / 2), ($y1 - $rotated[1] * $l1 / 2)];
var $p2 = [($p1[0] + $rotated[0] * $l1), ($p1[1] + $rotated[1] * $l1)];
var $p3 = [($p1[0] + $normalized[0] * $l2), ($p1[1] + $normalized[1] * $l2)];
var $p4 = [($p3[0] + $rotated[0] * $l1), ($p3[1] + $rotated[1] * $l1)];
var $points = [
{lat: $p1[0], lng: $p1[1]},
{lat: $p3[0], lng: $p3[1]},
{lat: $p4[0], lng: $p4[1]},
{lat: $p2[0], lng: $p2[1]},
{lat: $p1[0], lng: $p1[1]}
];
return $points;
}
Then I draw it on Google Maps like this:
new google.maps.Polygon({
paths: getPolygon(first_city_lat, first_city_lng, second_city_lat, second_city_lng, 30),
strokeColor: '#FF0000',
strokeOpacity: 0.5,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.05
});
Here is an example should be rectangle between Birmingham and Oxford: JSFiddle
Additionally I'm sure that kilometers converter is not exact and it again depends how cities are placed.
The earth is curved. To get a polygon that appears rectangular on the curved sphere, you need to use calculations that take the projection of the map into account.
The Google Maps Javascript API v3 has a spherical geometry library that can be used to compute the desired points.
function getPolygon($x1,$y1,$x2,$y2,$l1){
var points = [];
var city1 = new google.maps.LatLng($x1, $y1);
var city2 = new google.maps.LatLng($x2, $y2);
var heading = google.maps.geometry.spherical.computeHeading(city1, city2);
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1/2*1000, heading+90));
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1/2*1000, heading-90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1/2*1000, heading-90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1/2*1000, heading+90));
points.push(points[0]);
return points;
}
proof of concept fiddle
code snippet:
var map;
google.maps.event.addDomListener(window, "load", function() {
var map = new google.maps.Map(document.getElementById("map_div"), {
center: new google.maps.LatLng(52.489471, -1.898575),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var trace = new google.maps.Polygon({
paths: getPolygon(52.489471, -1.898575, 51.752022, -1.257677, 30),
strokeColor: '#FF0000',
strokeOpacity: 0.5,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.05,
map: map
});
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < trace.getPath().getLength(); i++) {
bounds.extend(trace.getPath().getAt(i));
}
map.fitBounds(bounds);
function getPolygon($x1, $y1, $x2, $y2, $l1) {
var points = [];
var city1 = new google.maps.LatLng($x1, $y1);
var city2 = new google.maps.LatLng($x2, $y2);
var heading = google.maps.geometry.spherical.computeHeading(city1, city2);
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1 / 2 * 1000, heading + 90));
points.push(google.maps.geometry.spherical.computeOffset(city1, $l1 / 2 * 1000, heading - 90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1 / 2 * 1000, heading - 90));
points.push(google.maps.geometry.spherical.computeOffset(city2, $l1 / 2 * 1000, heading + 90));
points.push(points[0]);
return points;
}
});
html,
body {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
}
#map_div {
height: 95%;
}
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="map_div"></div>
I'm using the following function to generate random geo coordinates within a specified radius from a seed point:
function randomGeo(center, radius) {
var y0 = center.latitude;
var x0 = center.longitude;
var rd = radius / 111300;
var u = Math.random();
var v = Math.random();
var w = rd * Math.sqrt(u);
var t = 2 * Math.PI * v;
var x = w * Math.cos(t);
var y = w * Math.sin(t);
var xp = x / Math.cos(y0);
return {
'latitude': y + y0,
'longitude': xp + x0
};
}
I do this in a loop, several times, using a 2000m radius and the following seed point:
location: { // Oxford
latitude: 51.73213,
longitude: -1.20631
}
I'd expect all of these results to be within 2000m; instead, I'm seeing values upwards of 10000m:
[ { latitude: 51.73256540025445, longitude: -1.3358092771716716 }, // 3838.75070783092
{ latitude: 51.7214165686511, longitude: -1.1644147572878725 }, // 3652.1890457730474
{ latitude: 51.71721400063117, longitude: -1.2082082568884593 }, // 8196.861603477768
{ latitude: 51.73583824510363, longitude: -1.0940424351649711 }, // 5104.820455873758
{ latitude: 51.74017571473442, longitude: -1.3150742602532257 }, // 4112.3279147866215
{ latitude: 51.73496163915278, longitude: -1.0379454413532996 }, // 9920.01459343298
{ latitude: 51.73582333121239, longitude: -1.0939302282840453 }, // 11652.160906253064
{ latitude: 51.72145745285658, longitude: -1.2491630482776055 }, // 7599.550622138115
{ latitude: 51.73036335927129, longitude: -1.3516902043395063 }, // 8348.276271205428
{ latitude: 51.748104753808924, longitude: -1.2669212014250266 }, // 8880.760669882042
{ latitude: 51.72010719621805, longitude: -1.327161328951446 }, // 8182.466715589904
{ latitude: 51.725727610071125, longitude: -1.0691503599266818 } ] // 2026.3687763449955
Given that I (shamelessly!) plagiarized this solution from elsewhere (albeit I've seen several similar implementations), I can't seem to figure out where the math is going wrong.
(Also, in case you want it, this is how I'm calculating the distance. Pretty sure this is correct.)
function distance(lat1, lon1, lat2, lon2) {
var R = 6371000;
var a = 0.5 - Math.cos((lat2 - lat1) * Math.PI / 180) / 2 + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * (1 - Math.cos((lon2 - lon1) * Math.PI / 180)) / 2;
return R * 2 * Math.asin(Math.sqrt(a));
}
The problem seems to stem from the fact that this is just an inaccurate calculation depending on which center point you are using. Particularly this line:
var xp = x / Math.cos(y0);
Removing this line and changing longitude to
'longitude': x + x0
Seems to keep all of the points within the specified radius, although without this line it seems the points will not completely fill out east to west in some cases.
Anyway, I found someone experiencing a similar issue here with someone elses Matlab code as a possible solution. Depends on how uniformly spread out you need the random points if you wanted to work with a different formula.
Here is a google maps visualization of what's going on with your provided formula:
<!doctype html>
<html>
<head>
<script type="text/javascript" src="//maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
var distanceLimit = 2000; //in meters
var numberRandomPoints = 200;
var mapZoomLevel = 11;
var locationindex = 0;
var locations = [
{'name': 'Oxford, England', 'latitude': 51.73213, 'longitude': -1.20631},
{'name': 'Quito, Ecuador', 'latitude': -0.2333, 'longitude': -78.5167},
{'name': 'Ushuaia, Argentina', 'latitude': -54.8000, 'longitude': -68.3000},
{'name': 'McMurdo Station, Antartica', 'latitude': -77.847281, 'longitude': 166.667942},
{'name': 'Norilsk, Siberia', 'latitude': 69.3333, 'longitude': 88.2167},
{'name': 'Greenwich, England', 'latitude': 51.4800, 'longitude': 0.0000},
{'name': 'Suva, Fiji', 'latitude': -18.1416, 'longitude': 178.4419},
{'name': 'Tokyo, Japan', 'latitude': 35.6833, 'longitude': 139.6833},
{'name': 'Mumbai, India', 'latitude': 18.9750, 'longitude': 72.8258},
{'name': 'New York, USA', 'latitude': 40.7127, 'longitude': -74.0059},
{'name': 'Moscow, Russia', 'latitude': 55.7500, 'longitude': 37.6167},
{'name': 'Cape Town, South Africa', 'latitude': -33.9253, 'longitude': 18.4239},
{'name': 'Cairo, Egypt', 'latitude': 30.0500, 'longitude': 31.2333},
{'name': 'Sydney, Australia', 'latitude': -33.8650, 'longitude': 151.2094},
];
</script>
</head>
<body>
<div id="topbar">
<select id="location_switch">
<script>
for (i=0; i<locations.length; i++) {
document.write('<option value="' + i + '">' + locations[i].name + '</option>');
}
</script>
</select>
<img src="http://google.com/mapfiles/ms/micons/ylw-pushpin.png" style="height:15px;"> = Center
<img src="https://maps.gstatic.com/mapfiles/ms2/micons/red.png" style="height:15px;"> = No Longitude Adjustment
<img src="https://maps.gstatic.com/mapfiles/ms2/micons/pink.png" style="height:15px;"> = With Longitude Adjustment (var xp = x / Math.cos(y0);)
</div>
<div id="map_canvas" style="position:absolute; top:30px; left:0px; height:100%; height:calc(100% - 30px); width:100%;overflow:hidden;"></div>
<script>
var markers = [];
var currentcircle;
//Create the default map
var mapcenter = new google.maps.LatLng(locations[locationindex].latitude, locations[locationindex].longitude);
var myOptions = {
zoom: mapZoomLevel,
scaleControl: true,
center: mapcenter
};
var map = new google.maps.Map(document.getElementById('map_canvas'), myOptions);
//Draw default items
var centermarker = addCenterMarker(mapcenter, locations[locationindex].name + '<br>' + locations[locationindex].latitude + ', ' + locations[locationindex].longitude);
var mappoints = generateMapPoints(locations[locationindex], distanceLimit, numberRandomPoints);
drawRadiusCircle(map, centermarker, distanceLimit);
createRandomMapMarkers(map, mappoints);
//Create random lat/long coordinates in a specified radius around a center point
function randomGeo(center, radius) {
var y0 = center.latitude;
var x0 = center.longitude;
var rd = radius / 111300; //about 111300 meters in one degree
var u = Math.random();
var v = Math.random();
var w = rd * Math.sqrt(u);
var t = 2 * Math.PI * v;
var x = w * Math.cos(t);
var y = w * Math.sin(t);
//Adjust the x-coordinate for the shrinking of the east-west distances
var xp = x / Math.cos(y0);
var newlat = y + y0;
var newlon = x + x0;
var newlon2 = xp + x0;
return {
'latitude': newlat.toFixed(5),
'longitude': newlon.toFixed(5),
'longitude2': newlon2.toFixed(5),
'distance': distance(center.latitude, center.longitude, newlat, newlon).toFixed(2),
'distance2': distance(center.latitude, center.longitude, newlat, newlon2).toFixed(2),
};
}
//Calc the distance between 2 coordinates as the crow flies
function distance(lat1, lon1, lat2, lon2) {
var R = 6371000;
var a = 0.5 - Math.cos((lat2 - lat1) * Math.PI / 180) / 2 + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * (1 - Math.cos((lon2 - lon1) * Math.PI / 180)) / 2;
return R * 2 * Math.asin(Math.sqrt(a));
}
//Generate a number of mappoints
function generateMapPoints(centerpoint, distance, amount) {
var mappoints = [];
for (var i=0; i<amount; i++) {
mappoints.push(randomGeo(centerpoint, distance));
}
return mappoints;
}
//Add a unique center marker
function addCenterMarker(centerposition, title) {
var infowindow = new google.maps.InfoWindow({
content: title
});
var newmarker = new google.maps.Marker({
icon: 'http://google.com/mapfiles/ms/micons/ylw-pushpin.png',
position: mapcenter,
map: map,
title: title,
zIndex: 3
});
google.maps.event.addListenerOnce(map, 'tilesloaded', function() {
infowindow.open(map,newmarker);
});
markers.push(newmarker);
return newmarker;
}
//Draw a circle on the map
function drawRadiusCircle (map, marker, distance) {
currentcircle = new google.maps.Circle({
map: map,
radius: distance
});
currentcircle.bindTo('center', marker, 'position');
}
//Create markers for the randomly generated points
function createRandomMapMarkers(map, mappoints) {
for (var i = 0; i < mappoints.length; i++) {
//Map points without the east/west adjustment
var newmappoint = new google.maps.LatLng(mappoints[i].latitude, mappoints[i].longitude);
var marker = new google.maps.Marker({
position:newmappoint,
map: map,
title: mappoints[i].latitude + ', ' + mappoints[i].longitude + ' | ' + mappoints[i].distance + 'm',
zIndex: 2
});
markers.push(marker);
//Map points with the east/west adjustment
var newmappoint = new google.maps.LatLng(mappoints[i].latitude, mappoints[i].longitude2);
var marker = new google.maps.Marker({
icon: 'https://maps.gstatic.com/mapfiles/ms2/micons/pink.png',
position:newmappoint,
map: map,
title: mappoints[i].latitude + ', ' + mappoints[i].longitude2 + ' | ' + mappoints[i].distance2 + 'm',
zIndex: 1
});
markers.push(marker);
}
}
//Destroy all markers
function clearMarkers() {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
markers = [];
}
$('#location_switch').change(function() {
var newlocation = $(this).val();
clearMarkers();
mapcenter = new google.maps.LatLng(locations[newlocation].latitude, locations[newlocation].longitude);
map.panTo(mapcenter);
centermarker = addCenterMarker(mapcenter, locations[newlocation].name + '<br>' + locations[newlocation].latitude + ', ' + locations[newlocation].longitude);
mappoints = generateMapPoints(locations[newlocation], distanceLimit, numberRandomPoints);
//Draw default items
currentcircle.setMap(null);
drawRadiusCircle(map, centermarker, distanceLimit);
createRandomMapMarkers(map, mappoints);
});
</script>
</body>
</html>
You can generate points with a random bearing and distance from the center by moving some distance using vincenty distances (see this stackoverflow answer). In Python, for example, you could use the geopy package.
import random
from geopy import Point
from geopy.distance import geodesic
def generate_point(center: Point, radius: int) -> Point:
radius_in_kilometers = radius * 1e-3
random_distance = random.random() * radius_in_kilometers
random_bearing = random.random() * 360
return geodesic(kilometers=random_distance).destination(center, random_bearing)
radius = 2000
center = Point(51.73213, -1.20631)
points = [generate_point(center, radius) for _ in range(3000)]
Distances are confirmed with:
assert all(geodesic(center, point).meters <= radius for point in points)
Here a simple Vanilla Javascript solution that works like a charm. I want to give credits where it's due and where I found it : https://gist.github.com/fajarlabs/af9e0859fc29b2107bd1797536d2ff2d
/**
* Generates number of random geolocation points given a center and a radius.
* #param {Object} center A JS object with lat and lng attributes.
* #param {number} radius Radius in meters.
* #param {number} count Number of points to generate.
* #return {array} Array of Objects with lat and lng attributes.
*/
function generateRandomPoints(center, radius, count) {
var points = [];
for (var i=0; i<count; i++) {
points.push(generateRandomPoint(center, radius));
}
return points;
}
/**
* Generates number of random geolocation points given a center and a radius.
*
* #param {Object} center A JS object with lat and lng attributes.
* #param {number} radius Radius in meters.
* #return {Object} The generated random points as JS object with lat and lng attributes.
*/
function generateRandomPoint(center, radius) {
var x0 = center.lng;
var y0 = center.lat;
// Convert Radius from meters to degrees.
var rd = radius/111300;
var u = Math.random();
var v = Math.random();
var w = rd * Math.sqrt(u);
var t = 2 * Math.PI * v;
var x = w * Math.cos(t);
var y = w * Math.sin(t);
var xp = x/Math.cos(y0);
// Resulting point.
return {'lat': y+y0, 'lng': xp+x0};
}
// Usage Example.
// Generates 100 points that is in a 1km radius from the given lat and lng point.
var randomGeoPoints = generateRandomPoints({'lat':24.23, 'lng':23.12}, 1000, 100);
console.log(randomGeoPoints);
I have tried lots but could not figure out the problem. I want to draw a polygon around specific lat,lng. The polygon will consists of 13 coordinates in specific radius.
Person inter the address and radius in text box.
Geo code get lat,lng of that address
Center the map to there.
Draw the polygon around that center point with radius
The polygon should consists of 13 coordinates
Code
function showAddress(address, miles) {
var geocoder = new google.maps.Geocoder();
geocoder.geocode({
address : address
}, function(results, status) {
if(status == google.maps.GeocoderStatus.OK) {
//searchLocationsNear(results[0].geometry.location);
var cordinate = results[0].geometry.location;
//alert(cordinate);
var mapOptions = {
center : cordinate,
zoom : 8,
mapTypeId : google.maps.MapTypeId.ROADMAP,
overviewMapControl : true,
overviewMapControlOptions : {
opened : true,
position : google.maps.ControlPosition.BOTTOM_LEFT
}
};
//
//var address = document.getElementById("address").value;
var radius = 1;
var latitude = 23.1793013;
var longitude = 75.78490970000007;
//Degrees to radians
var d2r = Math.PI / 180;
// Radians to degrees
var r2d = 180 / Math.PI;
// Earth radius is 3,963 miles
var cLat = (radius / 3963) * r2d;
var cLng = cLat / Math.cos(latitude * d2r);
//Store points in array
var points = [];
alert("declare array");
var bounds = new google.maps.LatLngBounds();
// Calculate the points
// Work around 360 points on circle
for(var i = 0; i < 13; i++) {
var theta = Math.PI * (i / 180);
// Calculate next X point
circleY = longitude + (cLng * Math.cos(theta));
//console.log("CircleY:"+circleY);
// Calculate next Y point
circleX = latitude + (cLat * Math.sin(theta));
//console.log("circleX:"+circleX);
// Add point to array
var aPoint = new google.maps.LatLng(circleX, circleY);
points.push(aPoint);
bounds.extend(aPoint);
}
points.push(points[0]);
//console.log(points);
//to complete circle
var colors = ["#CD0000", "#2E6444", "#003F87"];
var Polyline_Path = new google.maps.Polyline({
path : points,
strokeColor : colors[0],
// color of the outline of the polygon
strokeOpacity : 1,
// between 0.0 and 1.0
strokeWeight : 1,
// The stroke width in pixels
fillColor : colors[1],
fillOpacity : 0
});
var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
Polyline_Path.setMap(map);
} else {
alert(address + ' not found');
}
});
}
Replace i<13;i++ by
i<360;i+=360/13
this will work
thank
edit: the last point isn't needed since gmap will close it automagically
I believe that cLng should be changed to:
var cLng = cLat * Math.cos(latitude * d2r);
(to get a perfect circle, that is)
This bit of Javascript parses an xml file which contains latitude and longitude co-ordinates for a start and end point. I can get the markers out on a map fine, the issue I'm having is that the map doesn't center on the points (eventually it's going to make a call to the Google Directions Service and draw a route between the two points, so would be good to have the map fit nicely around both points rather than just centering on one of the points).
At the minute the map is created using hardcoded lat and long values so I know that needs changing, but I've tried putting in 'startpoint, and 'endpoint' to no avail, the map doesn't load, so I'm guessing the way I'm doing it below is incorrect.
jQuery(document).ready(function($) {
downloadUrl("xml.php", function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("title");
var startpoint = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("startlat")),
parseFloat(markers[i].getAttribute("startlng")));
var endpoint = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("endlat")),
parseFloat(markers[i].getAttribute("endlng")));
var html = "<b>" + name;
var icon = customIcons || {};
var startmarker = new google.maps.Marker({
map: map,
position: startpoint,
icon: icon.icon,
shadow: icon.shadow
});
bindInfoWindow(startmarker, map, infoWindow, html);
var endmarker = new google.maps.Marker({
map: map,
position: endpoint,
icon: icon.icon,
shadow: icon.shadow
});
bindInfoWindow(endmarker, map, infoWindow, html);
}
});
var map = new google.maps.Map(document.getElementById("map_canvas"), {
center: new google.maps.LatLng(startpoint, endpoint),
zoom: 13,
mapTypeId: 'roadmap'
});
var infoWindow = new google.maps.InfoWindow;
});
This is the output of the XML...
<markers>
<marker title="Journey" description="Lorem Ipsum..." startlat="53.403023" startlng="-2.130801" endlat="53.414257" endlng="-2.094128"/>
</markers>
If you generate a bounds using your startpoint and endpoint, you can fit the map to display that bounds.
var map = new google.maps.Map(document.getElementById("map_canvas"), {
zoom: 13,
mapTypeId: 'roadmap'
});
var bounds = new google.maps.LatLngBounds();
bounds.extend(startpoint);
bounds.extend(endpoint);
map.fitBounds(bounds);
LatLng expect's latitude and longtude of the point where you want to center your map.
And that is why below code doesn't work.
center: new google.maps.LatLng(startpoint, endpoint),
To show the route between two point's on centre of the map. you can try finding the middle point between your start and end point.
Here is an implementation in java that calculate's middle point, more info - Haversine_formula
public static void midPoint(double lat1,double lon1,double lat2,double lon2){
double dLon = Math.toRadians(lon2 - lon1);
//convert to radians
lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(lat2);
lon1 = Math.toRadians(lon1);
double Bx = Math.cos(lat2) * Math.cos(dLon);
double By = Math.cos(lat2) * Math.sin(dLon);
double lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By));
double lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);
//print out in degrees
System.out.println(Math.toDegrees(lat3) + " " + Math.toDegrees(lon3));
}
Edit:
Javascript implementation
function middlePoint(lat1,lon1,lat2,lon2){
var dLon = toRad(lon2 - lon1);
lat1 = toRad(lat1);
lat2 = toRad(lat2);
lon1 = toRad(lon1);
var Bx = Math.cos(lat2) * Math.cos(dLon);
var By = Math.cos(lat2) * Math.sin(dLon);
var lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By));
var lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);
var middlePoint = new Object();
middlePoint.latitude=lat3;
middlePoint.longitude=lon3;
return middlePoint;
}
function toRad(Value) {
return Value * Math.PI / 180;
}