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/MorphologicalTree.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 computeUnitRowsEstablished(context);
149 }
150
151 private:
158 template <class Computer, class Context> friend void mmcfilters::detail::kernel::computeUnitRows(const Context& context);
159
161 template <std::floating_point Real> static void computeUnitRowsEstablished(const UnitAttributeComputeContext<Real>& context) {
162 const RegularGridAdjacency2D* adjacency = context.tree.constructionAdjacency();
163 if (adjacency == nullptr) {
164 throw std::invalid_argument("Bitquad attributes require an adjacency relation.");
165 }
166 if (!adjacency->isCanonical4Or8Connectivity()) {
167 throw std::invalid_argument("Bitquad attributes require canonical 4- or 8-connectivity.");
168 }
169
170 const bool is4Connectivity = adjacency->is4connectivity();
171 auto unitValue = [&](Attribute attribute) -> Real {
172 if (is4Connectivity) {
173 switch (attribute) {
174 case BitquadArea:
175 return Real{0};
176 case BitquadNumberEuler:
177 return Real{1};
178 case BitquadNumberHoles:
179 return Real{0};
180 case BitquadPerimeter:
181 return Real{0};
182 case BitquadPerimeterContinuous:
183 return Real{0};
184 case BitquadCircularity:
185 return Real{0};
186 case BitquadPerimeterAverage:
187 return Real{0};
188 case BitquadLengthAverage:
189 return Real{0};
190 case BitquadWidthAverage:
191 return Real{0};
192 default:
193 break;
194 }
195 }
196
197 switch (attribute) {
198 case BitquadArea:
199 return Real{1};
200 case BitquadNumberEuler:
201 return Real{0};
202 case BitquadNumberHoles:
203 return Real{1};
204 case BitquadPerimeter:
205 return Real{4};
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:
211 return Real{0};
212 case BitquadLengthAverage:
213 return Real{0};
214 case BitquadWidthAverage:
215 return static_cast<Real>(0.75);
216 default:
217 break;
218 }
219 throw std::runtime_error("Unsupported finite-window Bitquad unit attribute.");
220 };
221
222 constexpr std::array<Attribute, 9> unitAttributes{
223 BitquadArea, BitquadNumberEuler, BitquadNumberHoles, BitquadPerimeter, BitquadPerimeterContinuous,
224 BitquadCircularity, BitquadPerimeterAverage, BitquadLengthAverage, BitquadWidthAverage};
225
226 for (Attribute attribute : unitAttributes) {
227 if (!requestsAttribute(context.requestedAttributes, attribute)) {
228 continue;
229 }
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;
233 }
234 }
235 }
236};
237
238} // 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.