feat: extend Selection
This commit is contained in:
1 parent
7ca42dcf3b
commit
03b0fa187b
1 file changed
+153
@@ -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));
|
||||||
|
|
||||||
Reference in new issue
Block a user