1<?php 2/* 3 * 4 * Copyright 2020 gRPC authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 */ 19 20 21class RouteGuideService extends \Routeguide\RouteGuideStub 22{ 23 public function __construct($dbFilePath) 24 { 25 $dbFilePath = $dbFilePath ?? dirname(__FILE__) . '/route_guide_db.json'; 26 $dbData = file_get_contents($dbFilePath); 27 if (!$dbData) { 28 throw new InvalidArgumentException( 29 "Error reading route db file: " . $dbFilePath 30 ); 31 } 32 $featureList = json_decode($dbData); 33 if (!$featureList) { 34 throw new InvalidArgumentException( 35 "Error decoding route db file: " . $dbFilePath 36 ); 37 } 38 foreach ($featureList as $feature) { 39 array_push($this->featureList, new Routeguide\Feature([ 40 'name' => $feature->name, 41 'location' => new Routeguide\Point([ 42 'latitude' => $feature->location->latitude, 43 'longitude' => $feature->location->longitude, 44 ]), 45 ])); 46 } 47 } 48 49 private function findFeature(\Routeguide\Point $point) 50 { 51 foreach ($this->featureList as $feature) { 52 $location = $feature->getLocation(); 53 if ( 54 $location->getLatitude() === $point->getLatitude() 55 && $location->getLongitude() === $point->getLongitude() 56 ) { 57 return $feature; 58 } 59 } 60 return null; 61 } 62 63 // The formula is based on http://mathforum.org/library/drmath/view/51879.html 64 private function calculateDistance( 65 \Routeguide\Point $start, 66 \Routeguide\Point $end 67 ) { 68 $toRadians = function (float $num) { 69 return $num * 3.1415926 / 180; 70 }; 71 $coordFactor = 10000000.0; 72 $R = 6371000; // metres 73 74 $lat_1 = $start->getLatitude() / $coordFactor; 75 $lat_2 = $end->getLatitude() / $coordFactor; 76 $lon_1 = $start->getLongitude() / $coordFactor; 77 $lon_2 = $end->getLongitude() / $coordFactor; 78 $lat_rad_1 = $toRadians($lat_1); 79 $lat_rad_2 = $toRadians($lat_2); 80 $delta_lat_rad = $toRadians($lat_2 - $lat_1); 81 $delta_lon_rad = $toRadians($lon_2 - $lon_1); 82 83 $a = pow(sin($delta_lat_rad / 2), 2) + 84 cos($lat_rad_1) * cos($lat_rad_2) * pow(sin($delta_lon_rad / 2), 2); 85 $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); 86 87 return $R * $c; 88 } 89 90 public function GetFeature( 91 \Routeguide\Point $request, 92 \Grpc\ServerContext $serverContext 93 ): ?\Routeguide\Feature { 94 $feature = $this->findFeature($request); 95 $notFoundFeature = new Routeguide\Feature([ 96 'name' => '', 97 'location' => $request, 98 ]); 99 return $feature ?? $notFoundFeature; 100 } 101 102 public function ListFeatures( 103 \Routeguide\Rectangle $request, 104 \Grpc\ServerCallWriter $writer, 105 \Grpc\ServerContext $serverContext 106 ): void { 107 $lo = $request->getLo(); 108 $hi = $request->getHi(); 109 $left = min($lo->getLongitude(), $hi->getLongitude()); 110 $right = max($lo->getLongitude(), $hi->getLongitude()); 111 $top = max($lo->getLatitude(), $hi->getLatitude()); 112 $bottom = min($lo->getLatitude(), $hi->getLatitude()); 113 114 foreach ($this->featureList as $feature) { 115 $longitude = $feature->getLocation()->getLongitude(); 116 $latitude = $feature->getLocation()->getLatitude(); 117 if ( 118 $longitude >= $left && $longitude <= $right 119 && $latitude >= $bottom && $latitude <= $top 120 ) { 121 $writer->write($feature); 122 } 123 } 124 125 $writer->finish(); 126 } 127 128 public function RecordRoute( 129 \Grpc\ServerCallReader $reader, 130 \Grpc\ServerContext $serverContext 131 ): ?\Routeguide\RouteSummary { 132 $point_count = 0; 133 $feature_count = 0; 134 $distance = 0; 135 $previous = null; 136 137 $start_time = time(); 138 while ($point = $reader->read()) { 139 $point_count++; 140 $feature = $this->findFeature($point); 141 if ($feature) { 142 $feature_count++; 143 if ($previous) { 144 $distance += $this->calculateDistance($previous, $point); 145 } 146 $previous = $point; 147 } 148 } 149 150 $summary = new \Routeguide\RouteSummary(); 151 $summary->setPointCount($point_count); 152 $summary->setFeatureCount($feature_count); 153 $summary->setDistance($distance); 154 $summary->setElapsedTime(time() - $start_time); 155 156 return $summary; 157 } 158 159 public function RouteChat( 160 \Grpc\ServerCallReader $reader, 161 \Grpc\ServerCallWriter $writer, 162 \Grpc\ServerContext $serverContext 163 ): void { 164 while ($note = $reader->read()) { 165 foreach ($this->received_notes as $n) { 166 if ( 167 $n->getLocation()->getLatitude() === 168 $note->getLocation()->getLatitude() 169 && $n->getLocation()->getLongitude() === 170 $note->getLocation()->getLongitude() 171 ) { 172 $writer->write($n); 173 } 174 } 175 array_push($this->received_notes, $note); 176 } 177 $writer->finish(); 178 } 179 180 private $received_notes = []; 181 private $featureList = []; 182} 183