Commit 0c80da45 authored by Björn Richerzhagen's avatar Björn Richerzhagen
Browse files

Removed deprecated `Position`-Interface

parent db566de9
......@@ -9,12 +9,12 @@ import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Random;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.util.positioning.GeoSpherePosition;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
public class AppJobberPositioning implements PositioningStrategy {
......@@ -25,7 +25,7 @@ public class AppJobberPositioning implements PositioningStrategy {
private Random rnd = Randoms.getRandom(AppJobberPositioning.class);
@Override
public Position getPosition(
public Location getPosition(
SimHost host,
NetMeasurementDB db,
NetMeasurementDB.Host hostMeta) {
......
......@@ -24,12 +24,12 @@ package de.tud.kom.p2psim.impl.network.modular.st.positioning;
import java.util.List;
import java.util.Vector;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.network.modular.common.GNPToolkit;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
/**
* Applies the (virtual) GNP position as the host's position
......@@ -40,7 +40,7 @@ import de.tud.kom.p2psim.impl.topology.PositionVector;
public class GNPPositioning implements PositioningStrategy {
@Override
public Position getPosition(SimHost host, NetMeasurementDB db,
public Location getPosition(SimHost host, NetMeasurementDB db,
NetMeasurementDB.Host hostMeta) {
if (hostMeta == null)
......@@ -51,7 +51,7 @@ public class GNPPositioning implements PositioningStrategy {
}
public static class GNPPosition extends PositionVector implements Position {
public static class GNPPosition extends PositionVector {
private List<Double> coords;
......@@ -63,7 +63,7 @@ public class GNPPositioning implements PositioningStrategy {
}
@Override
public double getDistance(Position netPosition) {
public double distanceTo(Location netPosition) {
if (!(netPosition instanceof PositionVector))
throw new AssertionError(
"Can not calculate distances between different position classes: "
......
......@@ -21,12 +21,12 @@
package de.tud.kom.p2psim.impl.network.modular.st.positioning;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.network.modular.common.GeoToolkit;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
/**
* Applies a geographical position as defined by the GeoIP project.
......@@ -49,8 +49,7 @@ public class GeographicalPositioning implements PositioningStrategy {
}
public class GeographicalPosition extends PositionVector implements
Position {
public class GeographicalPosition extends PositionVector {
private double latitude;
private double longitude;
......@@ -70,7 +69,7 @@ public class GeographicalPositioning implements PositioningStrategy {
*
*/
@Override
public double getDistance(Position netPosition) {
public double distanceTo(Location netPosition) {
if (!(netPosition instanceof PositionVector))
throw new AssertionError(
"Can not calculate the distance between two different position classes: "
......@@ -80,12 +79,6 @@ public class GeographicalPositioning implements PositioningStrategy {
return GeoToolkit.getDistance(this.latitude, this.longitude,
other.getEntry(1), other.getEntry(0));
}
@Override
public double getAngle(Position target) {
throw new AssertionError(
"getAngle is not defined for this Position-Type");
}
@Override
public int getTransmissionSize() {
......
......@@ -20,11 +20,11 @@
package de.tud.kom.p2psim.impl.network.modular.st.positioning;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.topology.placement.PositionDistribution;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
/**
* Positioning on a 2D-Plane, used for all Movement-Enabled Routing-Scenarios
......@@ -42,7 +42,7 @@ public class PlanePositioning implements PositioningStrategy {
}
@Override
public Position getPosition(
public Location getPosition(
SimHost host,
NetMeasurementDB db,
de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Host hostMeta) {
......
......@@ -22,13 +22,13 @@ package de.tud.kom.p2psim.impl.network.modular.st.positioning;
import java.util.Random;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.network.simple.SimpleSubnet;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
/**
* Implementation of the <code>NetPosition</code> interface representing a two
......@@ -48,7 +48,7 @@ public class SimpleEuclidianPositioning implements PositioningStrategy {
* @see de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy#getPosition(de.tud.kom.p2psim.api.common.Host, de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB, de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB.Host)
*/
@Override
public Position getPosition(
public Location getPosition(
SimHost host,
NetMeasurementDB db,
NetMeasurementDB.Host hostMeta) {
......@@ -59,7 +59,7 @@ public class SimpleEuclidianPositioning implements PositioningStrategy {
}
public class SimpleEuclidianPosition extends PositionVector implements Position {
public class SimpleEuclidianPosition extends PositionVector {
private double xPos;
......@@ -93,7 +93,8 @@ public class SimpleEuclidianPositioning implements PositioningStrategy {
* de.tud.kom.p2psim.api.network.NetPosition#getDistance(de.tud.kom.
* p2psim .api.network.NetPosition)
*/
public double getDistance(Position ep) {
@Override
public double distanceTo(Location ep) {
double xDiff = 0;
double yDiff = 0;
SimpleEuclidianPosition point = (SimpleEuclidianPosition) ep;
......@@ -118,11 +119,6 @@ public class SimpleEuclidianPositioning implements PositioningStrategy {
return Math.pow(Math.pow(xDiff, 2) + Math.pow(yDiff, 2), 0.5);
}
@Override
public double getAngle(Position target) {
throw new AssertionError("getAngle is not defined for this Position-Type");
}
@Override
public int getTransmissionSize() {
return 16; // 2 * double
......
......@@ -23,12 +23,12 @@ package de.tud.kom.p2psim.impl.network.modular.st.positioning;
import java.util.Random;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.network.modular.st.PositioningStrategy;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
/**
* Applies a uniformly-distributed random position on a 2-or multi-dimensional
......@@ -48,7 +48,7 @@ public class TorusPositioning implements PositioningStrategy {
Random rand = Randoms.getRandom(TorusPosition.class);
@Override
public Position getPosition(SimHost host, NetMeasurementDB db,
public Location getPosition(SimHost host, NetMeasurementDB db,
NetMeasurementDB.Host hostMeta) {
double[] rawPos = getRawTorusPositionFor(host);
......@@ -93,7 +93,7 @@ public class TorusPositioning implements PositioningStrategy {
this.halfTorusDimensionSize = torusDimensionSize * 0.5d;
}
public class TorusPosition extends PositionVector implements Position {
public class TorusPosition extends PositionVector {
TorusPosition(double[] rawPos) {
......@@ -101,7 +101,7 @@ public class TorusPositioning implements PositioningStrategy {
}
@Override
public double getDistance(Position netPosition) {
public double distanceTo(Location netPosition) {
if (!(netPosition instanceof PositionVector))
throw new AssertionError(
"Can not calculate distances between different position classes: "
......
......@@ -28,7 +28,6 @@ import java.util.Map;
import de.tud.kom.p2psim.api.analyzer.ConnectivityAnalyzer;
import de.tud.kom.p2psim.api.analyzer.MessageAnalyzer.Reason;
import de.tud.kom.p2psim.api.analyzer.NetlayerAnalyzer;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.common.SimHostComponent;
import de.tud.kom.p2psim.api.linklayer.LinkLayer;
......@@ -57,6 +56,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.network.Bandwidth;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetInterface;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetworkComponent;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.component.transport.ConnectivityListener;
/**
......@@ -548,7 +548,7 @@ public class RoutedNetLayer implements SimNetworkComponent, NetworkComponent,
}
@Override
public Position getNetPosition() {
public Location getNetPosition() {
return host.getTopologyComponent().getRealPosition();
}
......
......@@ -19,11 +19,10 @@
*/
package de.tud.kom.p2psim.impl.network.simple;
package de.tud.kom.p2psim.impl.network.simple;
import de.tud.kom.p2psim.api.analyzer.MessageAnalyzer.Reason;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.network.BandwidthImpl;
import de.tud.kom.p2psim.api.network.NetMessage;
......@@ -34,105 +33,106 @@ import de.tud.kom.p2psim.impl.transport.AbstractTransMessage;
import de.tudarmstadt.maki.simonstrator.api.Message;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.component.network.NetID;
public class SimpleNetLayer extends AbstractNetLayer {
private double currentDownBandwidth;
private double currentUpBandwidth;
private final SimpleSubnet subNet;
public SimpleNetLayer(SimHost host, SimpleSubnet subNet, SimpleNetID netID,
Position netPosition, BandwidthImpl bandwidth) {
super(host, netID, bandwidth, netPosition, null);
this.subNet = subNet;
subNet.registerNetLayer(this);
}
public boolean isSupported(TransProtocol transProtocol) {
if (transProtocol.equals(TransProtocol.UDP))
return true;
else
return false;
}
public void send(Message msg, NetID receiver, NetProtocol netProtocol) {
// outer if-else-block is used to avoid sending although the host is
// offline
if (this.isOnline()) {
TransProtocol usedTransProtocol = ((AbstractTransMessage) msg)
.getProtocol();
if (this.isSupported(usedTransProtocol)) {
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
public class SimpleNetLayer extends AbstractNetLayer {
private double currentDownBandwidth;
private double currentUpBandwidth;
private final SimpleSubnet subNet;
public SimpleNetLayer(SimHost host, SimpleSubnet subNet, SimpleNetID netID,
Location netPosition, BandwidthImpl bandwidth) {
super(host, netID, bandwidth, netPosition, null);
this.subNet = subNet;
subNet.registerNetLayer(this);
}
public boolean isSupported(TransProtocol transProtocol) {
if (transProtocol.equals(TransProtocol.UDP))
return true;
else
return false;
}
public void send(Message msg, NetID receiver, NetProtocol netProtocol) {
// outer if-else-block is used to avoid sending although the host is
// offline
if (this.isOnline()) {
TransProtocol usedTransProtocol = ((AbstractTransMessage) msg)
.getProtocol();
if (this.isSupported(usedTransProtocol)) {
NetMessage netMsg = new SimpleNetMessage(msg, receiver,
getLocalInetAddress(),
getLocalInetAddress(),
netProtocol);
if (hasAnalyzer) {
netAnalyzerProxy
.netMsgEvent(netMsg, getHost(), Reason.SEND);
}
subNet.send(netMsg);
} else {
throw new IllegalArgumentException("Transport protocol "
+ usedTransProtocol
+ " not supported by this NetLayer implementation.");
}
} else {
int assignedMsgId = subNet.determineTransMsgNumber(msg);
}
subNet.send(netMsg);
} else {
throw new IllegalArgumentException("Transport protocol "
+ usedTransProtocol
+ " not supported by this NetLayer implementation.");
}
} else {
int assignedMsgId = subNet.determineTransMsgNumber(msg);
Monitor.log(SimpleNetLayer.class, Monitor.Level.DEBUG,
"During send: Assigning MsgId " + assignedMsgId
+ " to dropped message");
((AbstractTransMessage) msg).setCommId(assignedMsgId);
"During send: Assigning MsgId " + assignedMsgId
+ " to dropped message");
((AbstractTransMessage) msg).setCommId(assignedMsgId);
NetMessage netMsg = new SimpleNetMessage(msg, receiver,
getLocalInetAddress(),
getLocalInetAddress(),
netProtocol);
if (hasAnalyzer) {
netAnalyzerProxy.netMsgEvent(netMsg, getHost(), Reason.DROP);
}
}
}
@Override
public String toString() {
}
}
}
@Override
public String toString() {
return "NetLayer(netID=" + getLocalInetAddress() + ", "
+ (isOffline() ? "online" : "offline") + ")";
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(currentDownBandwidth);
result = PRIME * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(currentUpBandwidth);
result = PRIME * result + (int) (temp ^ (temp >>> 32));
result = PRIME * result + ((subNet == null) ? 0 : subNet.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final SimpleNetLayer other = (SimpleNetLayer) obj;
if (Double.doubleToLongBits(currentDownBandwidth) != Double
.doubleToLongBits(other.currentDownBandwidth))
return false;
if (Double.doubleToLongBits(currentUpBandwidth) != Double
.doubleToLongBits(other.currentUpBandwidth))
return false;
if (subNet == null) {
if (other.subNet != null)
return false;
} else if (!subNet.equals(other.subNet))
return false;
return true;
}
}
+ (isOffline() ? "online" : "offline") + ")";
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(currentDownBandwidth);
result = PRIME * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(currentUpBandwidth);
result = PRIME * result + (int) (temp ^ (temp >>> 32));
result = PRIME * result + ((subNet == null) ? 0 : subNet.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final SimpleNetLayer other = (SimpleNetLayer) obj;
if (Double.doubleToLongBits(currentDownBandwidth) != Double
.doubleToLongBits(other.currentDownBandwidth))
return false;
if (Double.doubleToLongBits(currentUpBandwidth) != Double
.doubleToLongBits(other.currentUpBandwidth))
return false;
if (subNet == null) {
if (other.subNet != null)
return false;
} else if (!subNet.equals(other.subNet))
return false;
return true;
}
}
......@@ -28,7 +28,6 @@ import java.util.Random;
import java.util.Set;
import de.tud.kom.p2psim.api.common.HostProperties;
import de.tud.kom.p2psim.api.common.Position;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.linklayer.mac.MacAddress;
import de.tud.kom.p2psim.api.linklayer.mac.MacLayer;
......@@ -178,7 +177,7 @@ public class DefaultTopologyComponent implements TopologyComponent {
@Override
public void positionChanged() {
for (PositionListener listener : positionListener) {
if (listener.getPosition().getDistance(position) < listener
if (listener.getPosition().distanceTo(position) < listener
.getRadius()) {
listener.reachedPosition();
}
......@@ -212,14 +211,6 @@ public class DefaultTopologyComponent implements TopologyComponent {
return position;
}
@Override
public Position getPosition(PositionAccuracy accuracy) {
/*
* TODO :)
*/
return position;
}
@Override
public Topology getTopology() {
return topology;
......
......@@ -25,7 +25,6 @@ import java.util.Arrays;
import com.vividsolutions.jts.geom.Coordinate;
import de.tud.kom.p2psim.api.common.Position;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
/**
......@@ -50,7 +49,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
* @author Bjoern Richerzhagen
* @version 1.0, 04/25/2011
*/
public class PositionVector implements Position, Location {
public class PositionVector implements Location {
private int dimensions;
......@@ -255,55 +254,6 @@ public class PositionVector implements Position, Location {
return result;
}
@Override
public double getDistance(Position position) {
if (position instanceof PositionVector) {
PositionVector pv = (PositionVector) position;
if (pv.getDimensions() == getDimensions()) {
double dist = 0;
for (int i = 0; i < dimensions; i++) {
// faster as Math.pow
dist += (pv.getEntry(i) - getEntry(i))
* (pv.getEntry(i) - getEntry(i));
}
return Math.sqrt(dist);
} else {
throw new AssertionError(
"Can not compute distance between Vectors of different length!");
}
} else {
throw new AssertionError("Incompatible Types!");
}
}
@Override
public double getAngle(Position target) {
if (target instanceof PositionVector) {
PositionVector t = (PositionVector) target;
/*
* Calculates the angle using atan2 - this implies that the first
* two dimensions in your vector are the plane you are interested
* in.
*/
return Math.atan2(t.getEntry(1) - this.getEntry(1), t.getEntry(0)
- this.getEntry(0));
} else {
throw new AssertionError(
"Can only calculate an Angle on elements of type position vector");
}
}
@Override
public Position getTarget(double distance, double angle) {
/*
* The call to "clone" ensures correct typing
*/
PositionVector newPos = clone();
newPos.setEntry(0, newPos.getEntry(0) + distance * Math.cos(angle));
newPos.setEntry(1, newPos.getEntry(1) + distance * Math.sin(angle));
return newPos;
}
@Override
public int getTransmissionSize() {
return getDimensions() * 8;
......@@ -496,13 +446,39 @@ public class PositionVector implements Position, Location {
@Override
public double distanceTo(Location dest) {
assert (dest instanceof PositionVector);
return this.getDistance((PositionVector) dest);
if (dest instanceof PositionVector) {
PositionVector pv = (PositionVector) dest;
if (pv.getDimensions() == getDimensions()) {
double dist = 0;
for (int i = 0; i < dimensions; i++) {
// faster as Math.pow
dist += (pv.getEntry(i) - getEntry(i))
* (pv.getEntry(i) - getEntry(i));
}
return Math.sqrt(dist);
} else {
throw new AssertionError(
"Can not compute distance between Vectors of different length!");
}
} else {
throw new AssertionError("Incompatible Types!");
}
}
@Override
public float bearingTo(Location dest) {
assert (dest instanceof PositionVector);
return (float) ((this.getAngle((PositionVector) dest) - (Math.PI / 2)) * 180 / Math.PI);
if (dest instanceof PositionVector) {
PositionVector t = (PositionVector) dest;
/*
* Calculates the angle using atan2 - this implies that the first
* two dimensions in your vector are the plane you are interested
* in.
*/
return (float) Math.atan2(t.getEntry(1) - this.getEntry(1),
t.getEntry(0) - this.getEntry(0));
} else {
throw new AssertionError(
"Can only calculate an Angle on elements of type position vector");
}
}
}
......@@ -39,6 +39,7 @@ import de.tud.kom.p2psim.impl.network.modular.db.NetMeasurementDB;
import de.tud.kom.p2psim.impl.topology.movement.AbstractWaypointMovementModel;
import de.tud.kom.p2psim.impl.topology.placement.GNPPlacement;
import de.tud.kom.p2psim.impl.topology.views.latency.GNPLatency;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
......@@ -88,7 +89,8 @@ public class TopologyFactory implements HostComponentFactory {
@XMLConfigurableConstructor({ "worldX", "worldY" })
public TopologyFactory(double worldX, double worldY) {
topo = new DefaultTopology(new PositionVector(worldX, worldY));
de.tud.kom.p2psim.impl.topology.Topology.setTopology(topo);
// Make the topology component available globally
Binder.registerComponent(topo);
}
@Override
......
......@@ -26,11 +26,12 @@ import java.util.List;
import java.util.Random;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.MovementListener;
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.Topology;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
......@@ -87,7 +88,8 @@ public abstract class AbstractMovementModel implements MovementModel {
@Override
public void addComponent(MovementSupported component) {
if (worldDimensions == null) {
worldDimensions = Topology.getWorldDimension();
worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
}
components.add(component);
}
......
/*
* Copyright (c) 2005-2011 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;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.WeakHashMap;
import com.google.common.eventbus.Subscribe;
import de.tud.kom.p2psim.api.topology.movement.MovementListener;
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.scenario.simcfg2.annotations.After;
import de.tud.kom.p2psim.impl.scenario.simcfg2.annotations.Configure;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.events.ScaleWorldEvent;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.geo.maps.MapLoader;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* The AbstractWaypointMovementModel can be used to implement movement models
* based on way point data. It uses an implementation of LocalMovementStrategy
* for the movement between selected way points.
*
* @author Fabio Zöllner
* @version 1.0, 27.03.2012
*/
public abstract class AbstractWaypointMovementModel implements MovementModel {
private Set<MovementSupported> components = new LinkedHashSet<MovementSupported>();
protected PositionVector worldDimensions;
protected WeakHashMap<MovementSupported, PositionVector> destinations;
protected WeakHashMap<MovementSupported, Long> pauseTimes;
protected WeakHashMap<MovementSupported, Long> pauseInProgressTimes;
private List<MovementListener> listeners;
protected WaypointModel waypointModel;
protected LocalMovementStrategy localMovementStrategy;
private int configurationCounter = 100;
private long timeBetweenMovement = 1 * Time.SECOND;
private double speedLimit = 1;
private double unscaledSpeedLimit = speedLimit;
private Random rnd = Randoms.getRandom(AbstractWaypointMovementModel.class);
public AbstractWaypointMovementModel(double worldX, double worldY) {
worldDimensions = new PositionVector(worldX, worldY);
listeners = new LinkedList<MovementListener>();
destinations = new WeakHashMap<MovementSupported, PositionVector>();
pauseTimes = new WeakHashMap<MovementSupported, Long>();
pauseInProgressTimes = new WeakHashMap<MovementSupported, Long>();
// Simulator.registerAtEventBus(this);
}
@Configure()
@After(required = { WaypointModel.class, MapLoader.class })
public boolean configure() {
if (this.waypointModel == null && configurationCounter > 0) {
configurationCounter--;
return false;
}
if (this.waypointModel == null) {
Monitor.log(
AbstractWaypointMovementModel.class,
Level.INFO,
"No waypoint model has been configured. Thus the movement speed won't be adjusted for the scale of the waypoint model.");
}
//
// if (waypointModel.getScaleFactor() != 1.0) {
// Simulator.postEvent(new ScaleWorldEvent(waypointModel
// .getScaleFactor()));
// }
return true;
}
@Subscribe
public void scaleWorld(ScaleWorldEvent event) {
double scaleFactor = event.getFactor();
speedLimit = unscaledSpeedLimit * scaleFactor;
Monitor.log(
AbstractWaypointMovementModel.class,
Level.INFO,
"Movement speed of the local movement strategy has been adjusted for the waypoint model scale and is now "
+ speedLimit + "m/s");
}
/**
* Gets called periodically (after timeBetweenMoveOperations) or by an
* application and should be used to recalculate positions
*/
public void move() {
long nrOfSteps = timeBetweenMovement / Time.SECOND;
for (int i = 0; i < nrOfSteps; i++) {
step();
}
notifyRoundEnd();
}
private void step() {
Set<MovementSupported> comps = getComponents();
for (MovementSupported mcomp : comps) {
if (!mcomp.movementActive()) {
continue;
}
Long currentPause = pauseInProgressTimes.get(mcomp);
if (currentPause != null) {
if (Time.getCurrentTime() >= currentPause) {
Monitor.log(AbstractWaypointMovementModel.class,
Level.DEBUG, "Pause time ended...");
pauseInProgressTimes.remove(mcomp);
} else
continue;
}
PositionVector dst = getDestination(mcomp);
// If the movement model gave null as a destination no move is
// executed
if (dst == null) {
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"No destination before reachedPosition check... continuing");
continue;
}
// If the position has been reached last round
// set pause active and get a new destination
if (reachedPosition(mcomp, dst)) {
pauseAndGetNextPosition(mcomp);
continue;
}
// Ask the local movement strategy for the next position.
// It may return the next position or a boolean with true to notify
// the
// movement model that it can't get any closer to the current way
// point.
Either<PositionVector, Boolean> either = localMovementStrategy
.nextPosition(mcomp, dst);
if (either.hasLeft()) {
mcomp.getRealPosition().replace(either.getLeft());
notifyPositionChange(mcomp);
} else {
if (either.getRight().booleanValue()) {
pauseAndGetNextPosition(mcomp);
continue;
} else {
// Pause this round
continue;
}
}
}
}
/**
* Sets the pause time for the given component and calls nextPosition on it.
*
* @param comp
*/
private void pauseAndGetNextPosition(MovementSupported comp) {
Long pt = pauseTimes.get(comp) * Time.SECOND;
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"Position reached... pause time is " + pt);
if (pt != null) {
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"Simulator time: " + Time.getCurrentTime());
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"Pause time: " + pt);
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"Added up: " + (Time.getCurrentTime() + pt));
pauseInProgressTimes.put(comp, Time.getCurrentTime() + pt);
}
nextPosition(comp);
}
/**
* Checks if the given component has reached its destination
*
* @param comp
* @param dst
* @return Returns true if the destination was reached
*/
private boolean reachedPosition(MovementSupported comp, PositionVector dst) {
PositionVector pos = comp.getRealPosition();
double distance = pos.getDistance(dst);
// FIXME: Better detection?
return (distance < getSpeedLimit() * 2);
}
/**
* Returns the current destination of the given component and calls
* nextPosition if it hasn't been set yet.
*
* @param comp
* @return
*/
private PositionVector getDestination(MovementSupported comp) {
PositionVector dst = destinations.get(comp);
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG, "Pos: "
+ comp.getRealPosition());
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG, "Dst: "
+ dst);
if (dst == null) {
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"No destination, calling nextPosition()");
nextPosition(comp);
dst = destinations.get(comp);
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"New destination is: " + dst);
}
return dst;
}
/**
* This method can be called by the concrete implementation to let the
* AbstractWaypointMovementModel know the next destination and pause time.
*
* @param comp
* @param destination
* @param pauseTime
*/
protected void nextDestination(MovementSupported comp,
PositionVector destination, long pauseTime) {
destinations.put(comp, destination);
pauseTimes.put(comp, pauseTime);
}
/**
* Is to be implemented by the concrete movement model and will be called by
* the AbstractWaypointMovementModel to ask the concrete implementation for
* a new destination.
*
* @param component
*/
public abstract void nextPosition(MovementSupported component);
/**
* Get all participating Components
*
* @return
*/
protected Set<MovementSupported> getComponents() {
return components;
}
/**
* Add a component to this movement-Model (used to keep global information
* about all participants in a movement model). Each Component acts as a
* callback upon movement of this component
*
* @param component
*/
@Override
public void addComponent(MovementSupported component) {
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"AbstractMovementModel: Adding component to the movement model");
components.add(component);
}
@Override
public void addMovementListener(MovementListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
@Override
public void removeMovementListener(MovementListener listener) {
listeners.remove(listener);
}
/**
* Notify Listeners
*/
protected void notifyRoundEnd() {
for (MovementListener listener : listeners) {
listener.afterComponentsMoved();
}
}
protected void notifyPositionChange(MovementSupported comp) {
for (MovementListener listener : listeners) {
listener.afterComponentMoved(comp);
}
comp.positionChanged();
}
/**
* Get a valid delta-Vector (does not cross world-boundaries and does not
* exceed moveSpeedLimit)
*
* @param oldPosition
* @return
*/
protected PositionVector getRandomDelta(PositionVector oldPosition) {
return getRandomDelta(oldPosition, getSpeedLimit());
}
/**
* Get a valid delta-Vector, where each abs(entry) must not exceed maxLength
*
* @param oldPosition
* @param maxLength
* @return
*/
protected PositionVector getRandomDelta(PositionVector oldPosition,
double maxLength) {
double[] delta = new double[oldPosition.getDimensions()];
for (int i = 0; i < oldPosition.getDimensions(); i++) {
int tries = 0;
do {
delta[i] = getRandomDouble(-maxLength, maxLength);
if (++tries > 50) {
delta[i] = 0;
break;
}
// delta[i] = (r.nextInt(2 * getMoveSpeedLimit() + 1) -
// getMoveSpeedLimit());
} while (oldPosition.getEntry(i) + delta[i] > getWorldDimension(i)
|| oldPosition.getEntry(i) + delta[i] < 0);
}
PositionVector deltaVector = new PositionVector(delta);
return deltaVector;
}
/**
* Returns if this is a valid position within the boundaries
*
* @return
*/
protected boolean isValidPosition(PositionVector vector) {
for (int i = 0; i < vector.getDimensions(); i++) {
if (vector.getEntry(i) > getWorldDimension(i)
|| vector.getEntry(i) < 0) {
return false;
}
}
return true;
}
/**
* Returns a random int between from and to, including both interval ends!
*
* @param from
* @param to
* @return
*/
protected int getRandomInt(int from, int to) {
int intervalSize = Math.abs(to - from);
return (rnd.nextInt(intervalSize + 1) + from);
}
protected double getRandomDouble(double from, double to) {
double intervalSize = Math.abs(to - from);
return (rnd.nextDouble() * intervalSize + from);
}
/**
* Move models can periodically calculate new positions and notify
* listeners, if a position changed. Here you can specify the interval
* between these notifications/calculations. If this is set to zero, there
* is no periodical execution, which may be useful if you want to call
* move() from within an application.
*
* @param timeBetweenMoveOperations
*/
public void setTimeBetweenMoveOperations(long timeBetweenMoveOperations) {
this.timeBetweenMovement = timeBetweenMoveOperations;
if (timeBetweenMoveOperations > 0) {
reschedule();
}
}
protected void reschedule() {
Event.scheduleWithDelay(timeBetweenMovement, new PeriodicMove(), this,
0);
}
@Deprecated
public void setSpeedLimit(double speedLimit) {
this.speedLimit = speedLimit;
this.unscaledSpeedLimit = speedLimit;
}
@Deprecated
public double getSpeedLimit() {
return speedLimit;
}
public void setWorldX(double dimension) {
this.worldDimensions.setEntry(0, dimension);
}
public void setWorldY(double dimension) {
this.worldDimensions.setEntry(1, dimension);
}
public double getWorldDimension(int dim) {
return worldDimensions.getEntry(dim);
}
public void setWorldZ(double dimension) {
this.worldDimensions.setEntry(2, dimension);
}
public void setWaypointModel(WaypointModel model) {
this.waypointModel = model;
if (localMovementStrategy != null)
localMovementStrategy.setWaypointModel(getWaypointModel());
}
public WaypointModel getWaypointModel() {
return this.waypointModel;
}
public void setLocalMovementStrategy(LocalMovementStrategy strategy) {
strategy.setWaypointModel(getWaypointModel());
this.localMovementStrategy = strategy;
}
/**
* Triggers the periodic move
*
* @author Bjoern Richerzhagen
* @version 1.0, 20.03.2012
*/
protected class PeriodicMove implements EventHandler {
@Override
public void eventOccurred(Object content, int type) {
move();
reschedule();
}
}
}
/*
* Copyright (c) 2005-2011 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;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.WeakHashMap;
import com.google.common.eventbus.Subscribe;
import de.tud.kom.p2psim.api.topology.movement.MovementListener;
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.scenario.simcfg2.annotations.After;
import de.tud.kom.p2psim.impl.scenario.simcfg2.annotations.Configure;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.events.ScaleWorldEvent;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.geo.maps.MapLoader;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* The AbstractWaypointMovementModel can be used to implement movement models
* based on way point data. It uses an implementation of LocalMovementStrategy
* for the movement between selected way points.
*
* @author Fabio Zöllner
* @version 1.0, 27.03.2012
*/
public abstract class AbstractWaypointMovementModel implements MovementModel {
private Set<MovementSupported> components = new LinkedHashSet<MovementSupported>();
protected PositionVector worldDimensions;
protected WeakHashMap<MovementSupported, PositionVector> destinations;
protected WeakHashMap<MovementSupported, Long> pauseTimes;
protected WeakHashMap<MovementSupported, Long> pauseInProgressTimes;
private List<MovementListener> listeners;
protected WaypointModel waypointModel;
protected LocalMovementStrategy localMovementStrategy;
private int configurationCounter = 100;
private long timeBetweenMovement = 1 * Time.SECOND;
private double speedLimit = 1;
private double unscaledSpeedLimit = speedLimit;
private Random rnd = Randoms.getRandom(AbstractWaypointMovementModel.class);
public AbstractWaypointMovementModel(double worldX, double worldY) {
worldDimensions = new PositionVector(worldX, worldY);
listeners = new LinkedList<MovementListener>();
destinations = new WeakHashMap<MovementSupported, PositionVector>();
pauseTimes = new WeakHashMap<MovementSupported, Long>();
pauseInProgressTimes = new WeakHashMap<MovementSupported, Long>();
// Simulator.registerAtEventBus(this);
}
@Configure()
@After(required = { WaypointModel.class, MapLoader.class })
public boolean configure() {
if (this.waypointModel == null && configurationCounter > 0) {
configurationCounter--;
return false;
}
if (this.waypointModel == null) {
Monitor.log(
AbstractWaypointMovementModel.class,
Level.INFO,
"No waypoint model has been configured. Thus the movement speed won't be adjusted for the scale of the waypoint model.");
}
//
// if (waypointModel.getScaleFactor() != 1.0) {
// Simulator.postEvent(new ScaleWorldEvent(waypointModel
// .getScaleFactor()));
// }
return true;
}
@Subscribe
public void scaleWorld(ScaleWorldEvent event) {
double scaleFactor = event.getFactor();
speedLimit = unscaledSpeedLimit * scaleFactor;
Monitor.log(
AbstractWaypointMovementModel.class,
Level.INFO,
"Movement speed of the local movement strategy has been adjusted for the waypoint model scale and is now "
+ speedLimit + "m/s");
}
/**
* Gets called periodically (after timeBetweenMoveOperations) or by an
* application and should be used to recalculate positions
*/
public void move() {
long nrOfSteps = timeBetweenMovement / Time.SECOND;
for (int i = 0; i < nrOfSteps; i++) {
step();
}
notifyRoundEnd();
}
private void step() {
Set<MovementSupported> comps = getComponents();
for (MovementSupported mcomp : comps) {
if (!mcomp.movementActive()) {
continue;
}
Long currentPause = pauseInProgressTimes.get(mcomp);
if (currentPause != null) {
if (Time.getCurrentTime() >= currentPause) {
Monitor.log(AbstractWaypointMovementModel.class,
Level.DEBUG, "Pause time ended...");
pauseInProgressTimes.remove(mcomp);
} else
continue;
}
PositionVector dst = getDestination(mcomp);
// If the movement model gave null as a destination no move is
// executed
if (dst == null) {
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"No destination before reachedPosition check... continuing");
continue;
}
// If the position has been reached last round
// set pause active and get a new destination
if (reachedPosition(mcomp, dst)) {
pauseAndGetNextPosition(mcomp);
continue;
}
// Ask the local movement strategy for the next position.
// It may return the next position or a boolean with true to notify
// the
// movement model that it can't get any closer to the current way
// point.
Either<PositionVector, Boolean> either = localMovementStrategy
.nextPosition(mcomp, dst);
if (either.hasLeft()) {
mcomp.getRealPosition().replace(either.getLeft());
notifyPositionChange(mcomp);
} else {
if (either.getRight().booleanValue()) {
pauseAndGetNextPosition(mcomp);
continue;
} else {
// Pause this round
continue;
}
}
}
}
/**
* Sets the pause time for the given component and calls nextPosition on it.
*
* @param comp
*/
private void pauseAndGetNextPosition(MovementSupported comp) {
Long pt = pauseTimes.get(comp) * Time.SECOND;
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"Position reached... pause time is " + pt);
if (pt != null) {
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"Simulator time: " + Time.getCurrentTime());
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"Pause time: " + pt);
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"Added up: " + (Time.getCurrentTime() + pt));
pauseInProgressTimes.put(comp, Time.getCurrentTime() + pt);
}
nextPosition(comp);
}
/**
* Checks if the given component has reached its destination
*
* @param comp
* @param dst
* @return Returns true if the destination was reached
*/
private boolean reachedPosition(MovementSupported comp, PositionVector dst) {
PositionVector pos = comp.getRealPosition();
double distance = pos.distanceTo(dst);
// FIXME: Better detection?
return (distance < getSpeedLimit() * 2);
}
/**
* Returns the current destination of the given component and calls
* nextPosition if it hasn't been set yet.
*
* @param comp
* @return
*/
private PositionVector getDestination(MovementSupported comp) {
PositionVector dst = destinations.get(comp);
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG, "Pos: "
+ comp.getRealPosition());
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG, "Dst: "
+ dst);
if (dst == null) {
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"No destination, calling nextPosition()");
nextPosition(comp);
dst = destinations.get(comp);
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"New destination is: " + dst);
}
return dst;
}
/**
* This method can be called by the concrete implementation to let the
* AbstractWaypointMovementModel know the next destination and pause time.
*
* @param comp
* @param destination
* @param pauseTime
*/
protected void nextDestination(MovementSupported comp,
PositionVector destination, long pauseTime) {
destinations.put(comp, destination);
pauseTimes.put(comp, pauseTime);
}
/**
* Is to be implemented by the concrete movement model and will be called by
* the AbstractWaypointMovementModel to ask the concrete implementation for
* a new destination.
*
* @param component
*/
public abstract void nextPosition(MovementSupported component);
/**
* Get all participating Components
*
* @return
*/
protected Set<MovementSupported> getComponents() {
return components;
}
/**
* Add a component to this movement-Model (used to keep global information
* about all participants in a movement model). Each Component acts as a
* callback upon movement of this component
*
* @param component
*/
@Override
public void addComponent(MovementSupported component) {
Monitor.log(AbstractWaypointMovementModel.class, Level.DEBUG,
"AbstractMovementModel: Adding component to the movement model");
components.add(component);
}
@Override
public void addMovementListener(MovementListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
@Override
public void removeMovementListener(MovementListener listener) {
listeners.remove(listener);
}
/**
* Notify Listeners
*/
protected void notifyRoundEnd() {
for (MovementListener listener : listeners) {
listener.afterComponentsMoved();
}
}
protected void notifyPositionChange(MovementSupported comp) {
for (MovementListener listener : listeners) {
listener.afterComponentMoved(comp);
}
comp.positionChanged();
}
/**
* Get a valid delta-Vector (does not cross world-boundaries and does not
* exceed moveSpeedLimit)
*
* @param oldPosition
* @return
*/
protected PositionVector getRandomDelta(PositionVector oldPosition) {
return getRandomDelta(oldPosition, getSpeedLimit());
}
/**
* Get a valid delta-Vector, where each abs(entry) must not exceed maxLength
*
* @param oldPosition
* @param maxLength
* @return
*/
protected PositionVector getRandomDelta(PositionVector oldPosition,
double maxLength) {
double[] delta = new double[oldPosition.getDimensions()];
for (int i = 0; i < oldPosition.getDimensions(); i++) {
int tries = 0;
do {
delta[i] = getRandomDouble(-maxLength, maxLength);
if (++tries > 50) {
delta[i] = 0;
break;
}
// delta[i] = (r.nextInt(2 * getMoveSpeedLimit() + 1) -
// getMoveSpeedLimit());
} while (oldPosition.getEntry(i) + delta[i] > getWorldDimension(i)
|| oldPosition.getEntry(i) + delta[i] < 0);
}
PositionVector deltaVector = new PositionVector(delta);
return deltaVector;
}
/**
* Returns if this is a valid position within the boundaries
*
* @return
*/
protected boolean isValidPosition(PositionVector vector) {
for (int i = 0; i < vector.getDimensions(); i++) {
if (vector.getEntry(i) > getWorldDimension(i)
|| vector.getEntry(i) < 0) {
return false;
}
}
return true;
}
/**
* Returns a random int between from and to, including both interval ends!
*
* @param from
* @param to
* @return
*/
protected int getRandomInt(int from, int to) {
int intervalSize = Math.abs(to - from);
return (rnd.nextInt(intervalSize + 1) + from);
}
protected double getRandomDouble(double from, double to) {
double intervalSize = Math.abs(to - from);
return (rnd.nextDouble() * intervalSize + from);
}
/**
* Move models can periodically calculate new positions and notify
* listeners, if a position changed. Here you can specify the interval
* between these notifications/calculations. If this is set to zero, there
* is no periodical execution, which may be useful if you want to call
* move() from within an application.
*
* @param timeBetweenMoveOperations
*/
public void setTimeBetweenMoveOperations(long timeBetweenMoveOperations) {
this.timeBetweenMovement = timeBetweenMoveOperations;
if (timeBetweenMoveOperations > 0) {
reschedule();
}
}
protected void reschedule() {
Event.scheduleWithDelay(timeBetweenMovement, new PeriodicMove(), this,
0);
}
@Deprecated
public void setSpeedLimit(double speedLimit) {
this.speedLimit = speedLimit;
this.unscaledSpeedLimit = speedLimit;
}
@Deprecated
public double getSpeedLimit() {
return speedLimit;
}
public void setWorldX(double dimension) {
this.worldDimensions.setEntry(0, dimension);
}
public void setWorldY(double dimension) {
this.worldDimensions.setEntry(1, dimension);
}
public double getWorldDimension(int dim) {
return worldDimensions.getEntry(dim);
}
public void setWorldZ(double dimension) {
this.worldDimensions.setEntry(2, dimension);
}
public void setWaypointModel(WaypointModel model) {
this.waypointModel = model;
if (localMovementStrategy != null)
localMovementStrategy.setWaypointModel(getWaypointModel());
}
public WaypointModel getWaypointModel() {
return this.waypointModel;
}
public void setLocalMovementStrategy(LocalMovementStrategy strategy) {
strategy.setWaypointModel(getWaypointModel());
this.localMovementStrategy = strategy;
}
/**
* Triggers the periodic move
*
* @author Bjoern Richerzhagen
* @version 1.0, 20.03.2012
*/
protected class PeriodicMove implements EventHandler {
@Override
public void eventOccurred(Object content, int type) {
move();
reschedule();
}
}
}
......@@ -27,26 +27,19 @@ import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import org.jfree.data.io.CSV;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.api.common.SimHostComponent;
import de.tud.kom.p2psim.api.network.SimNetInterface;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.MovementInformation;
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.impl.network.gnp.topology.Host;
import de.tud.kom.p2psim.impl.simengine.Simulator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.Topology;
import de.tud.kom.p2psim.impl.topology.movement.modular.ModularMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modular.attraction.AttractionPoint;
import de.tud.kom.p2psim.impl.topology.movement.modular.transition.FixedAssignmentStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modular.transition.TransitionStrategy;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
......@@ -82,7 +75,8 @@ public class CsvMovement extends AbstractMovementModel {
@XMLConfigurableConstructor({ "movementPointsFile" , "minMovementSpeed", "maxMovementSpeed" })
public CsvMovement(String movementPointsFile, double minMovementSpeed, double maxMovementSpeed) {
super();
this.worldDimensions = Topology.getWorldDimension();
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
this.file = movementPointsFile;
this.readPathInfos = new LinkedList<LinkedList<CsvPathInfo>>();
this.stateInfo = new LinkedHashMap<MovementSupported, CsvMovementInfo>();
......@@ -144,7 +138,7 @@ public class CsvMovement extends AbstractMovementModel {
double distancePerMoveOperation = pathInfo.getSpeed()
* getTimeBetweenMoveOperations() / Time.SECOND;
double distance = actPos.getDistance(targetPos);
double distance = actPos.distanceTo(targetPos);
steps = (int) Math.round(distance / distancePerMoveOperation);
......
/*
* 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;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import java.util.WeakHashMap;
import javax.swing.JComponent;
import com.google.common.collect.Maps;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.scenario.simcfg2.annotations.After;
import de.tud.kom.p2psim.impl.scenario.simcfg2.annotations.Configure;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector.DisplayString;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.StrongWaypoint;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.Waypoint;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* The SLAW Movement Model is based on the implementation in
* BonnMotion Copyright (C) 2002-2010 University of Bonn
* by Zia-Ul-Huda, Gufron Atokhojaev and Florian Schmitt
*
* @author Fabio Zöllner
* @version 1.0, 09.04.2012
*/
public class SLAWMovementModel extends AbstractWaypointMovementModel {
private static final int powerlaw_step = 1;
private static int levy_scale_factor = 1;
private static int powerlaw_mode = 1;
protected Random rand = Randoms
.getRandom(SLAWMovementModel.class);
protected Random xorShiftRandom = new XorShiftRandom(rand.nextLong());
protected double beta = 1;
protected long minpause = 10;
protected long maxpause = 50;
protected double dist_alpha = 3;
protected double cluster_range;
protected int cluster_ratio = 3;
protected int waypoint_ratio = 3;
protected Cluster[] clusters;
protected WeakHashMap<MovementSupported, SLAWMovementInformation> movementInformation;
// TODO: minpause and maxpause are currently in microseconds... should be
// changed to minutes
@XMLConfigurableConstructor({"worldX", "worldY", "minpause", "maxpause", "beta", "distAlpha", "clusterRange", "clusterRatio", "waypointRatio" })
public SLAWMovementModel(double worldX, double worldY, long minpause, long maxpause, double beta, double distAlpha, double clusterRange, int clusterRatio, int waypointRatio) {
super(worldX, worldY);
this.minpause = minpause;
this.maxpause = maxpause;
this.dist_alpha = distAlpha;
this.cluster_range = clusterRange;
this.cluster_ratio = clusterRatio;
this.waypoint_ratio = waypointRatio;
movementInformation = new WeakHashMap<MovementSupported, SLAWMovementModel.SLAWMovementInformation>();
}
@Override
public void nextPosition(MovementSupported node) {
// These variables have values same as in the matlab implementation of
// SLAW model by Seongik Hong, NCSU, US (3/10/2009)
if (waypointModel == null) {
throw new ConfigurationException("SLAWMovementModel requires a valid waypoint model which hasn't been provided, cannot execute");
}
SLAWMovementInformation mi = movementInformation.get(node);
if (mi == null) {
//System.err.println("Creating new movement information for node " + node.toString());
mi = new SLAWMovementInformation();
movementInformation.put(node, mi);
}
// log.debug("Selecting new destination for node " + mi.nodeId);
// get random clusters and waypoints
if (mi.clts == null)
mi.clts = make_selection(clusters, null, false);
// get random clusters and waypoints
if (mi.wlist == null)
mi.wlist = get_waypoint_list(mi.clts);
// random source node
if (mi.srcIndex == -1) {
int old = mi.srcIndex;
mi.srcIndex = (int) Math
.floor(randomNextDouble() * mi.wlist.length);
//System.err.println("mi.srcIndex was " + old + " but is now " + mi.srcIndex);
// Set the initial position to the selected waypoint
nextDestination(node, mi.wlist[mi.srcIndex].pos, 0);
//System.err.println("Default case? 0");
return;
}
if (mi.dstIndex != -1) {
mi.srcIndex = mi.dstIndex;
}
int count = 0;
PositionVector source = new PositionVector(node.getRealPosition()
.getX(), node.getRealPosition().getY());
mi.wlist[mi.srcIndex].is_visited = true;
// get list of not visited locations
for (int i = 0; i < mi.wlist.length; i++) {
if (!mi.wlist[i].is_visited) {
count++;
}
}
// if all waypoints are visited then select new clusters and
// waypoints. Destructive mode of original SLAW matlab
// implementation by Seongik Hong, NCSU, US (3/10/2009)
while (count == 0) {
mi.clts = make_selection(clusters, mi.clts, true);
mi.wlist = get_waypoint_list(mi.clts);
for (int i = 0; i < mi.wlist.length; i++) {
if (!mi.wlist[i].is_visited) {
if (source.getDistance(mi.wlist[i].pos) != 0.0) {
count++;
} else {
mi.wlist[i].is_visited = true;
}
}
}
}
ClusterMember[] not_visited = new ClusterMember[count];
count = 0;
for (int i = 0; i < mi.wlist.length; i++) {
if (!mi.wlist[i].is_visited) {
not_visited[count++] = mi.wlist[i];
}
}
// get distance from source to all remaining waypoints
double[] dist = new double[not_visited.length];
for (int i = 0; i < not_visited.length; i++) {
dist[i] = source.getDistance(not_visited[i].pos);
}
double[] weights = new double[not_visited.length];
// cumulative sum of distance weights
for (int i = 0; i < weights.length; i++) {
weights[i] = 0;
for (int j = 0; j <= i; j++) {
weights[i] += 1 / Math.pow(dist[j], this.dist_alpha);
}
}
for (int i = 0; i < weights.length; i++) {
weights[i] /= weights[weights.length - 1];
}
double r = randomNextDouble();
int index;
for (index = 0; index < weights.length; index++) {
if (r < weights[index]) {
break;
}
}
// select the next destination
for (int i = 0; i < mi.wlist.length; i++) {
if (mi.wlist[i].pos.equals(not_visited[index].pos)) {
mi.dstIndex = i;
double pauseTime = random_powerlaw(powerlaw_step,
levy_scale_factor, powerlaw_mode)[0];
//System.err.println("Next pause time is " + pauseTime);
nextDestination(
node,
mi.wlist[mi.dstIndex].pos, (long) pauseTime
);
break;
}
}
// change destination to next source
// mi.srcIndex = mi.dstIndex;
}
/**
* returns aggregated list of cluster members from all passed clusters
*
* @param clusters
* clusters list
* @return array of ClusterMember type
*/
protected ClusterMember[] get_waypoint_list(Cluster[] clusters) {
ArrayList<ClusterMember> result = new ArrayList<ClusterMember>();
for (Cluster cluster : clusters) {
for (ClusterMember clustermember : cluster.members) {
result.add(clustermember);
}
}
return result.toArray(new ClusterMember[0]);
}
/**
* makes the selection of new clusters and waypoints from passed clusters
*
* @param clusters
* array of clusters to make selection from
* @param change_one
* changes only one of the clusters randomly and then selects new
* waypoints from all clusters
* @return array of selected clusters
*/
protected Cluster[] make_selection(Cluster[] clusters, Cluster[] cur_list,
boolean change_one) {
ArrayList<Integer> cluster_selection;
if (!change_one) {
// Number of clusters to select
int num_clusters = (int) Math.ceil((double) clusters.length
/ (double) cluster_ratio);
cluster_selection = new ArrayList<Integer>(num_clusters);
for (int i = 0; i < num_clusters; i++) {
cluster_selection.add(i, -1);
}
int[] total_list = new int[waypointModel.getNumberOfWaypoints(StrongWaypoint.class)];
int counter = 0;
// probability array
for (int i = 0; i < clusters.length; i++) {
for (int j = 0; j < clusters[i].members.length; j++) {
total_list[counter++] = clusters[i].index;
}
}
// select clusters randomly with weights
int t = total_list[(int) Math.floor(this.randomNextDouble()
* waypointModel.getNumberOfWaypoints(StrongWaypoint.class))];
for (int i = 0; i < cluster_selection.size(); i++) {
while (cluster_selection.contains(t)) {
t = total_list[(int) Math.floor(this.randomNextDouble()
* waypointModel.getNumberOfWaypoints(StrongWaypoint.class))];
}
cluster_selection.set(i, t);
}
} else {// just need to change one randomly
cluster_selection = new ArrayList<Integer>(cur_list.length);
for (Cluster cluster : cur_list) {
cluster_selection.add(cluster.index);
}
}
// change one cluster without weight consideration
cluster_selection = change_one_random(cluster_selection,
clusters.length);
// select waypoints from selected clusters.
Cluster[] result = new Cluster[cluster_selection.size()];
double numberOfWaypoints;
Cluster cluster_iterator = null;
for (int i = 0; i < cluster_selection.size(); i++) {
// find Cluster object in clusters array
for (int j = 0; j < clusters.length; j++) {
if (cluster_selection.get(i) == clusters[j].index) {
cluster_iterator = clusters[j];
break;
}
}
result[i] = new Cluster(cluster_iterator.index);
numberOfWaypoints = (double) cluster_iterator.members.length
/ (double) this.waypoint_ratio;
int[] waypoint_selection;
if (numberOfWaypoints < 1) {
waypoint_selection = select_uniformly(
cluster_iterator.members.length, 1);
} else {
if (this.randomNextDouble() < numberOfWaypoints % 1) {
waypoint_selection = select_uniformly(
cluster_iterator.members.length,
(int) (Math.floor(numberOfWaypoints) + 1));
} else {
waypoint_selection = select_uniformly(
cluster_iterator.members.length,
(int) Math.floor(numberOfWaypoints));
}
}
result[i].members = new ClusterMember[waypoint_selection.length];
for (int j = 0; j < waypoint_selection.length; j++) {
result[i].members[j] = cluster_iterator.members[waypoint_selection[j]]
.clone();
}
}
return result;
}
/**
* changes one of the numbers randomly from the passed array. The new
* changed number is in range [1,n]
*
* @param list
* array of integers
* @param n
* range of numbers
* @return array of integers with one element changed randomly
*/
protected ArrayList<Integer> change_one_random(ArrayList<Integer> list,
int n) {
int index = (int) Math.floor(this.randomNextDouble() * list.size());
int value = (int) Math.floor(this.randomNextDouble() * n) + 1;
while (list.contains(value)) {
value = (int) Math.floor(this.randomNextDouble() * n) + 1;
}
list.set(index, value);
return list;
}
/**
* selects k numbers out of n uniformly
*
* @param n
* @param k
* @return array of k integers
*/
protected int[] select_uniformly(int n, int k) {
if (k > n)
throw new RuntimeException(
"SLAW.select_uniformaly(): value of k must not be larger than n.");
int t;
int[] list = new int[k];
for (int i = 0; i < k; i++) {
list[i] = -1;
}
boolean is_in;
int count = 0;
while (count < k) {
is_in = false;
t = (int) Math.floor(this.randomNextDouble() * n);
for (int i = 0; i < list.length; i++) {
if (list[i] == t) {
is_in = true;
break;
}
}
if (!is_in) {
list[count++] = t;
}
}
return list;
}
/**
* Generates random values from power-law distribution.
*
* @param powerlaw_step
* the total numbers to generate. Returns an array of this size.
* @param levy_scale_factor
* levy scaling factor of distribution
* @param powerlaw_mode
* 1: stabrnd 2: reverse computation
* @return double array of powerlaw_step length
**/
protected double[] random_powerlaw(int powerlaw_step,
int levy_scale_factor, int powerlaw_mode) {
double[] result = new double[powerlaw_step];
for (int xi = 0; xi < powerlaw_step;) {
if (powerlaw_mode == 1) { // stabrnd
double[] stabrnd_result = stabrnd(0, levy_scale_factor, 0,
powerlaw_step);
ArrayList<Double> temp = new ArrayList<Double>();
for (int i = 0; i < stabrnd_result.length; i++) {
if (stabrnd_result[i] > this.minpause
&& stabrnd_result[i] < this.maxpause) {
temp.add(new Double(stabrnd_result[i]));
}
}
if (temp.size() > 0) {
for (Double d : temp) {
result[xi++] = d;
if (xi > powerlaw_step)
break;
}
}
} else if (powerlaw_mode == 2) { // reverse computation
double temp = Math.pow(randomNextDouble(),
1 / (1 - (this.beta + 1))) * this.minpause;
if (temp < this.maxpause) {
result[xi++] = temp;
}
}
}
return result;
}
/**
* Returns array of randomly generated n numbers based on the method of J.M.
* Chambers, C.L. Mallows and B.W. Stuck,
* "A Method for Simulating Stable Random Variables," JASA 71 (1976): 340-4.
*
* @param b
* beta factor
* @param levy_scale_factor
* @param delta
* @param n
* count of random numbers to generate
* @return double array of n length
*/
private double[] stabrnd(double b, int levy_scale_factor, double delta,
int n) {
if (this.beta < .1 || this.beta > 2) {
throw new RuntimeException(
"SLAW.stabrnd(): Beta value must be in [.1,2]");
}
if (Math.abs(b) > 1) {
throw new RuntimeException(
"SLAW.stabrnd(): local beta value must be in [-1,1]");
}
// Generate exponential w and uniform phi
double[] w = new double[n];
double[] x = new double[n];
double[] phi = new double[n];
for (int i = 0; i < n; i++) {
w[i] = -Math.log(randomNextDouble());
phi[i] = (randomNextDouble() - 0.5) * Math.PI;
}
// Gaussian case (Box-Muller)
if (this.beta == 2) {
for (int i = 0; i < n; i++) {
x[i] = 2 * Math.sqrt(w[i]) * Math.sin(phi[i]);
x[i] = delta + levy_scale_factor * x[i];
}
} else if (b == 0) { // Symmetrical cases
if (this.beta == 1) { // Cauchy case
for (int i = 0; i < n; i++) {
x[i] = Math.tan(phi[i]);
}
} else {
for (int i = 0; i < n; i++) {
x[i] = Math.pow(Math.cos((1 - this.beta) * phi[i]) / w[i],
1 / this.beta - 1)
* Math.sin(this.beta * phi[i])
/ Math.pow(Math.cos(phi[i]), 1 / this.beta);
}
}
} else { // General cases
double cosphi, zeta, aphi, a1phi, bphi;
if (Math.abs(this.beta - 1) > 0.00000001) {
for (int i = 0; i < n; i++) {
cosphi = Math.cos(phi[i]);
zeta = b * Math.tan(Math.PI * this.beta / 2);
aphi = this.beta * phi[i];
a1phi = (1 - this.beta) * phi[i];
x[i] = (Math.sin(aphi) + zeta * Math.cos(aphi))
/ cosphi
* Math.pow(
(Math.cos(a1phi) + zeta * Math.sin(a1phi))
/ (w[i] * cosphi), (1 - this.beta)
/ this.beta);
}
} else {
for (int i = 0; i < n; i++) {
cosphi = Math.cos(phi[i]);
bphi = Math.PI / 2 + b * phi[i];
x[i] = 2
/ Math.PI
* (bphi * Math.tan(phi[i]) - b
* Math.log((Math.PI / 2) * w[i] * cosphi
/ bphi));
}
if (this.beta != 1) {
for (int i = 0; i < n; i++) {
x[i] += b * Math.tan(Math.PI * this.beta / 2);
}
}
}
for (int i = 0; i < n; i++) {
x[i] = delta + levy_scale_factor * x[i];
}
}
return x;
}
protected double randomNextDouble(final double value) {
return (randomNextDouble() * value);
}
protected double randomNextDouble() {
return xorShiftRandom.nextDouble();
//return rand.nextDouble();
}
private static final class Cluster {
public ClusterMember[] members;
public int index = -1;
public Cluster(int _index) {
index = _index;
}
public Cluster(int _index, ClusterMember[] _members) {
index = _index;
members = _members;
}
public String toString() {
return "Cluster[index: " + index + "]";
}
}
private static final class ClusterMember {
public int cluster_index = -1;
public PositionVector pos;
public boolean is_visited = false;
public ClusterMember(int _cluster_index, PositionVector _pos,
boolean _is_visited) {
this.cluster_index = _cluster_index;
this.is_visited = _is_visited;
this.pos = _pos;
}
public ClusterMember clone() {
return new ClusterMember(this.cluster_index, this.pos,
this.is_visited);
}
}
private static class SLAWMovementInformation {
public SLAWMovementInformation() {
//
}
public int srcIndex = -1;
public int dstIndex = -1;
public Cluster[] clts = null;
public ClusterMember[] wlist = null;
}
@Configure()
@After(required={WaypointModel.class})
public void _verifyConfig() {
/*
* FIXME: get rid of this method!
*/
Collection<Waypoint> strongWaypoints = waypointModel.getWaypoints(StrongWaypoint.class);
if (strongWaypoints == null)
throw new ConfigurationException("The configured waypoint model hasn't generated any strong waypoints that are required by the SLAWMovementModel.");
clusters = generate_clusters(waypointModel);
if (clusters.length <= 2) {
throw new ConfigurationException("The SLAW movement model could only generate 1 cluster, please adjust the cluster range parameter");
}
VisualizationInjector.injectComponent("Clusters", -1, new SLAWClusterOverlay(clusters, waypointModel), false);
VisualizationInjector.addDisplayString(new DisplayString() {
@Override
public String getDisplayString() {
int clusterWps = 0;
for (Cluster c : clusters) {
clusterWps += c.members.length;
}
return "SLAW[Clusters: " + clusters.length + ", WPs in clusters: " + clusterWps + ", Avg per cluster: " + (clusterWps / clusters.length) + "]";
}
});
}
@Override
public void setWaypointModel(WaypointModel waypointModel) {
super.setWaypointModel(waypointModel);
}
/**
* generates clusters
*
* @param waypoints
* list of waypoint s
* @return array of clusters
*/
protected Cluster[] generate_clusters(WaypointModel model) {
Vector<PositionVector> all_points = new Vector<PositionVector>();
Vector<PositionVector> new_points = new Vector<PositionVector>();
Vector<PositionVector> members = new Vector<PositionVector>();
Vector<Cluster> clusters = new Vector<Cluster>();
Vector<ClusterMember> cluster_members = new Vector<ClusterMember>();
Waypoint[] waypoints = new Waypoint[]{};
Collection<Waypoint> waypointList = model.getWaypoints(StrongWaypoint.class);
if (waypointList == null)
throw new ConfigurationException("The configured waypoint model didn't generate any strong waypoints");
waypoints = waypointList.toArray(waypoints);
for (int i = 0; i < waypoints.length; i++) {
all_points.add(waypoints[i].getPosition());
}
PositionVector init_pos = null;
int cluster_count = 0;
while (!all_points.isEmpty()) {
if (init_pos == null) {
init_pos = all_points.firstElement();
all_points.remove(0);
members.add(init_pos);
}
for (int i = 0; i < all_points.size(); i++) {
PositionVector new_pos = all_points.elementAt(i);
if (init_pos.getDistance(new_pos) <= this.cluster_range) {
new_points.add(new_pos);
members.add(new_pos);
all_points.remove(i--);
}
}// for all_points
if (!new_points.isEmpty() && !all_points.isEmpty()) {
init_pos = new_points.firstElement();
new_points.remove(0);
}
else {
for (int i = 0; i < members.size(); i++) {
cluster_members.add(new ClusterMember(cluster_count, members.elementAt(i), false));
}
clusters.add(new Cluster(++cluster_count, cluster_members.toArray(new ClusterMember[0])));
cluster_members.clear();
new_points.clear();
members.clear();
init_pos = null;
}
}// while all_points
return clusters.toArray(new Cluster[0]);
}
private class SLAWClusterOverlay extends JComponent {
private Map<Cluster, Color> clusterColors = Maps.newHashMap();
private Cluster[] clusters;
private Random rnd = new Random(System.nanoTime());
private WaypointModel model;
public SLAWClusterOverlay(Cluster[] clusters, WaypointModel model) {
super();
this.clusters = clusters;
this.model = model;
PositionVector dimension = model.getMap().getDimensions();
setBounds(0, 0, (int) dimension.getX(), (int) dimension.getY());
setOpaque(false);
setVisible(true);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setFont(new Font("SansSerif", Font.PLAIN, 9));
for (Cluster c : clusters) {
PositionVector lastPos = null;
Color randomColor = clusterColors.get(c);
if (randomColor == null) {
final float hue = rnd.nextFloat();
// Saturation between 0.1 and 0.3
final float saturation = (rnd.nextInt(2000) + 1000) / 10000f;
final float luminance = 0.9f;
randomColor = Color.getHSBColor(hue, saturation, luminance);
randomColor = new Color(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat());
clusterColors.put(c, randomColor);
}
g2.setColor(randomColor);
for (ClusterMember m : c.members) {
if (lastPos == null) lastPos = m.pos;
g2.drawLine((int)lastPos.getX(), (int)lastPos.getY(), (int)m.pos.getX(), (int)m.pos.getY());
lastPos = m.pos;
}
}
}
}
}
/*
* 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;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Random;
import java.util.Vector;
import java.util.WeakHashMap;
import javax.swing.JComponent;
import com.google.common.collect.Maps;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.api.topology.waypoints.WaypointModel;
import de.tud.kom.p2psim.impl.scenario.simcfg2.annotations.After;
import de.tud.kom.p2psim.impl.scenario.simcfg2.annotations.Configure;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector.DisplayString;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.StrongWaypoint;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.Waypoint;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* The SLAW Movement Model is based on the implementation in
* BonnMotion Copyright (C) 2002-2010 University of Bonn
* by Zia-Ul-Huda, Gufron Atokhojaev and Florian Schmitt
*
* @author Fabio Zöllner
* @version 1.0, 09.04.2012
*/
public class SLAWMovementModel extends AbstractWaypointMovementModel {
private static final int powerlaw_step = 1;
private static int levy_scale_factor = 1;
private static int powerlaw_mode = 1;
protected Random rand = Randoms
.getRandom(SLAWMovementModel.class);
protected Random xorShiftRandom = new XorShiftRandom(rand.nextLong());
protected double beta = 1;
protected long minpause = 10;
protected long maxpause = 50;
protected double dist_alpha = 3;
protected double cluster_range;
protected int cluster_ratio = 3;
protected int waypoint_ratio = 3;
protected Cluster[] clusters;
protected WeakHashMap<MovementSupported, SLAWMovementInformation> movementInformation;
// TODO: minpause and maxpause are currently in microseconds... should be
// changed to minutes
@XMLConfigurableConstructor({"worldX", "worldY", "minpause", "maxpause", "beta", "distAlpha", "clusterRange", "clusterRatio", "waypointRatio" })
public SLAWMovementModel(double worldX, double worldY, long minpause, long maxpause, double beta, double distAlpha, double clusterRange, int clusterRatio, int waypointRatio) {
super(worldX, worldY);
this.minpause = minpause;
this.maxpause = maxpause;
this.dist_alpha = distAlpha;
this.cluster_range = clusterRange;
this.cluster_ratio = clusterRatio;
this.waypoint_ratio = waypointRatio;
movementInformation = new WeakHashMap<MovementSupported, SLAWMovementModel.SLAWMovementInformation>();
}
@Override
public void nextPosition(MovementSupported node) {
// These variables have values same as in the matlab implementation of
// SLAW model by Seongik Hong, NCSU, US (3/10/2009)
if (waypointModel == null) {
throw new ConfigurationException("SLAWMovementModel requires a valid waypoint model which hasn't been provided, cannot execute");
}
SLAWMovementInformation mi = movementInformation.get(node);
if (mi == null) {
//System.err.println("Creating new movement information for node " + node.toString());
mi = new SLAWMovementInformation();
movementInformation.put(node, mi);
}
// log.debug("Selecting new destination for node " + mi.nodeId);
// get random clusters and waypoints
if (mi.clts == null)
mi.clts = make_selection(clusters, null, false);
// get random clusters and waypoints
if (mi.wlist == null)
mi.wlist = get_waypoint_list(mi.clts);
// random source node
if (mi.srcIndex == -1) {
int old = mi.srcIndex;
mi.srcIndex = (int) Math
.floor(randomNextDouble() * mi.wlist.length);
//System.err.println("mi.srcIndex was " + old + " but is now " + mi.srcIndex);
// Set the initial position to the selected waypoint
nextDestination(node, mi.wlist[mi.srcIndex].pos, 0);
//System.err.println("Default case? 0");
return;
}
if (mi.dstIndex != -1) {
mi.srcIndex = mi.dstIndex;
}
int count = 0;
PositionVector source = new PositionVector(node.getRealPosition()
.getX(), node.getRealPosition().getY());
mi.wlist[mi.srcIndex].is_visited = true;
// get list of not visited locations
for (int i = 0; i < mi.wlist.length; i++) {
if (!mi.wlist[i].is_visited) {
count++;
}
}
// if all waypoints are visited then select new clusters and
// waypoints. Destructive mode of original SLAW matlab
// implementation by Seongik Hong, NCSU, US (3/10/2009)
while (count == 0) {
mi.clts = make_selection(clusters, mi.clts, true);
mi.wlist = get_waypoint_list(mi.clts);
for (int i = 0; i < mi.wlist.length; i++) {
if (!mi.wlist[i].is_visited) {
if (source.distanceTo(mi.wlist[i].pos) != 0.0) {
count++;
} else {
mi.wlist[i].is_visited = true;
}
}
}
}
ClusterMember[] not_visited = new ClusterMember[count];
count = 0;
for (int i = 0; i < mi.wlist.length; i++) {
if (!mi.wlist[i].is_visited) {
not_visited[count++] = mi.wlist[i];
}
}
// get distance from source to all remaining waypoints
double[] dist = new double[not_visited.length];
for (int i = 0; i < not_visited.length; i++) {
dist[i] = source.distanceTo(not_visited[i].pos);
}
double[] weights = new double[not_visited.length];
// cumulative sum of distance weights
for (int i = 0; i < weights.length; i++) {
weights[i] = 0;
for (int j = 0; j <= i; j++) {
weights[i] += 1 / Math.pow(dist[j], this.dist_alpha);
}
}
for (int i = 0; i < weights.length; i++) {
weights[i] /= weights[weights.length - 1];
}
double r = randomNextDouble();
int index;
for (index = 0; index < weights.length; index++) {
if (r < weights[index]) {
break;
}
}
// select the next destination
for (int i = 0; i < mi.wlist.length; i++) {
if (mi.wlist[i].pos.equals(not_visited[index].pos)) {
mi.dstIndex = i;
double pauseTime = random_powerlaw(powerlaw_step,
levy_scale_factor, powerlaw_mode)[0];
//System.err.println("Next pause time is " + pauseTime);
nextDestination(
node,
mi.wlist[mi.dstIndex].pos, (long) pauseTime
);
break;
}
}
// change destination to next source
// mi.srcIndex = mi.dstIndex;
}
/**
* returns aggregated list of cluster members from all passed clusters
*
* @param clusters
* clusters list
* @return array of ClusterMember type
*/
protected ClusterMember[] get_waypoint_list(Cluster[] clusters) {
ArrayList<ClusterMember> result = new ArrayList<ClusterMember>();
for (Cluster cluster : clusters) {
for (ClusterMember clustermember : cluster.members) {
result.add(clustermember);
}
}
return result.toArray(new ClusterMember[0]);
}
/**
* makes the selection of new clusters and waypoints from passed clusters
*
* @param clusters
* array of clusters to make selection from
* @param change_one
* changes only one of the clusters randomly and then selects new
* waypoints from all clusters
* @return array of selected clusters
*/
protected Cluster[] make_selection(Cluster[] clusters, Cluster[] cur_list,
boolean change_one) {
ArrayList<Integer> cluster_selection;
if (!change_one) {
// Number of clusters to select
int num_clusters = (int) Math.ceil((double) clusters.length
/ (double) cluster_ratio);
cluster_selection = new ArrayList<Integer>(num_clusters);
for (int i = 0; i < num_clusters; i++) {
cluster_selection.add(i, -1);
}
int[] total_list = new int[waypointModel.getNumberOfWaypoints(StrongWaypoint.class)];
int counter = 0;
// probability array
for (int i = 0; i < clusters.length; i++) {
for (int j = 0; j < clusters[i].members.length; j++) {
total_list[counter++] = clusters[i].index;
}
}
// select clusters randomly with weights
int t = total_list[(int) Math.floor(this.randomNextDouble()
* waypointModel.getNumberOfWaypoints(StrongWaypoint.class))];
for (int i = 0; i < cluster_selection.size(); i++) {
while (cluster_selection.contains(t)) {
t = total_list[(int) Math.floor(this.randomNextDouble()
* waypointModel.getNumberOfWaypoints(StrongWaypoint.class))];
}
cluster_selection.set(i, t);
}
} else {// just need to change one randomly
cluster_selection = new ArrayList<Integer>(cur_list.length);
for (Cluster cluster : cur_list) {
cluster_selection.add(cluster.index);
}
}
// change one cluster without weight consideration
cluster_selection = change_one_random(cluster_selection,
clusters.length);
// select waypoints from selected clusters.
Cluster[] result = new Cluster[cluster_selection.size()];
double numberOfWaypoints;
Cluster cluster_iterator = null;
for (int i = 0; i < cluster_selection.size(); i++) {
// find Cluster object in clusters array
for (int j = 0; j < clusters.length; j++) {
if (cluster_selection.get(i) == clusters[j].index) {
cluster_iterator = clusters[j];
break;
}
}
result[i] = new Cluster(cluster_iterator.index);
numberOfWaypoints = (double) cluster_iterator.members.length
/ (double) this.waypoint_ratio;
int[] waypoint_selection;
if (numberOfWaypoints < 1) {
waypoint_selection = select_uniformly(
cluster_iterator.members.length, 1);
} else {
if (this.randomNextDouble() < numberOfWaypoints % 1) {
waypoint_selection = select_uniformly(
cluster_iterator.members.length,
(int) (Math.floor(numberOfWaypoints) + 1));
} else {
waypoint_selection = select_uniformly(
cluster_iterator.members.length,
(int) Math.floor(numberOfWaypoints));
}
}
result[i].members = new ClusterMember[waypoint_selection.length];
for (int j = 0; j < waypoint_selection.length; j++) {
result[i].members[j] = cluster_iterator.members[waypoint_selection[j]]
.clone();
}
}
return result;
}
/**
* changes one of the numbers randomly from the passed array. The new
* changed number is in range [1,n]
*
* @param list
* array of integers
* @param n
* range of numbers
* @return array of integers with one element changed randomly
*/
protected ArrayList<Integer> change_one_random(ArrayList<Integer> list,
int n) {
int index = (int) Math.floor(this.randomNextDouble() * list.size());
int value = (int) Math.floor(this.randomNextDouble() * n) + 1;
while (list.contains(value)) {
value = (int) Math.floor(this.randomNextDouble() * n) + 1;
}
list.set(index, value);
return list;
}
/**
* selects k numbers out of n uniformly
*
* @param n
* @param k
* @return array of k integers
*/
protected int[] select_uniformly(int n, int k) {
if (k > n)
throw new RuntimeException(
"SLAW.select_uniformaly(): value of k must not be larger than n.");
int t;
int[] list = new int[k];
for (int i = 0; i < k; i++) {
list[i] = -1;
}
boolean is_in;
int count = 0;
while (count < k) {
is_in = false;
t = (int) Math.floor(this.randomNextDouble() * n);
for (int i = 0; i < list.length; i++) {
if (list[i] == t) {
is_in = true;
break;
}
}
if (!is_in) {
list[count++] = t;
}
}
return list;
}
/**
* Generates random values from power-law distribution.
*
* @param powerlaw_step
* the total numbers to generate. Returns an array of this size.
* @param levy_scale_factor
* levy scaling factor of distribution
* @param powerlaw_mode
* 1: stabrnd 2: reverse computation
* @return double array of powerlaw_step length
**/
protected double[] random_powerlaw(int powerlaw_step,
int levy_scale_factor, int powerlaw_mode) {
double[] result = new double[powerlaw_step];
for (int xi = 0; xi < powerlaw_step;) {
if (powerlaw_mode == 1) { // stabrnd
double[] stabrnd_result = stabrnd(0, levy_scale_factor, 0,
powerlaw_step);
ArrayList<Double> temp = new ArrayList<Double>();
for (int i = 0; i < stabrnd_result.length; i++) {
if (stabrnd_result[i] > this.minpause
&& stabrnd_result[i] < this.maxpause) {
temp.add(new Double(stabrnd_result[i]));
}
}
if (temp.size() > 0) {
for (Double d : temp) {
result[xi++] = d;
if (xi > powerlaw_step)
break;
}
}
} else if (powerlaw_mode == 2) { // reverse computation
double temp = Math.pow(randomNextDouble(),
1 / (1 - (this.beta + 1))) * this.minpause;
if (temp < this.maxpause) {
result[xi++] = temp;
}
}
}
return result;
}
/**
* Returns array of randomly generated n numbers based on the method of J.M.
* Chambers, C.L. Mallows and B.W. Stuck,
* "A Method for Simulating Stable Random Variables," JASA 71 (1976): 340-4.
*
* @param b
* beta factor
* @param levy_scale_factor
* @param delta
* @param n
* count of random numbers to generate
* @return double array of n length
*/
private double[] stabrnd(double b, int levy_scale_factor, double delta,
int n) {
if (this.beta < .1 || this.beta > 2) {
throw new RuntimeException(
"SLAW.stabrnd(): Beta value must be in [.1,2]");
}
if (Math.abs(b) > 1) {
throw new RuntimeException(
"SLAW.stabrnd(): local beta value must be in [-1,1]");
}
// Generate exponential w and uniform phi
double[] w = new double[n];
double[] x = new double[n];
double[] phi = new double[n];
for (int i = 0; i < n; i++) {
w[i] = -Math.log(randomNextDouble());
phi[i] = (randomNextDouble() - 0.5) * Math.PI;
}
// Gaussian case (Box-Muller)
if (this.beta == 2) {
for (int i = 0; i < n; i++) {
x[i] = 2 * Math.sqrt(w[i]) * Math.sin(phi[i]);
x[i] = delta + levy_scale_factor * x[i];
}
} else if (b == 0) { // Symmetrical cases
if (this.beta == 1) { // Cauchy case
for (int i = 0; i < n; i++) {
x[i] = Math.tan(phi[i]);
}
} else {
for (int i = 0; i < n; i++) {
x[i] = Math.pow(Math.cos((1 - this.beta) * phi[i]) / w[i],
1 / this.beta - 1)
* Math.sin(this.beta * phi[i])
/ Math.pow(Math.cos(phi[i]), 1 / this.beta);
}
}
} else { // General cases
double cosphi, zeta, aphi, a1phi, bphi;
if (Math.abs(this.beta - 1) > 0.00000001) {
for (int i = 0; i < n; i++) {
cosphi = Math.cos(phi[i]);
zeta = b * Math.tan(Math.PI * this.beta / 2);
aphi = this.beta * phi[i];
a1phi = (1 - this.beta) * phi[i];
x[i] = (Math.sin(aphi) + zeta * Math.cos(aphi))
/ cosphi
* Math.pow(
(Math.cos(a1phi) + zeta * Math.sin(a1phi))
/ (w[i] * cosphi), (1 - this.beta)
/ this.beta);
}
} else {
for (int i = 0; i < n; i++) {
cosphi = Math.cos(phi[i]);
bphi = Math.PI / 2 + b * phi[i];
x[i] = 2
/ Math.PI
* (bphi * Math.tan(phi[i]) - b
* Math.log((Math.PI / 2) * w[i] * cosphi
/ bphi));
}
if (this.beta != 1) {
for (int i = 0; i < n; i++) {
x[i] += b * Math.tan(Math.PI * this.beta / 2);
}
}
}
for (int i = 0; i < n; i++) {
x[i] = delta + levy_scale_factor * x[i];
}
}
return x;
}
protected double randomNextDouble(final double value) {
return (randomNextDouble() * value);
}
protected double randomNextDouble() {
return xorShiftRandom.nextDouble();
//return rand.nextDouble();
}
private static final class Cluster {
public ClusterMember[] members;
public int index = -1;
public Cluster(int _index) {
index = _index;
}
public Cluster(int _index, ClusterMember[] _members) {
index = _index;
members = _members;
}
public String toString() {
return "Cluster[index: " + index + "]";
}
}
private static final class ClusterMember {
public int cluster_index = -1;
public PositionVector pos;
public boolean is_visited = false;
public ClusterMember(int _cluster_index, PositionVector _pos,
boolean _is_visited) {
this.cluster_index = _cluster_index;
this.is_visited = _is_visited;
this.pos = _pos;
}
public ClusterMember clone() {
return new ClusterMember(this.cluster_index, this.pos,
this.is_visited);
}
}
private static class SLAWMovementInformation {
public SLAWMovementInformation() {
//
}
public int srcIndex = -1;
public int dstIndex = -1;
public Cluster[] clts = null;
public ClusterMember[] wlist = null;
}
@Configure()
@After(required={WaypointModel.class})
public void _verifyConfig() {
/*
* FIXME: get rid of this method!
*/
Collection<Waypoint> strongWaypoints = waypointModel.getWaypoints(StrongWaypoint.class);
if (strongWaypoints == null)
throw new ConfigurationException("The configured waypoint model hasn't generated any strong waypoints that are required by the SLAWMovementModel.");
clusters = generate_clusters(waypointModel);
if (clusters.length <= 2) {
throw new ConfigurationException("The SLAW movement model could only generate 1 cluster, please adjust the cluster range parameter");
}
VisualizationInjector.injectComponent("Clusters", -1, new SLAWClusterOverlay(clusters, waypointModel), false);
VisualizationInjector.addDisplayString(new DisplayString() {
@Override
public String getDisplayString() {
int clusterWps = 0;
for (Cluster c : clusters) {
clusterWps += c.members.length;
}
return "SLAW[Clusters: " + clusters.length + ", WPs in clusters: " + clusterWps + ", Avg per cluster: " + (clusterWps / clusters.length) + "]";
}
});
}
@Override
public void setWaypointModel(WaypointModel waypointModel) {
super.setWaypointModel(waypointModel);
}
/**
* generates clusters
*
* @param waypoints
* list of waypoint s
* @return array of clusters
*/
protected Cluster[] generate_clusters(WaypointModel model) {
Vector<PositionVector> all_points = new Vector<PositionVector>();
Vector<PositionVector> new_points = new Vector<PositionVector>();
Vector<PositionVector> members = new Vector<PositionVector>();
Vector<Cluster> clusters = new Vector<Cluster>();
Vector<ClusterMember> cluster_members = new Vector<ClusterMember>();
Waypoint[] waypoints = new Waypoint[]{};
Collection<Waypoint> waypointList = model.getWaypoints(StrongWaypoint.class);
if (waypointList == null)
throw new ConfigurationException("The configured waypoint model didn't generate any strong waypoints");
waypoints = waypointList.toArray(waypoints);
for (int i = 0; i < waypoints.length; i++) {
all_points.add(waypoints[i].getPosition());
}
PositionVector init_pos = null;
int cluster_count = 0;
while (!all_points.isEmpty()) {
if (init_pos == null) {
init_pos = all_points.firstElement();
all_points.remove(0);
members.add(init_pos);
}
for (int i = 0; i < all_points.size(); i++) {
PositionVector new_pos = all_points.elementAt(i);
if (init_pos.distanceTo(new_pos) <= this.cluster_range) {
new_points.add(new_pos);
members.add(new_pos);
all_points.remove(i--);
}
}// for all_points
if (!new_points.isEmpty() && !all_points.isEmpty()) {
init_pos = new_points.firstElement();
new_points.remove(0);
}
else {
for (int i = 0; i < members.size(); i++) {
cluster_members.add(new ClusterMember(cluster_count, members.elementAt(i), false));
}
clusters.add(new Cluster(++cluster_count, cluster_members.toArray(new ClusterMember[0])));
cluster_members.clear();
new_points.clear();
members.clear();
init_pos = null;
}
}// while all_points
return clusters.toArray(new Cluster[0]);
}
private class SLAWClusterOverlay extends JComponent {
private Map<Cluster, Color> clusterColors = Maps.newHashMap();
private Cluster[] clusters;
private Random rnd = new Random(System.nanoTime());
private WaypointModel model;
public SLAWClusterOverlay(Cluster[] clusters, WaypointModel model) {
super();
this.clusters = clusters;
this.model = model;
PositionVector dimension = model.getMap().getDimensions();
setBounds(0, 0, (int) dimension.getX(), (int) dimension.getY());
setOpaque(false);
setVisible(true);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setFont(new Font("SansSerif", Font.PLAIN, 9));
for (Cluster c : clusters) {
PositionVector lastPos = null;
Color randomColor = clusterColors.get(c);
if (randomColor == null) {
final float hue = rnd.nextFloat();
// Saturation between 0.1 and 0.3
final float saturation = (rnd.nextInt(2000) + 1000) / 10000f;
final float luminance = 0.9f;
randomColor = Color.getHSBColor(hue, saturation, luminance);
randomColor = new Color(rnd.nextFloat(), rnd.nextFloat(), rnd.nextFloat());
clusterColors.put(c, randomColor);
}
g2.setColor(randomColor);
for (ClusterMember m : c.members) {
if (lastPos == null) lastPos = m.pos;
g2.drawLine((int)lastPos.getX(), (int)lastPos.getY(), (int)m.pos.getX(), (int)m.pos.getY());
lastPos = m.pos;
}
}
}
}
}
......@@ -59,7 +59,7 @@ public class TargetMovement extends AbstractMovementModel {
PositionVector rVec = new PositionVector(x, y);
rVec = rVec.minus(pos);
double length = rVec.getDistance(new PositionVector(0, 0));
double length = rVec.distanceTo(new PositionVector(0, 0));
PositionVector vec;
if (length > distance) {
......
/*
* 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 de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Left;
/**
* This movement strategy moves directly towards a given destination without
* regard for obstacles or way points.
*
* @author Fabio Zöllner
* @version 1.0, 09.04.2012
*/
public class LinearMovement extends AbstractLocalMovementStrategy {
public Either<PositionVector, Boolean> nextPosition(MovementSupported comp,
PositionVector destination) {
PositionVector newPosition;
if (destination.getDistance(comp.getRealPosition()) < getMovementSpeed(comp)) {
newPosition = destination.clone();
} else {
newPosition = comp.getRealPosition().moveStep(destination, getMovementSpeed(comp));
}
return new Left<PositionVector, Boolean>(newPosition);
}
}
/*
* 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 de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Left;
/**
* This movement strategy moves directly towards a given destination without
* regard for obstacles or way points.
*
* @author Fabio Zöllner
* @version 1.0, 09.04.2012
*/
public class LinearMovement extends AbstractLocalMovementStrategy {
public Either<PositionVector, Boolean> nextPosition(MovementSupported comp,
PositionVector destination) {
PositionVector newPosition;
if (destination
.distanceTo(comp.getRealPosition()) < getMovementSpeed(comp)) {
newPosition = destination.clone();
} else {
newPosition = comp.getRealPosition().moveStep(destination, getMovementSpeed(comp));
}
return new Left<PositionVector, Boolean>(newPosition);
}
}
......@@ -25,6 +25,7 @@ import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
......@@ -34,12 +35,13 @@ 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.MovementSupported;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.Topology;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.GPSCalculation;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Left;
import de.tudarmstadt.maki.simonstrator.api.Binder;
/**
* This movement strategy uses the data from MapQuest
......@@ -63,7 +65,8 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
//if the distance is smaller than the given one, the node will choose the next point in the list
public OnlineMapQuestMovement() {
this.worldDimensions = Topology.getWorldDimension();
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
latLeft = GPSCalculation.getLatLower();
latRight = GPSCalculation.getLatUpper();
lonLeft = GPSCalculation.getLonLeft();
......@@ -74,7 +77,8 @@ public class OnlineMapQuestMovement extends AbstractLocalMovementStrategy {
PositionVector destination) {
PositionVector newPosition = null;
if (destination.getDistance(comp.getRealPosition()) < getMovementSpeed(comp)) {
if (destination
.distanceTo(comp.getRealPosition()) < getMovementSpeed(comp)) {
newPosition = destination.clone();
} else {
//if not set already for this node or new destination is different than last one
......
......@@ -31,12 +31,13 @@ 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.MovementSupported;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.Topology;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.GPSCalculation;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Left;
import de.tudarmstadt.maki.simonstrator.api.Binder;
/**
* This movement strategy uses the data from osm and navigates the nodes throught streets to the destination
......@@ -68,7 +69,8 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
private double tolerance = 1;
public RealWorldStreetsMovement() {
this.worldDimensions = Topology.getWorldDimension();
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
latLeft = GPSCalculation.getLatLower();
latRight = GPSCalculation.getLatUpper();
lonLeft = GPSCalculation.getLonLeft();
......@@ -90,7 +92,8 @@ public class RealWorldStreetsMovement extends AbstractLocalMovementStrategy {
if(!init) init();
PositionVector newPosition = null;
if (destination.getDistance(comp.getRealPosition()) < getMovementSpeed(comp)) {
if (destination
.distanceTo(comp.getRealPosition()) < getMovementSpeed(comp)) {
newPosition = destination.clone();
} else {
//if not set already for this node or new destination is different than last one
......
/*
* 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.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.Path;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.Waypoint;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.WeakWaypoint;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Left;
import de.tud.kom.p2psim.impl.util.Right;
/**
* This movement strategy uses the getShortestPath method implemented by the
* waypoint model and moves along path given by this method.
*
* @author Fabio Zöllner
* @version 1.0, 10.04.2012
*/
public class ShortestPathWaypointMovement extends AbstractLocalMovementStrategy {
// Contains the shortest path and the currently used path
protected final WeakHashMap<MovementSupported, Integer> currentPath = new WeakHashMap<MovementSupported, Integer>();
protected final WeakHashMap<MovementSupported, List<Waypoint>> dstPaths = new WeakHashMap<MovementSupported, List<Waypoint>>();
// Used to check if the destination was altered by the waypoint movement
// model
protected WeakHashMap<MovementSupported, PositionVector> currentDestination = new WeakHashMap<MovementSupported, PositionVector>();
/**
* Calculates the next position of the given movement supported component by
* using the shortest path to the waypoint closest to the destination.
*/
@Override
public Either<PositionVector, Boolean> nextPosition(MovementSupported comp,
PositionVector destination) {
if (currentDestination.get(comp) == null
|| !currentDestination.get(comp).equals(destination)) {
currentDestination.put(comp, destination);
calculateNextMovementPath(comp, destination);
// If the list of the shortest path is empty the destination is the
// same
// as the current position. Thus tell the abstract waypoint model
// that we
// reached the destination.
if (dstPaths.get(comp).size() == 0) {
return new Right<PositionVector, Boolean>(true);
}
}
int currentPathIdx = currentPath.get(comp);
Waypoint currentWaypoint = dstPaths.get(comp).get(currentPathIdx);
double speed = getMovementSpeed(comp);
PositionVector newPosition = comp.getRealPosition().moveStep(
currentWaypoint.getPosition(), speed);
if (destinationWaypointReached(currentWaypoint, newPosition, speed)) {
// We reached the next waypoint on the path to the destination
// move to the next waypoint
currentPath.put(comp, ++currentPathIdx);
// The destination waypoint has been reached, tell the abstract
// waypoint model
if (dstPaths.get(comp).size() <= currentPathIdx) {
currentPath.put(comp, --currentPathIdx);
return new Right<PositionVector, Boolean>(true);
}
}
return new Left<PositionVector, Boolean>(newPosition);
}
/**
* Finds the closest waypoints to the current position of the movement
* supported component as well as the final destination and searches for a
* path between the two waypoints using the underlying network of
* WeakWaypoints.
*
* @param comp
* @param finalDestination
*/
protected void calculateNextMovementPath(MovementSupported comp,
PositionVector finalDestination) {
// Required for shortest path calculation
Waypoint closestWaypointToCurrentPosition = waypointModel
.getClosestWaypoint(comp.getRealPosition(), WeakWaypoint.class);
Waypoint closestWaypointToDestination = waypointModel
.getClosestWaypoint(finalDestination, WeakWaypoint.class);
List<Path> shortestPath = waypointModel.getShortestPath(
closestWaypointToCurrentPosition, closestWaypointToDestination);
List<Waypoint> waypointList = buildWaypointList(
closestWaypointToCurrentPosition, shortestPath);
dstPaths.put(comp, waypointList);
currentPath.put(comp, Integer.valueOf(0));
}
/**
* Build a list of waypoints that starts a the given starting waypoint based
* on the given list of paths.
*
* @param start
* @param shortestPath
* @return
*/
protected List<Waypoint> buildWaypointList(Waypoint start,
List<Path> shortestPath) {
List<Waypoint> waypointList = new ArrayList<Waypoint>();
Waypoint lastWaypoint = start;
waypointList.add(start);
for (Path p : shortestPath) {
lastWaypoint = p.getOtherEnd(lastWaypoint);
waypointList.add(lastWaypoint);
}
return waypointList;
}
/**
* Checks if the current destination waypoint has been reached by testing
* the distance between the current position an the current destination
* waypoint for distance < speedLimit * 2.
*
* FIXME BR: why *2?
*
* @param currentWaypoint
* @param newPosition
* @return
*/
protected boolean destinationWaypointReached(Waypoint currentWaypoint,
PositionVector newPosition, double speed) {
double distance = newPosition
.getDistance(currentWaypoint.getPosition());
return (distance < speed * 2);
}
}
/*
* 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.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
import de.tud.kom.p2psim.api.topology.movement.MovementSupported;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.Path;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.Waypoint;
import de.tud.kom.p2psim.impl.topology.waypoints.graph.WeakWaypoint;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Left;
import de.tud.kom.p2psim.impl.util.Right;
/**
* This movement strategy uses the getShortestPath method implemented by the
* waypoint model and moves along path given by this method.
*
* @author Fabio Zöllner
* @version 1.0, 10.04.2012
*/
public class ShortestPathWaypointMovement extends AbstractLocalMovementStrategy {
// Contains the shortest path and the currently used path
protected final WeakHashMap<MovementSupported, Integer> currentPath = new WeakHashMap<MovementSupported, Integer>();
protected final WeakHashMap<MovementSupported, List<Waypoint>> dstPaths = new WeakHashMap<MovementSupported, List<Waypoint>>();
// Used to check if the destination was altered by the waypoint movement
// model
protected WeakHashMap<MovementSupported, PositionVector> currentDestination = new WeakHashMap<MovementSupported, PositionVector>();
/**
* Calculates the next position of the given movement supported component by
* using the shortest path to the waypoint closest to the destination.
*/
@Override
public Either<PositionVector, Boolean> nextPosition(MovementSupported comp,
PositionVector destination) {
if (currentDestination.get(comp) == null
|| !currentDestination.get(comp).equals(destination)) {
currentDestination.put(comp, destination);
calculateNextMovementPath(comp, destination);
// If the list of the shortest path is empty the destination is the
// same
// as the current position. Thus tell the abstract waypoint model
// that we
// reached the destination.
if (dstPaths.get(comp).size() == 0) {
return new Right<PositionVector, Boolean>(true);
}
}
int currentPathIdx = currentPath.get(comp);
Waypoint currentWaypoint = dstPaths.get(comp).get(currentPathIdx);
double speed = getMovementSpeed(comp);
PositionVector newPosition = comp.getRealPosition().moveStep(
currentWaypoint.getPosition(), speed);
if (destinationWaypointReached(currentWaypoint, newPosition, speed)) {
// We reached the next waypoint on the path to the destination
// move to the next waypoint
currentPath.put(comp, ++currentPathIdx);
// The destination waypoint has been reached, tell the abstract
// waypoint model
if (dstPaths.get(comp).size() <= currentPathIdx) {
currentPath.put(comp, --currentPathIdx);
return new Right<PositionVector, Boolean>(true);
}
}
return new Left<PositionVector, Boolean>(newPosition);
}
/**
* Finds the closest waypoints to the current position of the movement
* supported component as well as the final destination and searches for a
* path between the two waypoints using the underlying network of
* WeakWaypoints.
*
* @param comp
* @param finalDestination
*/
protected void calculateNextMovementPath(MovementSupported comp,
PositionVector finalDestination) {
// Required for shortest path calculation
Waypoint closestWaypointToCurrentPosition = waypointModel
.getClosestWaypoint(comp.getRealPosition(), WeakWaypoint.class);
Waypoint closestWaypointToDestination = waypointModel
.getClosestWaypoint(finalDestination, WeakWaypoint.class);
List<Path> shortestPath = waypointModel.getShortestPath(
closestWaypointToCurrentPosition, closestWaypointToDestination);
List<Waypoint> waypointList = buildWaypointList(
closestWaypointToCurrentPosition, shortestPath);
dstPaths.put(comp, waypointList);
currentPath.put(comp, Integer.valueOf(0));
}
/**
* Build a list of waypoints that starts a the given starting waypoint based
* on the given list of paths.
*
* @param start
* @param shortestPath
* @return
*/
protected List<Waypoint> buildWaypointList(Waypoint start,
List<Path> shortestPath) {
List<Waypoint> waypointList = new ArrayList<Waypoint>();
Waypoint lastWaypoint = start;
waypointList.add(start);
for (Path p : shortestPath) {
lastWaypoint = p.getOtherEnd(lastWaypoint);
waypointList.add(lastWaypoint);
}
return waypointList;
}
/**
* Checks if the current destination waypoint has been reached by testing
* the distance between the current position an the current destination
* waypoint for distance < speedLimit * 2.
*
* FIXME BR: why *2?
*
* @param currentWaypoint
* @param newPosition
* @return
*/
protected boolean destinationWaypointReached(Waypoint currentWaypoint,
PositionVector newPosition, double speed) {
double distance = newPosition.distanceTo(currentWaypoint.getPosition());
return (distance < speed * 2);
}
}
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