Files
somaesque-native/VoxelSpace.cpp
2022-11-13 22:08:20 +01:00

263 lines
9.2 KiB
C++

#include "VoxelSpace.h"
#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdint>
namespace Voxel {
inline auto index(int dims[3], int x, int y, int z) -> int {
return (dims[1] * dims[2] * x + dims[2] * y + z);
}
// [1, 0, 0] [x] [ x]
// [0, 0, -1] * [y] = [-z]
// [0, 1, 0] [z] [ y]
inline auto newIndexRotX(int dims[3], int x, int y, int z) -> int {
return dims[2] * dims[1] * x + dims[1] * (dims[2] - 1 - z) + y;
}
// [ 0, 0, 1] [x] [ z]
// [ 0, 1, 0] * [y] = [ y]
// [-1, 0, 0] [z] [-x]
inline auto newIndexRotY(int dims[3], int x, int y, int z) -> int {
return dims[1] * dims[0] * z + dims[0] * y + (dims[0] - 1 - x);
}
// [0, -1, 0] [x] [-y]
// [1, 0, 0] * [y] = [ x]
// [0, 0, 1] [z] [ z]
inline auto newIndexRotZ(int dims[3], int x, int y, int z) -> int {
return dims[0] * dims[2] * (dims[1] - 1 - y) + dims[2] * x + z;
}
inline auto toggle(uint64_t space, int index) -> uint64_t {
space ^= 1ull << index;
return space;
}
inline auto set(uint64_t *space, int index, bool val) -> void {
if (val) {
*space |= 1ull << index;
} else {
*space &= ~(1ull << index);
}
}
inline auto collides(uint64_t a, uint64_t b) -> bool {
return (a | b) != (a ^ b);
}
inline auto filledAt(uint64_t space, int dims[3], int x, int y, int z) -> bool {
auto mask = 1ull << (dims[1] * dims[2] * x + dims[2] * y + z);
return (space & mask) != 0ull;
}
auto getExtrema(uint64_t space, int dims[3]) -> Extrema {
auto extrema = Extrema{
.xMax=0,
.xMin=dims[0],
.yMax=0,
.yMin=dims[1],
.zMax=0,
.zMin=dims[2],
};
for (int x = 0; x < dims[0]; x++) {
for (int y = 0; y < dims[1]; y++) {
for (int z = 0; z < dims[2]; z++) {
if (filledAt(space, dims, x, y, z)) {
if (x > extrema.xMax) extrema.xMax = x;
if (x < extrema.xMin) extrema.xMin = x;
if (y > extrema.yMax) extrema.yMax = y;
if (y < extrema.yMin) extrema.yMin = y;
if (z > extrema.zMax) extrema.zMax = z;
if (z < extrema.zMin) extrema.zMin = z;
}
}
}
}
return extrema;
}
auto cullEmptySpace(Space *space) -> void {
auto extrema = getExtrema(space->space, space->dims);
auto space_index = 0;
auto newSpace = 0ull;
for (int x = extrema.xMin; x <= extrema.xMax; x++) {
for (int y = extrema.yMin; y <= extrema.yMax; y++) {
for (int z = extrema.zMin; z <= extrema.zMax; z++) {
if (filledAt(space->space, space->dims, x, y, z)) {
newSpace |= 1ull << space_index;
}
space_index++;
}
}
}
space->dims[0] = extrema.xMax - extrema.xMin + 1;
space->dims[1] = extrema.yMax - extrema.yMin + 1;
space->dims[2] = extrema.zMax - extrema.zMin + 1;
space->space = newSpace;
}
auto rotate90X(Space *space) -> void {
for (int x = 0; x < space->dims[0]; x++) {
for (int y = 0; y < space->dims[1]; y++) {
for (int z = 0; z < space->dims[2]; z++) {
if (filledAt(space->space, space->dims, x, y, z)) {
space->space |= 1 << newIndexRotX(space->dims, x, y, z);
}
}
}
}
auto temp = space->dims[1];
space->dims[1] = space->dims[2];
space->dims[2] = temp;
}
auto rotate90Y(Space *space) -> void {
for (int x = 0; x < space->dims[0]; x++) {
for (int y = 0; y < space->dims[1]; y++) {
for (int z = 0; z < space->dims[2]; z++) {
if (filledAt(space->space, space->dims, x, y, z)) {
space->space |= 1 << newIndexRotY(space->dims, x, y, z);
}
}
}
}
auto temp = space->dims[0];
space->dims[0] = space->dims[2];
space->dims[2] = temp;
}
auto rotate90Z(Space *space) -> void {
for (int x = 0; x < space->dims[0]; x++) {
for (int y = 0; y < space->dims[1]; y++) {
for (int z = 0; z < space->dims[2]; z++) {
if (filledAt(space->space, space->dims, x, y, z)) {
space->space |= 1 << newIndexRotZ(space->dims, x, y, z);
}
}
}
}
auto temp = space->dims[0];
space->dims[0] = space->dims[1];
space->dims[1] = temp;
}
inline auto isMatch(Space *a, Space *b) -> bool {
return a->space == b->space
&& a->dims[0] == b->dims[0]
&& a->dims[1] == b->dims[1]
&& a->dims[2] == b->dims[2];
}
auto pushNewUniqueSpins(std::vector<Space> *existingSpaces, Space* spaceToSpin) -> void {
Space spins[4] = {};
spins[0] = *spaceToSpin;
for (int i = 0; i < 3; i++) {
spins[i + 1] = spins[i];
rotate90X(&spins[i + 1]);
}
for (int i = 0; i < 4; i++) {
auto matchFound = false;
for (auto &existingSpace : *existingSpaces) {
if (isMatch(&existingSpace, &spins[i])) {
matchFound = true;
break;
}
}
if (!matchFound) {
existingSpaces->push_back(spins[i]);
}
}
}
auto getUniqueRotations(Space *space) -> std::vector<Space> {
auto rotations = std::vector<Space>();
rotations.reserve(6*24);
auto dims = space->dims;
auto refSpace = *space;
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Y(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
rotate90Z(&refSpace);
rotate90Z(&refSpace);
pushNewUniqueSpins(&rotations, &refSpace);
return rotations;
}
/*
getAllRotations(): Space[] {
let rotations: Space[] = new Array<Space>();
const refSpace = this.clone();
rotations = rotations.concat(refSpace.getXAxisSpins());
refSpace.rot90Y();
rotations = rotations.concat(refSpace.getXAxisSpins());
refSpace.rot90Y();
rotations = rotations.concat(refSpace.getXAxisSpins());
refSpace.rot90Y();
rotations = rotations.concat(refSpace.getXAxisSpins());
refSpace.rot90Z();
rotations = rotations.concat(refSpace.getXAxisSpins());
refSpace.rot90Z();
refSpace.rot90Z();
rotations = rotations.concat(refSpace.getXAxisSpins());
return rotations;
}
*/
auto getAllPositionsInPrism(uint64_t space, int space_dims[3], int prism_dims[3]) -> std::vector<uint64_t> {
auto cubePositions = std::vector<uint64_t>();
if (space_dims[0] > prism_dims[0] || space_dims[1] > prism_dims[1] || space_dims[2] > prism_dims[2]) {
return cubePositions;
}
auto xPositionCount = prism_dims[0] - space_dims[0] + 1;
auto yPositionCount = prism_dims[1] - space_dims[1] + 1;
auto zPositionCount = prism_dims[2] - space_dims[2] + 1;
cubePositions.reserve(xPositionCount + yPositionCount + zPositionCount);
for (int x = 0; x < xPositionCount; x++) {
for (int y = 0; y < yPositionCount; y++) {
for (int z = 0; z < zPositionCount; z++) {
auto new_space = space;
for (int posX = 0; posX < space_dims[0]; posX++) {
for (int posY = 0; posY < space_dims[1]; posY++) {
for (int posZ = 0; posZ < space_dims[2]; posZ++) {
auto set_val = filledAt(space, space_dims, x, y, z);
auto index_to_set = index(space_dims, x + posX, y + posY, z + posZ);
set(&new_space, index_to_set, set_val);
}
}
}
cubePositions.push_back(new_space);
}
}
}
return cubePositions;
}
auto getAllPermutationsInPrism(Space *space, int prism_dims[3]) -> std::vector<uint64_t> {
auto rotations = getUniqueRotations(space);
auto result = std::vector<uint64_t>();
for (auto &rotation : rotations) {
auto positions = getAllPositionsInPrism(rotation.space, rotation.dims, prism_dims);
result.insert(result.end(), positions.begin(), positions.end());
}
return result;
}
auto size(uint64_t space) -> int {
auto size = 0;
for (int i = 0; i < 64; i++) {
if ((space & (1ull << i)) != 0) {
size++;
}
}
return size;
}
}