Skip to content

Commit

Permalink
VOXEL: moved code into region class
Browse files Browse the repository at this point in the history
  • Loading branch information
mgerhardy committed Feb 23, 2025
1 parent b204348 commit 23c006c
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 64 deletions.
68 changes: 68 additions & 0 deletions src/modules/voxel/Region.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,74 @@ namespace voxel {

const Region Region::InvalidRegion = Region(0, -1);

static core::DynamicArray<Region> subtractRegion(const Region &box, const Region &sub) {
core::DynamicArray<Region> result;
result.reserve(6);

// Ensure the subtraction region is inside the box
if (sub.getLowerCorner().x > box.getUpperCorner().x || sub.getUpperCorner().x < box.getLowerCorner().x ||
sub.getLowerCorner().y > box.getUpperCorner().y || sub.getUpperCorner().y < box.getLowerCorner().y ||
sub.getLowerCorner().z > box.getUpperCorner().z || sub.getUpperCorner().z < box.getLowerCorner().z) {
// No overlap, box remains unchanged
result.push_back(box);
return result;
}

// Top part (above the selected region)
if (sub.getUpperCorner().z < box.getUpperCorner().z) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, box.getLowerCorner().y, sub.getUpperCorner().z + 1),
glm::ivec3(box.getUpperCorner().x, box.getUpperCorner().y, box.getUpperCorner().z));
}

// Bottom part (below the selected region)
if (sub.getLowerCorner().z > box.getLowerCorner().z) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, box.getLowerCorner().y, box.getLowerCorner().z),
glm::ivec3(box.getUpperCorner().x, box.getUpperCorner().y, sub.getLowerCorner().z - 1));
}

// Front part (in front of the selected region)
if (sub.getUpperCorner().y < box.getUpperCorner().y) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, sub.getUpperCorner().y + 1, sub.getLowerCorner().z),
glm::ivec3(box.getUpperCorner().x, box.getUpperCorner().y, sub.getUpperCorner().z));
}

// Back part (behind the selected region)
if (sub.getLowerCorner().y > box.getLowerCorner().y) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, box.getLowerCorner().y, sub.getLowerCorner().z),
glm::ivec3(box.getUpperCorner().x, sub.getLowerCorner().y - 1, sub.getUpperCorner().z));
}

// Left part (left of the selected region)
if (sub.getLowerCorner().x > box.getLowerCorner().x) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, sub.getLowerCorner().y, sub.getLowerCorner().z),
glm::ivec3(sub.getLowerCorner().x - 1, sub.getUpperCorner().y, sub.getUpperCorner().z));
}

// Right part (right of the selected region)
if (sub.getUpperCorner().x < box.getUpperCorner().x) {
result.emplace_back(glm::ivec3(sub.getUpperCorner().x + 1, sub.getLowerCorner().y, sub.getLowerCorner().z),
glm::ivec3(box.getUpperCorner().x, sub.getUpperCorner().y, sub.getUpperCorner().z));
}

return result;
}

core::DynamicArray<Region> Region::subtract(const Region& a, const core::DynamicArray<Region>& b) {
core::DynamicArray<Region> remainingSelections;
remainingSelections.reserve(b.size() * 6);
remainingSelections.push_back(a);

for (const Region &r : b) {
core::DynamicArray<Region> newSelections;
for (const Region &region : remainingSelections) {
const core::DynamicArray<Region> &subtracted = subtractRegion(region, r);
newSelections.insert(newSelections.end(), subtracted.begin(), subtracted.end());
}
remainingSelections = core::move(newSelections);
}
return remainingSelections;
}

