Skip to content

Commit

Permalink
added reverse geocoding by lat/lon
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Baettig committed Jan 24, 2020
1 parent b9cce72 commit 3bff2af
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 10 deletions.
2 changes: 2 additions & 0 deletions app/Interfaces/ReverseGeocoding.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
interface ReverseGeocoding
{
public static function findCitiesNearPoint(float $x, float $y, float $radius) : ?array;
public static function findCitiesNearLatLon(float $lat, float $lon, float $radius) : ?array;
public static function findCityByPoint(float $x, float $y): ?string;
public static function findCityByLatLon(float $lat, float $lon): ?string;
public static function findPostcodeByPoint(float $x, float $y): ?int;
}
78 changes: 78 additions & 0 deletions app/Support/GeoConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php /** @noinspection CallableParameterUseCaseInTypeContextInspection */


namespace SwissGeo\Support;


class GeoConverter
{
public static function latLonToPoint(float $lat, float $lon): array
{

// Converts decimal degrees sexagesimal seconds
$lat = self::decimalAngleToSexagesimalSeconds($lat);
$lon = self::decimalAngleToSexagesimalSeconds($lon);

// Auxiliary values (% Bern)
$lat_aux = ($lat - 169028.66)/10000;
$lon_aux = ($lon - 26782.5)/10000;

$x = 200147.07
+ 308807.95 * $lat_aux
+ 3745.25 * ($lon_aux ** 2)
+ 76.63 * ($lat_aux ** 2)
- 194.56 * ($lon_aux ** 2) * $lat_aux
+ 119.79 * ($lat_aux ** 3);

$y = 600072.37
+ 211455.93 * $lon_aux
- 10938.51 * $lon_aux * $lat_aux
- 0.36 * $lon_aux * ($lat_aux ** 2)
- 44.54 * ($lon_aux ** 3);

return ['x' => $x, 'y' => $y];
}

public static function pointToLatLon(float $x, float $y): array
{
// Converts military to civil and to unit = 1000km
// Auxiliary values (% Bern)
$y_aux = ($y - 600000)/1000000;
$x_aux = ($x - 200000)/1000000;

// Process lat
$lat = 16.9023892
+ 3.238272 * $x_aux
- 0.270978 * ($y_aux ** 2)
- 0.002528 * ($x_aux ** 2)
- 0.0447 * ($y_aux ** 2) * $x_aux
- 0.0140 * ($x_aux ** 3);

// Unit 10000" to 1 " and converts seconds to degrees (dec)
$lat = $lat * 100/36;

// Process long
$lon = 2.6779094
+ 4.728982 * $y_aux
+ 0.791484 * $y_aux * $x_aux
+ 0.1306 * $y_aux * ($x_aux ** 2)
- 0.0436 * ($y_aux ** 3);

// Unit 10000" to 1 " and converts seconds to degrees (dec)
$lon = $lon * 100/36;

return ['lat' => $lat, 'lon' => $lon];
}


private static function decimalAngleToSexagesimalSeconds(float $angle)
{
// Extract DMS
$deg = (int)$angle;
$min = (int)(($angle - $deg) * 60);
$sec = ((($angle-$deg)*60)-$min)*60;

// Result in sexagesimal seconds
return $sec + $min*60 + $deg*3600;
}
}
18 changes: 18 additions & 0 deletions app/SwissGeo.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use SwissGeo\Gateways\SwissPostGateway;
use SwissGeo\Interfaces\Geocoding;
use SwissGeo\Interfaces\ReverseGeocoding;
use SwissGeo\Support\GeoConverter;

