// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include "Coord.h" // How the stored image is laid out in the detector plane: mirrored in Y, and/or turned by a multiple // of 90 degrees about the beam. Both are exact pixel remappings, which an arbitrary in-plane rotation // (PONI rot3) is not - a viewer can show the image the right way up from these two without resampling // anything. // // It is applied to the offset from the PONI, in stored-image millimetres, BEFORE the continuous PONI // tilt takes that offset to the laboratory: // // lab = R(rot1, rot2, rot3) * Matrix() * ( (x-beam_x)*pixel, (y-beam_y)*pixel, distance ) // // Mirror first, then the quarter turns. Every element of the group the two generate can be written // that way, so the order is a convention rather than a derivation, and this is the one. // // This is NOT the same thing as DetectorSetup::mirror_y, which describes the raw readout -> assembled // image module layout and is spent before the geometry sees anything. This one describes the assembled // image -> detector canonical frame, changes no pixel, and defaults to the identity. class DetectorOrientation { bool mirror_y = false; int64_t quarter_turns = 0; // 0..3, right-handed about the beam = clockwise on the displayed image public: DetectorOrientation() = default; DetectorOrientation(bool mirror_y, int64_t quarter_turns); DetectorOrientation& MirrorY(bool input); DetectorOrientation& QuarterTurns(int64_t input); [[nodiscard]] bool IsMirrorY() const; [[nodiscard]] int64_t GetQuarterTurns() const; [[nodiscard]] bool IsIdentity() const; // Rz(quarter_turns * 90 deg) * diag(1,-1,1)^mirror_y. Entries are exactly 0 and +-1. [[nodiscard]] RotMatrix Matrix() const; // The orientation whose fast and slow axes are the two directions given, or nothing when they are // not one of the eight. Nothing means the image is turned in its own plane by something that is // not a multiple of 90 degrees, which is a continuous rotation of the detector and belongs in the // PONI angles - it cannot be told apart from the tilt by looking at the two directions alone. [[nodiscard]] static std::optional Match(const Coord &fast, const Coord &slow); bool operator==(const DetectorOrientation &other) const; };