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
......@@ -340,7 +340,7 @@
<dependency>
<groupId>com.graphhopper</groupId>
<artifactId>graphhopper</artifactId>
<version>0.5.0</version>
<version>0.7.0</version>
<exclusions>
<exclusion>
<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 @@
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.
......@@ -36,13 +35,20 @@ import de.tud.kom.p2psim.api.common.SimHost;
*
* @author Christoph Muenker
* @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
*
* @return The application which is using the listener.
* Called when a {@link WorkloadItem} is ready.
* @param item The workload item.
*/
public Application getApplication();
void doWork(WorkloadItem item);
}
package de.tud.kom.p2psim.api.common;
/**
* Created by Clemens on 02.04.2017.
*/
public interface NodeDebugUpdateListener
{
}
......@@ -19,73 +19,61 @@
*/
package de.tud.kom.p2psim.api.transport;
/**
* Instances of this type describe the service properties chosen for message
* transmission.
*
* @author Sebastian Kaune
* @author Konstantin Pussep
* @version 3.0, 11/29/2007
*
*/
public enum TransProtocol {
/**
* User Datagram Protocol
*/
UDP(false, false, 8),
/**
* Transmission Control Protocol
*/
TCP(true, true, 20),
package de.tud.kom.p2psim.api.transport;
/**
* Instances of this type describe the service properties chosen for message
* transmission.
*
* @author Sebastian Kaune
* @author Konstantin Pussep
* @version 3.0, 11/29/2007
*
*/
public enum TransProtocol {
/**
* Mobile Communication, one hop (this will be changed to UDP/TCP on the
* BaseStation or one of its backbone nodes). Only available, if an
* UMTS-transceiver is configured in the LinkLayer. TODO check Header Size
* User Datagram Protocol
*/
UMTS(true, true, 20),
UDP(false, false, 8),
/**
* Bluetooth (this will only allow one-hop communication to short-ranged
* neighbors). Only available, if a BT-transceiver is configured in the
* LinkLayer. TODO check Header Size
* Transmission Control Protocol
*/
BLUETOOTH(true, true, 20);
private boolean isConOriented;
TCP(true, true, 20);
private boolean isConOriented;
private boolean isReliable;
private int headerSize;
private int headerSize;
private TransProtocol(boolean isConOriented, boolean isReliable,
int headerSize) {
this.isConOriented = isConOriented;
int headerSize) {
this.isConOriented = isConOriented;
this.isReliable = isReliable;
this.headerSize = headerSize;
}
/**
* If the used service is connection-oriented the in-order delivery of
* messages is guaranteed.
*
* @return whether the applied service should be connection-oriented
*/
public boolean isConnectionOriented() {
return this.isConOriented;
}
/**
* Whether the used connection is reliable, i.e. the network wrapper tries
* to deliver the message in case of loss or and if the message cannot be
* delivered an exception is reported to the upper layer.
*
* @return whether the applied service should be reliable
*/
public boolean isReliable() {
return this.isReliable;
}
this.headerSize = headerSize;
}
/**
* If the used service is connection-oriented the in-order delivery of
* messages is guaranteed.
*
* @return whether the applied service should be connection-oriented
*/
public boolean isConnectionOriented() {
return this.isConOriented;
}
/**
* Whether the used connection is reliable, i.e. the network wrapper tries
* to deliver the message in case of loss or and if the message cannot be
* delivered an exception is reported to the upper layer.
*
* @return whether the applied service should be reliable
*/
public boolean isReliable() {
return this.isReliable;
}
/**
* Size of the headers of this TransMessage in byte.
......@@ -95,5 +83,5 @@ public enum TransProtocol {
public int getHeaderSize() {
return this.headerSize;
}
}
}
......@@ -99,7 +99,7 @@ public class MaxPeerCountChurnGenerator
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
......
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
}
}
......@@ -737,7 +737,7 @@ public class DefaultConfigurator implements Configurator {
if (cArgs.length != types.length)
throw new ConfigurationException(
"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.");
// Constructor can be called with the given XML
......
......@@ -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.views.TopologyView;
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.visualization.world.SocialViewComponentVis;
......@@ -63,6 +64,8 @@ public class DefaultTopology implements Topology {
public DefaultTopology(PositionVector worldDimensions) {
this.worldDimensions = worldDimensions;
components = new LinkedList<TopologyComponent>();
// obstacles = new LinkedList<Obstacle>();
topoListeners = new LinkedList<TopologyListener>();
......
......@@ -90,6 +90,8 @@ public class DefaultTopologyComponent implements TopologyComponent {
private MovementModel movementModel;
private PlacementModel placementModel;
private final boolean registerAsInformationProviderInSiS;
/**
* Create a TopologyComponent for the current host.
......@@ -99,7 +101,7 @@ public class DefaultTopologyComponent implements TopologyComponent {
* @param movementModel
*/
public DefaultTopologyComponent(SimHost host, Topology topology,
MovementModel movementModel, PlacementModel placementModel) {
MovementModel movementModel, PlacementModel placementModel, boolean registerAsInformationProviderInSiS) {
this.topology = topology;
this.host = host;
this.position = new PositionVector(0, 0);
......@@ -113,6 +115,7 @@ public class DefaultTopologyComponent implements TopologyComponent {
if (this.placementModel != null) {
this.placementModel.addComponent(this);
}
this.registerAsInformationProviderInSiS = registerAsInformationProviderInSiS;
}
@Override
......@@ -131,80 +134,83 @@ public class DefaultTopologyComponent implements TopologyComponent {
position.set(placementModel.place(this));
}
try {
final SiSComponent sis = host.getComponent(SiSComponent.class);
sis.provide().nodeState(SiSTypes.PHY_LOCATION,
new SiSDataCallback<Location>() {
Set<INodeID> localID = INodeID
.getSingleIDSet(getHost().getId());
@Override
public Location getValue(INodeID nodeID,
SiSProviderHandle providerHandle)
throws InformationNotAvailableException {
if (nodeID.equals(getHost().getId())) {
return getLastLocation();
} else {
throw new InformationNotAvailableException();
}
}
if (registerAsInformationProviderInSiS) {
try {
final SiSComponent sis = host.getComponent(SiSComponent.class);
sis.provide().nodeState(SiSTypes.PHY_LOCATION,
new SiSDataCallback<Location>() {
Set<INodeID> localID = INodeID
.getSingleIDSet(getHost().getId());
@Override
public Location getValue(INodeID nodeID,
SiSProviderHandle providerHandle)
throws InformationNotAvailableException {
if (nodeID.equals(getHost().getId())) {
return getLastLocation();
} else {
throw new InformationNotAvailableException();
}
}
@Override
public Set<INodeID> getObservedNodes() {
return localID;
}
@Override
public Set<INodeID> getObservedNodes() {
return localID;
}
@Override
public SiSInfoProperties getInfoProperties() {
return new SiSInfoProperties();
}
});
sis.provide().nodeState(SiSTypes.SPEED,
new SiSDataCallback<Double>() {
Set<INodeID> localID = INodeID
.getSingleIDSet(getHost().getId());
@Override
public Double getValue(INodeID nodeID,
SiSProviderHandle providerHandle)
throws InformationNotAvailableException {
if (nodeID.equals(getHost().getId())) {
return getMovementSpeed();
} else {
throw new InformationNotAvailableException();
}
}
@Override
public SiSInfoProperties getInfoProperties() {
return new SiSInfoProperties();
}
});
sis.provide().nodeState(SiSTypes.SPEED,
new SiSDataCallback<Double>() {
Set<INodeID> localID = INodeID
.getSingleIDSet(getHost().getId());
@Override
public Double getValue(INodeID nodeID,
SiSProviderHandle providerHandle)
throws InformationNotAvailableException {
if (nodeID.equals(getHost().getId())) {
return getMovementSpeed();
} else {
throw new InformationNotAvailableException();
}
}
@Override
public Set<INodeID> getObservedNodes() {
return localID;
}
@Override
public Set<INodeID> getObservedNodes() {
return localID;
}
@Override
public SiSInfoProperties getInfoProperties() {
return new SiSInfoProperties();
}
});
// Provide Underlay topology
Event.scheduleImmediately(new EventHandler() {
@Override
public void eventOccurred(Object content, int type) {
if (getHost().getLinkLayer().hasPhy(PhyType.WIFI)) {
new SiSTopologyProvider(sis, SiSTypes.NEIGHBORS_WIFI,
DefaultTopologyComponent.this,
getTopologyID(NetInterfaceName.WIFI, true),
DefaultTopologyComponent.class);
@Override
public SiSInfoProperties getInfoProperties() {
return new SiSInfoProperties();
}
});
// Provide Underlay topology
Event.scheduleImmediately(new EventHandler() {
@Override
public void eventOccurred(Object content, int type) {
if (getHost().getLinkLayer().hasPhy(PhyType.WIFI)) {
new SiSTopologyProvider(sis,
SiSTypes.NEIGHBORS_WIFI,
DefaultTopologyComponent.this,
getTopologyID(NetInterfaceName.WIFI, true),
DefaultTopologyComponent.class);
}
}
}
}, null, 0);
}, null, 0);
} catch (ComponentNotAvailableException e) {
// OK
} catch (ComponentNotAvailableException e) {
// OK
}
}
}
......@@ -285,6 +291,18 @@ public class DefaultTopologyComponent implements TopologyComponent {
@Override
public void updateCurrentLocation(Location 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
for (LocationListener locationListener : listeners) {
locationListener.onLocationChanged(getHost(), getLastLocation());
......@@ -295,6 +313,7 @@ public class DefaultTopologyComponent implements TopologyComponent {
public void setTargetAttractionPoint(AttractionPoint targetAttractionPoint)
throws UnsupportedOperationException {
movementModel.changeTargetLocation(this, targetAttractionPoint);
// NodeDebugMonitor.update(this.getClass(), getHost().getId(), "Target Location", targetAttractionPoint);
}
@Override
......
......@@ -23,8 +23,6 @@ package de.tud.kom.p2psim.impl.topology;
import java.awt.Point;
import java.util.Arrays;
import org.aopalliance.aop.AspectException;
import com.vividsolutions.jts.geom.Coordinate;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
......
......@@ -71,6 +71,8 @@ public class TopologyFactory implements HostComponentFactory {
private WaypointModel waypointModel;
private ObstacleModel obstacleModel;
private boolean registerAsInformationProviderInSiS = false;
private static NetMeasurementDB measurementDB = null;
......@@ -125,7 +127,7 @@ public class TopologyFactory implements HostComponentFactory {
* movement model.
*/
TopologyComponent toCo = new DefaultTopologyComponent(host, topo,
movement, placement);
movement, placement, registerAsInformationProviderInSiS);
/*
* Need to register TopoViews as movement listeners, as they might need
......@@ -227,6 +229,17 @@ public class TopologyFactory implements HostComponentFactory {
public void setUseRegionGroups(boolean useRegionGroups) {
TopologyFactory.useRegionGroups = useRegionGroups;
}
/**
* Option to disable the default behavior of nodes registering as
* topology providers.
*
* @param registerAsLocationProviderInSiS
*/
public void setRegisterAsInformationProviderInSiS(
boolean registerAsInformationProviderInSiS) {
this.registerAsInformationProviderInSiS = registerAsInformationProviderInSiS;
}
/**
* Allows GNP-based strategies to retrieve the unique
......
......@@ -26,6 +26,7 @@ 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;
import de.tud.kom.p2psim.impl.util.Either;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor;
public abstract class AbstractLocalMovementStrategy implements
LocalMovementStrategy {
......@@ -34,6 +35,8 @@ public abstract class AbstractLocalMovementStrategy implements
protected ObstacleModel obstacleModel;
private static boolean calculateRouteSegments = false;
private double scaleFactor = 1;
public double getMovementSpeed(SimLocationActuator ms) {
......@@ -57,6 +60,37 @@ public abstract class AbstractLocalMovementStrategy implements
this.obstacleModel = model;
}
protected boolean isCalculateRouteSegments() {
return calculateRouteSegments;
}
/**
* For the visualization: programmatically enable route segment
* calculations.
*/
public static void setCalculationOfRouteSegments(boolean setting) {
calculateRouteSegments = setting;
}
/**
* For the visualization: programmatically check route segment
* calculation.
*/
public static boolean isCalculatingRouteSegments() {
return calculateRouteSegments;
}
/**
* If you intend to use the {@link RouteSensor} and operate on a per-segment
* basis, set this to true. If you DO NOT use the respective segment data,
* set it to false, as this option consumes significant resources.
*
* @param calculateRouteSegments
*/
public void setCalculateRouteSegments(boolean calculateRouteSegments) {
this.calculateRouteSegments = calculateRouteSegments;
}
@Override
public abstract Either<PositionVector, Boolean> nextPosition(
SimLocationActuator comp, PositionVector destination);
......
......@@ -53,7 +53,7 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
private PositionVector worldDimensions;
private static HashMap<Integer, RealWorldMovementPoints> movementPoints = new HashMap<>();
private static HashMap<SimLocationActuator, RouteImpl> movementPoints = new HashMap<>();
private String movementType; // {Fastest, Shortest, Pedestrian, Bicycle}
private String mapQuestKey;
......@@ -82,8 +82,8 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
newPosition = destination.clone();
} else {
//if not set already for this node or new destination is different than last one
PointList pointList;
if(!movementPoints.containsKey(comp.hashCode()) || destination.distanceTo(movementPoints.get(comp.hashCode()).getDestination()) > 1.0) {
RouteImpl trajectory = movementPoints.get(comp);
if(trajectory == null || destination.distanceTo(trajectory.getDestination()) > 1.0) {
double[] startPosition = transformOwnWorldWindowToGPS(comp.getRealPosition().getX(), comp.getRealPosition().getY());
double[] destinationPosition = transformOwnWorldWindowToGPS(destination.getX(), destination.getY());
......@@ -110,7 +110,7 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
}
//read in all waypoints
pointList = new PointList();
PointList pointList = new PointList();
if(allDirections != null) {
for(int i = 0; i < allDirections.length(); i++) {
try {
......@@ -123,25 +123,12 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
}
}
}
movementPoints.put(comp.hashCode(), new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0));
}
else {
pointList = movementPoints.get(comp.hashCode()).getPointList();
trajectory = new RouteImpl(comp.getRealPosition(), destination, pointList);
movementPoints.put(comp, trajectory);
}
int actualIndex = movementPoints.get(comp.hashCode()).getActualIndex();
int i = 0;
for(GHPoint3D temp : pointList) {
if(i==actualIndex) {
PositionVector nextPoint = transformGPSWindowToOwnWorld(temp.getLat(), temp.getLon());
newPosition = comp.getRealPosition().moveStep(nextPoint, getMovementSpeed(comp));
if(nextPoint.distanceTo(comp.getRealPosition()) < maxDistanceNextPoint) actualIndex++;
}
i++;
}
newPosition = trajectory.updateCurrentLocation(comp, getMovementSpeed(comp), 1.0);
movementPoints.put(comp.hashCode(), new RealWorldMovementPoints(movementPoints.get(comp.hashCode()).getStart(), destination, pointList, actualIndex));
}
return new Left<PositionVector, Boolean>(newPosition);
}
......@@ -159,18 +146,6 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
return gps_coordinates;
}
/**
* Projects the gps coordinates in the given gps window to the world-coordinates given in world-dimensions
* @param lat
* @param lon
* @return The projected position in world-dimensions
*/
private PositionVector transformGPSWindowToOwnWorld(double lat, double lon) {
double x = worldDimensions.getX() * (lon - lonLeft)/(lonRight - lonLeft);
double y = worldDimensions.getY() - worldDimensions.getY() * (lat - latLeft)/(latRight - latLeft);
return new PositionVector(x, y);
}
public void setMovementType(String movementType) {
this.movementType = movementType;
}
......
......@@ -21,51 +21,72 @@
package de.tud.kom.p2psim.impl.topology.movement.local;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import com.graphhopper.GHRequest;
import com.graphhopper.GHResponse;
import com.graphhopper.GraphHopper;
import com.graphhopper.PathWrapper;
import com.graphhopper.routing.util.EdgeFilter;
import com.graphhopper.routing.util.EncodingManager;
import com.graphhopper.routing.util.TraversalMode;
import com.graphhopper.storage.index.LocationIndex;
import com.graphhopper.storage.index.QueryResult;
import com.graphhopper.util.DistanceCalc2D;
import com.graphhopper.util.EdgeIteratorState;
import com.graphhopper.util.Instruction;
import com.graphhopper.util.InstructionList;
import com.graphhopper.util.PointList;
import com.graphhopper.util.shapes.GHPoint;
import com.graphhopper.util.shapes.GHPoint3D;
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.GPSCalculation;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.RouteSensorComponent;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Left;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
/**
* 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
* @version 1.0, 07.07.2015
*/
public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
private PositionVector worldDimensions;
private static PositionVector worldDimensions;
private GraphHopper hopper;
private LocationIndex index;
private boolean init = false;
private static HashMap<SimLocationActuator, RealWorldMovementPoints> movementPoints = new HashMap<>();
private static HashMap<SimLocationActuator, RouteImpl> currentRoutes = new HashMap<>();
private Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
private String osmFileLocation; //use pbf-format, because osm-format causes problems (xml-problems)
private String graphFolderFiles;
private String movementType; //car, bike or foot
private String navigationalType; //fastest,
private double latLeft; //Values from -90 to 90; always smaller than latRight
private double latRight; //Values from -90 to 90
private double lonLeft; //Values from -180 to 180; Always smaller than lonRight
private double lonRight; //Values from -180 to 180
private String defaultMovement;
private String navigationalType; //fastest,
private static double latLower; //Values from -90 to 90; always smaller than latUpper
private static double latUpper; //Values from -90 to 90
private static double lonLeft; //Values from -180 to 180; Always smaller than lonRight
private static double lonRight; //Values from -180 to 180
private boolean uniqueFolders;
/**
* Tolerance in meters (if the node reached a waypoint up to "tolerance"
* meters, it will select the next waypoint in the path.
......@@ -73,17 +94,19 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
private double tolerance = 1;
public RealWorldStreetsMovement() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
latLeft = GPSCalculation.getLatLower();
latRight = GPSCalculation.getLatUpper();
latLower = GPSCalculation.getLatLower();
latUpper = GPSCalculation.getLatUpper();
lonLeft = GPSCalculation.getLonLeft();
lonRight = GPSCalculation.getLonRight();
}
private void init() {
hopper = new GraphHopper().forServer();
hopper.setOSMFile(osmFileLocation);
// where to store graphhopper files?
if (uniqueFolders) {
Monitor.log(RealWorldStreetsMovement.class, Level.WARN,
......@@ -97,19 +120,48 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
}
hopper.setEncodingManager(new EncodingManager(movementType));
hopper.importOrLoad();
index = hopper.getLocationIndex();
init = true;
}
@Override
public Either<PositionVector, Boolean> nextPosition(
SimLocationActuator comp, PositionVector destination) {
return nextPosition(comp, destination, defaultMovement);
}
public Either<PositionVector, Boolean> nextPosition(SimLocationActuator comp,
PositionVector destination) {
if(!init) init();
PositionVector destination, String movementType) {
if (movementType == null || movementType.equals("")
|| !this.movementType.contains(movementType)) {
throw new AssertionError("Invalid movement type: " + movementType);
}
if (!init) {
init();
}
RouteSensorComponent routeSensor = routeSensorComponents.get(comp);
if (routeSensor == null) {
try {
routeSensorComponents.put(comp, comp.getHost()
.getComponent(RouteSensorComponent.class));
routeSensor = routeSensorComponents.get(comp);
} catch (ComponentNotAvailableException e) {
throw new AssertionError(
"The movement model needs to provide RouteSensorComponents.");
}
}
PositionVector newPosition = null;
if (destination
.distanceTo(comp.getRealPosition()) > getMovementSpeed(comp)) {
//if not set already for this node or new destination is different than last one
PointList pointList;
if(!movementPoints.containsKey(comp) || destination.distanceTo(movementPoints.get(comp).getDestination()) > 1.0) {
RouteImpl trajectory = currentRoutes.get(comp);
if(trajectory == null || destination.distanceTo(trajectory.getDestination()) > 1.0) {
double[] startPosition = transformOwnWorldWindowToGPS(comp.getRealPosition().getX(), comp.getRealPosition().getY());
double[] destinationPosition = transformOwnWorldWindowToGPS(destination.getX(), destination.getY());
GHRequest req = new GHRequest(startPosition[0], startPosition[1], destinationPosition[0], destinationPosition[1]).
......@@ -119,51 +171,129 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
GHResponse rsp = hopper.route(req);
//If the requested point is not in the map data, simple return the destination as next point
if(rsp.hasErrors()) {
System.err.println("Requested Points (" + startPosition[0] + ", " + startPosition[1]
+ ") or (" + destinationPosition[0] + ", " + destinationPosition[1] + ") are out of the bounding box.");
Monitor.log(this.getClass(), Monitor.Level.ERROR, "Routing request for Host %s with starting point (" +
"%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.add(new GHPoint(destination.getLatitude(), destination.getLongitude()));
movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0));
}
else {
pointList = rsp.getPoints();
movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0));
PointList pointList = new PointList();
pointList.add(new GHPoint(destinationPosition[0], destinationPosition[1]));
trajectory = new RouteImpl(comp.getRealPosition(), destination, pointList);
currentRoutes.put(comp, trajectory);
} else {
PointList pointList = rsp.getBest().getPoints();
if (isCalculateRouteSegments()) {
/*
* Obtain segment IDs along the route.
*/
trajectory = new RouteImpl(comp.getRealPosition(),
destination, pointList,
routeSensor.getSegmentListeners(), routeSensor,
calculateSegments(rsp.getBest()));
} else {
trajectory = new RouteImpl(comp.getRealPosition(),
destination, pointList);
}
currentRoutes.put(comp, trajectory);
}
routeSensor.setNewRoute(trajectory);
}
else {
pointList = movementPoints.get(comp).getPointList();
newPosition = trajectory.updateCurrentLocation(comp, getMovementSpeed(comp), tolerance);
if (trajectory.reachedDestination()) {
routeSensor.reachedDestination();
}
int actualIndex = movementPoints.get(comp).getActualIndex();
int i = 0;
for(GHPoint3D temp : pointList) {
if(i==actualIndex) {
PositionVector nextPoint = transformGPSWindowToOwnWorld(temp.getLat(), temp.getLon());
newPosition = comp.getRealPosition().moveStep(nextPoint, getMovementSpeed(comp));
if (nextPoint
.distanceTo(comp.getRealPosition()) < tolerance) {
actualIndex++;
}
return new Left<PositionVector, Boolean>(newPosition);
}
/**
* Calculate RouteSegments using the PathWrapper
* @param pathWrapper
* @return
*/
private List<RouteSegmentImpl> calculateSegments(PathWrapper pathWrapper) {
InstructionList instructions = pathWrapper.getInstructions();
int ptIdx = 0;
List<RouteSegmentImpl> segments = new LinkedList<>();
RouteSegmentImpl lastSegment = null;
for (Instruction instr : instructions) {
RouteSegmentImpl segment = null;
PointList points = instr.getPoints();
String name = instr.getName();
if (name.isEmpty()) {
name = Integer.toString(instr.getPoints().toGHPoint(0).hashCode());
}
for (GHPoint point : points) {
if (segment == null) {
if (lastSegment != null) {
lastSegment.addRouteLocation(transformGPSWindowToOwnWorld(
point.getLat(), point.getLon()));
}
segment = new RouteSegmentImpl(name, ptIdx, transformGPSWindowToOwnWorld(point.getLat(),
point.getLon()));
} else {
segment.addRouteLocation(transformGPSWindowToOwnWorld(
point.getLat(), point.getLon()));
}
i++;
ptIdx++;
}
movementPoints.put(comp, new RealWorldMovementPoints(movementPoints.get(comp).getStart(), destination, pointList, actualIndex));
lastSegment = segment;
segments.add(segment);
}
return new Left<PositionVector, Boolean>(newPosition);
return segments;
}
/**
* Projects the world coordinates in the given gps window to the gps-coordinates
* Calculate the route segments along the given point list.
*
* @return
*/
private List<RouteSegmentImpl> calculateSegments(PointList pointList) {
int ptIdx = 0;
int prevEdgeId = -1;
List<RouteSegmentImpl> segments = new LinkedList<>();
RouteSegmentImpl lastSegment = null;
for (GHPoint point : pointList) {
QueryResult qr = index.findClosest(point.getLat(), point.getLon(),
EdgeFilter.ALL_EDGES);
EdgeIteratorState nearEdge = qr.getClosestEdge();
if (nearEdge != null) {
int edgeId = nearEdge.getEdge();
if (edgeId != prevEdgeId) {
if (lastSegment != null) {
lastSegment.addRouteLocation(
transformGPSWindowToOwnWorld(point.getLat(),
point.getLon()));
}
lastSegment = new RouteSegmentImpl(Integer.toString(edgeId),
ptIdx, transformGPSWindowToOwnWorld(point.getLat(),
point.getLon()));
segments.add(lastSegment);
} else {
lastSegment.addRouteLocation(transformGPSWindowToOwnWorld(
point.getLat(), point.getLon()));
}
}
ptIdx++;
}
return segments;
}
/**
* Projects the world coordinates in the given gps window to the
* gps-coordinates
*
* @param x
* @param y
* @return The projected position in gps-coordinates (lat, long)
*/
private double[] transformOwnWorldWindowToGPS(double x, double y) {
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();
return gps_coordinates;
}
......@@ -174,15 +304,68 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
* @param lon
* @return The projected position in world-dimensions
*/
private PositionVector transformGPSWindowToOwnWorld(double lat, double lon) {
public static PositionVector transformGPSWindowToOwnWorld(double lat, double lon) {
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.min(worldDimensions.getX(), x);
y = Math.max(0, y);
y = Math.min(worldDimensions.getY(), 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 = currentRoutes.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 currentRoutes.get(ms).getPointList().calcDistance(new DistanceCalc2D());
}
public void setOsmFileLocation(String osmFileLocation) {
this.osmFileLocation = osmFileLocation;
......@@ -194,6 +377,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
public void setMovementType(String movementType) {
this.movementType = movementType;
defaultMovement = movementType.split(",")[0];
}
public void setNavigationalType(String navigationalType) {
......@@ -203,13 +387,13 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
public void setWaypointTolerance(double tolerance) {
this.tolerance = tolerance;
}
/**
* For large batch simulations, we need to prevent same-time access to
* garphhopper temp data. Therefore, this flag creates unique folders for
* each run (which, obviously, wastes a lot of space and comp-resources and
* should not be used in standalone, single-threaded demo mode...)
*
*
* @param uniqueFolders
*/
public void setCreateUniqueFolders(boolean uniqueFolders) {
......
/*
* 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.local;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import com.graphhopper.util.PointList;
import com.graphhopper.util.shapes.GHPoint3D;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
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.RouteSensor;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor.RouteSegmentListener;
/**
* This class contains one trajectory from a start to a destination. It saves
* the respective points (coordinates) along the path with a given movement
* speed and also (if enabled) the assigned IDs of the roads and walkways that
* are traversed.
*
* TODO add segment handling
*
* Segment handling is only done if there is a segment listener registered for
* the respective client.
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 9, 2017
*/
public class RouteImpl implements Route {
private final RouteSensor sensor;
private PositionVector start;
private PositionVector destination;
private PointList pointList;
private final List<PositionVector> positionsList;
private final List<RouteSegmentImpl> routeSegments;
private final Set<RouteSegmentListener> segmentListeners;
private int currentIndex;
private int currentSegmentIndex;
private int routeLength;
private int routeSegmentsLength;
private boolean reachedTarget;
/**
*
* @param start
* @param destination
* @param pointList
* @param segmentListeners
* @param routeSegments
*/
public RouteImpl(PositionVector start,
PositionVector destination, PointList pointList,
Set<RouteSegmentListener> segmentListeners, RouteSensor sensor,
List<RouteSegmentImpl> routeSegments) {
this.sensor = sensor;
this.start = start;
this.destination = destination;
this.pointList = pointList;
this.positionsList = new LinkedList<>();
// Create Position vectors ONCE
for (GHPoint3D temp : pointList) {
positionsList
.add(RealWorldStreetsMovement.transformGPSWindowToOwnWorld(
temp.getLat(), temp.getLon()));
}
routeLength = positionsList.size();
this.segmentListeners = segmentListeners;
this.routeSegments = routeSegments;
this.routeSegmentsLength = routeSegments.size();
}
/**
*
* @param start
* @param destination
* @param pointList
*/
public RouteImpl(PositionVector start,
PositionVector destination, PointList pointList) {
this(start, destination, pointList, Collections.emptySet(), null,
Collections.emptyList());
}
public PositionVector getStart() {
return start;
}
public PositionVector getDestination() {
return destination;
}
@Override
public Location getTargetLocation() {
return destination;
}
@Override
public boolean hasSegmentInformation() {
return routeSegmentsLength != 0;
}
@Override
public RouteSegment getCurrentSegment() {
if (!hasSegmentInformation()) {
throw new UnsupportedOperationException(
"To access segments within a Route, you need to enable the respective functionality in the local movement strategy (usually: calculateRouteSegments=true)");
}
return routeSegments.get(currentSegmentIndex);
}
@Override
public List<RouteSegment> getSegmentsAhead() {
if (!hasSegmentInformation()) {
throw new UnsupportedOperationException(
"To access segments within a Route, you need to enable the respective functionality in the local movement strategy (usually: calculateRouteSegments=true)");
}
return Collections.unmodifiableList(routeSegments
.subList(currentSegmentIndex, routeSegmentsLength));
}
@Override
public List<RouteSegment> getSegmentsBehind() {
if (!hasSegmentInformation()) {
throw new UnsupportedOperationException(
"To access segments within a Route, you need to enable the respective functionality in the local movement strategy (usually: calculateRouteSegments=true)");
}
return Collections.unmodifiableList(routeSegments
.subList(0, currentSegmentIndex));
}
/**
* Update the internal location with the given movement speed
*
* @param speed
* @param realPosition
* @return
*/
public PositionVector updateCurrentLocation(SimLocationActuator comp,
double speed, double tolerance) {
List<PositionVector> sublist = positionsList.subList(currentIndex,
routeLength);
PositionVector newPosition = null;
for (PositionVector candidate : sublist) {
newPosition = comp.getRealPosition().moveStep(candidate, speed);
if (candidate.distanceTo(comp.getRealPosition()) < tolerance) {
currentIndex++;
} else {
break;
}
}
/*
* Segment handling (also inform listeners!)
*/
if (routeSegmentsLength > 0
&& routeSegmentsLength > currentSegmentIndex) {
List<RouteSegmentImpl> segmentSublist = routeSegments
.subList(currentSegmentIndex + 1, routeSegmentsLength);
for (RouteSegmentImpl candidate : segmentSublist) {
if (candidate.getFromRouteIndex() >= currentIndex) {
break;
}
currentSegmentIndex++;
segmentListeners.forEach(l -> l.onChangedRouteSegment(sensor,
this, routeSegments.get(currentSegmentIndex - 1),
candidate));
}
}
/*
* Reached target flag
*/
if (currentIndex >= routeLength) {
reachedTarget = true;
}
return newPosition;
}
/**
* True, if the trajectory is done and the node reached the target.s
*
* @return
*/
public boolean reachedDestination() {
return reachedTarget;
}
@Override
public String toString() {
return "\n\tfrom " + start.toString() + " to " + destination.toString()
+ "\n\tstep: " + currentIndex + " length: " + routeLength;
}
public PointList getPointList() {
return pointList;
}
public int getCurrentIndex() {
return this.currentIndex;
}
}
/*
* 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.local;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route.RouteSegment;
/**
* Implementation of a {@link RouteSegment}
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 10, 2017
*/
public class RouteSegmentImpl implements RouteSegment {
private final String id;
private final int fromRouteIndex;
private final List<Location> routeLocations;
/**
* The segment and associated points (via their index)
*
* @param id
* @param fromRouteIndex
*/
public RouteSegmentImpl(String id, int fromRouteIndex,
Location startLocation) {
this.id = id;
this.fromRouteIndex = fromRouteIndex;
this.routeLocations = new LinkedList<>();
this.routeLocations.add(startLocation);
}
public void addRouteLocation(Location location) {
this.routeLocations.add(location);
}
@Override
public String getSegmentId() {
return id;
}
@Override
public List<Location> getSegmentLocations() {
return Collections.unmodifiableList(routeLocations);
}
public int getFromRouteIndex() {
return fromRouteIndex;
}
}
......@@ -25,7 +25,15 @@ import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.Visualiza
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
* @version 1.0, Nov 3, 2015
*/
......@@ -37,7 +45,10 @@ public class GPSCalculation {
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-
......@@ -64,7 +75,8 @@ public class GPSCalculation {
* is valid on all zoom levels.
*/
// 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() {
......@@ -79,54 +91,58 @@ public class GPSCalculation {
return zoom;
}
public static double getLatUpper() {
return latCenter + (Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getY() / 111111d) * scaleFactor;
public static double getMetersPerPixel()
{
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
// .getComponentOrNull(Topology.class).getWorldDimensions().getY()
// / 1000;
public static double getLatUpper() {
return latCenter + ((Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getY()/2) / 111111d);
}
public static double getLatLower() {
return latCenter - (Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getY() / 111111d) * scaleFactor;
// return latCenter - scaleFactor * 0.027613 * Binder
// .getComponentOrNull(Topology.class).getWorldDimensions().getY()
// / 1000;
return latCenter - ((Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getY()/2) / 111111d);
}
public static double getLonLeft() {
return lonCenter - (Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getX() / 111111d / scaleLon) * scaleFactor;
// return lonCenter - scaleFactor * 0.043 * Binder
// .getComponentOrNull(Topology.class).getWorldDimensions().getX()
// / 1000;
return lonCenter - ((Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getX()/2) / (111111d * scaleLon));
}
public static double getLonRight() {
return lonCenter + (Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getX() / 111111d / scaleLon) * scaleFactor;
// return lonCenter + scaleFactor * 0.043 * Binder
// .getComponentOrNull(Topology.class).getWorldDimensions().getX()
// / 1000;
return lonCenter + ((Binder.getComponentOrNull(Topology.class)
.getWorldDimensions().getX()/2) / (111111d * scaleLon));
}
public void setLatCenter(double latCenter) {
this.latCenter = latCenter;
this.scaleLon = Math.cos(Math.toRadians(latCenter));
this.scaleFactor = 0.38d;
}
public void setLonCenter(double lonCenter) {
this.lonCenter = lonCenter;
}
/**
* Formula http://wiki.openstreetmap.org/wiki/Zoom_levels
*
* @param 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();
}
}
......@@ -24,13 +24,10 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.Vector;
import javax.swing.JComponent;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
......@@ -52,7 +49,6 @@ import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationActuator;
/**
* Modular Movement Model uses different models/strategies to create a movement
......@@ -65,7 +61,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationAc
* M1: A general {@link MovementModel} is not used, because we use static
* attraction points.
* <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.
* It doesn't move the Hosts! It will be only assignment a new AttractionPoint!
*
......@@ -85,7 +81,12 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.LocationAc
* destination point (AttractionPoint), so that not all hosts, which are
* 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
* @version 1.0, 07.07.2015
......@@ -106,10 +107,14 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
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, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
private boolean initialized = false;
private long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
......@@ -132,8 +137,10 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
public void initialize() {
if (!initialized) {
VisualizationInjector
.injectComponent(new ModularMovementModelViz(this));
if (modelVisualisation == null) {
modelVisualisation = new ModularMovementModelViz(this);
}
VisualizationInjector.injectComponent(modelVisualisation);
if (mapVisualization != null) {
VisualizationInjector.injectComponent(mapVisualization);
}
......@@ -215,8 +222,11 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
@Override
public void addComponent(SimLocationActuator comp) {
moveableHosts.add(comp);
if (!routeSensorComponents.containsKey(comp)) {
routeSensorComponents.put(comp, new RouteSensorComponent(comp));
}
}
public Set<SimLocationActuator> getAllLocationActuators() {
return moveableHosts;
}
......@@ -230,7 +240,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
"time is negative for the Move Operations");
}
}
@Override
public void updatedAttractionAssignment(SimLocationActuator component,
AttractionPoint newAssignment) {
......@@ -244,7 +254,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
* Even if an AP does not have a radius, we slightly offset
*/
double apRadius = Math.max(newAssignment.getRadius(), 25.0);
int tries = 0;
do {
destination = new PositionVector(attractionCenter);
......@@ -268,7 +278,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
}
tries++;
} while (destination == null);
currentTarget.put(component, destination);
}
......@@ -290,7 +300,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
* @param ms
* @param destination
*/
private void doLocalMovement(SimLocationActuator ms,
protected void doLocalMovement(SimLocationActuator ms,
PositionVector destination) {
Either<PositionVector, Boolean> either = localMovementStrategy
......@@ -331,6 +341,12 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
this.mapVisualization = mapVisualization;
}
public void setModelVisualisation(ModularMovementModelViz modelVis)
{
modelVisualisation = modelVis;
modelVisualisation.setMovementModel(this);
}
@Override
public void eventOccurred(Object content, int type) {
if (type == EVENT_INIT) {
......
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