8#include "../../utils/Altitude.hpp"
9#include "../../utils/Common.hpp"
19namespace mmcfilters::sdrt {
40 for (std::size_t rank = 0; rank <
pixelsInOrder.size(); ++rank) {
42 if (pixel < 0 ||
static_cast<std::size_t
>(pixel) >=
pixelsInOrder.size()) {
43 throw std::invalid_argument(
"A spatial order must be a permutation of the pixel domain.");
45 auto&
storedRank = rankByPixel_[
static_cast<std::size_t
>(pixel)];
47 throw std::invalid_argument(
"A spatial order cannot contain a pixel more than once.");
64 if (!
isRowMajor() && rankByPixel_.size() != numPixels) {
65 throw std::invalid_argument(
"The explicit spatial order size differs from the image domain.");
76 return rank(
lhs) < rank(
rhs);
85 if (support.empty()) {
86 throw std::invalid_argument(
"A spatial minimum requires a non-empty support.");
89 for (
PixelId pixel : support.subspan(1)) {
104 return std::numeric_limits<std::size_t>::max();
114 throw std::out_of_range(
"A spatial-order query received a negative pixel identifier.");
117 return static_cast<std::size_t
>(pixel);
119 if (
static_cast<std::size_t
>(pixel) >= rankByPixel_.size()) {
120 throw std::out_of_range(
"A spatial-order query lies outside the configured domain.");
122 return rankByPixel_[
static_cast<std::size_t
>(pixel)];
125 std::vector<std::size_t> rankByPixel_;
160 if (
lhs.supportCardinality !=
rhs.supportCardinality) {
161 return lhs.supportCardinality <
rhs.supportCardinality;
163 if (
lhs.spatialMinimum ==
rhs.spatialMinimum) {
166 return spatialOrder_.
precedes(
lhs.spatialMinimum,
rhs.spatialMinimum);
197 : residualOrder_(std::
move(spatialOrder)) {}
206 throw std::invalid_argument(
"Residual-candidate selection requires a non-empty schedule.");
208 std::set<std::pair<std::size_t, PixelId>>
seenKeys;
210 for (std::size_t index = 0; index <
residualKeys.size(); ++index) {
212 throw std::invalid_argument(
"A self-dual residual schedule cannot contain duplicate candidate keys.");
256template <AltitudeValue T>
259 throw std::invalid_argument(
"A residual event requires a non-empty candidate support.");
262 throw std::invalid_argument(
"A residual candidate key has an inconsistent support cardinality.");
268 throw std::invalid_argument(
"A residual candidate polarity is inconsistent with its signed residual value.");
271 candidate.firstMergingLevel, signedResidualValue};
constexpr PixelId InvalidPixel
Sentinel value used to denote an invalid pixel identifier.
ResidualEvent< T > recordResidualEvent(std::size_t eventIndex, const ResidualCandidate< T > &candidate)
Records the immutable event associated with one prepared candidate.
Polarity
Polarity of a regional extremum in synchronized residual evolution.
Dense row-major spatial order used by default.
Strict order induced by (supportCardinality, spatialMinimum).
const SpatialOrder & spatialOrder() const noexcept
Returns the total spatial order used by this comparison.
SelfDualResidualOrder(SpatialOrder spatialOrder=RowMajorSpatialOrder{})
Creates the canonical residual-key order.
bool compareResidualCandidates(const SelfDualResidualKey &lhs, const SelfDualResidualKey &rhs) const
Compares two candidate keys without consulting polarity or altitude.
bool operator()(const SelfDualResidualKey &lhs, const SelfDualResidualKey &rhs) const
Applies the canonical strict comparison.
Selects the next residual candidate from the canonical self-dual order.
std::size_t selectResidualCandidate(std::span< const SelfDualResidualKey > residualKeys) const
Returns the index of the first key in canonical residual order.
const SelfDualResidualOrder & residualOrder() const noexcept
Returns the canonical key order used by this schedule.
SelfDualResidualSchedule(SpatialOrder spatialOrder=RowMajorSpatialOrder{})
Creates the unique canonical residual schedule.
Total order over the pixels of one construction domain.
bool isRowMajor() const noexcept
Returns whether the order uses implicit row-major ranks.
SpatialOrder()=default
Creates the implicit row-major order.
void validateDomainSize(std::size_t numPixels) const
Validates that this order covers a construction domain.
bool precedes(PixelId lhs, PixelId rhs) const
Returns whether lhs precedes rhs.
SpatialOrder(std::vector< PixelId > pixelsInOrder)
Creates an explicit total spatial order.
PixelId spatialMinimum(std::span< const PixelId > support) const
Returns the least pixel of a non-empty support.
Owning result for one computed scalar attribute layout and buffer.
std::vector< Real > second
Flat per-node attribute buffer indexed through first.
Immutable view of an eligible residual candidate before leveling.
std::span< const PixelId > support
Current candidate support.
Polarity polarity
Regional-extremum polarity.
T firstMergingLevel
First adjacent level reached by elementary leveling.
SelfDualResidualKey residualKey
Canonical support-only scheduling key.
T candidateAltitude
Constant altitude on the candidate before leveling.
Immutable record captured immediately before one elementary leveling.
T nodeAltitude
Candidate altitude before leveling.
Polarity polarity
Polarity in the pre-leveling state.
std::size_t eventIndex
Zero-based chronological event index.
AltitudeDifference< T > signedResidualValue
nodeAltitude - firstMergingLevel.
std::span< const PixelId > support
Candidate support in the pre-leveling state.
T firstMergingLevel
Level to which the support is moved.
Contrast-invariant key of one current residual candidate.
PixelId spatialMinimum
Least support pixel in the configured spatial order.
friend bool operator==(const SelfDualResidualKey &, const SelfDualResidualKey &)=default
Compares both coordinates of two residual keys.
std::size_t supportCardinality
Cardinality of the current candidate support.