Commit 35ea93a4 authored by Simon Luser's avatar Simon Luser
Browse files

Merge remote-tracking branch 'origin/master' into pl/disasterPrioritization

parents 92774550 6c429d62
...@@ -340,7 +340,7 @@ ...@@ -340,7 +340,7 @@
<dependency> <dependency>
<groupId>com.graphhopper</groupId> <groupId>com.graphhopper</groupId>
<artifactId>graphhopper</artifactId> <artifactId>graphhopper</artifactId>
<version>0.5.0</version> <version>0.7.0</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
......
package de.tud.kom.p2psim.api.application;
/**
* The workload items which should be generated by a {@link WorkloadGenerator}.
* More or less just a wrapper to pass a specific request to the {@link WorkloadListener}s.
*/
public class WorkloadItem<T>
{
private T content;
public WorkloadItem(T content)
{
this.content = content;
}
/**
* Returns the content of this workload item
* @return the content
*/
public T getContent()
{
return content;
}
}
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
package de.tud.kom.p2psim.api.application; package de.tud.kom.p2psim.api.application;
import de.tud.kom.p2psim.api.common.SimHost;
/** /**
* This is the Listener for an application, to get the call to do something. * This is the Listener for an application, to get the call to do something.
...@@ -36,13 +35,20 @@ import de.tud.kom.p2psim.api.common.SimHost; ...@@ -36,13 +35,20 @@ import de.tud.kom.p2psim.api.common.SimHost;
* *
* @author Christoph Muenker * @author Christoph Muenker
* @version 1.0, 14.06.2013 * @version 1.0, 14.06.2013
*
*
*
* 12.03.2017 Clemens Krug:
* The getApplication method has been removed since it did not comply to the
* typical Observer/Listener pattern. Instead {@link #doWork(WorkloadItem)} was added
* and the {@link Application}s should now handle the workloads accordingly.
*/ */
public interface WorkloadListener { public interface WorkloadListener
{
/** /**
* Gets the Application, which uses this Listener * Called when a {@link WorkloadItem} is ready.
* * @param item The workload item.
* @return The application which is using the listener.
*/ */
public Application getApplication(); void doWork(WorkloadItem item);
} }
package de.tud.kom.p2psim.api.common;
/**
* Created by Clemens on 02.04.2017.
*/
public interface NodeDebugUpdateListener
{
}
...@@ -99,7 +99,7 @@ public class MaxPeerCountChurnGenerator ...@@ -99,7 +99,7 @@ public class MaxPeerCountChurnGenerator
private PriorityQueue<HostSessionInfo> offlineHostsSortedByOfflineTime; private PriorityQueue<HostSessionInfo> offlineHostsSortedByOfflineTime;
private Random rnd = Randoms.getRandom(new Object()); private Random rnd = Randoms.getRandom(MaxPeerCountChurnGenerator.class);
/** /**
* Comparator used to sort client infos by offline time * Comparator used to sort client infos by offline time
......
package de.tud.kom.p2psim.impl.common;
import de.tud.kom.p2psim.impl.topology.views.visualization.ui.NodeDebugVisualisation;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.core.NodeDebugMonitorComponent;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* Default node debug monitor. Provides logging capabilities and data access as well
* as the option to define filters on which information should be logged.
* Per node information can be shown by simply clicking on the desired node.
* Filters can be used as blacklist or as whitelist and
* are specified via the xml config. <BR><BR>
*
* How to define Filters:<BR>
* The standard XML configuration looks like this:<BR><BR>
* &lt;DebugMonitor class="de.tud.kom.p2psim.impl.common.DefaultNodeDebugMonitor" static="getInstance" enableVis="$ENABLE_DEBUG_VIS"&gt;<BR>
* &#09;&lt;PackageFilter class="de.tud.kom.p2psim.impl.common.PackageFilter"<BR>
* &#09;&#09;type="EXCLUDE"<BR>
* &#09;&#09;packageName="de.tudarmstadt.maki.simonstrator.peerfact.application.resAlloc.user"/&gt<BR>
* &lt;/DebugMonitor&gt;<BR><BR>
*
* Any package or class can be specified as filter and all
* subpackages and classes will be filtered accordingly. For types you can use 'EXCLUDE' or 'INCLUDE'
* depending on if you want to use whitelisting or blacklisting. Multiple
* &lt;PackageFilter&gt; tags can be defined, however you can't use INCLUDE and EXCLUDE simultaneously.
*/
public class DefaultNodeDebugMonitor implements NodeDebugMonitorComponent
{
private static DefaultNodeDebugMonitor instance;
private HashMap<INodeID, HashMap<Class, HashMap<String, Object>>> data = new HashMap<>();
private LinkedList<NodeDebugUpdateListener> listeners = new LinkedList<>();
//Marker to prevent creation of two visualisation components
private boolean visAlreadyEnabled = false;
//Marker determining if blacklisting or whitelisting is enabled
private boolean filterInitialised = false;
private boolean whitelist = false;
private LinkedList<PackageFilter> filteredPackages = new LinkedList<>();
private HashMap<Class, Boolean> filteredClasses = new HashMap<>();
public static DefaultNodeDebugMonitor getInstance()
{
if(instance == null)
{
instance = new DefaultNodeDebugMonitor();
}
return instance;
}
@Override
public void update(Class<?> subject, INodeID nodeID, String entry, Object value)
{
if(filteredClasses.containsKey(subject))
{
//If Whitelisting and class not contained in filter
if(whitelist && !filteredClasses.get(subject)) return;
//If blacklisting and class contained in filter.
if(!whitelist && filteredClasses.get(subject)) return;
}
HashMap<Class, HashMap<String, Object>> nodeData;
if(data.containsKey(nodeID)) nodeData = data.get(nodeID);
else {
nodeData = new HashMap<>();
data.put(nodeID, nodeData);
}
HashMap<String, Object> nodeClassData;
if(nodeData.containsKey(subject)) nodeClassData = nodeData.get(subject);
else
{
//First update for this class. Check if the class needs to be filtered.
boolean classFiltered = isFiltered(subject);
filteredClasses.put(subject, classFiltered);
//If the class is excluded, don't add the information and return.
if((whitelist && !classFiltered) || (!whitelist && classFiltered) ) return;
nodeClassData = new HashMap<>();
nodeData.put(subject, nodeClassData);
}
nodeClassData.put(entry, value);
listeners.forEach(l -> l.onNodeDebugUpdate(subject, nodeID, entry, value));
}
@Override
public Map<Class, HashMap<String, Object>> getNodeData(INodeID nodeID) {
if(data.containsKey(nodeID)) return data.get(nodeID);
else return new HashMap<>();
}
@Override
public void addUpdateListener(NodeDebugUpdateListener listener) {
listeners.add(listener);
}
@Override
public void removeUpdateListener(NodeDebugUpdateListener listener) {
listeners.remove(listener);
}
@Override
public void setEnableVis(boolean enabled) {
if(enabled && !visAlreadyEnabled) new NodeDebugVisualisation();
}
/**
* Adds a filter to the debug monitor. Should only be used via XML config and
* is not meant to be only called while simulation setup.
* @param filter the filter to add
*/
public void setPackageFilter(PackageFilter filter)
{
//First entry sets whitelisting/blacklisting
if(!filterInitialised)
{
filterInitialised = true;
whitelist = filter.isWhitelist();
}
// If the added type is not conform with the type of listing, an error is thrown.
if(filter.isWhitelist() != whitelist) throw new AssertionError("Can't use Includes/Excludes simultaneously!");
//Don't save filters for packages where a parent package is already filtered.
for(PackageFilter pf : filteredPackages)
{
if(filter.subPackageOf(pf)) return;
if(pf.subPackageOf(filter))
{
filteredPackages.remove(pf);
filteredPackages.add(filter);
return;
}
}
filteredPackages.add(filter);
}
/**
* Check if a class is contained in the filter.
* @param c the class to check
* @return true if contained, false otherwise.
*/
private boolean isFiltered(Class c)
{
for(PackageFilter pf : filteredPackages)
{
if(pf.containsClass(c)) return true;
}
return false;
}
}
package de.tud.kom.p2psim.impl.common;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* Created by Clemens on 29.04.2017.
*/
public class PackageFilter
{
private String packageName;
private TYPE type;
@XMLConfigurableConstructor({"packageName", "type"})
public PackageFilter(String packageName, String type)
{
this.packageName = packageName;
this.type = TYPE.valueOf(type.toUpperCase());
}
private String getPackageName()
{
return packageName;
}
public boolean isWhitelist()
{
return type == TYPE.INCLUDE;
}
public boolean subPackageOf(PackageFilter filter)
{
return filter.getPackageName().contains(packageName);
}
public boolean containsClass(Class c)
{
return c.getName().contains(packageName);
}
public enum TYPE
{
INCLUDE,
EXCLUDE
}
}
...@@ -738,7 +738,7 @@ public class DefaultConfigurator implements Configurator { ...@@ -738,7 +738,7 @@ public class DefaultConfigurator implements Configurator {
if (cArgs.length != types.length) if (cArgs.length != types.length)
throw new ConfigurationException( throw new ConfigurationException(
"The size of the argument list of the XML configurable constructor (" "The size of the argument list of the XML configurable constructor ("
+ cArgs + Arrays.toString(cArgs)
+ ") is unequal to the size of arguments of the constructor is was applied to."); + ") is unequal to the size of arguments of the constructor is was applied to.");
// Constructor can be called with the given XML // Constructor can be called with the given XML
......
...@@ -32,6 +32,7 @@ import de.tud.kom.p2psim.api.topology.obstacles.ObstacleModel; ...@@ -32,6 +32,7 @@ import de.tud.kom.p2psim.api.topology.obstacles.ObstacleModel;
import de.tud.kom.p2psim.api.topology.social.SocialView; import de.tud.kom.p2psim.api.topology.social.SocialView;
import de.tud.kom.p2psim.api.topology.views.TopologyView; import de.tud.kom.p2psim.api.topology.views.TopologyView;
import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel; import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.GPSCalculation;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.visualization.world.SocialViewComponentVis; import de.tud.kom.p2psim.impl.topology.views.visualization.world.SocialViewComponentVis;
...@@ -63,6 +64,8 @@ public class DefaultTopology implements Topology { ...@@ -63,6 +64,8 @@ public class DefaultTopology implements Topology {
public DefaultTopology(PositionVector worldDimensions) { public DefaultTopology(PositionVector worldDimensions) {
this.worldDimensions = worldDimensions; this.worldDimensions = worldDimensions;
components = new LinkedList<TopologyComponent>(); components = new LinkedList<TopologyComponent>();
// obstacles = new LinkedList<Obstacle>(); // obstacles = new LinkedList<Obstacle>();
topoListeners = new LinkedList<TopologyListener>(); topoListeners = new LinkedList<TopologyListener>();
......
...@@ -44,7 +44,6 @@ import de.tudarmstadt.maki.simonstrator.api.Graphs; ...@@ -44,7 +44,6 @@ import de.tudarmstadt.maki.simonstrator.api.Graphs;
import de.tudarmstadt.maki.simonstrator.api.Host; import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Oracle; import de.tudarmstadt.maki.simonstrator.api.Oracle;
import de.tudarmstadt.maki.simonstrator.api.Randoms; import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.common.graph.Graph; import de.tudarmstadt.maki.simonstrator.api.common.graph.Graph;
import de.tudarmstadt.maki.simonstrator.api.common.graph.IEdge; import de.tudarmstadt.maki.simonstrator.api.common.graph.IEdge;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INode; import de.tudarmstadt.maki.simonstrator.api.common.graph.INode;
...@@ -263,6 +262,18 @@ public class DefaultTopologyComponent implements TopologyComponent { ...@@ -263,6 +262,18 @@ public class DefaultTopologyComponent implements TopologyComponent {
@Override @Override
public void updateCurrentLocation(Location location) { public void updateCurrentLocation(Location location) {
position.set(location); position.set(location);
/*
* FIXME utilization of the NodeDebugMonitor leads to huge performance drop.
*/
// NodeDebugMonitor.update(this.getClass(), getHost().getId(), "Current Location", location);
// try {
// NodeDebugMonitor.update(this.getClass(), getHost().getId(),
// "Distance to target",
// location.distanceTo(movementModel.getTargetLocation(this)));
// } catch (UnsupportedOperationException e) {
// // This is not supported by the movement model (which may happen see
// // MovementModel.java - thus catch and ignore)
// }
// notify "non-request" listeners // notify "non-request" listeners
for (LocationListener locationListener : listeners) { for (LocationListener locationListener : listeners) {
locationListener.onLocationChanged(getHost(), getLastLocation()); locationListener.onLocationChanged(getHost(), getLastLocation());
...@@ -273,6 +284,7 @@ public class DefaultTopologyComponent implements TopologyComponent { ...@@ -273,6 +284,7 @@ public class DefaultTopologyComponent implements TopologyComponent {
public void setTargetAttractionPoint(AttractionPoint targetAttractionPoint) public void setTargetAttractionPoint(AttractionPoint targetAttractionPoint)
throws UnsupportedOperationException { throws UnsupportedOperationException {
movementModel.changeTargetLocation(this, targetAttractionPoint); movementModel.changeTargetLocation(this, targetAttractionPoint);
// NodeDebugMonitor.update(this.getClass(), getHost().getId(), "Target Location", targetAttractionPoint);
} }
@Override @Override
......
...@@ -20,30 +20,32 @@ ...@@ -20,30 +20,32 @@
package de.tud.kom.p2psim.impl.topology.movement.local; package de.tud.kom.p2psim.impl.topology.movement.local;
import java.util.HashMap;
import java.util.Locale;
import java.util.UUID;
import com.graphhopper.GHRequest; import com.graphhopper.GHRequest;
import com.graphhopper.GHResponse; import com.graphhopper.GHResponse;
import com.graphhopper.GraphHopper; import com.graphhopper.GraphHopper;
import com.graphhopper.routing.util.EncodingManager; import com.graphhopper.routing.util.EncodingManager;
import com.graphhopper.util.DistanceCalc2D;
import com.graphhopper.util.PointList; import com.graphhopper.util.PointList;
import com.graphhopper.util.shapes.GHPoint; import com.graphhopper.util.shapes.GHPoint;
import com.graphhopper.util.shapes.GHPoint3D; import com.graphhopper.util.shapes.GHPoint3D;
import de.tud.kom.p2psim.api.topology.Topology; import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector; 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.movement.modularosm.GPSCalculation;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tud.kom.p2psim.impl.util.Either; import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Left; import de.tud.kom.p2psim.impl.util.Left;
import de.tudarmstadt.maki.simonstrator.api.Binder; import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor; import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level; import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import java.util.*;
/** /**
* This movement strategy uses the data from osm and navigates the nodes throught streets to the destination * This movement strategy uses the data from osm and navigates the nodes throught streets to the destination
*
* 13.03.2017 Clemens Krug: Fixed a bug. When the GraphHopper routing had errors the nodes would move to the
* top right corner and not, as intended, straight to their destination.
* *
* @author Martin Hellwig * @author Martin Hellwig
* @version 1.0, 07.07.2015 * @version 1.0, 07.07.2015
...@@ -59,13 +61,14 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -59,13 +61,14 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
private String osmFileLocation; //use pbf-format, because osm-format causes problems (xml-problems) private String osmFileLocation; //use pbf-format, because osm-format causes problems (xml-problems)
private String graphFolderFiles; private String graphFolderFiles;
private String movementType; //car, bike or foot private String movementType; //car, bike or foot
private String navigationalType; //fastest, private String defaultMovement;
private double latLeft; //Values from -90 to 90; always smaller than latRight private String navigationalType; //fastest,
private double latRight; //Values from -90 to 90 private double latLower; //Values from -90 to 90; always smaller than latUpper
private double latUpper; //Values from -90 to 90
private double lonLeft; //Values from -180 to 180; Always smaller than lonRight private double lonLeft; //Values from -180 to 180; Always smaller than lonRight
private double lonRight; //Values from -180 to 180 private double lonRight; //Values from -180 to 180
private boolean uniqueFolders; private boolean uniqueFolders;
/** /**
* Tolerance in meters (if the node reached a waypoint up to "tolerance" * Tolerance in meters (if the node reached a waypoint up to "tolerance"
* meters, it will select the next waypoint in the path. * meters, it will select the next waypoint in the path.
...@@ -75,8 +78,8 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -75,8 +78,8 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
public RealWorldStreetsMovement() { public RealWorldStreetsMovement() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class) this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions(); .getWorldDimensions();
latLeft = GPSCalculation.getLatLower(); latLower = GPSCalculation.getLatLower();
latRight = GPSCalculation.getLatUpper(); latUpper = GPSCalculation.getLatUpper();
lonLeft = GPSCalculation.getLonLeft(); lonLeft = GPSCalculation.getLonLeft();
lonRight = GPSCalculation.getLonRight(); lonRight = GPSCalculation.getLonRight();
} }
...@@ -84,6 +87,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -84,6 +87,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
private void init() { private void init() {
hopper = new GraphHopper().forServer(); hopper = new GraphHopper().forServer();
hopper.setOSMFile(osmFileLocation); hopper.setOSMFile(osmFileLocation);
// where to store graphhopper files? // where to store graphhopper files?
if (uniqueFolders) { if (uniqueFolders) {
Monitor.log(RealWorldStreetsMovement.class, Level.WARN, Monitor.log(RealWorldStreetsMovement.class, Level.WARN,
...@@ -97,16 +101,25 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -97,16 +101,25 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
} }
hopper.setEncodingManager(new EncodingManager(movementType)); hopper.setEncodingManager(new EncodingManager(movementType));
hopper.importOrLoad(); hopper.importOrLoad();
init = true; init = true;
} }
public Either<PositionVector, Boolean> nextPosition(SimLocationActuator comp, PositionVector destination)
{
return nextPosition(comp, destination, defaultMovement);
}
public Either<PositionVector, Boolean> nextPosition(SimLocationActuator comp, public Either<PositionVector, Boolean> nextPosition(SimLocationActuator comp,
PositionVector destination) { PositionVector destination, String movementType) {
if(!init) init();
if(movementType == null || movementType.equals("") || !this.movementType.contains(movementType))
throw new AssertionError("Invalid movement type: " + movementType);
if(!init) init();
PositionVector newPosition = null; PositionVector newPosition = null;
if (destination.distanceTo(comp.getRealPosition()) > getMovementSpeed(comp))
if (destination {
.distanceTo(comp.getRealPosition()) > getMovementSpeed(comp)) {
//if not set already for this node or new destination is different than last one //if not set already for this node or new destination is different than last one
PointList pointList; PointList pointList;
if(!movementPoints.containsKey(comp) || destination.distanceTo(movementPoints.get(comp).getDestination()) > 1.0) { if(!movementPoints.containsKey(comp) || destination.distanceTo(movementPoints.get(comp).getDestination()) > 1.0) {
...@@ -119,15 +132,16 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -119,15 +132,16 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
GHResponse rsp = hopper.route(req); GHResponse rsp = hopper.route(req);
//If the requested point is not in the map data, simple return the destination as next point //If the requested point is not in the map data, simple return the destination as next point
if(rsp.hasErrors()) { if(rsp.hasErrors()) {
System.err.println("Requested Points (" + startPosition[0] + ", " + startPosition[1] Monitor.log(this.getClass(), Monitor.Level.ERROR, "Routing request for Host %s with starting point (" +
+ ") or (" + destinationPosition[0] + ", " + destinationPosition[1] + ") are out of the bounding box."); "%f,%f), destination (%f,%f) and type %s failed with error: %s.", comp.getHost().getId().valueAsString(),startPosition[0], startPosition[1],
destinationPosition[0], destinationPosition[1], movementType, rsp.getErrors());
pointList = new PointList(); pointList = new PointList();
pointList.add(new GHPoint(destination.getLatitude(), destination.getLongitude())); pointList.add(new GHPoint(destinationPosition[0], destinationPosition[1]));
movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0)); movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0));
} }
else { else {
pointList = rsp.getPoints(); pointList = rsp.getBest().getPoints();
movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0)); movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0));
} }
} }
...@@ -163,7 +177,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -163,7 +177,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
*/ */
private double[] transformOwnWorldWindowToGPS(double x, double y) { private double[] transformOwnWorldWindowToGPS(double x, double y) {
double[] gps_coordinates = new double[2]; double[] gps_coordinates = new double[2];
gps_coordinates[0] = latLeft + (latRight - latLeft) * (worldDimensions.getY() - y)/worldDimensions.getY(); gps_coordinates[0] = latLower + (latUpper - latLower) * (worldDimensions.getY() - y)/worldDimensions.getY();
gps_coordinates[1] = lonLeft + (lonRight - lonLeft) * x/worldDimensions.getX(); gps_coordinates[1] = lonLeft + (lonRight - lonLeft) * x/worldDimensions.getX();
return gps_coordinates; return gps_coordinates;
} }
...@@ -176,13 +190,66 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -176,13 +190,66 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
*/ */
private PositionVector transformGPSWindowToOwnWorld(double lat, double lon) { private PositionVector transformGPSWindowToOwnWorld(double lat, double lon) {
double x = worldDimensions.getX() * (lon - lonLeft)/(lonRight - lonLeft); double x = worldDimensions.getX() * (lon - lonLeft)/(lonRight - lonLeft);
double y = worldDimensions.getY() - worldDimensions.getY() * (lat - latLeft)/(latRight - latLeft); double y = worldDimensions.getY() - worldDimensions.getY() * (lat - latLower)/(latUpper - latLower);
x = Math.max(0, x); x = Math.max(0, x);
x = Math.min(worldDimensions.getX(), x); x = Math.min(worldDimensions.getX(), x);
y = Math.max(0, y); y = Math.max(0, y);
y = Math.min(worldDimensions.getY(), y); y = Math.min(worldDimensions.getY(), y);
return new PositionVector(x, y); return new PositionVector(x, y);
} }
/**
* 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)
{
List<PositionVector> positions = new LinkedList<>();
PointList pointList = movementPoints.get(ms).getPointList();
pointList.forEach(p -> positions.add(new PositionVector(transformGPSWindowToOwnWorld(p.getLat(), p.getLon()))));
return positions;
}
/**
* Calculates the length of a route in meters.
* @param start Starting position in own world coordinates (x / y)
* @param destination Destination on own world coordinates (x / y)
* @return the length of the route in meters.
*/
public double calculateRouteLength(PositionVector start, PositionVector destination)
{
PointList pointList;
double[] startPosition = transformOwnWorldWindowToGPS(start.getX(), start.getY());
double[] destinationPosition = transformOwnWorldWindowToGPS(destination.getX(), destination.getY());
GHRequest req = new GHRequest(startPosition[0], startPosition[1], destinationPosition[0], destinationPosition[1]).
setWeighting(navigationalType).
setVehicle(movementType).
setLocale(Locale.GERMANY);
GHResponse rsp = hopper.route(req);
//If the requested point is not in the map data, return -1
if(rsp.hasErrors()) {
return -1;
}
else {
pointList = rsp.getBest().getPoints();
return pointList.calcDistance(new DistanceCalc2D());
}
}
/**
* Calculates the length of the current route of the SimLocationActuator.
* @param ms the component
* @return the length of the current route
*/
public double getCurrentRouteLength(SimLocationActuator ms)
{
return movementPoints.get(ms).getPointList().calcDistance(new DistanceCalc2D());
}
public void setOsmFileLocation(String osmFileLocation) { public void setOsmFileLocation(String osmFileLocation) {
this.osmFileLocation = osmFileLocation; this.osmFileLocation = osmFileLocation;
...@@ -194,6 +261,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -194,6 +261,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
public void setMovementType(String movementType) { public void setMovementType(String movementType) {
this.movementType = movementType; this.movementType = movementType;
defaultMovement = movementType.split(",")[0];
} }
public void setNavigationalType(String navigationalType) { public void setNavigationalType(String navigationalType) {
...@@ -203,13 +271,13 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -203,13 +271,13 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
public void setWaypointTolerance(double tolerance) { public void setWaypointTolerance(double tolerance) {
this.tolerance = tolerance; this.tolerance = tolerance;
} }
/** /**
* For large batch simulations, we need to prevent same-time access to * For large batch simulations, we need to prevent same-time access to
* garphhopper temp data. Therefore, this flag creates unique folders for * garphhopper temp data. Therefore, this flag creates unique folders for
* each run (which, obviously, wastes a lot of space and comp-resources and * each run (which, obviously, wastes a lot of space and comp-resources and
* should not be used in standalone, single-threaded demo mode...) * should not be used in standalone, single-threaded demo mode...)
* *
* @param uniqueFolders * @param uniqueFolders
*/ */
public void setCreateUniqueFolders(boolean uniqueFolders) { public void setCreateUniqueFolders(boolean uniqueFolders) {
......
...@@ -25,7 +25,15 @@ import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.Visualiza ...@@ -25,7 +25,15 @@ import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.Visualiza
import de.tudarmstadt.maki.simonstrator.api.Binder; import de.tudarmstadt.maki.simonstrator.api.Binder;
/** /**
* *
* CHANGELOG
* - 26.06.2017 Clemens Krug:
* Change some calculations that used numbers that were not comprehensible and not documented.
* In the previous version, changing the zoom of the visualisation / map would fuck up the whole
* positioning calculations. This has been fixed now.
*
*
*
* @author Martin Hellwig * @author Martin Hellwig
* @version 1.0, Nov 3, 2015 * @version 1.0, Nov 3, 2015
*/ */
...@@ -37,7 +45,10 @@ public class GPSCalculation { ...@@ -37,7 +45,10 @@ public class GPSCalculation {
private static int zoom; private static int zoom;
private static double scaleFactor; private static double metersPerPixel;
// Earth Circumference in meters
private static int EARTH_CIRCUMFERENCE = 40030173;
/* /*
* http://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a- * http://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-
...@@ -64,7 +75,8 @@ public class GPSCalculation { ...@@ -64,7 +75,8 @@ public class GPSCalculation {
* is valid on all zoom levels. * is valid on all zoom levels.
*/ */
// 17: 2, 16: 1, 15: 0.5, 14: 0.25 // 17: 2, 16: 1, 15: 0.5, 14: 0.25
VisualizationInjector.setScale(Math.pow(2.0d, (zoom - 16))); // VisualizationInjector.setScale(Math.pow(2.0d, (zoom - 16)));
VisualizationInjector.setScale(1/metersPerPixel);
} }
public static double getLatCenter() { public static double getLatCenter() {
...@@ -79,54 +91,58 @@ public class GPSCalculation { ...@@ -79,54 +91,58 @@ public class GPSCalculation {
return zoom; return zoom;
} }
public static double getLatUpper() { public static double getMetersPerPixel()
return latCenter + (Binder.getComponentOrNull(Topology.class) {
.getWorldDimensions().getY() / 111111d) * scaleFactor; return metersPerPixel;
}
public static double getWorldDimensionsX() {
return Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getX();
}
public static double getWorldDimensionsY() {
return Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getY();
}
// return latCenter + scaleFactor * 0.027613 * Binder public static double getLatUpper() {
// .getComponentOrNull(Topology.class).getWorldDimensions().getY() return latCenter + ((Binder.getComponentOrNull(Topology.class)
// / 1000; .getWorldDimensions().getY()/2) / 111111d);
} }
public static double getLatLower() { public static double getLatLower() {
return latCenter - (Binder.getComponentOrNull(Topology.class) return latCenter - ((Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getY() / 111111d) * scaleFactor; .getWorldDimensions().getY()/2) / 111111d);
// return latCenter - scaleFactor * 0.027613 * Binder
// .getComponentOrNull(Topology.class).getWorldDimensions().getY()
// / 1000;
} }
public static double getLonLeft() { public static double getLonLeft() {
return lonCenter - (Binder.getComponentOrNull(Topology.class) return lonCenter - ((Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getX() / 111111d / scaleLon) * scaleFactor; .getWorldDimensions().getX()/2) / (111111d * scaleLon));
// return lonCenter - scaleFactor * 0.043 * Binder
// .getComponentOrNull(Topology.class).getWorldDimensions().getX()
// / 1000;
} }
public static double getLonRight() { public static double getLonRight() {
return lonCenter + (Binder.getComponentOrNull(Topology.class) return lonCenter + ((Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getX() / 111111d / scaleLon) * scaleFactor; .getWorldDimensions().getX()/2) / (111111d * scaleLon));
// return lonCenter + scaleFactor * 0.043 * Binder
// .getComponentOrNull(Topology.class).getWorldDimensions().getX()
// / 1000;
} }
public void setLatCenter(double latCenter) { public void setLatCenter(double latCenter) {
this.latCenter = latCenter; this.latCenter = latCenter;
this.scaleLon = Math.cos(Math.toRadians(latCenter)); this.scaleLon = Math.cos(Math.toRadians(latCenter));
this.scaleFactor = 0.38d;
} }
public void setLonCenter(double lonCenter) { public void setLonCenter(double lonCenter) {
this.lonCenter = lonCenter; this.lonCenter = lonCenter;
} }
/**
* Formula http://wiki.openstreetmap.org/wiki/Zoom_levels
*
* @param zoom
*/
public void setZoom(int zoom) { public void setZoom(int zoom) {
this.zoom = zoom; GPSCalculation.zoom = zoom;
GPSCalculation.metersPerPixel = EARTH_CIRCUMFERENCE * Math.cos(Math.toRadians(GPSCalculation.getLatCenter())) / Math.pow(2, GPSCalculation.getZoom() + 8);
setScaleFactor(); setScaleFactor();
} }
} }
...@@ -65,7 +65,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationAc ...@@ -65,7 +65,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationAc
* M1: A general {@link MovementModel} is not used, because we use static * M1: A general {@link MovementModel} is not used, because we use static
* attraction points. * attraction points.
* <p> * <p>
* M2: The {@link TransitionStrategy}! It takes the Hosts, which should be moved * M2: The {@link ITransitionStrategy}! It takes the Hosts, which should be moved
* around, but calculates only the assignment to the {@link AttractionPoint}s. * around, but calculates only the assignment to the {@link AttractionPoint}s.
* It doesn't move the Hosts! It will be only assignment a new AttractionPoint! * It doesn't move the Hosts! It will be only assignment a new AttractionPoint!
* *
...@@ -85,7 +85,12 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationAc ...@@ -85,7 +85,12 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationAc
* destination point (AttractionPoint), so that not all hosts, which are * destination point (AttractionPoint), so that not all hosts, which are
* assigned to one {@link AttractionPoint}, lies on the same point.<br> * assigned to one {@link AttractionPoint}, lies on the same point.<br>
* *
* * CHANGELOG
*
* - 04.01.2017 Clemens Krug: Added the possibility to configure the model
* visualisation via XML. If not specified, the visualisation will use the
* {@link ModularMovementModelViz}, just as before. Thus there shouldn't be any problems
* with older code.
* *
* @author Martin Hellwig, Christoph Muenker * @author Martin Hellwig, Christoph Muenker
* @version 1.0, 07.07.2015 * @version 1.0, 07.07.2015
...@@ -106,10 +111,12 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -106,10 +111,12 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
protected IMapVisualization mapVisualization; protected IMapVisualization mapVisualization;
private Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>(); private ModularMovementModelViz modelVisualisation;
protected Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>();
private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>(); private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>();
private boolean initialized = false; private boolean initialized = false;
private long timeBetweenMoveOperation = Simulator.SECOND_UNIT; private long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
...@@ -121,6 +128,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -121,6 +128,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
.getWorldDimensions(); .getWorldDimensions();
this.rand = Randoms.getRandom(ModularMovementModel.class); this.rand = Randoms.getRandom(ModularMovementModel.class);
// Setting this model as default to prevent older code from braking. See Changelog.
modelVisualisation = new ModularMovementModelViz(this);
// scheduling initalization! // scheduling initalization!
Event.scheduleImmediately(this, null, EVENT_INIT); Event.scheduleImmediately(this, null, EVENT_INIT);
} }
...@@ -132,8 +142,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -132,8 +142,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
public void initialize() { public void initialize() {
if (!initialized) { if (!initialized) {
VisualizationInjector VisualizationInjector.injectComponent(modelVisualisation);
.injectComponent(new ModularMovementModelViz(this));
if (mapVisualization != null) { if (mapVisualization != null) {
VisualizationInjector.injectComponent(mapVisualization); VisualizationInjector.injectComponent(mapVisualization);
} }
...@@ -230,7 +239,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -230,7 +239,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
"time is negative for the Move Operations"); "time is negative for the Move Operations");
} }
} }
@Override @Override
public void updatedAttractionAssignment(SimLocationActuator component, public void updatedAttractionAssignment(SimLocationActuator component,
AttractionPoint newAssignment) { AttractionPoint newAssignment) {
...@@ -244,7 +253,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -244,7 +253,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
* Even if an AP does not have a radius, we slightly offset * Even if an AP does not have a radius, we slightly offset
*/ */
double apRadius = Math.max(newAssignment.getRadius(), 25.0); double apRadius = Math.max(newAssignment.getRadius(), 25.0);
int tries = 0; int tries = 0;
do { do {
destination = new PositionVector(attractionCenter); destination = new PositionVector(attractionCenter);
...@@ -268,7 +277,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -268,7 +277,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
} }
tries++; tries++;
} while (destination == null); } while (destination == null);
currentTarget.put(component, destination); currentTarget.put(component, destination);
} }
...@@ -290,7 +299,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -290,7 +299,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
* @param ms * @param ms
* @param destination * @param destination
*/ */
private void doLocalMovement(SimLocationActuator ms, protected void doLocalMovement(SimLocationActuator ms,
PositionVector destination) { PositionVector destination) {
Either<PositionVector, Boolean> either = localMovementStrategy Either<PositionVector, Boolean> either = localMovementStrategy
...@@ -331,6 +340,12 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -331,6 +340,12 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
this.mapVisualization = mapVisualization; this.mapVisualization = mapVisualization;
} }
public void setModelVisualisation(ModularMovementModelViz modelVis)
{
modelVisualisation = modelVis;
modelVisualisation.setMovementModel(this);
}
@Override @Override
public void eventOccurred(Object content, int type) { public void eventOccurred(Object content, int type) {
if (type == EVENT_INIT) { if (type == EVENT_INIT) {
......
...@@ -52,7 +52,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction ...@@ -52,7 +52,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
public class ModularMovementModelViz extends JComponent public class ModularMovementModelViz extends JComponent
implements VisualizationComponent { implements VisualizationComponent {
private ModularMovementModel movementModel; protected ModularMovementModel movementModel;
protected boolean showAttractionPoints = true; protected boolean showAttractionPoints = true;
...@@ -66,16 +66,26 @@ public class ModularMovementModelViz extends JComponent ...@@ -66,16 +66,26 @@ public class ModularMovementModelViz extends JComponent
private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D"); private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D");
public ModularMovementModelViz()
{
init();
}
protected void init()
{
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
setOpaque(true);
setVisible(true);
menu = new JMenu("Mobility Model");
menu.add(createCheckboxAp());
menu.add(createCheckboxNodePositions());
}
public ModularMovementModelViz(ModularMovementModel model) { public ModularMovementModelViz(ModularMovementModel model) {
setBounds(0, 0, VisualizationInjector.getWorldX(), init();
VisualizationInjector.getWorldY());
setOpaque(true);
setVisible(true);
this.movementModel = model; this.movementModel = model;
menu = new JMenu("Mobility Model");
menu.add(createCheckboxAp());
menu.add(createCheckboxNodePositions());
} }
private JCheckBoxMenuItem createCheckboxAp() { private JCheckBoxMenuItem createCheckboxAp() {
...@@ -112,43 +122,79 @@ public class ModularMovementModelViz extends JComponent ...@@ -112,43 +122,79 @@ public class ModularMovementModelViz extends JComponent
RenderingHints.VALUE_ANTIALIAS_ON); RenderingHints.VALUE_ANTIALIAS_ON);
if (showAttractionPoints) { if (showAttractionPoints) {
for (AttractionPoint aPoint : movementModel.getAttractionPoints()) { drawAttractionPoints(g2);
Point point = ((PositionVector) aPoint).asPoint();
// draw border
g2.setColor(Color.BLACK);
g2.setFont(VisualizationTopologyView.FONT_MEDIUM);
g2.drawString(aPoint.getName(),
VisualizationInjector.scaleValue(point.x) - ATTR_PAD,
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.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;
g2.drawOval(VisualizationInjector.scaleValue(point.x) - radius,
VisualizationInjector.scaleValue(point.y) - radius,
radius * 2 + 1, radius * 2 + 1);
}
} }
if (showNodePositions) { if (showNodePositions) {
for (SimLocationActuator comp : movementModel for (SimLocationActuator comp : movementModel
.getAllLocationActuators()) { .getAllLocationActuators()) {
Point2D pt = comp.getRealPosition().asPoint(); drawNodePosition(g2, comp);
g2.setColor(Color.GRAY); }
g2.fillOval((int) pt.getX() - NODE_PAD,
(int) pt.getY() - NODE_PAD, NODE_PAD * 2 + 1,
NODE_PAD * 2 + 1);
}
} }
} }
/**
* 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
g2.setColor(Color.BLACK);
g2.setFont(VisualizationTopologyView.FONT_MEDIUM);
g2.drawString(aPoint.getName(),
VisualizationInjector.scaleValue(point.x) - ATTR_PAD,
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.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 = VisualizationInjector.scaleValue(aPoint.getRadius()) + ATTR_PAD;
g2.drawOval(VisualizationInjector.scaleValue(point.x) - radius,
VisualizationInjector.scaleValue(point.y) - radius,
radius * 2 + 1, radius * 2 + 1);
}
}
/**
* 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(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 @Override
public String getDisplayName() { public String getDisplayName() {
return "Mobility Model"; return "Mobility Model";
......
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.RealWorldMovementPoints;
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);
}
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; ...@@ -38,8 +38,12 @@ import java.net.URL;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JMenu; 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.movement.modularosm.GPSCalculation;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector; 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 public class ShowMapQuestMapViz extends JComponent
implements IMapVisualization { implements IMapVisualization {
...@@ -66,25 +70,33 @@ public class ShowMapQuestMapViz extends JComponent ...@@ -66,25 +70,33 @@ public class ShowMapQuestMapViz extends JComponent
private void initializeImage() { private void initializeImage() {
if (!initialized) { if (!initialized) {
PositionVector worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
tempImageFilePath = tempImageFilePath + "mapquest" tempImageFilePath = tempImageFilePath + "mapquest"
+ GPSCalculation.getLatCenter() + GPSCalculation.getLatCenter() + "_"
+ GPSCalculation.getLonCenter() + GPSCalculation.getZoom() + GPSCalculation.getLonCenter() + "_" + GPSCalculation.getZoom() + "_"
+ VisualizationInjector.getWorldX() + worldDimensions.getX() + "_"
+ VisualizationInjector.getWorldY() + mapType + ".jpg"; + worldDimensions.getY() + mapType + ".jpg";
// Check if the file with same properties (same location) already // Check if the file with same properties (same location) already
// exists // exists
File f = new File(tempImageFilePath); File f = new File(tempImageFilePath);
if (!f.exists()) { if (!f.exists()) {
try { 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=" String imageUrl = "http://www.mapquestapi.com/staticmap/v4/getmap?key="
+ mapQuestKey + "&type=" + mapType + mapQuestKey + "&type=" + mapType
+ "&imagetype=jpeg&center=" + "&imagetype=jpeg&center="
+ GPSCalculation.getLatCenter() + "," + GPSCalculation.getLatCenter() + ","
+ GPSCalculation.getLonCenter() + "&zoom=" + GPSCalculation.getLonCenter() + "&zoom="
+ ((GPSCalculation.getZoom()) + 1) + "&size=" + ((GPSCalculation.getZoom())) + "&size="
+ VisualizationInjector.getWorldX() + "," + pxx + ","
+ VisualizationInjector.getWorldY(); + pxy;
URL url = new URL(imageUrl); URL url = new URL(imageUrl);
InputStream is = url.openStream(); InputStream is = url.openStream();
OutputStream os = new FileOutputStream(tempImageFilePath); 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;
}
}
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