Skip to content

Instantly share code, notes, and snippets.

@tomekzaw
Last active March 1, 2020 12:36
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomekzaw/4e499e3e36373b01cf8d36abe04494ac to your computer and use it in GitHub Desktop.
Save tomekzaw/4e499e3e36373b01cf8d36abe04494ac to your computer and use it in GitHub Desktop.
<?php
set_time_limit(5);
error_reporting(0);
function in_range($num, ...$ranges) {
foreach ($ranges as $range) {
if (is_array($range)) {
if ($range[0] <= $num and $num <= $range[1]) {
return true;
}
} else {
return $num == $range;
}
}
return false;
}
function vehicle_info($kmk_id) {
$num = (int) mb_substr($kmk_id, 2);
// based on: http://www.psmkms.krakow.pl/index.php/ciekawostki/krakowski-tabor
if (in_range($num, [2, 4])) {
return [
'name' => 'Solaris Urbino 18 IV electric',
'shortName' => 'SU18IVe',
'electric' => true,
];
}
if (in_range($num, [71, 83])) {
return [
'name' => 'Solaris Urbino 18 hybrid',
'shortName' => 'SU18h',
];
}
if (in_range($num, [84, 96])) {
return [
'name' => 'Volvo 7900A Hybrid',
'shortName' => '7900A',
];
}
if (in_range($num, [103, 105])) {
return [
'name' => 'Automet Cityliner Smile',
'shortName' => 'Smile',
];
}
if (in_range($num, [106, 138])) {
return [
'name' => 'Autosan M09LE',
'shortName' => 'M09LE',
];
}
if (in_range($num, 139)) {
return [
'name' => 'Autosan M12LF',
'shortName' => 'M12LF',
];
}
if (in_range($num, [141, 146])) {
return [
'name' => 'MAN NL283',
'shortName' => 'NL283',
];
}
if (in_range($num, 200)) {
return [
'name' => 'Mercedes Conecto',
'shortName' => 'Conecto',
];
}
if (in_range($num, [206, 243])) {
return [
'name' => 'Mercedes O530',
'shortName' => 'O530',
];
}
if (in_range($num, [244, 299])) {
return [
'name' => 'Mercedes O530 C2',
'shortName' => 'C2',
];
}
if (in_range($num, [301, 345], [978, 997])) {
return [
'name' => 'Solaris Urbino 12 IV',
'shortName' => 'SU12IV',
];
}
if (in_range($num, [400, 408])) {
return [
'name' => 'Solaris Urbino 12,9 hybrid',
'shortName' => 'SU12,9h',
];
}
if (in_range($num, [501, 595], [778, 797])) {
return [
'name' => 'Solaris Urbino 18 IV',
'shortName' => 'SU18IV',
];
}
if (in_range($num, 601, 606)) {
return [
'name' => 'Solaris Urbino 12 III electric',
'shortName' => 'SU12IIIe',
'electric' => true,
];
}
if (in_range($num, [602, 605])) {
return [
'name' => 'Solaris Urbino 8,9LE electric',
'shortName' => '8,9LE',
'electric' => true,
];
}
if (in_range($num, [607, 623])) {
return [
'name' => 'Solaris Urbino 12 IV electric',
'shortName' => 'SU12IVe',
'electric' => true,
];
}
if (in_range($num, 700, 732)) {
return [
'name' => 'Mercedes Conecto G',
'shortName' => 'Conecto G',
];
}
if (in_range($num, [701, 731])) {
return [
'name' => 'Mercedes O530G',
'shortName' => 'O530G',
];
}
if (in_range($num, [737, 768], 777)) {
return [
'name' => 'Solaris Urbino 18 III',
'shortName' => 'SU18III',
];
}
if (in_range($num, [769, 776])) {
return [
'name' => 'Solaris Urbino 18 MetroStyle',
'shortName' => 'SU18MS',
];
}
if (in_range($num, [851, 977])) {
return [
'name' => 'Solaris Urbino 12 III',
'shortName' => 'SU12III',
];
}
return [];
}
$vehicles_json_url = 'http://91.223.13.70/internetservice/geoserviceDispatcher/services/vehicleinfo/vehicles';
$vehicle_positions_pb_url = 'ftp://ztp.krakow.pl/VehiclePositions_A.pb';
define('TRIP_ID_PREFIX', '80952613041'); // all trip ids have this prefix
header('Content-type: application/json; charset=utf-8');
$vehicles_json_raw = file_get_contents($vehicles_json_url);
if ($vehicles_json_raw === false) {
die('{}');
}
$vehicles_json = json_decode($vehicles_json_raw, true);
$trip_ids_to_vehicle_ids = [];
foreach ($vehicles_json['vehicles'] as $vehicle) {
if (!array_key_exists('tripId', $vehicle)) {
continue;
}
$vehicleId = $vehicle['id'];
$tripId = $vehicle['tripId'];
$vehicle_ids_to_trip_ids[$vehicleId] = $tripId;
}
function trip_id_to_short_trip_id($trip_id) {
// simplifies arithmetic operations on trip ids
return bindec(mb_substr(decbin((int) mb_substr($trip_id, mb_strlen(TRIP_ID_PREFIX))), 0, -12));
}
$trip_ids = array_values($vehicle_ids_to_trip_ids);
$trip_ids_to_short_trip_ids = [];
foreach ($trip_ids as $trip_id) {
$trip_ids_to_short_trip_ids[$trip_id] = trip_id_to_short_trip_id($trip_id);
}
$vehicle_positions_pb_raw = file_get_contents($vehicle_positions_pb_url);
if ($vehicle_positions_pb_raw === false) {
die('{}');
}
$vehicle_positions_pb_raw_inline = str_replace(["\r\n", "\n", PHP_EOL], '', $vehicle_positions_pb_raw);
preg_match_all("/block_([0-9]+)_.*?\x05([A-Z]{2}[0-9]{3})/", $vehicle_positions_pb_raw_inline, $matches); // block = brygada
list(, $block_ids, $kmk_ids) = $matches;
$block_ids_to_kmk_ids = [];
foreach ($block_ids as $i => $block_id) {
$block_ids_to_kmk_ids[$block_id] = $kmk_ids[$i];
}
function find_best_shift($as, $bs) {
// finds s that a+s=b is true in most cases
$shift_min = min($bs) - max($as);
$shift_max = max($bs) - min($as);
$best_shift = $shift_min;
$best_count = -1;
for ($shift = $shift_min; $shift <= $shift_max; $shift++) {
$count = 0;
foreach ($as as $a) {
$count += (int) in_array($a + $shift, $bs);
}
if ($count > $best_count) {
$best_shift = $shift;
$best_count = $count;
}
}
return $best_shift;
}
$short_trip_ids = array_values($trip_ids_to_short_trip_ids);
$block_ids = array_keys($block_ids_to_kmk_ids);
$shift = find_best_shift($short_trip_ids, $block_ids); // -21111
$output = [];
ksort($vehicle_ids_to_trip_ids);
foreach ($vehicle_ids_to_trip_ids as $vehicle_id => $trip_id) {
$short_trip_id = $trip_ids_to_short_trip_ids[$trip_id];
$block_id = $short_trip_id + $shift;
if (!array_key_exists($block_id, $block_ids_to_kmk_ids)) {
continue;
}
$kmk_id = $block_ids_to_kmk_ids[$block_id];
// $output[$vehicle_id] = $kmk_id;
$output[] = [
'vehicleId' => $vehicle_id,
'tripId' => $trip_id,
'blockId' => $block_id,
'kmkId' => $kmk_id,
'vehicleInfo' => vehicle_info($kmk_id) + [
'type' => 'bus',
'name' => null,
'shortName' => null,
'lowFloor' => true,
],
];
}
$output_json = json_encode($output, JSON_PRETTY_PRINT);
echo $output_json;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment