Get polygons within polygons in Google maps - google-maps

With the help of #Dr.Molle answer I learnt to do free hand drawing in Google maps. Now I'm trying to get the polygon drawn within a polygon something like in the below SS
I want to get the polygons marked in yellow and green within the black.
I'm not sure whether this is possible or not. Please shed some light on this issue.
Updates: on further research I learnt about a method called containsLocation(point, polygons) which is used to find whether the given lat/lng point is within the polygon or not.
But sadly there is no default method to check polygons within polygon provided by Google maps :(

You can check if a polygon is within another polygon by looping through each point of the inner polygon and testing if it is contained within the outer polygon using containsLocation().
var isPolygonInsidePolygon = function (innerPolygon, outerPolygon) {
var pointsInside = 0;
var pointsOutside = 0;
innerPolygon.getPath().getArray().map(function (x) {
(google.maps.geometry.poly.containsLocation(x, outerPolygon)) ? pointsInside++ : pointsOutside++;
});
return (pointsOutside > 0) ? false : true;
};
The JavaScript map() function may not work in older browsers, IE8 or lower.

This is a GIS question. Google Maps API isn't really a full-blown GIS. If you want an open-source solution, I suggest loading your yellow and green polygons into a PostGIS database. Then you can query the database.
As an example, you can encode the drawn polygon as a POLYGON object which has the format:
POLYGON((lon lat, lon lat, lon lat, lon lat, ... lon lat))
And then send that to a PHP file from javascript like (you'll wrap this in a $.get() command or similar and return json results:
getParcels.php?bounds=POLYGON((lon lat, lon lat, lon lat, lon lat, ... lon lat))
In the PHP file, query the PostGIS database and return the ids of the yellow and green polygons:
<?php
$pgcon = pg_connect ("dbname=gis user=gisuser connect_timeout=5") or die ( 'Can not connect to PG server' );
if (!$pgcon) {
echo "No connection to GIS database.\n";
}
$bounds = urldecode($_GET["bounds"];
$ewkt = 'SRID=4326;' . $bounds);
$json = ''; // this will contain your output
// Here I am returning the polygon geometry and the parcelID...
$query .= <<<EOD
SELECT
ST_AsGeoJSON(the_geom) as geom,
parid
FROM
parcels
WHERE
ST_Intersects(the_geom, ST_GeomFromEWKT( $1 ));
EOD;
$result = pg_query_params($pgcon, $query, array($ewkt));
if($result) {
$json = '{"type":"FeatureCollection", "features":[';
while($row = pg_fetch_assoc($result)) {
$json .= '{"geometry":' . $row['geom'] . ',';
$json .= '"type":"Feature","properties":{"parid":"' . $row['parid'] . '"}},';
}
$json = substr($json, 0,-1).']}';
}
echo $json;
?>
This will return the parcels that intersect your polygon using the ST_Intersects command in PostGIS.

An alternative implementation working from #chris-smith solution that might be faster, since it doesn't keep looping if it finds an outside point:
function isPolygonInsidePolygon( innerPolygon, outerPolygon ) {
var points = innerPolygon.getPath().getArray();
for( var i = 0; i < points.length; i++ ){
if( ! google.maps.geometry.poly.containsLocation( points[i], outerPolygon) ){
return false;
}
}
return true;
}

Related

Calculate the distance between multi geolocations points

My application collects geolocation point from the user every certain amount of time, I am trying to use these points in order to calculate the distance from the first point through all of the points.
please note that when the user moves in a straight line, the geolocation points do not form a straight line, because the points I collect have a margin of error due to inaccuracy, thus I can't use something like Haversine formula because it will give incorrect value (longer distance than real distance)
and I can't use Google Maps Distance API because it calculates the distance between 2 points only, and it will be so expensive to call it 200 times to calculate distance through all points.
and I want to calculate this value on the server-side because of some security rules I have. so using the google maps SDK in the front end to calculate it is not an option either.
Any idea ...
One option would be to simplify the line, then run the data through the Google Roads API (assuming the travel is on roads), then measure the length of the resulting line (following the roads).
for anyone facing the same problem,I have followed this link
https://developers-dot-devsite-v2-prod.appspot.com/maps/documentation/roads/snap
here is my code in PHP
// snap the collected points from user to the nearest road using google API
$fields = array(
'path' => '60.170880,24.942795|60.170879,24.942796|60.170877,24.942796|60.170902,24.942654',
'key' => '<YOUR_KEY_HERE>'
);
$url = "https://roads.googleapis.com/v1/snapToRoads?" . http_build_query($fields, '', '&');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$response = json_decode($response);
$totalDistance = 0;
$previousPoint = null;
foreach ($response->snappedPoints as $pointOnRoad) {
if(!$previousPoint){
$previousPoint = $pointOnRoad;
continue;
}
$totalDistance += getDistance($pointOnRoad->location->latitude, $pointOnRoad->location->longitude,
$previousPoint->location->latitude, $previousPoint->location->longitude);
}
echo $totalDistance;
// calculate distance between 2 geo points
function getDistance($latitude1, $longitude1, $latitude2, $longitude2) {
$earth_radius = 6371;
$dLat = deg2rad($latitude2 - $latitude1);
$dLon = deg2rad($longitude2 - $longitude1);
$a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * sin($dLon/2) * sin($dLon/2);
$c = 2 * asin(sqrt($a));
$d = $earth_radius * $c;
return $d;
}
We are having similar kind of requirement. There are 2 paths and we need to make sure that each node in 1st path (except start and end) are at least 100 KM away from each other of 2nd path.
Can you please share code snippet or logic behind this.
Using Haversine formula in loop will impact performance. So, please suggest some better solution.

Mysql query within a given geographical area

A table in my database contains many postal addresses that also have longitude and latitude information like this:
Name ---- Street Address -------- Post Code ---- Longitude ---- Latitude
Fred ---- 11 Monarch Street ----- 4114 ---------- 57.317715 ---- 10.154355
Barney -- 4 Reign Street -------- 4114 ------------ 56.151112 ---- 10.087925
I have a given area (kml coordinates via google maps), defined like this:
12.548740,55.694469,0.000000
12.541320,55.687840,0.000000
12.537410,55.690552,0.000000
12.535310,55.694641,0.000000
12.534499,55.695293,0.000000
12.535787,55.696625,0.000000
12.538100,55.696911,0.000000
12.543890,55.697659,0.000000
12.548740,55.694469,0.000000
What mysql query do I use to find addresses located within in the area?
I don't know any MySQL query for this.
In this Answer I use a PHP function to find if a point is in a polygon (4points).The function is based on C code Point in Polygon by Darel Rex Finley
You can use it for your 8 point polygon.
$polySides = 8; //how many corners the polygon has
$polyX = array(12.548740,12.541320,12.537410,12.535310,12.534499,12.535787,12.538100,12.543890,12.548740);//horizontal coordinates of corners
$polyY = array(55.694469,55.687840,55.690552,55.694641,55.695293,55.696625,55.696911,55.697659,55.694469);//vertical coordinates of corners
$x = 12.548740;
$y = 55.694469;//Inside
//$y = 12.528740;//Outside
function pointInPolygon($polySides,$polyX,$polyY,$x,$y) {
$j = $polySides-1 ;
$oddNodes = 0;
for ($i=0; $i<$polySides; $i++) {
if ($polyY[$i]<$y && $polyY[$j]>=$y
|| $polyY[$j]<$y && $polyY[$i]>=$y) {
if ($polyX[$i]+($y-$polyY[$i])/($polyY[$j]-$polyY[$i])*($polyX[$j]-$polyX[$i])<$x) {
$oddNodes=!$oddNodes; }}
$j=$i; }
return $oddNodes; }
if (pointInPolygon($polySides,$polyX,$polyY,$x,$y)){
echo "Is in polygon!";
}
else echo "Is not in polygon";
You can loop through your database inserting lat,lng into function.
If the database is large you can create a bounding box with north_west and south_east
coordinates to limit the data to be filtered by the function.
$sql = "SELECT lat,lng FROM `table` WHERE (lng BETWEEN '$west_lng' AND '$east_lng') AND (lat BETWEEN '$north_lat' AND '$south_lat')";
The other solution is to use mysql spatial extension

Mongodb geoWithin google maps bounds

I'm kind of new to mongodb.
I want to use mongodb's geospatial feature to query locations in a boundary obtained from google maps. It's like withinBox(swLng, swLat, neLng, neLat). But it fails to give me correct results when the map zooms out, as neLng/neLat is less than swLng/swLat. It seems that this is calculated using x > swLng and x < neLng and y > swLat and y < neLat, not taking map projection into account.
So can I achieve the query by withinBox, or I have to adjust coordinates, or I should use near?
As I commented above, when northeast and southwest points cross the international date line, the query will fail as top right's y is smaller than bottom left's y.
If you are using mongodb with php and doctrine, you need make two queries and merge result on the client side like below:
if ($x1 > $x2) {
$qb->field('coordinates')->withinBox(-180, $y1, $x2, $y2);
$result1 = $qb->getQuery()->execute();
$qb->field('coordinates')->withinBox($x1, $y1, 180, $y2);
$result2 = $qb->getQuery()->execute();
$result = $result1->toArray() + $result2->toArray();
} else {
$qb->field('coordinates')->withinBox($x1, $y1, $x2, $y2);
$result = $qb->getQuery()->execute();
$result = $result->toArray();
}

Random Real US Address within a specific zip code, county or area

so for a project in school I am trying to simulate where students live in our town since official data is not available obviously due to privacy concerns. I started looking for a generator that works by zip code, radius or county but I haven't been able to find any (commercially or free) I would love it to be free, but I might be able to secure some funding for a license. If I find random generators, they cannot be limited to a ZIP code or city to produce real addresses randomly.
A good idea I found was here: https://stackoverflow.com/a/12289969/1778542
Based on that I would pick the city center's long\lat coordinates, find out the outskirts coordinates to create a plane, then randomly generate long\lat coordinates within the plane, feed them back in to have Google approximate the addresses for it. One concern that was raised (and I try to avoid) is that Google doesn't use verified addresses, rather approximations.
Does anyone have a hint where to find such a generator or a sleeker way to use GMaps?
Thanks a million!
GP
I use this code in one of my Laravel Seeder it gets a random street name in Romania provided that you give it the location area and Town,
It works by getting the latitude and longitude for that area and then randomly adds a radius of 2 Kilometers, after that it makes another request to google api, and from that it extracts a random street name.
I don't know if this will help you, adjusting this code can generate a real address provided that you give a first good location to look;
Here is the code:
protected function getRandomStreetNameFromCity($judet, $city){
$kmRange = 2;
$initalLocation = [];
$randomLocation= [];
$randomKmval = mt_rand(1, $kmRange) / mt_getrandmax();
// Poor Man Lat and Lng
//Latitude: 1 deg = 110.574 km
//Longitude: 1 deg = 111.320*cos(latitude) km
$guzzelCl = new Client();
$guzelReq = $guzzelCl->request('GET', 'http://maps.googleapis.com/maps/api/geocode/json?address=Romania,'.$judet.','.$city.'&sensor=false', [
'verify' => false,
]);
if($guzelReq->getStatusCode() == 200){
$arrJson = json_decode($guzelReq->getBody(), true);
while (count($arrJson['results']) <= 0){
$judet= $this->getNewJudet();
$city = $this->getNewOras();
$guzelReq = $guzzelCl->request('GET', 'http://maps.googleapis.com/maps/api/geocode/json?address=Romania,'.$judet.','.$city.'&sensor=false', [
'verify' => false,
]);
$arrJson = json_decode($guzelReq->getBody(), true);
}
$initalLocation = $arrJson['results'][0]['geometry']['location'];
}
$plusMinus = $this->generateRandomString(1);
$randomExp = [ 1 => $tempLat = eval("return (1 / (110.574 ".$plusMinus." ".$randomKmval." )+ ".$initalLocation['lat']." );"),
2 => eval('return ('.$initalLocation['lng'].' '.$plusMinus.' 1/111.320*cos($tempLat));'),
];
$guzelReq = $guzzelCl->request('GET', 'http://maps.googleapis.com/maps/api/geocode/json?latlng='.$randomExp[1].','.$randomExp[2], [
'verify' => false,
]);
return explode(',', json_decode($guzelReq->getBody(), true)['results'][0]['formatted_address'])[0];
}
protected function getNewJudet(){
//This is a administrative type of location named 'judet' Romania is divided in a number bellow 50 of this
return array_rand($this->judetOras, 1);
}
protected function getNewOras(){
//This is a Town String
return $this->judetOras[$iterateJud = array_rand($this->judetOras, 1)][array_rand($this->judetOras[$iterateJud], 1)];
}
protected function generateRandomString($length = 10) {
$characters = '-+';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}

how to use MySQL DB for EGmap extension in Yii

for example i have a MySQL database that contains latitude and longitude, how do I call these coordinates to be displayed in the map ? anyone can help me please?
Since your question and information are a bit unclear, these are my assumptions:
I assume that you have followed the instruction correctly to install the EGMap
extension into your yii application.
You want to place a marker at the said coordinates (latitude &
longitude).
Sample codes: (please adjust to fit your database tables and columns at the lines
commented as "// Get LatLong from table Location"). Place this straight into your view file example: protected/views/site/index.php
<!-- other html codes here -->
<div id="map-container">
<?php
// Get LatLong from table Location
$location=Location::model()->findByPk(1);
$latitude = $location->latitude;
$longitude = $location->longitude;
Yii::import('ext.gmap.*');
$gMap = new EGMap();
$gMap->setJsName('map');
$gMap->zoom = 10;
$mapTypeControlOptions = array(
'sensor'=>true,
'position'=> EGMapControlPosition::LEFT_BOTTOM,
'style'=>EGMap::MAPTYPECONTROL_STYLE_DROPDOWN_MENU
);
// Map settings
$gMap->mapTypeControlOptions= $mapTypeControlOptions;
$gMap->setWidth(800);
$gMap->setHeight(600);
$gMap->setCenter($latitude, $longitude);
// Prepare icon
$icon = new EGMapMarkerImage("http://google-maps-icons.googlecode.com/files/gazstation.png");
$icon->setSize(32, 37);
$icon->setAnchor(16, 16.5);
$icon->setOrigin(0, 0);
// Prepare marker
$marker = new EGMapMarker($latitude, $longitude, array('title' => 'Gas Station','icon'=>$icon));
$gMap->addMarker($marker);
$gMap->renderMap();
?>
</div>
<!-- other html codes here -->