All pastes #592441 Raw Edit

Something

public text v1 · immutable
#592441 ·published 2007-06-27 19:32 UTC
rendered paste body
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.PriorityQueue;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;

public class TestStaticFormat {
	private final static int E = 1;
	private final static int W = 2;
	private final static int S = 4;
	private final static int N = 8;

	private ByteBuffer[][][] _buffer = null;

	private int _rx, _ry, _layer;

	private int _mode = 0;
	private JLabel _mapLabel;
	private BufferedImage _mapImage;
	private JLabel _coordLabel;
	private BufferedImage _zoomImage;
	private JLabel _zoomLabel;
	private int[] _colorRange;
	private short _minZ;
	private short _maxZ;
	private JSplitPane _splitPane;
	private JScrollPane _scrollPane;
	private JComboBox _chooseMode;
	private int _maxLayer;

	public static void main(String[] args) throws IOException {
		// TestStaticFormat t = new TestStaticFormat(23, 18,1);
		TestStaticFormat t = new TestStaticFormat(19, 21, 0);
		System.out.println("");
		t.plotMap();
		// t.loadGeodataFile(19, 21);
	}

	public TestStaticFormat(int rx, int ry, int layer) throws IOException {
		_rx = rx;
		_ry = ry;
		_layer = layer;
	}

	public boolean checkVisibility(int x1, int y1, int x2, int y2, int h1, int h2, int maxrange) throws IOException {
		int dx = Math.abs(x1 - x2);
		int dy = Math.abs(y1 - y2);

		if (dx + dy == 0)
			return true;

		if (dx * dx + dy * dy > maxrange * maxrange)
			return false;

		int[] moveForward;
		int[] moveSideward;

		if (dx > dy) {
			moveForward = new int[] { x1 > x2 ? -1 : 1, 0 };
			moveSideward = new int[] { 0, y1 > y2 ? -1 : 1 };
		} else {
			moveSideward = new int[] { x1 > x2 ? -1 : 1, 0 };
			moveForward = new int[] { 0, y1 > y2 ? -1 : 1 };

			int t = dx;
			dx = dy;
			dy = t;
		}
		int error = dx >> 1;
		int height = (getCellHeight(x1, y1, _layer) + h1) * 65536;
		int heightTarget = (getCellHeight(x2, y2, _layer) + h2) * 65536;

		int heightDelta = (heightTarget - height) / Math.max(dx, dy);

		// Linienalgorithmus nach Bresenham (siehe
		// http://de.wikipedia.org/wiki/Bresenham-Algorithmus)
		while (x1 != x2 || y2 != y2) {
			x1 += moveForward[0];
			y1 += moveForward[1];
			error -= dy;

			height += heightDelta;

			// Neue Zelle blockiert ?
			if (getCellHeight(x1, y1, _layer) * 65536 > height)
				return false;

			// Prüfe Bewegung zur Seite überhaupt nötig ist !
			if (error > 0) {
				continue;
			}

			x1 += moveSideward[0];
			y1 += moveSideward[1];
			error += dx;

			// Neue Zelle blockiert ?
			if (getCellHeight(x1, y1, _layer) * 65536 > height)
				return false;
		}
		return true;
	}

