/* * Copyright 2010 Aalto University, ComNet * Released under GPLv3. See LICENSE.txt for details. */ package movement; import input.WKTReader; import java.io.File; import java.util.LinkedList; import java.util.List; import movement.map.DijkstraPathFinder; import movement.map.MapNode; import movement.map.SimMap; import core.Coord; import core.Settings; /** * A Class to model movement when people are out shopping or doing other * activities with friends. If the node happens to be at some other location * than the place where the shopping starts (where it meets its friends), it * first travels to the destination along the shortest path. * * @author Frans Ekman */ public class EveningActivityMovement extends MapBasedMovement implements SwitchableMovement { private static final int WALKING_TO_MEETING_SPOT_MODE = 0; private static final int EVENING_ACTIVITY_MODE = 1; public static final String NR_OF_MEETING_SPOTS_SETTING = "nrOfMeetingSpots"; public static final String EVENING_ACTIVITY_CONTROL_SYSTEM_NR_SETTING = "shoppingControlSystemNr"; public static final String MEETING_SPOTS_FILE_SETTING = "meetingSpotsFile"; public static final String MIN_GROUP_SIZE_SETTING = "minGroupSize"; public static final String MAX_GROUP_SIZE_SETTING = "maxGroupSize"; public static final String MIN_WAIT_TIME_SETTING = "minAfterShoppingStopTime"; public static final String MAX_WAIT_TIME_SETTING = "maxAfterShoppingStopTime"; private static int nrOfMeetingSpots = 10; private int mode; private boolean ready; private DijkstraPathFinder pathFinder; private Coord lastWaypoint; private Coord startAtLocation; private EveningActivityControlSystem scs; private EveningTrip trip; private boolean readyToShop; private int id; private static int nextID = 0; private int minGroupSize; private int maxGroupSize; /** * Creates a new instance of EveningActivityMovement * @param settings */ public EveningActivityMovement(Settings settings) { super(settings); super.backAllowed = false; pathFinder = new DijkstraPathFinder(null); mode = WALKING_TO_MEETING_SPOT_MODE; minGroupSize = settings.getInt(MIN_GROUP_SIZE_SETTING); maxGroupSize = settings.getInt(MAX_GROUP_SIZE_SETTING); MapNode[] mapNodes = (MapNode[])getMap().getNodes(). toArray(new MapNode[0]); String shoppingSpotsFile = null; try { shoppingSpotsFile = settings.getSetting(MEETING_SPOTS_FILE_SETTING); } catch (Throwable t) { // Do nothing; } List meetingSpotLocations = null; if (shoppingSpotsFile == null) { nrOfMeetingSpots = settings.getInt(NR_OF_MEETING_SPOTS_SETTING); meetingSpotLocations = new LinkedList(); for (int i=0; i(); List locationsRead = (new WKTReader()).readPoints( new File(shoppingSpotsFile)); for (Coord coord : locationsRead) { SimMap map = getMap(); Coord offset = map.getOffset(); // mirror points if map data is mirrored if (map.isMirrored()) { coord.setLocation(coord.getX(), -coord.getY()); } coord.translate(offset.getX(), offset.getY()); meetingSpotLocations.add(coord); } } catch (Exception e) { e.printStackTrace(); } } //this.id = nextID++; int scsID = settings.getInt(EVENING_ACTIVITY_CONTROL_SYSTEM_NR_SETTING); scs = EveningActivityControlSystem.getEveningActivityControlSystem(scsID); scs.setRandomNumberGenerator(rng); //scs.addEveningActivityNode(this); scs.setMeetingSpots(meetingSpotLocations); maxPathLength = 100; minPathLength = 10; maxWaitTime = settings.getInt(MAX_WAIT_TIME_SETTING); minWaitTime = settings.getInt(MIN_WAIT_TIME_SETTING); } /** * Creates a new instance of EveningActivityMovement from a prototype * @param proto */ public EveningActivityMovement(EveningActivityMovement proto) { super(proto); this.pathFinder = proto.pathFinder; this.mode = proto.mode; this.id = nextID++; scs = proto.scs; scs.addEveningActivityNode(this); this.setMinGroupSize(proto.getMinGroupSize()); this.setMaxGroupSize(proto.getMaxGroupSize()); } /** * @return Unique ID of the shopper */ public int getID() { return this.id; } @Override public Coord getInitialLocation() { MapNode[] mapNodes = (MapNode[])getMap().getNodes(). toArray(new MapNode[0]); int index = rng.nextInt(mapNodes.length - 1); lastWaypoint = mapNodes[index].getLocation().clone(); return lastWaypoint.clone(); } @Override public Path getPath() { if (mode == WALKING_TO_MEETING_SPOT_MODE) { // Try to find to the shopping center SimMap map = super.getMap(); if (map == null) { return null; } MapNode thisNode = map.getNodeByCoord(lastWaypoint); MapNode destinationNode = map.getNodeByCoord(startAtLocation); List nodes = pathFinder.getShortestPath(thisNode, destinationNode); Path path = new Path(generateSpeed()); for (MapNode node : nodes) { path.addWaypoint(node.getLocation()); } lastWaypoint = startAtLocation.clone(); mode = EVENING_ACTIVITY_MODE; return path; } else if (mode == EVENING_ACTIVITY_MODE) { readyToShop = true; if (trip.allMembersPresent()) { Path path = trip.getPath(); if (path == null) { super.lastMapNode = super.getMap(). getNodeByCoord(lastWaypoint); path = super.getPath(); // TODO Create levy walk path lastWaypoint = super.lastMapNode.getLocation(); trip.setPath(path); double waitTimeAtEnd = (maxWaitTime - minWaitTime) * rng.nextDouble() + minWaitTime; trip.setWaitTimeAtEnd(waitTimeAtEnd); trip.setDestination(lastWaypoint); } lastWaypoint = trip.getDestination(); ready = true; return path; } } return null; } @Override protected double generateWaitTime() { if (ready) { double wait = trip.getWaitTimeAtEnd(); return wait; } else { return 0; } } @Override public MapBasedMovement replicate() { return new EveningActivityMovement(this); } /** * @see SwitchableMovement */ public Coord getLastLocation() { return lastWaypoint.clone(); } /** * @see SwitchableMovement */ public boolean isReady() { return ready; } /** * @see SwitchableMovement */ public void setLocation(Coord lastWaypoint) { this.lastWaypoint = lastWaypoint.clone(); ready = false; mode = WALKING_TO_MEETING_SPOT_MODE; } /** * Sets the node ready to start a shopping trip. * @return The coordinate of the place where the shopping trip starts */ public Coord getShoppingLocationAndGetReady() { readyToShop = false; // New shopping round starts trip = scs.getEveningInstructions(id); startAtLocation = trip.getLocation().clone(); return startAtLocation.clone(); } public Coord getShoppingLocation() { return scs.getMeetingSpotForID(id).clone(); } public void skipShopping() { scs.skipEveningActivity(id); } /** * Checks if a node is at the correct place where the shopping begins * @return true if node is ready and waiting for the rest of the group to * arrive */ public boolean isReadyToShop() { return readyToShop; } public static void reset() { nextID = 0; } public int getMinGroupSize() { return minGroupSize; } public void setMinGroupSize(int minGroupSize) { this.minGroupSize = minGroupSize; } public int getMaxGroupSize() { return maxGroupSize; } public void setMaxGroupSize(int maxGroupSize) { this.maxGroupSize = maxGroupSize; } }