fixed kilometer calculation

This commit is contained in:
Luca Haid
2025-06-30 11:37:18 +02:00
parent 249b646025
commit a3eac7b212

View File

@@ -436,45 +436,133 @@ class WarehouseShippingNoteController extends TTCrud {
die(json_encode(['success' => true, 'status' => 'USER_NO_CAR']));
}
protected function geoAutocompleteAction() {
$search = $this->request->q;
$search = urlencode($search);
$url = "https://nominatim.haid.in/search?q=$search&format=json&addressdetails=1";
$data = json_decode(file_get_contents($url), true);
$out = [];
/**
* Helper function to parse Google Geocoding API response into the format expected by the frontend.
* @param array $components The address_components array from Google's response.
* @return array The formatted address array.
*/
private function formatGoogleAddress(array $components): array {
$address = [
'house_number' => null,
'road' => null,
'postcode' => null,
'city' => null,
'town' => null,
'village' => null,
'residential' => null,
'hamlet' => null,
];
foreach ($data as $entry) {
$parsedDisplayNameParts = [];
foreach (explode(',', $entry['display_name']) as $part) {
// if str_includes Bezirk remove it
if (strpos($part, 'Bezirk') !== false) {
continue;
}
$parsedDisplayNameParts[] = $part;
foreach ($components as $component) {
$types = $component['types'];
if (in_array('street_number', $types)) {
$address['house_number'] = $component['long_name'];
}
if (!empty($out)) {
foreach ($out as $key => $value) {
if ($value['text'] === implode(',', $parsedDisplayNameParts)) {
continue 2;
}
if (in_array('route', $types)) {
$address['road'] = $component['long_name'];
}
if (in_array('postal_code', $types)) {
$address['postcode'] = $component['long_name'];
}
if (in_array('locality', $types)) {
$address['city'] = $component['long_name'];
$address['town'] = $component['long_name']; // Town is often the same as city
}
// A village in Google can be sublocality or sublocality_level_1
if (in_array('sublocality', $types) || in_array('sublocality_level_1', $types)) {
$address['village'] = $component['long_name'];
}
if (in_array('neighborhood', $types)) {
$address['residential'] = $component['long_name'];
if (!$address['village']) { // Fallback for village if not already set
$address['village'] = $component['long_name'];
}
}
$out[] = ['value' => $entry['lat'] . "," . $entry['lon'] . (!isset($entry['address']['house_number']) ? ", area" : ""), 'text' => implode(',', $parsedDisplayNameParts)];
}
// If city is null, try to find it in administrative areas
if (!$address['city']) {
foreach ($components as $component) {
if (in_array('administrative_area_level_3', $component['types'])) {
$address['city'] = $component['long_name'];
$address['town'] = $component['long_name'];
break;
}
}
}
return $address;
}
protected function geoAutocompleteAction() {
$search = urlencode($this->request->q);
$apiKey = TT_GEOCODING_API_SECRET;
// Bias search results for Austria (AT) in German (de)
$url = TT_GEOCODING_API_URL . "?address=$search&key=$apiKey&region=at&language=de&components=country:AT";
$response = @file_get_contents($url);
if ($response === false) {
self::returnJson([]);
return;
}
$data = json_decode($response, true);
$out = [];
if ($data['status'] === 'OK') {
foreach ($data['results'] as $entry) {
$lat = $entry['geometry']['location']['lat'];
$lng = $entry['geometry']['location']['lng'];
$text = $entry['formatted_address'];
$hasHouseNumber = false;
foreach ($entry['address_components'] as $component) {
if (in_array('street_number', $component['types'])) {
$hasHouseNumber = true;
break;
}
}
$value = $lat . "," . $lng . (!$hasHouseNumber ? ", area" : "");
// Deduplication logic from original code
$isDuplicate = false;
foreach ($out as $existing) {
if ($existing['text'] === $text) {
$isDuplicate = true;
break;
}
}
if (!$isDuplicate) {
$out[] = ['value' => $value, 'text' => $text];
}
}
}
self::returnJson($out);
}
protected function geoReverseAction() {
$lat = $this->request->lat;
$lon = $this->request->lon;
$url = "https://nominatim.haid.in/reverse?lat=$lat&lon=$lon&format=json&addressdetails=1";
$data = json_decode(file_get_contents($url), true);
self::returnJson(is_array($data) ? $data : ['data' => $data]);
}
$apiKey = TT_GEOCODING_API_SECRET;
$url = TT_GEOCODING_API_URL . "?latlng=$lat,$lon&key=$apiKey&language=de";
$response = @file_get_contents($url);
if ($response === false) {
self::returnJson(['address' => [], 'error' => 'REQUEST_FAILED', 'error_message' => 'Could not connect to Google Maps API.']);
return;
}
$data = json_decode($response, true);
if ($data['status'] === 'OK' && !empty($data['results'])) {
$addressComponents = $data['results'][0]['address_components'];
$formattedAddress = $this->formatGoogleAddress($addressComponents);
self::returnJson(['address' => $formattedAddress]);
} else {
self::returnJson(['address' => [], 'error' => $data['status'], 'error_message' => $data['error_message'] ?? 'Reverse geocoding failed.']);
}
}
//TODO: export this to an api class for openstreetmap
protected function getDistanceAction() {
@@ -486,7 +574,6 @@ class WarehouseShippingNoteController extends TTCrud {
self::returnJson(json_decode($data, true));
}
$from = $this->request->from;
$to = $this->request->to;
$from = urlencode($from);
@@ -497,47 +584,66 @@ class WarehouseShippingNoteController extends TTCrud {
return [['lat' => 46.99555015, 'lon' => 15.77507876755547]];
}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://nominatim.haid.in/search?q=$address&format=json",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"accept: application/json",
"accept-language: de-AT,de;q=0.9,en;q=0.8",
"origin: https://routing.openstreetmap.de",
"referer: https://routing.openstreetmap.de/",
"user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
],
]);
$address = urlencode($address);
$apiKey = TT_GEOCODING_API_SECRET;
// Bias search results for Austria
$url = TT_GEOCODING_API_URL . "?address=$address&key=$apiKey&region=at&components=country:AT";
$response = curl_exec($curl);
$err = curl_error($curl);
if ($err) {
die(json_encode(['success' => false, 'message' => 'Error while geocoding']));
$response = @file_get_contents($url);
if ($response === false) {
die(json_encode(['success' => false, 'message' => 'Error while geocoding: API connection failed.']));
}
curl_close($curl);
return json_decode($response, true);
$data = json_decode($response, true);
if ($data['status'] === 'OK' && !empty($data['results'])) {
$location = $data['results'][0]['geometry']['location'];
// The OSRM routing engine expects 'lon', so we map Google's 'lng' to 'lon'.
return [['lat' => $location['lat'], 'lon' => $location['lng']]];
} else {
die(json_encode(['success' => false, 'message' => 'Error while geocoding: ' . ($data['error_message'] ?? $data['status'])]));
}
}
function route($from, $to) {
// The geocode() function (which you've already updated to use Google)
// will provide the necessary coordinates. It will `die()` on error, so we can
// assume we have valid data if the script continues.
$fromData = geocode($from);
$toData = geocode($to);
$fromLat = $fromData[0]['lat'];
$fromLon = $fromData[0]['lon'];
$toLat = $toData[0]['lat'];
$toLon = $toData[0]['lon'];
$url = "https://router.project-osrm.org/route/v1/driving/$fromLon,$fromLat;$toLon,$toLat?overview=false";
$data = json_decode(file_get_contents($url), true);
$distance = $data['routes'][0]['distance'];
return $distance * 2;
$apiKey = TT_GEOCODING_API_SECRET;
$url = "https://maps.googleapis.com/maps/api/directions/json" .
"?origin={$fromLat},{$fromLon}" .
"&destination={$toLat},{$toLon}" .
"&key={$apiKey}" .
"&mode=driving" .
"&region=at"; // Bias results for Austria
$response = @file_get_contents($url);
if ($response === false) {
die(json_encode(['success' => false, 'message' => 'Could not connect to Google Directions API.']));
}
$data = json_decode($response, true);
// Check for a successful response and if a route was found
if ($data['status'] === 'OK' && !empty($data['routes'])) {
// The distance is provided in meters in the first "leg" of the first "route"
$distance = $data['routes'][0]['legs'][0]['distance']['value'];
// Return the round-trip distance
return $distance * 2;
} else {
// Handle cases where no route is found or another API error occurred
$errorMessage = $data['error_message'] ?? 'No route could be found between the locations.';
die(json_encode(['success' => false, 'message' => "Routing Error: " . $errorMessage]));
}
}
$distance = route($from, $to);