package rescuecore2.standard.misc; import rescuecore2.misc.Pair; import rescuecore2.standard.entities.StandardWorldModel; import rescuecore2.standard.entities.Human; import java.util.Iterator; import java.util.List; import java.util.ArrayList; /** A class for encapsulating the actual movement path an agent took during a timestep. */ public abstract class AgentPath { /** Compute the path an agent took. This will read the positionHistory property and generate a path. @param human The agent. @param world The world model. @return The computed Path, or null if the agent didn't move. */ public static AgentPath computePath(Human human, StandardWorldModel world) { if (human == null) { throw new IllegalArgumentException("Agent must not be null"); } if (!human.isPositionDefined()) { throw new IllegalArgumentException("Agent has an undefined position"); } if (!human.isPositionHistoryDefined()) { // Agent didn't move. return null; } int[] history = human.getPositionHistory(); if (history.length > 2) { return new CoordinatePath(history); } // Agent didn't move far enough: only one piece of history. return null; } /** Get the coordinates of a point along this path. @param d The distance along the path in the range [0..1]. @return The coordinates of the point along the path. */ public abstract Pair<Integer, Integer> getPointOnPath(double d); /** Get the length of this path. @return The length of the path. */ public abstract double getLength(); private static class CompositePath extends AgentPath { private List<AgentPath> parts; CompositePath() { parts = new ArrayList<AgentPath>(); } void addPath(AgentPath p) { parts.add(p); } @Override public double getLength() { double d = 0; for (AgentPath next : parts) { d += next.getLength(); } return d; } @Override public Pair<Integer, Integer> getPointOnPath(double d) { double length = getLength(); double point = d * length; // Find the right part AgentPath result = null; for (AgentPath next : parts) { double nextLength = next.getLength(); if (nextLength > point) { result = next; break; } point -= nextLength; } if (result == null) { // Fell off the end, probably because of numerical issues return parts.get(parts.size() - 1).getPointOnPath(1.0); } double p = point / result.getLength(); return result.getPointOnPath(p); } @Override public String toString() { StringBuilder result = new StringBuilder(); for (Iterator<AgentPath> it = parts.iterator(); it.hasNext();) { result.append(it.next()); if (it.hasNext()) { result.append(", "); } } return result.toString(); } } private abstract static class AbstractPath extends AgentPath { private Pair<Integer, Integer> start; private Pair<Integer, Integer> end; private double length; private String description; protected void setStart(int sX, int sY) { start = new Pair<Integer, Integer>(sX, sY); } protected void setEnd(int eX, int eY) { end = new Pair<Integer, Integer>(eX, eY); } protected void setStart(Pair<Integer, Integer> s) { start = s; } protected void setEnd(Pair<Integer, Integer> e) { end = e; } protected void setLength(double l) { length = l; } protected void computeLength() { int dx = end.first() - start.first(); int dy = end.second() - start.second(); length = Math.hypot(dx, dy); } protected void setDescription(String d) { description = d; } @Override public double getLength() { return length; } @Override public Pair<Integer, Integer> getPointOnPath(double d) { double dx = end.first() - start.first(); double dy = end.second() - start.second(); int x = start.first() + (int)(d * dx); int y = start.second() + (int)(d * dy); return new Pair<Integer, Integer>(x, y); } @Override public String toString() { return description; } } private static class CoordinatePath extends CompositePath { CoordinatePath(int[] history) { int fromX = history[0]; int fromY = history[1]; for (int i = 2; i < history.length; i += 2) { int toX = history[i]; int toY = history[i + 1]; addPath(new CoordinatePathSegment(fromX, fromY, toX, toY)); fromX = toX; fromY = toY; } } } private static class CoordinatePathSegment extends AbstractPath { CoordinatePathSegment(int fromX, int fromY, int toX, int toY) { setStart(fromX, fromY); setEnd(toX, toY); setDescription("From " + fromX + ", " + fromY + " to " + toX + ", " + toY); computeLength(); } } }