Add GeoLocation library
parent
fd77176765
commit
d0cc2b6fc1
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
$msgs = $database->select('messages', ['username', 'message', 'time'], ['AND' => [
|
||||
'lat[>]' => $searchbounds[0]->getLatitudeInDegrees(),
|
||||
'lat[<]' => $searchbounds[1]->getLatitudeInDegrees(),
|
||||
'long[>]' => $searchbounds[0]->getLongitudeInDegrees(),
|
||||
'long[<]' => $searchbounds[1]->getLongitudeInDegrees()],
|
||||
"ORDER" => "time DESC",
|
||||
"LIMIT" => 30
|
||||
]);
|
@ -0,0 +1,80 @@
|
||||
GeoLocation
|
||||
===========
|
||||
|
||||
Retrieve bounding coordinates and distances with GeoLocation.
|
||||
|
||||
This is a PHP port of Java code that was originally published at
|
||||
<a href="http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates">
|
||||
http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates</a>. A few modifications were made and an additional helper method to retrieve latitude and longitude from an address has been provided using Google's Geocoding API. <br />
|
||||
|
||||
License:
|
||||
http://creativecommons.org/licenses/by/3.0/
|
||||
|
||||
Examples
|
||||
========
|
||||
|
||||
Get distance between two points:
|
||||
--------------------------------------------------------
|
||||
<pre>
|
||||
<code>
|
||||
use AnthonyMartin\GeoLocation\GeoLocation as GeoLocation;
|
||||
|
||||
// Set locations
|
||||
$edison_nj = GeoLocation::fromDegrees(40.5187154, -74.4120953);
|
||||
$brooklyn_ny = GeoLocation::fromDegrees(40.65, -73.95);
|
||||
|
||||
echo "Distance from Edison, NJ to Brookyln, NY: " .
|
||||
$edison_nj->distanceTo($brooklyn_ny, 'miles') . " miles \n";
|
||||
|
||||
# Distance from Edison, NJ to Brookyln, NY: 25.888611494606 miles
|
||||
|
||||
|
||||
echo "Distance from Edison, NJ to Brooklyn, NY: " .
|
||||
$edison_nj->distanceTo($brooklyn_ny, 'kilometers') . " kilometers \n";
|
||||
|
||||
# Distance from Edison, NJ to Brooklyn, NY: 41.663681581973 kilometers
|
||||
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
|
||||
Get bounding coordinates
|
||||
--------------------------------------------------------
|
||||
<pre>
|
||||
<code>
|
||||
use AnthonyMartin\GeoLocation\GeoLocation as GeoLocation;
|
||||
|
||||
$edison = GeoLocation::fromDegrees(40.5187154, -74.4120953);
|
||||
$coordinates = $edison->boundingCoordinates(3, 'miles');
|
||||
|
||||
echo "min latitude: " . $coordinates[0]->getLatitudeInDegrees() . " \n";
|
||||
echo "min longitude: " . $coordinates[0]->getLongitudeInDegrees() . " \n";
|
||||
|
||||
echo "max latitude: " . $coordinates[1]->getLatitudeInDegrees() . " \n";
|
||||
echo "max longitude: " . $coordinates[1]->getLongitudeInDegrees() . " \n";
|
||||
|
||||
/**
|
||||
* Returns:
|
||||
* min latitude: 40.47529593323
|
||||
* min longitude: -74.469211617725
|
||||
* max latitude: 40.56213486677
|
||||
* max longitude: -74.354978982275
|
||||
**/
|
||||
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
Get latitude and longitude from address or location
|
||||
--------------------------------------------------------
|
||||
<pre>
|
||||
<code>
|
||||
use AnthonyMartin\GeoLocation\GeoLocation as GeoLocation;
|
||||
|
||||
$location = 'New York City';
|
||||
$response = GeoLocation::getGeocodeFromGoogle($location);
|
||||
$latitude = $response->results[0]->geometry->location->lat;
|
||||
$longitude = $response->results[0]->geometry->location->lng;
|
||||
echo $latitude . ', ' . $longitude;
|
||||
# 40.7143528, -74.0059731
|
||||
</code>
|
||||
</pre>
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "anthonymartin/geo-location",
|
||||
"type": "class",
|
||||
"description": "Retrieve bounding coordinates, distances, longitude and latitude with GeoLocation.class.php",
|
||||
"keywords": ["geolocation","geocoding", "bounding coordinates", "distances"],
|
||||
"homepage": "https://github.com/anthonymartin/GeoLocation.php",
|
||||
"license": "CC 3.0",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Anthony Martin",
|
||||
"email": "anthony@replaycreative.com",
|
||||
"homepage": "http://replaycreative.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"AnthonyMartin": "src/"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
namespace AnthonyMartin\GeoLocation;
|
||||
|
||||
/**
|
||||
* <p>Represents a point on the surface of a sphere. (The Earth is almost
|
||||
* spherical.)</p>
|
||||
*
|
||||
* <p>To create an instance, call one of the static methods fromDegrees() or
|
||||
* fromRadians().</p>
|
||||
*
|
||||
* <p>This is a PHP port of Java code that was originally published at
|
||||
* <a href="http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates#Java">
|
||||
* http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates#Java</a>.</p>
|
||||
*
|
||||
* Many thanks to the original author: Jan Philip Matuschek
|
||||
*
|
||||
* @author Anthony Martin
|
||||
* @version November 21 2012
|
||||
*/
|
||||
class GeoLocation {
|
||||
|
||||
private $radLat; // latitude in radians
|
||||
private $radLon; // longitude in radians
|
||||
|
||||
private $degLat; // latitude in degrees
|
||||
private $degLon; // longitude in degrees
|
||||
|
||||
private $angular; // angular radius
|
||||
|
||||
const EARTHS_RADIUS_KM = 6371.01;
|
||||
const EARTHS_RADIUS_MI = 3958.762079;
|
||||
|
||||
protected static $MIN_LAT; // -PI/2
|
||||
protected static $MAX_LAT; // PI/2
|
||||
protected static $MIN_LON; // -PI
|
||||
protected static $MAX_LON; // PI
|
||||
|
||||
public function __construct() {
|
||||
self::$MIN_LAT = deg2rad(-90); // -PI/2
|
||||
self::$MAX_LAT = deg2rad(90); // PI/2
|
||||
self::$MIN_LON = deg2rad(-180); // -PI
|
||||
self::$MAX_LON = deg2rad(180); // PI
|
||||
}
|
||||
|
||||
/**
|
||||
* @param double $latitude the latitude, in degrees.
|
||||
* @param double $longitude the longitude, in degrees.
|
||||
* @return GeoLocation
|
||||
*/
|
||||
public static function fromDegrees($latitude, $longitude) {
|
||||
$location = new GeoLocation();
|
||||
$location->radLat = deg2rad($latitude);
|
||||
$location->radLon = deg2rad($longitude);
|
||||
$location->degLat = $latitude;
|
||||
$location->degLon = $longitude;
|
||||
$location->checkBounds();
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param double $latitude the latitude, in radians.
|
||||
* @param double $longitude the longitude, in radians.
|
||||
* @return GeoLocation
|
||||
*/
|
||||
public static function fromRadians($latitude, $longitude) {
|
||||
$location = new GeoLocation();
|
||||
$location->radLat = $latitude;
|
||||
$location->radLon = $longitude;
|
||||
$location->degLat = rad2deg($latitude);
|
||||
$location->degLon = rad2deg($longitude);
|
||||
$location->checkBounds();
|
||||
return $location;
|
||||
}
|
||||
|
||||
protected function checkBounds() {
|
||||
if ($this->radLat < self::$MIN_LAT || $this->radLat > self::$MAX_LAT ||
|
||||
$this->radLon < self::$MIN_LON || $this->radLon > self::$MAX_LON)
|
||||
throw new \Exception("Invalid Argument");
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the great circle distance between this GeoLocation instance
|
||||
* and the location argument.
|
||||
* @param GeoLocation $location
|
||||
* @param string $unit_of_measurement
|
||||
* @internal param float $radius the radius of the sphere, e.g. the average radius for a
|
||||
* spherical approximation of the figure of the Earth is approximately
|
||||
* 6371.01 kilometers.
|
||||
* @return double the distance, measured in the same unit as the radius
|
||||
* argument.
|
||||
*/
|
||||
public function distanceTo(GeoLocation $location, $unit_of_measurement) {
|
||||
$radius = $this->getEarthsRadius($unit_of_measurement);
|
||||
|
||||
return acos(sin($this->radLat) * sin($location->radLat) +
|
||||
cos($this->radLat) * cos($location->radLat) *
|
||||
cos($this->radLon - $location->radLon)) * $radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return double the latitude, in degrees.
|
||||
*/
|
||||
public function getLatitudeInDegrees() {
|
||||
return $this->degLat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return double the longitude, in degrees.
|
||||
*/
|
||||
public function getLongitudeInDegrees() {
|
||||
return $this->degLon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return double the latitude, in radians.
|
||||
*/
|
||||
public function getLatitudeInRadians() {
|
||||
return $this->radLat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return double the longitude, in radians.
|
||||
*/
|
||||
public function getLongitudeInRadians() {
|
||||
return $this->radLon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return double angular radius.
|
||||
*/
|
||||
public function getAngular() {
|
||||
return $this->angular;
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return "(" . $this->degLat . ", " . $this->degLon . ") = (" .
|
||||
$this->radLat . " rad, " . $this->radLon . " rad";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Computes the bounding coordinates of all points on the surface
|
||||
* of a sphere that have a great circle distance to the point represented
|
||||
* by this GeoLocation instance that is less or equal to the distance
|
||||
* argument.</p>
|
||||
* <p>For more information about the formulae used in this method visit
|
||||
* <a href="http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates">
|
||||
* http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates</a>.</p>
|
||||
*
|
||||
* @param double $distance the distance from the point represented by this
|
||||
* GeoLocation instance. Must me measured in the same unit as the radius
|
||||
* argument.
|
||||
* @param string $unit_of_measurement
|
||||
* @throws \Exception
|
||||
* @internal param radius the radius of the sphere, e.g. the average radius for a
|
||||
* spherical approximation of the figure of the Earth is approximately
|
||||
* 6371.01 kilometers.
|
||||
* @return GeoLocation[] an array of two GeoLocation objects such that:<ul>
|
||||
* <li>The latitude of any point within the specified distance is greater
|
||||
* or equal to the latitude of the first array element and smaller or
|
||||
* equal to the latitude of the second array element.</li>
|
||||
* <li>If the longitude of the first array element is smaller or equal to
|
||||
* the longitude of the second element, then
|
||||
* the longitude of any point within the specified distance is greater
|
||||
* or equal to the longitude of the first array element and smaller or
|
||||
* equal to the longitude of the second array element.</li>
|
||||
* <li>If the longitude of the first array element is greater than the
|
||||
* longitude of the second element (this is the case if the 180th
|
||||
* meridian is within the distance), then
|
||||
* the longitude of any point within the specified distance is greater
|
||||
* or equal to the longitude of the first array element
|
||||
* <strong>or</strong> smaller or equal to the longitude of the second
|
||||
* array element.</li>
|
||||
* </ul>
|
||||
*/
|
||||
public function boundingCoordinates($distance, $unit_of_measurement) {
|
||||
$radius = $this->getEarthsRadius($unit_of_measurement);
|
||||
if ($radius < 0 || $distance < 0) throw new \Exception('Arguments must be greater than 0.');
|
||||
|
||||
// angular distance in radians on a great circle
|
||||
$this->angular = $distance / $radius;
|
||||
|
||||
$minLat = $this->radLat - $this->angular;
|
||||
$maxLat = $this->radLat + $this->angular;
|
||||
|
||||
$minLon = 0;
|
||||
$maxLon = 0;
|
||||
if ($minLat > self::$MIN_LAT && $maxLat < self::$MAX_LAT) {
|
||||
$deltaLon = asin(sin($this->angular) /
|
||||
cos($this->radLat));
|
||||
$minLon = $this->radLon - $deltaLon;
|
||||
if ($minLon < self::$MIN_LON) $minLon += 2 * pi();
|
||||
$maxLon = $this->radLon + $deltaLon;
|
||||
if ($maxLon > self::$MAX_LON) $maxLon -= 2 * pi();
|
||||
} else {
|
||||
// a pole is within the distance
|
||||
$minLat = max($minLat, self::$MIN_LAT);
|
||||
$maxLat = min($maxLat, self::$MAX_LAT);
|
||||
$minLon = self::$MIN_LON;
|
||||
$maxLon = self::$MAX_LON;
|
||||
}
|
||||
|
||||
return array(
|
||||
GeoLocation::fromRadians($minLat, $minLon),
|
||||
GeoLocation::fromRadians($maxLat, $maxLon)
|
||||
);
|
||||
}
|
||||
|
||||
protected function getEarthsRadius($unit_of_measurement) {
|
||||
$u = $unit_of_measurement;
|
||||
if($u == 'miles' || $u == 'mi')
|
||||
return $radius = self::EARTHS_RADIUS_MI;
|
||||
elseif($u == 'kilometers' || $u == 'km')
|
||||
return $radius = self::EARTHS_RADIUS_KM;
|
||||
|
||||
else throw new \Exception('You must supply a valid unit of measurement');
|
||||
}
|
||||
/**
|
||||
* Retrieves Geocoding information from Google
|
||||
* eg. $response = GeoLocation::getGeocodeFromGoogle($location);
|
||||
* $latitude = $response->results[0]->geometry->location->lng;
|
||||
* $longitude = $response->results[0]->geometry->location->lng;
|
||||
* @param string $location address, city, state, etc.
|
||||
* @return \stdClass
|
||||
*/
|
||||
public static function getGeocodeFromGoogle($location) {
|
||||
$url = 'http://maps.googleapis.com/maps/api/geocode/json?address='.urlencode($location).'&sensor=false';
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL,$url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
return json_decode(curl_exec($ch));
|
||||
}
|
||||
public static function MilesToKilometers($miles) {
|
||||
return $miles * 1.6093439999999999;
|
||||
}
|
||||
public static function KilometersToMiles($km) {
|
||||
return $km * 0.621371192237334;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue