From 97529abacae4764e853f150de3bc3ae0a2cd4f6f Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 19 Feb 2011 17:44:39 -0800 Subject: [PATCH] Added polygonal regions. --- plugin.yml | 13 +- src/com/sk89q/worldedit/LocalSession.java | 134 ++--- src/com/sk89q/worldedit/Vector2D.java | 9 + src/com/sk89q/worldedit/WorldEdit.java | 27 +- .../worldedit/bukkit/WorldEditPlugin.java | 3 +- .../worldedit/commands/ChunkCommands.java | 4 +- .../worldedit/commands/ClipboardCommands.java | 6 +- .../worldedit/commands/RegionCommands.java | 20 +- .../worldedit/commands/SelectionCommands.java | 222 +++++--- .../commands/SnapshotUtilCommands.java | 2 +- .../sk89q/worldedit/regions/CuboidRegion.java | 27 +- .../regions/CuboidRegionSelector.java | 122 ++++ .../worldedit/regions/Polygonal2DRegion.java | 527 ++++++++++++++++++ .../regions/Polygonal2DRegionSelector.java | 114 ++++ src/com/sk89q/worldedit/regions/Region.java | 20 +- .../regions/RegionOperationException.java | 30 + .../worldedit/regions/RegionSelector.java | 112 ++++ 17 files changed, 1184 insertions(+), 208 deletions(-) create mode 100644 src/com/sk89q/worldedit/regions/CuboidRegionSelector.java create mode 100644 src/com/sk89q/worldedit/regions/Polygonal2DRegion.java create mode 100644 src/com/sk89q/worldedit/regions/Polygonal2DRegionSelector.java create mode 100644 src/com/sk89q/worldedit/regions/RegionOperationException.java create mode 100644 src/com/sk89q/worldedit/regions/RegionSelector.java diff --git a/plugin.yml b/plugin.yml index b9976fe52..aff4f2261 100644 --- a/plugin.yml +++ b/plugin.yml @@ -178,15 +178,20 @@ commands: //count: description: Counts the number of a certain type of block usage: / - /size: + /m: description: Get information about the selection usage: / + aliases: ['//size'] /shift: description: Shift the selection area usage: / [direction] /expand: description: Expand the selection area usage: / [reverse-amount] + /sel: + description: Choose a region selector + usage: / [type] + aliases: [','] /inset: description: Inset the selection area usage: / [-hv] @@ -299,6 +304,10 @@ commands: /drain: description: Drain a pool usage: / - /version: + version: description: Get WorldEdit version usage: / + aliases: ['ver'] + reload: + description: Reload WorldEdit + usage: / diff --git a/src/com/sk89q/worldedit/LocalSession.java b/src/com/sk89q/worldedit/LocalSession.java index 9282e5326..c3821317b 100644 --- a/src/com/sk89q/worldedit/LocalSession.java +++ b/src/com/sk89q/worldedit/LocalSession.java @@ -28,8 +28,9 @@ import com.sk89q.worldedit.tools.SinglePickaxe; import com.sk89q.worldedit.tools.BlockTool; import com.sk89q.worldedit.tools.Tool; import com.sk89q.worldedit.bags.BlockBag; +import com.sk89q.worldedit.regions.CuboidRegionSelector; import com.sk89q.worldedit.regions.Region; -import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.RegionSelector; /** * An instance of this represents the WorldEdit session of a user. A session @@ -51,9 +52,9 @@ public class LocalSession { private LocalConfiguration config; + private LocalWorld selectionWorld; + private RegionSelector regionSelector = new CuboidRegionSelector(); private boolean placeAtPos1 = false; - private Vector pos1, pos2; - private Region region; private LinkedList history = new LinkedList(); private int historyPointer = 0; private CuboidClipboard clipboard; @@ -147,25 +148,41 @@ public class LocalSession { } /** - * Checks to make sure that position 1 is defined. + * Get the region selector for defining the selection. If the selection + * was defined for a different world, the old selection will be discarded. * - * @throws IncompleteRegionException + * @param world + * @return position */ - private void checkPos1() throws IncompleteRegionException { - if (pos1 == null) { - throw new IncompleteRegionException(); + public RegionSelector getRegionSelector(LocalWorld world) { + if (selectionWorld == null) { + selectionWorld = world; + } else if (!selectionWorld.equals(world)) { + selectionWorld = world; + regionSelector.clear(); } + return regionSelector; } /** - * Checks to make sure that position 2 is defined. - * - * @throws IncompleteRegionException + * Get the region selector. This won't check worlds so make sure that + * this region selector isn't used blindly. + * + * @return position */ - private void checkPos2() throws IncompleteRegionException { - if (pos2 == null) { - throw new IncompleteRegionException(); - } + public RegionSelector getRegionSelector() { + return regionSelector; + } + + /** + * Set the region selector. + * + * @param world + * @param selector + */ + public void setRegionSelector(LocalWorld world, RegionSelector selector) { + selectionWorld = world; + regionSelector = selector; } /** @@ -173,80 +190,50 @@ public class LocalSession { * * @return */ + @Deprecated public boolean isRegionDefined() { - return pos1 != null && pos2 != null; + return regionSelector.isDefined(); } /** - * Gets defined position 1. + * Returns true if the region is fully defined for the specified world. * - * @return position 1 - * @throws IncompleteRegionException + * @param world + * @return */ - public Vector getPos1() throws IncompleteRegionException { - checkPos1(); - return pos1; - } - - /** - * Sets position 1. - * - * @param pt - */ - public void setPos1(Vector pt) { - pos1 = pt; - if (pos1 != null && pos2 != null) { - region = new CuboidRegion(pos1, pos2); + public boolean isSelectionDefined(LocalWorld world) { + if (selectionWorld == null || !selectionWorld.equals(world)) { + return false; } + return regionSelector.isDefined(); } /** - * Gets position 2. - * - * @return position 2 - * @throws IncompleteRegionException - */ - public Vector getPos2() throws IncompleteRegionException { - checkPos2(); - return pos2; - } - - /** - * Sets position 2. - * - * @param pt - */ - public void setPos2(Vector pt) { - pos2 = pt; - if (pos1 != null && pos2 != null) { - region = new CuboidRegion(pos1, pos2); - } - } - - /** - * Update session position 1/2 based on the currently set region, - * provided that the region is of a cuboid. - */ - public void learnRegionChanges() { - if (region instanceof CuboidRegion) { - CuboidRegion cuboidRegion = (CuboidRegion)region; - pos1 = cuboidRegion.getPos1(); - pos2 = cuboidRegion.getPos2(); - } - } - - /** - * Get the region. If you change the region, you should - * call learnRegionChanges(). + * Use getSelection(). * * @return region * @throws IncompleteRegionException */ + @Deprecated public Region getRegion() throws IncompleteRegionException { - if (region == null) { + return regionSelector.getRegion(); + } + + /** + * Get the selection region. If you change the region, you should + * call learnRegionChanges(). If the selection is defined in + * a different world, the IncompleteRegionException + * exception will be thrown. + * + * @param world + * @return region + * @throws IncompleteRegionException + */ + public Region getSelection(LocalWorld world) throws IncompleteRegionException { + if (selectionWorld == null || !selectionWorld.equals(world)) { throw new IncompleteRegionException(); } - return region; + return regionSelector.getRegion(); } /** @@ -353,8 +340,7 @@ public class LocalSession { return player.getBlockIn(); } - checkPos1(); - return pos1; + return regionSelector.getPrimaryPosition(); } /** diff --git a/src/com/sk89q/worldedit/Vector2D.java b/src/com/sk89q/worldedit/Vector2D.java index 15893488f..b9e343a08 100644 --- a/src/com/sk89q/worldedit/Vector2D.java +++ b/src/com/sk89q/worldedit/Vector2D.java @@ -145,6 +145,15 @@ public class Vector2D { return new Vector2D(x, z); } + /** + * Gets a BlockVector version. + * + * @return BlockVector + */ + public BlockVector2D toBlockVector2D() { + return new BlockVector2D(this); + } + /** * Checks if another object is equivalent. * diff --git a/src/com/sk89q/worldedit/WorldEdit.java b/src/com/sk89q/worldedit/WorldEdit.java index ad8662cbb..711677681 100644 --- a/src/com/sk89q/worldedit/WorldEdit.java +++ b/src/com/sk89q/worldedit/WorldEdit.java @@ -35,6 +35,7 @@ import com.sk89q.worldedit.LocalSession.CompassMode; import com.sk89q.worldedit.bags.BlockBag; import com.sk89q.worldedit.blocks.*; import com.sk89q.worldedit.commands.*; +import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.scripting.*; import com.sk89q.worldedit.tools.BlockTool; import com.sk89q.worldedit.tools.Tool; @@ -782,13 +783,9 @@ public class WorldEdit { if (itemInHand == config.wandItem && session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) { - session.setPos2(clicked); - - try { - player.print("Second position set to " + clicked - + " (" + session.getRegion().getSize() + ")."); - } catch (IncompleteRegionException e) { - player.print("Second position set to " + clicked + "."); + RegionSelector selector = session.getRegionSelector(player.getWorld()); + if (selector.selectSecondary(clicked)) { + selector.explainSecondarySelection(player, clicked); } return true; @@ -823,19 +820,9 @@ public class WorldEdit { return false; } - try { - if (session.getPos1().equals(clicked)) { - return false; - } - } catch (IncompleteRegionException e) { - } - - session.setPos1(clicked); - try { - player.print("First position set to " + clicked - + " (" + session.getRegion().getSize() + ")."); - } catch (IncompleteRegionException e) { - player.print("First position set to " + clicked + "."); + RegionSelector selector = session.getRegionSelector(player.getWorld()); + if (selector.selectPrimary(clicked)) { + selector.explainPrimarySelection(player, clicked); } return true; diff --git a/src/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/src/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 4ffbe9583..bf0398812 100644 --- a/src/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/src/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -208,7 +208,8 @@ public class WorldEditPlugin extends JavaPlugin { */ public Region getPlayerSelection(Player player) throws IncompleteRegionException { - return controller.getSession(wrapPlayer(player)).getRegion(); + return controller.getSession(wrapPlayer(player)) + .getSelection(new BukkitWorld(player.getWorld())); } /** diff --git a/src/com/sk89q/worldedit/commands/ChunkCommands.java b/src/com/sk89q/worldedit/commands/ChunkCommands.java index 8be0e8d6d..8354850a1 100644 --- a/src/com/sk89q/worldedit/commands/ChunkCommands.java +++ b/src/com/sk89q/worldedit/commands/ChunkCommands.java @@ -70,7 +70,7 @@ public class ChunkCommands { LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - Set chunks = session.getRegion().getChunks(); + Set chunks = session.getSelection(player.getWorld()).getChunks(); for (Vector2D chunk : chunks) { player.print(NestedFileChunkStore.getFilename(chunk)); @@ -91,7 +91,7 @@ public class ChunkCommands { LocalConfiguration config = we.getConfiguration(); - Set chunks = session.getRegion().getChunks(); + Set chunks = session.getSelection(player.getWorld()).getChunks(); FileOutputStream out = null; if (config.shellSaveType == null) { diff --git a/src/com/sk89q/worldedit/commands/ClipboardCommands.java b/src/com/sk89q/worldedit/commands/ClipboardCommands.java index aab62f2da..bb5bade85 100644 --- a/src/com/sk89q/worldedit/commands/ClipboardCommands.java +++ b/src/com/sk89q/worldedit/commands/ClipboardCommands.java @@ -47,7 +47,7 @@ public class ClipboardCommands { LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - Region region = session.getRegion(); + Region region = session.getSelection(player.getWorld()); Vector min = region.getMinimumPoint(); Vector max = region.getMaximumPoint(); Vector pos = player.getBlockIn(); @@ -79,7 +79,7 @@ public class ClipboardCommands { block = we.getBlock(player, args.getString(0)); } - Region region = session.getRegion(); + Region region = session.getSelection(player.getWorld()); Vector min = region.getMinimumPoint(); Vector max = region.getMaximumPoint(); Vector pos = player.getBlockIn(); @@ -90,7 +90,7 @@ public class ClipboardCommands { clipboard.copy(editSession); session.setClipboard(clipboard); - editSession.setBlocks(session.getRegion(), block); + editSession.setBlocks(session.getSelection(player.getWorld()), block); player.print("Block(s) cut."); } diff --git a/src/com/sk89q/worldedit/commands/RegionCommands.java b/src/com/sk89q/worldedit/commands/RegionCommands.java index 089179f1c..646d06a2b 100644 --- a/src/com/sk89q/worldedit/commands/RegionCommands.java +++ b/src/com/sk89q/worldedit/commands/RegionCommands.java @@ -53,10 +53,10 @@ public class RegionCommands { int affected; if (pattern instanceof SingleBlockPattern) { - affected = editSession.setBlocks(session.getRegion(), + affected = editSession.setBlocks(session.getSelection(player.getWorld()), ((SingleBlockPattern)pattern).getBlock()); } else { - affected = editSession.setBlocks(session.getRegion(), pattern); + affected = editSession.setBlocks(session.getSelection(player.getWorld()), pattern); } player.print(affected + " block(s) have been changed."); @@ -86,10 +86,10 @@ public class RegionCommands { int affected = 0; if (to instanceof SingleBlockPattern) { - affected = editSession.replaceBlocks(session.getRegion(), from, + affected = editSession.replaceBlocks(session.getSelection(player.getWorld()), from, ((SingleBlockPattern)to).getBlock()); } else { - affected = editSession.replaceBlocks(session.getRegion(), from, to); + affected = editSession.replaceBlocks(session.getSelection(player.getWorld()), from, to); } player.print(affected + " block(s) have been replaced."); @@ -109,7 +109,7 @@ public class RegionCommands { Pattern pat = we.getBlockPattern(player, args.getString(0)); - Region region = session.getRegion(); + Region region = session.getSelection(player.getWorld()); int affected = 0; if (pat instanceof SingleBlockPattern) { affected = editSession.overlayCuboidBlocks(region, @@ -133,7 +133,7 @@ public class RegionCommands { throws WorldEditException { BaseBlock block = we.getBlock(player, args.getString(0)); - int affected = editSession.makeCuboidWalls(session.getRegion(), block); + int affected = editSession.makeCuboidWalls(session.getSelection(player.getWorld()), block); player.print(affected + " block(s) have been changed."); } @@ -151,7 +151,7 @@ public class RegionCommands { throws WorldEditException { BaseBlock block = we.getBlock(player, args.getString(0)); - int affected = editSession.makeCuboidFaces(session.getRegion(), block); + int affected = editSession.makeCuboidFaces(session.getSelection(player.getWorld()), block); player.print(affected + " block(s) have been changed."); } @@ -172,7 +172,7 @@ public class RegionCommands { iterations = args.getInteger(0); } - HeightMap heightMap = new HeightMap(editSession, session.getRegion()); + HeightMap heightMap = new HeightMap(editSession, session.getSelection(player.getWorld())); HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); int affected = heightMap.applyFilter(filter, iterations); player.print("Terrain's height map smoothed. " + affected + " block(s) changed."); @@ -203,7 +203,7 @@ public class RegionCommands { replace = new BaseBlock(0); } - int affected = editSession.moveCuboidRegion(session.getRegion(), + int affected = editSession.moveCuboidRegion(session.getSelection(player.getWorld()), dir, count, true, replace); player.print(affected + " blocks moved."); } @@ -226,7 +226,7 @@ public class RegionCommands { Vector dir = we.getDirection(player, args.argsLength() > 1 ? args.getString(1).toLowerCase() : "me"); - int affected = editSession.stackCuboidRegion(session.getRegion(), + int affected = editSession.stackCuboidRegion(session.getSelection(player.getWorld()), dir, count, !args.hasFlag('a')); player.print(affected + " blocks changed. Undo with //undo"); } diff --git a/src/com/sk89q/worldedit/commands/SelectionCommands.java b/src/com/sk89q/worldedit/commands/SelectionCommands.java index e7eb479b4..c52a98907 100644 --- a/src/com/sk89q/worldedit/commands/SelectionCommands.java +++ b/src/com/sk89q/worldedit/commands/SelectionCommands.java @@ -27,7 +27,10 @@ import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.worldedit.*; import com.sk89q.worldedit.data.ChunkStore; +import com.sk89q.worldedit.regions.CuboidRegionSelector; +import com.sk89q.worldedit.regions.Polygonal2DRegionSelector; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.blocks.*; /** @@ -48,14 +51,14 @@ public class SelectionCommands { LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - session.setPos1(player.getBlockIn()); - - if (session.isRegionDefined()) { - player.print("First position set to " + player.getBlockIn() - + " (" + session.getRegion().getSize() + ")."); - } else { - player.print("First position set to " + player.getBlockIn() + "."); + if (!session.getRegionSelector(player.getWorld()) + .selectPrimary(player.getBlockIn())) { + player.printError("Position already set."); + return; } + + session.getRegionSelector(player.getWorld()) + .explainPrimarySelection(player, player.getBlockIn()); } @Command( @@ -69,15 +72,16 @@ public class SelectionCommands { public static void pos2(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - - session.setPos2(player.getBlockIn()); - - if (session.isRegionDefined()) { - player.print("Second position set to " + player.getBlockIn() - + " (" + session.getRegion().getSize() + ")."); - } else { - player.print("Second position set to " + player.getBlockIn() + "."); + + if (!session.getRegionSelector(player.getWorld()) + .selectSecondary(player.getBlockIn())) { + player.printError("Position already set."); + return; } + + + session.getRegionSelector(player.getWorld()) + .explainSecondarySelection(player, player.getBlockIn()); } @Command( @@ -95,13 +99,14 @@ public class SelectionCommands { Vector pos = player.getBlockTrace(300); if (pos != null) { - session.setPos1(pos); - if (session.isRegionDefined()) { - player.print("First position set to " + pos - + " (" + session.getRegion().getSize() + ")."); - } else { - player.print("First position set to " + pos.toString() + " ."); + if (!session.getRegionSelector(player.getWorld()) + .selectPrimary(pos)) { + player.printError("Position already set."); + return; } + + session.getRegionSelector(player.getWorld()) + .explainPrimarySelection(player, pos); } else { player.printError("No block in sight!"); } @@ -122,14 +127,14 @@ public class SelectionCommands { Vector pos = player.getBlockTrace(300); if (pos != null) { - session.setPos2(pos); - - if (session.isRegionDefined()) { - player.print("Second position set to " + pos - + " (" + session.getRegion().getSize() + ")."); - } else { - player.print("Second position set to " + pos.toString() + " ."); + if (!session.getRegionSelector(player.getWorld()) + .selectSecondary(pos)) { + player.printError("Position already set."); + return; } + + session.getRegionSelector(player.getWorld()) + .explainSecondarySelection(player, pos); } else { player.printError("No block in sight!"); } @@ -151,8 +156,10 @@ public class SelectionCommands { Vector min = new Vector(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); Vector max = min.add(15, 127, 15); - session.setPos1(min); - session.setPos2(max); + CuboidRegionSelector selector = new CuboidRegionSelector(); + selector.selectPrimary(min); + selector.selectSecondary(max); + session.setRegionSelector(player.getWorld(), selector); player.print("Chunk selected: " + min2D.getBlockX() + ", " + min2D.getBlockZ()); @@ -213,14 +220,18 @@ public class SelectionCommands { // sky and bedrock. if (args.getString(0).equalsIgnoreCase("vert") || args.getString(0).equalsIgnoreCase("vertical")) { - Region region = session.getRegion(); - int oldSize = region.getSize(); - region.expand(new Vector(0, 128, 0)); - region.expand(new Vector(0, -128, 0)); - session.learnRegionChanges(); - int newSize = region.getSize(); - player.print("Region expanded " + (newSize - oldSize) - + " blocks [top-to-bottom]."); + Region region = session.getSelection(player.getWorld()); + try { + int oldSize = region.getArea(); + region.expand(new Vector(0, 128, 0)); + region.expand(new Vector(0, -128, 0)); + session.getRegionSelector().learnChanges(); + int newSize = region.getArea(); + player.print("Region expanded " + (newSize - oldSize) + + " blocks [top-to-bottom]."); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); + } return; } @@ -246,16 +257,16 @@ public class SelectionCommands { dir = we.getDirection(player, "me"); } - Region region = session.getRegion(); - int oldSize = region.getSize(); + Region region = session.getSelection(player.getWorld()); + int oldSize = region.getArea(); region.expand(dir.multiply(change)); if (reverseChange != 0) { region.expand(dir.multiply(reverseChange)); } - - session.learnRegionChanges(); - int newSize = region.getSize(); + + session.getRegionSelector().learnChanges(); + int newSize = region.getArea(); player.print("Region expanded " + (newSize - oldSize) + " blocks."); } @@ -294,16 +305,20 @@ public class SelectionCommands { dir = we.getDirection(player, "me"); } - Region region = session.getRegion(); - int oldSize = region.getSize(); - region.contract(dir.multiply(change)); - if (reverseChange != 0) { - region.contract(dir.multiply(reverseChange)); + try { + Region region = session.getSelection(player.getWorld()); + int oldSize = region.getArea(); + region.contract(dir.multiply(change)); + if (reverseChange != 0) { + region.contract(dir.multiply(reverseChange)); + } + session.getRegionSelector().learnChanges(); + int newSize = region.getArea(); + + player.print("Region contracted " + (oldSize - newSize) + " blocks."); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); } - session.learnRegionChanges(); - int newSize = region.getSize(); - - player.print("Region contracted " + (oldSize - newSize) + " blocks."); } @Command( @@ -327,12 +342,16 @@ public class SelectionCommands { dir = we.getDirection(player, "me"); } - Region region = session.getRegion(); - region.expand(dir.multiply(change)); - region.contract(dir.multiply(change)); - session.learnRegionChanges(); - - player.print("Region shifted."); + try { + Region region = session.getSelection(player.getWorld()); + region.expand(dir.multiply(change)); + region.contract(dir.multiply(change)); + session.getRegionSelector().learnChanges(); + + player.print("Region shifted."); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); + } } @Command( @@ -349,23 +368,27 @@ public class SelectionCommands { throws WorldEditException { int change = args.getInteger(0); - Region region = session.getRegion(); + Region region = session.getSelection(player.getWorld()); - if (!args.hasFlag('h')) { - region.expand((new Vector(0, 1, 0)).multiply(change)); - region.expand((new Vector(0, -1, 0)).multiply(change)); + try { + if (!args.hasFlag('h')) { + region.expand((new Vector(0, 1, 0)).multiply(change)); + region.expand((new Vector(0, -1, 0)).multiply(change)); + } + + if (!args.hasFlag('v')) { + region.expand((new Vector(1, 0, 0)).multiply(change)); + region.expand((new Vector(-1, 0, 0)).multiply(change)); + region.expand((new Vector(0, 0, 1)).multiply(change)); + region.expand((new Vector(0, 0, -1)).multiply(change)); + } + + session.getRegionSelector().learnChanges(); + + player.print("Region outset."); + } catch (RegionOperationException e) { + player.printError(e.getMessage()); } - - if (!args.hasFlag('v')) { - region.expand((new Vector(1, 0, 0)).multiply(change)); - region.expand((new Vector(-1, 0, 0)).multiply(change)); - region.expand((new Vector(0, 0, 1)).multiply(change)); - region.expand((new Vector(0, 0, -1)).multiply(change)); - } - - session.learnRegionChanges(); - - player.print("Region outset."); } @Command( @@ -382,7 +405,7 @@ public class SelectionCommands { throws WorldEditException { int change = args.getInteger(0); - Region region = session.getRegion(); + Region region = session.getSelection(player.getWorld()); if (!args.hasFlag('h')) { region.contract((new Vector(0, 1, 0)).multiply(change)); @@ -395,14 +418,14 @@ public class SelectionCommands { region.contract((new Vector(0, 0, 1)).multiply(change)); region.contract((new Vector(0, 0, -1)).multiply(change)); } - - session.learnRegionChanges(); + + session.getRegionSelector().learnChanges(); player.print("Region inset."); } @Command( - aliases = {"/size"}, + aliases = {"/m", "//size"}, usage = "", desc = "Get information about the selection", min = 0, @@ -412,17 +435,21 @@ public class SelectionCommands { public static void size(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) throws WorldEditException { - - Region region = session.getRegion(); + + Region region = session.getSelection(player.getWorld()); Vector size = region.getMaximumPoint() .subtract(region.getMinimumPoint()) .add(1, 1, 1); + + player.print("Type: " + session.getRegionSelector().getTypeName()); + + for (String line : session.getRegionSelector().getInformationLines()) { + player.print(line); + } - player.print("First position: " + session.getPos1()); - player.print("Second position: " + session.getPos2()); player.print("Size: " + size); - player.print("Distance: " + region.getMaximumPoint().distance(region.getMinimumPoint())); - player.print("# of blocks: " + region.getSize()); + player.print("Cuboid distance: " + region.getMaximumPoint().distance(region.getMinimumPoint())); + player.print("# of blocks: " + region.getArea()); } @Command( @@ -440,7 +467,7 @@ public class SelectionCommands { Set searchIDs = we.getBlockIDs(player, args.getString(0), true); player.print("Counted: " + - editSession.countBlocks(session.getRegion(), searchIDs)); + editSession.countBlocks(session.getSelection(player.getWorld()), searchIDs)); } @Command( @@ -457,12 +484,12 @@ public class SelectionCommands { throws WorldEditException { List> distribution = - editSession.getBlockDistribution(session.getRegion()); + editSession.getBlockDistribution(session.getSelection(player.getWorld())); Logger logger = Logger.getLogger("Minecraft.WorldEdit"); if (distribution.size() > 0) { // *Should* always be true - int size = session.getRegion().getSize(); + int size = session.getSelection(player.getWorld()).getArea(); player.print("# total blocks: " + size); @@ -486,4 +513,27 @@ public class SelectionCommands { player.printError("No blocks counted."); } } + + @Command( + aliases = {"/sel", ","}, + usage = "[type]", + desc = "Choose a region selector", + min = 1, + max = 1 + ) + public static void select(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + String typeName = args.getString(0); + if (typeName.equalsIgnoreCase("cuboid")) { + session.setRegionSelector(player.getWorld(), new CuboidRegionSelector()); + player.print("Cuboid: left click for point 1, right click for point 2"); + } else if (typeName.equalsIgnoreCase("poly")) { + session.setRegionSelector(player.getWorld(), new Polygonal2DRegionSelector()); + player.print("2D polygon selector: Left/right click to add a point."); + } else { + player.printError("Only 'cuboid' and 'poly' are accepted."); + } + } } diff --git a/src/com/sk89q/worldedit/commands/SnapshotUtilCommands.java b/src/com/sk89q/worldedit/commands/SnapshotUtilCommands.java index 1dce23e39..f7178bf4a 100644 --- a/src/com/sk89q/worldedit/commands/SnapshotUtilCommands.java +++ b/src/com/sk89q/worldedit/commands/SnapshotUtilCommands.java @@ -71,7 +71,7 @@ public class SnapshotUtilCommands { return; } - Region region = session.getRegion(); + Region region = session.getSelection(player.getWorld()); Snapshot snapshot; if (args.argsLength() > 0) { diff --git a/src/com/sk89q/worldedit/regions/CuboidRegion.java b/src/com/sk89q/worldedit/regions/CuboidRegion.java index 3bea3012b..6445dfbaa 100644 --- a/src/com/sk89q/worldedit/regions/CuboidRegion.java +++ b/src/com/sk89q/worldedit/regions/CuboidRegion.java @@ -19,6 +19,7 @@ package com.sk89q.worldedit.regions; +import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.data.ChunkStore; @@ -28,7 +29,7 @@ import java.util.HashSet; /** * - * @author Albert + * @author sk89q */ public class CuboidRegion implements Region { /** @@ -80,7 +81,7 @@ public class CuboidRegion implements Region { * * @return number of blocks */ - public int getSize() { + public int getArea() { Vector min = getMinimumPoint(); Vector max = getMaximumPoint(); @@ -288,12 +289,30 @@ public class CuboidRegion implements Region { return chunks; } + /** + * Returns true based on whether the region contains the point, + * + * @param pt + */ + public boolean contains(Vector pt) { + double x = pt.getX(); + double y = pt.getY(); + double z = pt.getZ(); + + Vector min = getMinimumPoint(); + Vector max = getMaximumPoint(); + + return x >= min.getBlockX() && x <= max.getBlockX() + && y >= min.getBlockY() && y <= max.getBlockY() + && z >= min.getBlockZ() && z <= max.getBlockZ(); + } + /** * Get the iterator. * - * @return iterator of Points + * @return iterator of points inside the region */ - public Iterator iterator() { + public Iterator iterator() { throw new UnsupportedOperationException("Not implemented"); } } diff --git a/src/com/sk89q/worldedit/regions/CuboidRegionSelector.java b/src/com/sk89q/worldedit/regions/CuboidRegionSelector.java new file mode 100644 index 000000000..85203b91f --- /dev/null +++ b/src/com/sk89q/worldedit/regions/CuboidRegionSelector.java @@ -0,0 +1,122 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.regions; + +import java.util.ArrayList; +import java.util.List; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.Vector; + +/** + * Selector for cuboids. + * + * @author sk89q + */ +public class CuboidRegionSelector implements RegionSelector { + protected BlockVector pos1; + protected BlockVector pos2; + protected CuboidRegion region = new CuboidRegion(new Vector(), new Vector()); + + public boolean selectPrimary(Vector pos) { + if (pos1 != null && pos1.equals(pos)) { + return false; + } + pos1 = pos.toBlockVector(); + region.setPos1(pos1); + return true; + } + + public boolean selectSecondary(Vector pos) { + if (pos2 != null && pos2.equals(pos)) { + return false; + } + pos2 = pos.toBlockVector(); + region.setPos2(pos2); + return true; + } + + public void explainPrimarySelection(LocalPlayer player, Vector pos) { + if (pos1 != null && pos2 != null) { + player.print("First position set to " + pos1 + + " (" + region.getArea() + ")."); + } else { + player.print("First position set to " + pos1 + "."); + } + } + + public void explainSecondarySelection(LocalPlayer player, Vector pos) { + if (pos1 != null && pos2 != null) { + player.print("Second position set to " + pos1 + + " (" + region.getArea() + ")."); + } else { + player.print("Second position set to " + pos1 + "."); + } + } + + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + if (pos1 == null) { + throw new IncompleteRegionException(); + } + + return pos1; + } + + public boolean isDefined() { + return pos1 != null && pos2 != null; + } + + public Region getRegion() throws IncompleteRegionException { + if (pos1 == null || pos2 == null) { + throw new IncompleteRegionException(); + } + + return region; + } + + public void learnChanges() { + pos1 = region.getPos1().toBlockVector(); + pos2 = region.getPos2().toBlockVector(); + } + + public void clear() { + pos1 = null; + pos2 = null; + } + + public String getTypeName() { + return "cuboid"; + } + + public List getInformationLines() { + List lines = new ArrayList(); + + if (pos1 != null) { + lines.add("Position 1: " + pos1); + } + + if (pos2 != null) { + lines.add("Position 2: " + pos2); + } + + return lines; + } +} diff --git a/src/com/sk89q/worldedit/regions/Polygonal2DRegion.java b/src/com/sk89q/worldedit/regions/Polygonal2DRegion.java new file mode 100644 index 000000000..a1e27d81f --- /dev/null +++ b/src/com/sk89q/worldedit/regions/Polygonal2DRegion.java @@ -0,0 +1,527 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.regions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.Vector2D; +import com.sk89q.worldedit.data.ChunkStore; + +/** + * Represents a 2D polygonal region. + * + * @author sk89q + */ +public class Polygonal2DRegion implements Region { + protected List points; + protected BlockVector min; + protected BlockVector max; + protected int minY; + protected int maxY; + protected boolean hasY = false; + + /** + * Construct the region. + */ + public Polygonal2DRegion() { + points = new ArrayList(); + minY = 0; + maxY = 0; + hasY = false; + recalculate(); + } + + /** + * Construct the region. + * + * @param points + * @param minY + * @param maxY + */ + public Polygonal2DRegion(List points, int minY, int maxY) { + this.points = points; + this.minY = minY; + this.maxY = maxY; + hasY = true; + recalculate(); + } + + /** + * Get the list of points. + * + * @return + */ + public List getPoints() { + return Collections.unmodifiableList(points); + } + + /** + * Recalculate the bounding box of this polygonal region. This should be + * called after points have been changed. + */ + protected void recalculate() { + if (points.size() == 0) { + min = new BlockVector(0, 0, 0); + max = new BlockVector(0, 0, 0); + return; + } + + int minX = points.get(0).getBlockX(); + int minZ = points.get(0).getBlockZ(); + int maxX = points.get(0).getBlockX(); + int maxZ = points.get(0).getBlockZ(); + + for (BlockVector2D v : points) { + int x = v.getBlockX(); + int z = v.getBlockZ(); + if (x < minX) minX = x; + if (z < minZ) minZ = z; + if (x > maxX) maxX = x; + if (z > maxZ) maxZ = z; + } + + int oldMinY = minY; + int oldMaxY = maxY; + minY = Math.min(oldMinY, oldMaxY); + maxY = Math.max(oldMinY, oldMaxY); + + min = new BlockVector(minX, minY, minZ); + max = new BlockVector(maxX, maxY, maxZ); + } + + /** + * Add a point to the list. + * + * @param pt + */ + public void addPoint(Vector2D pt) { + points.add(pt.toBlockVector2D()); + recalculate(); + } + + /** + * Add a point to the list. + * + * @param pt + */ + public void addPoint(BlockVector2D pt) { + points.add(pt); + recalculate(); + } + + /** + * Add a point to the list. + * + * @param pt + */ + public void addPoint(Vector pt) { + points.add(new BlockVector2D(pt.getBlockX(), pt.getBlockZ())); + recalculate(); + } + + /** + * Get the lower point of a region. + * + * @return min. point + */ + public Vector getMinimumPoint() { + return min; + } + + /** + * Get the upper point of a region. + * + * @return max. point + */ + public Vector getMaximumPoint() { + return max; + } + + /** + * Get the number of blocks in the region. + * + * @return number of blocks + */ + public int getArea() { + double area = 0; + int i, j = points.size() - 1; + + for (i = 0; i < points.size(); i++) { + area += (points.get(j).getBlockX() + points.get(i).getBlockX()) + * (points.get(j).getBlockZ() - points.get(i).getBlockZ()); + j = i; + } + + return (int)Math.floor(Math.abs(area * 0.5) + * (maxY - minY + 1)); + } + + /** + * Get X-size. + * + * @return width + */ + public int getWidth() { + return max.getBlockX() - min.getBlockX(); + } + + /** + * Get Y-size. + * + * @return height + */ + public int getHeight() { + return max.getBlockY() - min.getBlockY(); + } + + /** + * Get Z-size. + * + * @return length + */ + public int getLength() { + return max.getBlockZ() - min.getBlockZ(); + } + + /** + * Expand the region. + * + * @param change + */ + public void expand(Vector change) throws RegionOperationException { + if (change.getBlockX() != 0 || change.getBlockZ() != 0) { + throw new RegionOperationException("Polygons can only be expanded vertically."); + } + + int changeY = change.getBlockY(); + if (changeY > 0) { + maxY += changeY; + } else { + minY += changeY; + } + recalculate(); + } + + /** + * Contract the region. + * + * @param change + */ + public void contract(Vector change) throws RegionOperationException { + if (change.getBlockX() != 0 || change.getBlockZ() != 0) { + throw new RegionOperationException("Polygons can only be contracted vertically."); + } + + int changeY = change.getBlockY(); + if (changeY > 0) { + minY += changeY; + } else { + maxY += changeY; + } + recalculate(); + } + + /** + * Checks to see if a point is inside this region. + */ + @Override + public boolean contains(Vector pt) { + return contains(points, minY, maxY, pt); + } + + /** + * Checks to see if a point is inside a region. + * + * @param points + * @param minY + * @param maxY + * @param pt + * @return + */ + public static boolean contains(List points, int minY, + int maxY, Vector pt) { + if (points.size() < 3) { + return false; + } + + int targetX = pt.getBlockX(); + int targetY = pt.getBlockY(); + int targetZ = pt.getBlockZ(); + + if (targetY < minY || targetY > maxY) { + return false; + } + + boolean inside = false; + int npoints = points.size(); + int xNew, zNew; + int xOld, zOld; + int x1, z1; + int x2, z2; + int i; + + xOld = points.get(npoints - 1).getBlockX(); + zOld = points.get(npoints - 1).getBlockZ(); + + for (i = 0; i < npoints; i++) { + xNew = points.get(i).getBlockX(); + zNew = points.get(i).getBlockZ(); + + if (xNew > xOld) { + x1 = xOld - 1; + x2 = xNew; + z1 = zOld; + z2 = zNew + 1; + } else { + x1 = xNew - 1; + x2 = xOld; + z1 = zNew; + z2 = zOld + 1; + } + + if (xNew < targetX == targetX <= xOld) { + long v1 = ((long) targetZ - (long) z1) * (long) (x2 - x1); + long v2 = ((long) z2 - (long) z1) * (long) (targetX - x1); + + if (v1 < v2) { + inside = !inside; + } + } + + xOld = xNew; + zOld = zNew; + } + + return inside; + } + + /** + * Get a list of chunks. + * + * @return + */ + public Set getChunks() { + Set chunks = new HashSet(); + + Vector min = getMinimumPoint(); + Vector max = getMaximumPoint(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + Vector pt = new Vector(x, y, z); + if (contains(pt)) { // Not the best + chunks.add(ChunkStore.toChunk(pt)); + } + } + } + } + + return chunks; + } + + /** + * Return the number of points. + * + * @return + */ + public int size() { + return points.size(); + } + + /** + * Expand the height of the polygon to fit the specified Y. + * + * @param y + * @return true if the area was expanded + */ + public boolean expandY(int y) { + if (!hasY) { + minY = y; + maxY = y; + hasY = true; + return true; + } else if (y < minY) { + minY = y; + return true; + } else if (y > maxY) { + maxY = y; + return true; + } + + return false; + } + + /** + * Get the iterator. + * + * @return iterator of points inside the region + */ + public Iterator iterator() { + return new Polygonal2DRegionIterator(this); + + /* + Incomplete iterator. Where's my yield?! + + ArrayList items = new ArrayList(); + + int nodes, pixelZ, i, j, swap; + int n = points.size(); + int[] nodeX = new int[n]; + + int minZ = getMinimumPoint().getBlockZ(); + int maxZ = getMaximumPoint().getBlockZ(); + + for (pixelZ = minZ; pixelZ < maxZ; pixelZ++) { + // Build a list of nodes + nodes = 0; + j = n - 1; + for (i = 0; i < n; i++) { + if (points.get(i).getBlockZ() < (double) pixelZ + && points.get(j).getBlockZ() >= (double) pixelZ + || points.get(j).getBlockZ() < (double) pixelZ + && points.get(i).getBlockZ() >= (double) pixelZ) { + nodeX[nodes++] = (int) (points.get(i).getBlockX() + + (pixelZ - points.get(i).getBlockZ()) + / (points.get(j).getBlockZ() - points.get(i) + .getBlockZ()) + * (points.get(j).getBlockX() - points.get(i) + .getBlockX())); + } + j = i; + } + + // Sort the nodes, via a simple bubble sort + i = 0; + while (i < nodes - 1) { + if (nodeX[i] > nodeX[i + 1]) { + swap = nodeX[i]; + nodeX[i] = nodeX[i + 1]; + nodeX[i + 1] = swap; + if (i > 0) + i--; + } else { + i++; + } + } + + // Fill the pixels between node pairs + for (i = 0; i < nodes; i += 2) { + for (j = nodeX[i]; j < nodeX[i + 1]; j++) { + for (int y = minY; y >= maxY; y++) { + items.add(new BlockVector(j, y, pixelZ)); + } + } + } + } + + return items.iterator();*/ + } + + /** + * A terrible polygonal region iterator. + */ + public class Polygonal2DRegionIterator implements Iterator { + protected List points = new ArrayList(); + protected int minX; + protected int minY; + protected int minZ; + protected int maxX; + protected int maxY; + protected int maxZ; + protected int n; + protected int i; + protected int curX; + protected int curZ; + protected int curY; + protected BlockVector next; + + public Polygonal2DRegionIterator(Polygonal2DRegion region) { + points = new ArrayList(region.points); + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + minX = min.getBlockX(); + minY = min.getBlockY(); + minZ = min.getBlockZ(); + maxX = max.getBlockX(); + maxY = max.getBlockY(); + maxZ = max.getBlockZ(); + n = (maxX - minX + 1) * (maxZ - minZ + 1); + i = 0; + curX = 0; + curZ = 0; + curY = minY; + next = null; + findNext(); + } + + private void findNext() { + if (i >= n) { + next = null; + return; + } + + if (next != null && curY <= maxY) { + curY++; + next = new BlockVector(curX, curY, curZ); + if (curY > maxY) { + i++; + curY = minY; + } else { + return; + } + } + + while (i < n) { + curZ = i / (maxX - minX + 1) + minZ; + curX = (i % (maxX - minX + 1)) + minX; + BlockVector pt = new BlockVector(curX, minY, curZ); + if (contains(points, minY, maxY, pt)) { + next = pt; + return; + } + i++; + } + + next = null; + } + + public boolean hasNext() { + return next != null; + } + + public BlockVector next() { + BlockVector next = this.next; + findNext(); + return next; + } + + public void remove() { + throw new UnsupportedOperationException("Not supported"); + } + } +} diff --git a/src/com/sk89q/worldedit/regions/Polygonal2DRegionSelector.java b/src/com/sk89q/worldedit/regions/Polygonal2DRegionSelector.java new file mode 100644 index 000000000..be0236dc9 --- /dev/null +++ b/src/com/sk89q/worldedit/regions/Polygonal2DRegionSelector.java @@ -0,0 +1,114 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.regions; + +import java.util.ArrayList; +import java.util.List; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.BlockVector2D; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.Vector; + +/** + * Selector for polygonal regions. + * + * @author sk89q + */ +public class Polygonal2DRegionSelector implements RegionSelector { + protected BlockVector pos1; + protected Polygonal2DRegion region = new Polygonal2DRegion(); + + public boolean selectPrimary(Vector pos) { + if (pos1 != null && pos1.equals(pos)) { + return false; + } + pos1 = pos.toBlockVector(); + region = new Polygonal2DRegion(); + region.addPoint(pos); + region.expandY(pos.getBlockY()); + return true; + } + + public boolean selectSecondary(Vector pos) { + if (region.size() > 0) { + List points = region.getPoints(); + BlockVector2D lastPoint = points.get(region.size() - 1); + if (lastPoint.getBlockX() == pos.getBlockX() + && lastPoint.getBlockZ() == pos.getBlockZ()) { + return false; + } + + if (points.size() >= 20) { + return false; + } + } + + region.addPoint(pos); + region.expandY(pos.getBlockY()); + return true; + } + + public void explainPrimarySelection(LocalPlayer player, Vector pos) { + player.print("Starting a new polygon at " + pos + "."); + } + + public void explainSecondarySelection(LocalPlayer player, Vector pos) { + player.print("Added point #" + region.size() + " at " + pos + "."); + } + + public BlockVector getPrimaryPosition() throws IncompleteRegionException { + if (pos1 == null) { + throw new IncompleteRegionException(); + } + return pos1; + } + + public Region getRegion() throws IncompleteRegionException { + if (!isDefined()) { + throw new IncompleteRegionException(); + } + + return region; + } + + public boolean isDefined() { + return region.size() > 2; + } + + public void learnChanges() { + } + + public void clear() { + pos1 = null; + region = new Polygonal2DRegion(); + } + + public String getTypeName() { + return "2Dx1D polygon"; + } + + public List getInformationLines() { + List lines = new ArrayList(); + lines.add("# points: " + region.size()); + return lines; + } + +} diff --git a/src/com/sk89q/worldedit/regions/Region.java b/src/com/sk89q/worldedit/regions/Region.java index d4872ab21..a07a277c1 100644 --- a/src/com/sk89q/worldedit/regions/Region.java +++ b/src/com/sk89q/worldedit/regions/Region.java @@ -19,15 +19,16 @@ package com.sk89q.worldedit.regions; +import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import java.util.Set; /** * - * @author Albert + * @author sk89q */ -public interface Region extends Iterable { +public interface Region extends Iterable { /** * Get the lower point of a region. * @@ -45,7 +46,7 @@ public interface Region extends Iterable { * * @return number of blocks */ - public int getSize(); + public int getArea(); /** * Get X-size. * @@ -68,14 +69,23 @@ public interface Region extends Iterable { * Expand the region. * * @param change + * @throws RegionOperationException */ - public void expand(Vector change); + public void expand(Vector change) throws RegionOperationException; /** * Contract the region. * * @param change + * @throws RegionOperationException */ - public void contract(Vector change); + public void contract(Vector change) throws RegionOperationException; + /** + * Returns true based on whether the region contains the point, + * + * @param pt + * @return + */ + public boolean contains(Vector pt); /** * Get a list of chunks. * diff --git a/src/com/sk89q/worldedit/regions/RegionOperationException.java b/src/com/sk89q/worldedit/regions/RegionOperationException.java new file mode 100644 index 000000000..c0047f285 --- /dev/null +++ b/src/com/sk89q/worldedit/regions/RegionOperationException.java @@ -0,0 +1,30 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.regions; + +import com.sk89q.worldedit.WorldEditException; + +public class RegionOperationException extends WorldEditException { + private static final long serialVersionUID = -6180325009115242142L; + + public RegionOperationException(String msg) { + super(msg); + } +} diff --git a/src/com/sk89q/worldedit/regions/RegionSelector.java b/src/com/sk89q/worldedit/regions/RegionSelector.java new file mode 100644 index 000000000..ee052803c --- /dev/null +++ b/src/com/sk89q/worldedit/regions/RegionSelector.java @@ -0,0 +1,112 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010, 2011 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.regions; + +import java.util.List; +import com.sk89q.worldedit.BlockVector; +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.Vector; + +/** + * Region selection factory. + * + * @author sk89q + */ +public interface RegionSelector { + /** + * Called when the first point is selected. + * + * @param pos + * @return true if something changed + */ + public boolean selectPrimary(Vector pos); + + /** + * Called when the second point is selected. + * + * @param pos + * @return true if something changed + */ + public boolean selectSecondary(Vector pos); + + /** + * Tell the player information about his/her primary selection. + * + * @param player + * @param pos + */ + public void explainPrimarySelection(LocalPlayer player, Vector pos); + + /** + * Tell the player information about his/her secondary selection. + * + * @param player + * @param pos + */ + public void explainSecondarySelection(LocalPlayer player, Vector pos); + + /** + * Get the primary position. + * + * @return + * @throws IncompleteRegionException + */ + public BlockVector getPrimaryPosition() throws IncompleteRegionException; + + /** + * Get the selection. + * + * @return + * @throws IncompleteRegionException + */ + public Region getRegion() throws IncompleteRegionException; + + /** + * Returns whether the region has been fully defined. + * + * @return + */ + public boolean isDefined(); + + /** + * Update the selector with changes to the region. + */ + public void learnChanges(); + + /** + * Clear the selection. + */ + public void clear(); + + /** + * Get a lowercase name of this region selector type. + * + * @return + */ + public String getTypeName(); + + /** + * Get lines of information about the selection. + * + * @return + */ + public List getInformationLines(); +}