break out room solver
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
d1ab990a63
commit
5def6da2de
@ -1851,6 +1851,7 @@ Script engine direct access to joml vectors
|
|||||||
Script engine passing objects back into methods successfully
|
Script engine passing objects back into methods successfully
|
||||||
Room detection within structures
|
Room detection within structures
|
||||||
Structure metadata organization
|
Structure metadata organization
|
||||||
|
Break out room solver
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
100
src/main/java/electrosphere/client/block/solver/RoomSolver.java
Normal file
100
src/main/java/electrosphere/client/block/solver/RoomSolver.java
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
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<Vector3i> localMaximums = new LinkedList<Vector3i>();
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ import java.io.File;
|
|||||||
import org.joml.Vector3d;
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
import electrosphere.client.block.ClientBlockSelection;
|
import electrosphere.client.block.ClientBlockSelection;
|
||||||
|
import electrosphere.client.block.solver.RoomSolver;
|
||||||
import electrosphere.client.interact.select.AreaSelection;
|
import electrosphere.client.interact.select.AreaSelection;
|
||||||
import electrosphere.data.block.fab.BlockFab;
|
import electrosphere.data.block.fab.BlockFab;
|
||||||
import electrosphere.data.block.fab.BlockFabMetadata;
|
import electrosphere.data.block.fab.BlockFabMetadata;
|
||||||
@ -40,7 +41,7 @@ public class ImGuiStructureTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(Globals.clientState.currentStructureData != null && ImGui.button("Calculate Rooms")){
|
if(Globals.clientState.currentStructureData != null && ImGui.button("Calculate Rooms")){
|
||||||
Globals.clientState.currentStructureData.computeRoomsFromSelection();
|
RoomSolver.computeRoomsFromSelection(Globals.cursorState.getAreaSelection(),Globals.clientState.currentStructureData);
|
||||||
}
|
}
|
||||||
if(ImGui.button("Convert current selection to room")){
|
if(ImGui.button("Convert current selection to room")){
|
||||||
AreaSelection currentSelection = Globals.cursorState.getAreaSelection();
|
AreaSelection currentSelection = Globals.cursorState.getAreaSelection();
|
||||||
|
|||||||
@ -3,25 +3,13 @@ package electrosphere.data.block.fab;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
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;
|
||||||
import electrosphere.client.interact.select.AreaSelection.AreaSelectionType;
|
|
||||||
import electrosphere.client.scene.ClientWorldData;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure data
|
* Structure data
|
||||||
*/
|
*/
|
||||||
public class StructureMetadata {
|
public class StructureMetadata {
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum radius of room in blocks
|
|
||||||
*/
|
|
||||||
public static final int MAX_ROOM_SIZE = 20;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The bounding area of the structure
|
* The bounding area of the structure
|
||||||
*/
|
*/
|
||||||
@ -44,80 +32,6 @@ public class StructureMetadata {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 void computeRoomsFromSelection(){
|
|
||||||
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<Vector3i> localMaximums = new LinkedList<Vector3i>();
|
|
||||||
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 : rooms){
|
|
||||||
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);
|
|
||||||
rooms.add(new RoomMetadata(roomArea));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the bounding area
|
* Gets the bounding area
|
||||||
* @return The bounding area
|
* @return The bounding area
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user