| <?php | |
| /* | |
| * | |
| * Copyright 2020 gRPC authors. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| * | |
| */ | |
| class RouteGuideService extends \Routeguide\RouteGuideStub | |
| { | |
| public function __construct($dbFilePath) | |
| { | |
| $dbFilePath = $dbFilePath ?? dirname(__FILE__) . '/route_guide_db.json'; | |
| $dbData = file_get_contents($dbFilePath); | |
| if (!$dbData) { | |
| throw new InvalidArgumentException( | |
| "Error reading route db file: " . $dbFilePath | |
| ); | |
| } | |
| $featureList = json_decode($dbData); | |
| if (!$featureList) { | |
| throw new InvalidArgumentException( | |
| "Error decoding route db file: " . $dbFilePath | |
| ); | |
| } | |
| foreach ($featureList as $feature) { | |
| array_push($this->featureList, new Routeguide\Feature([ | |
| 'name' => $feature->name, | |
| 'location' => new Routeguide\Point([ | |
| 'latitude' => $feature->location->latitude, | |
| 'longitude' => $feature->location->longitude, | |
| ]), | |
| ])); | |
| } | |
| } | |
| private function findFeature(\Routeguide\Point $point) | |
| { | |
| foreach ($this->featureList as $feature) { | |
| $location = $feature->getLocation(); | |
| if ( | |
| $location->getLatitude() === $point->getLatitude() | |
| && $location->getLongitude() === $point->getLongitude() | |
| ) { | |
| return $feature; | |
| } | |
| } | |
| return null; | |
| } | |
| // The formula is based on http://mathforum.org/library/drmath/view/51879.html | |
| private function calculateDistance( | |
| \Routeguide\Point $start, | |
| \Routeguide\Point $end | |
| ) { | |
| $toRadians = function (float $num) { | |
| return $num * 3.1415926 / 180; | |
| }; | |
| $coordFactor = 10000000.0; | |
| $R = 6371000; // metres | |
| $lat_1 = $start->getLatitude() / $coordFactor; | |
| $lat_2 = $end->getLatitude() / $coordFactor; | |
| $lon_1 = $start->getLongitude() / $coordFactor; | |
| $lon_2 = $end->getLongitude() / $coordFactor; | |
| $lat_rad_1 = $toRadians($lat_1); | |
| $lat_rad_2 = $toRadians($lat_2); | |
| $delta_lat_rad = $toRadians($lat_2 - $lat_1); | |
| $delta_lon_rad = $toRadians($lon_2 - $lon_1); | |
| $a = pow(sin($delta_lat_rad / 2), 2) + | |
| cos($lat_rad_1) * cos($lat_rad_2) * pow(sin($delta_lon_rad / 2), 2); | |
| $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); | |
| return $R * $c; | |
| } | |
| public function GetFeature( | |
| \Routeguide\Point $request, | |
| \Grpc\ServerContext $serverContext | |
| ): ?\Routeguide\Feature { | |
| $feature = $this->findFeature($request); | |
| $notFoundFeature = new Routeguide\Feature([ | |
| 'name' => '', | |
| 'location' => $request, | |
| ]); | |
| return $feature ?? $notFoundFeature; | |
| } | |
| public function ListFeatures( | |
| \Routeguide\Rectangle $request, | |
| \Grpc\ServerCallWriter $writer, | |
| \Grpc\ServerContext $serverContext | |
| ): void { | |
| $lo = $request->getLo(); | |
| $hi = $request->getHi(); | |
| $left = min($lo->getLongitude(), $hi->getLongitude()); | |
| $right = max($lo->getLongitude(), $hi->getLongitude()); | |
| $top = max($lo->getLatitude(), $hi->getLatitude()); | |
| $bottom = min($lo->getLatitude(), $hi->getLatitude()); | |
| foreach ($this->featureList as $feature) { | |
| $longitude = $feature->getLocation()->getLongitude(); | |
| $latitude = $feature->getLocation()->getLatitude(); | |
| if ( | |
| $longitude >= $left && $longitude <= $right | |
| && $latitude >= $bottom && $latitude <= $top | |
| ) { | |
| $writer->write($feature); | |
| } | |
| } | |
| $writer->finish(); | |
| } | |
| public function RecordRoute( | |
| \Grpc\ServerCallReader $reader, | |
| \Grpc\ServerContext $serverContext | |
| ): ?\Routeguide\RouteSummary { | |
| $point_count = 0; | |
| $feature_count = 0; | |
| $distance = 0; | |
| $previous = null; | |
| $start_time = time(); | |
| while ($point = $reader->read()) { | |
| $point_count++; | |
| $feature = $this->findFeature($point); | |
| if ($feature) { | |
| $feature_count++; | |
| if ($previous) { | |
| $distance += $this->calculateDistance($previous, $point); | |
| } | |
| $previous = $point; | |
| } | |
| } | |
| $summary = new \Routeguide\RouteSummary(); | |
| $summary->setPointCount($point_count); | |
| $summary->setFeatureCount($feature_count); | |
| $summary->setDistance($distance); | |
| $summary->setElapsedTime(time() - $start_time); | |
| return $summary; | |
| } | |
| public function RouteChat( | |
| \Grpc\ServerCallReader $reader, | |
| \Grpc\ServerCallWriter $writer, | |
| \Grpc\ServerContext $serverContext | |
| ): void { | |
| while ($note = $reader->read()) { | |
| foreach ($this->received_notes as $n) { | |
| if ( | |
| $n->getLocation()->getLatitude() === | |
| $note->getLocation()->getLatitude() | |
| && $n->getLocation()->getLongitude() === | |
| $note->getLocation()->getLongitude() | |
| ) { | |
| $writer->write($n); | |
| } | |
| } | |
| array_push($this->received_notes, $note); | |
| } | |
| $writer->finish(); | |
| } | |
| private $received_notes = []; | |
| private $featureList = []; | |
| } |