3#include "AttributeComputerDomain.hpp"
4#include "AttributeComputerFamily.hpp"
5#include "../detail/AttributeKernelSupport.hpp"
6#include "detail/BitquadAttributeProjection.hpp"
7#include "detail/BitquadFiniteWindowComputation.hpp"
8#include "../../trees/TreeAltitudeAlgorithms.hpp"
9#include "../../trees/MorphologicalTree.hpp"
10#include "../../utils/Contract.hpp"
19namespace mmcfilters::attributes::computers {
23inline void validateBitquadAdjacency(
const MorphologicalTree& tree,
bool altitudeAvailable) {
24 static_cast<void>(makeBitquadConnectivityPolicy(tree, altitudeAvailable));
27template <std::
floating_po
int Real>
inline void validateBitquadContext(
const AttributeComputeContext<Real>& context) {
28 requireAttributeBufferShape(context.tree, context.buffer, context.attrNames);
29 requireRequestedAttributeColumns(context);
30 local_attributes::detail::validateFiniteWindowLocalAttributeInput(context.tree);
31 validateBitquadAdjacency(context.tree,
false);
34template <std::
floating_po
int Real, AltitudeValue T>
inline void validateBitquadContext(
const AltitudeAttributeComputeContext<Real, T>& context) {
35 requireAttributeBufferShape(context.tree, context.buffer, context.attrNames);
36 requireRequestedAttributeColumns(context);
37 local_attributes::detail::validateFiniteWindowLocalAttributeInput(context.tree);
38 validateBitquadAdjacency(context.tree,
true);
41 const BitquadConnectivityPolicy connectivityPolicy = makeBitquadConnectivityPolicy(context.tree,
true);
42 if (!connectivityPolicy.requiresShapePolarity()) {
45 for (NodeId node : context.tree.aliveNodeIds()) {
46 static_cast<void>(shapePolarity(context.tree, context.altitude, node));
71 static constexpr std::string_view
familyName =
"bitquad";
74 static constexpr AttributeComputerFamily
family = AttributeComputerFamily::Bitquad;
77 static constexpr AttributeComputerDomain
domain = AttributeComputerDomain::Topology;
83 BitquadArea, BitquadNumberEuler, BitquadNumberHoles, BitquadPerimeter, BitquadPerimeterContinuous,
84 BitquadCircularity, BitquadPerimeterAverage, BitquadLengthAverage, BitquadWidthAverage};
99 const detail::BitquadRequest
request = detail::BitquadRequest::from(
context.requestedAttributes);
104 const std::vector<detail::BitquadFamilyCounts>
familyCounts = detail::kernel::computeBitquadFamilyCounts(
context.tree);
106 detail::BitquadAttributeProjection::materializeBitquadAttributes(
context.tree, std::span<const detail::BitquadFamilyCounts>(
familyCounts),
121 const detail::BitquadRequest
request = detail::BitquadRequest::from(
context.requestedAttributes);
126 const std::vector<detail::BitquadFamilyCounts>
familyCounts = detail::kernel::computeBitquadFamilyCounts(
context.tree);
128 detail::BitquadAttributeProjection::materializeBitquadAttributes(
context.tree,
context.altitude,
148 computeUnitRowsEstablished(
context);
158 template <
class Computer,
class Context>
friend void mmcfilters::detail::kernel::computeUnitRows(
const Context&
context);
163 if (adjacency ==
nullptr) {
164 throw std::invalid_argument(
"Bitquad attributes require an adjacency relation.");
167 throw std::invalid_argument(
"Bitquad attributes require canonical 4- or 8-connectivity.");
171 auto unitValue = [&](Attribute attribute) -> Real {
176 case BitquadNumberEuler:
178 case BitquadNumberHoles:
180 case BitquadPerimeter:
182 case BitquadPerimeterContinuous:
184 case BitquadCircularity:
186 case BitquadPerimeterAverage:
188 case BitquadLengthAverage:
190 case BitquadWidthAverage:
200 case BitquadNumberEuler:
202 case BitquadNumberHoles:
204 case BitquadPerimeter:
206 case BitquadPerimeterContinuous:
207 return Real{8} / Real{3};
208 case BitquadCircularity:
209 return Real{9} * std::numbers::pi_v<Real> / Real{16};
210 case BitquadPerimeterAverage:
212 case BitquadLengthAverage:
214 case BitquadWidthAverage:
215 return static_cast<Real
>(0.75);
219 throw std::runtime_error(
"Unsupported finite-window Bitquad unit attribute.");
222 constexpr std::array<Attribute, 9> unitAttributes{
223 BitquadArea, BitquadNumberEuler, BitquadNumberHoles, BitquadPerimeter, BitquadPerimeterContinuous,
224 BitquadCircularity, BitquadPerimeterAverage, BitquadLengthAverage, BitquadWidthAverage};
226 for (Attribute attribute : unitAttributes) {
227 if (!requestsAttribute(context.requestedAttributes, attribute)) {
230 const Real value = unitValue(attribute);
231 for (NodeId leafIndex = 0; leafIndex < static_cast<NodeId>(context.unitPixels.size()); ++leafIndex) {
232 context.buffer[context.attrNames.linearIndex(leafIndex, attribute)] = value;
#define MMCFILTERS_CONTRACT_CHECKED_ONLY(...)
Executes validation statements only when defensive checks are enabled.
Immutable regular-grid 2D adjacency with allocation-free traversal.
bool isCanonical4Or8Connectivity() const noexcept
Tests whether grid-topology formulas may interpret this as 4/8 connectivity.
bool is4connectivity() const noexcept
Returns true when the stencil represents canonical 4-connectivity.
static void validateNodeAltitudeBufferShape(const MorphologicalTree &tree, std::span< const T > altitude)
Validates that an altitude buffer covers the dense internal-node domain.
Bitquad scalar computer backed by finite-window computation.
static constexpr std::array< Attribute, 9 > producedAttributes
Canonical list of scalar bitquad attributes materialized by this computer.
static void computeUnitRows(const UnitAttributeComputeContext< Real > &context)
Materializes bitquad attributes for unit proper-part supports.
static constexpr AttributeComputerDomain domain
Execution domain required by the computer.
static constexpr AttributeComputerFamily family
Stable family id used by the scheduler.
static constexpr std::string_view familyName
Family name used in dependency-plan diagnostics.
static void compute(const AttributeComputeContext< Real > &context)
Computes requested scalar bitquad attributes for every live node.
static void compute(const AltitudeAttributeComputeContext< Real, T > &context)
Computes requested bitquad attributes using a generic altitude span.
Owning result for one computed scalar attribute layout and buffer.