Commit 5562c3fe authored by Simon Luser's avatar Simon Luser
Browse files

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

parents 4ea84d33 679a6f50
...@@ -23,8 +23,6 @@ package de.tud.kom.p2psim.impl.topology; ...@@ -23,8 +23,6 @@ package de.tud.kom.p2psim.impl.topology;
import java.awt.Point; import java.awt.Point;
import java.util.Arrays; import java.util.Arrays;
import org.aopalliance.aop.AspectException;
import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Coordinate;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
......
...@@ -26,6 +26,7 @@ import de.tud.kom.p2psim.api.topology.obstacles.ObstacleModel; ...@@ -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.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.topology.PositionVector; import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.util.Either; import de.tud.kom.p2psim.impl.util.Either;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor;
public abstract class AbstractLocalMovementStrategy implements public abstract class AbstractLocalMovementStrategy implements
LocalMovementStrategy { LocalMovementStrategy {
...@@ -34,6 +35,8 @@ public abstract class AbstractLocalMovementStrategy implements ...@@ -34,6 +35,8 @@ public abstract class AbstractLocalMovementStrategy implements
protected ObstacleModel obstacleModel; protected ObstacleModel obstacleModel;
private static boolean calculateRouteSegments = false;
private double scaleFactor = 1; private double scaleFactor = 1;
public double getMovementSpeed(SimLocationActuator ms) { public double getMovementSpeed(SimLocationActuator ms) {
...@@ -57,6 +60,37 @@ public abstract class AbstractLocalMovementStrategy implements ...@@ -57,6 +60,37 @@ public abstract class AbstractLocalMovementStrategy implements
this.obstacleModel = model; 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 @Override
public abstract Either<PositionVector, Boolean> nextPosition( public abstract Either<PositionVector, Boolean> nextPosition(
SimLocationActuator comp, PositionVector destination); SimLocationActuator comp, PositionVector destination);
......
...@@ -53,7 +53,7 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy { ...@@ -53,7 +53,7 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
private PositionVector worldDimensions; 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 movementType; // {Fastest, Shortest, Pedestrian, Bicycle}
private String mapQuestKey; private String mapQuestKey;
...@@ -82,8 +82,8 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy { ...@@ -82,8 +82,8 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
newPosition = destination.clone(); newPosition = destination.clone();
} else { } else {
//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; RouteImpl trajectory = movementPoints.get(comp);
if(!movementPoints.containsKey(comp.hashCode()) || destination.distanceTo(movementPoints.get(comp.hashCode()).getDestination()) > 1.0) { if(trajectory == null || destination.distanceTo(trajectory.getDestination()) > 1.0) {
double[] startPosition = transformOwnWorldWindowToGPS(comp.getRealPosition().getX(), comp.getRealPosition().getY()); double[] startPosition = transformOwnWorldWindowToGPS(comp.getRealPosition().getX(), comp.getRealPosition().getY());
double[] destinationPosition = transformOwnWorldWindowToGPS(destination.getX(), destination.getY()); double[] destinationPosition = transformOwnWorldWindowToGPS(destination.getX(), destination.getY());
...@@ -110,7 +110,7 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy { ...@@ -110,7 +110,7 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
} }
//read in all waypoints //read in all waypoints
pointList = new PointList(); PointList pointList = new PointList();
if(allDirections != null) { if(allDirections != null) {
for(int i = 0; i < allDirections.length(); i++) { for(int i = 0; i < allDirections.length(); i++) {
try { try {
...@@ -123,25 +123,12 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy { ...@@ -123,25 +123,12 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
} }
} }
} }
movementPoints.put(comp.hashCode(), new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0)); trajectory = new RouteImpl(comp.getRealPosition(), destination, pointList);
movementPoints.put(comp, trajectory);
} }
else {
pointList = movementPoints.get(comp.hashCode()).getPointList();
}
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++; newPosition = trajectory.updateCurrentLocation(comp, getMovementSpeed(comp), 1.0);
}
i++;
}
movementPoints.put(comp.hashCode(), new RealWorldMovementPoints(movementPoints.get(comp.hashCode()).getStart(), destination, pointList, actualIndex));
} }
return new Left<PositionVector, Boolean>(newPosition); return new Left<PositionVector, Boolean>(newPosition);
} }
...@@ -159,18 +146,6 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy { ...@@ -159,18 +146,6 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
return gps_coordinates; 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) { public void setMovementType(String movementType) {
this.movementType = movementType; this.movementType = movementType;
} }
......
...@@ -20,26 +20,37 @@ ...@@ -20,26 +20,37 @@
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.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.GHRequest;
import com.graphhopper.GHResponse; import com.graphhopper.GHResponse;
import com.graphhopper.GraphHopper; import com.graphhopper.GraphHopper;
import com.graphhopper.routing.util.EdgeFilter;
import com.graphhopper.routing.util.EncodingManager; import com.graphhopper.routing.util.EncodingManager;
import com.graphhopper.storage.index.LocationIndex;
import com.graphhopper.storage.index.QueryResult;
import com.graphhopper.util.DistanceCalc2D; import com.graphhopper.util.DistanceCalc2D;
import com.graphhopper.util.EdgeIteratorState;
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 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.topology.movement.modularosm.RouteSensorComponent;
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 de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
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
...@@ -52,21 +63,24 @@ import java.util.*; ...@@ -52,21 +63,24 @@ import java.util.*;
*/ */
public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
private PositionVector worldDimensions; private static PositionVector worldDimensions;
private GraphHopper hopper; private GraphHopper hopper;
private LocationIndex index;
private boolean init = false; 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 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 defaultMovement; private String defaultMovement;
private String navigationalType; //fastest, private String navigationalType; //fastest,
private double latLower; //Values from -90 to 90; always smaller than latUpper private static double latLower; //Values from -90 to 90; always smaller than latUpper
private double latUpper; //Values from -90 to 90 private static double latUpper; //Values from -90 to 90
private double lonLeft; //Values from -180 to 180; Always smaller than lonRight private static double lonLeft; //Values from -180 to 180; Always smaller than lonRight
private double lonRight; //Values from -180 to 180 private static double lonRight; //Values from -180 to 180
private boolean uniqueFolders; private boolean uniqueFolders;
/** /**
...@@ -76,12 +90,13 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -76,12 +90,13 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
private double tolerance = 1; private double tolerance = 1;
public RealWorldStreetsMovement() { public RealWorldStreetsMovement() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class) worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions(); .getWorldDimensions();
latLower = GPSCalculation.getLatLower(); latLower = GPSCalculation.getLatLower();
latUpper = GPSCalculation.getLatUpper(); latUpper = GPSCalculation.getLatUpper();
lonLeft = GPSCalculation.getLonLeft(); lonLeft = GPSCalculation.getLonLeft();
lonRight = GPSCalculation.getLonRight(); lonRight = GPSCalculation.getLonRight();
} }
private void init() { private void init() {
...@@ -101,28 +116,48 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -101,28 +116,48 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
} }
hopper.setEncodingManager(new EncodingManager(movementType)); hopper.setEncodingManager(new EncodingManager(movementType));
hopper.importOrLoad(); hopper.importOrLoad();
index = hopper.getLocationIndex();
init = true; init = true;
} }
public Either<PositionVector, Boolean> nextPosition(SimLocationActuator comp, PositionVector destination) @Override
{ public Either<PositionVector, Boolean> nextPosition(
SimLocationActuator comp, PositionVector destination) {
return nextPosition(comp, destination, defaultMovement); return nextPosition(comp, destination, defaultMovement);
} }
public Either<PositionVector, Boolean> nextPosition(SimLocationActuator comp, public Either<PositionVector, Boolean> nextPosition(SimLocationActuator comp,
PositionVector destination, String movementType) { PositionVector destination, String movementType) {
if(movementType == null || movementType.equals("") || !this.movementType.contains(movementType)) if (movementType == null || movementType.equals("")
|| !this.movementType.contains(movementType)) {
throw new AssertionError("Invalid movement type: " + 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.");
}
}
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; RouteImpl trajectory = currentRoutes.get(comp);
if(!movementPoints.containsKey(comp) || destination.distanceTo(movementPoints.get(comp).getDestination()) > 1.0) { if(trajectory == null || destination.distanceTo(trajectory.getDestination()) > 1.0) {
double[] startPosition = transformOwnWorldWindowToGPS(comp.getRealPosition().getX(), comp.getRealPosition().getY()); double[] startPosition = transformOwnWorldWindowToGPS(comp.getRealPosition().getX(), comp.getRealPosition().getY());
double[] destinationPosition = transformOwnWorldWindowToGPS(destination.getX(), destination.getY()); double[] destinationPosition = transformOwnWorldWindowToGPS(destination.getX(), destination.getY());
GHRequest req = new GHRequest(startPosition[0], startPosition[1], destinationPosition[0], destinationPosition[1]). GHRequest req = new GHRequest(startPosition[0], startPosition[1], destinationPosition[0], destinationPosition[1]).
...@@ -136,41 +171,79 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -136,41 +171,79 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
"%f,%f), destination (%f,%f) and type %s failed with error: %s.", comp.getHost().getId().valueAsString(),startPosition[0], startPosition[1], "%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()); destinationPosition[0], destinationPosition[1], movementType, rsp.getErrors());
pointList = new PointList(); PointList pointList = new PointList();
pointList.add(new GHPoint(destinationPosition[0], destinationPosition[1])); pointList.add(new GHPoint(destinationPosition[0], destinationPosition[1]));
movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0)); trajectory = new RouteImpl(comp.getRealPosition(), destination, pointList);
} currentRoutes.put(comp, trajectory);
else {
pointList = rsp.getBest().getPoints(); } else {
movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0)); PointList pointList = rsp.getBest().getPoints();
if (isCalculateRouteSegments()) {
/*
* Obtain segment IDs along the route.
*/
trajectory = new RouteImpl(comp.getRealPosition(),
destination, pointList,
routeSensor.getSegmentListeners(), routeSensor,
calculateSegments(pointList));
} else {
trajectory = new RouteImpl(comp.getRealPosition(),
destination, pointList);
} }
currentRoutes.put(comp, trajectory);
} }
else { routeSensor.setNewRoute(trajectory);
pointList = movementPoints.get(comp).getPointList();
} }
newPosition = trajectory.updateCurrentLocation(comp, getMovementSpeed(comp), tolerance);
int actualIndex = movementPoints.get(comp).getActualIndex(); if (trajectory.reachedDestination()) {
int i = 0; routeSensor.reachedDestination();
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++;
} }
} }
i++; return new Left<PositionVector, Boolean>(newPosition);
} }
movementPoints.put(comp, new RealWorldMovementPoints(movementPoints.get(comp).getStart(), destination, pointList, actualIndex)); /**
* 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()));
} }
return new Left<PositionVector, Boolean>(newPosition); 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 * Projects the world coordinates in the given gps window to the
* gps-coordinates
*
* @param x * @param x
* @param y * @param y
* @return The projected position in gps-coordinates (lat, long) * @return The projected position in gps-coordinates (lat, long)
...@@ -188,7 +261,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -188,7 +261,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
* @param lon * @param lon
* @return The projected position in world-dimensions * @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 x = worldDimensions.getX() * (lon - lonLeft)/(lonRight - lonLeft);
double y = worldDimensions.getY() - worldDimensions.getY() * (lat - latLower)/(latUpper - latLower); double y = worldDimensions.getY() - worldDimensions.getY() * (lat - latLower)/(latUpper - latLower);
x = Math.max(0, x); x = Math.max(0, x);
...@@ -207,7 +280,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -207,7 +280,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
public List<PositionVector> getMovementPoints(SimLocationActuator ms) public List<PositionVector> getMovementPoints(SimLocationActuator ms)
{ {
List<PositionVector> positions = new LinkedList<>(); List<PositionVector> positions = new LinkedList<>();
PointList pointList = movementPoints.get(ms).getPointList(); PointList pointList = currentRoutes.get(ms).getPointList();
pointList.forEach(p -> positions.add(new PositionVector(transformGPSWindowToOwnWorld(p.getLat(), p.getLon())))); pointList.forEach(p -> positions.add(new PositionVector(transformGPSWindowToOwnWorld(p.getLat(), p.getLon()))));
...@@ -248,7 +321,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy { ...@@ -248,7 +321,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
*/ */
public double getCurrentRouteLength(SimLocationActuator ms) public double getCurrentRouteLength(SimLocationActuator ms)
{ {
return movementPoints.get(ms).getPointList().calcDistance(new DistanceCalc2D()); return currentRoutes.get(ms).getPointList().calcDistance(new DistanceCalc2D());
} }
public void setOsmFileLocation(String osmFileLocation) { public void setOsmFileLocation(String osmFileLocation) {
......
/*
* 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;
}
}
...@@ -20,43 +20,57 @@ ...@@ -20,43 +20,57 @@
package de.tud.kom.p2psim.impl.topology.movement.local; package de.tud.kom.p2psim.impl.topology.movement.local;
import com.graphhopper.util.PointList; import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
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.RouteSegment;
public class RealWorldMovementPoints { /**
* Implementation of a {@link RouteSegment}
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 10, 2017
*/
public class RouteSegmentImpl implements RouteSegment {
private PositionVector start; private final String id;
private PositionVector destination;
private PointList pointList;
private int actualIndex;
public RealWorldMovementPoints(PositionVector start, PositionVector destination, PointList pointList, int actualIndex) { private final int fromRouteIndex;
this.start = start;
this.destination = destination;
this.pointList = pointList;
this.actualIndex = actualIndex;
}
public PositionVector getStart() { private final List<Location> routeLocations;
return start;
} /**
public void setStart(PositionVector start) { * The segment and associated points (via their index)
this.start = start; *
} * @param id
public PositionVector getDestination() { * @param fromRouteIndex
return destination; */
public RouteSegmentImpl(String id, int fromRouteIndex,
Location startLocation) {
this.id = id;
this.fromRouteIndex = fromRouteIndex;
this.routeLocations = new LinkedList<>();
this.routeLocations.add(startLocation);
} }
public void setDestination(PositionVector destination) {
this.destination = destination; public void addRouteLocation(Location location) {
this.routeLocations.add(location);
} }
public PointList getPointList() {
return pointList; @Override
public String getSegmentId() {
return id;
} }
public void setPointList(PointList pointList) {
this.pointList = pointList; @Override
public List<Location> getSegmentLocations() {
return Collections.unmodifiableList(routeLocations);
} }
public int getActualIndex() {
return this.actualIndex; public int getFromRouteIndex() {
return fromRouteIndex;
} }
} }
...@@ -24,13 +24,10 @@ import java.util.LinkedHashMap; ...@@ -24,13 +24,10 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.Vector; import java.util.Vector;
import javax.swing.JComponent;
import de.tud.kom.p2psim.api.scenario.ConfigurationException; import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.Topology; import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.MovementModel; import de.tud.kom.p2psim.api.topology.movement.MovementModel;
...@@ -52,7 +49,6 @@ import de.tudarmstadt.maki.simonstrator.api.EventHandler; ...@@ -52,7 +49,6 @@ import de.tudarmstadt.maki.simonstrator.api.EventHandler;
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.Time;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint; 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 * Modular Movement Model uses different models/strategies to create a movement
...@@ -117,6 +113,8 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -117,6 +113,8 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>(); private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>();
private Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
private boolean initialized = false; private boolean initialized = false;
private long timeBetweenMoveOperation = Simulator.SECOND_UNIT; private long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
...@@ -128,9 +126,6 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -128,9 +126,6 @@ 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);
} }
...@@ -142,6 +137,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -142,6 +137,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
public void initialize() { public void initialize() {
if (!initialized) { if (!initialized) {
if (modelVisualisation == null) {
modelVisualisation = new ModularMovementModelViz(this);
}
VisualizationInjector.injectComponent(modelVisualisation); VisualizationInjector.injectComponent(modelVisualisation);
if (mapVisualization != null) { if (mapVisualization != null) {
VisualizationInjector.injectComponent(mapVisualization); VisualizationInjector.injectComponent(mapVisualization);
...@@ -224,6 +222,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -224,6 +222,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
@Override @Override
public void addComponent(SimLocationActuator comp) { public void addComponent(SimLocationActuator comp) {
moveableHosts.add(comp); moveableHosts.add(comp);
if (!routeSensorComponents.containsKey(comp)) {
routeSensorComponents.put(comp, new RouteSensorComponent(comp));
}
} }
public Set<SimLocationActuator> getAllLocationActuators() { public Set<SimLocationActuator> getAllLocationActuators() {
......
...@@ -21,12 +21,16 @@ ...@@ -21,12 +21,16 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm; package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import java.awt.AlphaComposite; import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Point; import java.awt.Point;
import java.awt.RenderingHints; import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.JCheckBoxMenuItem; import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent; import javax.swing.JComponent;
...@@ -36,10 +40,20 @@ import javax.swing.event.ChangeListener; ...@@ -36,10 +40,20 @@ import javax.swing.event.ChangeListener;
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.local.AbstractLocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector; import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent; import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent;
import de.tud.kom.p2psim.impl.topology.views.visualization.world.NodeVisInteractionListener;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Oracle;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route.RouteSegment;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor;
/** /**
* Visualization Component of the Attraction Points in the Modular Movement * Visualization Component of the Attraction Points in the Modular Movement
...@@ -50,7 +64,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction ...@@ -50,7 +64,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
* @version 1.0, 02.07.2015 * @version 1.0, 02.07.2015
*/ */
public class ModularMovementModelViz extends JComponent public class ModularMovementModelViz extends JComponent
implements VisualizationComponent { implements VisualizationComponent, NodeVisInteractionListener {
protected ModularMovementModel movementModel; protected ModularMovementModel movementModel;
...@@ -58,29 +72,35 @@ public class ModularMovementModelViz extends JComponent ...@@ -58,29 +72,35 @@ public class ModularMovementModelViz extends JComponent
protected boolean showNodePositions = true; protected boolean showNodePositions = true;
protected boolean showTrajectories = false;
protected boolean setupCalculatesTrajectories = false;
private JMenu menu; private JMenu menu;
private Map<Long, TrajectoryVis> trajectoryVisualizations = new LinkedHashMap<>();
private final static int NODE_PAD = 2; private final static int NODE_PAD = 2;
private final static int ATTR_PAD = 5; private final static int ATTR_PAD = 5;
private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D"); private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D");
public ModularMovementModelViz() public ModularMovementModelViz() {
{
init(); init();
} }
protected void init() protected void init() {
{
setBounds(0, 0, VisualizationInjector.getWorldX(), setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY()); VisualizationInjector.getWorldY());
VisualizationInjector.addInteractionListener(this);
setOpaque(true); setOpaque(true);
setVisible(true); setVisible(true);
menu = new JMenu("Mobility Model"); menu = new JMenu("Mobility Model");
menu.add(createCheckboxAp()); menu.add(createCheckboxAp());
menu.add(createCheckboxNodePositions()); menu.add(createCheckboxNodePositions());
menu.add(createCheckboxTrajectories());
} }
public ModularMovementModelViz(ModularMovementModel model) { public ModularMovementModelViz(ModularMovementModel model) {
...@@ -114,6 +134,28 @@ public class ModularMovementModelViz extends JComponent ...@@ -114,6 +134,28 @@ public class ModularMovementModelViz extends JComponent
return checkBox; return checkBox;
} }
private JCheckBoxMenuItem createCheckboxTrajectories() {
setupCalculatesTrajectories = AbstractLocalMovementStrategy.isCalculatingRouteSegments();
final JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(
"show node trajectories", showTrajectories);
checkBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
showTrajectories = checkBox.isSelected();
if (!setupCalculatesTrajectories) {
AbstractLocalMovementStrategy
.setCalculationOfRouteSegments(showTrajectories);
}
VisualizationInjector.invalidate();
}
});
if (!setupCalculatesTrajectories) {
AbstractLocalMovementStrategy
.setCalculationOfRouteSegments(showTrajectories);
}
return checkBox;
}
@Override @Override
public void paint(Graphics g) { public void paint(Graphics g) {
super.paintComponent(g); super.paintComponent(g);
...@@ -131,6 +173,73 @@ public class ModularMovementModelViz extends JComponent ...@@ -131,6 +173,73 @@ public class ModularMovementModelViz extends JComponent
drawNodePosition(g2, comp); drawNodePosition(g2, comp);
} }
} }
if (showTrajectories) {
for (TrajectoryVis tVis : trajectoryVisualizations.values()) {
tVis.drawTrajectory(g2);
}
}
}
@Override
public void onHostClick(long hostID, boolean isActive) {
if (isActive) {
Host h = Oracle.getHostByID(INodeID.get(hostID));
try {
RouteSensor routeSensor = h.getComponent(RouteSensor.class);
trajectoryVisualizations.put(hostID,
new TrajectoryVis(routeSensor));
} catch (ComponentNotAvailableException e) {
// ignore.
}
} else {
trajectoryVisualizations.remove(hostID);
}
}
/**
* Visualizes the movement trajectory of a given node.
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 10, 2017
*/
private class TrajectoryVis {
private final RouteSensor routeSensor;
public TrajectoryVis(RouteSensor routeSensor) {
this.routeSensor = routeSensor;
}
public void drawTrajectory(Graphics2D g2) {
Route rt = routeSensor.getRoute();
if (!rt.hasSegmentInformation()) {
return;
}
for (RouteSegment segment : rt.getSegmentsAhead()) {
Location lastLoc = null;
for (Location loc : segment.getSegmentLocations()) {
if (lastLoc == null) {
lastLoc = loc;
continue;
}
g2.setColor(Color.MAGENTA);
g2.setStroke(new BasicStroke(3.0f));
g2.drawLine(
VisualizationInjector
.scaleValue(lastLoc.getLongitude()),
VisualizationInjector
.scaleValue(lastLoc.getLatitude()),
VisualizationInjector
.scaleValue(loc.getLongitude()),
VisualizationInjector
.scaleValue(loc.getLatitude()));
lastLoc = loc;
}
}
}
} }
/** /**
......
...@@ -3,7 +3,7 @@ package de.tud.kom.p2psim.impl.topology.movement.modularosm; ...@@ -3,7 +3,7 @@ package de.tud.kom.p2psim.impl.topology.movement.modularosm;
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.local.RealWorldMovementPoints; import de.tud.kom.p2psim.impl.topology.movement.local.RouteImpl;
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement; import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy; import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.util.Either; import de.tud.kom.p2psim.impl.util.Either;
......
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import java.util.LinkedHashSet;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor;
/**
* The OSM-based models provide an implementation of the {@link RouteSensor},
* which is added as a new host component. It is created by supporting mobility
* models, registers itself with the host container and can then be retrieved
* via the host container from w.g., a local movement strategy.
*
* @author Bjoern Richerzhagen
* @version 1.0, Aug 10, 2017
*/
public class RouteSensorComponent implements RouteSensor {
private final SimLocationActuator actuator;
private Route currentRoute;
private final Set<RouteListener> listeners;
private final Set<RouteSegmentListener> segmentListeners;
public RouteSensorComponent(SimLocationActuator actuator) {
this.actuator = actuator;
this.listeners = new LinkedHashSet<>();
this.segmentListeners = new LinkedHashSet<>();
actuator.getHost().registerComponent(RouteSensorComponent.this);
}
@Override
public void initialize() {
//
}
@Override
public void shutdown() {
//
}
public SimLocationActuator getActuator() {
return actuator;
}
@Override
public Host getHost() {
return actuator.getHost();
}
@Override
public Route getRoute() {
return currentRoute;
}
@Override
public void addRouteListener(RouteListener listener) {
listeners.add(listener);
}
@Override
public void removeRouteListener(RouteListener listener) {
listeners.remove(listener);
}
@Override
public void addRouteSegmentListener(RouteSegmentListener listener) {
segmentListeners.add(listener);
}
@Override
public void removeRouteSegmentListener(RouteSegmentListener listener) {
segmentListeners.remove(listener);
}
/*
* The following methods are used by the mobility models.
*/
public void setNewRoute(Route newRoute) {
// notifies listeners
listeners.forEach(l -> l.onChangedRoute(this, currentRoute, newRoute));
currentRoute = newRoute;
}
public void reachedDestination() {
// notifies listeners
listeners.forEach(l -> l.onReachedDestination(this, currentRoute));
}
public Set<RouteSegmentListener> getSegmentListeners() {
return segmentListeners;
}
}
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
package de.tud.kom.p2psim.impl.topology.views; package de.tud.kom.p2psim.impl.topology.views;
import java.util.Arrays;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
...@@ -43,7 +44,6 @@ import de.tudarmstadt.maki.simonstrator.api.Time; ...@@ -43,7 +44,6 @@ import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.handover.HandoverSensor; import de.tudarmstadt.maki.simonstrator.api.component.sensor.handover.HandoverSensor;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location; import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor; import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
import edu.emory.mathcs.backport.java.util.Arrays;
/** /**
* This topology view offers a topology for mobile apps - mobile clients * This topology view offers a topology for mobile apps - mobile clients
......
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