mmcfilters
Public API documentation
Loading...
Searching...
No Matches
BitquadAttributeComputer.hpp
1#pragma once
2
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/detail/MorphologicalTreeConstructionContextQueries.hpp"
10#include "../../utils/Contract.hpp"
11
12#include <array>
13#include <numbers>
14#include <span>
15#include <stdexcept>
16#include <string_view>
17#include <vector>
18
19namespace mmcfilters::attributes::computers {
20
21namespace detail {
22
23inline void validateBitquadAdjacency(const MorphologicalTree& tree, bool altitudeAvailable) {
24 static_cast<void>(makeBitquadConnectivityPolicy(tree, altitudeAvailable));
25}
26
27template <std::floating_point 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);
32}
33
34template <std::floating_point 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);
39 TreeAltitudeAlgorithms::validateNodeAltitudeBufferShape(context.tree, context.altitude);
40
41 const BitquadConnectivityPolicy connectivityPolicy = makeBitquadConnectivityPolicy(context.tree, true);
42 if (!connectivityPolicy.requiresShapePolarity()) {
43 return;
44 }
45 for (NodeId node : context.tree.aliveNodeIds()) {
46 static_cast<void>(shapePolarity(context.tree, context.altitude, node));
47 }
48}
49
50} // namespace detail
51
69 public:
71 static constexpr std::string_view familyName = "bitquad";
72
74 static constexpr AttributeComputerFamily family = AttributeComputerFamily::Bitquad;
75
77 static constexpr AttributeComputerDomain domain = AttributeComputerDomain::Topology;
78
82 inline static constexpr std::array<Attribute, 9> producedAttributes{
83 BitquadArea, BitquadNumberEuler, BitquadNumberHoles, BitquadPerimeter, BitquadPerimeterContinuous,
84 BitquadCircularity, BitquadPerimeterAverage, BitquadLengthAverage, BitquadWidthAverage};
85
98 template <std::floating_point Real> static void compute(const AttributeComputeContext<Real>& context) {
99 const detail::BitquadRequest request = detail::BitquadRequest::from(context.requestedAttributes);
100 MMCFILTERS_CONTRACT_CHECKED_ONLY(detail::validateBitquadContext(context));
101 if (!request.any()) {
102 return;
103 }
104 const std::vector<detail::BitquadFamilyCounts> familyCounts = detail::kernel::computeBitquadFamilyCounts(context.tree);
105 const detail::BitquadConnectivityPolicy connectivityPolicy = detail::makeBitquadConnectivityPolicy(context.tree, false);
106 detail::BitquadAttributeProjection::materializeBitquadAttributes(context.tree, std::span<const detail::BitquadFamilyCounts>(familyCounts),
107 connectivityPolicy, context.buffer, context.attrNames, context.requestedAttributes);
108 }
109
120 template <std::floating_point Real, AltitudeValue T> static void compute(const AltitudeAttributeComputeContext<Real, T>& context) {
121 const detail::BitquadRequest request = detail::BitquadRequest::from(context.requestedAttributes);
122 MMCFILTERS_CONTRACT_CHECKED_ONLY(detail::validateBitquadContext(context));
123 if (!request.any()) {
124 return;
125 }
126 const std::vector<detail::BitquadFamilyCounts> familyCounts = detail::kernel::computeBitquadFamilyCounts(context.tree);
127 const detail::BitquadConnectivityPolicy connectivityPolicy = detail::makeBitquadConnectivityPolicy(context.tree, true);
128 detail::BitquadAttributeProjection::materializeBitquadAttributes(context.tree, context.altitude,
129 std::span<const detail::BitquadFamilyCounts>(familyCounts), connectivityPolicy,
130 context.buffer, context.attrNames, context.requestedAttributes);
131 }
132
146 template <std::floating_point Real> static void computeUnitRows(const UnitAttributeComputeContext<Real>& context) {
147 requireUnitAttributeBufferShape(context.tree, context.unitPixels, context.buffer, context.attrNames);
148 const RegularGridAdjacency2D* adjacency = ::mmcfilters::detail::constructionAdjacency(context.tree);
149 if (adjacency == nullptr) {
150 throw std::invalid_argument("Bitquad attributes require an adjacency relation.");
151 }
152 if (!adjacency->isCanonical4Or8Connectivity()) {
153 throw std::invalid_argument("Bitquad attributes require canonical 4- or 8-connectivity.");
154 }
155
156 const bool is4Connectivity = adjacency->is4connectivity();
157 auto unitValue = [&](Attribute attribute) -> Real {
158 if (is4Connectivity) {
159 switch (attribute) {
160 case BitquadArea:
161 return Real{0};
162 case BitquadNumberEuler:
163 return Real{1};
164 case BitquadNumberHoles:
165 return Real{0};
166 case BitquadPerimeter:
167 return Real{0};
168 case BitquadPerimeterContinuous:
169 return Real{0};
170 case BitquadCircularity:
171 return Real{0};
172 case BitquadPerimeterAverage:
173 return Real{0};
174 case BitquadLengthAverage:
175 return Real{0};
176 case BitquadWidthAverage:
177 return Real{0};
178 default:
179 break;
180 }
181 }
182
183 switch (attribute) {
184 case BitquadArea:
185 return Real{1};
186 case BitquadNumberEuler:
187 return Real{0};
188 case BitquadNumberHoles:
189 return Real{1};
190 case BitquadPerimeter:
191 return Real{4};
192 case BitquadPerimeterContinuous:
193 return Real{8} / Real{3};
194 case BitquadCircularity:
195 return Real{9} * std::numbers::pi_v<Real> / Real{16};
196 case BitquadPerimeterAverage:
197 return Real{0};
198 case BitquadLengthAverage:
199 return Real{0};
200 case BitquadWidthAverage:
201 return static_cast<Real>(0.75);
202 default:
203 break;
204 }
205 throw std::runtime_error("Unsupported finite-window Bitquad unit attribute.");
206 };
207
208 constexpr std::array<Attribute, 9> unitAttributes{
209 BitquadArea, BitquadNumberEuler, BitquadNumberHoles, BitquadPerimeter, BitquadPerimeterContinuous,
210 BitquadCircularity, BitquadPerimeterAverage, BitquadLengthAverage, BitquadWidthAverage};
211
212 for (Attribute attribute : unitAttributes) {
213 if (!requestsAttribute(context.requestedAttributes, attribute)) {
214 continue;
215 }
216 const Real value = unitValue(attribute);
217 for (NodeId leafIndex = 0; leafIndex < static_cast<NodeId>(context.unitPixels.size()); ++leafIndex) {
218 context.buffer[context.attrNames.linearIndex(leafIndex, attribute)] = value;
219 }
220 }
221 }
222};
223
224} // namespace mmcfilters::attributes::computers
#define MMCFILTERS_CONTRACT_CHECKED_ONLY(...)
Executes validation statements only when defensive checks are enabled.
Definition Contract.hpp:67
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.