Geo-related tools PHP 5.4+ library built atop Geocoder and React libraries

Overview

Geotools

Geotools is a PHP geo-related library, built atop Geocoder and React libraries.

Build Status Latest Version Total Downloads Quality Score SensioLabs Insight PHP7 Ready

Features

  • Batch geocode & reverse geocoding request(s) in series / in parallel against one or a set of providers. »
  • Cache geocode & reverse geocoding result(s) with PSR-6 to improve performances. »
  • Compute geocode & reverse geocoding in the command-line interface (CLI) + dumpers and formatters. »
  • Accept almost all kind of WGS84 geographic coordinates as coordinates. »
  • Support 23 different ellipsoids and it's easy to provide a new one if needed. »
  • Convert and format decimal degrees coordinates to decimal minutes or degrees minutes seconds coordinates. »
  • Convert decimal degrees coordinates in the Universal Transverse Mercator (UTM) projection. »
  • Compute the distance in meter (by default), km, mi or ft between two coordinates using flat, great circle, haversine or vincenty algorithms. »
  • Compute the initial and final bearing from the origin coordinate to the destination coordinate in degrees. »
  • Compute the initial and final cardinal point (direction) from the origin coordinate to the destination coordinate, read more in wikipedia. »
  • Compute the half-way point (coordinate) between the origin and the destination coordinates. »
  • Compute the destination point (coordinate) with given bearing in degrees and a distance in meters. »
  • Encode a coordinate to a geo hash string and decode it to a coordinate, read more in wikipedia and on geohash.org. »
  • Encode a coordinate via the 10:10 algorithm. »
  • Polygon class provides methods to check either a poing (coordinate) is in, or on the polygon's boundaries. »
  • A command-line interface (CLI) for Distance, Point, Geohash and Convert classes. »
  • Integration with Frameworks: Laravel 4, Silex ... »
  • ... more to come ...

Installation

Geotools can be found on Packagist. The recommended way to install Geotools is through composer.

Run the following on the command line:

php composer require league/[email protected]

Protip: you should browse the league/geotools page to choose a stable version to use, avoid the @stable meta constraint.

Important: you should use the 0.4 version if you use Geocoder 2.x or/and PHP 5.3.

And install dependencies:

$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar install

Now you can add the autoloader, and you will have access to the library:

<?php

require 'vendor/autoload.php';

Usage & API

Coordinate & Ellipsoid

The default geodetic datum is WGS84 and coordinates are in decimal degrees.

Here are the available ellipsoids: AIRY, AUSTRALIAN_NATIONAL, BESSEL_1841, BESSEL_1841_NAMBIA, CLARKE_1866, CLARKE_1880, EVEREST, FISCHER_1960_MERCURY, FISCHER_1968, GRS_1967, GRS_1980, HELMERT_1906, HOUGH, INTERNATIONAL, KRASSOVSKY, MODIFIED_AIRY, MODIFIED_EVEREST, MODIFIED_FISCHER_1960, SOUTH_AMERICAN_1969, WGS60, WGS66, WGS72, and WGS84.

If you need to use an other ellipsoid, just create an array like this:

<?php

$myEllipsoid = \League\Geotools\Coordinate\Ellipsoid::createFromArray([
    'name' => 'My Ellipsoid', // The name of the Ellipsoid
    'a'    => 123.0, // The semi-major axis (equatorial radius) in meters
    'invF' => 456.0 // The inverse flattening
]);

Geotools is built atop Geocoder. It means it's possible to use the \Geocoder\Model\Address directly but it's also possible to use a string or a simple array with its latitude and longitude.

It supports valid and acceptable geographic coordinates like:

  • 40:26:46N,079:56:55W
  • 40:26:46.302N 079:56:55.903W
  • 40°26′47″N 079°58′36″W
  • 40d 26′ 47″ N 079d 58′ 36″ W
  • 40.446195N 79.948862W
  • 40.446195, -79.948862
  • 40° 26.7717, -79° 56.93172

Latitudes below -90.0 or above 90.0 degrees are capped through \League\Geotools\Coordinate\Coordinate::normalizeLatitude().
Longitudes below -180.0 or above 180.0 degrees are wrapped through \League\Geotools\Coordinate\Coordinate::normalizeLongitude().

<?php

use League\Geotools\Coordinate\Coordinate;
use League\Geotools\Coordinate\Ellipsoid;

// from an \Geocoder\Model\Address instance within Airy ellipsoid
$coordinate = new Coordinate($geocoderResult, Ellipsoid::createFromName(Ellipsoid::AIRY));
// or in an array of latitude/longitude coordinate within GRS 1980 ellipsoid
$coordinate = new Coordinate([48.8234055, 2.3072664], Ellipsoid::createFromName(Ellipsoid::GRS_1980));
// or in latitude/longitude coordinate within WGS84 ellipsoid
$coordinate = new Coordinate('48.8234055, 2.3072664');
// or in degrees minutes seconds coordinate within WGS84 ellipsoid
$coordinate = new Coordinate('48°49′24″N, 2°18′26″E');
// or in decimal minutes coordinate within WGS84 ellipsoid
$coordinate = new Coordinate('48 49.4N, 2 18.43333E');
// the result will be:
printf("Latitude: %F\n", $coordinate->getLatitude()); // 48.8234055
printf("Longitude: %F\n", $coordinate->getLongitude()); // 2.3072664
printf("Ellipsoid name: %s\n", $coordinate->getEllipsoid()->getName()); // WGS 84
printf("Equatorial radius: %F\n", $coordinate->getEllipsoid()->getA()); // 6378136.0
printf("Polar distance: %F\n", $coordinate->getEllipsoid()->getB()); // 6356751.317598
printf("Inverse flattening: %F\n", $coordinate->getEllipsoid()->getInvF()); // 298.257224
printf("Mean radius: %F\n", $coordinate->getEllipsoid()->getArithmeticMeanRadius()); // 6371007.772533
// it's also possible to modify the coordinate without creating an other coodinate
$coordinate->setFromString('40°26′47″N 079°58′36″W');
printf("Latitude: %F\n", $coordinate->getLatitude()); // 40.446388888889
printf("Longitude: %F\n", $coordinate->getLongitude()); // -79.976666666667