	public int[] checkDirectPath(int x1, int y1, int x2, int y2) throws IOException {
		int dx = Math.abs(x1 - x2);
		int dy = Math.abs(y1 - y2);

		int[] moveForward;
		int[] moveSideward;
		int forward;
		int sideward;

		if (dx > dy) {
			moveForward = new int[] { x1 > x2 ? -1 : 1, 0 };
			moveSideward = new int[] { 0, y1 > y2 ? -1 : 1 };

			forward = x1 > x2 ? W : E;
			sideward = y1 > y2 ? N : S;
		} else {
			moveSideward = new int[] { x1 > x2 ? -1 : 1, 0 };
			moveForward = new int[] { 0, y1 > y2 ? -1 : 1 };

			sideward = x1 > x2 ? W : E;
			forward = y1 > y2 ? N : S;

			int t = dx;
			dx = dy;
			dy = t;
		}

		int[] index = new int[] { x1 & 0xfffc, y1 & 0xfffc };

		byte indexValue = getIndex(index[0], index[1], _layer);
		boolean freeBlockForward = (indexValue & forward) != 0;
		boolean freeBlockSideward = (indexValue & sideward) != 0;

		int stepsForwardInsideBlock = 0;
		int stepsSidewardInsideBlock = 0;

		for (int tx = x1, ty = y1; (tx & 0xfffc) == index[0] && (ty & 0xfffc) == index[1]; tx += moveForward[0], ty += moveForward[1])
			stepsForwardInsideBlock++;

		for (int tx = x1, ty = y1; (tx & 0xfffc) == index[0] && (ty & 0xfffc) == index[1]; tx += moveSideward[0], ty += moveSideward[1])
			stepsSidewardInsideBlock++;

		int error = dx >> 1;

		// Linienalgorithmus nach Bresenham (siehe
		// http://de.wikipedia.org/wiki/Bresenham-Algorithmus)
		while (x1 != x2 || y2 != y2) {
			// Prüfe Bewegung nach vorne
			if (!freeBlockForward) {
				int block = getCellBlock(x1, y1, _layer);

				// Bewegung nach vorne blockiert ?
				if ((block & forward) == 0) {
					System.out.println("Blocked forward by Block " + (x1 / 8) + "/" + (y1 / 8) + " Cell " + (x1 & 7)
							+ "/" + (y1 & 7));
					break;
				}
			}

			// erfolgreich bewegt
			x1 += moveForward[0];
			y1 += moveForward[1];
			error -= dy;

			// neuen Block erreicht ?
			stepsForwardInsideBlock--;
			if (stepsForwardInsideBlock == 0) {
				stepsForwardInsideBlock = 4;
				index[0] += (moveForward[0] * 4);
				index[1] += (moveForward[1] * 4);
				indexValue = getIndex(index[0], index[1], _layer);
				freeBlockForward = (indexValue & forward) != 0;
				freeBlockSideward = (indexValue & sideward) != 0;
				// System.out.println("New Index
				// "+freeBlockForward+"/"+freeBlockSideward+
				// " Block: "+(x1/8)+"/"+(y1/8)+" Cell "+(x1&7)+"/"+(y1&7));
			}

			// Prüfe Bewegung zur Seite überhaupt nötig ist !
			if (error > 0) {
				continue;
			}

			if (!freeBlockSideward) {
				int block = getCellBlock(x1, y1, _layer);

				// Bewegung nach vorne blockiert ?
				if ((block & sideward) == 0) {
					System.out.println("Blocked sideward by Block " + (x1 / 8) + "/" + (y1 / 8) + " Cell " + (x1 & 7)
							+ "/" + (y1 & 7));
					break;
				}
			}

			// erfolgreich bewegt
			x1 += moveSideward[0];
			y1 += moveSideward[1];
			error += dx;

			// neuen Block erreicht ?
			stepsSidewardInsideBlock--;
			if (stepsSidewardInsideBlock == 0) {
				stepsSidewardInsideBlock = 4;
				index[0] += (moveSideward[0] * 4);
				index[1] += (moveSideward[1] * 4);
				indexValue = getIndex(index[0], index[1], _layer);
				freeBlockForward = (indexValue & forward) != 0;
				freeBlockSideward = (indexValue & sideward) != 0;
				// System.out.println("New Index
				// "+freeBlockForward+"/"+freeBlockSideward+
				// " Block: "+(x1/8)+"/"+(y1/8)+" Cell "+(x1&7)+"/"+(y1&7));
			}
		}
		return new int[] { x1, y1 };
	}

	private class CellComparater implements Comparator<Integer> {
		private Map<Integer, Integer> _costs;

		public CellComparater(Map<Integer, Integer> costs) {
			_costs = costs;
		}

		public int compare(Integer o1, Integer o2) {
			return _costs.get(o1).compareTo(_costs.get(o2));
		}
	}

