cbor: carry the direct beam on the start message

beam_center_x/y is the PONI - the foot of the perpendicular from the sample - so on a tilted
detector it is not where the beam lands, and the two are distance*tan(tilt)/pixel apart (~8 px on
a real in-house setup). A consumer that wants the beam position, which is what most of them mean,
had to redo the tilt arithmetic or get it wrong.

Add optional direct_beam_x/direct_beam_y to StartMessage, filled from the geometry's own
GetDirectBeam_pxl() so there is no second formula, and put them at the top level of the CBOR start
map beside beam_center_x/y. Optional keys, so a consumer that does not know them skips them.

No _pxl suffix: the stream2 neighbours (beam_center_x, pixel_size_x, detector_distance) carry none
and the units are in docs/CBOR.md. The API's calibration schema spells it direct_beam_x_pxl because
its neighbours there are beam_x_pxl - same quantity, each matching its own neighbourhood.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
2026-09-01 15:12:28 +02:00
co-authored by Claude Opus 5
parent 0e245d28cf
commit 336fafffd0
5 changed files with 27 additions and 0 deletions
@@ -689,6 +689,10 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
CBOR_ENC_AXIS(mapEncoder, "detector_translation", message.detector_translation);
CBOR_ENC(mapEncoder, "beam_center_x", message.beam_center_x);
CBOR_ENC(mapEncoder, "beam_center_y", message.beam_center_y);
// Not a DECTRIS field, and skipped by a consumer that does not know it. beam_center_x/y above is
// the PONI, which is not where the beam lands once the detector is tilted; these two are.
CBOR_ENC(mapEncoder, "direct_beam_x", message.direct_beam_x);
CBOR_ENC(mapEncoder, "direct_beam_y", message.direct_beam_y);
CBOR_ENC(mapEncoder, "countrate_correction_enabled", message.countrate_correction_enabled);
CBOR_ENC(mapEncoder, "flatfield_enabled", message.flatfield_enabled);
CBOR_ENC(mapEncoder, "number_of_images", message.number_of_images);