Convert

It provides methods (and aliases) to convert decimal degrees WGS84 coordinates to degrees minutes seconds or decimal minutes WGS84 coordinates. You can format the output string easily.

You can also convert them in the Universal Transverse Mercator (UTM) projection (Southwest coast of Norway and the region of Svalbard are covered).

<?php

$geotools   = new \League\Geotools\Geotools();
$coordinate = new \League\Geotools\Coordinate\Coordinate('40.446195, -79.948862');
$converted  = $geotools->convert($coordinate);
// convert to decimal degrees without and with format string
printf("%s\n", $converted->toDecimalMinutes()); // 40 26.7717N, -79 56.93172W
printf("%s\n", $converted->toDM('%P%D°%N %p%d°%n')); // 40°26.7717 -79°56.93172
// convert to degrees minutes seconds without and with format string
printf("%s\n", $converted->toDegreesMinutesSeconds('<p>%P%D:%M:%S, %p%d:%m:%s</p>')); // <p>40:26:46, -79:56:56</p>
printf("%s\n", $converted->toDMS()); // 40°26′46″N, 79°56′56″W
// convert in the UTM projection (standard format)
printf("%s\n", $converted->toUniversalTransverseMercator()); // 17T 589138 4477813
printf("%s\n", $converted->toUTM()); // 17T 589138 4477813 (alias)

Here is the mapping:

Decimal minutes Latitude Longitude
Positive or negative sign %P %p
Direction %L %l
Degrees %D %d
Decimal minutes %N %n
Degrees minutes seconds Latitude Longitude
Positive or negative sign %P %p
Direction %L %l
Degrees %D %d
Minutes %M %m
Seconds %S %s

Batch

It provides a very handy way to batch geocode and reverse geocoding requests in serie or in parallel against a set of providers.
Thanks to Geocoder and React libraries.

It's possible to batch one request (a string) or a set of request (an array) against one provider or set of providers.

You can use a provided cache engine or use your own by setting a cache object which should implement League\Geotools\Cache\CacheInterface and extend League\Geotools\Cache\AbstractCache if needed.

At the moment Geotools supports any PSR-6 cache.

NB: Before you implement caching in your app please be sure that doing so does not violate the Terms of Service for your(s) geocoding provider(s).

<?php

$geocoder = new \Geocoder\ProviderAggregator(); // or \Geocoder\TimedGeocoder
$httpClient  = HttpClientDiscovery:::find();

$geocoder->registerProviders([
    new \Geocoder\Provider\GoogleMaps\GoogleMaps($httpClient),
    new \Geocoder\Provider\OpenStreetMap\OpenStreetMap($httpClient),
    new \Geocoder\Provider\BingMaps\BingMaps($httpClient, '<FAKE_API_KEY>'), // throws InvalidCredentialsException
    new \Geocoder\Provider\Yandex\Yandex($httpClient),
    new \Geocoder\Provider\FreeGeoIp\FreeGeoIp($httpClient),
    new \Geocoder\Provider\Geoip\Geoip(),
]);

try {
    $geotools = new \League\Geotools\Geotools();
    $cache    = new \Cache\Adapter\PHPArray\ArrayCachePool();
  
    $results  = $geotools->batch($geocoder)->setCache($cache)->geocode([
        'Paris, France',
        'Copenhagen, Denmark',
        '74.200.247.59',
        '::ffff:66.147.244.214'
    ])->parallel();
} catch (\Exception $e) {
    die($e->getMessage());
}

$dumper = new \Geocoder\Dumper\WktDumper();
foreach ($results as $result) {
    // if a provider throws an exception (UnsupportedException, InvalidCredentialsException ...)
    // an custom /Geocoder/Result/Geocoded instance is returned which embedded the name of the provider,
    // the query string and the exception string. It's possible to use dumpers
    // and/or formatters from the Geocoder library.
    printf("%s|%s|%s\n",
        $result->getProviderName(),
        $result->getQuery(),
        '' == $result->getExceptionMessage() ? $dumper->dump($result) : $result->getExceptionMessage()
    );
}

You should get 24 results (4 values to geocode against 6 providers) something like:

