This page walks through installing geo-utils-cpp and writing your first
program. For a wider tour of the library, see the README;
for full function-level documentation, see api.md; for
performance comparisons against S2, Boost.Geometry, and GeographicLib,
see benchmarks.md.
- C++17 or later (tested on C++17, C++20, and C++23 in CI)
- CMake 3.14 or later
- A standard-conformant compiler. CI covers recent GCC, Clang, AppleClang, and MSVC on Linux, macOS, and Windows — see the CI badges in the README for the exact matrix.
The library is header-only with no runtime dependencies — there is nothing to link against beyond the headers themselves.
Pick the option that matches how your project already manages dependencies. If you don't have a preference, FetchContent is the lowest-friction path: no separate install step, version pinned per project, works offline once cached.
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)The library is available in the official vcpkg registry.
Classic mode — install once into the vcpkg shared store:
vcpkg install geo-utils-cppManifest mode — pin the dependency per-project in vcpkg.json (preferred
for new projects, since the manifest commits alongside your source):
{
"dependencies": [
"geo-utils-cpp"
]
}Either mode, then consume it from CMake:
find_package(GeoUtilsCpp 1.0.1 REQUIRED)
target_link_libraries(your_target PRIVATE geo::utils)The library is available in the official
xmake-repo registry as
geo-utils-cpp.
Install via the xrepo CLI:
xrepo install geo-utils-cppOr declare it as a dependency in your xmake.lua:
add_requires("geo-utils-cpp")
target("your_target")
set_kind("binary")
add_files("main.cpp")
add_packages("geo-utils-cpp")A minimal smoke-test consumer (tests/consumer/) is included for both CMake
and xmake builds — see tests/consumer/xmake.lua
for the xmake variant.
conan install --requires=geo-utils-cpp/1.0.1 --build=missingConan Center support is pending conan-io/conan-center-index#30152; until that lands, install from the local recipe in the conan/ directory.
Build and install the library to a prefix on your machine, then have
downstream projects locate it via find_package:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --install build --prefix /usr/localfind_package(GeoUtilsCpp 1.0.1 REQUIRED)
target_link_libraries(your_target PRIVATE geo::utils)If find_package can't locate the library, point CMake at the install
prefix via -DCMAKE_PREFIX_PATH=/usr/local (or wherever you installed it).
Copy the include/ directory into your project and add it to your
compiler's include path:
g++ main.cpp -std=c++17 -I/path/to/geo-utils-cpp/include -o mainInclude the umbrella header for everything, or pull in individual modules for tighter compile times:
// Everything at once
#include <geo/geo.hpp>
// Or individual modules
#include <geo/latlng.hpp> // types
#include <geo/spherical.hpp> // distance, heading, offset, area
#include <geo/poly.hpp> // point-in-polygon, on-path#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";
}LatLng::operator== is an approximate comparison with tolerance 1e-12
degrees (≈ 0.1 nanometers on Earth) — fine for bit-exact equality, too
strict to compare results of floating-point geometry. For coarser-scale
comparisons, pass an explicit tolerance to approx_equal:
#include <geo/spherical.hpp>
geo::LatLng start{40.0, -74.0};
geo::LatLng end = geo::offset(start, 100'000.0, 90.0); // 100 km east
auto recovered = geo::offset_origin(end, 100'000.0, 90.0);
assert(recovered.has_value());
// 1e-6 degrees ≈ 11 cm on the equator — comfortably above the
// floating-point noise of a 100 km round-trip.
assert(recovered->approx_equal(start, 1e-6));#include <iostream>
#include <vector>
#include <geo/poly.hpp>
int main() {
// A small box around midtown Manhattan.
std::vector<geo::LatLng> polygon = {
{ 40.7650, -73.9900 },
{ 40.7650, -73.9700 },
{ 40.7450, -73.9700 },
{ 40.7450, -73.9900 },
};
geo::LatLng timesSquare = { 40.7580, -73.9855 };
geo::LatLng centralPark = { 40.7829, -73.9654 };
std::cout << std::boolalpha;
std::cout << "Times Square inside: " << geo::contains(timesSquare, polygon) << "\n"; // true
std::cout << "Central Park inside: " << geo::contains(centralPark, polygon) << "\n"; // false
}More runnable samples live in examples/ — each is a
single .cpp file you can build and run standalone.
After CMake configure, compile_commands.json is generated in the build
directory. Most language servers (clangd, ccls) pick it up automatically;
point your editor at the build directory if it doesn't.
The sections above are for using geo-utils-cpp as a dependency. If
you're working on the library — running tests, building examples,
measuring coverage — clone the repo and configure it as a top-level
project:
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure| Option | Default | Purpose |
|---|---|---|
GEO_UTILS_CPP_BUILD_TESTS |
ON if top-level |
Build unit tests |
GEO_UTILS_CPP_BUILD_EXAMPLES |
ON if top-level |
Build the examples in examples/ |
GEO_UTILS_CPP_ENABLE_COVERAGE |
OFF |
gcov instrumentation; GCC/Clang only |
Downstream users consuming geo-utils-cpp as a dependency don't need to
touch these — tests and examples are off by default when the library is
included via FetchContent / find_package.
A few issues that catch people on first use:
-
find_package(GeoUtilsCpp)fails. The install prefix isn't on CMake's search path. Add-DCMAKE_PREFIX_PATH=/path/to/prefixto your configure command (or set the env var). -
FetchContentre-downloads on every configure. Add-DFETCHCONTENT_UPDATES_DISCONNECTED=ONonce the dependency is cached, or pin to a specificGIT_TAG(which we already do in the snippet above). -
no matching function for call to 'area({{...}, ...})'. A braced initializer can't be deduced as aPathtemplate parameter — wrap it in astd::vector<geo::LatLng>first. See the Path notes in api.md. -
clangd doesn't see the headers. Make sure CMake has generated
compile_commands.json(it does so automatically once you've configured a build directory) and that your editor is pointed at it.
- API reference — every public function, with examples and edge-case notes.
- Benchmarks — how
geo-utils-cppcompares to S2, Boost.Geometry, and GeographicLib, and where each one is the right tool. examples/— runnable code samples.- Open an issue if something here doesn't work or doesn't make sense.