Commit 2e28bc46 authored by Björn Richerzhagen's avatar Björn Richerzhagen
Browse files

Merge branch 'master' into tm/sumo-integration

Conflicts:
	src/de/tud/kom/p2psim/impl/topology/DefaultTopologyComponent.java
parents 8aeec4ee 686eca40
......@@ -21,12 +21,16 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
......@@ -36,10 +40,20 @@ import javax.swing.event.ChangeListener;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.local.AbstractLocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent;
import de.tud.kom.p2psim.impl.topology.views.visualization.world.NodeVisInteractionListener;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Oracle;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route.RouteSegment;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor;
/**
* Visualization Component of the Attraction Points in the Modular Movement
......@@ -50,32 +64,48 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
* @version 1.0, 02.07.2015
*/
public class ModularMovementModelViz extends JComponent
implements VisualizationComponent {
implements VisualizationComponent, NodeVisInteractionListener {
private ModularMovementModel movementModel;
protected ModularMovementModel movementModel;
protected boolean showAttractionPoints = true;
protected boolean showNodePositions = true;
protected boolean showTrajectories = false;
protected boolean setupCalculatesTrajectories = false;
private JMenu menu;
private Map<Long, TrajectoryVis> trajectoryVisualizations = new LinkedHashMap<>();
private final static int NODE_PAD = 2;
private final static int ATTR_PAD = 5;
private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D");
public ModularMovementModelViz(ModularMovementModel model) {
public ModularMovementModelViz() {
init();
}
protected void init() {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
VisualizationInjector.addInteractionListener(this);
setOpaque(true);
setVisible(true);
this.movementModel = model;
menu = new JMenu("Mobility Model");
menu.add(createCheckboxAp());
menu.add(createCheckboxNodePositions());
menu.add(createCheckboxTrajectories());
}
public ModularMovementModelViz(ModularMovementModel model) {
init();
this.movementModel = model;
}
private JCheckBoxMenuItem createCheckboxAp() {
......@@ -104,6 +134,28 @@ public class ModularMovementModelViz extends JComponent
return checkBox;
}
private JCheckBoxMenuItem createCheckboxTrajectories() {
setupCalculatesTrajectories = AbstractLocalMovementStrategy.isCalculatingRouteSegments();
final JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(
"show node trajectories", showTrajectories);
checkBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
showTrajectories = checkBox.isSelected();
if (!setupCalculatesTrajectories) {
AbstractLocalMovementStrategy
.setCalculationOfRouteSegments(showTrajectories);
}
VisualizationInjector.invalidate();
}
});
if (!setupCalculatesTrajectories) {
AbstractLocalMovementStrategy
.setCalculationOfRouteSegments(showTrajectories);
}
return checkBox;
}
@Override
public void paint(Graphics g) {
super.paintComponent(g);
......@@ -112,6 +164,111 @@ public class ModularMovementModelViz extends JComponent
RenderingHints.VALUE_ANTIALIAS_ON);
if (showAttractionPoints) {
drawAttractionPoints(g2);
}
if (showNodePositions) {
for (SimLocationActuator comp : movementModel
.getAllLocationActuators()) {
drawNodePosition(g2, comp);
}
}
if (showTrajectories) {
for (TrajectoryVis tVis : trajectoryVisualizations.values()) {
tVis.drawTrajectory(g2);
}
}
}
@Override
public void onHostClick(long hostID, boolean isActive) {
if (isActive) {
Host h = Oracle.getHostByID(INodeID.get(hostID));
try {
RouteSensor routeSensor = h.getComponent(RouteSensor.class);
trajectoryVisualizations.put(hostID,
new TrajectoryVis(routeSensor));
} catch (ComponentNotAvailableException e) {
// ignore.
}
} else {
trajectoryVisualizations.remove(hostID);
}
}
/**
* Visualizes the movement trajectory of a given node.
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 10, 2017
*/
private class TrajectoryVis {
private final RouteSensor routeSensor;
public TrajectoryVis(RouteSensor routeSensor) {
this.routeSensor = routeSensor;
}
public void drawTrajectory(Graphics2D g2) {
Route rt = routeSensor.getRoute();
if (!rt.hasSegmentInformation()) {
return;
}
boolean alt = false;
for (RouteSegment segment : rt.getSegmentsAhead()) {
Location lastLoc = null;
g2.setColor(Color.MAGENTA);
if (alt) {
g2.setColor(Color.ORANGE);
}
alt = !alt;
for (Location loc : segment.getSegmentLocations()) {
if (lastLoc == null) {
lastLoc = loc;
g2.drawString(segment.getSegmentId(),
VisualizationInjector
.scaleValue(lastLoc.getLongitude()),
VisualizationInjector
.scaleValue(lastLoc.getLatitude()));
continue;
}
g2.setStroke(new BasicStroke(3.0f));
g2.drawLine(
VisualizationInjector
.scaleValue(lastLoc.getLongitude()),
VisualizationInjector
.scaleValue(lastLoc.getLatitude()),
VisualizationInjector
.scaleValue(loc.getLongitude()),
VisualizationInjector
.scaleValue(loc.getLatitude()));
lastLoc = loc;
}
}
}
}
/**
* Provides access super.paintComponent() for extending classes.
* @param g the Graphics object for painting.
*/
protected void paintSuper(Graphics g)
{
super.paintComponent(g);
}
/**
* Draws the attraction points. This method has been extracted from paint()
* to make it possible for extending class to override only this bit while leaving everything
* else untouched.
* @param g2 the Graphics2D object for painting.
*/
protected void drawAttractionPoints(Graphics2D g2)
{
for (AttractionPoint aPoint : movementModel.getAttractionPoints()) {
Point point = ((PositionVector) aPoint).asPoint();
// draw border
......@@ -122,14 +279,13 @@ public class ModularMovementModelViz extends JComponent
VisualizationInjector.scaleValue(point.y) - ATTR_PAD);
g2.setColor(COLOR_ATTR_POINT);
float alpha = 0.25f + (float) (aPoint.getWeight() / 2);
g2.setComposite(AlphaComposite
.getInstance(AlphaComposite.SRC_OVER, alpha));
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
g2.fillOval(
VisualizationInjector.scaleValue(point.x) - ATTR_PAD,
VisualizationInjector.scaleValue(point.y) - ATTR_PAD,
ATTR_PAD * 2 + 1, ATTR_PAD * 2 + 1);
g2.setColor(COLOR_ATTR_POINT);
int radius = (int) aPoint.getRadius() + ATTR_PAD;
int radius = VisualizationInjector.scaleValue(aPoint.getRadius()) + ATTR_PAD;
g2.drawOval(VisualizationInjector.scaleValue(point.x) - radius,
VisualizationInjector.scaleValue(point.y) - radius,
radius * 2 + 1, radius * 2 + 1);
......@@ -137,16 +293,25 @@ public class ModularMovementModelViz extends JComponent
}
}
if (showNodePositions) {
for (SimLocationActuator comp : movementModel
.getAllLocationActuators()) {
/**
* Draws the position of the node. This method has been extracted from paint()
* to make it possible for extending class to override only this bit while leaving everything
* else untouched. Instead of painting all of the nodes, only a specific one gets painted. This allows
* extending class to fall back to this implementation if one specific node could not be drawn for whatever reason.
* @param g2 the Graphics2D object for painting.
*/
protected void drawNodePosition(Graphics2D g2, SimLocationActuator comp)
{
Point2D pt = comp.getRealPosition().asPoint();
g2.setColor(Color.GRAY);
g2.fillOval((int) pt.getX() - NODE_PAD,
(int) pt.getY() - NODE_PAD, NODE_PAD * 2 + 1,
g2.fillOval(VisualizationInjector.scaleValue(pt.getX()) - NODE_PAD,
VisualizationInjector.scaleValue(pt.getY()) - NODE_PAD, NODE_PAD * 2 + 1,
NODE_PAD * 2 + 1);
}
}
protected void setMovementModel(ModularMovementModel model)
{
movementModel = model;
}
@Override
......
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.local.RouteImpl;
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.util.Either;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.NodeDebugMonitor;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
* This class is meant to be used with the RealWorldStreetsMovement
* and allows changes of the movement type and the used {@link ITransitionStrategy} mid-simulation
* on a per-host basis. It acts like the {@link ModularMovementModel}, but each of the {@link SimLocationActuator}s
* can have a different movement type and {@link ITransitionStrategy}. All routes and targets will be
* calculated accordingly. <BR><BR>
*
* Originally the whole movement system within the simonstrator platform was not intended to be manipulable
* by an application since only overlays were implemented which in a real world would reside on handheld devices
* for example and should therefore not be able to manipulate the movement of the node/user.
* But demand changed and for some systems it is inevitable to be able to control/influence the movement. Therefore
* this class was created to fill the gap and provide access to the movement from outside the internal system.
*
* USAGE:
* So, since the movement of a person in real life could not be controlled by anyone but the person itself,
* the access to this class is only provided from the simrunner project since it is responsible for the simulation
* of the "real-life" parts of the simonstrator platform. From within this project you have access to the
* {@link de.tud.kom.p2psim.impl.topology.DefaultTopologyComponent} from where you can access this movement model.
* If you want to use different movement types, all you have to do is
* (besides selecting this model in your config) call the {@link #setMovementType(SimLocationActuator, String)}
* for each of your components.<BR>
*
* The used {@link ITransitionStrategy} can be changed on runtime, too. However, the first
* TransitionStrategy specified in the config will be used as default, and will be applied if there is
* no further strategy specified for a specific host. To use multiple strategies, add them to your
* config just as the first one. To set a specific strategy for a specific host, call the {@link #setTransitionForComponent(SimLocationActuator, Class)}
* with the second parameter being the class of the transition strategy you want to use.
*
* NOTE: All the movement types you are using need to be specified in you config for the
* {@link RealWorldStreetsMovement}. E.g if you are using 'car' and 'foot' movement types,
* in you config the MovementType for the {@link RealWorldStreetsMovement} should be specified as 'car,foot'.
* If not done properly there won't be an error, but the movement behaviour will be strange.
*
* @author Clemens Krug
*/
public class ModularMultiTypeMovementModel extends ModularMovementModel
{
private HashMap<SimLocationActuator, String> movementTypes;
private HashMap<SimLocationActuator, ITransitionStrategy> transitions;
private HashMap<Class, ITransitionStrategy> supportedTransitions;
private LinkedList<MultiTypeMovementListener> movementListeners = new LinkedList<>();
/**
* Suppresses notifications to {@link de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy.AttractionAssignmentListener}s.
*/
private boolean suppressListenerNotify = false;
public ModularMultiTypeMovementModel()
{
super();
movementTypes = new HashMap<>();
transitions = new HashMap<>();
supportedTransitions = new HashMap<>();
}
@Override
public void initialize()
{
super.initialize();
suppressListenerNotify = true;
for(ITransitionStrategy strategy : supportedTransitions.values())
{
strategy.setAttractionPoints(transition.getAllAttractionPoints());
strategy.addAttractionAssignmentListener(this);
for (SimLocationActuator ms : moveableHosts) {
strategy.addComponent(ms);
}
}
suppressListenerNotify = false;
}
@Override
protected void doLocalMovement(SimLocationActuator ms, PositionVector destination)
{
assert localMovementStrategy instanceof RealWorldStreetsMovement: "ModularMultiTypeMovementModel can only be used with RealWorldStreetsMovement!";
Either<PositionVector, Boolean> either;
if(movementTypes.containsKey(ms)) either = ((RealWorldStreetsMovement) localMovementStrategy).nextPosition(ms, destination, movementTypes.get(ms));
else either = localMovementStrategy.nextPosition(ms, destination);
if (either.hasLeft()) {
ms.updateCurrentLocation(either.getLeft());
/*
* 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();
} else {
if(transitions.containsKey(ms)) transitions.get(ms).reachedAttractionPoint(ms);
else transition.reachedAttractionPoint(ms);
movementListeners.forEach(l -> l.onTransition(ms));
}
}
/**
* Sets the movement type for the specified {@link SimLocationActuator}. Movement types can be for example
* 'car' or 'foot'. Used types need to be specified in the config at the {@link RealWorldStreetsMovement}.
* @param ms The SimLocationActuator
* @param movementType the movement type
*/
public void setMovementType(SimLocationActuator ms, String movementType)
{
movementTypes.put(ms, movementType);
}
/**
* Returns the current movement type for this {@link SimLocationActuator} as String.
* @param ms The SimLocationActuator
* @return the current movement type
*/
public String getMovementType(SimLocationActuator ms)
{
return movementTypes.get(ms);
}
/**
* Return the currently used transitions strategy of the specified component
* @param ms the component
* @return the current transition strategy
*/
public ITransitionStrategy getTransitionForComponent(SimLocationActuator ms)
{
return transitions.get(ms);
}
/**
* Gets one of the supported transition strategies.
* @param strategy The class of the strategy which should be returned.
* @return The specified strategy
*/
public ITransitionStrategy getTransitionStrategy(Class strategy)
{
ITransitionStrategy selectedStrategy = supportedTransitions.get(strategy);
if(selectedStrategy == null)
{
throw new UnsupportedOperationException(
String.format("ModularMultiTypeMovementModel: TransitionStrategy %s ist not supported!", strategy.toString()));
}
return selectedStrategy;
}
/**
* Sets the {@link ITransitionStrategy} for the specified {@link SimLocationActuator}. Used strategies
* need to be registered in the config.
* @param ms The SimLocationActuator
* @param strategy the strategy to use
*/
public void setTransitionForComponent(SimLocationActuator ms, Class strategy)
{
changeTransitionStrategy(ms, getTransitionStrategy(strategy));
}
/**
* Changes the transition strategy of the specified {@link SimLocationActuator}.
* @param ms The SimLocationActuator
* @param newStrategy the new strategy to use
*/
private void changeTransitionStrategy(SimLocationActuator ms, ITransitionStrategy newStrategy)
{
ITransitionStrategy usedStrategy = transitions.containsKey(ms) ? transitions.get(ms) : transition;
newStrategy.updateTargetAttractionPoint(ms, usedStrategy.getAssignment(ms));
transitions.put(ms, newStrategy);
Monitor.log(ModularMultiTypeMovementModel.class, Monitor.Level.DEBUG, String.format("Client %s changed his transition strategy from %s to %s", ms.getHost().getId().toString(), usedStrategy.getClass(), newStrategy.getClass()));
}
/**
* Returns a list of points representing the current route of the component. Points are
* in x / y values of the own world.
* @param ms the component
* @return list of movement points.
*/
public List<PositionVector> getMovementPoints(SimLocationActuator ms)
{
return ((RealWorldStreetsMovement) localMovementStrategy).getMovementPoints(ms);
}
public RealWorldStreetsMovement getMovementStrategy()
{
return (RealWorldStreetsMovement) localMovementStrategy;
}
/**
* Sets the default {@link ITransitionStrategy} for the specified {@link SimLocationActuator}.
* @param ms The SimLocationActuator
*/
public void returnToDefaultTransition(SimLocationActuator ms)
{
transitions.remove(ms);
}
@Override
public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) {
if(transitions.containsKey(actuator)) transitions.get(actuator).updateTargetAttractionPoint(actuator, ap);
else transition.updateTargetAttractionPoint(actuator, ap);
}
@Override
public void setITransitionStrategy(ITransitionStrategy transition) {
if(supportedTransitions.size() == 0) this.transition = transition;
supportedTransitions.put(transition.getClass(), transition);
}
@Override
public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
if(transitions.containsKey(actuator)) return transitions.get(actuator).getAssignment(actuator);
else return transition.getAssignment(actuator);
}
@Override
public void updatedAttractionAssignment(SimLocationActuator component, AttractionPoint newAssignment) {
//Notifications of listeners get suppressed in setup phase to prevent multiple assignments of destinations.
if(suppressListenerNotify) return;
super.updatedAttractionAssignment(component, newAssignment);
}
public void addMovementListener(MultiTypeMovementListener listener)
{
movementListeners.add(listener);
}
public void removeMovementListener(MultiTypeMovementListener listener)
{
movementListeners.remove(listener);
}
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
/**
* Listener for the {@link ModularMultiTypeMovementModel} to get
* informed about important changes in the movement.
*
* @author Clemens Krug
*/
public interface MultiTypeMovementListener
{
/**
* Gets called when the {@link SimLocationActuator} can't move
* any closer to the destination. This does NOT necessarily mean that he reached the
* destination!
*/
void onTransition(SimLocationActuator ms);
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import java.util.LinkedHashSet;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor;
/**
* The OSM-based models provide an implementation of the {@link RouteSensor},
* which is added as a new host component. It is created by supporting mobility
* models, registers itself with the host container and can then be retrieved
* via the host container from w.g., a local movement strategy.
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 10, 2017
*/
public class RouteSensorComponent implements RouteSensor {
private final SimLocationActuator actuator;
private Route currentRoute;
private final Set<RouteListener> listeners;
private final Set<RouteSegmentListener> segmentListeners;
public RouteSensorComponent(SimLocationActuator actuator) {
this.actuator = actuator;
this.listeners = new LinkedHashSet<>();
this.segmentListeners = new LinkedHashSet<>();
actuator.getHost().registerComponent(RouteSensorComponent.this);
}
@Override
public void initialize() {
//
}
@Override
public void shutdown() {
//
}
public SimLocationActuator getActuator() {
return actuator;
}
@Override
public Host getHost() {
return actuator.getHost();
}
@Override
public Route getRoute() {
return currentRoute;
}
@Override
public void addRouteListener(RouteListener listener) {
listeners.add(listener);
}
@Override
public void removeRouteListener(RouteListener listener) {
listeners.remove(listener);
}
@Override
public void addRouteSegmentListener(RouteSegmentListener listener) {
segmentListeners.add(listener);
}
@Override
public void removeRouteSegmentListener(RouteSegmentListener listener) {
segmentListeners.remove(listener);
}
/*
* The following methods are used by the mobility models.
*/
public void setNewRoute(Route newRoute) {
// notifies listeners
listeners.forEach(l -> l.onChangedRoute(this, currentRoute, newRoute));
currentRoute = newRoute;
}
public void reachedDestination() {
// notifies listeners
listeners.forEach(l -> l.onReachedDestination(this, currentRoute));
}
public Set<RouteSegmentListener> getSegmentListeners() {
return segmentListeners;
}
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
/**
* A basic attraction point, as simple as it can get. Really just a named location
* without any checks performed.
*/
public class BasicAttractionPoint extends PositionVector implements AttractionPoint
{
private String name;
private double weight = 0;
private double radius = 0;
public BasicAttractionPoint(String name, PositionVector pos)
{
super(pos);
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public double getWeight() {
return weight;
}
@Override
public double getRadius() {
return radius;
}
@Override
public void setWeight(double weight) {
this.weight = weight;
}
@Override
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public AttractionPoint clone(String newName) {
return new BasicAttractionPoint(newName, this);
}
}
......@@ -38,8 +38,12 @@ import java.net.URL;
import javax.swing.JComponent;
import javax.swing.JMenu;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.GPSCalculation;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
public class ShowMapQuestMapViz extends JComponent
implements IMapVisualization {
......@@ -66,25 +70,33 @@ public class ShowMapQuestMapViz extends JComponent
private void initializeImage() {
if (!initialized) {
PositionVector worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
tempImageFilePath = tempImageFilePath + "mapquest"
+ GPSCalculation.getLatCenter()
+ GPSCalculation.getLonCenter() + GPSCalculation.getZoom()
+ VisualizationInjector.getWorldX()
+ VisualizationInjector.getWorldY() + mapType + ".jpg";
+ GPSCalculation.getLatCenter() + "_"
+ GPSCalculation.getLonCenter() + "_" + GPSCalculation.getZoom() + "_"
+ worldDimensions.getX() + "_"
+ worldDimensions.getY() + mapType + ".jpg";
// Check if the file with same properties (same location) already
// exists
File f = new File(tempImageFilePath);
if (!f.exists()) {
try {
//Based on the meters per pixel, the needed height and width in pixels can be determined.
int pxx = (int) (worldDimensions.getX() / GPSCalculation.getMetersPerPixel());
int pxy = (int) (worldDimensions.getY() / GPSCalculation.getMetersPerPixel());
String imageUrl = "http://www.mapquestapi.com/staticmap/v4/getmap?key="
+ mapQuestKey + "&type=" + mapType
+ "&imagetype=jpeg&center="
+ GPSCalculation.getLatCenter() + ","
+ GPSCalculation.getLonCenter() + "&zoom="
+ ((GPSCalculation.getZoom()) + 1) + "&size="
+ VisualizationInjector.getWorldX() + ","
+ VisualizationInjector.getWorldY();
+ ((GPSCalculation.getZoom())) + "&size="
+ pxx + ","
+ pxy;
URL url = new URL(imageUrl);
InputStream is = url.openStream();
OutputStream os = new FileOutputStream(tempImageFilePath);
......
package de.tud.kom.p2psim.impl.topology.movement.modularosm.movementIconVisualisation;
/**
* Mapping of objects to icons, for usage with the {@link ModularMovementIconVis}, especially
* if the config files.
*
* @author Clemens Krug
*/
public class IconMapping
{
private String object;
private String iconpath;
public void setObject(String icon)
{
object = icon;
}
public void setIconPath(String path)
{
iconpath = path;
}
public String getObject() {
return object;
}
public String getIconpath() {
return iconpath;
}
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm.movementIconVisualisation;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModelViz;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tudarmstadt.maki.simonstrator.api.*;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* Visualises the different nodes as icons instead of these lame dots.
* The icons are configured entirely in the config files. To use this visualisation
* the first thing to do is specify this {@link ModularMovementIconVis} as visualisation for
* your modular movement model. To add icons to the visualisation the class {@link IconMapping} is used within the tags.
* You have two tags available for different kind of icons:<BR><BR>
* <p>
* 1. Class icons: These icons are used dependent on the class of the components the host includes. You can
* add a class icon by using the &lt;ClassIcon> tag you config and setting the fully qualified classname
* of you components as object. If a host has multiple components with different specified icons, the first one will be used.<BR><BR>
* <p>
* 2. State icons: These icons are used dependent on the state of a host and take precedence over the class icons. You
* can add them via the &lt;StateIcon> tag. The object should be a String representing the state. When
* using these types of icons, you need to set a {@link StateSelector} for this class in the config.<BR><BR>
* <p>
* For example usage, see the movement_social.xml config for the resourceAllocation overlay.
*
* @author Clemens Krug
*/
public class ModularMovementIconVis extends ModularMovementModelViz implements EventHandler
{
private HashMap<Class, String> pathMap;
private HashMap<Class, Image> classIconMap;
private HashMap<String, String> stateMap;
private HashMap<String, Image> stateIconMap;
private StateSelector stateSelector;
private boolean init = false;
public ModularMovementIconVis()
{
init();
pathMap = new HashMap<>();
classIconMap = new HashMap<>();
stateMap = new HashMap<>();
stateIconMap = new HashMap<>();
// scheduling initalization!
de.tudarmstadt.maki.simonstrator.api.Event.scheduleImmediately(this, null, 0);
}
private void initialize()
{
assert !init : "ModularMovementIconVis: Was already initialized!";
VisualizationTopologyView.VisualizationInjector.getTopologyView().setShowNodes(false);
for (Map.Entry<Class, String> e : pathMap.entrySet())
{
try
{
Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST);
classIconMap.put(e.getKey(), icon);
} catch (IOException ioe)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue());
}
}
for (Map.Entry<String, String> e : stateMap.entrySet())
{
assert stateSelector != null : "There must be a state selector specified when using state icons!";
try
{
Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST);
stateIconMap.put(e.getKey(), icon);
} catch (IOException ioe)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue());
}
}
init = true;
}
@Override
public void paint(Graphics g)
{
super.paintSuper(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (showAttractionPoints)
{
super.drawAttractionPoints(g2);
}
if (showNodePositions)
{
for (SimLocationActuator comp : movementModel
.getAllLocationActuators())
{
drawNodePosition(g2, comp);
}
}
}
@Override
protected void drawNodePosition(Graphics2D g2, SimLocationActuator comp)
{
boolean iconNotFound = true;
Host host = comp.getHost();
Point2D pt = comp.getRealPosition().asPoint();
pt = new Point2D.Double(VisualizationTopologyView.VisualizationInjector.scaleValue(pt.getX()), VisualizationTopologyView.VisualizationInjector.scaleValue(pt.getY()));
g2.setColor(Color.GRAY);
// Check if the component has a specified state, as this would have precedence over the classIcon.
if (stateSelector != null)
{
String state = stateSelector.getState(comp);
if (stateIconMap.containsKey(state))
{
Image icon = stateIconMap.get(state);
int width = icon.getWidth(null);
int height = icon.getHeight(null);
g2.drawImage(icon, (int) pt.getX() - width / 2, (int) pt.getY() - height / 2, null);
return;
}
}
// If not, check if there's a class icon available
for (Map.Entry<Class, Image> e : classIconMap.entrySet())
{
try
{
host.getComponent(e.getKey());
Image icon = e.getValue();
int width = icon.getWidth(null);
int height = icon.getHeight(null);
g2.drawImage(icon, (int) pt.getX() - width / 2, (int) pt.getY() - height / 2, null);
iconNotFound = false;
break;
} catch (ComponentNotAvailableException nae)
{
iconNotFound = true;
}
}
// If not, use standard visualisation
if (iconNotFound) super.drawNodePosition(g2, comp);
}
@Override
public void eventOccurred(Object content, int type)
{
if (type == 0)
{
initialize();
}
}
public void setClassIcon(IconMapping classIcon)
{
try
{
pathMap.put(Class.forName(classIcon.getObject()), classIcon.getIconpath());
} catch (ClassNotFoundException e)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Class %s not found!", classIcon.getObject());
}
}
public void setStateIcon(IconMapping stateIcon)
{
stateMap.put(stateIcon.getObject(), stateIcon.getIconpath());
}
public void setStateSelector(StateSelector selector)
{
this.stateSelector = selector;
}
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm.movementIconVisualisation;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
/**
* Interface for the state selector which shall be used in conjunction with the
* {@link ModularMovementIconVis} in order to use state icons.
*
* @author Clemens Krug
*/
public interface StateSelector
{
/**
* Returns the state of the host as string. The returned state
* must be equal to the one specified in the state-icon mapping to have any effect.
* The state of a host can not be null! In case there is no state matched which has an icon
* specified, you can return whatever string you like.
*
* @param ms The host of whom the state should be determined.
* @return The state of the host as string, not null.
*/
String getState(SimLocationActuator ms);
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm.transition;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import java.util.*;
/**
* This {@link ITransitionStrategy} works with manual assignments. Initially components will be assigned
* one of the attraction points, but at any further point, the set list of attraction points doesn't really matter.
* New target can be assigned by using the {@link #updateTargetAttractionPoint(SimLocationActuator, AttractionPoint)} method,
* otherwise the components will stop moving upon reaching their target.
*
* @author Clemens Krug
*/
public class ManualAssignmentStrategy implements ITransitionStrategy
{
private LinkedHashSet<AttractionPoint> aPoints = new LinkedHashSet<>();
private Map<SimLocationActuator, AttractionPoint> assignments = new HashMap<>();
private List<AttractionAssignmentListener> listeners = new LinkedList<>();
@Override
public AttractionPoint getAssignment(SimLocationActuator comp)
{
return assignments.get(comp);
}
@Override
public void addAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.add(listener);
}
@Override
public void removeAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.remove(listener);
}
@Override
public void setAttractionPoints(Collection<AttractionPoint> attractionPoints) {
aPoints.addAll(attractionPoints);
}
@Override
public Set<AttractionPoint> getAllAttractionPoints() {
return aPoints;
}
@Override
public void addComponent(SimLocationActuator ms) {
if(!assignments.containsKey(ms))
{
AttractionPoint aPoint = aPoints.iterator().next();
assignments.put(ms, aPoint);
}
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, assignments.get(ms)));
}
@Override
public void reachedAttractionPoint(SimLocationActuator ms) {
//Nothing to do.
}
@Override
public void updateTargetAttractionPoint(SimLocationActuator comp, AttractionPoint attractionPoint) {
assignments.put(comp, attractionPoint);
listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
}
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm.transition;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.BasicAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
/**
* This {@link ITransitionStrategy} makes clients move around randomly in a specified area. You can specify the target
* area center via the {@link #updateTargetAttractionPoint(SimLocationActuator, AttractionPoint)} method. The client will then start
* to roam the area randomly till a new target area is assigned.
*
* @author Clemens Krug
*/
public class RandomInAreaTransitionStrategy implements ITransitionStrategy
{
private final Random random = Randoms
.getRandom(RandomInAreaTransitionStrategy.class);
private LinkedHashSet<AttractionPoint> aPoints = new LinkedHashSet<>();
/**
* These are the target area centers the clients have assigned.
*/
private Map<SimLocationActuator, AttractionPoint> assignments = new HashMap<>();
/**
* These are the current spots inside the target area where the client is currently heading.
*/
private Map<SimLocationActuator, AttractionPoint> currentTarget = new HashMap<>();
private Map<SimLocationActuator, Integer> currentSearchRadius = new HashMap<>();
private List<AttractionAssignmentListener> listeners = new LinkedList<>();
/**
* The radius the target area should have. Should be set via XML config file.
*/
private int defaultRadius;
@Override
public AttractionPoint getAssignment(SimLocationActuator comp)
{
return currentTarget.get(comp);
}
@Override
public void addAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.add(listener);
}
@Override
public void removeAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.remove(listener);
}
@Override
public void setAttractionPoints(Collection<AttractionPoint> attractionPoints) {
aPoints.addAll(attractionPoints);
}
@Override
public Set<AttractionPoint> getAllAttractionPoints() {
return aPoints;
}
@Override
public void addComponent(SimLocationActuator ms) {
if(!assignments.containsKey(ms))
{
AttractionPoint aPoint = aPoints.iterator().next();
assignments.put(ms, aPoint);
currentTarget.put(ms, nextRandomPosition(aPoint, defaultRadius));
currentSearchRadius.put(ms, defaultRadius);
}
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
}
@Override
public void reachedAttractionPoint(SimLocationActuator ms) {
currentTarget.put(ms, nextRandomPosition(assignments.get(ms), currentSearchRadius.get(ms)));
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
}
@Override
public void updateTargetAttractionPoint(SimLocationActuator comp, AttractionPoint attractionPoint) {
assignments.put(comp, attractionPoint);
currentTarget.put(comp, nextRandomPosition(attractionPoint, currentSearchRadius.get(comp)));
listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
}
public void setSearchRadiusForComponent(SimLocationActuator ms, int radius)
{
currentSearchRadius.put(ms, radius);
}
public void setDefaultRadius(int radius)
{
this.defaultRadius = radius;
}
/**
* Calculates a random point within a given circular area.
* @param center The center of the area.
* @param radius The radius of the area.
* @return A random position within the area.
*/
private BasicAttractionPoint nextRandomPosition(Location center, int radius)
{
assert radius > 0 : "An area radius must be specified for the RandomInAreaTransitionStrategy! Did you set the 'DefaultRadius' property for this transition?";
double x = center.getLongitude();
double y = center.getLatitude();
double newX = -1;
double newY = -1;
int tries = 0;
while(newX < 0.0 || newX > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getX()
|| newY < 0.0 || newY > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getY())
{
double calcRadius = random.nextDouble() * radius;
double calcAngle = random.nextDouble() * 360;
newX = x + Math.sin(calcAngle) * calcRadius;
newY = y + Math.cos(calcAngle) * calcRadius;
tries++;
if(tries > 100) throw new AssertionError("Unable to find a valid target destination within <100 tries.");
}
Monitor.log(this.getClass(), Monitor.Level.DEBUG, "Next random position is " + newX + " / " + newY);
return new BasicAttractionPoint("RNDPOS", new PositionVector(newX, newY));
}
}
......@@ -110,8 +110,8 @@ public class CsvPlacement implements PlacementModel {
if (XY.getX() > world.getX() || XY.getY() > world.getY() || XY.getX() < 0
|| XY.getY() < 0) {
// System.err.println("Skipped entry " + x + ";"
// + y);
// System.err.println("Skipped entry " + x + ";"
// + y);
continue;
}
......
......@@ -20,6 +20,7 @@
package de.tud.kom.p2psim.impl.topology.views;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
......@@ -30,7 +31,6 @@ import de.tud.kom.p2psim.api.linklayer.mac.Link;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
import de.tud.kom.p2psim.api.linklayer.mac.MacLayer;
import de.tud.kom.p2psim.api.linklayer.mac.PhyType;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.api.topology.obstacles.ObstacleModel;
import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.topology.PositionVector;
......@@ -44,7 +44,6 @@ import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.handover.HandoverSensor;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
import edu.emory.mathcs.backport.java.util.Arrays;
/**
* This topology view offers a topology for mobile apps - mobile clients
......@@ -529,8 +528,9 @@ public class FiveGTopologyView extends AbstractTopologyView<CellLink> {
public long getBandwidth(boolean isBroadcast) {
assert (apLinkData != null && supportsAccessPoints)
|| apLinkData == null;
return apLinkData != null ? apLinkData.getBandwidth(isUpload)
long tmp = apLinkData != null ? apLinkData.getBandwidth(isUpload)
: linkData.getBandwidth(isUpload);
return tmp;
}
@Override
......
......@@ -802,10 +802,29 @@ public class VisualizationTopologyView extends JFrame
SCALE = scale;
}
/**
* Returns the SCALED value of the given value. This is to be used by
* visualizations!
*
* @param value
* @return
*/
public static int scaleValue(double value) {
return (int) (value * getScale());
}
/**
* Returns the original value (in meters) of the given scaled value.
* This should be used if you need map values in meters from a scaled
* value. E.g. to find segments in a to meters mapped vector.
*
* @param value
* @return
*/
public static double originalValue(int value) {
return value * (1 / getScale());
}
/**
* Recommended way to add a custom visualization layer.
*
......
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.views.fiveg;
import java.util.HashMap;
import java.util.HashSet;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.fiveg.models.AbstractModel;
import de.tud.kom.p2psim.impl.topology.views.fiveg.utils.Direction;
import de.tud.kom.p2psim.impl.topology.views.fiveg.utils.ParameterType;
import de.tud.kom.p2psim.impl.topology.views.visualization.world.ModelFiveGVisualization;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* A grid based FiveG model-based database.
*
* This module allows to add transmission models to each segment of the map to
* accommodate different behaviors of wireless network transmission
* technologies. It enables the developer to define different models for
* **Latency**, **Bandwidth** and **Drop Rate** (called *characteristics*), for
* **Upload** and **Download** and for every **Segment**.
*
* For more information see README.md in
* de.tud.kom.p2psim.impl.topology.views.fiveg.models.README.md
*
* @author Nils Richerzhagen
* @version 1.0, Jul 7, 2017
*/
public class ModelBasedSegmentDatabase
extends AbstractGridBasedTopologyDatabase {
final Integer DEFAULT_SEGMENT_ID = new Integer(-1);
// Models[Type][SegID][Up/Down/Both]
HashMap<ParameterType, HashMap<Integer, HashMap<Direction, AbstractModel>>> models = new HashMap<>();
public ModelBasedSegmentDatabase() {
super(100, true);
super.setSupportCloudlets(true);
}
@Override
protected Entry createEntryFor(int segmentID, boolean isCloudlet) {
return new ModelBasedEntry(segmentID);
}
@Override
public void setEnableVis(boolean enableVis) {
if (enableVis == true) {
Event.scheduleImmediately(new EventHandler() {
@Override
public void eventOccurred(Object content, int type) {
ModelFiveGVisualization viz = ModelFiveGVisualization.getInstance();
viz.setDatabase(ModelBasedSegmentDatabase.this);
VisualizationInjector.injectComponent(viz);
}
}, null, 0);
}
}
/**
* Add a model to Database
*
* @param model
* the model to add
*/
public void setModel(AbstractModel model) {
// Enable debugging
model.debug();
// Check if model is valid
ParameterType type = model.getParameterType();
if (type == null) {
throw new ConfigurationException(
"Model is not defined for any Parameter Type. Please specify the Type for this Model.");
}
Direction dir = model.getDirection();
if (dir == null) {
throw new ConfigurationException(
"Model is not defined for any Direction. Please specify the Direction for this Model.");
}
Integer segmentID = new Integer(model.getSegmentID());
// Check if there is no contradicting model
if (models.containsKey(type)) {
// There is already this Type
if (models.get(type).containsKey(segmentID)) {
// There is already this SegID
if (models.get(type).get(segmentID).containsKey(dir)
|| (models.get(type).get(segmentID)
.containsKey(Direction.BOTH)
&& (dir.equals(Direction.DOWNLOAD)
|| dir.equals(Direction.UPLOAD)))
|| (dir.equals(Direction.BOTH) && (models.get(type)
.get(segmentID).containsKey(Direction.DOWNLOAD)
|| models.get(type).get(segmentID)
.containsKey(Direction.UPLOAD)))) {
// There is already a model defined
throw new ConfigurationException(
"Conflicting Models for SegmentID " + segmentID
+ ", Type " + type.toString()
+ " and Direction " + dir.toString());
} else {
// Add new model
models.get(type).get(segmentID).put(dir, model);
}
} else {
// Add new SegmentID
// Direction => Model
HashMap<Direction, AbstractModel> tmp1 = new HashMap<>();
tmp1.put(dir, model);
models.get(type).put(segmentID, tmp1);
}
} else {
// Add new model
// Direction => Model
HashMap<Direction, AbstractModel> tmp1 = new HashMap<>();
tmp1.put(dir, model);
// SegID => [Direction => Model]
HashMap<Integer, HashMap<Direction, AbstractModel>> tmp2 = new HashMap<>();
tmp2.put(segmentID, tmp1);
models.put(type, tmp2);
}
}
/**
* Get the model for the specific combination
*
* @param segID
* The SegmentID to get the model for
* @param type
* The Type of the Parameter
* @param isUpload
* Is it a Up or Downlink
* @return The Model for the given segment
*/
AbstractModel getModel(int segID, ParameterType type, Boolean isUpload) {
Integer segmentID = new Integer(segID);
Direction dir = Direction.DOWNLOAD;
if (isUpload) {
dir = Direction.UPLOAD;
}
// Check if type exists
if (!this.models.containsKey(type)) {
throw new ConfigurationException(
"No Model is defined for " + type + ".");
}
// Check if there is a specific model
if(this.models.get(type).containsKey(segmentID) && this.models.get(type).get(segmentID).containsKey(dir)) {
return this.models.get(type).get(segmentID).get(dir);
}
// Check if there is a BOTH model in this segment
if(this.models.get(type).containsKey(segmentID) && this.models.get(type).get(segmentID).containsKey(Direction.BOTH)) {
return this.models.get(type).get(segmentID).get(Direction.BOTH);
}
// Check default model for specific model
if(this.models.get(type).containsKey(DEFAULT_SEGMENT_ID) && this.models.get(type).get(DEFAULT_SEGMENT_ID).containsKey(dir)) {
return this.models.get(type).get(DEFAULT_SEGMENT_ID).get(dir);
}
// Check if there is a default BOTH model
if(this.models.get(type).containsKey(DEFAULT_SEGMENT_ID) && this.models.get(type).get(DEFAULT_SEGMENT_ID).containsKey(Direction.BOTH)) {
return this.models.get(type).get(DEFAULT_SEGMENT_ID).get(Direction.BOTH);
}
throw new ConfigurationException(
"No Model is defined for Type " + type + ", Segment ID "
+ segmentID + " and Direction " + dir + ".");
}
public class ModelBasedEntry implements FiveGTopologyDatabase.Entry {
// How is a overload defined
// FIXME Can the time in the Latency result in problems if the drop-rate is set to 100%?
private final long OVERLOAD_LATENCY = 9999 * Time.MILLISECOND;
private final long OVERLOAD_BANDWIDTH = 1;
private final double OVERLOAD_DROPRATE = 1;
// When is a node considered overloaded
private final long THRESHOLD_LATENCY = Time.SECOND;
private final long THRESHOLD_BANDWIDTH = 10;
private final double THRESHOLD_DROPRATE = 1;
private final double YELLOW_INDICATOR = .8;
// Other storage
private final int segment;
private boolean isAvailable = true;
private HashSet<MacAddress> hostsInSegment = new HashSet<>();
private boolean overload;
// The current metrics of this segment
private long bandUp;
private long bandDown;
private long latUp;
private long latDown;
private double dropUp;
private double dropDown;
/**
* Create a new entry for the given segment
*
* @param segment
*/
public ModelBasedEntry(int segment) {
this.segment = segment;
calc();
}
@Override
public int getSegmentID() {
return segment;
}
/**
* A host leaves this segment
*/
public void onHostLeavesSegment(MacAddress hostAddr) {
// Remove MAC from current users
this.hostsInSegment.remove(hostAddr);
calc();
}
/**
* A host enters this segment
*/
public void onHostEntersSegment(MacAddress hostAddr) {
// Add MAC to current users
this.hostsInSegment.add(hostAddr);
calc();
}
@Override
public double getDropProbability(boolean isUpload) {
// Segment is overloaded or not available return overloaded drop
// probability
if (!isAvailable || overload) {
return OVERLOAD_DROPRATE;
}
// Return calculated drop probability
if (isUpload) {
return dropUp;
} else {
return dropDown;
}
}
@Override
public long getLatency(boolean isUpload) {
// Segment is overloaded or not available return overloaded latency
if (!isAvailable || overload) {
return OVERLOAD_LATENCY;
}
// Return calculated latency
if (isUpload) {
return latUp;
} else {
return latDown;
}
}
@Override
public long getBandwidth(boolean isUpload) {
// Segment is overloaded or not available return overloaded
// bandwidth
if (!isAvailable || overload) {
return OVERLOAD_BANDWIDTH;
}
// Return calculated bandwidth
if (isUpload) {
return bandUp;
} else {
return bandDown;
}
}
@Override
public boolean isAvailable() {
return isAvailable;
}
@Override
public void setAvailability(boolean isAvailable) {
this.isAvailable = isAvailable;
}
public int getStatus(ParameterType type, Direction dir) {
if(type.equals(ParameterType.BANDWIDTH) && dir.equals(Direction.UPLOAD)) {
if(this.bandUp <= THRESHOLD_BANDWIDTH) {
return 2;
}
if(this.bandUp < ((2 - YELLOW_INDICATOR) * THRESHOLD_BANDWIDTH)) {
return 1;
}
return 0;
}
if(type.equals(ParameterType.BANDWIDTH) && dir.equals(Direction.DOWNLOAD)) {
if(this.bandDown <= THRESHOLD_BANDWIDTH) {
return 2;
}
if(this.bandDown < ((2 - YELLOW_INDICATOR) * THRESHOLD_BANDWIDTH)) {
return 1;
}
return 0;
}
if(type.equals(ParameterType.DROPRATE) && dir.equals(Direction.UPLOAD)) {
if(this.dropUp >= THRESHOLD_DROPRATE) {
return 2;
}
if(this.dropUp > (YELLOW_INDICATOR * THRESHOLD_DROPRATE)) {
return 1;
}
return 0;
}
if(type.equals(ParameterType.DROPRATE) && dir.equals(Direction.DOWNLOAD)) {
if(this.dropDown >= THRESHOLD_DROPRATE) {
return 2;
}
if(this.dropDown > (YELLOW_INDICATOR * THRESHOLD_DROPRATE)) {
return 1;
}
return 0;
}
if(type.equals(ParameterType.LATENCY) && dir.equals(Direction.UPLOAD)) {
if(this.latUp >= THRESHOLD_LATENCY) {
return 2;
}
if(this.latUp > ((2 - YELLOW_INDICATOR) * THRESHOLD_LATENCY)) {
return 1;
}
return 0;
}
if(type.equals(ParameterType.LATENCY) && dir.equals(Direction.DOWNLOAD)) {
if(this.latDown >= THRESHOLD_LATENCY) {
return 2;
}
if(this.latDown > ((2 - YELLOW_INDICATOR) * THRESHOLD_LATENCY)) {
return 1;
}
return 0;
}
return 0;
}
public boolean isOverloaded() {
return overload;
}
public int getHostsInSegment() {
return this.hostsInSegment.size();
}
/**
* Recalculate every metric when a host leaves or enters
*/
private void calc() {
int users = this.hostsInSegment.size();
// Assume not overloaded
this.overload = false;
// Calc Bandwidth
this.bandUp = getModel(getSegmentID(), ParameterType.BANDWIDTH,
true).getLong(users);
this.bandDown = getModel(getSegmentID(), ParameterType.BANDWIDTH,
false).getLong(users);
if (bandDown <= THRESHOLD_BANDWIDTH
|| bandUp <= THRESHOLD_BANDWIDTH) {
overload = true;
}
// Calc Latency
this.latUp = getModel(getSegmentID(), ParameterType.LATENCY, true)
.getLong(users);
this.latDown = getModel(getSegmentID(), ParameterType.LATENCY,
false).getLong(users);
if (latUp >= THRESHOLD_LATENCY || latDown >= THRESHOLD_LATENCY) {
overload = true;
}
// Calc Droprate
this.dropUp = getModel(getSegmentID(), ParameterType.DROPRATE, true)
.getDouble(users);
this.dropDown = getModel(getSegmentID(), ParameterType.DROPRATE,
false).getDouble(users);
if (dropUp >= THRESHOLD_DROPRATE
|| dropDown >= THRESHOLD_DROPRATE) {
overload = true;
}
}
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.views.fiveg.models;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.views.FiveGTopologyView;
import de.tud.kom.p2psim.impl.topology.views.fiveg.ModelBasedSegmentDatabase;
import de.tud.kom.p2psim.impl.topology.views.fiveg.utils.Direction;
import de.tud.kom.p2psim.impl.topology.views.fiveg.utils.Graph;
import de.tud.kom.p2psim.impl.topology.views.fiveg.utils.ParameterType;
/**
* Abstract base model for the {@link FiveGTopologyView} when using the {@link ModelBasedSegmentDatabase}.
*
* @author Nils
* @version 1.0, 05.03.2017
*/
public abstract class AbstractModel {
// Storage
private int segmentID = -1;
private ParameterType type;
private Direction dir = Direction.BOTH;
// Is debug enabled for this model
private boolean debug = false;
public void setSegmentID(int segmentid) {
assert segmentid > 0;
this.segmentID = segmentid;
}
public int getSegmentID() {
return this.segmentID;
}
/**
* Set the parameter type {@link ParameterType}
* @param param
*/
public void setParameterType(String param) {
param = param.toUpperCase();
// Check if type is valid
try {
this.type = ParameterType.valueOf(param);
} catch (IllegalArgumentException e) {
throw new ConfigurationException(
"The Parameter " + param + " is unknown. Please select one of "
+ ParameterType.printTypes());
}
if(this.type == null) {
throw new ConfigurationException(
"The Parameter " + param + " is unknown. Please select one of "
+ ParameterType.printTypes());
}
}
public ParameterType getParameterType() {
return type;
}
/**
* Set the direction of model {@link Direction}
* @param param
*/
public void setDirection(String param) {
param = param.toUpperCase();
try {
this.dir = Direction.valueOf(param);
} catch (IllegalArgumentException e) {
throw new ConfigurationException(
"Direction " + param + " is unknown. Please select one of "
+ Direction.printTypes());
}
if(this.type == null) {
throw new ConfigurationException(
"Direction " + param + " is unknown. Please select one of "
+ Direction.printTypes());
}
}
public Direction getDirection() {
return dir;
}
/**
* Enable debugging - visualization of the model set in the config.
*
* @param debug
*/
public void setDebug(boolean debug) {
this.debug = debug;
}
public boolean getDebug() {
return this.debug;
}
public abstract long getLong(int users);
public abstract double getDouble(int users);
/**
* Debug this model
*/
public void debug() {
Graph test = new Graph();
test.setModel(this);
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.views.fiveg.models;
/**
* A Constant Model which return always the constant value C
* c(u) = C
* @author Marc Schiller
* @version 1.0, 15 Dec 2016
*/
public class ConstantModel extends AbstractModel {
private double c = 0;
public void setC(double c) {
this.c = c;
}
@Override
public long getLong(int users) {
return (long) this.c;
}
@Override
public double getDouble(int users) {
return this.c;
}
public String toString() {
return "Constant Model: c(u) = " + c;
}
}
......@@ -18,45 +18,63 @@
*
*/
package de.tud.kom.p2psim.impl.topology.movement.local;
package de.tud.kom.p2psim.impl.topology.views.fiveg.models;
/**
* A cut off model based on the heaviside step function.
*
* https://de.wikipedia.org/wiki/Heaviside-Funktion
*
* cut(u) = a * θ(c * u + d) + b
* @author Marc Schiller
* @version 1.0, 15 Dec 2016
*/
public class CutOffModel extends AbstractModel {
import com.graphhopper.util.PointList;
private double a = 1;
import de.tud.kom.p2psim.impl.topology.PositionVector;
private double b = 0;
public class RealWorldMovementPoints {
private double c = 1;
private PositionVector start;
private PositionVector destination;
private PointList pointList;
private int actualIndex;
private double d = 0;
public RealWorldMovementPoints(PositionVector start, PositionVector destination, PointList pointList, int actualIndex) {
this.start = start;
this.destination = destination;
this.pointList = pointList;
this.actualIndex = actualIndex;
public void setA(double a) {
this.a = a;
}
public PositionVector getStart() {
return start;
public void setB(double b) {
this.b = b;
}
public void setStart(PositionVector start) {
this.start = start;
public void setC(double c) {
this.c = c;
}
public PositionVector getDestination() {
return destination;
public void setD(double d) {
this.d = d;
}
public void setDestination(PositionVector destination) {
this.destination = destination;
private double heaviside(double x) {
if(x < 0) {
return 0;
} else {
return 1;
}
public PointList getPointList() {
return pointList;
}
public void setPointList(PointList pointList) {
this.pointList = pointList;
@Override
public long getLong(int users) {
return (long) getDouble(users);
}
public int getActualIndex() {
return this.actualIndex;
@Override
public double getDouble(int users) {
return this.a * heaviside(this.c * users + this.d) + this.b;
}
@Override
public String toString() {
return "CutOffModel: cut(u) = " + this.a + " * θ(" + this.c + " * u + " + this.d + ") + " + this.b;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.views.fiveg.models;
/**
* An exponential model
* exp(u) = a * e^(c * (u - d)) + b
* @author Marc Schiller
* @version 1.0, 15 Dec 2016
*/
public class ExponentialModel extends AbstractModel {
// exp(u) = a * e ^(c * u + d) + b
private double a = 1;
private double b = 0;
private double c = 1;
private double d = 0;
public void setA(double a) {
this.a = a;
}
public void setB(double b) {
this.b = b;
}
public void setC(double c) {
this.c = c;
}
public void setD(double d) {
this.d = d;
}
@Override
public long getLong(int users) {
return (long) getDouble(users);
}
@Override
public double getDouble(int users) {
return this.a * Math.exp(this.c * (users - this.d)) + this.b;
}
@Override
public String toString() {
return "Exponential Model: exp(u) = " + this.a + " * e^(" + this.c + " * (u - " + this.d + ")) + " + this.b;
}
}
/*
* 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 <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.views.fiveg.models;
/**
* Linear Model
* lin(u) = a * u + b
* @author Marc Schiller
* @version 1.0, 15 Dec 2016
*/
public class LinearModel extends AbstractModel {
private double a = 1;
private double b = 0;
public void setA(double a) {
this.a = a;
}
public void setB(double b) {
this.b = b;
}
@Override
public long getLong(int users) {
return (long) (this.a * users + this.b);
}
@Override
public double getDouble(int users) {
return this.a * users + this.b;
}
public String toString() {
return "Linear Model: lin(u) = " + a + " * u + " + b;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment