Working rules for Claude Code (and any human collaborator) when editing this package. The figureextract meta-repo's
ARCHITECTURE.mdandDECISIONS.mddescribe the wider ecosystem; this file is the per-package complement.
thinr provides binary image thinning (skeletonization) algorithms — Zhang-Suen, Guo-Hall, Lee (2-D), K3M, the parallel form commonly attributed to Hilditch, OPTA / SPTA, and Holt — behind a single dispatching API. Also provides the medial axis transform (Blum 1967) and a fast distance transform (Felzenszwalb-Huttenlocher 2012; classic two-pass sweep). EBImage provides binary morphology but no thinning operator, so thinr complements it rather than replacing any of its functions. Per ADR-007 this is the one public CRAN package in the figureextract ecosystem; LGPL-3 is chosen for EBImage compatibility.
- Slice: 0 — Infrastructure
- Version: 0.2.0
- Status: CRAN-prep release. Seven thinning algorithms fully implemented in Rcpp, all verified against original papers (or the Lam-Lee-Suen 1992 survey for Hilditch's parallel form). Medial axis and distance transform shipped as standalone exported utilities. PR #1 (
release-prep) and PR #2 (coverage-bump) both merged tomain. Tests pass; lintr clean; R CMD check --as-cran clean (0/0/2 NOTEs, both expected). GitHub Actions: R-CMD-check (matrix), pkgdown, test-coverage, lint, pr-commands. - Recent shipments:
- R-side coverage to its practical maximum (2026-05-21, PR #2,
1870e25) — added tests covering the remaining branches in thethin()dispatcher and the storage-restoration helpers. - release-prep merged (2026-05-20, PR #1,
98f4a80) — the CRAN-prep branch (with all reviewer-feedback fixes, the K3M / OPTA / Holt verifications, the Stentiford / Pavlidis drop, and pkgdown reference-index fix) landed onmain. - Dropped
stentiford(folk misattribution; the 1983 paper is preprocessing not thinning) andpavlidis(the implementation didn't match the contour-following algorithm of the 1980 paper). The dropped algorithms are not implemented in any major image-processing library (scikit-image, OpenCV, MATLAB, ImageJ, mahotas); per the package's "widely used elsewhere" inclusion criterion, removing them keeps the package focused. (2026-05-20) - Algorithm verification pass against papers in
references/: K3M lookup tables corrected against Saeed et al. 2010; OPTA rewritten per survey's safe-point expression; Holt rewritten per the original CACM paper (correcting a survey transcription error in the middle clause). (2026-05-20) - Tier-1 + Tier-2 algorithm expansion: Hilditch, OPTA, Holt; plus
medial_axis()anddistance_transform(). (2026-05-16) - CRAN reviewer feedback addressed (function-name quotes + DOIs). (2026-05-16)
- v0.2.0 stub-replacement: Lee 2-D and K3M fully implemented. (2026-05-16)
- v0.1.0 skeleton with Rcpp setup, 2 algorithms, vignette, README, NEWS, GitHub Actions CI, pkgdown. (2026-05-16)
- R-side coverage to its practical maximum (2026-05-21, PR #2,
- Style: tidyverse style guide.
styler::style_pkg()clean.lintr::lint_package()clean per.lintr(line length 100, snake_case + CamelCase, no commented-code linter). - C++: ISO C++17 baseline (Rcpp default for current R). Two-space indent. No
using namespace std. Avoid Rcpp sugar in tight loops where it costs measurable performance. - R version: ≥ 4.2.
- Pipe: native
|>preferred. - Imports: Rcpp only. Don't add dependencies without a strong reason — this is a small, focused, CRAN-friendly package.
- Framework:
testthat3rd edition with thedescribe/itBDD style (legible test reports for a public package). - Coverage: every algorithm in
methods <- c(...)(currently nine) is exercised against the same property suite (solid square thins, line collapse, idempotence, empty input, isolated-pixel preservation, ring topology). New methods are added to the vector and inherit all tests automatically. distance_transformandmedial_axiseach have their own test files (tests/testthat/test-distance-transform.R,test-medial-axis.R).- Acceptance:
R CMD check --as-cranclean (0 errors, 0 warnings, NOTEs acceptable for "new submission" and the Ubuntu system compilation-flags note).
C++ sources in src/:
thinr_common.h— shared inline helpers (crossing_number,neighbour_count,is_border_4).zhang_suen.cpp— Zhang & Suen (1984).guo_hall.cpp— Guo & Hall (1989).lee.cpp— Lee, Kashyap & Chu (1994), 2-D adaptation.k3m.cpp— Saeed et al. (2010); paper lookup tables reproduced verbatim.hilditch.cpp— parallel form commonly attributed to Hilditch (1969); the actual implementation follows the Rutovitz-style R1–R4 conditions as documented in Lam, Lee & Suen (1992).opta.cpp— Naccache & Shinghal (1984), Safe Point Thinning Algorithm; boolean safe-point expression follows the survey.holt.cpp— Holt, Stewart, Clint & Perrott (1987); condition H follows the original CACM paper (a survey transcription error was caught and corrected against the original).distance_transform.h+distance_transform.cpp— Felzenszwalb-Huttenlocher 2012 squared Euclidean + Rosenfeld-Pfaltz two-pass sweep for L1 and L∞.medial_axis.cpp— ridge detection on the squared Euclidean DT.RcppExports.cpp— auto-generated; do not edit (regenerated byRcpp::compileAttributes()).
R sources in R/:
thin.R—thin()dispatching function and theas_binary_matrix()/restore_storage()coercion helpers.distance_transform.R— exported wrapper for.distance_transform_cpp.medial_axis.R— exported wrapper for.medial_axis_cpp.thinr-package.R— package-level Roxygen doc.RcppExports.R— auto-generated; do not edit.
- Exported:
thin(),medial_axis(),distance_transform(). - Internal:
as_binary_matrix(),restore_storage()(helpers; not exported).
To add a new thinning algorithm:
- Add
src/<algorithm>.cppexporting.<algorithm>_cpp(IntegerMatrix, int). Use the helpers inthinr_common.h. - Run
Rcpp::compileAttributes(".")soR/RcppExports.Ris regenerated. - Add the method name to the
match.arglist and theswitch()inR/thin.R. - Add the method to the
methodsvector at the top oftests/testthat/test-thin.R— all property tests apply automatically. - Update
NEWS.md, the algorithms table inREADME.md, the algorithms section inR/thinr-package.R, and the algorithms table invignettes/choosing-a-method.Rmd. - Add the published reference to
DESCRIPTIONDescription field if it has a DOI.
CRAN package documentation conventions:
- Every exported function has Roxygen
@param,@return,@examples. - Examples are runnable (
R CMD checkruns them with--run-donttest). - The vignette is non-trivial; it shows a real comparison of algorithms.
- The README has install instructions and a usage snippet.
- NEWS.md follows the standard "version - bullet list" format.
cran-comments.mdis updated on every CRAN submission.
R CMD check,devtools::check(),devtools::test(),devtools::document().Rcpp::compileAttributes(),roxygen2::roxygenize().lintr::lint_package(),styler::style_pkg(),covr::package_coverage().pkgdown::build_site(),usethis::use_*()helpers that only edit local files.- Reading any file;
ls,git status,git log,git diff.
- Adding / removing dependencies (this package wants to stay small).
- Renaming / removing exported functions (breaking change).
- Bumping the major version.
- Modifying CI configuration.
- Any
gitcommit, tag, branch, or push. - Submitting to CRAN (
devtools::submit_cran(),devtools::release()). - Modifying the LGPL-3 license declaration.
- Force-push.
- Commit secrets.
- Modify git config.
- Skip git hooks.
- Destructive resets without per-instance approval.
- Multi-step work: propose a plan, wait for explicit approval.
- Surface suggestions; don't implement without approval.
- Convert relative dates to absolute when committing or writing docs.
LGPL-3, per ADR-007 and ADR-017. Public CRAN release.
- The LGPL-3 license is the same as EBImage's, so EBImage can depend on
thinrwithout relicensing concerns. - Source files do not carry per-file copyright headers (CRAN convention); the LGPL-3 text is included by R's standard license machinery via
License: LGPL-3inDESCRIPTION. - Contributors retain copyright in their contributions, licensed under LGPL-3.