Commit 941fd777 authored by Björn Richerzhagen's avatar Björn Richerzhagen
Browse files

Merge branch '2-provide-routesensor-information-within-the-osm-mobility-models' into 'master'

Resolve "Provide RouteSensor Information within the OSM mobility models"

Closes #2

See merge request !19
parents 6c429d62 6d17b580
......@@ -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;
......
......@@ -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,29 @@ 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;
}
/**
* 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;
}
......
......@@ -20,26 +20,37 @@
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.routing.util.EdgeFilter;
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.EdgeIteratorState;
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.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.Left;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import java.util.*;
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
......@@ -52,21 +63,24 @@ import java.util.*;
*/
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 defaultMovement;
private String navigationalType; //fastest,
private double latLower; //Values from -90 to 90; always smaller than latUpper
private double latUpper; //Values from -90 to 90
private double lonLeft; //Values from -180 to 180; Always smaller than lonRight
private double lonRight; //Values from -180 to 180
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;
/**
......@@ -76,12 +90,13 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
private double tolerance = 1;
public RealWorldStreetsMovement() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
latLower = GPSCalculation.getLatLower();
latUpper = GPSCalculation.getLatUpper();
lonLeft = GPSCalculation.getLonLeft();
lonRight = GPSCalculation.getLonRight();
}
private void init() {
......@@ -101,28 +116,48 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
}
hopper.setEncodingManager(new EncodingManager(movementType));
hopper.importOrLoad();
index = hopper.getLocationIndex();
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);
}
public Either<PositionVector, Boolean> nextPosition(SimLocationActuator comp,
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);
}
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;
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
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]).
......@@ -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],
destinationPosition[0], destinationPosition[1], movementType, rsp.getErrors());
pointList = new PointList();
PointList pointList = new PointList();
pointList.add(new GHPoint(destinationPosition[0], destinationPosition[1]));
movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0));
}
else {
pointList = rsp.getBest().getPoints();
movementPoints.put(comp, new RealWorldMovementPoints(comp.getRealPosition(), destination, pointList, 0));
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(pointList));
} 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 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()));
}
i++;
}
movementPoints.put(comp, new RealWorldMovementPoints(movementPoints.get(comp).getStart(), destination, pointList, actualIndex));
ptIdx++;
}
return new Left<PositionVector, Boolean>(newPosition);
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 y
* @return The projected position in gps-coordinates (lat, long)
......@@ -188,7 +261,7 @@ 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 - latLower)/(latUpper - latLower);
x = Math.max(0, x);
......@@ -207,7 +280,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
public List<PositionVector> getMovementPoints(SimLocationActuator ms)
{
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()))));
......@@ -248,7 +321,7 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
*/
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) {
......
/*
* 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 @@
package de.tud.kom.p2psim.impl.topology.movement.local;
import com.graphhopper.util.PointList;
import de.tud.kom.p2psim.impl.topology.PositionVector;
public class RealWorldMovementPoints {
private PositionVector start;
private PositionVector destination;
private PointList pointList;
private int actualIndex;
public RealWorldMovementPoints(PositionVector start, PositionVector destination, PointList pointList, int actualIndex) {
this.start = start;
this.destination = destination;
this.pointList = pointList;
this.actualIndex = actualIndex;
}
public PositionVector getStart() {
return start;
}
public void setStart(PositionVector start) {
this.start = start;
}
public PositionVector getDestination() {
return destination;
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 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;
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
......@@ -117,6 +113,8 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>();
private Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
private boolean initialized = false;
private long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
......@@ -128,9 +126,6 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
.getWorldDimensions();
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!
Event.scheduleImmediately(this, null, EVENT_INIT);
}
......@@ -142,6 +137,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
public void initialize() {
if (!initialized) {
if (modelVisualisation == null) {
modelVisualisation = new ModularMovementModelViz(this);
}
VisualizationInjector.injectComponent(modelVisualisation);
if (mapVisualization != null) {
VisualizationInjector.injectComponent(mapVisualization);
......@@ -224,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;
}
......
......@@ -27,6 +27,8 @@ import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.Point2D;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
......@@ -36,10 +38,20 @@ import javax.swing.event.ChangeListener;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.local.AbstractLocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent;
import de.tud.kom.p2psim.impl.topology.views.visualization.world.NodeVisInteractionListener;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Oracle;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route.RouteSegment;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.RouteSensor;
/**
* Visualization Component of the Attraction Points in the Modular Movement
......@@ -50,7 +62,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
* @version 1.0, 02.07.2015
*/
public class ModularMovementModelViz extends JComponent
implements VisualizationComponent {
implements VisualizationComponent, NodeVisInteractionListener {
protected ModularMovementModel movementModel;
......@@ -58,29 +70,33 @@ public class ModularMovementModelViz extends JComponent
protected boolean showNodePositions = true;
protected boolean showTrajectories = false;
private JMenu menu;
private Map<Long, TrajectoryVis> trajectoryVisualizations = new LinkedHashMap<>();
private final static int NODE_PAD = 2;
private final static int ATTR_PAD = 5;
private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D");
public ModularMovementModelViz()
{
public ModularMovementModelViz() {
init();
}
protected void init()
{
protected void init() {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
VisualizationInjector.addInteractionListener(this);
setOpaque(true);
setVisible(true);
menu = new JMenu("Mobility Model");
menu.add(createCheckboxAp());
menu.add(createCheckboxNodePositions());
menu.add(createCheckboxTrajectories());
}
public ModularMovementModelViz(ModularMovementModel model) {
......@@ -114,6 +130,23 @@ public class ModularMovementModelViz extends JComponent
return checkBox;
}
private JCheckBoxMenuItem createCheckboxTrajectories() {
final JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(
"show node trajectories", showTrajectories);
checkBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
showTrajectories = checkBox.isSelected();
AbstractLocalMovementStrategy
.setCalculationOfRouteSegments(showTrajectories);
VisualizationInjector.invalidate();
}
});
AbstractLocalMovementStrategy
.setCalculationOfRouteSegments(showTrajectories);
return checkBox;
}
@Override
public void paint(Graphics g) {
super.paintComponent(g);
......@@ -131,6 +164,72 @@ public class ModularMovementModelViz extends JComponent
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.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;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldMovementPoints;
import de.tud.kom.p2psim.impl.topology.movement.local.RouteImpl;
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.util.Either;
......
/*
* 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 @@
package de.tud.kom.p2psim.impl.topology.views;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
......@@ -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.location.Location;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
import edu.emory.mathcs.backport.java.util.Arrays;
/**
* This topology view offers a topology for mobile apps - mobile clients
......
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