Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ compute `dem_coverage` that each passed their own tests
`camera_formats_manifest.csv` as the offline drift guard
- `inst/notes/camera-formats.md` — why `SCALE` is unusable for digital frames, what each of the five QA
checks can and cannot catch, and the PDF extraction traps these specific reports carry
- `inst/notes/georeferencing.md` — the ring-order contract, the three measurements that established the
digital corner mapping, and the one of them that was wrong while looking strongest
- `mixed_media_fixture()` in `tests/testthat/setup.R` — synthesized frames whose format nothing resolves;
`digital_fixture()` beside it covers every resolver branch, and `footprint_cases()` sweeps the 12 input
shapes the invariant tests run over
Expand All @@ -46,8 +48,17 @@ geometry column may be named `geom` not `geometry`
recording format, so a 9-inch negative applied to a digital sensor is wrong by an unknown factor while still
drawing as a rectangle and still producing a coverage percentage. `fly_footprint()` sizes each row from its
`media` value, records the outcome in `footprint_basis`, and returns an **empty geometry** where the format is
unknown. Downstream functions report how many frames they excluded. Digital defaults are deliberately unshipped
until sensor widths are established (#32) — `format_size` is the slot they drop into
unknown. Downstream functions report how many frames they excluded. Sensor widths landed in #32 and
georeferencing in #38, so `footprint_basis` is now the record of *which* route sized a frame rather than a
list of what is missing

- **The digital corner mapping is rotation 270, and it was measured, not reasoned** (v0.7.0, #38) — a
non-square footprint is already rotated onto its flight line by `fly_rectangles()`, so `fly_georef()` must
not apply `bearing_to_rotation()` on top; the top-left pixel maps to the ring's rear-left corner. Three
independent public routes agree (exterior orientation from `patb_georef_url`, adjacent-frame overlap
correlation, FWA lake darkness). **The geometry alone cannot get there** — the aspect invariant narrows
the answer to 270 or 90 and a rectangle is symmetric under the 180 degrees between them, so anyone
re-deriving this from the ring will produce a plausible wrong answer. Read `inst/notes/georeferencing.md`

- **Terrain error is a datum offset, not slope** (v0.5.0, #9) — `FLYING_HEIGHT` is metres **above sea level**,
and reported scale is referenced to an elevation above the ground the photos cover, so it understates footprint
Expand Down Expand Up @@ -85,6 +96,12 @@ a tibble, so `footprint_basis`, `footprint_terrain`, `height_agl` and `dem_cover
documented data source, with geometry and every downstream number still correct. Use `centroid_shapes()` in
`tests/testthat/setup.R` — it sweeps plain / tibble / grouped / `bcdc_sf` — for anything that attaches columns to
user-supplied data. Note the class *set* is carried but not its order: `st_transform()` moves `sf` to the front
- **`local_mocked_bindings(.env = )` is the cleanup environment, not the target.** `.package` names the
package to mock in; `.env` says what the mock unwinds with. Passing `asNamespace("fly")` to `.env` installs
the stub correctly and then never removes it, because a namespace does not exit — so every later test in
the run keeps it. It leaks in the direction that reads as success, since a stub returning `TRUE` makes
assertions pass. Caught in #38 only because a later test asserted a file existed that the stub never wrote

- **`fly_footprint()` must not be handed its own output** (fly#37, open) — `st_coordinates()` on POLYGON returns one
row per vertex, so 20 footprints in gives 100 rows out, silently. There is no guard yet

Expand Down
6 changes: 3 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: fly
Title: Historic Airphoto Footprints, Selection and Georeferencing for
British Columbia
Version: 0.6.0
Date: 2026-08-29
Version: 0.7.0
Date: 2026-08-30
Authors@R: c(
person("Allan", "Irvine", , "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-3495-2128")),
Expand Down Expand Up @@ -32,7 +32,7 @@ Suggests:
furrr,
future,
terra,
testthat (>= 3.0.0),
testthat (>= 3.2.0),
knitr,
rmarkdown
Config/testthat/edition: 3
Expand Down
9 changes: 9 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# fly (development version)

## 0.7.0 (2026-08-30)

- `fly_georef()` georeferences digital frames ([#38](https://github.com/NewGraphEnvironment/fly/issues/38)). v0.6.0 gave them footprints and then excluded them from georeferencing with a warning; that exclusion is gone, so the whole post-2010 catalogue is now georeferenceable rather than only sizeable
- **The corner mapping for a non-square footprint is rotation 270 — the top-left pixel maps to the ring's rear-left corner, equivalently image columns run in the flight direction and image rows run flight-right.** It was measured, not reasoned: a digital footprint is already rotated onto its flight line, so `bearing_to_rotation()` is not applied to it, and the geometry that remains cannot distinguish 270 from 90
- The measurement needed no licence-restricted imagery, which the issue had assumed it would. Three independent public routes agree: the per-frame exterior orientation the catalogue publishes through `patb_georef_url` (the UltraCam Eagle's mount is rigid to 0.18 degrees over 6839 frames spanning the compass); adjacent-frame overlap correlation, which needs no reference imagery at all because consecutive frames check each other (+0.616 and +0.659 against at most +0.43 for the alternatives); and FWA lake darkness. `data-raw/georef_calibrate-corner_mapping.R` reproduces all three, and `inst/notes/georeferencing.md` records them — including the one that disagreed and was wrong
- A frame whose delivered image aspect does not pair with its footprint edges is now **skipped with a warning** rather than written stretched. A wrong pairing produces a valid GeoTIFF in the right CRS over the right ground, squashed by the aspect ratio squared, which nothing downstream would report. This also catches a frame sized from an inferred camera format that does not match the camera that took it
- A non-square footprint built without a flight bearing is drawn axis-aligned and so georeferences as though the flight line ran due north. `fly_bearing()` needs a neighbouring frame, so this is the ordinary result of georeferencing one frame on its own, and it is now warned about rather than left to be noticed in the output
- The `rotation` argument applies to square footprints only, and is documented as such; a `rotation` column in `photos_sf` still overrides per-photo for both. Carrying a film-era `rotation` column into a digital batch therefore overrides the correct mapping — drop the column, or set it to `NA` for those rows

## 0.6.0 (2026-08-30)

- `fly_footprint()` now sizes digital frames, closing the gap #30 made honest but left open ([#32](https://github.com/NewGraphEnvironment/fly/issues/32)). Province-wide that is 223,667 of 1,670,471 frames — the package was quietly film-only for anything after ~2010
Expand Down
Loading
Loading