Imported from jolars/polylabelr (
AGENTS.md). Install upstream withnpx skills add jolars/polylabelr. Copyright stays with the author.
AGENTS.md
This file provides guidance to agents when working with code in this repository.
Overview
polylabelr is an R package wrapping Mapbox's C++ polylabel library. It exposes
poi(), which finds the approximate pole of inaccessibility (visual center) of a
polygon, and poi_multi() for lists of polygons.
Commands
The environment is provided by devenv (loaded automatically by direnv), which supplies
R with Rcpp, testthat, devtools, roxygen2, covr, spelling, and sf.
Rscript -e 'devtools::load_all()' # compile + load for interactive work
Rscript -e 'devtools::test()' # run all tests
Rscript -e 'devtools::test(filter = "poi-sf")' # run one test file (tests/testthat/test-poi-sf.R)
Rscript -e 'devtools::document()' # regenerate NAMESPACE and man/ from roxygen
Rscript -e 'Rcpp::compileAttributes()' # regenerate RcppExports after editing src/poi.cpp
Rscript -e 'devtools::check()' # full R CMD check
Rscript -e 'devtools::build_readme()' # README.md is generated; edit README.Rmd only
Generated files that must never be hand-edited: NAMESPACE, man/*.Rd,
R/RcppExports.R, src/RcppExports.cpp, README.md.
Architecture
Everything funnels into a single C++ entry point. src/poi.cpp exports poi_cpp(poly_list, precision), which takes a list of two-column numeric matrices — the first matrix is the
outer ring, the rest are holes — and returns c(x, y, dist). All R-level complexity is about
reducing arbitrary geometry inputs to that list of rings.
The R layer is S3 dispatch on poi():
poi.default()(R/poi.R) is the base case. It runs input throughgrDevices::xy.coords()and then splits the coordinates onNAvalues, which act as ring separators (matchinggraphics::polypath()semantics). Every other method eventually delegates here.R/poi_sf.Rholds the simple-features methods.poi.sf→poi.sfc→ per-geometry methods;poi.POLYGONrbinds its rings back into oneNA-free matrix stack and hands off topoi.default. Points and lines return their first coordinate. Unsupportedsfgtypes warn and returnNA.- Methods that must choose among several candidate points (
poi.MULTIPOLYGON,poi.GEOMETRYCOLLECTION,poi_multi.list) all usewhich_max_dist()inR/utils.R, which picks the candidate with the largest$distand toleratesNAentries from unsupported geometries.
sf is a soft dependency (Suggests); sf tests use skip_if_not_installed("sf").
Vendored Mapbox headers
inst/include/mapbox/ contains vendored upstream headers (polylabel.hpp, geometry.hpp,
variant.hpp, and friends), reachable via -I../inst/include/ in src/Makevars. These are
locally patched and should not be refreshed from upstream wholesale:
geometry.hpphad GCC diagnostic pragmas removed because they trippedR CMD check.variant.hppconditionsstd::result_ofon the C++ standard version, falling back tostd::invoke_resultfor C++20 wherestd::result_ofwas removed.polylabel.hppis no longer vendored upstream code. Mapbox deleted its C++ implementation in #124, so the header is a local C++ port of upstream'spolylabel.js, tracked against https://github.com/mapbox/polylabel/blob/master/polylabel.js. It is kept structurally close to the JavaScript (same function names, same comments) so future upstream changes can be transliterated. Upstream's own test expectations are reproduced bit for bit.- It deliberately diverges in one place: upstream short-circuits any polygon whose smaller
bounding-box dimension is
<= precisionand returns a bounding-box corner, whereas we only short-circuit genuinely degenerate polygons. See theNOTEinpolylabelWithDistance(). polylabelWithDistance()returns the center and its distance together, since the search already knows the distance;polylabel()remains available and returns just the point.tests/testthat/test-upstream.Rmirrors upstream's whole test suite and must keep passing. Itswater.rdsfixture is upstream'stest/fixtures/water1.jsonandwater2.json, each read into a list of two-column ring matrices and saved withsaveRDS(..., version = 2, compress = "xz").
- It deliberately diverges in one place: upstream short-circuits any polygon whose smaller
bounding-box dimension is
License attribution for each vendored file lives in inst/COPYRIGHTS; update it if the set
of vendored files changes.
Conventions
- Semantic versioning;
NEWS.mdis maintained in release-please format. tests/spelling.Rspell-checks documentation — add legitimate new terms toinst/WORDLIST.- New tests generally assert both a numeric property of the result and that the point lies
inside the polygon, using the
point_in_polygon()helper intests/testthat/helper_point_in_polygon.R.