Commit eff5d429 authored by Julian Zobel's avatar Julian Zobel 🦄
Browse files

Merge branch 'master' into 'cherry-pick-7698d9d7'

# Conflicts:
#   src/de/tud/kom/p2psim/impl/analyzer/metric/output/MetricOutputDAO.java
#   src/de/tud/kom/p2psim/impl/util/db/dao/DAO.java
parents 1c7f20ec 37020b44
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
public interface ISocialGroupMovementAnalyzer extends IAttractionBasedMovementAnalyzer {
public void onGroupForming(SocialMovementGroup group, IAttractionPoint currentDestination, IAttractionPoint targetDestination);
public void onGroupDisbanding(SocialMovementGroup group);
public void onGroupMerge(SocialMovementGroup group1, SocialMovementGroup group2);
public void onGroupWait(SocialMovementGroup group);
public void onGroupMovesToAttractionPoint(SocialMovementGroup group);
public void onGroupArriveAtAttractionPoint(SocialMovementGroup group);
public void onMoveToMeetingPoint(SocialMovementGroup group, SimLocationActuator node);
public void onMemberWaitAtMeetingPoint(SocialMovementGroup group, SimLocationActuator node);
public void onGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2);
}
......@@ -35,34 +35,38 @@ import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.api.topology.placement.PlacementModel;
import de.tud.kom.p2psim.impl.simengine.Simulator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.DefaultTopology;
import de.tud.kom.p2psim.impl.topology.TopologyFactory;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.AttractionPointViz;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionProvider;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.MobileAttractionPoint;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.mapvisualization.IMapVisualization;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy.AttractionAssignmentListener;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy.AttractionAssignmentListener;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.util.Either;
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.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
/**
* Modular Movement Model uses different models/strategies to create a movement
* model. In this implementation, it has 3 different models/strategies.
* <p>
* M0: AttractionGenerator -> Generates the {@link AttractionPoint}s and place
* them on the map. The {@link AttractionPoint}s can't be moved, because they
* M0: AttractionGenerator -> Generates the {@link IAttractionPoint}s and place
* them on the map. The {@link IAttractionPoint}s can't be moved, because they
* are static POIs from real-world data!
* <p>
* M1: A general {@link MovementModel} is not used, because we use static
* attraction points.
* <p>
* M2: The {@link ITransitionStrategy}! It takes the Hosts, which should be moved
* around, but calculates only the assignment to the {@link AttractionPoint}s.
* M2: The {@link IAttractionAssigmentStrategy}! It takes the Hosts, which should be moved
* around, but calculates only the assignment to the {@link IAttractionPoint}s.
* It doesn't move the Hosts! It will be only assignment a new AttractionPoint!
*
* <p>
......@@ -79,7 +83,7 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
* the AttractionPoints will be handled by the movement model in M1! <br>
* Further it contains an offset for every Host, which will be added to the
* destination point (AttractionPoint), so that not all hosts, which are
* assigned to one {@link AttractionPoint}, lies on the same point.<br>
* assigned to one {@link IAttractionPoint}, lies on the same point.<br>
*
* CHANGELOG
*
......@@ -93,43 +97,50 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
*/
public class ModularMovementModel implements MovementModel, EventHandler, AttractionAssignmentListener {
private final int EVENT_MOVE = 1;
protected final int EVENT_MOVE = 1;
private final int EVENT_INIT = 2;
protected final int EVENT_INIT = 2;
protected PositionVector worldDimensions;
protected ITransitionStrategy transition;
protected IAttractionAssigmentStrategy attractionAssigment;
protected IAttractionGenerator attractionGenerator;
protected IAttractionProvider attractionProvider;
protected LocalMovementStrategy localMovementStrategy;
protected IMapVisualization mapVisualization;
private ModularMovementModelViz modelVisualisation;
protected ModularMovementModelViz modelVisualisation;
protected Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>();
protected AttractionPointViz attractionPointViz;
private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>();
protected LinkedHashSet<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>();
private Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
protected LinkedHashMap<SimLocationActuator, PositionVector> currentTargets = new LinkedHashMap<>();
private boolean initialized = false;
protected LinkedHashMap<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
private long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
protected boolean initialized = false;
private Random rand;
protected long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
protected Random rand = Randoms.getRandom(ModularMovementModel.class);
protected boolean placeNodesAtAP = false;
public ModularMovementModel() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
this.rand = Randoms.getRandom(ModularMovementModel.class);
// scheduling initalization!
Event.scheduleImmediately(this, null, EVENT_INIT);
}
public void setPlaceNodes(boolean placeNodes) {
this.placeNodesAtAP = placeNodes;
}
/**
* This Method will be not called from the Components. So we call this
* manually!
......@@ -137,6 +148,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
public void initialize() {
if (!initialized) {
if (modelVisualisation == null) {
modelVisualisation = new ModularMovementModelViz(this);
}
......@@ -144,6 +156,10 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
if (mapVisualization != null) {
VisualizationInjector.injectComponent(mapVisualization);
}
if (attractionPointViz != null) {
System.out.println("insert AP viz");
VisualizationInjector.injectComponent(attractionPointViz);
}
checkConfiguration();
......@@ -159,15 +175,20 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
localMovementStrategy
.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
List<AttractionPoint> attractionPoints = attractionGenerator
.getAttractionPoints();
transition.setAttractionPoints(attractionPoints);
transition.addAttractionAssignmentListener(this);
attractionAssigment.addAttractionAssignmentListener(this);
attractionAssigment.setAttractionProvider(attractionProvider);
// This adds the mobile hosts (smartphones/users) to the transition
// strategy
for (SimLocationActuator ms : moveableHosts) {
transition.addComponent(ms);
attractionAssigment.addComponent(ms);
if(placeNodesAtAP) {
IAttractionPoint assignment = attractionAssigment.getAssignment(ms);
ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment),
(assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0)));
attractionAssigment.updateTargetAttractionPoint(ms, assignment);
}
}
setTimeBetweenMoveOperations(timeBetweenMoveOperation);
......@@ -176,6 +197,12 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
move();
initialized = true;
// Inform analyzer of resolved movement
if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) {
Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAllNodeInitializationCompleted(moveableHosts);
}
}
}
......@@ -189,34 +216,19 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
}
@Override
public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) {
transition.updateTargetAttractionPoint(actuator, ap);
}
@Override
public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
return transition.getAssignment(actuator);
}
@Override
public Set<AttractionPoint> getAllAttractionPoints()
throws UnsupportedOperationException {
return transition.getAllAttractionPoints();
public void changeTargetLocation(SimLocationActuator actuator, IAttractionPoint ap) {
attractionAssigment.updateTargetAttractionPoint(actuator, ap);
}
private void checkConfiguration() {
protected void checkConfiguration() {
if (localMovementStrategy == null) {
throw new ConfigurationException(
"LocalMovementStrategy is missing in ModularMovementModel!");
}
if (transition == null) {
if (attractionAssigment == null) {
throw new ConfigurationException(
"TransitionStrategy is missing in ModularMovementModel!");
}
if (attractionGenerator == null) {
throw new ConfigurationException(
"AttractionGenerator is missing in ModularMovementModel!");
}
}
@Override
......@@ -227,23 +239,10 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
}
}
public Set<SimLocationActuator> getAllLocationActuators() {
return moveableHosts;
}
@Override
public void setTimeBetweenMoveOperations(long time) {
if (time > 0) {
this.timeBetweenMoveOperation = time;
} else {
throw new ConfigurationException(
"time is negative for the Move Operations");
}
}
@Override
public void updatedAttractionAssignment(SimLocationActuator component,
AttractionPoint newAssignment) {
IAttractionPoint newAssignment) {
/*
* Use this method to calculate the offset and target location for a
* host.
......@@ -253,24 +252,13 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
/*
* Even if an AP does not have a radius, we slightly offset
*/
double apRadius = Math.max(newAssignment.getRadius(), 25.0);
double apRadius = (newAssignment.hasRadius() ? Math.max(newAssignment.getRadius(), 25.0) : 25.0);
int tries = 0;
do {
destination = new PositionVector(attractionCenter);
// Gaussian with std = 1 --> >99% of nodes
PositionVector offset = new PositionVector(
rand.nextGaussian() * apRadius / 3,
rand.nextGaussian() * apRadius / 3);
destination.add(offset);
destination = addOffset(attractionCenter, apRadius);
// Check constraints
if (destination.getX() < 0.0
|| destination.getX() > Binder
.getComponentOrNull(Topology.class)
.getWorldDimensions().getX() || destination.getY() < 0.0
|| destination.getY() > Binder
.getComponentOrNull(Topology.class)
.getWorldDimensions().getY()) {
if (!checkBoundaries(destination)) {
destination = null;
if (tries > 100) {
throw new AssertionError("Unable to find a valid target destination within <100 tries.");
......@@ -279,18 +267,54 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
tries++;
} while (destination == null);
currentTarget.put(component, destination);
currentTargets.put(component, destination);
}
protected void move() {
for (SimLocationActuator component : moveableHosts) {
assert currentTarget.containsKey(component);
doLocalMovement(component, currentTarget.get(component));
assert currentTargets.containsKey(component);
doLocalMovement(component, currentTargets.get(component));
}
for (IAttractionPoint aps : getAttractionPoints()) {
if(aps instanceof MobileAttractionPoint) {
((MobileAttractionPoint) aps).move();
}
}
Event.scheduleWithDelay(timeBetweenMoveOperation, this, null,
EVENT_MOVE);
}
/**
* Add a random gaussian offset to the given position. The offset will be within the given radius
* around the given position with a standard deviation of a third of the radius. Thus, the returned
* positions are more clustered around the position center.
*
* @param position
* @param radius
* @return
*/
public PositionVector addOffset(PositionVector position, double radius) {
/*
* This function will use a gaussian offset from the center. Most values are therefore more clustered around the position,
* only a few on the outskirts of the circle.
*
* For a uniform distribution, see for example https://stackoverflow.com/a/50746409
*/
PositionVector offsetPosition = new PositionVector(position);
double rad = Math.min(rand.nextGaussian() * radius / 3, radius);
double angle = rand.nextDouble() * 2 * Math.PI;
PositionVector offset = new PositionVector(rad * Math.cos(angle), rad * Math.sin(angle));
offsetPosition.add(offset);
return offsetPosition;
}
/**
*
* Ask the local movement strategy for the next position. It may return the
......@@ -300,41 +324,85 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
* @param ms
* @param destination
*/
protected void doLocalMovement(SimLocationActuator ms,
PositionVector destination) {
protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) {
Either<PositionVector, Boolean> either = localMovementStrategy.nextPosition(ms, destination);
Either<PositionVector, Boolean> either = localMovementStrategy
.nextPosition(ms, destination);
if (either.hasLeft()) {
ms.updateCurrentLocation(either.getLeft());
if(!checkBoundaries(ms.getRealPosition())) {
System.err.println("Modular Movement Model: Host moved outside of simulated area!");
}
}
else {
attractionAssigment.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
}
}
/*
* Check for negative or out of bound coordinates!
* =====================================================================================================
* === HELPER FUNCTIONS
* =====================================================================================================
*/
assert ms.getRealPosition().getX() >= 0.0
&& ms.getRealPosition().getX() <= Binder
.getComponentOrNull(Topology.class)
.getWorldDimensions().getX();
assert ms.getRealPosition().getY() >= 0.0
&& ms.getRealPosition().getY() <= Binder
.getComponentOrNull(Topology.class)
.getWorldDimensions().getY();
/**
* Notifies the user if a hosts position lies outside of the specified world size.
* Enable asserts to get the notification
*
*/
public boolean checkBoundaries(PositionVector position) {
return DefaultTopology.isWithinWorldBoundaries(position);
}
@Override
public void eventOccurred(Object content, int type) {
if (type == EVENT_INIT) {
initialize();
} else if (type == EVENT_MOVE) {
move();
}
}
/*
* =====================================================================================================
* === GETTER AND SETTER FUNCTIONS
* =====================================================================================================
*/
public LinkedHashSet<SimLocationActuator> getAllLocationActuators() {
return moveableHosts;
}
@Override
public void setTimeBetweenMoveOperations(long time) {
if (time > 0) {
this.timeBetweenMoveOperation = time;
} else {
transition.reachedAttractionPoint(ms);
throw new ConfigurationException(
"time is negative for the Move Operations");
}
}
public void setIAttractionGenerator(
IAttractionGenerator attractionGenerator) {
this.attractionGenerator = attractionGenerator;
public void setIAttractionProvider(IAttractionProvider attractionProvider) {
if (attractionProvider == null) {
throw new ConfigurationException(
"AttractionProvider is missing in ModularMovementModel!");
}
this.attractionProvider = attractionProvider;
}
public void setLocalMovementStrategy(
LocalMovementStrategy localMovementStrategy) {
public void setLocalMovementStrategy(LocalMovementStrategy localMovementStrategy) {
if (localMovementStrategy == null) {
throw new ConfigurationException(
"LocalMovementStrategy is missing in ModularMovementModel!");
}
this.localMovementStrategy = localMovementStrategy;
}
public void setITransitionStrategy(ITransitionStrategy transition) {
this.transition = transition;
public void setITransitionStrategy(IAttractionAssigmentStrategy transition) {
if (transition == null) {
throw new ConfigurationException(
"TransitionStrategy is missing in ModularMovementModel!");
}
this.attractionAssigment = transition;
}
public void setIMapVisualization(IMapVisualization mapVisualization) {
......@@ -348,12 +416,8 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
}
@Override
public void eventOccurred(Object content, int type) {
if (type == EVENT_INIT) {
initialize();
} else if (type == EVENT_MOVE) {
move();
}
public IAttractionPoint getTargetLocation(SimLocationActuator actuator) {
return attractionAssigment.getAssignment(actuator);
}
/**
......@@ -361,7 +425,11 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
*
* @return
*/
public List<AttractionPoint> getAttractionPoints() {
return new Vector<AttractionPoint>(transition.getAllAttractionPoints());
public List<IAttractionPoint> getAttractionPoints() {
return new Vector<IAttractionPoint>(attractionProvider.getAttractionPoints());
}
public void setAttractionPointViz(AttractionPointViz viz) {
this.attractionPointViz = viz;
}
}
......@@ -20,27 +20,31 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Point2D;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.graphhopper.util.PointList;
import com.graphhopper.util.shapes.GHPoint3D;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.local.AbstractLocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionProvider;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent;
......@@ -49,7 +53,7 @@ import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Oracle;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.route.Route.RouteSegment;
......@@ -70,7 +74,7 @@ public class ModularMovementModelViz extends JComponent
protected boolean showAttractionPoints = true;
protected boolean showNodePositions = true;
protected boolean showNodePositions = false;
protected boolean showTrajectories = false;
......@@ -80,9 +84,9 @@ public class ModularMovementModelViz extends JComponent
private Map<Long, TrajectoryVis> trajectoryVisualizations = new LinkedHashMap<>();
private final static int NODE_PAD = 2;
private final static int NODE_SIZE = 2;
private final static int ATTR_PAD = 5;
private final static int ATTR_SIZE = 5;
private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D");
......@@ -156,6 +160,8 @@ public class ModularMovementModelViz extends JComponent
return checkBox;
}
public static LinkedList<PointList> paths = new LinkedList<PointList>();
@Override
public void paint(Graphics g) {
super.paintComponent(g);
......@@ -179,6 +185,33 @@ public class ModularMovementModelViz extends JComponent
tVis.drawTrajectory(g2);
}
}
// g2.setColor(Color.black);
// PositionVector p1 = GPSCalculation.transformGPSWindowToOwnWorld(51.813680,8.783510);
// PositionVector p2 = GPSCalculation.transformGPSWindowToOwnWorld(51.806795,8.804239);
//
// g2.fillRect(VisualizationInjector.scaleValue(p1.getX()), VisualizationInjector.scaleValue(p1.getX()),
// VisualizationInjector.scaleValue(p2.getX()) - VisualizationInjector.scaleValue(p1.getX()),
// VisualizationInjector.scaleValue(p2.getY())- VisualizationInjector.scaleValue(p1.getY()));
//
// p1 = GPSCalculation.transformGPSWindowToOwnWorld(51.821036,8.771151);
// p2 = GPSCalculation.transformGPSWindowToOwnWorld(51.814987, 8.779090);
//
// g2.fillRect(VisualizationInjector.scaleValue(p1.getX()), VisualizationInjector.scaleValue(p1.getX()),
// VisualizationInjector.scaleValue(p2.getX() - p1.getX()),
// VisualizationInjector.scaleValue(p2.getY() - p1.getY()));
//
// for (PointList pointList : paths) {
// for (GHPoint3D temp : pointList) {
// PositionVector p = RealWorldStreetsMovement.transformGPSWindowToOwnWorld(temp.getLat(), temp.getLon());
//
// g2.fillOval(VisualizationInjector.scaleValue(p.getX()) - 2, VisualizationInjector.scaleValue(p.getY()) - 2, 4,4 );
// }
// }
}
@Override
......@@ -230,21 +263,21 @@ public class ModularMovementModelViz extends JComponent
lastLoc = loc;
g2.drawString(segment.getSegmentId(),
VisualizationInjector
.scaleValue(lastLoc.getLongitude()),
.scaleValue(lastLoc.getLongitudeOrX()),
VisualizationInjector
.scaleValue(lastLoc.getLatitude()));
.scaleValue(lastLoc.getLatitudeOrY()));
continue;
}
g2.setStroke(new BasicStroke(3.0f));
g2.drawLine(
VisualizationInjector
.scaleValue(lastLoc.getLongitude()),
.scaleValue(lastLoc.getLongitudeOrX()),
VisualizationInjector
.scaleValue(lastLoc.getLatitude()),
.scaleValue(lastLoc.getLatitudeOrY()),
VisualizationInjector
.scaleValue(loc.getLongitude()),
.scaleValue(loc.getLongitudeOrX()),
VisualizationInjector
.scaleValue(loc.getLatitude()));
.scaleValue(loc.getLatitudeOrY()));
lastLoc = loc;
}
}
......@@ -269,27 +302,30 @@ public class ModularMovementModelViz extends JComponent
*/
protected void drawAttractionPoints(Graphics2D g2)
{
for (AttractionPoint aPoint : movementModel.getAttractionPoints()) {
Composite gc = g2.getComposite();
for (IAttractionPoint aPoint : movementModel.getAttractionPoints()) {
Point point = ((PositionVector) aPoint).asPoint();
// draw border
g2.setColor(Color.BLACK);
g2.setFont(VisualizationTopologyView.FONT_MEDIUM);
g2.drawString(aPoint.getName(),
VisualizationInjector.scaleValue(point.x) - ATTR_PAD,
VisualizationInjector.scaleValue(point.y) - ATTR_PAD);
VisualizationInjector.scaleValue(point.x) - g2.getFontMetrics().stringWidth(aPoint.getName()) / 2,
VisualizationInjector.scaleValue(point.y - aPoint.getRadius() - 5) - ATTR_SIZE);
// g2.setColor(COLOR_ATTR_POINT);
// float alpha = 0.25f + (float) (aPoint.getWeight() / 2);
// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
// g2.fillOval(
// VisualizationInjector.scaleValue(point.x) - ATTR_PAD,
// VisualizationInjector.scaleValue(point.y) - ATTR_PAD,
// ATTR_PAD * 2 + 1, ATTR_PAD * 2 + 1);
g2.setColor(COLOR_ATTR_POINT);
float alpha = 0.25f + (float) (aPoint.getWeight() / 2);
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
g2.fillOval(
VisualizationInjector.scaleValue(point.x) - ATTR_PAD,
VisualizationInjector.scaleValue(point.y) - ATTR_PAD,
ATTR_PAD * 2 + 1, ATTR_PAD * 2 + 1);
g2.setColor(COLOR_ATTR_POINT);
int radius = VisualizationInjector.scaleValue(aPoint.getRadius()) + ATTR_PAD;
int radius = VisualizationInjector.scaleValue(aPoint.getRadius()) + ATTR_SIZE;
g2.drawOval(VisualizationInjector.scaleValue(point.x) - radius,
VisualizationInjector.scaleValue(point.y) - radius,
radius * 2 + 1, radius * 2 + 1);
g2.setComposite(gc);
}
}
......@@ -303,10 +339,11 @@ public class ModularMovementModelViz extends JComponent
protected void drawNodePosition(Graphics2D g2, SimLocationActuator comp)
{
Point2D pt = comp.getRealPosition().asPoint();
g2.setColor(Color.GRAY);
g2.fillOval(VisualizationInjector.scaleValue(pt.getX()) - NODE_PAD,
VisualizationInjector.scaleValue(pt.getY()) - NODE_PAD, NODE_PAD * 2 + 1,
NODE_PAD * 2 + 1);
g2.fillOval(VisualizationInjector.scaleValue(pt.getX()) - NODE_SIZE,
VisualizationInjector.scaleValue(pt.getY()) - NODE_SIZE,
NODE_SIZE * 2, NODE_SIZE * 2);
}
protected void setMovementModel(ModularMovementModel model)
......
......@@ -2,15 +2,15 @@ package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.local.RouteImpl;
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.util.Either;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.NodeDebugMonitor;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
import java.util.HashMap;
import java.util.LinkedList;
......@@ -18,9 +18,9 @@ import java.util.List;
/**
* This class is meant to be used with the RealWorldStreetsMovement
* and allows changes of the movement type and the used {@link ITransitionStrategy} mid-simulation
* and allows changes of the movement type and the used {@link IAttractionAssigmentStrategy} mid-simulation
* on a per-host basis. It acts like the {@link ModularMovementModel}, but each of the {@link SimLocationActuator}s
* can have a different movement type and {@link ITransitionStrategy}. All routes and targets will be
* can have a different movement type and {@link IAttractionAssigmentStrategy}. All routes and targets will be
* calculated accordingly. <BR><BR>
*
* Originally the whole movement system within the simonstrator platform was not intended to be manipulable
......@@ -33,12 +33,12 @@ import java.util.List;
* So, since the movement of a person in real life could not be controlled by anyone but the person itself,
* the access to this class is only provided from the simrunner project since it is responsible for the simulation
* of the "real-life" parts of the simonstrator platform. From within this project you have access to the
* {@link de.tud.kom.p2psim.impl.topology.DefaultTopologyComponent} from where you can access this movement model.
* {@link de.tud.kom.p2psim.impl.topology.component.DefaultTopologyComponent} from where you can access this movement model.
* If you want to use different movement types, all you have to do is
* (besides selecting this model in your config) call the {@link #setMovementType(SimLocationActuator, String)}
* for each of your components.<BR>
*
* The used {@link ITransitionStrategy} can be changed on runtime, too. However, the first
* The used {@link IAttractionAssigmentStrategy} can be changed on runtime, too. However, the first
* TransitionStrategy specified in the config will be used as default, and will be applied if there is
* no further strategy specified for a specific host. To use multiple strategies, add them to your
* config just as the first one. To set a specific strategy for a specific host, call the {@link #setTransitionForComponent(SimLocationActuator, Class)}
......@@ -54,12 +54,12 @@ import java.util.List;
public class ModularMultiTypeMovementModel extends ModularMovementModel
{
private HashMap<SimLocationActuator, String> movementTypes;
private HashMap<SimLocationActuator, ITransitionStrategy> transitions;
private HashMap<Class, ITransitionStrategy> supportedTransitions;
private HashMap<SimLocationActuator, IAttractionAssigmentStrategy> transitions;
private HashMap<Class, IAttractionAssigmentStrategy> supportedTransitions;
private LinkedList<MultiTypeMovementListener> movementListeners = new LinkedList<>();
/**
* Suppresses notifications to {@link de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy.AttractionAssignmentListener}s.
* Suppresses notifications to {@link de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy.AttractionAssignmentListener}s.
*/
private boolean suppressListenerNotify = false;
......@@ -77,9 +77,8 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
super.initialize();
suppressListenerNotify = true;
for(ITransitionStrategy strategy : supportedTransitions.values())
for(IAttractionAssigmentStrategy strategy : supportedTransitions.values())
{
strategy.setAttractionPoints(transition.getAllAttractionPoints());
strategy.addAttractionAssignmentListener(this);
for (SimLocationActuator ms : moveableHosts) {
strategy.addComponent(ms);
......@@ -94,8 +93,12 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
assert localMovementStrategy instanceof RealWorldStreetsMovement: "ModularMultiTypeMovementModel can only be used with RealWorldStreetsMovement!";
Either<PositionVector, Boolean> either;
if(movementTypes.containsKey(ms)) either = ((RealWorldStreetsMovement) localMovementStrategy).nextPosition(ms, destination, movementTypes.get(ms));
else either = localMovementStrategy.nextPosition(ms, destination);
if(movementTypes.containsKey(ms)) {
either = ((RealWorldStreetsMovement) localMovementStrategy).nextPosition(ms, destination, movementTypes.get(ms));
}
else {
either = localMovementStrategy.nextPosition(ms, destination);
}
if (either.hasLeft()) {
ms.updateCurrentLocation(either.getLeft());
......@@ -112,10 +115,10 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
.getWorldDimensions().getY();
} else {
if(transitions.containsKey(ms)) {
transitions.get(ms).reachedAttractionPoint(ms);
transitions.get(ms).reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
}
else {
transition.reachedAttractionPoint(ms);
attractionAssigment.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
}
movementListeners.forEach(l -> l.onTransition(ms));
}
......@@ -147,7 +150,7 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
* @param ms the component
* @return the current transition strategy
*/
public ITransitionStrategy getTransitionForComponent(SimLocationActuator ms)
public IAttractionAssigmentStrategy getTransitionForComponent(SimLocationActuator ms)
{
return transitions.get(ms);
}
......@@ -157,9 +160,9 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
* @param strategy The class of the strategy which should be returned.
* @return The specified strategy
*/
public ITransitionStrategy getTransitionStrategy(Class strategy)
public IAttractionAssigmentStrategy getTransitionStrategy(Class strategy)
{
ITransitionStrategy selectedStrategy = supportedTransitions.get(strategy);
IAttractionAssigmentStrategy selectedStrategy = supportedTransitions.get(strategy);
if(selectedStrategy == null)
{
throw new UnsupportedOperationException(
......@@ -170,7 +173,7 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
}
/**
* Sets the {@link ITransitionStrategy} for the specified {@link SimLocationActuator}. Used strategies
* Sets the {@link IAttractionAssigmentStrategy} for the specified {@link SimLocationActuator}. Used strategies
* need to be registered in the config.
* @param ms The SimLocationActuator
* @param strategy the strategy to use
......@@ -185,9 +188,9 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
* @param ms The SimLocationActuator
* @param newStrategy the new strategy to use
*/
private void changeTransitionStrategy(SimLocationActuator ms, ITransitionStrategy newStrategy)
private void changeTransitionStrategy(SimLocationActuator ms, IAttractionAssigmentStrategy newStrategy)
{
ITransitionStrategy usedStrategy = transitions.containsKey(ms) ? transitions.get(ms) : transition;
IAttractionAssigmentStrategy usedStrategy = transitions.containsKey(ms) ? transitions.get(ms) : attractionAssigment;
newStrategy.updateTargetAttractionPoint(ms, usedStrategy.getAssignment(ms));
transitions.put(ms, newStrategy);
Monitor.log(ModularMultiTypeMovementModel.class, Monitor.Level.DEBUG, String.format("Client %s changed his transition strategy from %s to %s", ms.getHost().getId().toString(), usedStrategy.getClass(), newStrategy.getClass()));
......@@ -210,7 +213,7 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
}
/**
* Sets the default {@link ITransitionStrategy} for the specified {@link SimLocationActuator}.
* Sets the default {@link IAttractionAssigmentStrategy} for the specified {@link SimLocationActuator}.
* @param ms The SimLocationActuator
*/
public void returnToDefaultTransition(SimLocationActuator ms)
......@@ -219,25 +222,25 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
}
@Override
public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) {
public void changeTargetLocation(SimLocationActuator actuator, IAttractionPoint ap) {
if(transitions.containsKey(actuator)) transitions.get(actuator).updateTargetAttractionPoint(actuator, ap);
else transition.updateTargetAttractionPoint(actuator, ap);
else attractionAssigment.updateTargetAttractionPoint(actuator, ap);
}
@Override
public void setITransitionStrategy(ITransitionStrategy transition) {
if(supportedTransitions.size() == 0) this.transition = transition;
public void setITransitionStrategy(IAttractionAssigmentStrategy transition) {
if(supportedTransitions.size() == 0) this.attractionAssigment = transition;
supportedTransitions.put(transition.getClass(), transition);
}
@Override
public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
public IAttractionPoint getTargetLocation(SimLocationActuator actuator) {
if(transitions.containsKey(actuator)) return transitions.get(actuator).getAssignment(actuator);
else return transition.getAssignment(actuator);
else return attractionAssigment.getAssignment(actuator);
}
@Override
public void updatedAttractionAssignment(SimLocationActuator component, AttractionPoint newAssignment) {
public void updatedAttractionAssignment(SimLocationActuator component, IAttractionPoint newAssignment) {
//Notifications of listeners get suppressed in setup phase to prevent multiple assignments of destinations.
if(suppressListenerNotify) return;
super.updatedAttractionAssignment(component, newAssignment);
......
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.api.topology.placement.PlacementModel;
import de.tud.kom.p2psim.impl.simengine.Simulator;
import de.tud.kom.p2psim.impl.topology.DefaultTopology;
import de.tud.kom.p2psim.impl.topology.TopologyFactory;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.mapvisualization.IMapVisualization;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.waypoints.RandomWaypointGenerator;
import de.tud.kom.p2psim.impl.util.Either;
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;
import de.tudarmstadt.maki.simonstrator.api.Time;
public class SimpleMovementModel implements MovementModel, EventHandler {
protected final int EVENT_MOVE = 1;
protected final int EVENT_INIT = 2;
protected PositionVector worldDimensions;
protected LocalMovementStrategy localMovementStrategy;
// TODO more generic approach
protected RandomWaypointGenerator attractionGenerator;
protected IMapVisualization mapVisualization;
protected Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>();
protected Map<SimLocationActuator, PositionVector> currentTargets = new LinkedHashMap<>();
protected Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
protected boolean initialized = false;
protected long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
protected Random rand = Randoms.getRandom(SimpleMovementModel.class);
public SimpleMovementModel() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
this.attractionGenerator = new RandomWaypointGenerator();
// scheduling initalization!
Event.scheduleImmediately(this, null, EVENT_INIT);
}
/**
* This Method will be not called from the Components. So we call this
* manually!
*/
public void initialize() {
if (!initialized) {
if (mapVisualization != null) {
VisualizationInjector.injectComponent(mapVisualization);
}
checkConfiguration();
// setWayPointModel
localMovementStrategy.setObstacleModel(Binder
.getComponentOrNull(Topology.class).getObstacleModel());
localMovementStrategy.setWaypointModel(Binder
.getComponentOrNull(Topology.class).getWaypointModel());
/*
* Scale depending on calculation interval, if interval != 1 Second.
*/
localMovementStrategy
.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
setTimeBetweenMoveOperations(timeBetweenMoveOperation);
for (SimLocationActuator component : moveableHosts) {
updatedTargetAssignment(component, attractionGenerator.getRandomPoint());
}
// initial move
move();
initialized = true;
}
}
/**
* This default implementation relies on {@link PlacementModel}s to be
* configured in the {@link TopologyFactory}
*/
@Override
public void placeComponent(SimLocationActuator actuator) {
// not supported
}
protected void checkConfiguration() {
if (localMovementStrategy == null) {
throw new ConfigurationException(
"LocalMovementStrategy is missing in ModularMovementModel!");
}
if (attractionGenerator == null) {
throw new ConfigurationException(
"AttractionGenerator is missing in ModularMovementModel!");
}
}
@Override
public void addComponent(SimLocationActuator comp) {
moveableHosts.add(comp);
if (!routeSensorComponents.containsKey(comp)) {
routeSensorComponents.put(comp, new RouteSensorComponent(comp));
}
}
public void updatedTargetAssignment(SimLocationActuator component,
PositionVector target) {
currentTargets.put(component, target);
}
protected void move() {
for (SimLocationActuator component : moveableHosts) {
assert currentTargets.containsKey(component);
doLocalMovement(component, currentTargets.get(component));
}
Event.scheduleWithDelay(timeBetweenMoveOperation, this, null,
EVENT_MOVE);
}
/**
*
* 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.
*
* @param ms
* @param destination
*/
protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) {
Either<PositionVector, Boolean> either = localMovementStrategy.nextPosition(ms, destination);
if (either.hasLeft()) {
ms.updateCurrentLocation(either.getLeft());
if(!checkBoundaries(ms.getRealPosition())) {
System.err.println("Modular Movement Model: Host moved outside of simulated area!");
}
}
else {
updatedTargetAssignment(ms, attractionGenerator.getRandomPoint());
}
}
/*
* =====================================================================================================
* === HELPER FUNCTIONS
* =====================================================================================================
*/
/**
* Notifies the user if a hosts position lies outside of the specified world size.
* Enable asserts to get the notification
*
*/
public boolean checkBoundaries(PositionVector position) {
return DefaultTopology.isWithinWorldBoundaries(position);
}
@Override
public void eventOccurred(Object content, int type) {
if (type == EVENT_INIT) {
initialize();
} else if (type == EVENT_MOVE) {
move();
}
}
/*
* =====================================================================================================
* === GETTER AND SETTER FUNCTIONS
* =====================================================================================================
*/
public Set<SimLocationActuator> getAllLocationActuators() {
return moveableHosts;
}
@Override
public void setTimeBetweenMoveOperations(long time) {
if (time > 0) {
this.timeBetweenMoveOperation = time;
} else {
throw new ConfigurationException(
"time is negative for the Move Operations");
}
}
public void setLocalMovementStrategy(LocalMovementStrategy localMovementStrategy) {
if (localMovementStrategy == null) {
throw new ConfigurationException(
"LocalMovementStrategy is missing in ModularMovementModel!");
}
this.localMovementStrategy = localMovementStrategy;
}
public void setIMapVisualization(IMapVisualization mapVisualization) {
this.mapVisualization = mapVisualization;
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.MovementGroupContainer;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupencounter.IGroupEncounterBehavior;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupforming.IGroupFormingBehavior;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
/**
*
* @author Julian Zobel
* @version 1.0, 28.01.2020
*/
public class SocialGroupMovementModel extends ModularMovementModel {
private final double MEETING_POINT_DISTANCE = 5;
private final double LEADER_GROUP_DISTANCE = 10;
protected MovementGroupContainer groupContainer;
protected IGroupFormingBehavior groupFormingBehavior;
protected IGroupEncounterBehavior groupEncounterBehavior;
private LinkedHashSet<SimLocationActuator> singleHosts = new LinkedHashSet<SimLocationActuator>();
private int numberOfSingleHosts;
@Override
public void initialize() {
if (!initialized) {
groupContainer = MovementGroupContainer.getInstance();
groupFormingBehavior.initialize(this);
groupEncounterBehavior.initialize(this);
// Choose single hosts
if(numberOfSingleHosts > 0) {
do {
singleHosts.add(getRandomActuator());
} while(singleHosts.size() < numberOfSingleHosts);
}
if (modelVisualisation == null) {
modelVisualisation = new ModularMovementModelViz(this);
}
VisualizationInjector.injectComponent(modelVisualisation);
if (mapVisualization != null) {
VisualizationInjector.injectComponent(mapVisualization);
}
if (attractionPointViz != null) {
System.out.println("insert AP viz");
VisualizationInjector.injectComponent(attractionPointViz);
}
checkConfiguration();
// setWayPointModel
localMovementStrategy.setObstacleModel(Binder
.getComponentOrNull(Topology.class).getObstacleModel());
localMovementStrategy.setWaypointModel(Binder
.getComponentOrNull(Topology.class).getWaypointModel());
/*
* Scale depending on calculation interval, if interval != 1 Second.
*/
localMovementStrategy
.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
attractionAssigment.addAttractionAssignmentListener(this);
attractionAssigment.setAttractionProvider(attractionProvider);
// This adds the mobile hosts (smartphones/users) to the transition
// strategy
for (SimLocationActuator ms : moveableHosts) {
attractionAssigment.addComponent(ms);
if(placeNodesAtAP) {
IAttractionPoint assignment = attractionAssigment.getAssignment(ms);
ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment),
(assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0)));
attractionAssigment.updateTargetAttractionPoint(ms, assignment);
}
}
setTimeBetweenMoveOperations(timeBetweenMoveOperation);
// Inform analyzer of resolved movement
if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) {
Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAllNodeInitializationCompleted(moveableHosts);
}
// initial move
move();
initialized = true;
}
}
/**
* Returns a random SimLocationActuator component from the set of moveable hosts.
*
* @return SimLocationActuator
*/
private SimLocationActuator getRandomActuator() {
int index = rand.nextInt(moveableHosts.size());
int i = 0;
for(SimLocationActuator actuator : moveableHosts) {
if(i == index) {
return actuator;
}
i++;
}
return null;
}
/**
* The movement model.
* 1) Updates the number of hosts within each attraction point.
* 2) Creates and deletes groups, if necessary.
* 3) Applies encounter action to meeting groups.
* 4) Moves the hosts using doGroupMovement, movement style depends on role of the host (Leader, Participant, Single)
*/
@Override
protected void move() {
// Check POIs if groups can be created. Delete groups, if destination reached.
groupFormingBehavior.manageGroups();
// Checks if groups encounter each other and applies a specified action to these groups.
groupEncounterBehavior.handleEncounters();
/*
* Moves all nodes according to definition in group movement method
*/
for (SimLocationActuator host : moveableHosts) {
assert currentTargets.containsKey(host);
// Single Host Movement
if(singleHosts.contains(host) || !groupContainer.isGroupMember(host)) {
doLocalMovement(host, currentTargets.get(host));
}
else if(groupContainer.isGroupMember(host)){
doGroupMovement(host, currentTargets.get(host));
}
else {
throw new UnsupportedOperationException("SimLocationActuator " + host + " is neither in a group nor a single node");
}
// TODO maybe remodel the group movement to do a whole group?
}
// TODO Move each group
Event.scheduleWithDelay(timeBetweenMoveOperation, this, null, EVENT_MOVE);
}
/**
* Applies movement of the host according to different circumstances:
*
* Towards Destination: Host is not a group member || Group has met at meeting point successfully.
* Towards MeetingPoint: Host if group member and has not reached meeting point yet.
* No movement: Host reached meeting point, but still waits for group members to arrive.
*
* @param SimLocationActuator The host to move.
* @param PositionVector Destination of the host.
*/
protected void doGroupMovement(SimLocationActuator host, PositionVector destination) {
// This host is a member of a group, thus...
SocialMovementGroup group = groupContainer.getGroupOfHost(host);
// if the group is currently gathering at a meeting point...
if(movesToGroupMeetingPoint(host)) {
// if this host has already arrived at the group meeting point..
if(hostIsAtMeetingPoint(host)) {
// ... and if the whole group is also at the meeting point...
if(groupGatheredAtMeetingPoint(group)) {
// remove the meeting point and thus, start moving towards the actual destination
group.setMeetingPoint(null);
}
// ... but the group is not gathered at the meeting point, do nothing and wait for the rest.
else {
// inform analyzer of waiting group members
if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {
Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onMemberWaitAtMeetingPoint(group, host);
}
}
}
// if the host has not reached the group meeting point, move towards it.
else {
PositionVector mp = groupContainer.getGroupOfHost(host).getMeetingPoint();
doLocalMovement(host, mp);
// inform analyzer group member moves to meeting point
if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {
Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onMoveToMeetingPoint(group, host);
}
}
}
// ... but if the group is currently on their way to the destination
else {
// the leader does a local movement
if(groupContainer.isLeader(host)) {
if(!groupContainer.isWaiting(groupContainer.getGroupOfHost(host))) {
// inform analyzer of movement to attraction point
if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {
Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupMovesToAttractionPoint(group);
}
doLocalMovement(host, destination);
PositionVector leaderPos = host.getRealPosition();
LinkedHashSet<SimLocationActuator> groupMembers = groupContainer.getGroupMembers(host);
groupMembers.remove(host); // remove leader
for (SimLocationActuator groupMember : groupMembers) {
// Assign small offset to the host depending on the leaders position.
PositionVector offset = new PositionVector(rand.nextDouble() * LEADER_GROUP_DISTANCE, rand.nextDouble() * LEADER_GROUP_DISTANCE);
PositionVector newPos = leaderPos.plus(offset);
// Update location of host, which will be around the leaders location.
groupMember.updateCurrentLocation(newPos);
}
}
else {
// inform analyzer of waiting group
if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {
Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupWait(group);
}
}
}
}
}
/*
* =====================================================================================================
* === MEETING POINT FUNCTIONS
* =====================================================================================================
*/
/**
* Checks if a host is currently on its way to a meeting point or to its destination.
* Returns true if moving towards meeting point, false else.
*
* @param SimLocationActuator The host to be checked.
* @return Boolean
*/
private boolean movesToGroupMeetingPoint(SimLocationActuator host) {
PositionVector meetingpoint = groupContainer.getGroupOfHost(host).getMeetingPoint();
if(meetingpoint == null)
return false;
else if(meetingpoint != groupContainer.getGroupOfHost(host).getDestination())
return true;
else
return false;
}
/**
* Returns true, if all group members of a host including the host itself reached the meeting point, false else.
*
* @param SimLocationActuator The host to be checked.
* @return Boolean
*/
private boolean groupGatheredAtMeetingPoint(SocialMovementGroup group) {
for(SimLocationActuator participant : group.getMembers()) {
if(!hostIsAtMeetingPoint(participant)) {
return false;
}
}
return true;
}
/**
* Returns true if the host reached its current meeting point, false else.
*
* @param SimLocationActuator The host to be checked.
* @return Boolean
*
*/
private boolean hostIsAtMeetingPoint(SimLocationActuator host) {
PositionVector meetingpoint = groupContainer.getGroupOfHost(host).getMeetingPoint();
if(host.getLastLocation().distanceTo(meetingpoint) <= MEETING_POINT_DISTANCE)
return true;
else
return false;
}
/*
* =====================================================================================================
* === MOVEMENT FUNCTIONS
* =====================================================================================================
*/
/**
* Host position adapts to leaders position by taking the leader position and adding a small offset
*
* @param SimLocationActuator The host to be moved.
*/
private void followLeader(SimLocationActuator host) {
SimLocationActuator leader = groupContainer.getGroupOfHost(host).getLeader();
// Assign small offset to the host depending on the leaders position.
PositionVector leaderPos = leader.getRealPosition();
PositionVector offset = new PositionVector(rand.nextDouble() * LEADER_GROUP_DISTANCE, rand.nextDouble() * LEADER_GROUP_DISTANCE);
PositionVector newPos = leaderPos.plus(offset);
// Update location of host, which will be around the leaders location.
host.updateCurrentLocation(newPos);
}
/*
* =====================================================================================================
* === GETTER AND SETTER FUNCTIONS
* =====================================================================================================
*/
public void setGroupFormingBehavior(IGroupFormingBehavior defaultGroupForming) {
if (defaultGroupForming == null) {
throw new ConfigurationException(
"GroupFormingStrategy is missing in ModularMovementModel!");
}
this.groupFormingBehavior = defaultGroupForming;
}
public void setGroupEncounterBehavior(IGroupEncounterBehavior defaultGroupEncounterBehavior) {
if (defaultGroupEncounterBehavior == null) {
throw new ConfigurationException(
"GroupEncounterStrategy is missing in ModularMovementModel!");
}
this.groupEncounterBehavior = defaultGroupEncounterBehavior;
}
public IAttractionAssigmentStrategy getAttractionAssignmentStrategy() {
return attractionAssigment;
}
public IGroupFormingBehavior getGroupFormingBehavior() {
return groupFormingBehavior;
}
public LocalMovementStrategy getMovementStrategy() {
return localMovementStrategy;
}
public void setNumberOfSingleHosts(int numberOfSingleHosts) {
this.numberOfSingleHosts = numberOfSingleHosts;
}
public LinkedHashSet<SimLocationActuator> getSingleHosts(){
return singleHosts;
}
public LinkedHashMap<SimLocationActuator, PositionVector> getCurrentTargets(){
return currentTargets;
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.util.LinkedList;
import java.util.List;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.util.oracle.GlobalOracle;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
public class AbstractAttractionProvider implements IAttractionProvider {
private LinkedList<AttractionPoint> attractionPoints = new LinkedList<>();
protected PositionVector worldDimension;
public AbstractAttractionProvider() {
this.worldDimension = Binder.getComponentOrNull(Topology.class).getWorldDimensions();
}
public LinkedList<AttractionPoint> getAttractionPoints() {
return new LinkedList<AttractionPoint>(attractionPoints);
}
protected void clearAttractionPoints() {
attractionPoints.clear();
}
protected boolean hasAttractionPoint(AttractionPoint ap) {
return attractionPoints.contains(ap);
}
/**
* Remove an {@link IAttractionPoint} from the list
* @param ap
*/
public void removeAttractionPoint(AttractionPoint ap) {
if(Monitor.hasAnalyzer(AttractionPointMonitor.class)) {
Monitor.getOrNull(AttractionPointMonitor.class).removedAttractionPoint(ap);
}
GlobalOracle.removeAttractionPoint(ap);
attractionPoints.remove(ap);
}
/**
* Add an {@link IAttractionPoint} to the list
* @param ap
*/
public void addAttractionPoint(AttractionPoint ap) {
if(ap == null) {
Monitor.log(IAttractionProvider.class, Level.ERROR, "IAttractionGenerator: Tried to add NULL as Attraction Point");
return;
}
if(Monitor.hasAnalyzer(AttractionPointMonitor.class)) {
Monitor.getOrNull(AttractionPointMonitor.class).addedAttractionPoint(ap);
}
GlobalOracle.addAttractionPoint(ap);
attractionPoints.add(ap);
}
}
......@@ -21,46 +21,105 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.IAttractionBasedMovementAnalyzer;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* In the current implementation, {@link AttractionPoint}s cannot move anymore.
* In the current implementation, {@link IAttractionPoint}s cannot move anymore.
* We hold a static list of attraction points to ensure that there exists only
* one instance of each name at a time.
*
* @author Christoph Muenker, Bjoern Richerzhagen
* @author Christoph Muenker, Bjoern Richerzhagen, Julian Zobel
* @version 1.0, 02.07.2013
* @version 1.1, 26.10.2018 - since the class was very similar to {@link BasicAttractionPoint}, made this class an extension
* @version 1.2, 24.01.2020 - added pause time interval, weight, and radius exclusively to this class, because {@link BasicAttractionPoint} should be just a named point.
*/
public class AttractionPointImpl extends PositionVector
implements AttractionPoint {
public class AttractionPoint extends BasicAttractionPoint {
protected static LinkedHashMap<String, AttractionPoint> instances = new LinkedHashMap<>();
protected long pauseTimeMin = -1;
protected long pauseTimeMax = -1;
protected double weight = 0;
protected double radius = 0;
protected double area = 1;
@XMLConfigurableConstructor({ "name", "x", "y" })
public AttractionPoint(String name, double x, double y) {
this(name, new PositionVector(x, y));
}
protected static Random rnd = Randoms.getRandom(AttractionPoint.class);
public AttractionPoint(String name, PositionVector posVec) {
super(name, posVec);
private static Map<String, AttractionPointImpl> instances = new LinkedHashMap<>();
if (instances.containsKey(name)) {
throw new AssertionError("Name "+name+" already in use for an attraction point.");
}
instances.put(name, this);
private String name;
if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) {
Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAttractionPointAdded(this);
}
}
private double weight = 0;
public AttractionPoint(String name, PositionVector posVec, double weight, double radius, long pauseTimeMin, long pauseTimeMax) {
this(name, posVec);
private double radius = 0;
assert weight >= 0 && weight <= 1.0;
assert radius >= 0;
public AttractionPointImpl(String name, PositionVector posVec) {
super(posVec);
this.name = name;
if (instances.containsKey(name)) {
throw new AssertionError("Name "+name+" already in use for an attraction point.");
this.weight = weight;
this.radius = radius;
this.setPauseTime(pauseTimeMin, pauseTimeMax);
if(radius > 0) {
this.area = Math.PI * Math.pow(radius, 2);
}
instances.put(name, this);
}
@Override
public String getName() {
return name;
public IAttractionPoint clone(String newName) {
return new AttractionPoint(name, this, weight, radius, pauseTimeMin, pauseTimeMax);
}
@Override
public int getTransmissionSize() {
return super.getTransmissionSize() + name.length() + Double.BYTES * 2;
}
@Override
public int hashCode() {
final int prime = 31;
int result = prime * ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if(obj == null)
return false;
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
AttractionPoint other = (AttractionPoint) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name)) {
return false;
} else if(weight != other.weight) {
return false;
} else if(radius != other.radius) {
return false;
} else if(pauseTimeMin != other.pauseTimeMin) {
return false;
} else if(pauseTimeMax != other.pauseTimeMax) {
return false;
}
return true;
}
@Override
......@@ -81,38 +140,56 @@ public class AttractionPointImpl extends PositionVector
@Override
public void setRadius(double radius) {
this.radius = radius;
if(radius > 0) {
this.area = Math.PI * Math.pow(radius, 2);
}
}
@Override
public AttractionPoint clone(String newName) {
return new AttractionPointImpl(name, this);
public long getPauseTimeMin() {
return pauseTimeMin;
}
@Override
public int getTransmissionSize() {
return super.getTransmissionSize() + name.length() + Double.BYTES * 2;
public long getPauseTimeMax() {
return pauseTimeMax;
}
@Override
public int hashCode() {
final int prime = 31;
int result = prime * ((name == null) ? 0 : name.hashCode());
return result;
public void setPauseTime(long pauseTimeMin, long pauseTimeMax) {
assert pauseTimeMin >= 0 && pauseTimeMax >= 0;
assert pauseTimeMax >= pauseTimeMin;
this.pauseTimeMin = pauseTimeMin;
this.pauseTimeMax = pauseTimeMax;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
public boolean hasPauseTime() {
if(pauseTimeMax >= 0 || pauseTimeMin >= 0) {
return true;
if (getClass() != obj.getClass())
return false;
AttractionPointImpl other = (AttractionPointImpl) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
}
else
return false;
}
@Override
public boolean hasWeight() {
return true;
}
@Override
public boolean hasRadius() {
return true;
}
@Override
public String toString() {
return getName() + " (" + getX() + ", " + getY() + ")" + " <" + getRadius() + "> ";
}
public double getArea() {
return area;
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import de.tudarmstadt.maki.simonstrator.api.component.core.MonitorComponent.Analyzer;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
public interface AttractionPointMonitor extends Analyzer {
public void addedAttractionPoint(IAttractionPoint ap);
public void removedAttractionPoint(IAttractionPoint ap);
}
/*
* Copyright (c) 2005-2015 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.util.LinkedList;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import de.tud.kom.p2psim.api.common.SimHost;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.topology.views.visualization.ui.VisualizationComponent;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
public class AttractionPointViz extends JComponent
implements VisualizationComponent {
protected boolean showAttractionPoints = true;
private JMenu menu;
private final static int ATTR_SIZE = 5;
private static Color COLOR_ATTR_POINT = Color.decode("#4A7B9D");
public static LinkedList<LinkedList<SimHost>> clusters = new LinkedList<LinkedList<SimHost>>();
public static LinkedList<Color> colors = new LinkedList<Color>();
public LinkedList<IAttractionPoint> aps;
public AttractionPointViz() {
init();
}
public void setAttractionPoints(LinkedList<IAttractionPoint> aps) {
this.aps = aps;
}
protected void init() {
setBounds(0, 0, VisualizationInjector.getWorldX(),
VisualizationInjector.getWorldY());
setOpaque(true);
setVisible(true);
menu = new JMenu("Attraction Points");
menu.add(createCheckboxAp());
}
private JCheckBoxMenuItem createCheckboxAp() {
final JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(
"show attraction points", showAttractionPoints);
checkBox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
showAttractionPoints = checkBox.isSelected();
VisualizationInjector.invalidate();
}
});
return checkBox;
}
@Override
public void paint(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
if (showAttractionPoints) {
drawAttractionPoints(g2);
}
if(true) {
drawClusters(g2);
}
}
/**
* Provides access super.paintComponent() for extending classes.
* @param g the Graphics object for painting.
*/
protected void paintSuper(Graphics g)
{
super.paintComponent(g);
}
protected void drawClusters(Graphics2D g2)
{
// Composite gc = g2.getComposite();
if(colors.isEmpty()) {
for( int i = 0; i < 20; i++) {
colors.add(new Color(new java.util.Random().nextInt()));
}
}
for (LinkedList<SimHost> group : clusters) {
g2.setColor(colors.get(clusters.indexOf(group)));
for (SimHost member : group) {
PositionVector p = member.getTopologyComponent().getRealPosition();
g2.fillOval(VisualizationInjector.scaleValue(p.getX()) - 10,
VisualizationInjector.scaleValue(p.getY()) - 10, 20, 20);
}
}
}
/**
* Draws the attraction points. This method has been extracted from paint()
* to make it possible for extending class to override only this bit while leaving everything
* else untouched.
* @param g2 the Graphics2D object for painting.
*/
protected void drawAttractionPoints(Graphics2D g2)
{
if(aps == null || aps.size() == 0) {
return;
}
Composite gc = g2.getComposite();
for (IAttractionPoint aPoint : aps) {
Point point = ((PositionVector) aPoint).asPoint();
// draw border
g2.setColor(Color.BLACK);
g2.setFont(VisualizationTopologyView.FONT_MEDIUM);
g2.drawString(aPoint.getName(),
VisualizationInjector.scaleValue(point.x) - g2.getFontMetrics().stringWidth(aPoint.getName()) / 2,
VisualizationInjector.scaleValue(point.y - aPoint.getRadius() - 5) - ATTR_SIZE);
// g2.setColor(COLOR_ATTR_POINT);
// float alpha = 0.25f + (float) (aPoint.getWeight() / 2);
// g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
// g2.fillOval(
// VisualizationInjector.scaleValue(point.x) - ATTR_PAD,
// VisualizationInjector.scaleValue(point.y) - ATTR_PAD,
// ATTR_PAD * 2 + 1, ATTR_PAD * 2 + 1);
g2.setColor(COLOR_ATTR_POINT);
int radius = VisualizationInjector.scaleValue(aPoint.getRadius()) + ATTR_SIZE;
g2.drawOval(VisualizationInjector.scaleValue(point.x) - radius,
VisualizationInjector.scaleValue(point.y) - radius,
radius * 2 + 1, radius * 2 + 1);
g2.setComposite(gc);
}
}
@Override
public String getDisplayName() {
return "Attraction Points";
}
@Override
public JComponent getComponent() {
return this;
}
@Override
public JMenu getCustomMenu() {
return menu;
}
@Override
public boolean isHidden() {
return false;
}
}
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* A basic attraction point, as simple as it can get. Really just a named location
* without any checks performed.
*/
public class BasicAttractionPoint extends PositionVector implements AttractionPoint
public class BasicAttractionPoint extends PositionVector implements IAttractionPoint
{
private String name;
private double weight = 0;
private double radius = 0;
protected String name;
public BasicAttractionPoint(String name, PositionVector pos)
{
public BasicAttractionPoint(String name, PositionVector pos) {
super(pos);
this.name = name;
}
@XMLConfigurableConstructor({ "name", "x", "y" })
public BasicAttractionPoint(String name, double x, double y) {
this(name, new PositionVector(x, y));
}
@Override
public String getName() {
......@@ -26,27 +28,8 @@ public class BasicAttractionPoint extends PositionVector implements AttractionPo
}
@Override
public double getWeight() {
return weight;
}
@Override
public double getRadius() {
return radius;
}
@Override
public void setWeight(double weight) {
this.weight = weight;
}
@Override
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public AttractionPoint clone(String newName) {
public IAttractionPoint clone(String newName) {
return new BasicAttractionPoint(newName, this);
}
}
......@@ -20,28 +20,16 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.util.LinkedList;
import java.util.List;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
/**
* For simple scenarios: add attraction points by specifying a coordinate.
*
* @author Bjoern Richerzhagen
* @version 1.0, Dec 11, 2015
*/
public class ConfigAttractionGenerator implements IAttractionGenerator {
private final List<AttractionPoint> points = new LinkedList<>();
@Override
public List<AttractionPoint> getAttractionPoints() {
return points;
}
public class ConfigAttractionGenerator extends AbstractAttractionProvider {
public void setAttractionPoint(AttractionPoint point) {
this.points.add(point);
addAttractionPoint(point);
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
/**
* Implementation of the interface {@link AttractionGenerator}.
*
* @author Julian Zobel
* @version 1.0, April 2019
*/
public class ConfigDynamicAttractionGenerator extends AbstractAttractionProvider {
//private LinkedList<TemporalAttractionPoint> temporalAttractionPoints = new LinkedList<>();
public void setAttractionPoint(AttractionPoint ap) {
addAttractionPoint(ap);
}
public void setTemporalAttractionPoint(TemporalAttractionPoint ap) {
//temporalAttractionPoints.add(ap);
if(ap.getPlacementTime() == 0) {
placeAP(ap);
}
else {
Event.scheduleWithDelay(ap.getPlacementTime(), new EventHandler() {
@Override
public void eventOccurred(Object content, int type) {
placeAP(ap);
}
}, null, 0);
}
}
void placeAP(TemporalAttractionPoint ap) {
addAttractionPoint(ap);
Event.scheduleWithDelay(ap.getRemovalTime(), new EventHandler() {
@Override
public void eventOccurred(Object content, int type) {
removeAttractionPoint(ap);
}
}, null, 0);
}
}
......@@ -27,27 +27,25 @@ import java.util.LinkedList;
import java.util.List;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* Generates a given number of {@link AttractionPoint}s and sets the Position
* Generates a given number of {@link IAttractionPoint}s and sets the Position
* according to a given CSV file.
*
* @author Nils Richerzhagen
* @version 1.0, 16.07.2014
*/
public class CsvAttractionGenerator implements IAttractionGenerator {
private PositionVector worldDimensions;
public class CsvAttractionGenerator extends AbstractAttractionProvider {
private String file;
private final String SEP = ";";
private List<AttractionPoint> attractionPoints;
private double radius = 0;
/**
*
......@@ -55,18 +53,22 @@ public class CsvAttractionGenerator implements IAttractionGenerator {
*/
@XMLConfigurableConstructor({ "placementFile" })
public CsvAttractionGenerator(String placementFile) {
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
super();
this.file = placementFile;
readData();
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public List<AttractionPoint> getAttractionPoints() {
if (attractionPoints == null) {
attractionPoints = new LinkedList<>();
public LinkedList<AttractionPoint> getAttractionPoints() {
if (super.getAttractionPoints().isEmpty()) {
readData();
}
return attractionPoints;
return super.getAttractionPoints();
}
private void readData() {
......@@ -86,15 +88,17 @@ public class CsvAttractionGenerator implements IAttractionGenerator {
Double x = Double.parseDouble(parts[0]);
Double y = Double.parseDouble(parts[1]);
if (x > worldDimensions.getX()
|| y > worldDimensions.getY() || x < 0
if (x > worldDimension.getX()
|| y > worldDimension.getY() || x < 0
|| y < 0) {
System.err.println("Skipped entry " + x + ";"
+ y);
continue;
}
attractionPoints.add(new AttractionPointImpl("AP"+i, new PositionVector(x,
y)));
AttractionPoint ap = new AttractionPoint("AP"+i, new PositionVector(x, y));
ap.setRadius(radius);
addAttractionPoint(ap);
i++;
entrySuccessfullyRead = true;
} catch (NumberFormatException e) {
......@@ -104,6 +108,34 @@ public class CsvAttractionGenerator implements IAttractionGenerator {
}
}
}
else if(parts.length == 3) {
try {
Double x = Double.parseDouble(parts[0]);
Double y = Double.parseDouble(parts[1]);
Double r = Double.parseDouble(parts[2]);
if (x > worldDimension.getX()
|| y > worldDimension.getY() || x < 0
|| y < 0) {
System.err.println("Skipped entry " + x + ";"
+ y);
continue;
}
AttractionPoint ap = new AttractionPoint("AP"+i, new PositionVector(x, y));
ap.setRadius(r);
addAttractionPoint(ap);
i++;
entrySuccessfullyRead = true;
} catch (NumberFormatException e) {
// Ignore leading comments
if (entrySuccessfullyRead) {
// System.err.println("CSV ParseError " + line);
}
}
}
} else {
throw new AssertionError("To many columns in CSV.");
}
......
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.util.LinkedList;
import java.util.List;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* Attraction Generator, providing 4 equidistant attraction points, i.e., in a square
*
* @author Julian Zobel
* @version 1.0, Nov 2018
*/
public class EquidistantSquareAttractionGenerator extends AbstractAttractionProvider {
private PositionVector worldDimension;
private double squareSize;
@XMLConfigurableConstructor({ "squareSize" })
public EquidistantSquareAttractionGenerator(double squareSize) {
this.squareSize = squareSize;
createAttractionPoints();
}
@Override
public LinkedList<AttractionPoint> getAttractionPoints() {
if(super.getAttractionPoints().isEmpty())
createAttractionPoints();
return super.getAttractionPoints();
}
private void createAttractionPoints() {
double x = worldDimension.getX() / 2;
double y = worldDimension.getY() / 2;
PositionVector p1 = new PositionVector(x - squareSize, y - squareSize);
this.addAttractionPoint(new AttractionPoint("AP1", p1));
PositionVector p2 = new PositionVector(x - squareSize, y + squareSize);
this.addAttractionPoint(new AttractionPoint("AP2", p2));
PositionVector p3 = new PositionVector(x + squareSize, y - squareSize);
this.addAttractionPoint(new AttractionPoint("AP3", p3));
PositionVector p4 = new PositionVector(x + squareSize, y + squareSize);
this.addAttractionPoint(new AttractionPoint("AP4", p4));
}
}
......@@ -21,18 +21,15 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.util.List;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
/**
* This is the interface for the generator of the {@link AttractionPoint}s. It
* gets the set number of AttractionPoints back. This mean, it will be generate
* them and set the Position of them.
* Interface for {@link IAttractionPoint} generators. Will generate a given amount of attraction points.
*
* @author Christoph Muenker
* @version 1.0, 02.07.2013
* @author Christoph Muenker, Julian Zobel
* @version 1.1, 09 2018
*/
public interface IAttractionGenerator {
public interface IAttractionProvider {
public List<AttractionPoint> getAttractionPoints();
......
......@@ -25,17 +25,12 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.GPSCalculation;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* Generates attraction points out of real data from osm
......@@ -43,51 +38,50 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
*
* @author Martin Hellwig
* @version 1.0, 02.07.2015
*
* Added an upper limit for the number of attraction points. Use 0 to allow all APs in the JSON file.
* @author Julian Zobel
* @version 1.1, November 2018
*
* You now can set an upper limit for the radius.
* @author Julian Zobel
* @version 1.2, January 2019
*
*
*/
public class JSONAttractionGenerator implements IAttractionGenerator {
private PositionVector worldDimensions;
public class JSONAttractionGenerator extends AbstractAttractionProvider {
private List<AttractionPoint> attractionPoints;
protected int numberOfAttractionPoints;
protected String placementJsonFile = "";
private String placementJsonFile;
private double latLeft; //Values from -90 to 90; always smaller than latRight
private double latRight; //Values from -90 to 90
private double lonLeft; //Values from -180 to 180; Always smaller than lonRight
private double lonRight; //Values from -180 to 180
protected double maximumRadius = -1; // Values >= 0, or -1 if radius taken from file
/**
* You have to set a json-file, which has set some POIs
* Sample-query for "bar"-POIs in Darmstadt (Bounding Box from [49.4813, 8.5590] to [49.9088, 8,7736]:
http://overpass-api.de/api/interpreter?data=%5Bout:json%5D;node%5Bamenity=bar%5D%2849%2E4813%2C8%2E5590%2C49%2E9088%2C8%2E7736%29%3Bout%3B
*/
public JSONAttractionGenerator() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
attractionPoints = new LinkedList<AttractionPoint>();
@XMLConfigurableConstructor({"numberOfAttractionPoints", "maximumRadius", "placementJsonFile"})
public JSONAttractionGenerator(int numberOfAttractionPoints, double maximumRadius, String placementJsonFile) {
this.numberOfAttractionPoints = numberOfAttractionPoints;
this.maximumRadius = maximumRadius;
this.placementJsonFile = placementJsonFile;
latLeft = GPSCalculation.getLatLower();
latRight = GPSCalculation.getLatUpper();
lonLeft = GPSCalculation.getLonLeft();
lonRight = GPSCalculation.getLonRight();
createAttractionPoints();
}
/**
* Projects the gps coordinates in the given gps window to the world-coordinates given in world-dimensions
* @param lat
* @param lon
* @return The projected position in world-dimensions
*/
private PositionVector transformGPSWindowToOwnWorld(double lat, double lon) {
double x = worldDimensions.getX() * (lon - lonLeft)/(lonRight - lonLeft);
//Invert the y value, because in Java Swing we start drawing in the upper left corner instead in the lower left one
double y = worldDimensions.getY() - worldDimensions.getY() * (lat - latLeft)/(latRight - latLeft);
return new PositionVector(x, y);
@Override
public LinkedList<AttractionPoint> getAttractionPoints() {
if(super.getAttractionPoints().size() == 0) {
createAttractionPoints();
}
@Override
public List<AttractionPoint> getAttractionPoints() {
if(attractionPoints.size() == 0) {
return super.getAttractionPoints();
}
protected JSONArray getPOIArray() {
assert !placementJsonFile.equals("");
String poiString = "";
JSONArray allPOI = null;
FileInputStream inputStream;
......@@ -104,33 +98,68 @@ public class JSONAttractionGenerator implements IAttractionGenerator {
e.printStackTrace();
}
if(allPOI != null) {
for(int i = 0; i < allPOI.length(); i++) {
return allPOI;
}
private void createAttractionPoints() {
assert super.getAttractionPoints().size() == 0;
JSONArray allPOI = getPOIArray();
if(allPOI == null) {
throw new UnsupportedOperationException("[JSONAttractionGenerator] POI Data Array cannot be NULL.");
}
int limit = 0;
if(numberOfAttractionPoints == 0 || numberOfAttractionPoints > allPOI.length()) {
limit = allPOI.length();
}
else {
limit = numberOfAttractionPoints;
}
for(int i = 0; i < limit; i++) {
try {
String barname = allPOI.getJSONObject(i).getJSONObject("tags").getString("name");
double lat = allPOI.getJSONObject(i).getDouble("lat");
double lon = allPOI.getJSONObject(i).getDouble("lon");
AttractionPointImpl ap;
if(lat > latLeft && lat < latRight &&
lon > lonLeft && lon < lonRight) {
ap = new AttractionPointImpl(barname, transformGPSWindowToOwnWorld(lat, lon));
attractionPoints.add(ap);
// the following is allowed to fail.
AttractionPoint ap;
// check that the point is within the simulation boundaries
if(GPSCalculation.isWithinGPSBoundaries(lat, lon)) {
// initialize the attraction point with basic information, will be filled now...
ap = new AttractionPoint(barname, GPSCalculation.transformGPSWindowToOwnWorld(lat, lon));
// the following setters are allowed to fail
// AP weight
if(allPOI.getJSONObject(i).getJSONObject("tags").has("weight")) {
ap.setWeight(allPOI.getJSONObject(i).getJSONObject("tags").getDouble("weight"));
ap.setRadius(allPOI.getJSONObject(i).getJSONObject("tags").getDouble("radius"));
}
}
catch (JSONException e) {
//This bar had no name defined, so there was an error. Not so bad
}
// AP radius
if(allPOI.getJSONObject(i).getJSONObject("tags").has("radius")) {
double radius = allPOI.getJSONObject(i).getJSONObject("tags").getDouble("radius");
if(maximumRadius == -1) {
ap.setRadius(radius);
}
else {
ap.setRadius(Math.min(maximumRadius, radius));
}
}
return attractionPoints;
if(allPOI.getJSONObject(i).getJSONObject("tags").has("pauseTimeMin") && allPOI.getJSONObject(i).getJSONObject("tags").has("pauseTimeMax")) {
ap.setPauseTime( allPOI.getJSONObject(i).getJSONObject("tags").getLong("pauseTimeMin"), allPOI.getJSONObject(i).getJSONObject("tags").getLong("pauseTimeMax"));
}
public void setPlacementJsonFile(String placementJsonFile) {
this.placementJsonFile = placementJsonFile;
addAttractionPoint(ap);
}
}
catch (JSONException e) {
//This bar had no name defined, so there was an error. Not so bad
System.out.println(e);
}
}
}
}
/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see <http://www.gnu.org/licenses/>.
*
*/
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.util.LinkedList;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
public class MobileAttractionPoint extends AttractionPoint {
private LinkedList<PositionVector> waypoints;
private double speed = 0.5;
private boolean move = false;
private long pausetime = Time.MINUTE * 10;
private long timer = 0L;
@XMLConfigurableConstructor({ "name", "x", "y" })
public MobileAttractionPoint(String name, double x, double y) {
super(name, x, y);
waypoints = new LinkedList<PositionVector>();
waypoints.add(new PositionVector(250,250));
waypoints.add(new PositionVector(250,400));
waypoints.add(new PositionVector(750,400));
waypoints.add(new PositionVector(750,250));
}
public void move() {
if(move) {
PositionVector destination = waypoints.getFirst();
if (destination.distanceTo(this) > speed) {
this.set(this.moveStep(destination, speed));
}
else {
this.set(destination);
waypoints.add(waypoints.removeFirst());
timer = 0;
move = false;
}
}
else {
timer += Time.SECOND;
if(timer >= pausetime) {
timer = 0;
move = true;
}
}
}
}
......@@ -21,26 +21,18 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.GPSCalculation;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* Generates attraction points out of real data from osm
......@@ -49,61 +41,26 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
* @author Martin Hellwig
* @version 1.0, 02.07.2015
*/
public class OnlineJSONAttractionGenerator implements IAttractionGenerator {
private PositionVector worldDimensions;
private List<AttractionPoint> attractionPoints;
private int maxNumberOfAttractionPoints;
private String placementJsonFile;
private String placementJsonPath;
public class OnlineJSONAttractionGenerator extends JSONAttractionGenerator {
private String amenity;
private double latLeft; //Values from -90 to 90; always smaller than latRight
private double latRight; //Values from -90 to 90
private double lonLeft; //Values from -180 to 180; Always smaller than lonRight
private double lonRight; //Values from -180 to 180
public OnlineJSONAttractionGenerator() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
attractionPoints = new LinkedList<AttractionPoint>();
latLeft = GPSCalculation.getLatLower();
latRight = GPSCalculation.getLatUpper();
lonLeft = GPSCalculation.getLonLeft();
lonRight = GPSCalculation.getLonRight();
}
/**
* Projects the gps coordinates in the given gps window to the world-coordinates given in world-dimensions
* @param lat
* @param lon
* @return The projected position in world-dimensions
*/
private PositionVector transformGPSWindowToOwnWorld(double lat, double lon) {
double x = worldDimensions.getX() * (lon - lonLeft)/(lonRight - lonLeft);
//Invert the y value, because in Java Swing we start drawing in the upper left corner instead in the lower left one
double y = worldDimensions.getY() - worldDimensions.getY() * (lat - latLeft)/(latRight - latLeft);
return new PositionVector(x, y);
}
public void setNumberOfAttractionPoints(int numberOfAttractionPoints) {
this.maxNumberOfAttractionPoints = numberOfAttractionPoints;
}
@XMLConfigurableConstructor({"numberOfAttractionPoints", "maximumRadius", "placementJsonPath", "amenity"})
public OnlineJSONAttractionGenerator(int numberOfAttractionPoints, double maximumRadius,
String placementJsonPath, String amenity) {
@Override
public List<AttractionPoint> getAttractionPoints() {
if(attractionPoints.size() == 0) {
placementJsonFile = placementJsonPath +
super(numberOfAttractionPoints, maximumRadius, placementJsonPath +
"pois" +
GPSCalculation.getLatCenter() +
GPSCalculation.getLonCenter() +
GPSCalculation.getZoom() +
amenity + ".json";
amenity + ".json");
this.amenity = amenity;
}
@Override
protected JSONArray getPOIArray() {
//Check if the file with same properties (same location) already exists
File f = new File(placementJsonFile);
if(!f.exists()) {
......@@ -111,7 +68,9 @@ public class OnlineJSONAttractionGenerator implements IAttractionGenerator {
JSONArray allPOI = null;
InputStream in;
try {
in = new URL( "http://overpass-api.de/api/interpreter?data=%5Bout:json%5D;node%5Bamenity=" + amenity + "%5D%28" + latLeft + "%2C" + lonLeft + "%2C" + latRight + "%2C" + lonRight + "%29%3Bout%3B" ).openStream();
in = new URL( "http://overpass-api.de/api/interpreter?data=%5Bout:json%5D;node%5Bamenity=" + amenity + "%5D%28"
+ GPSCalculation.getLatUpper() + "%2C" + GPSCalculation.getLonLeft() + "%2C"
+ GPSCalculation.getLatLower() + "%2C" + GPSCalculation.getLonRight() + "%29%3Bout%3B" ).openStream();
poiString = IOUtils.toString(in);
//Save the json data in file
PrintWriter out = new PrintWriter(placementJsonFile);
......@@ -129,70 +88,11 @@ public class OnlineJSONAttractionGenerator implements IAttractionGenerator {
e.printStackTrace();
}
if(allPOI != null) {
for(int i = 0; i < allPOI.length(); i++) {
try {
String barname = allPOI.getJSONObject(i).getJSONObject("tags").getString("name");
double lat = allPOI.getJSONObject(i).getDouble("lat");
double lon = allPOI.getJSONObject(i).getDouble("lon");
if(lat > latLeft && lat < latRight &&
lon > lonLeft && lon < lonRight) {
attractionPoints.add(new AttractionPointImpl(barname, transformGPSWindowToOwnWorld(lat, lon)));
}
}
catch (JSONException e) {
//This bar had no name defined, so there was an error. Not so bad
}
}
}
return allPOI;
}
else {
//File already exists, now we have to parse this file
String poiString = "";
JSONArray allPOI = null;
FileInputStream inputStream;
try {
inputStream = new FileInputStream(placementJsonFile);
poiString = IOUtils.toString(inputStream);
JSONObject poiData = new JSONObject(poiString);
allPOI = poiData.getJSONArray("elements");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
if(allPOI != null) {
for(int i = 0; i < allPOI.length(); i++) {
try {
String barname = allPOI.getJSONObject(i).getJSONObject("tags").getString("name");
double lat = allPOI.getJSONObject(i).getDouble("lat");
double lon = allPOI.getJSONObject(i).getDouble("lon");
attractionPoints.add(new AttractionPointImpl(barname, transformGPSWindowToOwnWorld(lat, lon)));
}
catch (JSONException e) {
//This bar had no name defined, so there was an error. Not so bad
}
}
}
return super.getPOIArray();
}
}
if(maxNumberOfAttractionPoints == 0) maxNumberOfAttractionPoints = Integer.MAX_VALUE;
List<AttractionPoint> result = new LinkedList<AttractionPoint>();
for (int i = 0; (i < attractionPoints.size() && i < maxNumberOfAttractionPoints); i++) {
result.add(attractionPoints.get(i));
}
return result;
}
public void setAmenity(String amenity) {
this.amenity = amenity;
}
public void setPlacementJsonPath(String placementJsonPath) {
this.placementJsonPath = placementJsonPath;
}
}
......@@ -20,64 +20,121 @@
package de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.util.XMLConfigurableConstructor;
/**
* Implementation of the interface {@link AttractionGenerator}.
*
* It generates the given number of {@link AttractionPoint}s and sets the
* Position randomly.
* Generates the given number of {@link IAttractionPoint}s and sets the
* position randomly within the world dimensions.
*
* v1.1: statically available attraction points [JZ]
* v1.2: added a minimum distance between attraction points [JZ]
* v1.21: added a random radius to attraction points. Minimum is 10 meters, default maximum 100 meters. APs cannot have overlapping radii.
*
* @author Christoph Muenker
* @version 1.0, 02.07.2013
* @author Christoph Muenker, Julian Zobel
* @version 1.21, 12 2018
*/
public class RandomAttractionGenerator implements IAttractionGenerator {
public class RandomAttractionGenerator extends AbstractAttractionProvider {
private Random rand;
private PositionVector worldDimension;
private int numberOfAttractionPoints;
private boolean numberOfAPsSet = false;
@XMLConfigurableConstructor({"numberOfAttractionPoints"})
public RandomAttractionGenerator(int numberOfAttractionPoints) {
private double minimumDistance = 50;
private double maximumRadius = 100;
private double minimumRadius = 10;
@XMLConfigurableConstructor({"numberOfAttractionPoints", "maximumRadius", "minimumRadius", "minimumDistance"})
public RandomAttractionGenerator(int numberOfAttractionPoints, double maximumRadius, double minimumRadius, double minimumDistance) {
super();
this.rand = Randoms.getRandom(RandomAttractionGenerator.class);
this.worldDimension = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions();
if (numberOfAttractionPoints <= 0) {
throw new ConfigurationException(
"NumberOfAttractionPoints should be at least 1!");
}
this.numberOfAPsSet = true;
this.numberOfAttractionPoints = numberOfAttractionPoints;
this.maximumRadius = maximumRadius;
this.minimumRadius = minimumRadius;
this.minimumDistance = minimumDistance;
createAttractionPoints();
}
@Override
public List<AttractionPoint> getAttractionPoints() {
public LinkedList<AttractionPoint> getAttractionPoints() {
if (!numberOfAPsSet) {
throw new ConfigurationException(
"Number of Attraction Points is not set in RandomAttractionGenerator!");
}
List<AttractionPoint> result = new Vector<AttractionPoint>();
for (int i = 0; i < numberOfAttractionPoints; i++) {
if(super.getAttractionPoints().isEmpty())
createAttractionPoints();
return super.getAttractionPoints();
}
private void createAttractionPoints() {
LinkedList<AttractionPoint> result = new LinkedList<AttractionPoint>();
// make a break counter to prevent more than 10 iterations and an infinity loop in general.
int c = 0;
create: for (int i = 0; i < numberOfAttractionPoints; i++) {
PositionVector posVec = createPosVec();
AttractionPoint aPoint = new AttractionPointImpl("AP"+i,posVec);
// set the radius of this attraction point
// minimum radius is 10 meters
double radius = Math.max(minimumRadius, rand.nextDouble() * maximumRadius);
if(c < 20)
{
// if not within the world dimensions, directly go back to calculation
if(posVec.getX() + radius > worldDimension.getX() || posVec.getY() + radius > worldDimension.getY()
|| posVec.getX() - radius < 0 || posVec.getY() - radius < 0) {
i--;
c++;
continue create;
}
for (IAttractionPoint ap : result) {
// if this point is closer than the given minimum distance to another point, or the radii of the points would overlap,
// or if the radius would exceed the simulation area
// then discard this attraction point and create a new one
if(posVec.distanceTo(ap) < minimumDistance || (posVec.distanceTo(ap) - radius - ap.getRadius()) < 0 ) {
i--;
c++;
continue create;
}
}
}
else
{
radius = minimumRadius;
}
AttractionPoint aPoint = new AttractionPoint("AP-"+i, posVec);
aPoint.setRadius(radius);
c = 0;
result.add(aPoint);
}
return result;
for (AttractionPoint ap : result) {
addAttractionPoint(ap);
}
}
private PositionVector createPosVec() {
......@@ -86,4 +143,33 @@ public class RandomAttractionGenerator implements IAttractionGenerator {
return new PositionVector(x, y);
}
/**
* Set a minimum distance between the randomly generated attraction points
* @param distance
*/
public void setMinimumDistance(double distance) {
this.minimumDistance = distance;
}
/**
* Set a maximum radius that an attraction point can have.
* @param radius
*/
public void setMaximumRadius(double radius) {
this.maximumRadius = radius;
}
/**
* Set a minimum radius that an attraction point can have. Minimum is 10 meters.
* @param radius
*/
public void setMinimumRadius(double radius) {
if(radius < 10) {
this.minimumRadius = 10;
}
else {
this.minimumRadius = radius;
}
}
}
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