/* * 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.Map; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.impl.topology.movement.distributions.ISpeedDistributionProvider; import de.tud.kom.p2psim.impl.topology.movement.modularosm.ISocialGroupMovementAnalyzer; import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel; 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.Time; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint; import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor; /** * With this transition strategy, nodes are roaming around {@link IAttractionPoint}s that have a radius. As the {@link ModularMovementModel} * uses a Gauss function to add jitter and offsets to the movement, some nodes may also roam outside of the circle's radius (this is intended to make it more realistic) * * @author Julian Zobel * @version 1.0, 24.01.2019 */ public class InAreaRoamingTransitionStrategy extends AbstractAttractionBasedAssignmentStrategy implements EventHandler { public static enum roamingTransitionState { PAUSE, ROAMING, TRANSITION } protected ISpeedDistributionProvider roamSpeedProvider; protected Map roamingStates = new LinkedHashMap<>(); protected final static int EVENT_ROAMING_PAUSE_ENDED = 2; private boolean useGaussianDistributedPauseTime = false; @XMLConfigurableConstructor({ "defaultPauseTimeMin", "defaultPauseTimeMax" }) public InAreaRoamingTransitionStrategy(long defaultPauseTimeMin, long defaultPauseTimeMax) { super(defaultPauseTimeMin, defaultPauseTimeMax); } @Override public void addComponent(SimLocationActuator comp) { this.roamingStates.put(comp, roamingTransitionState.TRANSITION); IAttractionPoint nextAP = getNewAttractionPointAssignment(comp); // trigger recalculation of speed comp.setMovementSpeed(-1); updateTargetAttractionPoint(comp, nextAP); } @Override public void reachedAttractionPoint(SimLocationActuator comp, IAttractionPoint attractionPoint) { if(roamingStates.get(comp) == roamingTransitionState.PAUSE) { return; } if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) { Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onNodeReachedAttractionPoint(comp, attractionPoint); } // start roaming if the AP was reached if(roamingStates.get(comp) == roamingTransitionState.TRANSITION) { // schedule the end of the roaming phase, which will make a new transition Event.scheduleWithDelay(getPauseTime(attractionPoint), this, comp, EVENT_PAUSE_ENDED); } this.roamingStates.put(comp, roamingTransitionState.PAUSE); // schedule roaming //Event.scheduleWithDelay(gaussianDistributionPauseTime(5 * Time.MINUTE, Time.MINUTE), this, comp, EVENT_ROAMING_PAUSE_ENDED); Event.scheduleWithDelay(15 * Time.SECOND, this, comp, EVENT_ROAMING_PAUSE_ENDED); } @Override public long getPauseTime(IAttractionPoint attractionPoint) { if(useGaussianDistributedPauseTime) { return gaussianDistributionPauseTime(defaultPauseTimeMax - defaultPauseTimeMin, 0.5*(defaultPauseTimeMax - defaultPauseTimeMin)); } else { return super.getPauseTime(attractionPoint); } } /** * Use a gaussian distribution for the pause time interval generation, using a mean value and a standard deviation * * @return */ private long gaussianDistributionPauseTime(double mean, double std) { double x = rnd.nextGaussian() * std + mean; if(x <= 0) return gaussianDistributionPauseTime(mean, std*0.9); return (long) x; } private void roamAroundAttractionPoint(SimLocationActuator comp) { if(roamingStates.get(comp) != roamingTransitionState.TRANSITION) { IAttractionPoint currentAttractionPoint = this.assignments.get(comp); if(currentAttractionPoint.getRadius() > 0) { this.roamingStates.put(comp, roamingTransitionState.ROAMING); comp.setMovementSpeed(roamSpeedProvider.calculateSpeed()); updateTargetAttractionPoint(comp, currentAttractionPoint); } } } @Override public void eventOccurred(Object content, int type) { if(type == EVENT_PAUSE_ENDED) { SimLocationActuator comp = (SimLocationActuator) content; // if the transit was triggered beforehand (e.g., attraction point moved), then do nothing. if(roamingStates.get(comp) != roamingTransitionState.TRANSITION) { this.addComponent(comp); } } else if(type == EVENT_ROAMING_PAUSE_ENDED) { SimLocationActuator comp = (SimLocationActuator) content; IAttractionPoint currentAttractionPoint = this.assignments.get(comp); // if the attraction point was removed in the meantime, go directly to transit state if(currentAttractionPoint == null || !attractionProvider.getAttractionPoints().contains(currentAttractionPoint)) { this.addComponent(comp); } else { this.roamAroundAttractionPoint(comp); } } } public void setGaussianPauseTime(boolean useGaussian) { useGaussianDistributedPauseTime = useGaussian; } public void setRoamingSpeedDistribution(ISpeedDistributionProvider dist) { this.roamSpeedProvider = dist; } }