	public int[] findPath(int x1, int y1, int x2, int y2) throws IOException {
		long lengthSquared = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
		if (lengthSquared > 1024 * 1024)
			return new int[0];

		HashMap<Integer, Integer> g = new HashMap<Integer, Integer>();
		HashMap<Integer, Integer> queueSort = new HashMap<Integer, Integer>();
		HashMap<Integer, Integer> last = new HashMap<Integer, Integer>();

		PriorityQueue<Integer> open = new PriorityQueue<Integer>(100, new CellComparater(queueSort));
		HashSet<Integer> closed = new HashSet<Integer>();

		int start = x1 + (y1 << 16);
		int target = x2 + (y2 << 16);
		int[] neighFree = new int[] { N, E, S, W };
		int[] neighOffset = new int[] { -65536, 1, 65536, -1 };

		g.put(start, 0);
		queueSort.put(start, 0);
		open.add(start);

		Integer next;
		int maxSize = 1;
		while ((next = open.poll()) != null) {
			if (next == target)
				break;
			maxSize = Math.max(open.size(), maxSize);

			closed.add(next);
			int free = getCellBlock(next & 0xffff, next >> 16, _layer);

			int newCost = g.get(next) + 1000;
			long nCS = newCost * newCost;
			if (nCS > lengthSquared * 1440000)
				continue;

			for (int i = 0; i < 4; i++) {
				int neighPos = next + neighOffset[i];
				if ((free & neighFree[i]) == 0)
					continue;

				if (open.contains(neighPos) && newCost < g.get(neighPos))
					open.remove(neighPos);
				if (closed.contains(neighPos) && newCost < g.get(neighPos))
					closed.remove(neighPos);

				if (!(open.contains(neighPos) || closed.contains(neighPos))) {
					g.put(neighPos, newCost);
					queueSort.put(neighPos, newCost + h(neighPos, i, x1, y1, x2, y2));
					open.add(neighPos);
					last.put(neighPos, next);
				}
			}
		}

		if (next == null)
			return new int[0];

		// Draw Path
		int[] result = new int[g.get(target)];

		int count = result.length - 1;
		while (target != start) {
			result[count] = target;
			count--;
			target = last.get(target);
		}
		return result;
	}

	public Integer[] findQuickPath(int x1, int y1, int x2, int y2) throws IOException {
		x1 = x1 & 0xfffc;
		x2 = x2 & 0xfffc;
		y1 = y1 & 0xfffc;
		y2 = y2 & 0xfffc;

		long lengthSquared = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
		if (lengthSquared > 1024 * 1024)
			return new Integer[0];

		HashMap<Integer, Integer> g = new HashMap<Integer, Integer>();
		HashMap<Integer, Integer> queueSort = new HashMap<Integer, Integer>();
		HashMap<Integer, Integer> last = new HashMap<Integer, Integer>();

		PriorityQueue<Integer> open = new PriorityQueue<Integer>(100, new CellComparater(queueSort));
		HashSet<Integer> closed = new HashSet<Integer>();

		int start = x1 + (y1 << 16);
		int target = x2 + (y2 << 16);
		int[] neighFree = new int[] { N, E, S, W };
		int[] neighOffset = new int[] { -65536 * 4, 4, 65536 * 4, -4 };

		g.put(start, 0);
		queueSort.put(start, 0);
		open.add(start);

		Integer next;
		while ((next = open.poll()) != null) {
			if (next == target)
				break;

			closed.add(next);
			int free = getIndex(next & 0xffff, next >> 16, _layer);

			int newCost = g.get(next) + 1000;
			long nCS = newCost * newCost;
			if (nCS > lengthSquared * 1440000)
				continue;

			for (int i = 0; i < 4; i++) {
				int neighPos = next + neighOffset[i];
				if ((free & neighFree[i]) == 0)
					continue;

				if (open.contains(neighPos) && newCost < g.get(neighPos))
					open.remove(neighPos);
				if (closed.contains(neighPos) && newCost < g.get(neighPos))
					closed.remove(neighPos);

				if (!(open.contains(neighPos) || closed.contains(neighPos))) {
					g.put(neighPos, newCost);
					queueSort.put(neighPos, newCost + h(neighPos, i, x1, y1, x2, y2));
					open.add(neighPos);
					last.put(neighPos, next);
				}
			}
		}

		if (next == null)
			return new Integer[0];

		// Draw Path
		ArrayList<Integer> out = new ArrayList<Integer>();
		while (target != start) {
			out.add(target);
			target = last.get(target);
		}
		out.add(start);
		return (Integer[]) out.toArray(new Integer[out.size()]);
	}

