117 static constexpr bool usesDenseLevels() {
118 if constexpr (std::is_integral_v<altitude_t>) {
120 return std::numeric_limits<unsigned_altitude_t>::digits <= MMCFILTERS_COMPONENT_TREE_ADJUSTMENT_DENSE_MAX_BITS;
129 static constexpr bool use_dense_levels = usesDenseLevels();
140 class MergedNodesCollection {
142 template<
bool dense,
typename altitude_type>
143 struct StorageSelector;
148 template<
typename altitude_type>
149 struct StorageSelector<
true, altitude_type> {
150 static constexpr std::size_t domain_size =
151 static_cast<std::size_t
>(
152 static_cast<long long>(std::numeric_limits<altitude_type>::max()) -
153 static_cast<long long>(std::numeric_limits<altitude_type>::lowest()) + 1);
154 using type = std::array<std::vector<NodeId>, domain_size>;
160 template<
typename altitude_type>
161 struct StorageSelector<
false, altitude_type> {
162 using type = std::map<altitude_type, std::vector<NodeId>>;
165 using storage_t =
typename StorageSelector<use_dense_levels, altitude_t>::type;
167 storage_t mergeNodesByLevelStorage_;
168 std::vector<altitude_t> mergeLevels_;
169 std::vector<NodeId> frontierNodesAboveB_;
173 std::size_t maxBucketSize_ = 0;
174 int currentMergeLevelIndex_ = 0;
175 bool isMaxtree_ =
false;
183 static std::size_t denseBucketIndex(altitude_t level) {
184 if constexpr (std::is_signed_v<altitude_t>) {
185 return static_cast<std::size_t
>(
186 static_cast<long long>(level) -
187 static_cast<long long>(std::numeric_limits<altitude_t>::lowest()));
189 return static_cast<std::size_t
>(level);
196 static altitude_t levelFromDenseBucketIndex(std::size_t index) {
197 if constexpr (std::is_signed_v<altitude_t>) {
198 return static_cast<altitude_t
>(
199 static_cast<long long>(index) +
200 static_cast<long long>(std::numeric_limits<altitude_t>::lowest()));
202 return static_cast<altitude_t
>(index);
210 explicit MergedNodesCollection(
int maxNodes = 0)
211 : collectedNodeMarks_(
static_cast<size_t>(std::max(
maxNodes, 0))),
212 mergeBucketNodeMarks_(
static_cast<size_t>(std::max(
maxNodes, 0))),
213 adjacentSeedMarks_(
static_cast<size_t>(std::max(
maxNodes, 0))) {}
221 for (altitude_t level : mergeLevels_) {
222 if constexpr (use_dense_levels) {
225 mergeNodesByLevelStorage_[denseBucketIndex(level)].clear();
229 auto it = mergeNodesByLevelStorage_.find(level);
230 if (
it != mergeNodesByLevelStorage_.end()) {
235 mergeLevels_.clear();
236 frontierNodesAboveB_.clear();
241 currentMergeLevelIndex_ = 0;
247 std::vector<NodeId>& getMergedNodes(
const altitude_t& level) {
248 if constexpr (use_dense_levels) {
249 return mergeNodesByLevelStorage_[denseBucketIndex(level)];
251 return mergeNodesByLevelStorage_[level];
260 std::vector<NodeId>& getFrontierNodesAboveB() {
return frontierNodesAboveB_; }
266 std::size_t getMaxBucketSize()
const {
return maxBucketSize_; }
276 adjacentSeedMarks_.
mark(
static_cast<size_t>(
nodeId));
285 frontierNodesAboveB_.push_back(
nodeId);
286 collectedNodeMarks_.
mark(
static_cast<size_t>(
nodeId));
299 auto&
bucket = getMergedNodes(tree.getAltitude(
nodeId));
301 maxBucketSize_ = std::max(maxBucketSize_,
bucket.size());
302 collectedNodeMarks_.
mark(
static_cast<size_t>(
nodeId));
303 mergeBucketNodeMarks_.
mark(
static_cast<size_t>(
nodeId));
310 return mergeBucketNodeMarks_.
isMarked(
static_cast<size_t>(
nodeId));
319 altitude_t firstMergeLevel() {
320 mergeLevels_.clear();
321 if constexpr (use_dense_levels) {
324 for (std::size_t
i = 0;
i < mergeNodesByLevelStorage_.size(); ++
i) {
325 if (!mergeNodesByLevelStorage_[
i].empty()) {
326 mergeLevels_.push_back(levelFromDenseBucketIndex(
i));
331 mergeLevels_.reserve(mergeNodesByLevelStorage_.size());
332 for (
const auto&
entry : mergeNodesByLevelStorage_) {
338 if (mergeLevels_.empty()) {
341 currentMergeLevelIndex_ = isMaxtree_ ?
static_cast<int>(mergeLevels_.size()) - 1 : 0;
342 return mergeLevels_[
static_cast<size_t>(currentMergeLevelIndex_)];
348 bool hasMergeLevel()
const {
349 return !mergeLevels_.empty() &&
350 currentMergeLevelIndex_ >= 0 &&
357 altitude_t nextMergeLevel() {
358 currentMergeLevelIndex_ = isMaxtree_ ? currentMergeLevelIndex_ - 1 : currentMergeLevelIndex_ + 1;
359 if (!hasMergeLevel()) {
362 return mergeLevels_[
static_cast<size_t>(currentMergeLevelIndex_)];
367 tree_t* mintree_ =
nullptr;
368 tree_t* maxtree_ =
nullptr;
372 MergedNodesCollection mergeNodesByLevel_;
377 std::vector<NodeId> properPartSetC_;
378 std::vector<NodeId> nodesPendingRemoval_;
379 std::vector<NodeId> removedNodesPendingAbsorption_;
380 altitude_t altitudeCa_ = altitude_t{};
385 std::vector<double>* attributeBufferMin_ =
nullptr;
386 std::vector<double>* attributeBufferMax_ =
nullptr;
393 return tree->topology();
400 typename attribute_computer_t::buffer_type* getAttributeBuffer(
tree_t* tree)
const {
401 const auto*
computer = tree == maxtree_ ? attributeComputerMax_ : attributeComputerMin_;
405 return tree == maxtree_ ? attributeBufferMax_ : attributeBufferMin_;
412 if (tree ==
nullptr) {
415 return tree == maxtree_ ? attributeComputerMax_ : attributeComputerMin_;
424 const auto*
computer = getAttributeComputer(tree);
434 const auto*
computer = getAttributeComputer(tree);
435 if (
computer !=
nullptr && tree !=
nullptr) {
444 const auto*
computer = getAttributeComputer(tree);
445 if (
computer !=
nullptr && tree !=
nullptr) {
455 return tree->getAltitude(
nodeId);
467 const auto*
computer = getAttributeComputer(tree);
469 !topologyOf(tree).isNode(
nodeId) || !topologyOf(tree).isAlive(
nodeId)) {
473 auto*
buffer = getAttributeBuffer(tree);
475 if (!attributeUpdateMarks_.
isMarked(
static_cast<size_t>(
nodeId))) {
479 const altitude_t level = nodeAltitude(tree,
nodeId);
480 if ((tree == maxtree_ && level < altitudeCa_) || (tree == mintree_ && level > altitudeCa_)) {
481 attributeUpdateMarks_.
unmark(
static_cast<size_t>(
nodeId));
486 attributeUpdateMarks_.
unmark(
static_cast<size_t>(
nodeId));
492 void resetAttributeUpdateMarks() {
494 altitudeCa_ = altitude_t{};
501 if (getAttributeComputer(tree) ==
nullptr || tree ==
nullptr ||
nodeId ==
InvalidNode) {
504 if (!topologyOf(tree).isNode(
nodeId) || !topologyOf(tree).isAlive(
nodeId)) {
507 attributeUpdateMarks_.
mark(
static_cast<size_t>(
nodeId));
527 notifyNodeRemoved(tree,
nodeId);
553 removedNodesPendingAbsorption_.push_back(
ownerId);
649 std::vector<Frame>
stack;
665 while (!
stack.empty()) {
851 absorbRemovedNodes(
dualTree,
editor, removedNodesPendingAbsorption_);
875 if (mergeNodesByLevel_.isMergeNode(
childId)) {
885 if (mergeNodesByLevel_.isMergeNode(
childId)) {
907 mergeNodesByLevel_.resetCollection(
isMaxtree);
914 if (pixelsInCMarks_.
isMarked(
static_cast<size_t>(
q))) {
918 const NodeId nodeQ = tree.topology().getProperPartOwner(
q);
929 if (mergeNodesByLevel_.markAdjacentSeed(
nodeQ)) {
932 while (n !=
InvalidNode && tree.topology().isAlive(n) && !climbedNodeMarks_.
isMarked(
static_cast<size_t>(n))) {
938 climbedNodeMarks_.
mark(
static_cast<size_t>(n));
942 mergeNodesByLevel_.addMergeNode(tree,
nodeSubtree);
951 mergeNodesByLevel_.addFrontierNodeAboveB(
nodeSubtree);
988 resetAttributeUpdateMarks();
1001 altitudeCa_ = altitude_t{};
1003 properPartSetC_.clear();
1004 properPartSetC_.reserve(64);
1008 properPartSetC_.push_back(
p);
1009 pixelsInCMarks_.
mark(
static_cast<size_t>(
p));
1022 if (properPartSetC_.empty()) {
1034 removedNodesPendingAbsorption_.clear();
1035 nodesPendingRemoval_.reserve(mergeNodesByLevel_.getMaxBucketSize());
1037 while (mergeNodesByLevel_.hasMergeLevel() &&
1041 nodesPendingRemoval_.clear();
1050 nodesPendingRemoval_.push_back(
nodeId);
1063 nodesPendingRemoval_.clear();
1091 for (
NodeId nodeId : mergeNodesByLevel_.getFrontierNodesAboveB()) {
1115 editor.commitUnchecked();
1128 return MMCFILTERS_COMPONENT_TREE_ADJUSTMENT_DENSE_MAX_BITS;
1146 mergeNodesByLevel_(std::
max(
mintree ?
mintree->topology().getNumInternalNodeSlots() : 0,
1156 assert(mintree_ !=
nullptr);
1157 assert(maxtree_ !=
nullptr);
1158 assert(graph_ !=
nullptr);
1194 assert(mintree_ !=
nullptr);
1195 assert(maxtree_ !=
nullptr);
1216 assert(mintree_ !=
nullptr);
1217 assert(maxtree_ !=
nullptr);