/* * 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.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import de.tud.kom.p2psim.api.common.SimHost; import de.tud.kom.p2psim.api.network.SimNetInterface; import de.tud.kom.p2psim.api.topology.Topology; import de.tud.kom.p2psim.api.topology.movement.MovementInformation; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.impl.simengine.Simulator; import de.tud.kom.p2psim.impl.topology.PositionVector; import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel; import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.FixedAssignmentStrategy; import de.tudarmstadt.maki.simonstrator.api.Binder; import de.tudarmstadt.maki.simonstrator.api.Time; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint; import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor; /** * Movement of the {@link AttractionPoint}s in the {@link ModularMovementModel}. * {@link AttractionPoint}s follow path given via a .csv file. * * @author Nils Richerzhagen * @version 1.0, 02.08.2014 */ public class CsvMovement extends AbstractMovementModel { private FixedAssignmentStrategy transitionStrategy; private PositionVector worldDimensions; private final String SEP = ";"; private final String INTERMEDIATE_SEP = ","; private String file; private LinkedList> readPathInfos; private Map> componentsPathsInfos; private Map stateInfo; /** * * @param movementPointsFile */ @XMLConfigurableConstructor({ "movementPointsFile" , "minMovementSpeed", "maxMovementSpeed" }) public CsvMovement(String movementPointsFile, double minMovementSpeed, double maxMovementSpeed) { super(); this.worldDimensions = Binder.getComponentOrNull(Topology.class) .getWorldDimensions(); this.file = movementPointsFile; this.readPathInfos = new LinkedList>(); this.stateInfo = new LinkedHashMap(); this.componentsPathsInfos = new LinkedHashMap>(); readData(minMovementSpeed, maxMovementSpeed); } @Override public void addComponent(SimLocationActuator component) { super.addComponent(component); LinkedList first = readPathInfos.removeFirst(); componentsPathsInfos.put(component, first); stateInfo.put(component, new CsvMovementInfo()); } @Override public void move() { Set comps = getComponents(); for (SimLocationActuator comp : comps) { PositionVector pos = comp.getRealPosition(); CsvMovementInfo info = stateInfo.get(comp); if (info.getRemainingSteps() == 0 || info.getDelta() == null) { // assign next delta and next steps for next path point if (!assignNextMovementInfo(comp)) { return; } } updatePosition(comp, pos.plus(info.getDelta())); info.setRemainingSteps(info.getRemainingSteps() - 1); } } protected boolean assignNextMovementInfo(SimLocationActuator comp) { CsvMovementInfo info = stateInfo.get(comp); PositionVector actPos = comp.getRealPosition(); PositionVector delta = null; int steps = 1; if (componentsPathsInfos.get(comp).isEmpty()) { return false; } // PositionVector targetPos = CsvPathInfo pathInfo = componentsPathsInfos.get(comp).removeFirst(); PositionVector targetPos = pathInfo.getNextPostion(); if(actPos.getX() == targetPos.getX() && actPos.getY() == targetPos.getY()){ new Error("New position is exactly on the same place where old is. Do not do that!"); } double distancePerMoveOperation = pathInfo.getSpeed() * getTimeBetweenMoveOperations() / Time.SECOND; double distance = actPos.distanceTo(targetPos); steps = (int) Math.round(distance / distancePerMoveOperation); double xDelta = (targetPos.getX() - actPos.getX()) / steps; double yDelta = (targetPos.getY() - actPos.getY()) / steps; String groupId = transitionStrategy .getGroupIdOfAttractionPoint((AttractionPoint) comp); if (!(groupId == null)) { // Go offline whenever intervals says to do so. if (!pathInfo.isOnline()) { List hosts = Simulator.getInstance().getScenario() .getHosts().get(groupId); for (SimHost simHost : hosts) { for (SimNetInterface net : simHost.getNetworkComponent() .getSimNetworkInterfaces()) { if (net.isOnline()) net.goOffline(); } } } else if (pathInfo.isOnline()) { List hosts = Simulator.getInstance().getScenario() .getHosts().get(groupId); for (SimHost simHost : hosts) { for (SimNetInterface net : simHost.getNetworkComponent() .getSimNetworkInterfaces()) { if (net.isOffline()) net.goOnline(); } } } } delta = new PositionVector(xDelta, yDelta); info.setDelta(delta); info.setRemainingSteps(steps); return true; } /** * Read the given csv file. * * x, y, 'ONLINE'/'OFFLINE', min speed, max speed * * if min speed == max speed = speed */ private void readData(double minMovementSpeed, double maxMovementSpeed) { readPathInfos.clear(); boolean entrySuccessfullyRead = false; BufferedReader csv = null; try { csv = new BufferedReader(new FileReader(file)); while (csv.ready()) { String line = csv.readLine(); LinkedList currentPathInfos = new LinkedList(); if (line.indexOf(SEP) > -1) { String[] parts = line.split(SEP); for (String actPart : parts) { String[] subParts = actPart.split(INTERMEDIATE_SEP); if (subParts.length == 5) { try { Double x = Double.parseDouble(subParts[0]); Double y = Double.parseDouble(subParts[1]); String online = subParts[2]; online = online.replaceAll("\\s+",""); Double minSpeed; Double maxSpeed; if(online.equals("OFFLINE")){ minSpeed = Double .parseDouble(subParts[3]); maxSpeed = Double .parseDouble(subParts[4]); } else{ minSpeed = minMovementSpeed; maxSpeed = maxMovementSpeed; } // log.error("Min speed: " + minSpeed + " max speed " + maxSpeed ); if (x > worldDimensions.getX() || y > worldDimensions.getY() || x < 0 || y < 0) { System.err.println("Skipped entry " + x + ";" + y); continue; } CsvPathInfo actPathInfo = new CsvPathInfo( new PositionVector(x, y), online, minSpeed, maxSpeed); currentPathInfos.add(actPathInfo); entrySuccessfullyRead = true; } catch (NumberFormatException e) { // Ignore leading comments if (entrySuccessfullyRead) { // System.err.println("CSV ParseError " + // line); } } } else { throw new AssertionError("To many columns in CSV."); } } } // Put MovementInfos of one line into the full vector. readPathInfos.add(currentPathInfos); } } catch (Exception e) { System.err.println(e.toString()); } finally { if (csv != null) { try { csv.close(); } catch (IOException e) { // } } } } /** * * @param transStrategy */ public void addTransitionStrategy(FixedAssignmentStrategy transStrategy) { this.transitionStrategy = transStrategy; } /** * * @author Nils Richerzhagen * @version 1.0, 16.07.2014 */ public class CsvMovementInfo implements MovementInformation { private PositionVector delta; private int remainingSteps = 0; public void setDelta(PositionVector delta) { this.delta = delta; } public void setRemainingSteps(int remainingSteps) { this.remainingSteps = remainingSteps; } public PositionVector getDelta() { return delta; } public int getRemainingSteps() { return remainingSteps; } } /** * * @author Nils Richerzhagen * @version 1.0, 02.08.2014 */ public class CsvPathInfo { private PositionVector nextPostion; private boolean online; private double minSpeed; private double maxSpeed; public CsvPathInfo(PositionVector nextPosition, String online, double minSpeed, double maxSpeed) { this.nextPostion = nextPosition; this.minSpeed = minSpeed; this.maxSpeed = maxSpeed; if (online.equals("ONLINE")) this.online = true; else if (online.equals("OFFLINE")) this.online = false; else throw new Error(online + " no valid String in CsvMovement"); } public PositionVector getNextPostion() { return nextPostion; } public double getSpeed() { if (minSpeed == maxSpeed) return minSpeed; return getRandomDouble(minSpeed, maxSpeed); } public boolean isOnline() { return online; } } }