class SwissGeo implements Geocoding, ReverseGeocoding
{
Expand Down Expand Up @@ -63,6 +64,14 @@ public static function findCitiesNearPoint(float $x, float $y, float $radius = 0
return $cityArray;
}

public static function findCitiesNearLatLon(float $lat, float $lon, float $radius = 0): ?array
{
$point = GeoConverter::latLonToPoint($lat, $lon);
if (!$point) {
return null;
}
return self::findCitiesNearPoint($point['x'], $point['y'], $radius);
}
public static function findCitiesNearAddress(string $location, float $radius = 0): ?array
{
$currentLocation = self::findPointByAddress($location);
Expand Down Expand Up @@ -99,4 +108,13 @@ public static function findCantonByCity(string $name): ?string
{
return SwissPostGateway::getCantonByCity($name);
}

public static function findCityByLatLon(float $lat, float $lon): ?string
{
$point = GeoConverter::latLonToPoint($lat, $lon);
if (!$point) {
return null;
}
return self::findCityByPoint($point['x'], $point['y']);
}
}
24 changes: 24 additions & 0 deletions tests/SwissGeo/GeoConverterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace SwissGeo;

use PHPUnit\Framework\TestCase;
use SwissGeo\Support\GeoConverter;

class GeoConverterTest extends TestCase
{
public function testCanConvertSwissCoordinatesToLatLon(): void
{
$latLon = GeoConverter::pointToLatLon(210318.1875, 657089.5);
$this->assertEqualsWithDelta(47.041442871094, $latLon['lat'], 0.01);
$this->assertEqualsWithDelta(8.1898508071899, $latLon['lon'], 0.01);
}

public function testCanLatLonToSwissCoordinates(): void
{
$point = GeoConverter::latLonToPoint(47.041442871094, 8.1898508071899);
$this->assertEqualsWithDelta(210318.1875, $point['x'], 1);
$this->assertEqualsWithDelta(657089.5, $point['y'], 1);
}

}
31 changes: 21 additions & 10 deletions tests/SwissGeo/SwissGeoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,67 @@
class SwissGeoTest extends TestCase
{

public function testFindCitiesNearAddress()
public function testFindCitiesNearAddress(): void
{
$this->assertCount(2,SwissGeo::findCitiesNearAddress('Malters', 1.5));
$this->assertCount(1,SwissGeo::findCitiesNearAddress('Malters'));
$this->assertEquals(['Malters'], SwissGeo::findCitiesNearAddress('Malters'));
}

public function testFindPointByAddress()
public function testFindPointByAddress(): void
{
$point = SwissGeo::findPointByAddress('Malters');
$this->assertEqualsWithDelta(210318,$point['x'] ,1);
}

public function testFindCitiesNearPoint()
public function testFindCitiesNearPoint(): void
{
$this->assertCount(2,SwissGeo::findCitiesNearPoint(210318.1875, 657089.5,1.5));
$this->assertCount(1,SwissGeo::findCitiesNearPoint(210318.1875, 657089.5));
}

public function testFindPostcodeByCity()
public function testFindCitiesNearLatLong(): void
{
$this->assertCount(2,SwissGeo::findCitiesNearLatLon(47.041442871094, 8.1898508071899,1.5));
$this->assertCount(1,SwissGeo::findCitiesNearLatLon(47.041442871094, 8.1898508071899));
}

public function testFindPostcodeByCity(): void
{
$this->assertEquals('6102',SwissGeo::findPostcodeByCity('Malters'));
}

public function testFindCityByPostcode()
public function testFindCityByPostcode(): void
{
$this->assertEquals('Malters',SwissGeo::findCityByPostcode('6102'));
}

public function testFindCantonByPostcode()
public function testFindCantonByPostcode(): void
{
$this->assertEquals('LU',SwissGeo::findCantonByPostcode('6102'));
}

public function testFindCantonByCity()
public function testFindCantonByCity(): void
{
$this->assertEquals('LU',SwissGeo::findCantonByCity('Malters'));
}

public function testFindCityByPoint()
public function testFindCityByPoint(): void
{
$this->assertEquals('Malters',SwissGeo::findCityByPoint(210318.1875, 657089.5));
}

public function testFindPostcodeByPoint()
public function testFindCityByLatLon(): void
{
$this->assertEquals('Malters',SwissGeo::findCityByLatLon(47.041442871094, 8.1898508071899));
}

public function testFindPostcodeByPoint(): void
{
$this->assertEquals('6102',SwissGeo::findPostcodeByPoint(210318.1875, 657089.5));
}

public function testFindPossibleStreetnames()
public function testFindPossibleStreetnames(): void
{
$this->assertCount(1, SwissGeo::findStreetnames('Haldenhüslistrasse'));
$this->assertEquals('Haldenhüslistrasse', SwissGeo::findStreetnames('Haldenhüslistrasse')['0']);
Expand Down

0 comments on commit 3bff2af

Please sign in to comment.