MorphologicalAttributeFilters
Public API documentation
Loading...
Searching...
No Matches
VolumeComputer.hpp
1#pragma once
2
3#include "AttributeComputerDomain.hpp"
4#include "AttributeComputerFamily.hpp"
5#include "../detail/AttributeKernelSupport.hpp"
6#include "../../trees/detail/TreeTraversalDetail.hpp"
7#include "../../trees/TreeAltitudeAlgorithms.hpp"
8#include "../../utils/Altitude.hpp"
9
10#include <algorithm>
11#include <array>
12#include <cmath>
13#include <span>
14#include <stdexcept>
15#include <string_view>
16
17namespace mmcfilters::attributes::computers {
18
19namespace detail {
20inline NodeId volumeSlotOf(const MorphologicalTree&, NodeId nodeId) noexcept {
21 return nodeId;
22}
23
24struct VolumeRequest {
25 bool volume = false;
26 bool relative = false;
27
28 [[nodiscard]] bool any() const noexcept {
29 return volume || relative;
30 }
31
32 [[nodiscard]] bool needsAreaDependency() const noexcept {
33 return relative;
34 }
35
36 [[nodiscard]] static VolumeRequest from(std::span<const Attribute> requestedAttributes) {
37 return {
38 .volume = containsVolumeAttribute(requestedAttributes, VOLUME),
39 .relative = containsVolumeAttribute(requestedAttributes, RELATIVE_VOLUME)};
40 }
41
42private:
43 [[nodiscard]] static bool containsVolumeAttribute(
44 std::span<const Attribute> requestedAttributes,
45 Attribute attribute)
46 {
47 return std::find(requestedAttributes.begin(), requestedAttributes.end(), attribute) != requestedAttributes.end();
48 }
49};
50
63template<std::floating_point Real, AltitudeValue T>
64void computeVolumeAttributeKernel(
65 const MorphologicalTree& tree,
66 std::span<const T> altitude,
67 std::span<Real> buffer,
68 const AttributeNames& attrNames,
69 std::span<const Attribute> requestedAttributes,
70 std::span<const DependencySourceT<Real>> dependencySources)
71{
73
74 const VolumeRequest request = VolumeRequest::from(requestedAttributes);
75 if (!request.any()) {
76 return;
77 }
78
79 auto indexOfVol = [&](NodeId idx) { return attrNames.linearIndex(idx, VOLUME); };
80 auto indexOfRel = [&](NodeId idx) { return attrNames.linearIndex(idx, RELATIVE_VOLUME); };
81 const DependencyResolver<Real> dependencies{dependencySources};
82 const DependencySourceT<Real>* dependencyArea = request.needsAreaDependency()
83 ? &dependencies.require(AREA)
84 : nullptr;
85 auto indexOfArea = [&](NodeId idx) { return dependencyArea->attrNames->linearIndex(idx, AREA); };
86
87 ::mmcfilters::detail::traversePostOrder(
88 tree,
89 tree.getRoot(),
90 [&](NodeId nodeId) {
91 const NodeId node = detail::volumeSlotOf(tree, nodeId);
92 const T nodeAltitude = TreeAltitudeAlgorithms::getAltitude(altitude, nodeId);
93 if (request.volume)
94 buffer[indexOfVol(node)] =
95 static_cast<Real>(tree.getNumProperParts(nodeId)) * static_cast<Real>(nodeAltitude);
96 if (request.relative)
97 buffer[indexOfRel(node)] = Real{0};
98 },
99 [&](NodeId parentNodeId, NodeId childNodeId) {
100 const NodeId parent = detail::volumeSlotOf(tree, parentNodeId);
101 const NodeId child = detail::volumeSlotOf(tree, childNodeId);
102 if (request.volume)
103 buffer[indexOfVol(parent)] += buffer[indexOfVol(child)];
104 if (request.relative)
105 buffer[indexOfRel(parent)] +=
106 buffer[indexOfRel(child)] +
107 static_cast<Real>(
108 dependencyArea->buffer[indexOfArea(child)] *
109 std::abs(
110 static_cast<Real>(TreeAltitudeAlgorithms::getAltitude(altitude, childNodeId)) -
111 static_cast<Real>(TreeAltitudeAlgorithms::getAltitude(altitude, parentNodeId))));
112 },
113 [&](NodeId nodeId) {
114 const NodeId node = detail::volumeSlotOf(tree, nodeId);
115 if (request.relative)
116 buffer[indexOfRel(node)] += dependencyArea->buffer[indexOfArea(node)];
117 });
118}
119
120}
121
142public:
144 static constexpr std::string_view familyName = "volume";
145
147 static constexpr AttributeComputerFamily family = AttributeComputerFamily::Volume;
148
150 static constexpr AttributeComputerDomain domain = AttributeComputerDomain::Altitude;
151
155 inline static constexpr std::array<Attribute, 2> producedAttributes{
156 VOLUME,
157 RELATIVE_VOLUME};
158
168 template <std::floating_point Real, AltitudeValue T>
170 {
171 requireAttributeBufferShape(context.tree, context.buffer, context.attrNames);
172 detail::computeVolumeAttributeKernel(
173 context.tree,
174 context.altitude,
175 context.buffer,
176 context.attrNames,
177 context.requestedAttributes,
178 context.dependencySources);
179 }
180
188 template <std::floating_point Real, AltitudeValue T>
190 {
191 requireUnitAttributeBufferShape(context.tree, context.unitProperParts, context.buffer, context.attrNames);
192 TreeAltitudeAlgorithms::validateAltitudeBufferShape(context.tree, context.altitude);
193
194 const detail::VolumeRequest request = detail::VolumeRequest::from(context.requestedAttributes);
195 if (!request.any()) {
196 return;
197 }
198
199 for (NodeId leafIndex = 0; leafIndex < static_cast<NodeId>(context.unitProperParts.size()); ++leafIndex) {
200 const NodeId properPart = context.unitProperParts[static_cast<size_t>(leafIndex)];
201 if (request.volume) {
202 context.buffer[context.attrNames.linearIndex(leafIndex, VOLUME)] =
203 static_cast<Real>(unitAltitude(context.tree, context.altitude, properPart));
204 }
205 if (request.relative) {
206 context.buffer[context.attrNames.linearIndex(leafIndex, RELATIVE_VOLUME)] = Real{1};
207 }
208 }
209 }
210
211};
212
213} // namespace mmcfilters::attributes::computers
int NodeId
Node identifier type used throughout the project.
Definition Common.hpp:17
static T getAltitude(std::span< const T > altitude, NodeId nodeId)
Reads one node altitude from an explicit altitude buffer.
static void validateAltitudeBufferShape(const MorphologicalTree &tree, std::span< const T > altitude)
Validates that an altitude buffer covers the dense internal-node domain.
Computes cumulative grey-level volume descriptors on the hierarchy.
static void compute(const AltitudeAttributeComputeContext< Real, T > &context)
Computes the requested volume descriptors.
static void computeUnitRows(const AltitudeUnitAttributeComputeContext< Real, T > &context)
Materializes volume descriptors for one-pixel unit supports.
Owning result for one computed scalar attribute layout and buffer.