Solved How to find the corners of a cuboid?

Discussion in 'Plugin Development' started by Assist, Nov 19, 2014.

Thread Status:
Not open for further replies.
  1. Hey.

    I have a list of blocks collected from the Minecraft world. These blocks form a cuboid. How would I go about finding the two opposite corners, as shown in this picture?
    Show Spoiler
    [​IMG]

    This is what I use to collect the blocks. I arrange the relatives into their own ArrayLists for simplicity.
    Code:java
    1. ArrayList<Location[]> cubes = new ArrayList<>(); // where the final cubes should be stored
    2. ArrayList<ArrayList<Block>> bedrockConnections = new ArrayList<>(); // list of bedrocks that form a cube
    3.  
    4. Block startBlock = arena.getStartBlock();
    5. Block endBlock = arena.getEndBlock();
    6.  
    7. for (int x = startBlock.getLocation().getBlockX(); x <= endBlock.getLocation().getBlockX(); x++) {
    8. for (int y = startBlock.getLocation().getBlockY(); y <= endBlock.getLocation().getBlockY(); y++) {
    9. for (int z = startBlock.getLocation().getBlockZ(); z <= endBlock.getLocation().getBlockZ(); z++) {
    10. Block block = startBlock.getWorld().getBlockAt(x, y, z);
    11. byte data = block.getData();
    12.  
    13. if (block.getType() == Material.BEDROCK) {
    14. ArrayList <Block> connectionList = findConnectionList(block, bedrockConnections);
    15.  
    16. if (connectionList == null) {
    17. connectionList = new ArrayList < Block > ();
    18. bedrockConnections.add(connectionList);
    19. }
    20.  
    21. connectionList.add(block);
    22. }
    23. }
    24. }
    25. }
    26.  
    27. for (ArrayList <Block> connectionList: bedrockConnections) {
    28. Block[] corners = findCorners(connectionList);
    29. Block b1 = corners[0];
    30. Block b2 = corners[1];
    31.  
    32. if (b1 == null || b2 == null) {
    33. continue;
    34. }
    35.  
    36. cubes.add(new Location[] { corners[0].getLocation(), corners[1].getLocation() });
    37. }
    38.  
    39. // attempts to find the list that contains the relatives of that block
    40. private ArrayList<Block> findConnectionList(Block origin, List <ArrayList<Block>> mainConnectionList) {
    41. for (ArrayList <Block> list: mainConnectionList) {
    42. for (BlockFace direction: DIRECTIONS) {
    43. if (list.contains(origin.getRelative(direction))) {
    44. return list;
    45. }
    46. }
    47. }
    48.  
    49. return null;
    50. }
    51.  
    52. // my failed attempt at getting the corners
    53. private Block[] findCorners(ArrayList<Block> blocks) {
    54. Block b1 = null;
    55. Block b2 = null;
    56.  
    57. for (Block block: blocks) {
    58. int x = block.getLocation().getBlockX();
    59. int y = block.getLocation().getBlockY();
    60. int z = block.getLocation().getBlockZ();
    61.  
    62. int bX1 = b1 == null ? -1 : b1.getLocation().getBlockX();
    63. int bY1 = b1 == null ? -1 : b1.getLocation().getBlockY();
    64. int bZ1 = b1 == null ? -1 : b1.getLocation().getBlockZ();
    65.  
    66. int bX2 = b2 == null ? -1 : b2.getLocation().getBlockX();
    67. int bY2 = b2 == null ? -1 : b2.getLocation().getBlockY();
    68. int bZ2 = b2 == null ? -1 : b2.getLocation().getBlockZ();
    69.  
    70. if (b1 == null || x < bX1 && y < bY1 && z < bZ1) {
    71. b1 = block;
    72. } else if (b2 == null || x > bX2 && y > bY2 && z > bZ2) {
    73. b2 = block;
    74. }
    75. }
    76.  
    77. b1.setType(Material.WOOD);
    78. b2.setType(Material.WOOD);
    79. return new Block[] { b1, b2 };
    80. }
     
  2. Offline

    FabeGabeMC

    You could get the block y axis for the first and second position.
    or something like:
    Code:java
    1. Location p1, p2; // Pretend it exists.
    2. Location cornerBottom1XZ = new Location(p1.getBlockX(), p2.getBlockY(), p1.getBlockZ());
    3. // That will get the bottom corner corresponding to p1's X and Z axis.
    4. Location cornerBottom1X = new Location(p1.getBlockX(), p2.getBlockY(), p2.getBlockZ());
    5. // That will get the bottom corner corresponding to p1's X axis and p2's Z axis.
    6. // Do it for all of them, and then reversed.
    7. Location cornerTop2XZ = new Location(p2.getBlockX(), p1.getBlockY(), p2.getBlockZ());
     
  3. FabeGabeMC
    I don't think I quite get what you mean. What would the p1 and p2 locations be?

    I may have been a bit unclear in my first post, I was on a hurry. I'll try to update it later. But as I said earlier, I have a list of blocks that form a cube. Out of those blocks, I need to somehow find the two corner blocks so I can save them for further use. I tried finding the block with smallest x, y and z and same for biggest, however this returned only the bottom (same side) corners rather than the bottom and top opposite side corners as shown in the picture.
     
  4. Offline

    FabeGabeMC

    Assist
    p1 and p2 are both positions (startBlock and endBlock)
     
  5. FabeGabeMC
    startBlock and endBlock are the corners of the whole arena. I'm collecting bedrock blocks that are connected to each other from the whole arena into ArrayLists.

    Consider an arena within this stone brick foundation:
    Show Spoiler

    [​IMG]

    This arena contains two bedrock cubes which I both put into their own ArrayList<Block> using the code I provided above.
    Show Spoiler

    [​IMG]

    Now I need to find the opposite side, top and bottom corners, like in the picture provided in my first post.
    Show Spoiler

    [​IMG]


    I have already found one of the corners, so as a temporary solution, I could find the block that is furthest away from this corner to find the second corner.

    My goal with this is to not make the user manually define all of the cubes in the arena, as that would take a lot of time (the ideal map for this plugin should contain a lot of them).

    Thanks in advance.

    Edit: Temporary solution for anyone who might be interested. Seems to be working fine.
    Code:java
    1. private Block[] findCorners(ArrayList<Block> blocks) {
    2. Block b1 = null;
    3.  
    4. for (Block block: blocks) {
    5. int x = block.getLocation().getBlockX();
    6. int y = block.getLocation().getBlockY();
    7. int z = block.getLocation().getBlockZ();
    8.  
    9. int bX1 = b1 == null ? -1 : b1.getLocation().getBlockX();
    10. int bY1 = b1 == null ? -1 : b1.getLocation().getBlockY();
    11. int bZ1 = b1 == null ? -1 : b1.getLocation().getBlockZ();
    12.  
    13. if (b1 == null || x < bX1 && y < bY1 && z < bZ1) {
    14. b1 = block;
    15. }
    16. }
    17.  
    18. Block b2 = null;
    19.  
    20. for (Block block: blocks) {
    21. Location location = block.getLocation();
    22.  
    23. if (b2 == null || (b1.getLocation().distanceSquared(location) > b2.getLocation().distanceSquared(b1.getLocation()))) {
    24. b2 = block;
    25. }
    26. }
    27.  
    28. return new Block[] {
    29. b1, b2
    30. };
    31. }
     
  6. Offline

    Avygeil

    Assist I don't understand why this wouldn't work. That's basically what you describe in your first picture. Also, there are multiple opposite corners in a cuboid, you have to define more conditions : lowest and highest coordinates seems like the right way to do it.

    I haven't read your whole code, and I don't know how you store blocks in your List, but I can think of multiple ways to improve efficiency. For example, you could make a class that extends ArrayList and for every block added, check its coordinates, and store its index in a field if it has the highest/lowest coordinates. Then implement getLowerCorner() / getHigherCorner().

    Or even better : at the point where you add your blocks to the ArrayList, if you know the size of the cuboid AND have a way to loop through its contents in a linear way, then make a new class that only consists holds a Block[][][]. If you add your blocks in the right order, you can use blocks[0][0][0] and blocks[width-1][length-1][height-1] as your corners. If you don't want that array to store relative coordinates, you can always store the absolute origin of blocks[0][0][0] as another field to any origin later.
     
  7. Avygeil
    Thanks for the suggestions. Efficiency isn't that big of a deal in my opinion. This code will be executed only once, on the arena creation.

    I don't know the size. The groups of blocks are collected from the world, and every map can be different.
     
  8. Offline

    Avygeil

    Assist Yeah I just noticed the size of your bedrock cuboids in the picture above. In that case extending ArrayList sounds fine to me. :)
     
Thread Status:
Not open for further replies.

Share This Page