google_maps|Paris, France|POINT(2.352222 48.856614)
google_maps|Copenhagen, Denmark|POINT(12.568337 55.676097)
google_maps|74.200.247.59|The GoogleMapsProvider does not support IP addresses.
google_maps|::ffff:66.147.244.214|The GoogleMapsProvider does not support IP addresses.
openstreetmaps|Paris, France|POINT(2.352133 48.856506)
openstreetmaps|Copenhagen, Denmark|POINT(12.570072 55.686724)
openstreetmaps|74.200.247.59|Could not execute query http://nominatim.openstreetmap.org/search?q=74.200.247.59&format=xml&addressdetails=1&limit=1
openstreetmaps|::ffff:66.147.244.214|The OpenStreetMapProvider does not support IPv6 addresses.
bing_maps|Paris, France|Could not execute query http://dev.virtualearth.net/REST/v1/Locations/?q=Paris%2C+France&key=<FAKE_API_KEY>
bing_maps|Copenhagen, Denmark|Could not execute query http://dev.virtualearth.net/REST/v1/Locations/?q=Copenhagen%2C+Denmark&key=<FAKE_API_KEY>
bing_maps|74.200.247.59|The BingMapsProvider does not support IP addresses.
bing_maps|::ffff:66.147.244.214|The BingMapsProvider does not support IP addresses.
yandex|Paris, France|POINT(2.341198 48.856929)
yandex|Copenhagen, Denmark|POINT(12.567602 55.675682)
yandex|74.200.247.59|The YandexProvider does not support IP addresses.
yandex|::ffff:66.147.244.214|The YandexProvider does not support IP addresses.
free_geo_ip|Paris, France|The FreeGeoIpProvider does not support Street addresses.
free_geo_ip|Copenhagen, Denmark|The FreeGeoIpProvider does not support Street addresses.
free_geo_ip|74.200.247.59|POINT(-122.415600 37.748400)
free_geo_ip|::ffff:66.147.244.214|POINT(-111.613300 40.218100)
geoip|Paris, France|The GeoipProvider does not support Street addresses.
geoip|Copenhagen, Denmark|The GeoipProvider does not support Street addresses.
geoip|74.200.247.59|POINT(-122.415604 37.748402)
geoip|::ffff:66.147.244.214|The GeoipProvider does not support IPv6 addresses.

Batch reverse geocoding is something like:

<?php

// ... $geocoder like the previous example ...
// If you want to reverse one coordinate
try {
    $results = $geotools->batch($geocoder)->reverse(
        new \League\Geotools\Coordinate\Coordinate([2.307266, 48.823405])
    )->parallel();
} catch (\Exception $e) {
    die($e->getMessage());
}
// Or if you want to reverse geocoding 3 coordinates
$coordinates = [
    new \League\Geotools\Coordinate\Coordinate([2.307266, 48.823405]),
    new \League\Geotools\Coordinate\Coordinate([12.568337, 55.676097]),
    new \League\Geotools\Coordinate\Coordinate('-74.005973 40.714353')),
];
$results = $geotools->batch($geocoder)->reverse($coordinates)->parallel();
// ...

If you want to batch it in serie, replace the method parallel() by serie().

To optimize batch requests you need to register providers according to their capabilities and what you're looking for (geocode street addresses, geocode IPv4, geocode IPv6 or reverse geocoding), please read more at the Geocoder library doc.

Distance

It provides methods to compute the distance in meter (by default), km, mi or ft between two coordinates using flat (most performant), great circle, haversine or vincenty (most accurate) algorithms.

Those coordinates should be in the same ellipsoid.

<?php

$geotools = new \League\Geotools\Geotools();
$coordA   = new \League\Geotools\Coordinate\Coordinate([48.8234055, 2.3072664]);
$coordB   = new \League\Geotools\Coordinate\Coordinate([43.296482, 5.36978]);
$distance = $geotools->distance()->setFrom($coordA)->setTo($coordB);

printf("%s\n",$distance->flat()); // 659166.50038742 (meters)
printf("%s\n",$distance->greatCircle()); // 659021.90812846
printf("%s\n",$distance->in('km')->haversine()); // 659.02190812846
printf("%s\n",$distance->in('mi')->vincenty()); // 409.05330679648
printf("%s\n",$distance->in('ft')->flat()); // 2162619.7519272

Point

It provides methods to compute the initial and final bearing in degrees, the initial and final cardinal direction, the middle point and the destination point. The middle and the destination points returns a \League\Geotools\Coordinate\Coordinate object with the same ellipsoid.

<?php

$geotools = new \League\Geotools\Geotools();
$coordA   = new \League\Geotools\Coordinate\Coordinate([48.8234055, 2.3072664]);
$coordB   = new \League\Geotools\Coordinate\Coordinate([43.296482, 5.36978]);
$vertex    =  $geotools->vertex()->setFrom($coordA)->setTo($coordB);

printf("%d\n", $vertex->initialBearing()); // 157 (degrees)
printf("%s\n", $vertex->initialCardinal()); // SSE (SouthSouthEast)
printf("%d\n", $vertex->finalBearing()); // 160 (degrees)
printf("%s\n", $vertex->finalCardinal()); // SSE (SouthSouthEast)

$middlePoint = $vertex->middle(); // \League\Geotools\Coordinate\Coordinate
printf("%s\n", $middlePoint->getLatitude()); // 46.070143125815
printf("%s\n", $middlePoint->getLongitude()); // 3.9152401085931

$destinationPoint = $geotools->vertex()->setFrom($coordA)->destination(180, 200000); // \League\Geotools\Coordinate\Coordinate
printf("%s\n", $destinationPoint->getLatitude()); // 47.026774650075
printf("%s\n", $destinationPoint->getLongitude()); // 2.3072664

Geohash

It provides methods to get the geo hash and its bounding box's coordinates (SouthWest & NorthEast) of a coordinate and the coordinate and its bounding box's coordinates (SouthWest & NorthEast) of a geo hash.

<?php

$geotools       = new \League\Geotools\Geotools();
$coordToGeohash = new \League\Geotools\Coordinate\Coordinate('43.296482, 5.36978');

// encoding
$encoded = $geotools->geohash()->encode($coordToGeohash, 4); // 12 is the default length / precision
// encoded
printf("%s\n", $encoded->getGeohash()); // spey
// encoded bounding box
$boundingBox = $encoded->getBoundingBox(); // array of \League\Geotools\Coordinate\CoordinateInterface
$southWest   = $boundingBox[0];
$northEast   = $boundingBox[1];
printf("http://www.openstreetmap.org/?minlon=%s&minlat=%s&maxlon=%s&maxlat=%s&box=yes\n",
    $southWest->getLongitude(), $southWest->getLatitude(),
    $northEast->getLongitude(), $northEast->getLatitude()
); // http://www.openstreetmap.org/?minlon=5.2734375&minlat=43.2421875&maxlon=5.625&maxlat=43.41796875&box=yes

