/* * Copyright (c) 2005-2010 KOM – Multimedia Communications Lab * * This file is part of PeerfactSim.KOM. * * PeerfactSim.KOM is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * PeerfactSim.KOM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PeerfactSim.KOM. If not, see . * */ package de.tud.kom.p2psim.impl.topology.movement; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Random; import java.util.Set; import de.tud.kom.p2psim.api.scenario.ConfigurationException; import de.tud.kom.p2psim.api.topology.Topology; import de.tud.kom.p2psim.api.topology.movement.MovementModel; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.api.topology.placement.PlacementModel; import de.tud.kom.p2psim.impl.simengine.Simulator; import de.tud.kom.p2psim.impl.topology.PositionVector; import de.tud.kom.p2psim.impl.topology.TopologyFactory; import de.tud.kom.p2psim.impl.topology.movement.modularosm.GPSCalculation; import de.tudarmstadt.maki.simonstrator.api.Binder; import de.tudarmstadt.maki.simonstrator.api.Event; import de.tudarmstadt.maki.simonstrator.api.EventHandler; import de.tudarmstadt.maki.simonstrator.api.Randoms; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint; /** * * * * @author Julian Zobel * * */ public class StreetMovement implements MovementModel, EventHandler { private final int EVENT_MOVE = 1; private final int EVENT_INIT = 2; protected PositionVector worldDimensions; private Set moveableHosts = new LinkedHashSet(); private Map positions = new LinkedHashMap(); private Map attractionOfClients = new LinkedHashMap(); List attractionPoints = new LinkedList(); private boolean initialized = false; private long timeBetweenMoveOperation = Simulator.SECOND_UNIT; private Random rand; private double latLeft; //Values from -90 to 90; always smaller than latRight private double latRight; //Values from -90 to 90 private double lonLeft; //Values from -180 to 180; Always smaller than lonRight private double lonRight; //Values from -180 to 180 public StreetMovement() { this.worldDimensions = Binder.getComponentOrNull(Topology.class) .getWorldDimensions(); this.rand = Randoms.getRandom(StreetMovement.class); latLeft = GPSCalculation.getLatLower(); latRight = GPSCalculation.getLatUpper(); lonLeft = GPSCalculation.getLonLeft(); lonRight = GPSCalculation.getLonRight(); System.out.println("Scheduling first event for Init"); // scheduling initalization! Event.scheduleImmediately(this, null, EVENT_INIT); } /** * This Method will be not called from the Components. So we call this * manually! */ public void initialize() { if (!initialized) { setTimeBetweenMoveOperations(timeBetweenMoveOperation); for (SimLocationActuator ms : moveableHosts) { initializeStartingPosition(ms); } // initial move move(); initialized = true; } } /** * Assign the given node a random attraction point and place it * on a randomly selected position on the line between * the assigned attraction point and another adjacent attraction point. * * @param ms */ private void initializeStartingPosition(SimLocationActuator ms) { // set an initial attraction point int index = rand.nextInt(attractionPoints.size()); AttractionPoint a = attractionPoints.get(index); attractionOfClients.put(ms, a); AttractionPoint b = this.returnNextOrLastAttractionPoint(index); PositionVector startingPosition = this.returnRandomPositionBetweenPoints(a,b); ms.updateCurrentLocation(startingPosition); positions.put(ms, ms.getRealPosition()); } /** * Returns a randomly selected point on the line between the two given attraction points * * @param a Attraction Point A * @param b Attraction Point B * @return PositionVector of a randomly selected point on the connecting line of the attraction points */ private PositionVector returnRandomPositionBetweenPoints(AttractionPoint a, AttractionPoint b) { double longMin, longMax, latMin, latMax, longNew, latNew; // Points have different longitude, so only search for random value for longitude if(a.getLongitude() != b.getLongitude()) { if(a.getLongitude() < b.getLongitude()) { longMin = a.getLongitude(); longMax = b.getLongitude(); } else { longMin = b.getLongitude(); longMax = a.getLongitude(); } do { longNew = rand.nextDouble()*longMax; } while(longNew < longMin); assert longNew > longMin && longNew <= longMax; return new PositionVector(longNew, a.getLatitude()); } // Points have different latitude, so only search for random value for latitude if(a.getLatitude() != b.getLatitude()) { if(a.getLatitude() < b.getLatitude()) { latMin = a.getLatitude(); latMax = b.getLatitude(); } else { latMin = b.getLatitude(); latMax = a.getLatitude(); } do{ latNew = rand.nextDouble()*latMax; } while(latNew < latMin); assert latNew > latMin && latNew <= latMax; return new PositionVector(a.getLongitude(), latNew); } return null; } /** * This default implementation relies on {@link PlacementModel}s to be * configured in the {@link TopologyFactory} */ @Override public void placeComponent(SimLocationActuator actuator) { // not used here i guess } @Override public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) { /* * Set a new target AP for the current actuator */ attractionOfClients.put(actuator, ap); } @Override public void addComponent(SimLocationActuator comp) { moveableHosts.add(comp); positions.put(comp, comp.getRealPosition()); } @Override public void setTimeBetweenMoveOperations(long time) { if (time > 0) { this.timeBetweenMoveOperation = time; } else { throw new ConfigurationException( "time is negative for the Move Operations"); } } /** * Move all nodes towards their assigned attraction point */ protected void move() { for (Entry entry : attractionOfClients.entrySet()) { SimLocationActuator ms = entry.getKey(); PositionVector attractionCenter = (PositionVector) entry.getValue(); PositionVector destination = new PositionVector(attractionCenter); if (destination.distanceTo(ms.getRealPosition()) > ms.getMovementSpeed()) { PositionVector newPosition = ms.getRealPosition().moveStep(destination, ms.getMovementSpeed()); ms.updateCurrentLocation(newPosition); positions.put(ms, newPosition); } else { assignNewAttractionPoint(ms); } /* * Check for negative or out of bound coordinates! */ assert ms.getRealPosition().getX() >= 0.0 && ms.getRealPosition().getX() <= Binder .getComponentOrNull(Topology.class) .getWorldDimensions().getX(); assert ms.getRealPosition().getY() >= 0.0 && ms.getRealPosition().getY() <= Binder .getComponentOrNull(Topology.class) .getWorldDimensions().getY(); } Event.scheduleWithDelay(timeBetweenMoveOperation, this, null, EVENT_MOVE); } /** * Assign the node a random attraction point, that is adjacent to the last one * * @param ms The given node */ private void assignNewAttractionPoint(SimLocationActuator ms) { if(attractionOfClients.containsKey(ms)) { boolean updownrand = rand.nextBoolean(); int index = attractionPoints.indexOf(attractionOfClients.get(ms)); if(updownrand) { index = ((index + 1) % attractionPoints.size()); } else { index = ((index - 1 + attractionPoints.size()) % attractionPoints.size()); } attractionOfClients.put(ms, attractionPoints.get(index)); } else { attractionOfClients.put(ms, attractionPoints.get(rand.nextInt(attractionPoints.size()))); } } /** * Returns the next or last attraction point of the list to the given list index * * @param index Index of the attraction point, for which another attraction point should be returned * @return Attraction Point */ private AttractionPoint returnNextOrLastAttractionPoint(int index) { boolean updownrand = rand.nextBoolean(); if(updownrand) { index = ((index + 1) % attractionPoints.size()); } else { index = ((index - 1 + attractionPoints.size()) % attractionPoints.size()); } return attractionPoints.get(index); } @Override public void eventOccurred(Object content, int type) { if (type == EVENT_INIT) { initialize(); } else if (type == EVENT_MOVE) { move(); } } public List getAttractionPoints() { return attractionPoints; } public void setAttractionPoint(AttractionPoint point) { this.attractionPoints.add(point); } }