Practical latitude/longitude geometry for C++17 projects that need GPS math, not a full geometry framework.
Distance, heading, polygon area, point-in-polygon, and path proximity checks — header-only, no dependencies, no build step.
The API is inspired by Google Maps geometry utilities and uses the same spherical Earth approximation model.
- Lat/lng-native API — pass latitude/longitude coordinates directly, no framework-specific point types to convert through.
- Header-only, dependency-free — about 36 KB across 4 headers; nothing to build or link.
- Spherical math — distance, heading, offset, interpolation, area.
- Polygon utilities — point-in-polygon and path proximity checks.
- Fast — matches hand-written haversine on
distance; especially strong on polygonarea(see benchmarks). - Focused scope — intentionally small API for GPS, navigation, tracking, backend, and GIS workflows.
include(FetchContent)
FetchContent_Declare(
GeoUtilsCpp
GIT_REPOSITORY https://github.com/gistrec/geo-utils-cpp.git
GIT_TAG v1.0.1
)
FetchContent_MakeAvailable(GeoUtilsCpp)
target_link_libraries(your_target PRIVATE geo::utils)vcpkg install geo-utils-cppxrepo install geo-utils-cppOr declare it as a dependency in your xmake.lua:
add_requires("geo-utils-cpp")
target("your_target")
add_packages("geo-utils-cpp")conan install --requires=geo-utils-cpp/1.0.1 --build=missingConan Center support is pending conan-io/conan-center-index#30152
Copy the include/ directory into your project and add it to your include path.
With any of the above methods (vcpkg, xrepo, Conan, FetchContent, or a
system find_package), wire it into your build with:
find_package(GeoUtilsCpp 1.0.1 REQUIRED)
target_link_libraries(your_target PRIVATE geo::utils)For more details, see docs/getting-started.md.
Distance and heading between two points:
#include <iostream>
#include <geo/spherical.hpp>
int main() {
geo::LatLng newYork = { 40.7128, -74.0060 };
geo::LatLng london = { 51.5074, -0.1278 };
double distance = geo::distance_between(newYork, london);
double heading = geo::heading(newYork, london);
std::cout << "Distance: " << distance / 1000.0 << " km\n";
std::cout << "Heading: " << heading << " deg\n";
}Polygon area, point-in-polygon, path length, and path proximity:
#include <iostream>
#include <vector>
#include <geo/poly.hpp>
int main() {
// A small box around midtown Manhattan (vertices in CCW order).
std::vector<geo::LatLng> midtown = {
{40.74, -74.01}, {40.74, -73.96}, {40.78, -73.96}, {40.78, -74.01},
};
geo::LatLng timesSquare{40.7580, -73.9855};
std::cout << "Times Square inside: "
<< (geo::contains(timesSquare, midtown) ? "true" : "false") << "\n";
std::cout << "Polygon area: "
<< geo::area(midtown) / 1e6 << " km^2\n";
// A short polyline along Broadway, and a point near it.
std::vector<geo::LatLng> route = {
{40.7580, -73.9855}, // Times Square
{40.7680, -73.9818}, // Columbus Circle
{40.7780, -73.9740}, // Lincoln Center
};
geo::LatLng nearby{40.7670, -73.9820};
std::cout << "Route length: "
<< geo::path_length(route) / 1000.0 << " km\n";
std::cout << "Point within 200 m of route: "
<< (geo::on_path(nearby, route, /*geodesic=*/true, /*tolerance=*/200.0)
? "true" : "false")
<< "\n";
}geo-utils-cpp is header-only with no runtime dependencies. Throughput on
Apple M1 / clang 17 / -O2 -DNDEBUG (higher is better):
| Library | distance_between (M pairs/s) |
area (poly N=100, M polys/s) |
|---|---|---|
| geo-utils-cpp | 40.5 | 67.2 |
| naive haversine | 38.3 | — |
| S2 Geometry | 82.9 | 14.0 |
| Boost.Geometry | 39.8 | 36.2 |
| GeographicLib | 1.2 | 2.0 |
Native types are pre-built outside the timed loop, so the table compares
algorithmic cost rather than object-construction overhead. geo-utils-cpp
matches hand-written haversine and Boost.Geometry on simple spherical operations,
is especially strong on area, while S2 is faster on several operations when
conversion from lat/lng is excluded.
See docs/benchmarks.md for full methodology, all operations, and when to use each library.
- If you need high-precision ellipsoidal geodesics or sub-meter accuracy, use GeographicLib.
- If polygon containment is your main hot path, especially for larger polygons, consider S2 Geometry.
- If you need many geometry types, coordinate systems, or generic geometry algorithms, Boost.Geometry may be a better fit.
- If you need spatial indexing, use S2, CGAL, or another dedicated spatial index.
See docs/api.md for the full API reference.
Please open an issue on GitHub
Licensed under the Apache License, Version 2.0. See LICENSE for details.