// decoding
$decoded = $geotools->geohash()->decode('spey61y');
// decoded coordinate
printf("%s\n", $decoded->getCoordinate()->getLatitude()); // 43.296432495117
printf("%s\n", $decoded->getCoordinate()->getLongitude()); // 5.3702545166016
// decoded bounding box
$boundingBox = $decoded->getBoundingBox(); //array of \League\Geotools\Coordinate\CoordinateInterface
$southWest   = $boundingBox[0];
$northEast   = $boundingBox[1];
printf("http://www.openstreetmap.org/?minlon=%s&minlat=%s&maxlon=%s&maxlat=%s&box=yes\n",
    $southWest->getLongitude(), $southWest->getLatitude(),
    $northEast->getLongitude(), $northEast->getLatitude()
); // http://www.openstreetmap.org/?minlon=5.3695678710938&minlat=43.295745849609&maxlon=5.3709411621094&maxlat=43.297119140625&box=yes

10:10

Represent a location with 10m accuracy using a 10 character code that includes features to prevent errors in entering the code. Read more about the algorithm here.

<?php

$tenten = new \League\Geotools\Tests\Geohash\TenTen;
$tenten->encode(new Coordinate([51.09559, 1.12207])); // MEQ N6G 7NY5

Vertex

Represents a segment with a direction. You can find if two vertexes are on the same line.

<?php
	$vertexA->setFrom(48.8234055);
	$vertexA->setTo(2.3072664);

	$vertexB->setFrom(48.8234055);
	$vertexB->setTo(2.3072664);
	$vertexA->isOnSameLine($vertexB);

Polygon

It helps you to know if a point (coordinate) is in a Polygon or on the Polygon's boundaries and if this in on a Polygon's vertex.

First you need to create the polygon, you can provide:

  • an array of arrays
  • an array of Coordinate
  • a CoordinateCollection
<?php

$polygon = new \League\Geotools\Polygon\Polygon([
    [48.9675969, 1.7440796],
    [48.4711003, 2.5268555],
    [48.9279131, 3.1448364],
    [49.3895245, 2.6119995],
]);

$polygon->setPrecision(5); // set the comparision precision
$polygon->pointInPolygon(new \League\Geotools\Coordinate\Coordinate([49.1785607, 2.4444580])); // true
$polygon->pointInPolygon(new \League\Geotools\Coordinate\Coordinate([49.1785607, 5])); // false
$polygon->pointOnBoundary(new \League\Geotools\Coordinate\Coordinate([48.7193486, 2.13546755])); // true
$polygon->pointOnBoundary(new \League\Geotools\Coordinate\Coordinate([47.1587188, 2.87841795])); // false
$polygon->pointOnVertex(new \League\Geotools\Coordinate\Coordinate([48.4711003, 2.5268555])); // true
$polygon->pointOnVertex(new \League\Geotools\Coordinate\Coordinate([49.1785607, 2.4444580])); // false
$polygon->getBoundingBox(); // return the BoundingBox object

CLI

It provides command lines to compute methods provided by Distance, Point, Geohash and Convert classes. Thanks to the Symfony Console Component.

$ php geotools list // list of available commands
$ php geotools help distance:flat // get the help
$ php geotools distance:flat "40° 26.7717, -79° 56.93172" "30°16′57″N 029°48′32″W" // 4690203.1048522
$ php geotools distance:haversine "35,45" "45,35" --ft  // 4593030.9787593
$ php geotools distance:vincenty "35,45" "45,35" --km  // 1398.4080717661
$ php geotools d:v "35,45" "45,35" --km --ellipsoid=WGS60 // 1398.4145201642
$ php geotools point:initial-cardinal "40:26:46.302N 079:56:55.903W" "43.296482, 5.36978" // NE (NordEast)
$ php geotools point:final-cardinal "40:26:46.302N 079:56:55.903W" "43.296482, 5.36978" // ESE (EastSouthEast)
$ php geotools point:destination "40° 26.7717, -79° 56.93172" 25 10000 // 40.527599285543, -79.898914904538
$ php geotools p:d "40° 26.7717, -79° 56.93172" 25 10000 --ellipsoid=GRS_1980 // 40.527599272782, -79.898914912379
$ php geotools geohash:encode "40° 26.7717, -79° 56.93172" --length=3 // dpp
$ php geotools convert:dm "40.446195, -79.948862" --format="%P%D°%N %p%d°%n" // 40°26.7717 -79°56.93172
$ php geotools convert:dms "40.446195, -79.948862" --format="%P%D:%M:%S, %p%d:%m:%s" // 40:26:46, -79:56:56
$ php geotools convert:utm "60.3912628, 5.3220544" // 32V 297351 6700644
$ php geotools c:u "60.3912628, 5.3220544" --ellipsoid=AIRY // 32V 297371 6700131
...

Compute street addresses, IPv4s or IPv6s geocoding and reverse geocoding right in your console.

It's possible to define and precise your request through these options:

  • --provider: bing_maps, yahoo, maxmind... google_maps is the default one. See the full list here.
  • --raw: the result output in RAW format, shows Adapter, Provider and Arguments if any.
  • --json: the result output in JSON string format.
  • --args: this option accepts multiple values (e.g. --args="API_KEY" --args="LOCALE") if your provider needs or can have arguments.
  • --dumper: this option is available for geocoding, gpx, geojson, kml, wkb and wkt by default. Read more here.
  • --format: this option is available for reverse geocoding, see the mapping here.