void Region::update() {
_width = _maxs - _mins;
_center = _mins + _width / 2;
Expand Down
8 changes: 8 additions & 0 deletions src/modules/voxel/Region.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <glm/fwd.hpp>
#include <glm/common.hpp>
#include "core/String.h"
#include "core/collection/DynamicArray.h"
#include <stdint.h>

namespace voxel {
Expand Down Expand Up @@ -107,6 +108,13 @@ class Region {
/** Sets the position of the upper corner. */
void setUpperCorner(const glm::ivec3& maxs);

static core::DynamicArray<voxel::Region> subtract(const voxel::Region& a, const core::DynamicArray<voxel::Region>& b);
static core::DynamicArray<voxel::Region> subtract(const voxel::Region& a, const voxel::Region& b) {
core::DynamicArray<voxel::Region> result;
result.push_back(b);
return subtract(a, result);
}

/**
* @return true if the given point is exactly on the region border
*/
Expand Down
11 changes: 11 additions & 0 deletions src/modules/voxel/tests/RegionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,15 @@ TEST_F(RegionTest, testCenter) {
EXPECT_GLM_EQ(glm::vec3(0.5f), region4.calcCenterf());
}

TEST_F(RegionTest, testSubtract) {
voxel::Region a(0, 3);
voxel::Region b(1, 1);
const core::DynamicArray<voxel::Region> &remainingSelections = voxel::Region::subtract(a, b);
EXPECT_EQ(6u, remainingSelections.size());
for (const voxel::Region &region : remainingSelections) {
EXPECT_FALSE(intersects(b, region));
EXPECT_TRUE(a.containsRegion(region));
}
}

} // namespace voxel
Original file line number Diff line number Diff line change
Expand Up @@ -18,74 +18,11 @@ void SelectionManager::setMaxRegionSize(const voxel::Region &maxRegion) {
_maxRegion = maxRegion;
}

static core::DynamicArray<Selection> subtractBox(const Selection &box, const Selection &sub) {
core::DynamicArray<Selection> result;
result.reserve(6);

// Ensure the subtraction region is inside the box
if (sub.getLowerCorner().x > box.getUpperCorner().x || sub.getUpperCorner().x < box.getLowerCorner().x ||
sub.getLowerCorner().y > box.getUpperCorner().y || sub.getUpperCorner().y < box.getLowerCorner().y ||
sub.getLowerCorner().z > box.getUpperCorner().z || sub.getUpperCorner().z < box.getLowerCorner().z) {
// No overlap, box remains unchanged
result.push_back(box);
return result;
}

// Top part (above the selected region)
if (sub.getUpperCorner().z < box.getUpperCorner().z) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, box.getLowerCorner().y, sub.getUpperCorner().z + 1),
glm::ivec3(box.getUpperCorner().x, box.getUpperCorner().y, box.getUpperCorner().z));
}

// Bottom part (below the selected region)
if (sub.getLowerCorner().z > box.getLowerCorner().z) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, box.getLowerCorner().y, box.getLowerCorner().z),
glm::ivec3(box.getUpperCorner().x, box.getUpperCorner().y, sub.getLowerCorner().z - 1));
}

// Front part (in front of the selected region)
if (sub.getUpperCorner().y < box.getUpperCorner().y) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, sub.getUpperCorner().y + 1, sub.getLowerCorner().z),
glm::ivec3(box.getUpperCorner().x, box.getUpperCorner().y, sub.getUpperCorner().z));
}

// Back part (behind the selected region)
if (sub.getLowerCorner().y > box.getLowerCorner().y) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, box.getLowerCorner().y, sub.getLowerCorner().z),
glm::ivec3(box.getUpperCorner().x, sub.getLowerCorner().y - 1, sub.getUpperCorner().z));
}

// Left part (left of the selected region)
if (sub.getLowerCorner().x > box.getLowerCorner().x) {
result.emplace_back(glm::ivec3(box.getLowerCorner().x, sub.getLowerCorner().y, sub.getLowerCorner().z),
glm::ivec3(sub.getLowerCorner().x - 1, sub.getUpperCorner().y, sub.getUpperCorner().z));
}

// Right part (right of the selected region)
if (sub.getUpperCorner().x < box.getUpperCorner().x) {
result.emplace_back(glm::ivec3(sub.getUpperCorner().x + 1, sub.getLowerCorner().y, sub.getLowerCorner().z),
glm::ivec3(box.getUpperCorner().x, sub.getUpperCorner().y, sub.getUpperCorner().z));
}

return result;
}

void SelectionManager::invert(voxel::RawVolume &volume) {
if (!hasSelection()) {
select(volume, volume.region().getLowerCorner(), volume.region().getUpperCorner());
} else {
core::DynamicArray<Selection> remainingSelections;
remainingSelections.reserve(_selections.size() * 6);
remainingSelections.push_back(volume.region());

for (const Selection &selection : _selections) {
core::DynamicArray<Selection> newSelections;
for (const Selection &region : remainingSelections) {
const core::DynamicArray<Selection> &subtracted = subtractBox(region, selection);
newSelections.insert(newSelections.end(), subtracted.begin(), subtracted.end());
}
remainingSelections = core::move(newSelections);
}
const core::DynamicArray<Selection> &remainingSelections = voxel::Region::subtract(volume.region(), _selections);
reset();
for (const Selection &selection : remainingSelections) {
select(volume, selection.getLowerCorner(), selection.getUpperCorner());
Expand Down

0 comments on commit 23c006c

Please sign in to comment.