mmcfilters
Public API documentation
Loading...
Searching...
No Matches
ContourTrace.hpp
1#pragma once
2
3#include "../utils/Common.hpp"
4
5#include <cstddef>
6#include <cstdint>
7#include <iterator>
8#include <span>
9#include <stdexcept>
10#include <utility>
11#include <vector>
12
13namespace mmcfilters {
14
15class ContourTraceComputation;
16namespace contours::detail {
17class ContourTraceTraversal;
18}
19
23enum class ContourSide : uint8_t { North = 0, West = 1, East = 2, South = 3 };
24
28enum class ContourBoundaryKind : uint8_t { External, Internal };
29
37 ContourSide side = ContourSide::North;
38
40 friend bool operator==(const ContourEdge&, const ContourEdge&) = default;
41};
42
48 ContourBoundaryKind kind = ContourBoundaryKind::External;
55};
56
57namespace contours::detail {
58
60[[nodiscard]] inline int packContourEdge(PixelId pixel, ContourSide side) {
61 return (4 * pixel) + static_cast<int>(side);
62}
63
65[[nodiscard]] inline ContourEdge unpackContourEdge(int packedEdge) {
66 if (packedEdge < 0) {
67 return {};
68 }
69 return ContourEdge{packedEdge / 4, static_cast<ContourSide>(packedEdge & 3)};
70}
71
72} // namespace contours::detail
73
78 public:
82 class iterator {
83 public:
85 using iterator_category = std::forward_iterator_tag;
89 using difference_type = std::ptrdiff_t;
91 using pointer = void;
94
95 iterator() = default;
96
101 explicit iterator(const int* packedEdge) : packedEdge_(packedEdge) {}
102
107 [[nodiscard]] value_type operator*() const { return contours::detail::unpackContourEdge(*packedEdge_); }
108
114 ++packedEdge_;
115 return *this;
116 }
117
123 iterator previous(*this);
124 ++(*this);
125 return previous;
126 }
127
129 friend bool operator==(const iterator&, const iterator&) = default;
130
131 private:
133 const int* packedEdge_ = nullptr;
134 };
135
136 ContourEdgeRange() = default;
137
142 explicit ContourEdgeRange(std::span<const int> packedEdges) : packedEdges_(packedEdges) {}
143
145 [[nodiscard]] iterator begin() const { return iterator(packedEdges_.data()); }
146
148 [[nodiscard]] iterator end() const {
149 return packedEdges_.empty() ? begin() : iterator(packedEdges_.data() + packedEdges_.size());
150 }
151
153 [[nodiscard]] bool empty() const noexcept { return packedEdges_.empty(); }
154
156 [[nodiscard]] std::size_t size() const noexcept { return packedEdges_.size(); }
157
158 private:
159 std::span<const int> packedEdges_;
160};
161
169 public:
171 class iterator {
172 public:
174 using iterator_category = std::forward_iterator_tag;
178 using difference_type = std::ptrdiff_t;
180 using pointer = void;
183
184 iterator() = default;
185
188
190 [[nodiscard]] value_type operator*() const { return (*edgeIterator_).pixel; }
191
194 ++edgeIterator_;
195 return *this;
196 }
197
203 iterator previous(*this);
204 ++(*this);
205 return previous;
206 }
207
209 friend bool operator==(const iterator&, const iterator&) = default;
210
211 private:
212 ContourEdgeRange::iterator edgeIterator_;
213 };
214
215 ContourPixelRange() = default;
216
218 explicit ContourPixelRange(ContourEdgeRange edges) : edges_(edges) {}
219
221 [[nodiscard]] iterator begin() const { return iterator(edges_.begin()); }
222
224 [[nodiscard]] iterator end() const { return iterator(edges_.end()); }
225
227 [[nodiscard]] bool empty() const noexcept { return edges_.empty(); }
228
230 [[nodiscard]] std::size_t size() const noexcept { return edges_.size(); }
231
232 private:
233 ContourEdgeRange edges_;
234};
235
236class ContourTrace;
237
249 public:
250 ContourTraceView() = default;
251
253 [[nodiscard]] std::span<const ContourBoundary> boundaries() const noexcept { return boundaries_; }
254
261 const ContourBoundary* external = nullptr;
262 for (const ContourBoundary& boundary : boundaries_) {
263 if (boundary.kind != ContourBoundaryKind::External) {
264 continue;
265 }
266 if (external != nullptr) {
267 throw std::logic_error("ContourTraceView::externalBoundary requires exactly one external boundary.");
268 }
270 }
271 if (external == nullptr) {
272 throw std::logic_error("ContourTraceView::externalBoundary requires exactly one external boundary.");
273 }
274 return *external;
275 }
276
279
286 return ContourEdgeRange(boundarySpan(boundary));
287 }
288
297
298 private:
299 friend class ContourTrace;
300 friend class ContourTraceComputation;
301 friend class contours::detail::ContourTraceTraversal;
302
308 ContourTraceView(std::span<const int> packedEdges, std::span<const ContourBoundary> boundaries)
309 : packedEdges_(packedEdges), boundaries_(boundaries) {}
310
316 [[nodiscard]] std::span<const int> boundarySpan(const ContourBoundary& boundary) const {
317 const std::size_t offset = boundary.edgeOffset;
318 const std::size_t count = boundary.edgeCount;
319 if (offset > packedEdges_.size() || count > packedEdges_.size() - offset) {
320 throw std::invalid_argument("ContourBoundary does not belong to this contour trace.");
321 }
322 return packedEdges_.subspan(offset, count);
323 }
324
325 std::span<const int> packedEdges_;
326 std::span<const ContourBoundary> boundaries_;
327};
328
337 public:
338 ContourTrace() = default;
339
345 : packedEdges_(trace.packedEdges_.begin(), trace.packedEdges_.end()),
346 boundaries_(trace.boundaries_.begin(), trace.boundaries_.end()) {}
347
349 [[nodiscard]] std::span<const ContourBoundary> boundaries() const noexcept { return view().boundaries(); }
350
357
360
367
374
380 [[nodiscard]] ContourTraceView view() const noexcept { return ContourTraceView(packedEdges_, boundaries_); }
381
382 private:
383 friend class ContourTraceComputation;
384
390 ContourTrace(std::vector<int> packedEdges, std::vector<ContourBoundary> boundaries)
391 : packedEdges_(std::move(packedEdges)), boundaries_(std::move(boundaries)) {}
392
393 std::vector<int> packedEdges_;
394 std::vector<ContourBoundary> boundaries_;
395};
396
397} // namespace mmcfilters
constexpr PixelId InvalidPixel
Sentinel value used to denote an invalid pixel identifier.
Definition Common.hpp:43
Forward iterator that unpacks contour edges on dereference.
std::ptrdiff_t difference_type
Signed iterator-distance type.
iterator & operator++()
Advances to the next packed edge.
ContourEdge value_type
Unpacked edge value yielded by dereference.
value_type operator*() const
Returns the unpacked current edge.
iterator operator++(int)
Advances while retaining the previous iterator position.
friend bool operator==(const iterator &, const iterator &)=default
Compares packed-edge positions.
iterator(const int *packedEdge)
Creates an iterator at one packed-edge position.
std::forward_iterator_tag iterator_category
Standard category for a multi-pass forward iterator.
Immutable range over unpacked contour edges.
iterator end() const
Returns the exclusive end iterator.
ContourEdgeRange(std::span< const int > packedEdges)
Creates a view over packed contour edges.
bool empty() const noexcept
Returns whether the range contains no edges.
iterator begin() const
Returns an iterator to the first contour edge.
std::size_t size() const noexcept
Returns the number of contour edges.
Forward iterator that returns the support pixel of each edge.
std::ptrdiff_t difference_type
Signed iterator-distance type.
std::forward_iterator_tag iterator_category
Standard category for a multi-pass forward iterator.
value_type operator*() const
Returns the support pixel of the current edge.
iterator operator++(int)
Advances while retaining the previous iterator position.
iterator & operator++()
Advances to the next edge pixel.
friend bool operator==(const iterator &, const iterator &)=default
Compares the underlying edge positions.
iterator(ContourEdgeRange::iterator edgeIterator)
Creates a projection over an edge iterator.
PixelId value_type
Pixel identifier yielded by dereference.
Immutable projection of ordered contour edges onto support pixels.
iterator begin() const
Returns an iterator to the first edge pixel.
iterator end() const
Returns the exclusive end iterator.
ContourPixelRange(ContourEdgeRange edges)
Creates a support-pixel projection of an edge range.
std::size_t size() const noexcept
Returns the number of projected edge pixels, including repetitions.
bool empty() const noexcept
Returns whether the range contains no pixels.
Incremental ordered contour traces on the image domain.
Borrowed ordered contour trace for one tree node.
ContourEdgeRange edges() const noexcept
Returns every contour edge in boundary order.
std::span< const ContourBoundary > boundaries() const noexcept
Returns all ordered boundary descriptors.
ContourPixelRange boundaryPixels(const ContourBoundary &boundary) const
Returns one support pixel for each ordered boundary edge.
ContourBoundary externalBoundary() const
Returns the unique external boundary.
ContourEdgeRange boundaryEdges(const ContourBoundary &boundary) const
Returns the ordered edges of one boundary.
Independently owned ordered contour trace for one tree node.
ContourPixelRange boundaryPixels(const ContourBoundary &boundary) const
Returns one support pixel for each ordered boundary edge.
ContourEdgeRange edges() const noexcept
Returns every contour edge in boundary order.
ContourTraceView view() const noexcept
Returns a borrowed view over this owned trace.
ContourEdgeRange boundaryEdges(const ContourBoundary &boundary) const
Returns the ordered edges of one boundary.
ContourTrace(ContourTraceView trace)
Copies a borrowed trace so it can outlive its source traversal.
ContourBoundary externalBoundary() const
Returns the unique external boundary.
std::span< const ContourBoundary > boundaries() const noexcept
Returns all ordered boundary descriptors.
Owning result for one computed scalar attribute layout and buffer.
Metadata for one ordered external or internal contour boundary.
uint32_t edgeCount
Number of consecutive edges in the boundary.
ContourBoundaryKind kind
Whether this boundary is external or surrounds a hole.
int doubledSignedArea
Doubled signed area under the contour orientation convention.
uint32_t edgeOffset
First edge in the trace edge buffer.
One contour edge represented by its support pixel and side.
PixelId pixel
Row-major support-pixel index incident to the boundary edge.
ContourSide side
Side of the support pixel occupied by the boundary edge.
friend bool operator==(const ContourEdge &, const ContourEdge &)=default
Compares the support pixel and side.