/* * 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.modularosm.transition; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import de.tud.kom.p2psim.api.scenario.ConfigurationException; import de.tud.kom.p2psim.api.topology.Topology; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.BasicAttractionPoint; import de.tud.kom.p2psim.impl.topology.util.PositionVector; 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.Monitor; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint; public class InAreaRoamingTransitionStrategy extends AbstractAttractionBasedTransitionStrategy implements EventHandler { public static enum roamingTransitionState { ROAMING, TRANSITION } private final static int EVENT_ROAMING_ENDED = 1; protected Map roamingStates = new LinkedHashMap<>(); private long pauseTimeMin = 0; private long pauseTimeMax = 0; @Override public void addComponent(SimLocationActuator comp) { this.roamingStates.put(comp, roamingTransitionState.TRANSITION); AttractionPoint nextAP = getNewAttractionPoint(comp); updateTargetAttractionPoint(comp, nextAP); } @Override public void reachedAttractionPoint(SimLocationActuator comp) { // start roaming if(roamingStates.get(comp) == roamingTransitionState.TRANSITION) { // schedule the end of the roaming phase, which will make a new transition Event.scheduleWithDelay(getPauseTime(), this, comp, EVENT_ROAMING_ENDED); this.roamingStates.put(comp, roamingTransitionState.ROAMING); } // roam around the attraction point roamAroundAttractionPoint(comp); } private void roamAroundAttractionPoint(SimLocationActuator comp) { if(roamingStates.get(comp) == roamingTransitionState.ROAMING) { AttractionPoint currentAttractionPoint = this.assignments.get(comp); if(currentAttractionPoint == null) { System.err.println("AP roaming failed: no AP"); } if(currentAttractionPoint.getRadius() > 0) { notifyListenersOfAssignmentUpdate(comp, currentAttractionPoint); } } } @Override public void eventOccurred(Object content, int type) { assert type == EVENT_ROAMING_ENDED; SimLocationActuator comp = (SimLocationActuator) content; this.addComponent(comp); } private long getPauseTime() { return (long) (rnd.nextDouble() * (pauseTimeMax-pauseTimeMin)) + pauseTimeMin; } public void setMinPauseTime(long minPauseTime) { if (minPauseTime < 0) { throw new ConfigurationException( "MinPauseTime should be >= 0!"); } this.pauseTimeMin = minPauseTime; } public void setMaxPauseTime(long maxPauseTime) { if (maxPauseTime < 0) { throw new ConfigurationException( "MaxPauseTime should be >= 0!"); } this.pauseTimeMax = maxPauseTime; } private AttractionPoint getNewAttractionPoint(SimLocationActuator component) { double score = rnd.nextDouble(); List candidates = new LinkedList<>(); for (AttractionPoint ap : attractionPoints) { if (ap.getWeight() >= score) { if(lastAssignments.get(component) == null || !ap.equals(lastAssignments.get(component))) { candidates.add(ap); } } } if (candidates.isEmpty()) { candidates.addAll(attractionPoints); } AttractionPoint assignment = candidates.get(rnd.nextInt(candidates.size())); return assignment; } private AttractionPoint getNewRoamingPosition(AttractionPoint roamingAP) { double apRadius = roamingAP.getRadius(); double x = roamingAP.getLongitudeOrX(); double y = roamingAP.getLatitudeOrY(); double newX = -1; double newY = -1; PositionVector destination = null; int tries = 0; do { double calcRadius = rnd.nextDouble() * apRadius; double calcAngle = rnd.nextDouble() * 360; newX = x + Math.sin(calcAngle) * calcRadius; newY = y + Math.cos(calcAngle) * calcRadius; destination = new PositionVector(newX, newY); // Check constraints if (destination.getX() < 0.0 || destination.getX() > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getX() || destination.getY() < 0.0 || destination.getY() > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getY()) { destination = null; if (tries > 100) { throw new AssertionError("Unable to find a valid target destination within <100 tries."); } } tries++; } while (destination == null); Monitor.log(this.getClass(), Monitor.Level.DEBUG, "Next roaming position is " + newX + " / " + newY); return new BasicAttractionPoint("ROAMING", destination); } }