	private int h(int pos, int dir, int x1, int y1, int x2, int y2) {
		int x = pos & 65535;
		int y = pos >> 16;

		// int penalty = 0;
		int diffX = Math.abs(x2 - x);
		int diffY = Math.abs(y2 - y);

		return Math.max(diffX, diffY) * 1001;

		// if (dir == 0 || dir == 2) // N & S
		// penalty = diffX > diffY ? 1 : 0;
		// else // E & W
		// penalty = diffX > diffY ? 0 : 1;
		// return (diffX + diffY) * 1002 + penalty;
	}

	public long getUsedMemoryMB() {
		return (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
	}

	public void plotMap() throws IOException {
		JFrame frame = new JFrame("Output");

		JPanel panel = new JPanel(new BorderLayout());
		frame.setContentPane(panel);

		_splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		panel.add(_splitPane, BorderLayout.CENTER);
		
		_scrollPane = new JScrollPane();
		_splitPane.setLeftComponent(_scrollPane);
		
		_mapImage = new BufferedImage(2048, 2048, BufferedImage.TYPE_INT_RGB);
		Icon icon = new ImageIcon(_mapImage, "");
		_mapLabel = new JLabel(icon);
		_scrollPane.setViewportView(_mapLabel);

		BufferedImage colorScaleImage = new BufferedImage(256 * 5, 8, BufferedImage.TYPE_INT_RGB);
		Icon colorIcon = new ImageIcon(colorScaleImage, "");
		JLabel colorScale = new JLabel(colorIcon);
		panel.add(colorScale, BorderLayout.NORTH);

		JPanel sidebarWrapper = new JPanel(new BorderLayout());
		_splitPane.setRightComponent(sidebarWrapper);
		_splitPane.setDividerLocation(1000-270);
		
		JPanel sidebarPanel = new JPanel(new GridLayout(0, 1));
		sidebarWrapper.add(sidebarPanel, BorderLayout.NORTH);

		_coordLabel = new JLabel("-----/----- (-----)");
		_coordLabel.setBorder(BorderFactory.createTitledBorder("Mouse Position:"));
		sidebarPanel.add(_coordLabel);

		_chooseMode = new JComboBox(new String[] { "find quick path", "find path", "check LoS",
						"check direct path", "Zoom", "Zoom3D" });
		_chooseMode.setBorder(BorderFactory.createTitledBorder("Choose Mode:"));
		_chooseMode.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				_mode = _chooseMode.getSelectedIndex();
			}
		});
		sidebarPanel.add(_chooseMode);
		
		_zoomImage = new BufferedImage(256+32/4,256+32/4, BufferedImage.TYPE_INT_RGB);
		Icon zoomIcon = new ImageIcon(_zoomImage, "");
		_zoomLabel = new JLabel(zoomIcon);
		_zoomLabel.setDoubleBuffered(true);
		sidebarWrapper.add(_zoomLabel, BorderLayout.CENTER);
		
		frame.setSize(1000, 750);
		frame.setVisible(true);
		frame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

		MouseListener mouseListener = new MouseListener();
		_mapLabel.addMouseListener(mouseListener);
		_mapLabel.addMouseMotionListener(mouseListener);

		MouseWheelListener wheelListener = new MouseWheelListener() {
			public void mouseWheelMoved(MouseWheelEvent e) {
				int rotate = e.getWheelRotation();
				rotate += _chooseMode.getSelectedIndex();
				if (rotate >= 0 && rotate < _chooseMode.getItemCount()) {
					_chooseMode.setSelectedIndex(rotate);
				}
			}
		};
		_mapLabel.addMouseWheelListener(wheelListener);
		
		_minZ = Short.MAX_VALUE;
		_maxZ = Short.MIN_VALUE;
		_colorRange = new int[256 * 5];
		int index = 0;
		File dir = new File("./data/geodata/" + _rx + "_" + _ry);
		for (int c = 0; c < 256; index++, c++) {
			_colorRange[index] = 255 + (255 - c) * 65536;
			for (int y = 0; y < 8; y++) {
				colorScaleImage.setRGB(c, y, _colorRange[index]);
			}
		}
		for (int c = 0; c < 256; index++, c++) {
			_colorRange[index] = 255 + c * 256;
			for (int y = 0; y < 8; y++) {
				colorScaleImage.setRGB(c + 256, y, _colorRange[index]);
			}
		}
		for (int c = 0; c < 256; index++, c++) {
			_colorRange[index] = 255 * 256 + (255 - c);
			for (int y = 0; y < 8; y++) {
				colorScaleImage.setRGB(c + 512, y, _colorRange[index]);
			}
		}
		for (int c = 0; c < 256; index++, c++) {
			_colorRange[index] = 255 * 256 + c * 65536;
			for (int y = 0; y < 8; y++) {
				colorScaleImage.setRGB(c + 768, y, _colorRange[index]);
			}
		}
		for (int c = 0; c < 256; index++, c++) {
			_colorRange[index] = 255 * 65536 + (255 - c) * 256;
			for (int y = 0; y < 8; y++) {
				colorScaleImage.setRGB(c + 1024, y, _colorRange[index]);
			}
		}

		initializeMinMax(dir);

		int count[] = new int[16];
		Arrays.fill(count, 0);

		for (int y = 0; y < 2048; y++) {
			for (int x = 0; x < 2048; x++) {
				short value = _buffer[x / 128][y / 128][_layer].getShort((x & 127) * 2 + (y & 127) * 256);
				index = _buffer[x / 128][y / 128][_layer].get(32768 + (x & 127) / 4 + (y & 127) / 4 * 32);

				drawCell(y, x, value, index, false);
				count[value & 0xf]++;
			}
			_mapLabel.repaint();
		}
