feat: extend Selection

This commit is contained in:
dualfroz committed 2026-09-09 16:45:09 +02:00
1 parent 7ca42dcf3b
commit 03b0fa187b
1 file changed
+153
+153
View File
@@ -153,3 +153,156 @@ SelectionMask SelectionMask::inverted() const {
return flipped; return flipped;
} }
SelectionMask SelectionMask::dilated(int radius) const {
if (radius <= 0 || cellCount() == 0u) return *this;
Vec3i lo{corner.x - radius, corner.y - radius, corner.z - radius};
Vec3i hi{max().x + radius, max().y + radius, max().z + radius};
SelectionMask grown(lo, extentOf(lo, hi));
forEach([&](const Vec3i& cell) { grown.add(cell); });
for (int step = 0; step < radius; ++step) {
SelectionMask next = grown;
grown.forEach([&](const Vec3i& cell) {
for (const Vec3i& offset : faceOffsets) next.add(cell + offset);
});
grown = next;
}
return grown;
}
SelectionMask SelectionMask::eroded(int radius) const {
if (radius <= 0 || cellCount() == 0u) return *this;
SelectionMask shrunk = *this;
for (int step = 0; step < radius; ++step) {
SelectionMask next = shrunk;
shrunk.forEach([&](const Vec3i& cell) {
for (const Vec3i& offset : faceOffsets) {
if (!shrunk.contains(cell + offset)) {
next.remove(cell);
break;
}
}
});
shrunk = next;
if (shrunk.empty()) break;
}
return shrunk;
}
SelectionMask SelectionMask::outline() const {
SelectionMask shell(corner, size);
forEach([&](const Vec3i& cell) {
for (const Vec3i& offset : faceOffsets) {
if (!contains(cell + offset)) {
shell.add(cell);
break;
}
}
});
return shell;
}
SelectionMask SelectionMask::trimmed() const {
if (empty()) return SelectionMask{};
Vec3i lo = max();
Vec3i hi = corner;
forEach([&](const Vec3i& cell) {
lo = minCorner(lo, cell);
hi = maxCorner(hi, cell);
});
SelectionMask tight(lo, extentOf(lo, hi));
forEach([&](const Vec3i& cell) { tight.add(cell); });
return tight;
}
SelectionMask SelectionMask::shifted(const Vec3i& delta) const {
SelectionMask moved = *this;
moved.corner = corner + delta;
return moved;
}
bool SelectionMask::sameCells(const SelectionMask& other) const {
if (setCells != other.setCells) return false;
if (setCells == 0u) return true;
SelectionMask left = trimmed();
SelectionMask right = other.trimmed();
if (!(left.corner == right.corner) || !(left.size == right.size)) return false;
return left.words == right.words;
}
void SelectionMask::forEach(const std::function<void(const Vec3i&)>& visit) const {
if (setCells == 0u) return;
for (int y = 0; y < size.y; ++y)
for (int z = 0; z < size.z; ++z)
for (int x = 0; x < size.x; ++x) {
Vec3i cell{corner.x + x, corner.y + y, corner.z + z};
if (contains(cell)) visit(cell);
}
}
std::vector<Vec3i> SelectionMask::cells() const {
std::vector<Vec3i> out;
out.reserve(setCells);
forEach([&](const Vec3i& cell) { out.push_back(cell); });
return out;
}
uint32_t SelectionStats::countOf(Block block) const {
std::size_t index = static_cast<std::size_t>(block);
if (index >= histogram.size()) return 0u;
return histogram[index];
}
Block SelectionStats::dominantBlock() const {
Block best = Block::Air;
uint32_t bestCount = 0;
for (std::size_t index = 1; index < histogram.size(); ++index) {
if (histogram[index] > bestCount) {
bestCount = histogram[index];
best = static_cast<Block>(index);
}
}
return best;
}
std::size_t SelectionStats::distinctBlocks() const {
std::size_t distinct = 0;
for (uint32_t entry : histogram)
if (entry != 0u) ++distinct;
return distinct;
}
Selection Selection::derived(SelectionMask mask) {
Selection out;
out.kind = SelectionShape::Mask;
out.cells = std::move(mask);
return out;
}
Selection Selection::box(const Vec3i& cornerA, const Vec3i& cornerB) {
Vec3i lo = minCorner(cornerA, cornerB);
Vec3i hi = maxCorner(cornerA, cornerB);
Selection out;
out.kind = SelectionShape::Box;
out.cells = SelectionMask(lo, extentOf(lo, hi));
out.cells.fillAll();
return out;
}
Selection Selection::sphere(const Vec3i& center, int radius) {
Selection out = ellipsoid(center, {radius, radius, radius});
out.kind = SelectionShape::Sphere;
return out;
}
Selection Selection::ellipsoid(const Vec3i& center, const Vec3i& radii) {
int rx = std::max(radii.x, 0);
int ry = std::max(radii.y, 0);
int rz = std::max(radii.z, 0);
Vec3i lo{center.x - rx, center.y - ry, center.z - rz};
Vec3i hi{center.x + rx, center.y + ry, center.z + rz};
Selection out;
out.kind = SelectionShape::Ellipsoid;
out.cells = SelectionMask(lo, extentOf(lo, hi));