From 8c0d0f9ed48d7a4f1289912f32713428029c0375 Mon Sep 17 00:00:00 2001 From: TomyLobo Date: Fri, 2 Sep 2011 21:38:38 +0200 Subject: [PATCH] //[h]sphere can now generate ellipsoid (stretched sphere) shapes --- .../java/com/sk89q/worldedit/EditSession.java | 67 ++++++++++++------ .../commands/GenerationCommands.java | 70 ++++++++++++++----- .../tools/brushes/HollowSphereBrush.java | 2 +- .../worldedit/tools/brushes/SphereBrush.java | 2 +- 4 files changed, 99 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/sk89q/worldedit/EditSession.java b/src/main/java/com/sk89q/worldedit/EditSession.java index 9fd43d5f9..5b485609c 100644 --- a/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1920,37 +1920,60 @@ public class EditSession { } /** - * Makes a sphere. + * Makes a sphere or ellipsoid. * - * @param pos - * @param block - * @param radius - * @param filled + * @param pos Center of the sphere or ellipsoid + * @param block The block pattern to use + * @param radiusX The sphere/ellipsoid's largest north/south extent + * @param radiusY The sphere/ellipsoid's largest up/down extent + * @param radiusZ The sphere/ellipsoid's largest east/west extent + * @param filled If false, only a shell will be generated. * @return number of blocks changed * @throws MaxChangedBlocksException */ - public int makeSphere(Vector pos, Pattern block, double radius, - boolean filled) throws MaxChangedBlocksException { + public int makeSphere(Vector pos, Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled) throws MaxChangedBlocksException { int affected = 0; - radius += 0.5; - final double radiusSq = radius*radius; - final double radius1Sq = (radius - 1)*(radius - 1); + radiusX += 0.5; + radiusY += 0.5; + radiusZ += 0.5; - final int ceilRadius = (int) Math.ceil(radius); - for (int x = 0; x <= ceilRadius; ++x) { - for (int y = 0; y <= ceilRadius; ++y) { - for (int z = 0; z <= ceilRadius; ++z) { - double dSq = lengthSq(x, y, z); + final double invRadiusX = 1 / radiusX; + final double invRadiusY = 1 / radiusY; + final double invRadiusZ = 1 / radiusZ; - if (dSq > radiusSq) - continue; + final int ceilRadiusX = (int) Math.ceil(radiusX); + final int ceilRadiusY = (int) Math.ceil(radiusY); + final int ceilRadiusZ = (int) Math.ceil(radiusZ); + + double nextXn = 0; + forX: + for (int x = 0; x <= ceilRadiusX; ++x) { + final double xn = nextXn; + nextXn = (x+1)*invRadiusX; + double nextYn = 0; + forY: + for (int y = 0; y <= ceilRadiusY; ++y) { + final double yn = nextYn; + nextYn = (y+1)*invRadiusY; + double nextZn = 0; + forZ: + for (int z = 0; z <= ceilRadiusZ; ++z) { + final double zn = nextZn; + nextZn = (z+1)*invRadiusZ; + + double distanceSq = lengthSq(xn, yn, zn); + if (distanceSq > 1) { + if (z == 0) { + if (y == 0) + break forX; + break forY; + } + break forZ; + } if (!filled) { - if (dSq < radius1Sq) - continue; - - if (lengthSq(x+1, y, z) <= radiusSq && lengthSq(x, y+1, z) <= radiusSq && lengthSq(x, y, z+1) <= radiusSq) + if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) continue; } @@ -1985,7 +2008,7 @@ public class EditSession { return affected; } - private static final double lengthSq(int x, int y, int z) { + private static final double lengthSq(double x, double y, double z) { return x*x + y*y + z*z; } diff --git a/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java b/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java index 2049e4053..94ce3d220 100644 --- a/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java +++ b/src/main/java/com/sk89q/worldedit/commands/GenerationCommands.java @@ -80,8 +80,8 @@ public class GenerationCommands { @Command( aliases = {"/hsphere"}, - usage = " [raised?] ", - desc = "Generate a hollow sphere", + usage = " [,,] [raised?] ", + desc = "Generate a hollow sphere. If you specify 3 radiuses separated by commas, an ellipsoid with the dimensions x,y,z will be generated.", min = 2, max = 3 ) @@ -91,19 +91,36 @@ public class GenerationCommands { LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - Pattern block = we.getBlockPattern(player, args.getString(0)); - double radius = Math.max(1, args.getDouble(1)); - boolean raised = args.argsLength() > 2 - ? (args.getString(2).equalsIgnoreCase("true") - || args.getString(2).equalsIgnoreCase("yes")) - : false; + final Pattern block = we.getBlockPattern(player, args.getString(0)); + String[] radiuses = args.getString(1).split(","); + final double radiusX, radiusY, radiusZ; + switch (radiuses.length) { + case 1: + radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); + break; + + case 3: + radiusX = Math.max(1, Double.parseDouble(radiuses[0])); + radiusY = Math.max(1, Double.parseDouble(radiuses[1])); + radiusZ = Math.max(1, Double.parseDouble(radiuses[2])); + break; + + default: + player.printError("You must either specify 1 or 3 radius values."); + return; + } + final boolean raised; + if (args.argsLength() > 2) + raised = args.getString(2).equalsIgnoreCase("true") || args.getString(2).equalsIgnoreCase("yes"); + else + raised = false; Vector pos = session.getPlacementPosition(player); if (raised) { - pos = pos.add(0, radius, 0); + pos = pos.add(0, radiusY, 0); } - int affected = editSession.makeSphere(pos, block, radius, false); + int affected = editSession.makeSphere(pos, block, radiusX, radiusY, radiusZ, false); player.findFreePosition(); player.print(affected + " block(s) have been created."); } @@ -111,7 +128,7 @@ public class GenerationCommands { @Command( aliases = {"/sphere"}, usage = " [raised?] ", - desc = "Generate a filled sphere", + desc = "Generate a filled sphere. If you specify 3 radiuses separated by commas, an ellipsoid with the dimensions x,y,z will be generated.", min = 2, max = 3 ) @@ -122,18 +139,35 @@ public class GenerationCommands { throws WorldEditException { Pattern block = we.getBlockPattern(player, args.getString(0)); - double radius = Math.max(1, args.getDouble(1)); - boolean raised = args.argsLength() > 2 - ? (args.getString(2).equalsIgnoreCase("true") - || args.getString(2).equalsIgnoreCase("yes")) - : false; + String[] radiuses = args.getString(1).split(","); + final double radiusX, radiusY, radiusZ; + switch (radiuses.length) { + case 1: + radiusX = radiusY = radiusZ = Math.max(1, Double.parseDouble(radiuses[0])); + break; + + case 3: + radiusX = Math.max(1, Double.parseDouble(radiuses[0])); + radiusY = Math.max(1, Double.parseDouble(radiuses[1])); + radiusZ = Math.max(1, Double.parseDouble(radiuses[2])); + break; + + default: + player.printError("You must either specify 1 or 3 radius values."); + return; + } + final boolean raised; + if (args.argsLength() > 2) + raised = args.getString(2).equalsIgnoreCase("true") || args.getString(2).equalsIgnoreCase("yes"); + else + raised = false; Vector pos = session.getPlacementPosition(player); if (raised) { - pos = pos.add(0, radius, 0); + pos = pos.add(0, radiusY, 0); } - int affected = editSession.makeSphere(pos, block, radius, true); + int affected = editSession.makeSphere(pos, block, radiusX, radiusY, radiusZ, true); player.findFreePosition(); player.print(affected + " block(s) have been created."); } diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/HollowSphereBrush.java b/src/main/java/com/sk89q/worldedit/tools/brushes/HollowSphereBrush.java index e31f28b70..3c83da1ba 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/HollowSphereBrush.java +++ b/src/main/java/com/sk89q/worldedit/tools/brushes/HollowSphereBrush.java @@ -30,6 +30,6 @@ public class HollowSphereBrush implements Brush { public void build(EditSession editSession, Vector pos, Pattern mat, double size) throws MaxChangedBlocksException { - editSession.makeSphere(pos, mat, size, false); + editSession.makeSphere(pos, mat, size, size, size, false); } } diff --git a/src/main/java/com/sk89q/worldedit/tools/brushes/SphereBrush.java b/src/main/java/com/sk89q/worldedit/tools/brushes/SphereBrush.java index f02088722..4ef2582d2 100644 --- a/src/main/java/com/sk89q/worldedit/tools/brushes/SphereBrush.java +++ b/src/main/java/com/sk89q/worldedit/tools/brushes/SphereBrush.java @@ -30,6 +30,6 @@ public class SphereBrush implements Brush { public void build(EditSession editSession, Vector pos, Pattern mat, double size) throws MaxChangedBlocksException { - editSession.makeSphere(pos, mat, size, true); + editSession.makeSphere(pos, mat, size, size, size, true); } }