package electrosphere.client.block.solver; import java.util.LinkedList; import org.joml.Vector3d; import org.joml.Vector3i; import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.ClientBlockSelection; import electrosphere.client.interact.select.AreaSelection; import electrosphere.client.interact.select.AreaSelection.AreaSelectionType; import electrosphere.client.scene.ClientWorldData; import electrosphere.data.block.fab.RoomMetadata; import electrosphere.data.block.fab.StructureMetadata; /** * Solves for the rooms in a structure */ public class RoomSolver { /** * Maximum radius of room in blocks */ public static final int MAX_ROOM_SIZE = 20; /** * 6-connected neighbors (orthogonal) */ static final int[][] NEIGHBORS = { { 1, 0, 0}, {-1, 0, 0}, { 0, 1, 0}, { 0,-1, 0}, { 0, 0, 1}, { 0, 0,-1} }; /** * Computes rooms from the currently selected voxels */ public static void computeRoomsFromSelection(AreaSelection boundingArea, StructureMetadata structureMetadata){ if(boundingArea.getType() != AreaSelectionType.RECTANGULAR){ throw new Error("Unsupported type! " + boundingArea.getType()); } int dimX = (int)Math.ceil((boundingArea.getRectEnd().x - boundingArea.getRectStart().x) * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE); int dimY = (int)Math.ceil((boundingArea.getRectEnd().y - boundingArea.getRectStart().y) * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE); int dimZ = (int)Math.ceil((boundingArea.getRectEnd().z - boundingArea.getRectStart().z) * BlockChunkData.BLOCKS_PER_UNIT_DISTANCE); int[][][] distField = ClientBlockSelection.computeCavitySDF(boundingArea); LinkedList localMaximums = new LinkedList(); for(int x = 0; x < dimX; x++){ for(int y = 0; y < dimY; y++){ for(int z = 0; z < dimZ; z++){ //don't consider edges of SDF if(x == 0 || y == 0 || z == 0 || x == dimX - 1 || y == dimY - 1 || z == dimZ - 1){ continue; } if( distField[x][y][z] >= distField[x-1][y][z] && distField[x][y][z] >= distField[x+1][y][z] && distField[x][y][z] >= distField[x][y-1][z] && distField[x][y][z] >= distField[x][y+1][z] && distField[x][y][z] >= distField[x][y][z-1] && distField[x][y][z] >= distField[x][y][z+1] ){ localMaximums.add(new Vector3i(x,y,z)); } } } } while(localMaximums.size() > 0){ Vector3i toConsider = localMaximums.poll(); Vector3d selectionStart = new Vector3d(boundingArea.getRectStart()).add( toConsider.x * BlockChunkData.BLOCK_SIZE_MULTIPLIER, toConsider.y * BlockChunkData.BLOCK_SIZE_MULTIPLIER, toConsider.z * BlockChunkData.BLOCK_SIZE_MULTIPLIER ); //make sure it's not already interecting any solved rooms boolean contained = false; for(RoomMetadata room : structureMetadata.getRooms()){ if(room.getArea().containsPoint(selectionStart)){ contained = true; break; } } if(contained){ continue; } //create the new room Vector3i roomCenterChunkPos = ClientWorldData.convertRealToChunkSpace(selectionStart); Vector3i roomCenterBlockPos = ClientWorldData.convertRealToLocalBlockSpace(selectionStart); AreaSelection roomArea = AreaSelection.selectRectangularBlockCavity(roomCenterChunkPos, roomCenterBlockPos, MAX_ROOM_SIZE); structureMetadata.getRooms().add(new RoomMetadata(roomArea)); } } }