Jacek Kowalski
2019-06-20 96b13b168db72ac01585954418ab01903fe4d42e
commit | author | age
4673cc 1 <?php
JK 2 require_once(__DIR__.'/../vendor/autoload.php');
3 require_once(__DIR__.'/vehicle_types.php');
4
5 use transit_realtime\FeedMessage;
6
7 class Mapper {
9afb6b 8     private $ttssDate = NULL;
0c85a7 9     private $ttssTrips = [];
9afb6b 10     private $gtfsrtDate = NULL;
0c85a7 11     private $gtfsrtTrips = [];
4673cc 12     private $logger = NULL;
JK 13     
14     private $specialNames = [
15         'Zjazd do zajezdni',
16         'Przejazd techniczny',
17         'Wyjazd na trasÄ™',
18     ];
19     
20     public function __construct() {
21         $this->logger = new Monolog\Logger(__CLASS__);
22     }
23     
24     public static function convertTripId($tripId) {
25         $tripId = explode('_', $tripId);
26         if($tripId[0] != 'block') return;
27         if($tripId[2] != 'trip') return;
28         return 4096 * (int)$tripId[1] + (int)$tripId[3];
29     }
30     
31     public function loadTTSS($file) {
0c85a7 32         $ttss = json_decode(file_get_contents($file));
9afb6b 33         $this->ttssDate = $ttss->lastUpdate;
0c85a7 34         foreach($ttss->vehicles as $vehicle) {
4673cc 35             if(isset($vehicle->isDeleted) && $vehicle->isDeleted) continue;
JK 36             if(!isset($vehicle->tripId) || !$vehicle->tripId) continue;
37             if(!isset($vehicle->name) || !$vehicle->name) continue;
38             if(!isset($vehicle->latitude) || !$vehicle->latitude) continue;
39             if(!isset($vehicle->longitude) || !$vehicle->longitude) continue;
40             foreach($this->specialNames as $name) {
41                 if(substr($vehicle->name, -strlen($name)) == $name) {
42                     continue;
43                 }
44             }
0c85a7 45             $this->ttssTrips[(int)$vehicle->tripId] = [
4673cc 46                 'id' => $vehicle->id,
JK 47                 'latitude' => (float)$vehicle->latitude / 3600000.0,
48                 'longitude' => (float)$vehicle->longitude / 3600000.0,
49             ];
50         }
0c85a7 51         ksort($this->ttssTrips);
4673cc 52     }
JK 53     
9afb6b 54     public function getTTSSDate() {
JK 55         return $this->ttssDate / 1000.0;
56     }
57     
0c85a7 58     public function loadGTFSRT($file) {
4673cc 59         $data = file_get_contents($file);
JK 60         $feed = new FeedMessage();
61         $feed->parse($data);
9afb6b 62         $this->gtfsrtDate = $feed->header->timestamp;
4673cc 63         foreach ($feed->getEntityList() as $entity) {
JK 64             $vehiclePosition = $entity->getVehicle();
65             $position = $vehiclePosition->getPosition();
66             $vehicle = $vehiclePosition->getVehicle();
67             $trip = $vehiclePosition->getTrip();
68             $tripId = $trip->getTripId();
0c85a7 69             $this->gtfsrtTrips[self::convertTripId($tripId)] = [
4673cc 70                 'id' => $entity->getId(),
JK 71                 'num' => $vehicle->getLicensePlate(),
72                 'tripId' => $tripId,
73                 'latitude' => $position->getLatitude(),
74                 'longitude' => $position->getLongitude(),
75             ];
76         }
0c85a7 77         ksort($this->gtfsrtTrips);
4673cc 78     }
JK 79     
9afb6b 80     public function getGTFSRTDate() {
JK 81         return $this->gtfsrtDate;
82     }
83     
4673cc 84     public function findOffset() {
0c85a7 85         if(count($this->ttssTrips) == 0 || count($this->gtfsrtTrips) == 0) {
4673cc 86             return NULL;
JK 87         }
88         
0c85a7 89         $ttssTripIds = array_keys($this->ttssTrips);
JK 90         $gtfsTripIds = array_keys($this->gtfsrtTrips);
4673cc 91         
JK 92         $possibleOffsets = [];
0c85a7 93         for($i = 0; $i < count($this->ttssTrips); $i++) {
JK 94             for($j = 0; $j < count($this->gtfsrtTrips); $j++) {
95                 $possibleOffsets[$ttssTripIds[$i] - $gtfsTripIds[$j]] = TRUE;
4673cc 96             }
JK 97         }
98         $possibleOffsets = array_keys($possibleOffsets);
99         
100         $bestOffset = 0;
101         $maxMatched = 0;
102         $options = 0;
103         
104         foreach($possibleOffsets as $offset) {
105             $matched = 0;
106             
107             foreach($gtfsTripIds as $tripId) {
108                 $tripId += $offset;
0c85a7 109                 if(isset($this->ttssTrips[$tripId])) {
4673cc 110                     $matched++;
JK 111                 }
112             }
113             
114             if($matched > $maxMatched) {
115                 $bestOffset = $offset;
116                 $maxMatched = $matched;
117                 $options = 1;
118             } elseif($matched == $maxMatched) {
119                 $options++;
120             }
121         }
122         
123         if($options != 1) {
124             throw new Exception('Found '.$options.' possible mappings!');
125         }
126         return $bestOffset;
127     }
128     
9970fb 129     public function mapUsingOffset($offset, $mapper) {
4673cc 130         $result = [];
0c85a7 131         foreach($this->gtfsrtTrips as $gtfsTripId => $gtfsTrip) {
JK 132             $ttssTripId = $gtfsTripId + $offset;
133             if(isset($this->ttssTrips[$ttssTripId])) {
9970fb 134                 $data = $mapper($gtfsTrip['id']);
4673cc 135                 $num = $gtfsTrip['num'];
JK 136                 if(!is_array($data) || !isset($data['num'])) {
137                     $data = [
2bac86 138                         'num' => $num ?: '??'.$gtfsTrip['id'],
288a26 139                         'low' => NULL,
4673cc 140                     ];
JK 141                 } elseif($data['num'] != $num) {
142                     // Ignore due to incorrect depot markings in the data
143                     //$this->logger->warn('Got '.$num.', database has '.$data['num']);
144                 }
0c85a7 145                 $result[$this->ttssTrips[$ttssTripId]['id']] = $data;
4673cc 146             }
JK 147         }
148         return $result;
149     }
150 }