| /* | |
| * | |
| * Copyright 2015, Google Inc. | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: | |
| * | |
| * * Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * * Redistributions in binary form must reproduce the above | |
| * copyright notice, this list of conditions and the following disclaimer | |
| * in the documentation and/or other materials provided with the | |
| * distribution. | |
| * * Neither the name of Google Inc. nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| * | |
| */ | |
| #include <algorithm> | |
| #include <chrono> | |
| #include <cmath> | |
| #include <iostream> | |
| #include <memory> | |
| #include <string> | |
| #include <grpc/grpc.h> | |
| #include <grpc++/server.h> | |
| #include <grpc++/server_builder.h> | |
| #include <grpc++/server_context.h> | |
| #include <grpc++/security/server_credentials.h> | |
| #include "helper.h" | |
| #include "route_guide.grpc.pb.h" | |
| using grpc::Server; | |
| using grpc::ServerBuilder; | |
| using grpc::ServerContext; | |
| using grpc::ServerReader; | |
| using grpc::ServerReaderWriter; | |
| using grpc::ServerWriter; | |
| using grpc::Status; | |
| using routeguide::Point; | |
| using routeguide::Feature; | |
| using routeguide::Rectangle; | |
| using routeguide::RouteSummary; | |
| using routeguide::RouteNote; | |
| using routeguide::RouteGuide; | |
| using std::chrono::system_clock; | |
| float ConvertToRadians(float num) { | |
| return num * 3.1415926 /180; | |
| } | |
| float GetDistance(const Point& start, const Point& end) { | |
| const float kCoordFactor = 10000000.0; | |
| float lat_1 = start.latitude() / kCoordFactor; | |
| float lat_2 = end.latitude() / kCoordFactor; | |
| float lon_1 = start.longitude() / kCoordFactor; | |
| float lon_2 = end.longitude() / kCoordFactor; | |
| float lat_rad_1 = ConvertToRadians(lat_1); | |
| float lat_rad_2 = ConvertToRadians(lat_2); | |
| float delta_lat_rad = ConvertToRadians(lat_2-lat_1); | |
| float delta_lon_rad = ConvertToRadians(lon_2-lon_1); | |
| float a = pow(sin(delta_lat_rad/2), 2) + cos(lat_rad_1) * cos(lat_rad_2) * | |
| pow(sin(delta_lon_rad/2), 2); | |
| float c = 2 * atan2(sqrt(a), sqrt(1-a)); | |
| int R = 6371000; // metres | |
| return R * c; | |
| } | |
| std::string GetFeatureName(const Point& point, | |
| const std::vector<Feature>& feature_list) { | |
| for (const Feature& f : feature_list) { | |
| if (f.location().latitude() == point.latitude() && | |
| f.location().longitude() == point.longitude()) { | |
| return f.name(); | |
| } | |
| } | |
| return ""; | |
| } | |
| class RouteGuideImpl final : public RouteGuide::Service { | |
| public: | |
| explicit RouteGuideImpl(const std::string& db) { | |
| routeguide::ParseDb(db, &feature_list_); | |
| } | |
| Status GetFeature(ServerContext* context, const Point* point, | |
| Feature* feature) override { | |
| feature->set_name(GetFeatureName(*point, feature_list_)); | |
| feature->mutable_location()->CopyFrom(*point); | |
| return Status::OK; | |
| } | |
| Status ListFeatures(ServerContext* context, | |
| const routeguide::Rectangle* rectangle, | |
| ServerWriter<Feature>* writer) override { | |
| auto lo = rectangle->lo(); | |
| auto hi = rectangle->hi(); | |
| long left = (std::min)(lo.longitude(), hi.longitude()); | |
| long right = (std::max)(lo.longitude(), hi.longitude()); | |
| long top = (std::max)(lo.latitude(), hi.latitude()); | |
| long bottom = (std::min)(lo.latitude(), hi.latitude()); | |
| for (const Feature& f : feature_list_) { | |
| if (f.location().longitude() >= left && | |
| f.location().longitude() <= right && | |
| f.location().latitude() >= bottom && | |
| f.location().latitude() <= top) { | |
| writer->Write(f); | |
| } | |
| } | |
| return Status::OK; | |
| } | |
| Status RecordRoute(ServerContext* context, ServerReader<Point>* reader, | |
| RouteSummary* summary) override { | |
| Point point; | |
| int point_count = 0; | |
| int feature_count = 0; | |
| float distance = 0.0; | |
| Point previous; | |
| system_clock::time_point start_time = system_clock::now(); | |
| while (reader->Read(&point)) { | |
| point_count++; | |
| if (!GetFeatureName(point, feature_list_).empty()) { | |
| feature_count++; | |
| } | |
| if (point_count != 1) { | |
| distance += GetDistance(previous, point); | |
| } | |
| previous = point; | |
| } | |
| system_clock::time_point end_time = system_clock::now(); | |
| summary->set_point_count(point_count); | |
| summary->set_feature_count(feature_count); | |
| summary->set_distance(static_cast<long>(distance)); | |
| auto secs = std::chrono::duration_cast<std::chrono::seconds>( | |
| end_time - start_time); | |
| summary->set_elapsed_time(secs.count()); | |
| return Status::OK; | |
| } | |
| Status RouteChat(ServerContext* context, | |
| ServerReaderWriter<RouteNote, RouteNote>* stream) override { | |
| std::vector<RouteNote> received_notes; | |
| RouteNote note; | |
| while (stream->Read(¬e)) { | |
| for (const RouteNote& n : received_notes) { | |
| if (n.location().latitude() == note.location().latitude() && | |
| n.location().longitude() == note.location().longitude()) { | |
| stream->Write(n); | |
| } | |
| } | |
| received_notes.push_back(note); | |
| } | |
| return Status::OK; | |
| } | |
| private: | |
| std::vector<Feature> feature_list_; | |
| }; | |
| void RunServer(const std::string& db_path) { | |
| std::string server_address("0.0.0.0:50051"); | |
| RouteGuideImpl service(db_path); | |
| ServerBuilder builder; | |
| builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); | |
| builder.RegisterService(&service); | |
| std::unique_ptr<Server> server(builder.BuildAndStart()); | |
| std::cout << "Server listening on " << server_address << std::endl; | |
| server->Wait(); | |
| } | |
| int main(int argc, char** argv) { | |
| // Expect only arg: --db_path=path/to/route_guide_db.json. | |
| std::string db = routeguide::GetDbFileContent(argc, argv); | |
| RunServer(db); | |
| return 0; | |
| } |