resq/src/Service/MapTools.php

221 lines
6.7 KiB
PHP

<?php
namespace App\Service;
use GuzzleHttp\Client as GuzzleClient;
use CrEOF\Spatial\PHP\Types\Geometry\Point;
use Doctrine\ORM\EntityManagerInterface;
class MapTools
{
const URL_DISTANCE_MATRIX = 'https://maps.googleapis.com/maps/api/distancematrix/json';
// entity manager
protected $em;
// google maps api key
protected $gmaps_api_key;
// customer distance limit
protected $cust_dist_limit;
public function __construct(EntityManagerInterface $em, $gmaps_api_key,
$cust_dist_limit)
{
$this->em = $em;
$this->gmaps_api_key = $gmaps_api_key;
$this->cust_dist_limit = $cust_dist_limit;
}
protected function mapGetDistances(Point $point, $hubs)
{
$client = new GuzzleClient();
// origins
$origins_value = $point->getLatitude() . ',' . $point->getLongitude();
// destinations
$dests = [];
foreach ($hubs as $hub)
{
$coord = $hub->getCoordinates();
$dests[] = round($coord->getLatitude(),5) . ',' . round($point->getLongitude(), 5);
}
$dests_value = implode('|', $dests);
// google maps url
$maps_url = self::URL_DISTANCE_MATRIX;
// parameters
$gmaps_params = [
'origins' => $origins_value,
'destinations' => $dests_value,
];
//error_log(print_r($gmaps_params, true));
// query google maps api
$res = $client->request('GET', $maps_url, [
'query' => $gmaps_params,
'curl' => [
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4
],
]);
return $res->getBody();
}
public function getClosestHubs(Point $point, $limit, $time = false)
{
// get closest hubs based on st_distance function from db
$query = $this->em->createQuery('SELECT h, st_distance(h.coordinates, point(:lng, :lat)) as dist FROM App\Entity\Hub h' . ($time ? ' WHERE :time BETWEEN h.time_open AND h.time_close' : '') . ' ORDER BY dist')
->setParameter('lat', $point->getLatitude())
->setParameter('lng', $point->getLongitude());
if ($time) {
$query->setParameter('time', $time);
}
$query->setMaxResults($limit);
// error_log($query->getSql());
$result = $query->getResult();
$hubs = [];
$final_data = [];
foreach ($result as $row)
{
//error_log($row[0]->getName() . ' - ' . $row['dist']);
$hubs[] = $row[0];
// get coordinates of hub
$hub_coordinates = $row[0]->getCoordinates();
$cust_lat = $point->getLatitude();
$cust_lng = $point->getLongitude();
$hub_lat = $hub_coordinates->getLatitude();
$hub_lng = $hub_coordinates->getLongitude();
// get distance in kilometers from customer point to hub point
$dist = $this->distance($cust_lat, $cust_lng, $hub_lat, $hub_lng);
$final_data[] = [
'hub' => $row[0],
'db_distance' => $row['dist'],
'distance' => $dist,
'duration' => 0,
];
}
return $final_data;
/*
// get actual distance details with eta from google maps api
$raw_res = $this->mapGetDistances($point, $hubs);
$res = json_decode($raw_res, true);
//error_log(print_r($res, true));
// check if status is ok
if ($res['status'] != 'OK')
{
return $final_data;
// error_log('status not ok');
}
// check that the elements array is there
if (!isset($res['rows'][0]['elements']))
{
// error_log('no elements');
return $final_data;
}
foreach($res['rows'][0]['elements'] as $index => $gm_row)
{
// check status
if (isset($gm_row['status']) && $gm_row['status'] != 'OK')
{
// error_log('element row status not ok');
continue;
}
// set distance
if (isset($gm_row['distance']['value']))
$final_data[$index]['distance'] = $gm_row['distance']['value'];
// set duration
if (isset($gm_row['duration']['value']))
$final_data[$index]['duration'] = $gm_row['duration']['value'];
}
return $final_data;
*/
}
// NOTE: only the API calls this
public function getClosestOpenHubs(Point $point, $limit, $time = false)
{
// get closest hubs based on st_distance function from db
$query = $this->em->createQuery('SELECT h, st_distance(h.coordinates, point(:lng, :lat)) as dist FROM App\Entity\Hub h' . ($time ? ' WHERE h.status_open = true AND :time BETWEEN h.time_open AND h.time_close' : '') . ' ORDER BY dist')
->setParameter('lat', $point->getLatitude())
->setParameter('lng', $point->getLongitude());
if ($time) {
$query->setParameter('time', $time);
}
$query->setMaxResults($limit);
// error_log($query->getSql());
$result = $query->getResult();
$hubs = [];
$final_data = [];
foreach ($result as $row)
{
//error_log($row[0]->getName() . ' - ' . $row['dist']);
$hubs[] = $row[0];
// get coordinates of hub
$hub_coordinates = $row[0]->getCoordinates();
$cust_lat = $point->getLatitude();
$cust_lng = $point->getLongitude();
$hub_lat = $hub_coordinates->getLatitude();
$hub_lng = $hub_coordinates->getLongitude();
// get distance in kilometers from customer point to hub point
$dist = $this->distance($cust_lat, $cust_lng, $hub_lat, $hub_lng);
if ($dist < $this->cust_dist_limit)
{
$final_data[] = [
'hub' => $row[0],
'db_distance' => $row['dist'],
'distance' => $dist,
'duration' => 0,
];
}
}
error_log('nearest open hubs count: ' . count($final_data));
return $final_data;
}
protected function distance($lat1, $lon1, $lat2, $lon2)
{
if (($lat1 == $lat2) && ($lon1 == $lon2))
return 0;
$theta = $lon1 - $lon2;
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
$dist = acos($dist);
$dist = rad2deg($dist);
$miles = $dist * 60 * 1.1515;
return round(($miles * 1.609344), 1);
}
}