diff --git a/download/mapping-1.1.1.jar b/download/mapping-1.1.1.jar deleted file mode 100644 index 4349c05..0000000 Binary files a/download/mapping-1.1.1.jar and /dev/null differ diff --git a/download/mapping-1.2.jar b/download/mapping-1.2.jar new file mode 100644 index 0000000..12a8602 Binary files /dev/null and b/download/mapping-1.2.jar differ diff --git a/pom.xml b/pom.xml index 681e503..07a8cd6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ fr.klemek mapping - 1.1.1 + 1.2 diff --git a/preview.png b/preview.png index 67f8b4e..d1b2a8f 100644 Binary files a/preview.png and b/preview.png differ diff --git a/src/main/java/fr/klemek/mapping/KeyEventListener.java b/src/main/java/fr/klemek/mapping/KeyEventListener.java index 828b5c8..451bd2d 100644 --- a/src/main/java/fr/klemek/mapping/KeyEventListener.java +++ b/src/main/java/fr/klemek/mapping/KeyEventListener.java @@ -44,10 +44,14 @@ public class KeyEventListener implements KeyListener { break; case KeyEvent.VK_1: case KeyEvent.VK_NUMPAD1: - this.mp.setShowGrid(!this.mp.isShowGrid()); + this.mp.changeShowGrid(); break; case KeyEvent.VK_2: case KeyEvent.VK_NUMPAD2: + this.mp.changeShowFaces(); + break; + case KeyEvent.VK_3: + case KeyEvent.VK_NUMPAD3: this.mp.getMap().randomize(); break; case KeyEvent.VK_PAGE_UP: @@ -93,6 +97,12 @@ public class KeyEventListener implements KeyListener { case KeyEvent.VK_SHIFT: this.mp.setShiftDown(true); break; + case KeyEvent.VK_SPACE: + this.mp.changeTool(); + break; + case KeyEvent.VK_DELETE: + this.mp.deleteSelected(); + break; default: break; } diff --git a/src/main/java/fr/klemek/mapping/MainPanel.java b/src/main/java/fr/klemek/mapping/MainPanel.java index b5fcce5..55aff2e 100644 --- a/src/main/java/fr/klemek/mapping/MainPanel.java +++ b/src/main/java/fr/klemek/mapping/MainPanel.java @@ -1,6 +1,8 @@ package fr.klemek.mapping; import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; import javax.swing.*; @@ -11,6 +13,10 @@ class MainPanel extends JPanel { private float ratio = DEFAULT_RATIO; private transient Map map; + private transient ToolChangeListener toolChangeListener; + + private transient Tool tool = Tool.NODE_EXTRUDER; + private int x0; private int y0; private float xstep; @@ -22,11 +28,13 @@ class MainPanel extends JPanel { private int[][] ys; private boolean showGrid; + private boolean showFaces = true; private boolean shiftDown; private float angle; - MainPanel(Map map) { + MainPanel(Map map, ToolChangeListener toolChangeListener) { this.map = map; + this.toolChangeListener = toolChangeListener; new MouseListener(this); } @@ -42,6 +50,8 @@ class MainPanel extends JPanel { if (this.showGrid) this.drawGrid(g2); this.drawMap(g2); + if (this.showFaces) + this.drawFaces(g2); } private void computeNodes() { @@ -95,8 +105,6 @@ class MainPanel extends JPanel { } private void drawMap(Graphics2D g2) { - - for (int x = 0; x < this.map.size(); x++) { for (int y = 0; y < this.map.size(); y++) { this.drawLine(g2, x - 1, y, x, y); @@ -122,47 +130,98 @@ class MainPanel extends JPanel { y1 >= 0 && y1 < this.map.size() && x2 >= 0 && x2 < this.map.size() && y2 >= 0 && y2 < this.map.size()) { - if (Utils.dist2(x1, y1, sx, sy) < (this.shiftDown ? 2 : 1) || Utils.dist2(x2, y2, sx, sy) < (this.shiftDown ? 2 : 1)) { - g2.setColor(Color.RED); - } else { - g2.setColor(Color.BLACK); - } + g2.setColor(isSelectedLine(x1, y1, x2, y2) ? Color.RED : Color.BLACK); g2.drawLine(this.xs[x1][y1], this.ys[x1][y1], this.xs[x2][y2], this.ys[x2][y2]); } } + private boolean isSelectedLine(int x1, int y1, int x2, int y2) { + return this.tool == Tool.NODE_EXTRUDER && + (Utils.dist2(x1, y1, sx, sy) < (this.shiftDown ? 2 : 1) || + Utils.dist2(x2, y2, sx, sy) < (this.shiftDown ? 2 : 1)); + } + + private void drawFaces(Graphics2D g2) { + for (int x = 0; x < this.map.size() - 1; x++) + for (int y = 0; y < this.map.size() - 1; y++) + drawFace(g2, x, y); + } + + private void drawFace(Graphics2D g2, int x, int y) { + int diffY = Math.round(this.map.get(x, y, false) * this.ystep); + boolean selected = this.tool == Tool.FACE_EXTRUDER && Utils.dist2(x, y, sx, sy) < (this.shiftDown ? 3 : 1); + if (diffY == 0 && !selected) + return; + g2.setColor(selected ? Color.RED : Color.BLUE); + for (int dx = 0; dx <= 1; dx++) + for (int dy = 0; dy <= 1; dy++) + g2.drawLine(this.xs[x + dx][y + dy], this.ys[x + dx][y + dy], this.xs[x + dx][y + dy], this.ys[x + dx][y + dy] - diffY); + Polygon face = getFace(x, y); + face.translate(0, -diffY); + g2.drawPolygon(face); + } + void computeMouseMoved(Point position) { sx = -1; sy = -1; - if (MainPanel.this.xs != null) { - for (int x = 0; x < MainPanel.this.map.size(); x++) - for (int y = 0; y < MainPanel.this.map.size(); y++) - if (position.distance(MainPanel.this.xs[x][y], MainPanel.this.ys[x][y]) < 6) { - sx = x; - sy = y; - return; - } - } + if (this.xs == null) + return; + int mx = -1; + int my = -1; + double min = 20; + double d; + for (int x = 0; x < this.map.size(); x++) + for (int y = 0; y < this.map.size(); y++) + if (this.tool == Tool.FACE_EXTRUDER && x < this.map.size() - 1 && y < this.map.size() - 1 && this.getFace(x, y).contains(position)) { + this.sx = x; + this.sy = y; + return; + } else if (this.tool == Tool.NODE_EXTRUDER && (d = position.distance(this.xs[x][y], this.ys[x][y])) < min) { + mx = x; + my = y; + min = d; + } + this.sx = mx; + this.sy = my; + } + + private Polygon getFace(int x, int y) { + return new Polygon(new int[]{this.xs[x][y], this.xs[x + 1][y], this.xs[x + 1][y + 1], this.xs[x][y + 1]}, + new int[]{this.ys[x][y], this.ys[x + 1][y], this.ys[x + 1][y + 1], this.ys[x][y + 1]}, 4); } void computeMouseWheel(int amount, boolean controlDown, boolean shiftDown) { - if (sx >= 0 && sy >= 0) { - if (shiftDown) { - for (int dx = -1; dx < 2; dx++) - for (int dy = -1; dy < 2; dy++) - changeNode(amount, controlDown, sx + dx, sy + dy); - } else - changeNode(amount, controlDown, sx, sy); - } + if (sx < 0 || sy < 0) + return; + if (shiftDown) { + for (int dx = -1; dx < 2; dx++) + for (int dy = -1; dy < 2; dy++) + editMap(amount, controlDown, sx + dx, sy + dy, this.tool == Tool.NODE_EXTRUDER); + } else + editMap(amount, controlDown, sx, sy, this.tool == Tool.NODE_EXTRUDER); } - private void changeNode(int amount, boolean controlDown, int x, int y) { + private void editMap(int amount, boolean controlDown, int x, int y, boolean node) { if (x >= 0 && x < this.map.size() && y >= 0 && y < this.map.size()) - this.map.set(x, y, MainPanel.this.map.get(x, y) - + amount * (controlDown ? -1f : -.1f)); + this.map.set(x, y, this.map.get(x, y, node) + + amount * (controlDown ? -1f : -.1f), node); } + void changeTool() { + ArrayList tools = new ArrayList<>(Arrays.asList(Tool.values())); + this.tool = tools.get((tools.indexOf(this.tool) + 1) % tools.size()); + if (this.tool == Tool.FACE_EXTRUDER) + this.showFaces = true; + if (toolChangeListener != null) + toolChangeListener.toolChange(this.tool); + } + + void deleteSelected() { + if (sx < 0 || sy < 0) + return; + this.map.set(sx, sy, 0f, this.tool == Tool.NODE_EXTRUDER); + } float getRatio() { return ratio; @@ -172,12 +231,12 @@ class MainPanel extends JPanel { this.ratio = ratio; } - boolean isShowGrid() { - return showGrid; + void changeShowGrid() { + this.showGrid = !showGrid; } - void setShowGrid(boolean showGrid) { - this.showGrid = showGrid; + void changeShowFaces() { + this.showFaces = !showFaces; } float getAngle() { @@ -195,4 +254,8 @@ class MainPanel extends JPanel { void setShiftDown(boolean shiftDown) { this.shiftDown = shiftDown; } + + Tool getTool() { + return tool; + } } diff --git a/src/main/java/fr/klemek/mapping/MainWindow.java b/src/main/java/fr/klemek/mapping/MainWindow.java index b661767..3da6093 100644 --- a/src/main/java/fr/klemek/mapping/MainWindow.java +++ b/src/main/java/fr/klemek/mapping/MainWindow.java @@ -9,7 +9,7 @@ import javax.swing.*; class MainWindow extends JFrame { static final String FILE_NAME = "mapping.csv"; - private static final String VERSION = "1.1"; + private static final String VERSION = "1.2"; private static final int DEFAULT_SIZE = 17; private static final String INFO_TEXT = "" + "" + @@ -19,11 +19,14 @@ class MainWindow extends JFrame { "[SHIFT+Mouse wheel] - Set surrounding heights
" + "[BACKSPACE] - Erase everything
" + "[ARROWS] - Move view
" + - "[PAGE UP/DOWN] - Change size
" + + "[PAGE UP/DOWN] - Change size
" + "[CTRL+S] - Save current work
" + + "[SPACE] - Change tool
" + + "[DELETE] - Reset node/face
" + "[0] - Show/hide this info
" + - "[1] - Show grid
" + - "[2] - Add random
"; + "[1] - Show/hide grid
" + + "[2] - Show/hide special faces
" + + "[3] - Add random
"; private transient MainPanel mp; private transient RefreshThread refresh; @@ -33,7 +36,7 @@ class MainWindow extends JFrame { String saved = Utils.openFile(FILE_NAME); if (saved != null) m = new Map(saved); - this.mp = new MainPanel(m); + this.mp = new MainPanel(m, tool -> this.setTitle("Mapping v" + VERSION + " (" + tool.name + ")")); this.refresh = new RefreshThread(this.mp, 100); this.initWindow(); } @@ -41,7 +44,7 @@ class MainWindow extends JFrame { private void initWindow() { this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); this.setResizable(true); - this.setTitle("Mapping v" + VERSION); + this.setTitle("Mapping v" + VERSION + " (" + this.mp.getTool().name + ")"); this.setSize(new Dimension(800, 600)); this.getContentPane().setLayout(new BorderLayout(0, 0)); diff --git a/src/main/java/fr/klemek/mapping/Map.java b/src/main/java/fr/klemek/mapping/Map.java index 24481e4..d2ecd1f 100644 --- a/src/main/java/fr/klemek/mapping/Map.java +++ b/src/main/java/fr/klemek/mapping/Map.java @@ -5,16 +5,33 @@ import java.util.Random; class Map { private float[][] m; + private float[][] m2; Map(String input) { - String[] lines = input.split("\n"); + String[] parts = input.split("\n\n"); + String[] lines = parts[0].split("\n"); this.m = new float[lines.length][lines.length]; - for (int x = 0; x < lines.length; x++) { + for (int x = 0; x < this.m.length; x++) { String[] lineSplit = lines[x].split(";"); - for (int y = 0; y < Math.min(lines.length, lineSplit.length); y++) { + for (int y = 0; y < Math.min(this.m.length, lineSplit.length); y++) { try { this.m[x][y] = Float.parseFloat(lineSplit[y]); } catch (NumberFormatException ignored) { + //ignored + } + } + } + this.m2 = new float[lines.length - 1][lines.length - 1]; + if (parts.length > 1) { + lines = parts[1].split("\n"); + for (int x = 0; x < Math.min(this.m2.length, lines.length); x++) { + String[] lineSplit = lines[x].split(";"); + for (int y = 0; y < Math.min(this.m2.length, lineSplit.length); y++) { + try { + this.m2[x][y] = Float.parseFloat(lineSplit[y]); + } catch (NumberFormatException ignored) { + //ignored + } } } } @@ -22,6 +39,7 @@ class Map { Map(int size) { this.m = new float[size][size]; + this.m2 = new float[size - 1][size - 1]; } int size() { @@ -29,37 +47,54 @@ class Map { } float get(int x, int y) { - if (x < 0 || y < 0 || x >= this.m.length || y >= this.m.length) + return this.get(x, y, true); + } + + float get(int x, int y, boolean primary) { + if (x < 0 || y < 0 || x >= this.m.length - (primary ? 0 : 1) || y >= this.m.length - (primary ? 0 : 1)) return 0f; - return this.m[x][y]; + return primary ? this.m[x][y] : this.m2[x][y]; } void set(int x, int y, float value) { - if (x < 0 || y < 0 || x >= this.m.length || y >= this.m.length) + this.set(x, y, value, true); + } + + void set(int x, int y, float value, boolean primary) { + if (x < 0 || y < 0 || x >= this.m.length - (primary ? 0 : 1) || y >= this.m.length - (primary ? 0 : 1)) return; - this.m[x][y] = value; + if (primary) + this.m[x][y] = value; + else + this.m2[x][y] = value; } void reset() { this.m = new float[this.m.length][this.m.length]; + this.m2 = new float[this.m.length - 1][this.m.length - 1]; } void changeSize(int newSize) { - if (newSize > 1) { - float[][] m2 = new float[newSize][newSize]; - for (int x = 0; x < newSize; x++) - for (int y = 0; y < newSize; y++) - if (x < this.m.length && y < this.m.length) - m2[x][y] = this.m[x][y]; - this.m = m2; - } + if (newSize < 2) + return; + float[][] tm = new float[newSize][newSize]; + float[][] tm2 = new float[newSize - 1][newSize - 1]; + for (int x = 0; x < newSize; x++) + for (int y = 0; y < newSize; y++) { + if (x < this.m.length && y < this.m.length) + tm[x][y] = this.m[x][y]; + if (x < this.m2.length && y < this.m2.length) + tm2[x][y] = this.m2[x][y]; + } + this.m = tm; + this.m2 = tm2; } void randomize() { Random r = new Random(); for (int x = 0; x < this.m.length; x++) for (int y = 0; y < this.m.length; y++) - this.m[x][y] += r.nextFloat() - 0.5f; + this.m[x][y] += r.nextInt(11) * .1f - 0.5f; } @Override @@ -72,6 +107,14 @@ class Map { } output.append('\n'); } + output.append('\n'); + for (int x = 0; x < this.size() - 1; x++) { + for (int y = 0; y < this.size() - 1; y++) { + output.append(this.m2[x][y]); + output.append(';'); + } + output.append('\n'); + } return output.toString(); } } diff --git a/src/main/java/fr/klemek/mapping/Tool.java b/src/main/java/fr/klemek/mapping/Tool.java new file mode 100644 index 0000000..0a8b387 --- /dev/null +++ b/src/main/java/fr/klemek/mapping/Tool.java @@ -0,0 +1,12 @@ +package fr.klemek.mapping; + +public enum Tool { + NODE_EXTRUDER("Node mode"), + FACE_EXTRUDER("Face mode"); + + String name; + + Tool(String name) { + this.name = name; + } +} diff --git a/src/main/java/fr/klemek/mapping/ToolChangeListener.java b/src/main/java/fr/klemek/mapping/ToolChangeListener.java new file mode 100644 index 0000000..5ec9db4 --- /dev/null +++ b/src/main/java/fr/klemek/mapping/ToolChangeListener.java @@ -0,0 +1,7 @@ +package fr.klemek.mapping; + +interface ToolChangeListener { + + void toolChange(Tool tool); + +} diff --git a/src/main/java/fr/klemek/mapping/Utils.java b/src/main/java/fr/klemek/mapping/Utils.java index 33a87ca..c54a969 100644 --- a/src/main/java/fr/klemek/mapping/Utils.java +++ b/src/main/java/fr/klemek/mapping/Utils.java @@ -7,6 +7,7 @@ import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.util.logging.Level; final class Utils { @@ -23,7 +24,7 @@ final class Utils { bw.write(content); return true; } catch (IOException ex) { - Logger.log(ex); + Logger.log(Level.WARNING, ex); return false; } } @@ -38,7 +39,7 @@ final class Utils { } return output.toString(); } catch (IOException ex) { - Logger.log(ex); + Logger.log(Level.WARNING, ex); return null; } } diff --git a/src/test/java/fr/klemek/mapping/MapTest.java b/src/test/java/fr/klemek/mapping/MapTest.java index 92d3937..8c74d0b 100644 --- a/src/test/java/fr/klemek/mapping/MapTest.java +++ b/src/test/java/fr/klemek/mapping/MapTest.java @@ -11,40 +11,48 @@ public class MapTest { public void testToString() { Map m = new Map(15); m.randomize(); + m.set(0, 0, 5f, false); assertEquals(15, m.size()); Map m2 = new Map(m.toString()); assertEquals(m.size(), m2.size()); for (int x = 0; x < m.size(); x++) for (int y = 0; y < m.size(); y++) assertEquals(m.get(x, y), m2.get(x, y), 0.001f); + assertEquals(m.get(0, 0, false), m2.get(0, 0, false), 0.001f); } @Test public void testReset() { Map m = new Map(15); m.randomize(); + m.set(0, 0, 5f, false); assertNotEquals(0, m.get(0, 0), 0.001f); m.reset(); assertEquals(0, m.get(0, 0), 0.001f); + assertEquals(0, m.get(0, 0, false), 0.001f); } @Test public void testChangeSize() { Map m = new Map(15); m.randomize(); + m.set(0, 0, 5f, false); float value = m.get(0, 0); assertEquals(15, m.size()); m.changeSize(18); assertEquals(18, m.size()); assertEquals(value, m.get(0, 0), 0.001f); assertEquals(0, m.get(17, 17), 0.001f); + assertEquals(5f, m.get(0, 0, false), 0.001f); } @Test public void testRandomize() { Map m = new Map(15); assertEquals(0, m.get(0, 0), 0.001f); + m.set(0, 0, 5f, false); m.randomize(); assertNotEquals(0, m.get(0, 0), 0.001f); + assertEquals(5f, m.get(0, 0, false), 0.001f); } } \ No newline at end of file