$ php geotools help geocoder:geocode // get the help
$ php geotools geocoder:geocode "Copenhagen, Denmark" // 55.6760968, 12.5683371
$ php geotools geocoder:geocode "74.200.247.59" --provider="free_geo_ip" // 37.7484, -122.4156
$ php geotools geocoder:geocode Paris --args="fr_FR" --args="France" --args="true" // 48.856614, 2.3522219
$ php geotools geocoder:geocode Paris --dumper=wkt // POINT(2.352222 48.856614)
...
$ php geotools geocoder:reverse "48.8631507, 2.388911" // Avenue Gambetta 10, 75020 Paris
$ php geotools geocoder:reverse "48.8631507, 2.388911" --format="%L, %A1, %C" // Paris, Île-De-France, France
$ php geotools geocoder:reverse "48.8631507, 2.388911" --format="%L, %A1, %C" --provider="openstreetmaps"
// Paris, Île-De-France, France Métropolitaine
...
$ php geotools geocoder:geocode "Tagensvej 47, Copenhagen" --raw --args=da_DK --args=Denmark

The last command will show an output like this:

HttpClient:    \Http\Client\Curl\Client
Provider:      \Geocoder\Provider\GoogleMaps
Cache:         \League\Geotools\Cache\Redis
Arguments:     da_DK,Denmark
---
Latitude:      55.699953
Longitude:     12.552736
Bounds
 - South: 55.699953
 - West:  12.552736
 - North: 55.699953
 - East:  12.552736
Street Number: 47
Street Name:   Tagensvej
Zipcode:       2200
City:          Copenhagen
City District: København N
County:        København
County Code:   KØBENHAVN
Region:        Capital Region Of Denmark
Region Code:   CAPITAL REGION OF DENMARK
Country:       Denmark
Country Code:  DK
Timezone:

Integration with Frameworks

Unit Tests

To run unit tests, you'll need the cURL extension and a set of dependencies, you can install them using Composer:

$ php composer.phar install --dev

Once installed, just launch the following command:

$ phpunit --coverage-text

Credits

Acknowledgments

Changelog

See the changelog file

Contributing

Please see CONTRIBUTING for details.

Support

Bugs and feature request are tracked on GitHub

Contributor Code of Conduct

As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.

Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.

This Code of Conduct is adapted from the Contributor Covenant, version 1.0.0, available at http://contributor-covenant.org/version/1/0/0/

License

Geotools is released under the MIT License. See the bundled LICENSE file for details.

Bitdeli Badge

