Skip to content

Bearing rotation for diagonal flight lines — film half (mechanism built in #32) #26

Description

@NewGraphEnvironment

Problem

fly_georef(rotation = "auto") derives rotation from flight bearing using floor((bearing + 91) / 90) * 90 %% 360. This works for E-W flight lines (~90°/~270° bearings) but fails for diagonal flights (~230°, ~45°, etc.).

Two photos at bearing ~230° needed opposite rotations:

  • bc5282_233 (1968): correct rotation = 0
  • bcd19503_522 (2019): correct rotation = 180

Same bearing, different eras → camera/scanner orientation difference that 90° quantization can't capture.

Proposed Solution

Rotate the footprint polygon by the flight bearing instead of shuffling pixel corners in a north-up box. This allows continuous rotation, not just 90° increments.

Requires changes to fly_footprint() to accept a bearing and produce a rotated rectangle.

Status update, 2026-08-30 — the mechanism now exists (#32, v0.6.0)

fly_rectangles() takes half_cross, half_along and a bearing, and applies
continuous rotation about the centroid. fly_footprint() computes the bearing via
fly_bearing() and threads it through both DEM sampling passes as well as the returned
geometry. So the change this issue asks for has been built.

It is deliberately applied only where the recording format is non-square — i.e. to
digital frames. Film stays square and axis-aligned, so film output is byte-identical to
before, which is what kept #32 from moving every existing footprint.

That splits this issue's two failing cases:

  • bcd19503_522 (2019, digital) — covered by Georeference digital frames: the corner mapping assumes a square, axis-aligned footprint #38, which is where the corner mapping for
    a pre-rotated non-square footprint gets established against real imagery.
  • bc5282_233 (1968, film) — still open, and still exactly as described above. A
    square footprint is unchanged by rotation, so rotating it cannot by itself fix a
    wrong-by-180 corner mapping; what is needed is for fly_georef() to stop quantizing
    the bearing to 90 degrees.

So what remains here is the film half, and it is a decision rather than a build: the
rotation machinery is in place, and applying it to film would change existing film
output. The workaround below is still the current answer.

Workaround

Set a rotation column on photos_sf for affected rolls:

photos$rotation <- dplyr::case_when(
  photos$film_roll == "bc5282" ~ 0L,
  photos$film_roll == "bcd19503" ~ 180L,
  .default = NA  # fall through to auto
)

Context

Discovered while calibrating auto-rotation (#25). Affects ~diagonal flights which are a minority of the dataset.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions