/* * 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.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel; import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator; import de.tudarmstadt.maki.simonstrator.api.Event; import de.tudarmstadt.maki.simonstrator.api.EventHandler; import de.tudarmstadt.maki.simonstrator.api.Time; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint; /** * With this transition strategy, nodes are roaming around {@link AttractionPoint}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 AbstractAttractionBasedTransitionStrategy implements EventHandler { public static enum roamingTransitionState { PAUSE, ROAMING, TRANSITION } protected Map roamingStates = new LinkedHashMap<>(); protected final static int EVENT_ROAMING_PAUSE_ENDED = 2; @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) { if(roamingStates.get(comp) == roamingTransitionState.PAUSE) { return; } // 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(), this, comp, EVENT_PAUSE_ENDED); } this.roamingStates.put(comp, roamingTransitionState.PAUSE); // schedule roaming Event.scheduleWithDelay(Time.SECOND * 30, this, comp, EVENT_ROAMING_PAUSE_ENDED); } private void roamAroundAttractionPoint(SimLocationActuator comp) { if(roamingStates.get(comp) != roamingTransitionState.TRANSITION) { AttractionPoint currentAttractionPoint = this.assignments.get(comp); if(currentAttractionPoint == null) { System.err.println("AP roaming failed: no AP"); } if(currentAttractionPoint.getRadius() > 0) { this.roamingStates.put(comp, roamingTransitionState.ROAMING); notifyListenersOfAssignmentUpdate(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; AttractionPoint currentAttractionPoint = this.assignments.get(comp); // if the attraction point was removed in the meantime, go directly to transit state if(currentAttractionPoint == null || !IAttractionGenerator.attractionPoints.contains(currentAttractionPoint)) { this.addComponent(comp); } else { this.roamAroundAttractionPoint(comp); } } } private AttractionPoint getNewAttractionPoint(SimLocationActuator component) { double score = rnd.nextDouble(); List candidates = new LinkedList<>(); for (AttractionPoint ap : IAttractionGenerator.attractionPoints) { if(ap == null) { continue; } if (ap.getWeight() >= score) { if(lastAssignments.get(component) == null || !ap.equals(lastAssignments.get(component))) { candidates.add(ap); } } } if (candidates.isEmpty()) { candidates.addAll(IAttractionGenerator.attractionPoints); } AttractionPoint assignment = candidates.get(rnd.nextInt(candidates.size())); return assignment; } }