Comments
  • Fix typeerror due to locale decimal separator

    Fix typeerror due to locale decimal separator

    This pull request fixes a TypeError when using a locale that uses decimal comma as decimal separator.

    // Example that triggers error when locale is set to Swedish (sv_SE):
    
    $firstLocation = new \League\Geotools\Coordinate\Coordinate(["59.3293235", "18.0685808"]);
    $secondLocation = new \League\Geotools\Coordinate\Coordinate(["59.646492", "17.937797"]);
    
    $geotools = new \League\Geotools\Geotools();
    $distanceBetweenLocations = $geotools->distance()->setFrom($firstLocation)->setTo($secondLocation);
    
    // This line causes error "deg2rad(): Argument #1 ($num) must be of type float, string given"
    echo "Distance: " . $distanceBetweenLocations->flat();
    

    The error is probably caused by the usage of sprintf in for example method
    normalizeLatitude($latitude): $latitude = rtrim(sprintf('%.13f', max(-90, min(90, $latitude))), 0); According to https://www.php.net/manual/en/function.sprintf.php the f specifier is locale aware. However the F specifier is non-locale aware so I think it should be sufficient to switch to that.

    Minimal test that shows the difference when using different locales:

      
    $ php -r "setlocale(LC_ALL, 'en_US'); echo rtrim(sprintf('%.13f', max(-90, min(90, '59.3293235'))), 0);"
    
    Output: 59.3293235
    
    $ php -r "setlocale(LC_ALL, 'sv_SE'); echo rtrim(sprintf('%.13f', max(-90, min(90, '59.3293235'))), 0);"
    
    Output: 59,3293235
    
    
    opened by bonny 12
  • Upgrade to PHP >= 7.3 and PHPUnit 8.5

    Upgrade to PHP >= 7.3 and PHPUnit 8.5

    Hello,

    Here is an upgrade of geotools and a new format of coordinates frequently used.

    Please review this PR. I'd like to use it without create my own fork. Maybe you can release as 1.0.0 (It's a breaking change I think)

    opened by Surfoo 12
  • Please release a new version

    Please release a new version

    Hi,

    The last release of this library is more than a year old, though many commits have been made to it since then. That was why I was using dev-master as a dependency. This unfortunately meant that the upgrade to geocoder 4.0 broke my application. Does this library follow semver? Most League packages do that right? That would have prevented this.

    If you could release more often it would be great :)

    opened by ChrisTitos 10
  • "Point" terminology

    An instance of the Point class has an origin and a destination coordinate. This seems like poor naming, as in most GIS implementations (and semantically) a point has exactly 1 coordinate.

    Having a quick Google around, either MultiPoint or Line would make more sense, although these are generally not limited to 2 coordinates.

    Maybe I'm viewing the class wrongly and it shouldn't be thought of a value object at all but a coordinate service / calculator. In that case perhaps Point should be in a different namespace that implies it's a tool rather than a value object, which is what Convert does.

    Feel free to close as wontfix, as I guess "geotools" implies that this is a collection of tools, as opposed to a component to drop into the business domain.

    enhancement BC break 
    opened by dave1010 9
  • Suppress deprecation warnings on PHP 8.1

    Suppress deprecation warnings on PHP 8.1

    I was getting all sorts of deprecation warnings on PHP 8.1.4. I've just implemented a "fix" similar to how you've previously handled deprecation notices on the jsonSerialize method.

    opened by BillyMorgan 6
  • composer error for symfony serializer (sf 3.0.1)

    composer error for symfony serializer (sf 3.0.1)

    composer update gives mu such error while updating to sf 3.0.1

    league/geotools 0.6.0 requires symfony/serializer ~2.7 -> satisfiable by symfony/symfony[v2.7.9], symfony/serializer[v2.7.0, v2.7.1, v2.7.2, v2.7.3, v2.7.4, v2.7.5, v2.7.6, v2.7.7, v2.7.8, v2.7.9, v2.8.0, v2.8.1, v2.8.2].
        - Can only install one of: symfony/symfony[v3.0.0, v2.7.9].
    
    opened by Venzon 6
  • Updated react/event-loop to stable version

    Updated react/event-loop to stable version

    Fixes #130.

    • I've updated react/event-loop to stable version.
    • Dropped support for unmaintainted PHP versions, updated travis config accordingly

    And some other small improvements:

    • Removed unused imports
    • Fixed typos in documentation
    • FQCN in unit tests
    • Added ext-json as a requirement
    opened by stephanvierkant 5
  • How to find out who provided geolocation using ChainProvider

    How to find out who provided geolocation using ChainProvider

    Hi, can I find out which provider provided geolocation for each address when I use ChainProvider? When I try something like this:

    $geocoder->registerProvider(new ChainProvider(array(
        new GoogleMapsProvider($adapter, null, null, true, $this->googleApiKey),
        new MapQuestProvider($adapter, $this->mapQuestKey),
        new YandexProvider($adapter),
        new NominatimProvider($adapter, 'http://nominatim.openstreetmap.org'),
    )));
    $geotools = new \League\Geotools\Geotools();
    $geocoded = $geotools->batch($geocoder)->geocode($locationsToSave)->parallel();
    foreach ($geocoded as $g) {
        echo $g->provider;
    }
    

    I get only "chain" for all addresses. And I'm not sure if it is bug or feature. ;o)

    Thanks.

    opened by JakubMatejka 5
  • Possibly use a cache in the CLI for geocoder

    Possibly use a cache in the CLI for geocoder

    I would love to see an option (on by default?) to use a cache in the CLI for geocoder.

    geotools --cache=yes geocoder:geocode "My Favorite Hiding Place"

    enhancement 
    opened by Fil 5
  • Distance setFrom Error

    Distance setFrom Error

    Hello there,

    i have some trouble calculating the distance between two points. Currently i'm using the latest version of this library in a project for tracking GPS devices. I want to filter out all coordinates, that are roughly in the same space. So i tried to implement the example into my app, only to get an error message. I also tried it in a plain PHP file with the same result.

    Error: Fatal error: Uncaught TypeError: Argument 1 passed to Geotools\Distance\Distance::setFrom() must implement interface Geotools\Coordinate\CoordinateInterface, null given, called in C:\Users\ferdi\Projekte\php\laravel\topas-tracker\vendor\league\geotools\src\Geotools\Geotools.php on line 66 and defined in C:\Users\ferdi\Projekte\php\laravel\topas-tracker\vendor\league\geotools\src\Geotools\Distance\Distance.php:35 Stack trace: #0 C:\Users\ferdi\Projekte\php\laravel\topas-tracker\vendor\league\geotools\src\Geotools\Geotools.php(66): Geotools\Distance\Distance->setFrom(NULL) #1 C:\Users\ferdi\Projekte\php\laravel\topas-tracker\geotools-test.php(8): Geotools\Geotools->distance(Object(Geotools\Coordinate\Coordinate), Object(Geotools\Coordinate\Coordinate)) #2 {main} thrown in C:\Users\ferdi\Projekte\php\laravel\topas-tracker\vendor\league\geotools\src\Geotools\Distance\Distance.php on line 35

    The plain PHP example looks like this:

    `require 'vendor/autoload.php';

    $geotools = new \Geotools\Geotools(); $coordA = new \Geotools\Coordinate\Coordinate([48.8234055, 2.3072664]); $coordB = new \Geotools\Coordinate\Coordinate([43.296482, 5.36978]); $distance = $geotools->distance($coordA, $coordB);

    printf("%s\n",$distance->flat()); // 659166.50038742 (meters) `

    Any suggestion? Thanks.

    opened by blindpenguin 4
  • Cache adapter for Credis library

    Cache adapter for Credis library

    A lot of Magento 1 projects use the Credis library, due its use as a cache and sessions backend in popular extensions that are now included in its core. It would be nice if there was an adapter for Credis to sit alongside the Predis adapter, so that an existing Credis_Client object could be passed in and used as a cache.

    See https://github.com/colinmollenhour/credis

    I am happy to develop this adapter, and am mostly putting this forward to discuss what the name of the class for this adapter should be so as to avoid naming conflicts with the existing Predis adapter.

    feature 
    opened by djmattyg007 4
  • php composer require league/geotools=@stable?

    php composer require league/[email protected]?

    Is that really the recommended way to install? Shouldn't the user simply set minimum-stability and prefer-stable in composer.json?

    In the github workflow tools, I'm getting this warning:

    Run composer validate
    ./composer.json is valid for simple usage with Composer but has
    strict errors that make it unable to be published as a package
    See https://getcomposer.org/doc/04-schema.md for details on the schema
    # Publish errors
    # General warnings
    - require.league/geotools : unbound version constraints (@stable) should be avoided
    

    Great tools, thanks for publishing them. I'm just wondering why the non-standard installation instructions, works fine without the stable reference.

    opened by tacman 0
  • calculate center and radius of polygon?

    calculate center and radius of polygon?

    Is it possible / are there plans to keep track of the center and radius of a polygon?

    My use case:

    1. first: keep adding coordinates to end of polygon until certain radius is exceeded
    2. then: keep removing coordinates from start of polygon until radius is within defined limit

    For this I need to calculate the weighted center of the current polygon (not: average of the bounding box) and the radius of the coordinates.

    Bonus points when average is calculated by keeping track of the sums of x/y/z (and dividing by number of coordinates) instead of calculating/adding all x/y/z's when center is calculated.

    opened by wivaku 2
  • Call to undefined method Geotools\Geotools::vertex()

    Call to undefined method Geotools\Geotools::vertex()

    I've got this when incorporating this lib with my laravel project

    use Geotools\Geotools;
    use Geotools\Coordinate\Coordinate;
    
    $geoTools = new Geotools();
    $coordinate = new Coordinate([$lat, $long]);
    
    $geoTools->vertex()->setFrom($coordinate)->destination(1111, 2222);
    
    opened by handhikadj 0
  • Extract points to some distance origin to destination?

    Extract points to some distance origin to destination?

    Let say I have set of latitudes and longitude points which would be shaped as line on map which have total distance 20 km.

    I want to extract only cordinate from 0 km point to 4 km so it will result by generating new set of lat-long points. In others case I need to extract from 3 km to 6 km.

    How can I implement it with this library?

    Thank you.

    opened by navotera 1
  • Vector bearing returns integer

    Vector bearing returns integer

    The 2 methods of Vector class returns integer instead of float value.

    public function initialBearing()
        {
            Ellipsoid::checkCoordinatesEllipsoid($this->from, $this->to);
    
            $latA = deg2rad($this->from->getLatitude());
            $latB = deg2rad($this->to->getLatitude());
            $dLng = deg2rad($this->to->getLongitude() - $this->from->getLongitude());
    
            $y = sin($dLng) * cos($latB);
            $x = cos($latA) * sin($latB) - sin($latA) * cos($latB) * cos($dLng);
    
            return (float) (rad2deg(atan2($y, $x)) + 360) % 360;
        }
    

    Using % with float variables cast it to integer losing a lot of precision. If u want an angle between 0 and 360 you can do something like this

    $angle = rad2deg(atan2($y, $x)) + 360;
    return $angle > 360 ? $angle - 360 : $angle;
    
    opened by luppiale 0
