module; #include export module routemon:geo.wgs84; import :geo; namespace routemon::geo::wgs84 { using cs = bgeo::cs::geographic; using point = bgeo::model::point; // TODO: guarantee that linestring provides non-static member // auto reserve(std::size_t) -> void // Perhaps better yet: guarantee that the backing container is a std::vector. using linestring = bgeo::model::linestring; using box = bgeo::model::box; using stype = bgeo::srs::spheroid; using vincenty_strategy = bgeo::strategy::distance::vincenty; inline auto from_lat_lon(double lat, double lon) -> point { return point{lon, lat}; } inline auto lat(point p) -> double { return bgeo::get<1>(p); } inline auto lon(point p) -> double { return bgeo::get<0>(p); } // Point p with latitude in [-90, 90] and longitude in [-180, 180) auto normalize(point p) -> point { // Equivalent degrees in the range [0, 360) auto nonneg_mod360 = [](double t) -> double { return std::remainder(std::remainder(t, 360.0) + 360.0, 360.0); }; auto p_lon = lon(p); auto p_lat = nonneg_mod360(lat(p)) - 90.0; if (90.0 < p_lat) { assert(p_lat < 270.0); // by nonneg_mod360 p_lon += 180.0; p_lat -= 180.0; } p_lon = nonneg_mod360(p_lon + 180.0) - 180.0; return from_lat_lon(p_lat, p_lon); } inline auto is_normalized(point p) -> bool { return -90 <= lat(p) && lat(p) <= 90 && -180 <= lon(p) && lon(p) < 180; } class normalized_point { point p_; public: inline normalized_point(point p) : p_{is_normalized(p) ? p : normalize(p)} {} inline normalized_point() : p_{} {} inline auto lat() const -> double { return bgeo::get<1>(p_); } inline auto lon() const -> double { return bgeo::get<0>(p_); } inline auto lat(double lat) -> void { if (lat < -90 || lat > 90) throw std::range_error{"latitude out of range"}; bgeo::set<1>(p_, lat); } inline auto lon(double lon) -> void { if (lon < -180 || lon > 180) throw std::range_error{"longitude out of range"}; bgeo::set<0>(p_, lon); } }; class normalized_linestring { std::vector ls_; public: inline auto empty() const -> bool { return ls_.empty(); } inline auto push_back(normalized_point p) -> void { ls_.push_back(p); } }; } // namespace routemon::geo::wgs84