fix(overlay): Photos-ready dims follow tape, not wood MAR

After rotateCalibration, map tape tick A→B through bakeTiltTransform into
baked cal coords, orient overlay bbox with orientedRect(..., tapeAngle), and
pass optional axis into buildOverlayPlan so length || tape and widths ⊥ tape.
This commit is contained in:
grokbot_ty
2026-09-26 08:08:21 -07:00
parent d7fc424b69
commit 4ea2618475
5 changed files with 257 additions and 18 deletions
+20 -2
View File
@@ -10,7 +10,7 @@ import { measure } from '../measure/measure';
import { orientedRect } from '../geometry/rect';
import { encodeInventoryPng, type InventoryInput } from '../png/inventory';
import { encodeOverlayPng, type EncodeOverlayInput } from '../png/overlay';
import { rotateCalibration } from '../png/rotateCal';
import { bakeTiltTransform, rotateCalibration } from '../png/rotateCal';
import { decodeOrientedBitmap } from '../decodeOrientedBitmap';
import { clampTiltDeg, defaultTape, tapeEndpoints, type TapeTransform } from './tapeGeometry';
import { getCropFill } from '../settings/cropFill';
@@ -636,19 +636,37 @@ export function createCaptureSession(opts: SessionOpts = {}): CaptureSession {
// #63: second copy of the calibration inventory PNG with dimension overlays.
// Keep clean inventoryPng untouched; never stash overlay into batchApply[cal].
// Overlay uses the same baked orientation as the clean cal PNG (#99 scope).
// Length / width directions follow the tape (not wood MAR): map tick A→B
// through the same bake as rotateCal, then orient the overlay bbox to that.
let overlayBlob: Blob;
try {
const preEp = axis.tape.spanPx > 0
? tapeEndpoints(axis.tape, source.widthPx, source.heightPx)
: null;
const bakeXform = bakeTiltTransform(source.widthPx, source.heightPx, axis.tape.tiltDeg);
let overlayBbox = calMask.bbox;
let overlayAxis: { start: [number, number]; end: [number, number] } | undefined;
if (preEp && preEp.spanPx > 0) {
const start = bakeXform.mapPoint(preEp.start[0], preEp.start[1]);
const end = bakeXform.mapPoint(preEp.end[0], preEp.end[1]);
const dx = end[0] - start[0];
const dy = end[1] - start[1];
const angleDeg = ((Math.atan2(dy, dx) * 180) / Math.PI + 180) % 180;
overlayBbox = orientedRect(calMask.bbox, angleDeg);
overlayAxis = { start, end };
}
overlayBlob = await encodeOverlay({
inventoryPng: pngBlob,
bitset: calMask.bitset,
widthPx: calSource.widthPx,
heightPx: calSource.heightPx,
bbox: calMask.bbox,
bbox: overlayBbox,
scale: base.scale,
lengthIn: eighthsToIn(lengthEighths),
lengthLabel: fmtEighths(lengthEighths),
slabBounds: calMask.slabBounds,
source: calSource,
axis: overlayAxis,
});
} catch {
// Deterministic tests may inject a non-decodable inventory blob; still