124 static constexpr bool usesDenseLevels() {
125 if constexpr (std::is_integral_v<altitude_t>) {
127 return std::numeric_limits<unsigned_altitude_t>::digits <= MMCFILTERS_COMPONENT_TREE_ADJUSTMENT_DENSE_MAX_BITS;
136 static constexpr bool use_dense_levels = usesDenseLevels();
147 class MergedNodesCollection {
149 template <
bool dense,
typename AltitudeType>
struct StorageSelector;
154 template <
typename AltitudeType>
struct StorageSelector<
true, AltitudeType> {
156 static constexpr std::size_t domain_size =
static_cast<std::size_t
>(
static_cast<long long>(std::numeric_limits<AltitudeType>::max()) -
157 static_cast<long long>(std::numeric_limits<AltitudeType>::lowest()) + 1);
159 using type = std::array<std::vector<NodeId>, domain_size>;
165 template <
typename AltitudeType>
struct StorageSelector<
false, AltitudeType> {
167 using type = std::map<AltitudeType, std::vector<NodeId>>;
171 using storage_t =
typename StorageSelector<use_dense_levels, altitude_t>::type;
174 storage_t mergeNodesByLevelStorage_;
176 std::vector<altitude_t> mergeLevels_;
178 std::vector<NodeId> frontierNodesAboveB_;
186 std::size_t maxBucketSize_ = 0;
188 int currentMergeLevelIndex_ = 0;
190 bool isMaxtree_ =
false;
201 static std::size_t denseBucketIndex(altitude_t
level) {
202 if constexpr (std::is_signed_v<altitude_t>) {
203 return static_cast<std::size_t
>(
static_cast<long long>(
level) -
static_cast<long long>(std::numeric_limits<altitude_t>::lowest()));
205 return static_cast<std::size_t
>(
level);
215 static altitude_t levelFromDenseBucketIndex(std::size_t index) {
216 if constexpr (std::is_signed_v<altitude_t>) {
217 return static_cast<altitude_t
>(
static_cast<long long>(index) +
static_cast<long long>(std::numeric_limits<altitude_t>::lowest()));
219 return static_cast<altitude_t
>(index);
227 explicit MergedNodesCollection(
int maxNodes = 0)
228 : collectedNodeMarks_(
static_cast<size_t>(std::max(
maxNodes, 0))), mergeBucketNodeMarks_(
static_cast<size_t>(std::max(
maxNodes, 0))),
229 adjacentSeedMarks_(
static_cast<size_t>(std::max(
maxNodes, 0))) {}
237 for (altitude_t
level : mergeLevels_) {
238 if constexpr (use_dense_levels) {
241 mergeNodesByLevelStorage_[denseBucketIndex(
level)].clear();
245 auto it = mergeNodesByLevelStorage_.find(
level);
246 if (
it != mergeNodesByLevelStorage_.end()) {
251 mergeLevels_.clear();
252 frontierNodesAboveB_.clear();
257 currentMergeLevelIndex_ = 0;
266 std::vector<NodeId>& getMergedNodes(
const altitude_t&
level) {
267 if constexpr (use_dense_levels) {
268 return mergeNodesByLevelStorage_[denseBucketIndex(
level)];
270 return mergeNodesByLevelStorage_[
level];
281 std::vector<NodeId>& getFrontierNodesAboveB() {
return frontierNodesAboveB_; }
289 std::size_t getMaxBucketSize()
const {
return maxBucketSize_; }
302 adjacentSeedMarks_.
mark(
static_cast<size_t>(
nodeId));
313 frontierNodesAboveB_.push_back(
nodeId);
314 collectedNodeMarks_.
mark(
static_cast<size_t>(
nodeId));
330 auto&
bucket = getMergedNodes(tree.nodeAltitude(
nodeId));
332 maxBucketSize_ = std::max(maxBucketSize_,
bucket.size());
333 collectedNodeMarks_.
mark(
static_cast<size_t>(
nodeId));
334 mergeBucketNodeMarks_.
mark(
static_cast<size_t>(
nodeId));
353 altitude_t firstMergeLevel() {
354 mergeLevels_.clear();
355 if constexpr (use_dense_levels) {
358 for (std::size_t
i = 0;
i < mergeNodesByLevelStorage_.size(); ++
i) {
359 if (!mergeNodesByLevelStorage_[
i].empty()) {
360 mergeLevels_.push_back(levelFromDenseBucketIndex(
i));
365 mergeLevels_.reserve(mergeNodesByLevelStorage_.size());
366 for (
const auto&
entry : mergeNodesByLevelStorage_) {
372 if (mergeLevels_.empty()) {
375 currentMergeLevelIndex_ = isMaxtree_ ?
static_cast<int>(mergeLevels_.size()) - 1 : 0;
376 return mergeLevels_[
static_cast<size_t>(currentMergeLevelIndex_)];
384 bool hasMergeLevel()
const {
393 altitude_t nextMergeLevel() {
394 currentMergeLevelIndex_ = isMaxtree_ ? currentMergeLevelIndex_ - 1 : currentMergeLevelIndex_ + 1;
395 if (!hasMergeLevel()) {
398 return mergeLevels_[
static_cast<size_t>(currentMergeLevelIndex_)];
404 tree_t* mintree_ =
nullptr;
406 tree_t* maxtree_ =
nullptr;
412 MergedNodesCollection mergeNodesByLevel_;
422 std::vector<PixelId> properPartSetC_;
424 std::vector<NodeId> nodesPendingRemoval_;
426 std::vector<NodeId> removedNodesPendingAbsorption_;
428 altitude_t altitudeCa_ = altitude_t{};
436 std::vector<double>* attributeBufferMin_ =
nullptr;
438 std::vector<double>* attributeBufferMax_ =
nullptr;
448 return tree->topology();
458 typename attribute_computer_t::buffer_type* getAttributeBuffer(
tree_t* tree)
const {
459 const auto*
computer = tree == maxtree_ ? attributeComputerMax_ : attributeComputerMin_;
463 return tree == maxtree_ ? attributeBufferMax_ : attributeBufferMin_;
473 if (tree ==
nullptr) {
476 return tree == maxtree_ ? attributeComputerMax_ : attributeComputerMin_;
488 const auto*
computer = getAttributeComputer(tree);
502 const auto*
computer = getAttributeComputer(tree);
503 if (
computer !=
nullptr && tree !=
nullptr) {
517 const auto*
computer = getAttributeComputer(tree);
518 if (
computer !=
nullptr && tree !=
nullptr) {
532 return tree->nodeAltitude(
nodeId);
547 const auto*
computer = getAttributeComputer(tree);
552 auto*
buffer = getAttributeBuffer(tree);
554 if (!attributeUpdateMarks_.
isMarked(
static_cast<size_t>(
nodeId))) {
558 const altitude_t
level = nodeAltitude(tree,
nodeId);
559 if ((tree == maxtree_ &&
level < altitudeCa_) || (tree == mintree_ &&
level > altitudeCa_)) {
560 attributeUpdateMarks_.
unmark(
static_cast<size_t>(
nodeId));
565 attributeUpdateMarks_.
unmark(
static_cast<size_t>(
nodeId));
571 void resetAttributeUpdateMarks() {
573 altitudeCa_ = altitude_t{};
583 if (getAttributeComputer(tree) ==
nullptr || tree ==
nullptr ||
nodeId ==
InvalidNode) {
586 if (!topologyOf(tree).isNode(
nodeId) || !topologyOf(tree).isAlive(
nodeId)) {
589 attributeUpdateMarks_.
mark(
static_cast<size_t>(
nodeId));
614 notifyNodeRemoved(tree,
nodeId);
640 if (topologyOf(
dualTree).isAlive(smallestNodeId) && topologyOf(
dualTree).properPartCardinality(smallestNodeId) == 0 && smallestNodeId !=
unionNode &&
641 !removedMarks_.
isMarked(
static_cast<size_t>(smallestNodeId))) {
642 removedMarks_.
mark(
static_cast<size_t>(smallestNodeId));
643 removedNodesPendingAbsorption_.push_back(smallestNodeId);
752 std::vector<Frame>
stack;
768 while (!
stack.empty()) {
963 absorbRemovedNodes(
dualTree,
editor, removedNodesPendingAbsorption_);
992 const NodeId next = topologyOf(tree).getNextSibling(
childId);
993 if (mergeNodesByLevel_.isMergeNode(
childId)) {
1002 const NodeId next = topologyOf(tree).getNextSibling(
childId);
1003 if (mergeNodesByLevel_.isMergeNode(
childId)) {
1031 mergeNodesByLevel_.resetCollection(
isMaxtree);
1053 if (mergeNodesByLevel_.markAdjacentSeed(
nodeQ)) {
1056 while (n !=
InvalidNode && tree.topology().isAlive(n) && !climbedNodeMarks_.
isMarked(
static_cast<size_t>(n))) {
1057 const altitude_t
levelCurrent = nodeAltitude(&tree, n);
1062 climbedNodeMarks_.
mark(
static_cast<size_t>(n));
1066 mergeNodesByLevel_.addMergeNode(tree,
nodeSubtree);
1074 mergeNodesByLevel_.addFrontierNodeAboveB(
nodeSubtree);
1115 resetAttributeUpdateMarks();
1128 altitudeCa_ = altitude_t{};
1130 properPartSetC_.clear();
1131 properPartSetC_.reserve(64);
1135 properPartSetC_.push_back(pixel);
1136 pixelsInCMarks_.
mark(
static_cast<size_t>(pixel));
1149 if (properPartSetC_.empty()) {
1161 removedNodesPendingAbsorption_.clear();
1162 nodesPendingRemoval_.reserve(mergeNodesByLevel_.getMaxBucketSize());
1167 nodesPendingRemoval_.clear();
1176 nodesPendingRemoval_.push_back(
nodeId);
1189 nodesPendingRemoval_.clear();
1217 for (
NodeId nodeId : mergeNodesByLevel_.getFrontierNodesAboveB()) {
1281 assert(mintree_ !=
nullptr);
1282 assert(maxtree_ !=
nullptr);
1283 assert(graph_ !=
nullptr);
1326 assert(mintree_ !=
nullptr);
1327 assert(maxtree_ !=
nullptr);
1348 assert(mintree_ !=
nullptr);
1349 assert(maxtree_ !=
nullptr);