mmcfilters
Public API documentation
Loading...
Searching...
No Matches
ConnectedSubsetTreeLocalizer.hpp
1#pragma once
2
3#include "../trees/MorphologicalTree.hpp"
4#include "../trees/detail/CommittedTreeAccess.hpp"
5#include "../utils/Common.hpp"
6
7#include <cstddef>
8#include <optional>
9#include <stdexcept>
10
11namespace mmcfilters::local_attributes {
12
15 int rowOffset = 0;
16 int columnOffset = 0;
17
19 friend bool operator==(const WindowOffset& lhs, const WindowOffset& rhs) = default;
20};
21
22namespace detail::kernel {
23
30inline NodeId connectedSubsetJoin(const MorphologicalTree& tree, NodeId lhsSmallestNode, NodeId rhsSmallestNode) {
31 return ::mmcfilters::detail::CommittedTreeAccess::lowestCommonAncestor(tree, lhsSmallestNode, rhsSmallestNode);
32}
33
35inline NodeId anchoredEntryFromSmallestNodes(const MorphologicalTree& tree, NodeId anchorSmallestNode, NodeId sampleSmallestNode) {
36 return connectedSubsetJoin(tree, anchorSmallestNode, sampleSmallestNode);
37}
38
40inline NodeId anchoredEntry(const MorphologicalTree& tree, PixelId anchorPixel, PixelId samplePixel) {
41 const NodeId anchorSmallestNode = ::mmcfilters::detail::CommittedTreeAccess::smallestNodeMap(tree, anchorPixel);
42 const NodeId sampleSmallestNode = ::mmcfilters::detail::CommittedTreeAccess::smallestNodeMap(tree, samplePixel);
43 return connectedSubsetJoin(tree, anchorSmallestNode, sampleSmallestNode);
44}
45
47inline NodeId anchoredEntry(const MorphologicalTree& tree, PixelId anchorPixel, WindowOffset offset) {
48 const GridDomain2D& domain = ::mmcfilters::detail::CommittedTreeAccess::gridDomain2D(tree);
49 const int anchorRow = anchorPixel / domain.columns;
50 const int anchorColumn = anchorPixel % domain.columns;
51 const int sampleRow = anchorRow + offset.rowOffset;
52 const int sampleColumn = anchorColumn + offset.columnOffset;
53 if (sampleRow < 0 || sampleRow >= domain.rows || sampleColumn < 0 || sampleColumn >= domain.columns) {
54 return InvalidNode;
55 }
56 return anchoredEntry(tree, anchorPixel, static_cast<PixelId>(sampleRow * domain.columns + sampleColumn));
57}
58
59} // namespace detail::kernel
60
70 public:
72 explicit ConnectedSubsetTreeLocalizer(const MorphologicalTree& tree) : tree_(tree), mutationVersion_(tree.getMutationVersion()) {
73 tree_.requireNotEditing("ConnectedSubsetTreeLocalizer");
74 }
75
78 requireStableTree();
79 if (!tree_.isPixel(pixel)) {
80 throw std::out_of_range("ConnectedSubsetTreeLocalizer::smallestNode received an invalid pixel.");
81 }
82 const NodeId value = tree_.smallestNode(pixel);
83 if (!tree_.isAlive(value)) {
84 throw std::logic_error("ConnectedSubsetTreeLocalizer::smallestNode found a pixel without a live smallest node.");
85 }
86 return value;
87 }
88
96 requireStableTree();
97 if (!tree_.isAlive(lhsSmallestNode) || !tree_.isAlive(rhsSmallestNode)) {
98 throw std::invalid_argument("ConnectedSubsetTreeLocalizer::join requires two live nodes.");
99 }
100 return detail::kernel::connectedSubsetJoin(tree_, lhsSmallestNode, rhsSmallestNode);
101 }
102
109 [[nodiscard]] std::optional<NodeId> anchoredEntry(PixelId anchorPixel, PixelId samplePixel) const {
110 requireStableTree();
111 if (!tree_.isPixel(anchorPixel) || !tree_.isPixel(samplePixel)) {
112 return std::nullopt;
113 }
114 return detail::kernel::anchoredEntry(tree_, anchorPixel, samplePixel);
115 }
116
123 [[nodiscard]] std::optional<NodeId> anchoredEntry(PixelId anchorPixel, WindowOffset offset) const {
124 requireStableTree();
125 const GridDomain2D& domain = tree_.requireGridDomain2D("ConnectedSubsetTreeLocalizer::anchoredEntry");
126 if (anchorPixel < 0 || anchorPixel >= domain.rows * domain.columns) {
127 return std::nullopt;
128 }
129 const NodeId entry = detail::kernel::anchoredEntry(tree_, anchorPixel, offset);
130 return entry == InvalidNode ? std::nullopt : std::optional<NodeId>{entry};
131 }
132
133 private:
135 void requireStableTree() const { tree_.requireMutationVersion(mutationVersion_, "ConnectedSubsetTreeLocalizer"); }
136
137 const MorphologicalTree& tree_;
138 std::size_t mutationVersion_ = 0;
139};
140
141} // namespace mmcfilters::local_attributes
int PixelId
Pixel identifier type used by source and active construction domains.
Definition Common.hpp:26
int NodeId
Node identifier type used throughout the project.
Definition Common.hpp:17
constexpr NodeId InvalidNode
Sentinel value used to denote an invalid node identifier.
Definition Common.hpp:34
Mutable connected-subset tree on a finite pixel domain.
Validated public view of connected-subset-tree localization.
NodeId smallestNode(PixelId pixel) const
Returns the smallest node of one valid pixel.
std::optional< NodeId > anchoredEntry(PixelId anchorPixel, PixelId samplePixel) const
Returns the first node on the anchor branch containing an absolute sample.
NodeId join(NodeId lhsSmallestNode, NodeId rhsSmallestNode) const
Returns the inclusion join, equivalently the LCA, of two live smallest nodes.
ConnectedSubsetTreeLocalizer(const MorphologicalTree &tree)
Captures one established tree without building another index.
std::optional< NodeId > anchoredEntry(PixelId anchorPixel, WindowOffset offset) const
Returns the first node containing a translated sample.
Owning result for one computed scalar attribute layout and buffer.
Shape metadata optionally attached to the pixel domain.
int columns
Number of grid columns.
int rows
Number of grid rows.
Relative row-column offset of one translated local sample.
friend bool operator==(const WindowOffset &lhs, const WindowOffset &rhs)=default
Compares both coordinate displacements.