Releases(1.1.0)
  • 1.1.0(Oct 26, 2022)

  • 1.0.0(Feb 11, 2022)

    Fixed

    • greatCircle calculator returned NAN #159
    • Suppressed deprecation warning for JsonSerializable in PHP 8.1 #167
    • Added floor on implicit float to in conversion #166
    • Haversine distance calculation #158

    Added

    • New coordinate format "Degree Decimal Minutes" available with toDegreeDecimalMinutes() [BC break]
    • Support PHP 8.1
    • Support Symfony 6, removed Symfony 3.4

    Change

    • Increased precision of initialBearing() and finalBearing()
    Source code(tar.gz)
    Source code(zip)
  • 0.8.3(Jul 7, 2021)

  • 0.8.2(Feb 2, 2021)

    • Fix namespace issue when creating provider class name (#125)
    • Upgrade to PHP >= 7.3 and PHPUnit 8.5 (#138)
    • Allow PHP8 & Fix PHPUnit deprecations (#146)
    Source code(tar.gz)
    Source code(zip)
  • 0.8.1(Jan 30, 2020)

  • 0.8.0(Feb 22, 2018)

  • 0.7.0(Feb 3, 2016)

    • [BC break] Updated: Point is now Vertex everywhere
    • Updated: use Predis 1.0 version
    • Updated: tests against PHP7
    • Updated: documentation and badges
    • Added: allow Symfony console, property-access and serializer ~3.0

    Thanks to all contributors!

    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(Oct 11, 2015)

    If you use the cache layer please update to this version.

    • Fixed: cache layer: Redis, Memcached and MongoDB
    • Added: cache possibility in CLI
    • Added: 10:10 algorithm
    • Updated: symfony console, serializer and property-access to ~2.7
    Source code(tar.gz)
    Source code(zip)
  • 0.5.0(Oct 10, 2015)

    • [BC breaks] Updated: use Geocoder 3.x / @morrislaptop
    • Added: Polygon class / @gabrielbull
    • Added: Bounding box class / @gabrielbull
    • Fixed: division by zero in vincenty algorithm / @tix
    • [BC breaks] Dropped: PHP 5.3 and stub to JsonSerializable
    • [BC breaks] Updated: switch from async to promise / @morrislaptop
    • Updated: documentation / @caseyw @brandonsavage @BreiteSeite @GrahamCampbell
    • Added: code of conduct

    NOTE: If you still use Geocoder 2.x and/or PHP 5.3 please use the Geotools 0.4!

    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Jul 30, 2014)

  • 0.3.3(May 16, 2014)

    • Fixed: HHVM compatible tested on HipHop VM 3.1.0-dev+2014.05.15
    • Added: falling tests in Distance with same coordinates (@kornrunner)
    • Fixed: division by zero in computing distance between 2 identical coordinates (@kornrunner)
    • Added: setFromString method to create and modify coordinate + doc - fix #31
    • Fixed: coordinate parsing issue
    Source code(tar.gz)
    Source code(zip)
  • 0.3.2(Mar 15, 2014)

    • Updated: geotools CLI moved in bin folder
    • Updated: use Geocoder 2.4.x
    • Added: great circle formula and CLI + tests
    • Added: test against php 5.6
    • Updated: repo name
    • Added: coverage and scrutinizer-ci badges
    • Updated: organisation name
    • Added: test against HHVM
    Source code(tar.gz)
    Source code(zip)
  • 0.3.1(Nov 16, 2013)

    • Updated: use Geocoder 2.3.x
    • Updated: use SensioLabs Insight
    • Updated: documentation
    • Fixed: travis, packagist and sensiolabs insight badges
    • Fixed: tests
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Jul 19, 2013)

    Changes:

    • Updated: loep (The League of Extraordinary Packages) is now owner - BC break
    • Updated: use Geocoder 2.0.0

    Upgrade: basically you just need to add League\ before Geotools' namespaces.

    NB: if you need to use an older version like 0.2.4 for instance, install or update packages with --prefer-source option.

    Source code(tar.gz)
    Source code(zip)
Owner
The League of Extraordinary Packages
A group of developers who have banded together to build solid, well tested PHP packages using modern coding standards.
The League of Extraordinary Packages
Simple Yet Powerful Geo Library for PHP

phpgeo - A Simple Geo Library for PHP phpgeo provides abstractions to geographical coordinates (including support for different ellipsoids) and allows

Marcus Jaschen 1.4k Nov 27, 2022
PHP library to easily get static image from French Cadastral Government map with markers and lines.

PHP French Cadastral Map Static API PHP library to easily get static image from French Cadastral Government map with markers and lines. Map source : c

Franck Alary 5 Oct 31, 2022
PHP library to easily get static image from OpenStreetMap (OSM) with markers and lines.

PHP OpenStreetMap Static API PHP library to easily get static image from OpenStreetMap with markers and lines. ✨ Supporting ⭐ Star this repository to

Franck Alary 30 Oct 25, 2022
Official PHP library for IPinfo (IP geolocation and other types of IP data)

This is the official PHP client library for the IPinfo.io IP address API, allowing you to lookup your own IP address,

IPinfo 168 Nov 22, 2022
ESRI ShapeFile library for PHP

shapefile ShapeFile library for PHP Features Currently the 2D and 3D variants except MultiPatch of the ShapeFile format as defined in https://www.esri

phpMyAdmin 23 Jun 29, 2022
PHP library to access the OpenCage geocoding API

OpenCage Geocoding API Library for PHP A PHP library to use the OpenCage geocoding API. Build Status / Code Quality Overview This library attempts to

OpenCage GmbH 29 Nov 15, 2022
PHP library for determining the physical location of binaries

Bin Locator Library for searching binary files in the operating system. Requirements PHP >= 7.4 Installation Library is available as composer reposito

PHP FFI 8 Jul 27, 2022
GeoSpatial integration on Laravel 5.2+ that supports MySQL and PostgreSQL.

Features GeoSpatial integration on Laravel 5.2+: Create geospatial columns using Schema and migrations Save and retrieve geospatial attributes using d

Eleven 46 Nov 6, 2022
Free database of geographic place names and corresponding geospatial data

FreeGeoDB Free database of geographic place names and corresponding geospatial data Entities airports cities countries (admin-0) lakes ports railroads

delight.im 1.6k Nov 10, 2022
Use: [i] to share item and name in hand, [coor] to share you current coordinates

General Now you can share your Coordinates and Item with Prefix Example if you type [i] in message, later it will be automatically replaced into the n

ItsRealNise 7 Oct 15, 2021
Generate and display maps without external services or compromising on privacy.

Generate and display maps without external services or compromising on privacy.

null 142 Nov 22, 2022
PHP extension for geospatial rendering with Mapnik

PHP7 Mapnik Introduction This project is an extension for PHP 7 that enables geospatial rendering with Mapnik. Create tile generation scripts, dynamic

Garrett Johnson 21 Sep 26, 2022
PHP Extension to handle common geospatial functions.

geospatial - PHP Geospatial Extension PHP Extension to handle common geospatial functions. The extension currently has implementations of the Haversin

PHP Geospatial, putting the Elephpant on your globe 55 Nov 15, 2022
GeoJSON implementation for PHP

GeoJson PHP Library This library implements the GeoJSON format specification. The GeoJson namespace includes classes for each data structure defined i

Jeremy Mikola 272 Nov 26, 2022
Geo-related tools PHP 7.3+ library built atop Geocoder and React libraries

Geotools Geotools is a PHP geo-related library, built atop Geocoder and React libraries. Features Batch geocode & reverse geocoding request(s) in seri

The League of Extraordinary Packages 1.3k Nov 30, 2022
Symfony React Blank is a blank symfony and react project, use this template to start your app using Symfony as an backend api and React as a frontend library.

Symfony React Blank Symfony React Blank is a blank symfony and react project, use this template to start your app using Symfony as an backend api and

Antoine Kingue 2 Nov 5, 2021
LittleProxy is a high performance HTTP proxy written in Java atop Trustin Lee's excellent Netty event-based networking library

LittleProxy is a high performance HTTP proxy written in Java atop Trustin Lee's excellent Netty event-based networking library

null 1.9k Dec 5, 2022
A multitool library offering access to recommended security related libraries, standardised implementations of security defences, and secure implementations of commonly performed tasks.

SecurityMultiTool A multitool library offering access to recommended security related libraries, standardised implementations of security defences, an

Pádraic Brady 131 Oct 30, 2022
A multitool library offering access to recommended security related libraries, standardised implementations of security defences, and secure implementations of commonly performed tasks.

SecurityMultiTool A multitool library offering access to recommended security related libraries, standardised implementations of security defences, an

Pádraic Brady 131 Oct 30, 2022