PathPlanning.java

package org.microcol.gui;

import org.microcol.model.Location;

/**
 * Class contains methods for computing path for units.
 * 
 * @author jan
 *
 */
public class PathPlanning {

	/**
	 * Allows to define step operation.
	 * 
	 * @author jan
	 *
	 */
	public interface WhatToDoWithPointInPath {
		void pathPoint(Location point);
	}

	/**
	 * Draw steps between two map points. It use naive algorithm. <i>y = ax +
	 * b</i>
	 * 
	 * @param tileFrom
	 *            required tile from
	 * @param tileTo
	 *            required tile to
	 * @param whatToDoWithPointInPath
	 *            required function that's executed with each found point to
	 *            visit
	 */
	public void paintPath(final Location tileFrom, final Location tileTo,
			final WhatToDoWithPointInPath whatToDoWithPointInPath) {
		final int diff = Math.abs(tileTo.getY() - tileFrom.getY()) - Math.abs(tileTo.getX() - tileFrom.getX());
		if (diff < 0) {
			float a = (tileFrom.getY() - tileTo.getY()) / (float) (tileFrom.getX() - tileTo.getX());
			float b = tileFrom.getY() - tileFrom.getX() * a;
			if (tileFrom.getX() < tileTo.getX()) {
				for (int x = tileFrom.getX(); x <= tileTo.getX(); x++) {
					int y = Math.round(a * x + b);
					addPoint(tileFrom, whatToDoWithPointInPath, Location.of(x, y));
				}
			} else {
				for (int x = tileFrom.getX(); x >= tileTo.getX(); x--) {
					int y = Math.round(a * x + b);
					addPoint(tileFrom, whatToDoWithPointInPath, Location.of(x, y));
				}
			}
		} else if (!tileFrom.equals(tileTo)) {
			float a = (tileFrom.getX() - tileTo.getX()) / (float) (tileFrom.getY() - tileTo.getY());
			float b = tileFrom.getX() - tileFrom.getY() * a;
			if (tileFrom.getY() < tileTo.getY()) {
				for (int y = tileFrom.getY(); y <= tileTo.getY(); y++) {
					int x = Math.round(a * y + b);
					addPoint(tileFrom, whatToDoWithPointInPath, Location.of(x, y));
				}
			} else {
				for (int y = tileFrom.getY(); y >= tileTo.getY(); y--) {
					int x = Math.round(a * y + b);
					addPoint(tileFrom, whatToDoWithPointInPath, Location.of(x, y));
				}
			}
		}
	}

	/**
	 * Draw steps between two map points. It use naive algorithm. <i>y = ax +
	 * b</i>
	 * 
	 * @param tileFrom
	 *            required tile from
	 * @param tileTo
	 *            required tile to
	 * @param whatToDoWithPointInPath
	 *            required function that's executed with each found point to
	 *            visit
	 * @param howManyStepsShouldBeDone
	 *            required how many steps should be done to reach target
	 */
	public void paintPath(final Location tileFrom, final Location tileTo,
			final WhatToDoWithPointInPath whatToDoWithPointInPath, final int howManyStepsShouldBeDone) {
		final int diff = Math.abs(tileTo.getY() - tileFrom.getY()) - Math.abs(tileTo.getX() - tileFrom.getX());
		if (diff < 0) {
			float a = (tileFrom.getY() - tileTo.getY()) / (float) (tileFrom.getX() - tileTo.getX());
			float b = tileFrom.getY() - tileFrom.getX() * a;
			if (tileFrom.getX() < tileTo.getX()) {
				final int increment = getStepSize(tileFrom.getX(), tileTo.getX(), howManyStepsShouldBeDone);
				for (int x = tileFrom.getX(); x <= tileTo.getX(); x += increment) {
					int y = Math.round(a * x + b);
					addPoint(tileFrom, whatToDoWithPointInPath, Location.of(x, y));
				}
			} else {
				final int increment = getStepSize(tileFrom.getX(), tileTo.getX(), howManyStepsShouldBeDone);
				for (int x = tileFrom.getX(); x >= tileTo.getX(); x += increment) {
					int y = Math.round(a * x + b);
					addPoint(tileFrom, whatToDoWithPointInPath, Location.of(x, y));
				}
			}
		} else if (!tileFrom.equals(tileTo)) {
			float a = (tileFrom.getX() - tileTo.getX()) / (float) (tileFrom.getY() - tileTo.getY());
			float b = tileFrom.getX() - tileFrom.getY() * a;
			if (tileFrom.getY() < tileTo.getY()) {
				final int increment = getStepSize(tileFrom.getY(), tileTo.getY(), howManyStepsShouldBeDone);
				for (int y = tileFrom.getY(); y <= tileTo.getY(); y += increment) {
					int x = Math.round(a * y + b);
					addPoint(tileFrom, whatToDoWithPointInPath, Location.of(x, y));
				}
			} else {
				final int increment = getStepSize(tileFrom.getY(), tileTo.getY(), howManyStepsShouldBeDone);
				for (int y = tileFrom.getY(); y >= tileTo.getY(); y += increment) {
					int x = Math.round(a * y + b);
					addPoint(tileFrom, whatToDoWithPointInPath, Location.of(x, y));
				}
			}
		}
	}

	private int getStepSize(final int from, final int to, final int howManyStepsShouldBeDone) {
		return (int) ((to - from) / (float) howManyStepsShouldBeDone);
	}

	/**
	 * Pass found location to callBack function. Just when start point is equals
	 * to found call back function is not called.
	 * 
	 * @param tileFrom
	 *            required from location
	 * @param whatToDoWithPointInPath
	 *            required call back function
	 * @param pointToAdd
	 *            required to location
	 */
	private void addPoint(final Location tileFrom, final WhatToDoWithPointInPath whatToDoWithPointInPath,
			final Location pointToAdd) {
		if (!tileFrom.equals(pointToAdd)) {
			whatToDoWithPointInPath.pathPoint(pointToAdd);
		}
	}

}