MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
RegionUtils.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "CoordUtils.hpp"
4
7
9
10namespace MayaFlux::Kakshya {
11
12/**
13 * @brief Per-region taper applied in-place before the write callback is invoked.
14 *
15 * Receives a mutable span covering exactly one region's samples for one channel.
16 * Applied after extraction, before the write function is called.
17 * Pass {} or nullptr to skip tapering entirely.
18 */
19using RegionTaper = std::function<void(std::span<double>)>;
20
21/**
22 * @brief Callback invoked once per region per channel during iteration.
23 *
24 * Receives the region index, channel index, and a mutable span of extracted
25 * (and optionally tapered) samples. Responsible for writing those samples
26 * into the caller's output buffer.
27 */
28using RegionWriteFn = std::function<void(size_t region_idx, uint32_t channel, std::span<double>)>;
29
30/** @brief Remove the channel dimension from a Region.
31 * @param region The original Region.
32 * @param dimensions Dimension descriptors to identify the channel dimension.
33 * @return New Region without the channel dimension.
34 *
35 * This function identifies the channel dimension based on the provided dimension descriptors
36 * and removes it from the region's start and end coordinates.
37 *
38 * This is useful for operations that need to ignore the channel dimension, such as spatial-only processing
39 * or planar data handling.
40 */
41Region remove_channel_dimension(const Region& region, const std::vector<DataDimension>& dimensions);
42
43/**
44@brief Get all non-channel dimensions from a list of dimensions.
45 * @param dimensions Vector of DataDimension descriptors.
46 * @return Vector of DataDimensions excluding the channel dimension.
47 *
48 * This function filters out the dimension marked as 'channel' from the provided list of dimensions.
49 * It is useful for operations that need to focus on spatial or temporal dimensions only.
50 */
51std::vector<DataDimension> get_non_channel_dimensions(const std::vector<DataDimension>& dimensions);
52
53/** @brief Flatten a vector of channel data into a single vector.
54 * @tparam T Data type.
55 * @param channel_data Vector of vectors, each representing a channel's data.
56 * @return Single flattened vector containing all channel data in sequence.
57 *
58 * This function concatenates the data from multiple channels into a single continuous vector.
59 * It is useful for operations that require planar data to be processed as a single array.
60 */
61template <typename T>
62std::vector<T> flatten_channels(const std::vector<std::vector<T>>& channel_data)
63{
64 std::vector<T> result;
65 size_t total_size = 0;
66 for (const auto& channel : channel_data) {
67 total_size += channel.size();
68 }
69 result.reserve(total_size);
70
71 for (const auto& channel : channel_data) {
72 result.insert(result.end(), channel.begin(), channel.end());
73 }
74 return result;
75}
76
77/**
78 * @brief Extract a region of data from a flat data span using a Region and dimension info.
79 * @tparam T Data type.
80 * @param source_data Source data span.
81 * @param region Region to extract.
82 * @param dimensions Dimension descriptors.
83 * @return Vector containing the extracted region data.
84 * @throws std::out_of_range if region is out of bounds.
85 */
86template <typename T>
87std::vector<T> extract_region_data(const std::span<const T>& source_data, const Region& region, const std::vector<DataDimension>& dimensions)
88{
89 for (size_t i = 0; i < region.start_coordinates.size(); ++i) {
90 if (region.end_coordinates[i] > 0 && (region.end_coordinates[i] >= dimensions[i].size)) {
91 error<std::out_of_range>(
93 std::source_location::current(),
94 "Requested region is out of bounds for dimension {}",
95 std::to_string(i));
96 }
97 }
98
99 uint64_t region_size = region.get_volume();
100 std::vector<T> result;
101 result.reserve(region_size);
102
103 std::vector<uint64_t> current = region.start_coordinates;
104 while (true) {
105 uint64_t linear_index = coordinates_to_linear(current, dimensions);
106 result.push_back(source_data[linear_index]);
107
108 bool done = true;
109 for (int dim = (int)current.size() - 1; dim >= 0; --dim) {
110 if (current[dim] < region.end_coordinates[dim]) {
111 current[dim]++;
112 done = false;
113 break;
114 }
115 current[dim] = region.start_coordinates[dim];
116 }
117 if (done)
118 break;
119 }
120 return result;
121}
122
123/**
124 * @brief Extract region data from planar storage (separate per channel/variant)
125 * @tparam T Data type
126 * @param source_variants Vector of data spans (one per channel/variant)
127 * @param region Region to extract
128 * @param dimensions Dimension descriptors
129 * @param flatten If true, return single flattened vector; if false, return per-channel vectors
130 * @return Vector of vectors (per-channel) or single flattened vector
131 */
132template <typename T>
133std::vector<std::vector<T>> extract_region_data(
134 const std::vector<std::span<const T>>& source_data,
135 const Region& region,
136 const std::vector<DataDimension>& dimensions,
137 bool flatten = false)
138{
139 std::vector<std::vector<T>> results;
140
141 for (size_t idx = 0; idx < source_data.size(); ++idx) {
142
143 Region channel_region = remove_channel_dimension(region, dimensions);
144
145 auto channel_data = extract_region_data(
146 source_data[idx],
147 channel_region,
148 get_non_channel_dimensions(dimensions));
149
150 results.push_back(std::move(channel_data));
151 }
152
153 if (flatten) {
154 return { flatten_channels(results) };
155 }
156
157 return results;
158}
159
160/**
161 * @brief Extract data for multiple regions from multi-channel source data.
162 * @tparam T Data type.
163 * @param source_spans Vector of source data spans (one per channel).
164 * @param group Group of regions to extract.
165 * @param dimensions Dimension descriptors.
166 * @param organization Storage organization strategy.
167 * @return Vector of vectors, each containing extracted data for one region.
168 */
169template <typename T>
170std::vector<std::vector<T>> extract_group_data(
171 const std::vector<std::span<const T>>& source_spans,
172 const RegionGroup& group,
173 const std::vector<DataDimension>& dimensions,
174 OrganizationStrategy organization)
175{
176 std::vector<std::vector<T>> result;
177 result.reserve(group.regions.size());
178
179 for (const auto& region : group.regions) {
180 auto region_data = extract_region_data<T>(source_spans, region, dimensions, organization);
181
182 if (organization == OrganizationStrategy::INTERLEAVED) {
183 if (result.empty())
184 result.resize(1);
185
186 for (size_t i = 0; i < region_data[0].size(); i++) {
187 result[0].push_back(region_data[0][i]);
188 }
189 } else {
190 if (result.empty())
191 result.resize(region_data.size());
192
193 auto channel_pairs = std::views::zip(result, region_data);
194 auto total_sizes = channel_pairs | std::views::transform([](auto&& pair) {
195 return std::get<0>(pair).size() + std::get<1>(pair).size();
196 });
197
198 size_t i = 0;
199 for (auto size : total_sizes) {
200 result[i].reserve(size);
201 std::ranges::copy(region_data[i],
202 std::back_inserter(result[i]));
203 ++i;
204 }
205 }
206 }
207
208 return result;
209}
210
211/**
212 * @brief Extract data for multiple segments from multi-channel source data.
213 * @tparam T Data type.
214 * @param segments Vector of region segments to extract.
215 * @param source_spans Vector of source data spans (one per channel).
216 * @param dimensions Dimension descriptors.
217 * @param organization Storage organization strategy.
218 * @return Vector of vectors, each containing extracted data for one segment.
219 */
220template <typename T>
221std::vector<std::vector<T>> extract_segments_data(
222 const std::vector<RegionSegment>& segments,
223 const std::vector<std::span<const T>>& source_spans,
224 const std::vector<DataDimension>& dimensions,
225 OrganizationStrategy organization)
226{
227 if (source_spans.size() != 1) {
228 error<std::invalid_argument>(
230 std::source_location::current(),
231 "Source spans cannot be empty");
232 }
233
234 std::vector<std::vector<T>> result;
235
236 for (const auto& segment : segments) {
237 if (segment.is_cached && !segment.cache.data.empty()) {
238 for (const auto& variant : segment.cache.data) {
239 std::vector<T> converted;
240 auto span = extract_from_variant<T>(variant, converted);
241 std::vector<T> cached_data(span.begin(), span.end());
242
243 if (organization == OrganizationStrategy::INTERLEAVED) {
244 if (result.empty())
245 result.resize(1);
246 std::ranges::copy(cached_data, std::back_inserter(result[0]));
247 } else {
248 if (result.size() <= result.size())
249 result.resize(result.size() + 1);
250 result.back() = std::move(cached_data);
251 }
252 }
253 } else {
254 auto region_data = extract_region_data<T>(source_spans, segment.source_region, dimensions, organization);
255
256 if (organization == OrganizationStrategy::INTERLEAVED) {
257 if (result.empty())
258 result.resize(1);
259 std::ranges::copy(region_data[0], std::back_inserter(result[0]));
260 } else {
261 if (result.empty())
262 result.resize(region_data.size());
263 for (size_t i = 0; i < region_data.size(); ++i) {
264 std::ranges::copy(region_data[i], std::back_inserter(result[i]));
265 }
266 }
267 }
268 }
269
270 return result;
271}
272
273/**
274 * @brief Extract a region of data from a vector using a Region and dimension info.
275 * @tparam T Data type.
276 * @param data Source data vector.
277 * @param region Region to extract.
278 * @param dimensions Dimension descriptors.
279 * @return Vector containing the extracted region data.
280 */
281template <typename T>
282std::vector<T> extract_region(
283 const std::vector<T>& data,
284 const Region& region,
285 const std::vector<DataDimension>& dimensions)
286{
287 std::span<const T> data_span(data.data(), data.size());
288 return extract_region_data(data_span, region, dimensions);
289}
290
291/**
292 * @brief Extract a region of data from vector of vectors (planar data).
293 * @tparam T Data type.
294 * @param source_data Vector of vectors containing source data (one per channel).
295 * @param region Region to extract.
296 * @param dimensions Dimension descriptors.
297 * @return Vector of vectors (channels) containing extracted data.
298 */
299template <typename T>
300std::vector<std::vector<T>> extract_region(
301 const std::vector<std::vector<T>>& source_data,
302 const Region& region,
303 const std::vector<DataDimension>& dimensions)
304{
305 std::vector<std::span<const T>> source_spans;
306 source_spans.reserve(source_data.size());
307
308 for (const auto& channel : source_data) {
309 source_spans.emplace_back(channel.data(), channel.size());
310 }
311
312 return extract_region_data(source_spans, region, dimensions);
313}
314
315/**
316 * @brief Extract a region of data with organization strategy.
317 * @tparam T Data type.
318 * @param source_spans Vector of source data spans (one per channel).
319 * @param region Region to extract.
320 * @param dimensions Dimension descriptors.
321 * @param organization Storage organization strategy.
322 * @return Vector of vectors (channels) containing extracted data.
323 */
324template <typename T>
326 const std::vector<std::span<const T>>& source_spans,
327 const Region& region,
328 const std::vector<DataDimension>& dimensions,
329 OrganizationStrategy organization)
330{
331 if (organization == OrganizationStrategy::INTERLEAVED) {
332 return std::vector<std::vector<T>> {
333 extract_region_data(source_spans[0], region, dimensions)
334 };
335 }
336
337 return extract_region_data(source_spans, region, dimensions);
338}
339
340/**
341 * @brief Write or update a region of data in a flat data span (interleaved).
342 * @tparam T Data type.
343 * @param dest_data Destination data span (to be updated).
344 * @param source_data Source data span (to write from).
345 * @param region Region to update.
346 * @param dimensions Dimension descriptors.
347 */
348template <typename T>
350 std::span<T> dest_data,
351 std::span<const T> source_data,
352 const Region& region,
353 const std::vector<DataDimension>& dimensions)
354{
355 std::vector<uint64_t> current = region.start_coordinates;
356 size_t source_index = 0;
357 while (source_index < source_data.size()) {
358 uint64_t linear_index = coordinates_to_linear(current, dimensions);
359 dest_data[linear_index] = source_data[source_index++];
360 bool done = true;
361 /* for (size_t dim = 0; dim < current.size(); ++dim) {
362 if (current[dim] < region.end_coordinates[dim]) {
363 current[dim]++;
364 done = false;
365 break;
366 }
367 current[dim] = region.start_coordinates[dim];
368 } */
369 for (int dim = static_cast<int>(current.size()) - 1; dim >= 0; --dim) {
370 if (current[dim] < region.end_coordinates[dim]) {
371 current[dim]++;
372 done = false;
373 break;
374 }
375 current[dim] = region.start_coordinates[dim];
376 }
377
378 if (done)
379 break;
380 }
381}
382
383/**
384 * @brief Write or update a region of data in planar storage.
385 * @tparam T Data type.
386 * @param dest_spans Vector of destination data spans (one per channel).
387 * @param source_data Vector of source data spans (one per channel).
388 * @param region Region to update (includes channel dimension).
389 * @param dimensions Dimension descriptors (includes channel dimension).
390 */
391template <typename T>
393 std::vector<std::span<T>>& dest_spans,
394 const std::vector<std::span<const T>>& source_data,
395 const Region& region,
396 const std::vector<DataDimension>& dimensions)
397{
398 size_t channel_dim_idx = 0;
399 for (size_t i = 0; i < dimensions.size(); ++i) {
400 if (dimensions[i].role == DataDimension::Role::CHANNEL) {
401 channel_dim_idx = i;
402 break;
403 }
404 }
405
406 size_t start_channel = region.start_coordinates[channel_dim_idx];
407 size_t end_channel = region.end_coordinates[channel_dim_idx];
408
409 for (size_t ch = start_channel; ch <= end_channel && ch < dest_spans.size(); ++ch) {
410 size_t source_channel_idx = ch - start_channel;
411 if (source_channel_idx >= source_data.size())
412 continue;
413
414 Region channel_region = remove_channel_dimension(region, dimensions);
415 auto non_channel_dims = get_non_channel_dimensions(dimensions);
416
418 dest_spans[ch],
419 source_data[source_channel_idx],
420 channel_region,
421 non_channel_dims);
422 }
423}
424
425/**
426 * @brief Write or update a region of data with organization strategy.
427 * @tparam T Data type.
428 * @param dest_spans Vector of destination data spans (one per channel).
429 * @param source_data Vector of source data spans (one per channel).
430 * @param region Region to update.
431 * @param dimensions Dimension descriptors.
432 * @param organization Storage organization strategy.
433 */
434template <typename T>
436 std::vector<std::span<T>>& dest_spans,
437 const std::vector<std::span<const T>>& source_data,
438 const Region& region,
439 const std::vector<DataDimension>& dimensions,
440 OrganizationStrategy organization)
441{
442 if (organization == OrganizationStrategy::INTERLEAVED) {
443 set_or_update_region_data(dest_spans[0], source_data[0], region, dimensions);
444 } else {
445 set_or_update_region_data(dest_spans, source_data, region, dimensions);
446 }
447}
448
449/**
450 * @brief Calculate the total number of elements in a region.
451 * @param region Region to query.
452 * @return Product of spans across all dimensions.
453 */
454uint64_t calculate_region_size(const Region& region);
455
456/**
457 * @brief Get an attribute value from a Region by key.
458 * @tparam T Expected type.
459 * @param region Region to query.
460 * @param key Attribute key.
461 * @return Optional value if present and convertible.
462 */
463template <typename T>
464std::optional<T> get_region_attribute(const Region& region, const std::string& key)
465{
466 auto it = region.attributes.find(key);
467 if (it != region.attributes.end()) {
468 try {
469 return safe_any_cast<T>(it->second);
470 } catch (const std::bad_any_cast&) {
471 return std::nullopt;
472 }
473 }
474 return std::nullopt;
475}
476
477/**
478 * @brief Set an attribute value on a Region.
479 * @param region Region to modify.
480 * @param key Attribute key.
481 * @param value Value to set.
482 */
483void set_region_attribute(Region& region, const std::string& key, std::any value);
484
485/**
486 * @brief Find all regions in a RegionGroup with a given label.
487 * @param group RegionGroup to search.
488 * @param label Label to match.
489 * @return Vector of matching Regions.
490 */
491std::vector<Region> find_regions_with_label(const RegionGroup& group, const std::string& label);
492
493/**
494 * @brief Find all regions in a RegionGroup with a specific attribute value.
495 * @param group RegionGroup to search.
496 * @param key Attribute key.
497 * @param value Attribute value to match.
498 * @return Vector of matching Regions.
499 */
500std::vector<Region> find_regions_with_attribute(const RegionGroup& group, const std::string& key, const std::any& value);
501
502/**
503 * @brief Find all regions in a RegionGroup that contain the given coordinates.
504 * @param group RegionGroup to search.
505 * @param coordinates N-dimensional coordinates.
506 * @return Vector of matching Regions.
507 */
508std::vector<Region> find_regions_containing_coordinates(const RegionGroup& group, const std::vector<uint64_t>& coordinates);
509
510/**
511 * @brief Translate a Region by an offset vector.
512 * @param region Region to translate.
513 * @param offset Offset for each dimension (can be negative).
514 * @return New translated Region.
515 */
516Region translate_region(const Region& region, const std::vector<int64_t>& offset);
517
518/**
519 * @brief Scale a Region about its center by the given factors.
520 * @param region Region to scale.
521 * @param factors Scaling factors for each dimension.
522 * @return New scaled Region.
523 */
524Region scale_region(const Region& region, const std::vector<double>& factors);
525
526/**
527 * @brief Get the bounding region that contains all regions in a RegionGroup.
528 * @param group RegionGroup to query.
529 * @return Region representing the bounding box.
530 */
531Region get_bounding_region(const RegionGroup& group);
532
533/**
534 * @brief Sort a vector of Regions by a specific dimension.
535 * @param regions Vector of Regions to sort.
536 * @param dimension Dimension index to sort by.
537 */
538void sort_regions_by_dimension(std::vector<Region>& regions, size_t dimension);
539
540/**
541 * @brief Sort a vector of Regions by a specific attribute (numeric).
542 * @param regions Vector of Regions to sort.
543 * @param attr_name Attribute name to sort by.
544 */
545void sort_regions_by_attribute(std::vector<Region>& regions, const std::string& attr_name);
546
547/**
548 * @brief Add a named reference region to a reference list.
549 * @param refs Reference list (name, Region) pairs.
550 * @param name Name for the reference.
551 * @param region Region to add.
552 */
553void add_reference_region(std::vector<std::pair<std::string, Region>>& refs, const std::string& name, const Region& region);
554
555/**
556 * @brief Remove a named reference region from a reference list.
557 * @param refs Reference list (name, Region) pairs.
558 * @param name Name of the reference to remove.
559 */
560void remove_reference_region(std::vector<std::pair<std::string, Region>>& refs, const std::string& name);
561
562/**
563 * @brief Get a named reference region from a reference list.
564 * @param refs Reference list (name, Region) pairs.
565 * @param name Name of the reference to retrieve.
566 * @return Optional Region if found.
567 */
568std::optional<Region> get_reference_region(const std::vector<std::pair<std::string, Region>>& refs, const std::string& name);
569
570/**
571 * @brief Find all references in a reference list that overlap a given region.
572 * @param refs Reference list (name, Region) pairs.
573 * @param region Region to check for overlap.
574 * @return Vector of (name, Region) pairs that overlap.
575 */
576std::vector<std::pair<std::string, Region>> find_references_in_region(const std::vector<std::pair<std::string, Region>>& refs, const Region& region);
577
578/**
579 * @brief Add a RegionGroup to a group map.
580 * @param groups Map of group name to RegionGroup.
581 * @param group RegionGroup to add.
582 */
583void add_region_group(std::unordered_map<std::string, RegionGroup>& groups, const RegionGroup& group);
584
585/**
586 * @brief Get a RegionGroup by name from a group map.
587 * @param groups Map of group name to RegionGroup.
588 * @param name Name of the group to retrieve.
589 * @return Optional RegionGroup if found.
590 */
591std::optional<RegionGroup> get_region_group(const std::unordered_map<std::string, RegionGroup>& groups, const std::string& name);
592
593/**
594 * @brief Remove a RegionGroup by name from a group map.
595 * @param groups Map of group name to RegionGroup.
596 * @param name Name of the group to remove.
597 */
598void remove_region_group(std::unordered_map<std::string, RegionGroup>& groups, const std::string& name);
599
600/**
601 * @brief Calculate output region bounds from current position and shape.
602 * @param current_pos Current position coordinates.
603 * @param output_shape Desired output shape.
604 * @return Region representing the output bounds.
605 */
606Region calculate_output_region(const std::vector<uint64_t>& current_pos,
607 const std::vector<uint64_t>& output_shape);
608
609/**
610 *@brief Calculate output region for frame-based processing.
611 * @param current_frame Current frame index.
612 * @param frames_to_process Number of frames to process.
613 * @param container Container providing layout information.
614 * @return Region representing the output bounds for the specified frames.
615 */
616Region calculate_output_region(uint64_t current_frame,
617 uint64_t frames_to_process,
618 const std::shared_ptr<SignalSourceContainer>& container);
619
620/**
621 * @brief Check if region access will be contiguous in memory.
622 * @param region Region to check.
623 * @param container Container providing layout information.
624 * @return True if access is contiguous, false otherwise.
625 */
626bool is_region_access_contiguous(const Region& region,
627 const std::shared_ptr<SignalSourceContainer>& container);
628
629/**
630 * @brief Extract all regions from container's region groups.
631 * @param container Container to extract regions from.
632 * @return Vector of structured region information.
633 */
634std::vector<std::unordered_map<std::string, std::any>> extract_all_regions_info(const std::shared_ptr<SignalSourceContainer>& container);
635
636/**
637 * @brief Extract bounds information from region group.
638 * @param group Region group to analyze.
639 * @return Map containing group bounds metadata.
640 */
641std::unordered_map<std::string, std::any> extract_group_bounds_info(const RegionGroup& group);
642
643/**
644 * @brief Extract metadata from region segments.
645 * @param segments Vector of region segments.
646 * @return Vector of metadata maps, one per segment.
647 */
648std::vector<std::unordered_map<std::string, std::any>> extract_segments_metadata(const std::vector<RegionSegment>& segments);
649
650/**
651 * @brief Extract structured bounds information from region.
652 * @param region The region to analyze.
653 * @return Map containing bounds metadata.
654 */
655std::unordered_map<std::string, std::any> extract_region_bounds_info(const Region& region);
656
657/**
658 * @brief Find optimal region containing given position.
659 * @param position Coordinates to search for.
660 * @param regions Vector of regions to search within.
661 * @return Optional index of containing region.
662 */
663std::optional<size_t> find_region_for_position(const std::vector<uint64_t>& position,
664 const std::vector<Region>& regions);
665
666/**
667 * @brief Find the index of the region containing the given position.
668 * @param position N-dimensional coordinates.
669 * @param regions vector of OrganizedRegions
670 * @return Optional index of the containing region, or std::nullopt if not found.
671 */
672std::optional<size_t> find_region_for_position(const std::vector<uint64_t>& position, std::vector<OrganizedRegion> regions);
673
674/**
675 * @brief Test whether two N-dimensional regions overlap on every shared axis.
676 *
677 * Regions are treated as closed intervals. Only axes present in both
678 * regions are tested; regions with fewer than 2 coordinates on either side
679 * are never considered intersecting.
680 *
681 * @param r1 First region.
682 * @param r2 Second region.
683 * @return true if all shared axes of r1 and r2 overlap.
684 */
685[[nodiscard]] bool regions_intersect(const Region& r1, const Region& r2) noexcept;
686
687/**
688 * @brief Extract the data described by @p region from @p src using the
689 * container's dimension descriptors.
690 *
691 * Delegates to the existing role-aware @c extract_region_data machinery so
692 * that the region coordinates are interpreted correctly regardless of axis
693 * order or modality. The caller decides what the region bounds mean — this
694 * function imposes no shape assumption (rectangular, cubic, or otherwise).
695 *
696 * For interleaved image data (IMAGE_COLOR / ROW_MAJOR) the channel dimension
697 * is included in the walk if the region carries a coordinate for it;
698 * if the region has fewer coordinates than dimensions, trailing axes are
699 * included in full.
700 *
701 * @tparam T Element type of the source buffer (e.g. @c uint8_t).
702 * @param src Flat source buffer in the layout described by @p dims.
703 * @param region N-dimensional bounds; start/end coordinate count may be
704 * less than @c dims.size() — missing trailing axes default
705 * to full extent.
706 * @param dims Dimension descriptors from the container structure,
707 * ordered consistently with the flat buffer layout.
708 * @return Flat buffer containing the extracted elements in the same
709 * axis order as @p dims.
710 * @throws std::invalid_argument if @p dims is empty or @p src is smaller
711 * than the total element count implied by @p dims.
712 * @throws std::out_of_range if any coordinate in @p region exceeds the
713 * corresponding dimension size.
714 */
715template <typename T>
716[[nodiscard]] std::vector<T> extract_nd_region(
717 std::span<const T> src,
718 const Region& region,
719 const std::vector<DataDimension>& dims)
720{
721 if (dims.empty()) {
722 error<std::invalid_argument>(
724 std::source_location::current(),
725 "extract_nd_region: dims must not be empty");
726 }
727
728 uint64_t total = 1;
729 for (const auto& d : dims)
730 total *= d.size;
731
732 if (src.size() < total) {
733 error<std::invalid_argument>(
735 std::source_location::current(),
736 "extract_nd_region: src smaller than total element count implied by dims");
737 }
738
739 Region clamped = region;
740 clamped.start_coordinates.resize(dims.size(), 0);
741 clamped.end_coordinates.resize(dims.size());
742 for (size_t i = 0; i < dims.size(); ++i) {
743 if (i >= region.end_coordinates.size()) {
744 clamped.end_coordinates[i] = dims[i].size - 1;
745 } else {
746 clamped.end_coordinates[i] = std::min(region.end_coordinates[i], dims[i].size - 1);
747 }
748 }
749
750 return extract_region_data<T>(src, clamped, dims);
751}
752
753/**
754 * @brief Iterate over a set of regions, extracting per-channel samples and
755 * dispatching them to a write callback.
756 *
757 * For each region in @p regions and each channel in [0, @p num_channels),
758 * extracts double samples via get_region_data, optionally applies @p taper
759 * in-place, then calls @p write_fn with the region index, channel index,
760 * and sample span. Regions or channels that yield empty data are silently
761 * skipped.
762 *
763 * @param regions Ordered set of regions to iterate.
764 * @param source Container supplying the sample data.
765 * @param num_channels Number of channels to extract per region.
766 * @param taper Optional in-place taper. Pass {} to skip.
767 * @param write_fn Callback receiving (region_idx, channel, samples).
768 */
769MAYAFLUX_API void iterate_region_channels(
770 const std::vector<Region>& regions,
771 const std::shared_ptr<SignalSourceContainer>& source,
772 uint32_t num_channels,
773 const RegionTaper& taper,
774 const RegionWriteFn& write_fn);
775
776}
Range size
glm::vec3 position
uint32_t channel
@ Runtime
General runtime operations (default fallback)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
uint64_t coordinates_to_linear(const std::vector< uint64_t > &coords, const std::vector< DataDimension > &dimensions)
Convert N-dimensional coordinates to a linear index for interleaved data.
Definition CoordUtils.cpp:6
std::vector< T > extract_region(const std::vector< T > &data, const Region &region, const std::vector< DataDimension > &dimensions)
Extract a region of data from a vector using a Region and dimension info.
void set_region_attribute(Region &region, const std::string &key, std::any value)
Set an attribute value on a Region.
Region remove_channel_dimension(const Region &region, const std::vector< DataDimension > &dimensions)
Remove the channel dimension from a Region.
std::vector< std::vector< T > > extract_segments_data(const std::vector< RegionSegment > &segments, const std::vector< std::span< const T > > &source_spans, const std::vector< DataDimension > &dimensions, OrganizationStrategy organization)
Extract data for multiple segments from multi-channel source data.
void sort_regions_by_attribute(std::vector< Region > &regions, const std::string &attr_name)
Sort a vector of Regions by a specific attribute (numeric).
std::optional< T > get_region_attribute(const Region &region, const std::string &key)
Get an attribute value from a Region by key.
std::optional< RegionGroup > get_region_group(const std::unordered_map< std::string, RegionGroup > &groups, const std::string &name)
Get a RegionGroup by name from a group map.
std::vector< Region > find_regions_with_label(const RegionGroup &group, const std::string &label)
Find all regions in a RegionGroup with a given label.
bool is_region_access_contiguous(const Region &region, const std::shared_ptr< SignalSourceContainer > &container)
Check if region access will be contiguous in memory.
std::unordered_map< std::string, std::any > extract_region_bounds_info(const Region &region)
Extract structured bounds information from region.
std::vector< T > flatten_channels(const std::vector< std::vector< T > > &channel_data)
Flatten a vector of channel data into a single vector.
std::function< void(std::span< double >)> RegionTaper
Per-region taper applied in-place before the write callback is invoked.
void add_reference_region(std::vector< std::pair< std::string, Region > > &refs, const std::string &name, const Region &region)
Add a named reference region to a reference list.
Region translate_region(const Region &region, const std::vector< int64_t > &offset)
Translate a Region by an offset vector.
void add_region_group(std::unordered_map< std::string, RegionGroup > &groups, const RegionGroup &group)
Add a RegionGroup to a group map.
std::function< void(size_t region_idx, uint32_t channel, std::span< double >)> RegionWriteFn
Callback invoked once per region per channel during iteration.
Region scale_region(const Region &region, const std::vector< double > &factors)
Scale a Region about its center by the given factors.
void iterate_region_channels(const std::vector< Region > &regions, const std::shared_ptr< SignalSourceContainer > &source, uint32_t num_channels, const RegionTaper &taper, const RegionWriteFn &write_fn)
Iterate over a set of regions, extracting per-channel samples and dispatching them to a write callbac...
bool regions_intersect(const Region &r1, const Region &r2) noexcept
Test whether two N-dimensional regions overlap on every shared axis.
std::vector< std::vector< T > > extract_group_data(const std::vector< std::span< const T > > &source_spans, const RegionGroup &group, const std::vector< DataDimension > &dimensions, OrganizationStrategy organization)
Extract data for multiple regions from multi-channel source data.
OrganizationStrategy
Data organization strategy for multi-channel/multi-frame data.
Definition NDData.hpp:49
@ INTERLEAVED
Single DataVariant with interleaved data (LRLRLR for stereo)
std::vector< std::unordered_map< std::string, std::any > > extract_segments_metadata(const std::vector< RegionSegment > &segments)
Extract metadata from region segments.
void remove_region_group(std::unordered_map< std::string, RegionGroup > &groups, const std::string &name)
Remove a RegionGroup by name from a group map.
std::unordered_map< std::string, std::any > extract_group_bounds_info(const RegionGroup &group)
Extract bounds information from region group.
std::vector< Region > find_regions_containing_coordinates(const RegionGroup &group, const std::vector< uint64_t > &coordinates)
Find all regions in a RegionGroup that contain the given coordinates.
void remove_reference_region(std::vector< std::pair< std::string, Region > > &refs, const std::string &name)
Remove a named reference region from a reference list.
std::vector< T > extract_region_data(const std::span< const T > &source_data, const Region &region, const std::vector< DataDimension > &dimensions)
Extract a region of data from a flat data span using a Region and dimension info.
std::vector< Region > find_regions_with_attribute(const RegionGroup &group, const std::string &key, const std::any &value)
Find all regions in a RegionGroup with a specific attribute value.
std::vector< std::unordered_map< std::string, std::any > > extract_all_regions_info(const std::shared_ptr< SignalSourceContainer > &container)
Extract all regions from container's region groups.
Region get_bounding_region(const RegionGroup &group)
Get the bounding region that contains all regions in a RegionGroup.
std::vector< std::pair< std::string, Region > > find_references_in_region(const std::vector< std::pair< std::string, Region > > &refs, const Region &region)
Find all references in a reference list that overlap a given region.
std::vector< T > extract_nd_region(std::span< const T > src, const Region &region, const std::vector< DataDimension > &dims)
Extract the data described by region from src using the container's dimension descriptors.
std::optional< size_t > find_region_for_position(const std::vector< uint64_t > &position, const std::vector< Region > &regions)
Find optimal region containing given position.
Region calculate_output_region(const std::vector< uint64_t > &current_pos, const std::vector< uint64_t > &output_shape)
Calculate output region bounds from current position and shape.
uint64_t calculate_region_size(const Region &region)
Calculate the total number of elements in a region.
std::optional< Region > get_reference_region(const std::vector< std::pair< std::string, Region > > &refs, const std::string &name)
Get a named reference region from a reference list.
void set_or_update_region_data(std::span< T > dest_data, std::span< const T > source_data, const Region &region, const std::vector< DataDimension > &dimensions)
Write or update a region of data in a flat data span (interleaved).
std::vector< DataDimension > get_non_channel_dimensions(const std::vector< DataDimension > &dimensions)
Get all non-channel dimensions from a list of dimensions.
void sort_regions_by_dimension(std::vector< Region > &regions, size_t dimension)
Sort a vector of Regions by a specific dimension.
@ CHANNEL
Parallel streams (audio channels, color channels)
std::vector< Region > regions
Collection of regions belonging to this group.
Organizes related signal regions into a categorized collection.
std::unordered_map< std::string, std::any > attributes
Flexible key-value store for region-specific attributes.
Definition Region.hpp:75
uint64_t get_volume() const
Get the total volume (number of elements) in the region.
Definition Region.hpp:295
std::vector< uint64_t > end_coordinates
Ending frame index (inclusive)
Definition Region.hpp:72
std::vector< uint64_t > start_coordinates
Starting frame index (inclusive)
Definition Region.hpp:69
Represents a point or span in N-dimensional space.
Definition Region.hpp:67