//		for (int i = 0; i < 16; i++) {
//			String b = "000" + Integer.toBinaryString(i);
//			System.out.println(b.substring(b.length() - 4) + ": " + count[i] + " times");
//		}
	}

	/**
	 * @param dir
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private void initializeMinMax(File dir) throws FileNotFoundException, IOException {
		for (int y = 0; y < 2048; y++) {
			for (int x = 0; x < 2048; x++) {
				short value = getCellHeight(x, y, _layer);
				if (value > _maxZ)
					_maxZ = value;
				if (value < _minZ)
					_minZ = value;
			}
		}
	}

	/**
	 * @param y
	 * @param x
	 * @param value
	 * @param index
	 * @param zoomed TODO
	 */
	private int drawCell(int y, int x, short value, int index, boolean zoomed) {
		short color = (short) (value & 0xfff0);
		int c;
		if (value == 0)
			c = 0;
		else {
			color = (short) ((color - _minZ) * (_colorRange.length - 1) / (_maxZ - _minZ));

			if ((index & 0xf) == 15)
				c = _colorRange[color];
			else {
				c = (_colorRange[color] & 0xfe) / 2 + (_colorRange[color] & 0xfe00) / 2 + (_colorRange[color] & 0xfe0000)
						/ 2;
			}
		}
		if (!zoomed) {
			_mapImage.setRGB(x, y, c);
		}
		return c;
	}

	private synchronized ByteBuffer getBuffer(int x, int y, int layer) throws IOException {
		// int regionX = x >> 11;
		// int regionY = y >> 11;

		int fileX = (x >> 7) & 0xf;
		int fileY = (y >> 7) & 0xf;

		if (_buffer == null) {
			loadBuffer(_rx, _ry);
		}
		
		return _buffer[fileX][fileY][layer];
	}

	private int getCellBlock(int x, int y, int layer) throws IOException {
		ByteBuffer buffer = getBuffer(x, y, layer);
		int sx = x & 0x7f;
		int sy = y & 0x7f;

		return buffer.getShort((sx << 1) + (sy << 8)) & 0xf;
	}

	private short getCellHeight(int x, int y, int layer) throws IOException {
		ByteBuffer buffer = getBuffer(x, y, layer);
		
		int sx = x & 0x7f;
		int sy = y & 0x7f;

		return (short) (buffer.getShort((sx << 1) + (sy << 8)) & 0xfff0);
	}

	private byte getIndex(int x, int y, int layer) throws IOException {
		ByteBuffer buffer = getBuffer(x, y, layer);

		int ix = (x >> 2) & 0x1f;
		int iy = (y >> 2) & 0x1f;

		return buffer.get(32768 + ix + (iy << 5));
	}

	private void loadBuffer(int fileX, int fileY) throws IOException {
		File dir = new File("./data/geodata/" + fileX + "_" + fileY + "/");
		_maxLayer = countLayers(dir);
		_buffer = new ByteBuffer[16][16][_maxLayer+1];
		ByteBuffer b = ByteBuffer.allocate(32768+1024);
		
		int count = 0;
		for (int y = 0; y < 16; y++) {
			for (int x = 0; x < 16; x++) {
				for (int l=0; l <= _maxLayer; l++) {
					_buffer[x][y][l] = b;
					File f = new File(dir, "block" + x + "_" + y + "_l" + l);
					if (!f.exists()) {
						count++;
						continue;
					}
					FileChannel roChannel = new RandomAccessFile(f, "r").getChannel();
					long size = (int) roChannel.size();
					_buffer[x][y][l] = roChannel.map(FileChannel.MapMode.READ_ONLY, 0, size).load();
				}
			}
		}
	}
	
	private int countLayers(File dir) {
		String[] files = dir.list();
		
		int count = 0;
		for (int i = 0; i < files.length; i++) {
			if (files[i].startsWith("block")) {
				int layer = Integer.parseInt(files[i].substring(files[i].lastIndexOf('l')+1));
				
				if (layer > count) {
					count = layer;
				}
			}
		}
		return 1;
	}
	
	private void open3DZoom(int x, int y) throws IOException {
		short[][][] height = new short[32][32][_maxLayer+1];
		
		Date now = new Date();
		
		short minHeight = Short.MAX_VALUE;
		short maxHeight = Short.MIN_VALUE;
		
		for (int xx=0; xx<32; xx++) {
			for (int yy=0; yy<32; yy++) {
				for (int l=0; l<=_maxLayer; l++) {
					short h = getCellHeight(x+xx, y+yy, l);
					height[xx][yy][l] = h;
					if (h == 0)
						continue;
					
					if (h > maxHeight)
						maxHeight = h;
					if (h < minHeight)
						minHeight = h;
				}
				Arrays.sort(height[0][0]);
			}
		}
		
		
		BufferedImage image = new BufferedImage(512 + 256, 512 + 256, BufferedImage.TYPE_INT_RGB);
		Graphics2D g = (Graphics2D) image.getGraphics();
		
		JFrame frame = new JFrame("3D");
		JScrollPane scroll = new JScrollPane();
		frame.setContentPane(scroll);
		
		ImageIcon icon = new ImageIcon(image, "");
		JLabel label = new JLabel(icon);
		scroll.setViewportView(label);
		
		frame.pack();
		frame.setVisible(true);
		frame.toFront();
		frame.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosed(WindowEvent e) {
				System.gc();
			}
		});
		g.clearRect(0,0, image.getWidth(), image.getHeight());
		
		int bottom = 511;
		
		int scale = maxHeight - minHeight;
		if (scale < 512)
			scale = 512;
		
		for (int xx=31; xx>=0 && frame.isShowing(); xx--) {
			for (int yy=0; yy<32 && frame.isShowing(); yy++) {
				for (int l=0; l<=0 && frame.isShowing(); l++) {
					int h = height[xx][yy][l];
					if (h == 0)
						continue;
						
					h -= minHeight;
					h = h * 256 / scale;
					
					Polygon p = new Polygon();
					p.addPoint(16 * xx + 8 * yy,      bottom - 128 + yy * 8 - h);
					p.addPoint(16 * xx + 8 * yy + 16, bottom - 128 + yy * 8 - h);
					p.addPoint(16 * xx + 8 * yy + 24, bottom - 128 + yy * 8 - h + 8);
					p.addPoint(16 * xx + 8 * yy +  8, bottom - 128 + yy * 8 - h + 8);
					
					g.setColor(Color.blue);
					g.fillPolygon(p);
					g.setColor(Color.white);
					g.drawPolygon(p);
					
					if (xx > 0 && height[xx-1][yy][l] != 0) {
						int h2 = (height[xx-1][yy][l] - minHeight)*256/scale;
						
						p = new Polygon();
						p.addPoint(16 * xx + 8 * yy,      bottom - 128 + yy * 8 - h);
						p.addPoint(16 * xx + 8 * yy +  8, bottom - 128 + yy * 8 - h + 8);
						p.addPoint(16 * xx + 8 * yy +  8, bottom - 128 + yy * 8 - h2 + 8);
						p.addPoint(16 * xx + 8 * yy,      bottom - 128 + yy * 8 - h2);
						
						g.setColor(Color.gray);
						g.fillPolygon(p);
						g.setColor(Color.white);
						g.drawPolygon(p);
					}
					if (yy < 31 && height[xx][yy+1][l] != 0) {
						int h2 = (height[xx][yy+1][l] - minHeight)*256/scale;
						
						p = new Polygon();
						p.addPoint(16 * xx + 8 * yy + 24, bottom - 128 + yy * 8 - h + 8);
						p.addPoint(16 * xx + 8 * yy +  8, bottom - 128 + yy * 8 - h + 8);
						p.addPoint(16 * xx + 8 * yy +  8, bottom - 128 + yy * 8 - h2 + 8);
						p.addPoint(16 * xx + 8 * yy + 24, bottom - 128 + yy * 8 - h2 + 8);
						
						g.setColor(Color.red);
						g.fillPolygon(p);
						g.setColor(Color.white);
						g.drawPolygon(p);
					}
				}
			}
		}
		label.repaint();
		g.dispose();
		
		System.out.println(new Date().getTime() - now.getTime());
	}
	
	private class MouseListener extends MouseAdapter implements Runnable, MouseMotionListener {
		private int _x1, _y1, _x2, _y2;
		private int _moveX, _moveY;
		private Rectangle _visible;
		
		public MouseListener() {
		}

		public void mouseMoved(MouseEvent e) {
			StringBuffer out = new StringBuffer("<html>");
			out.append(e.getX());
			out.append('/');
			out.append(e.getY());
			out.append(" (height: ");
			try {
				out.append(getCellHeight(e.getX(), e.getY(), _layer));
			} catch (IOException e1) {
			}
			out.append(')');

			_coordLabel.setText(out.toString());
		}

		public void mouseDragged(MouseEvent e) {
			if (_visible != null && e.getModifiersEx() == MouseEvent.BUTTON3_DOWN_MASK) {
				Component c = (Component)e.getSource();
				Point p = c.getParent().getMousePosition(true);
				if (p==null)
					return;
				
				Rectangle r = new Rectangle((p.x - _moveX)*2 + _visible.x, (p.y - _moveY)*2 + _visible.y,
						_visible.width, _visible.height);
				_mapLabel.scrollRectToVisible(r);
			}
		}

		@Override
		public void mousePressed(MouseEvent e) {
			if (e.getButton() == MouseEvent.BUTTON1) {
				_x1 = e.getX();
				_y1 = e.getY();
			}
			else if(e.getButton() == MouseEvent.BUTTON3) {
				JLabel c = (JLabel)e.getSource();
				Point p = c.getParent().getMousePosition(true);
				
				_moveX = p.x;
				_moveY = p.y;
				_visible = c.getVisibleRect();
			}
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			if (e.getButton() == MouseEvent.BUTTON1) {
				_x2 = e.getX();
				_y2 = e.getY();

				new Thread(this).start();
			}
			else if (e.getButton() == MouseEvent.BUTTON2) {
				// do nothing
			}
		}

		public void run() {
			try {
				if (_mode == 3) {
					int[] target = checkDirectPath(_x1, _y1, _x2, _y2);
					_mapImage.getGraphics().drawLine(_x1, _y1, target[0], target[1]);
				} else if (_mode == 2) {
					System.out.println(checkVisibility(_x1, _y1, _x2, _y2, 64, 64, 200));
				} else if (_mode == 1) {
					Date now = new Date();
					int[] path = findPath(_x1, _y1, _x2, _y2);
					System.out.println(new Date().getTime() - now.getTime());

					for (int i = 0; i < path.length; i++) {
						int x = path[i] & 0xffff;
						int y = path[i] >> 16;

						_mapImage.setRGB(x, y, 0xffffff);
					}
				} else if (_mode == 0) {
					Date now = new Date();
					Integer[] path1 = findQuickPath(_x1, _y1, _x2, _y2);
					System.out.println(new Date().getTime() - now.getTime());

					if (path1.length < 3)
						return;

					Graphics g = _mapImage.getGraphics();

					int[] path2 = new int[path1.length - 1];
					int[] path3 = new int[path1.length - 2];

					for (int i = 1, last = path1[0]; i < path1.length; i++) {
						int next = path1[i];
						path2[i - 1] = ((next + last) & 0xfffeffff) >> 1;
						last = next;
					}

					for (int i = 1, last = path2[0]; i < path2.length; i++) {
						int next = path2[i];
						path3[i - 1] = ((next + last) & 0xfffeffff) >> 1;
						last = next;
					}

					g.drawLine(path1[0] & 0xffff, path1[0] >> 16, path2[0] & 0xffff, path2[0] >> 16);

					int xx = path2[0] & 0xffff;
					int yy = path2[0] >> 16;

					for (int i = 0; i < path3.length; i++) {
						int x = path3[i] & 0xffff;
						int y = path3[i] >> 16;

						g.drawLine(xx, yy, x, y);

						xx = x;
						yy = y;
					}

					int p2 = path2[path2.length - 1];
					int p1 = path1[path1.length - 1];

					g.drawLine(xx, yy, p2 & 0xffff, p2 >> 16);
					g.drawLine(p2 & 0xffff, p2 >> 16, p1 & 0xffff, p1 >> 16);
				}
				else if (_mode == 4) {
					int left = Math.max(_x2 - 16, 0);
					int top = Math.max(_y2 - 16, 0);
					
					_zoomImage.getGraphics().clearRect(0,0,_zoomImage.getWidth(), _zoomImage.getHeight());
					
					for (int x=0; x<32; x++) {
						for (int y=0; y<32; y++) {
							ByteBuffer b = _buffer[(x+left)>>7][(y+top)>>7][_layer];
							short value = b.getShort(((x+left) & 127) * 2 + ((y+top) & 127) * 256);
							int index = value & 0xf;

							int c = drawCell(left+x, top+y,value, index, true);
							
							int addX = (x+left)/4 - left/4;
							int addY = (y+top)/4 - top/4;
							
							for (int xx=0; xx<8; xx++) {
								for (int yy=0; yy<8; yy++) {
									
									if (xx==0 || yy==0) {
										_zoomImage.setRGB((x<<3)+xx+addX, (y<<3)+yy+addY, 0);
									}
									else {
										_zoomImage.setRGB((x<<3)+xx+addX, (y<<3)+yy+addY, c);
									}
								}
							}
						}
					}
					_zoomLabel.repaint();
				}
				else if (_mode == 5) {
					int left = Math.max(_x2 - 16, 0);
					int top = Math.max(_y2 - 16, 0);
					open3DZoom(left, top);
				}
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			_mapLabel.repaint();
		}
	}
}