Commit dfddaec2 authored by Clemens Krug's avatar Clemens Krug
Browse files

Movement model allows transitions switches

+ Added the possibility to switch the transition mid-simulation for the ModularMultiTypeMovement
+ Added a new transition strategy
parent 65563542
...@@ -113,7 +113,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -113,7 +113,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
private ModularMovementModelViz modelVisualisation; private ModularMovementModelViz modelVisualisation;
private Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>(); protected Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>();
private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>(); private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>();
......
...@@ -2,24 +2,35 @@ package de.tud.kom.p2psim.impl.topology.movement.modularosm; ...@@ -2,24 +2,35 @@ package de.tud.kom.p2psim.impl.topology.movement.modularosm;
import de.tud.kom.p2psim.api.topology.Topology; import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator; import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.PositionVector; import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement; import de.tud.kom.p2psim.impl.topology.movement.local.RealWorldStreetsMovement;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.util.Either; import de.tud.kom.p2psim.impl.util.Either;
import de.tudarmstadt.maki.simonstrator.api.Binder; import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
/** /**
* This class is meant to be used with the RealWorldStreetsMovement * This class is meant to be used with the RealWorldStreetsMovement
* if different movement types should be used simultaneously. It acts * and allows changes of the movement type and the used {@link ITransitionStrategy} mid-simulation
* like the {@link ModularMovementModel}, but each of the {@link SimLocationActuator}s * 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 the movement route will be calculated according * can have a different movement type and {@link ITransitionStrategy}. All routes and target will be
* to this type. <BR><BR> * calculated accordingly. <BR><BR>
* *
* USAGE: * USAGE:
* So basically if you want to use this movement model, all you have to do is * If you want to use different movement types, all you have to do is
* (besides specifying it in your config) call the {@link #setMovementType(SimLocationActuator, String)} * (besides selecting this model it in your config) call the {@link #setMovementType(SimLocationActuator, String)}
* for each of your components.<BR><BR> * for each of your components.<BR>
*
* The used {@link ITransitionStrategy} 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)}
* with the second parameter being the class of the transition strategy you want to use.
* *
* NOTE: All the movement types you are using need to be specified in you config for the * NOTE: All the movement types you are using need to be specified in you config for the
* {@link RealWorldStreetsMovement}. E.g if you are using 'car' and 'foot' movement types, * {@link RealWorldStreetsMovement}. E.g if you are using 'car' and 'foot' movement types,
...@@ -31,13 +42,31 @@ import java.util.HashMap; ...@@ -31,13 +42,31 @@ import java.util.HashMap;
public class ModularMultiTypeMovementModel extends ModularMovementModel public class ModularMultiTypeMovementModel extends ModularMovementModel
{ {
private HashMap<SimLocationActuator, String> movementTypes; private HashMap<SimLocationActuator, String> movementTypes;
private HashMap<SimLocationActuator, ITransitionStrategy> transitions;
private HashMap<Class, ITransitionStrategy> supportedTransitions;
public ModularMultiTypeMovementModel() public ModularMultiTypeMovementModel()
{ {
super(); super();
movementTypes = new HashMap<>(); movementTypes = new HashMap<>();
transitions = new HashMap<>();
supportedTransitions = new HashMap<>();
} }
@Override
public void initialize()
{
super.initialize();
for(ITransitionStrategy strategy : supportedTransitions.values())
{
strategy.setAttractionPoints(transition.getAllAttractionPoints());
strategy.addAttractionAssignmentListener(this);
for (SimLocationActuator ms : moveableHosts) {
strategy.addComponent(ms);
}
}
}
@Override @Override
protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) protected void doLocalMovement(SimLocationActuator ms, PositionVector destination)
...@@ -62,7 +91,8 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel ...@@ -62,7 +91,8 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
.getComponentOrNull(Topology.class) .getComponentOrNull(Topology.class)
.getWorldDimensions().getY(); .getWorldDimensions().getY();
} else { } else {
transition.reachedAttractionPoint(ms); if(transitions.containsKey(ms)) transitions.get(ms).reachedAttractionPoint(ms);
else transition.reachedAttractionPoint(ms);
} }
} }
...@@ -75,4 +105,47 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel ...@@ -75,4 +105,47 @@ public class ModularMultiTypeMovementModel extends ModularMovementModel
{ {
return movementTypes.get(ms); return movementTypes.get(ms);
} }
public void setTransitionForComponent(SimLocationActuator ms, Class strategy)
{
ITransitionStrategy selectedStrategy = supportedTransitions.get(strategy);
if(selectedStrategy == null)
{
throw new UnsupportedOperationException(
String.format("ModularMultiTypeMovementModel: TransitionStrategy %s ist not supported!", strategy.toString()));
}
changeTransitionStrategy(ms, selectedStrategy);
}
private void changeTransitionStrategy(SimLocationActuator ms, ITransitionStrategy newStrategy)
{
ITransitionStrategy usedStrategy = transitions.containsKey(ms) ? transitions.get(ms) : transition;
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()));
}
public void returnToDefaultTransition(SimLocationActuator ms)
{
transitions.remove(ms);
}
@Override
public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) {
if(transitions.containsKey(actuator)) transitions.get(actuator).updateTargetAttractionPoint(actuator, ap);
else transition.updateTargetAttractionPoint(actuator, ap);
}
@Override
public void setITransitionStrategy(ITransitionStrategy transition) {
if(supportedTransitions.size() == 0) this.transition = transition;
supportedTransitions.put(transition.getClass(), transition);
}
@Override
public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
if(transitions.containsKey(actuator)) return transitions.get(actuator).getAssignment(actuator);
else return transition.getAssignment(actuator);
}
} }
...@@ -20,19 +20,18 @@ import java.util.Map; ...@@ -20,19 +20,18 @@ import java.util.Map;
* the first thing to do is specify this {@link ModularMovementIconVis} as visualisation for * the first thing to do is specify this {@link ModularMovementIconVis} as visualisation for
* your modular movement model. To add icons to the visualisation the class {@link IconMapping} is used within the tags. * your modular movement model. To add icons to the visualisation the class {@link IconMapping} is used within the tags.
* You have two tags available for different kind of icons:<BR><BR> * You have two tags available for different kind of icons:<BR><BR>
* * <p>
* 1. Class icons: These icons are used dependent on the class of the components the host includes. You can * 1. Class icons: These icons are used dependent on the class of the components the host includes. You can
* add a class icon by using the &lt;ClassIcon> tag you config and setting the fully qualified classname * add a class icon by using the &lt;ClassIcon> tag you config and setting the fully qualified classname
* of you components as object. If a host has multiple components with different specified icons, the first one will be used.<BR><BR> * of you components as object. If a host has multiple components with different specified icons, the first one will be used.<BR><BR>
* * <p>
* 2. State icons: These icons are used dependent on the state of a host and take precedence over the class icons. You * 2. State icons: These icons are used dependent on the state of a host and take precedence over the class icons. You
* can add them via the &lt;StateIcon> tag. The object should be a String representing the state. When * can add them via the &lt;StateIcon> tag. The object should be a String representing the state. When
* using these types of icons, you need to set a {@link StateSelector} for this class in the config.<BR><BR> * using these types of icons, you need to set a {@link StateSelector} for this class in the config.<BR><BR>
* * <p>
* For example usage, see the movement_social.xml config for the resourceAllocation overlay. * For example usage, see the movement_social.xml config for the resourceAllocation overlay.
* *
* @author Clemens Krug * @author Clemens Krug
*/ */
public class ModularMovementIconVis extends ModularMovementModelViz implements EventHandler public class ModularMovementIconVis extends ModularMovementModelViz implements EventHandler
{ {
...@@ -65,24 +64,28 @@ public class ModularMovementIconVis extends ModularMovementModelViz implements E ...@@ -65,24 +64,28 @@ public class ModularMovementIconVis extends ModularMovementModelViz implements E
VisualizationTopologyView.VisualizationInjector.getTopologyView().setShowNodes(false); VisualizationTopologyView.VisualizationInjector.getTopologyView().setShowNodes(false);
for(Map.Entry<Class, String> e : pathMap.entrySet()) for (Map.Entry<Class, String> e : pathMap.entrySet())
{ {
try { try
{
Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST); Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST);
classIconMap.put(e.getKey(), icon); classIconMap.put(e.getKey(), icon);
} catch (IOException ioe) { } catch (IOException ioe)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue()); Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue());
} }
} }
for(Map.Entry<String, String> e : stateMap.entrySet()) for (Map.Entry<String, String> e : stateMap.entrySet())
{ {
assert stateSelector != null : "There must be a state selector specified when using state icons!"; assert stateSelector != null : "There must be a state selector specified when using state icons!";
try { try
{
Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST); Image icon = ImageIO.read(new File(e.getValue())).getScaledInstance(-1, 15, Image.SCALE_FAST);
stateIconMap.put(e.getKey(), icon); stateIconMap.put(e.getKey(), icon);
} catch (IOException ioe) { } catch (IOException ioe)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue()); Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Could not load icon from path %s", e.getValue());
} }
} }
...@@ -91,71 +94,89 @@ public class ModularMovementIconVis extends ModularMovementModelViz implements E ...@@ -91,71 +94,89 @@ public class ModularMovementIconVis extends ModularMovementModelViz implements E
} }
@Override @Override
public void paint(Graphics g) { public void paint(Graphics g)
{
super.paintSuper(g); super.paintSuper(g);
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON); RenderingHints.VALUE_ANTIALIAS_ON);
if (showAttractionPoints) { if (showAttractionPoints)
{
super.drawAttractionPoints(g2); super.drawAttractionPoints(g2);
} }
if (showNodePositions) { if (showNodePositions)
{
for (SimLocationActuator comp : movementModel for (SimLocationActuator comp : movementModel
.getAllLocationActuators()) { .getAllLocationActuators())
{
drawNodePosition(g2, comp); drawNodePosition(g2, comp);
} }
} }
} }
@Override @Override
protected void drawNodePosition(Graphics2D g2, SimLocationActuator comp) protected void drawNodePosition(Graphics2D g2, SimLocationActuator comp)
{ {
boolean iconNotFound = false; boolean iconNotFound = true;
Host host = comp.getHost(); Host host = comp.getHost();
Point2D pt = comp.getRealPosition().asPoint(); Point2D pt = comp.getRealPosition().asPoint();
g2.setColor(Color.GRAY); g2.setColor(Color.GRAY);
//Check if the component has a specified state, as this would have precedence over the classIcon. // Check if the component has a specified state, as this would have precedence over the classIcon.
if (stateSelector != null)
{
String state = stateSelector.getState(comp); String state = stateSelector.getState(comp);
if(stateIconMap.containsKey(state)) if (stateIconMap.containsKey(state))
{ {
g2.drawImage(stateIconMap.get(state), (int) pt.getX(), (int) pt.getY(), null); Image icon = stateIconMap.get(state);
int width = icon.getWidth(null);
int height = icon.getHeight(null);
g2.drawImage(icon, (int) pt.getX() - width / 2, (int) pt.getY() - height / 2, null);
return; return;
} }
}
// If not, check if there's a class icon available // If not, check if there's a class icon available
for(Map.Entry<Class, Image> e : classIconMap.entrySet()) for (Map.Entry<Class, Image> e : classIconMap.entrySet())
{
try
{
host.getComponent(e.getKey());
Image icon = e.getValue();
int width = icon.getWidth(null);
int height = icon.getHeight(null);
g2.drawImage(icon, (int) pt.getX() - width / 2, (int) pt.getY() - height / 2, null);
iconNotFound = false;
break;
} catch (ComponentNotAvailableException nae)
{ {
try { iconNotFound = true;
host.getComponent(e.getKey());
g2.drawImage(e.getValue(), (int) pt.getX(), (int) pt.getY(), null);
iconNotFound = false;
break;
} catch (ComponentNotAvailableException nae) {
iconNotFound = true;
}
} }
}
// If not, use standard visualisation // If not, use standard visualisation
if(iconNotFound) super.drawNodePosition(g2, comp); if (iconNotFound) super.drawNodePosition(g2, comp);
} }
@Override @Override
public void eventOccurred(Object content, int type) { public void eventOccurred(Object content, int type)
if (type == 0) { {
if (type == 0)
{
initialize(); initialize();
} }
} }
public void setClassIcon(IconMapping classIcon) public void setClassIcon(IconMapping classIcon)
{ {
try { try
{
pathMap.put(Class.forName(classIcon.getObject()), classIcon.getIconpath()); pathMap.put(Class.forName(classIcon.getObject()), classIcon.getIconpath());
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e)
{
Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Class %s not found!", classIcon.getObject()); Monitor.log(ModularMovementIconVis.class, Monitor.Level.WARN, "Class %s not found!", classIcon.getObject());
} }
} }
......
...@@ -16,6 +16,7 @@ public class ManualAssignmentStrategy implements ITransitionStrategy ...@@ -16,6 +16,7 @@ public class ManualAssignmentStrategy implements ITransitionStrategy
private List<AttractionAssignmentListener> listeners = new LinkedList<>(); private List<AttractionAssignmentListener> listeners = new LinkedList<>();
@Override @Override
public AttractionPoint getAssignment(SimLocationActuator comp) public AttractionPoint getAssignment(SimLocationActuator comp)
{ {
...@@ -52,12 +53,11 @@ public class ManualAssignmentStrategy implements ITransitionStrategy ...@@ -52,12 +53,11 @@ public class ManualAssignmentStrategy implements ITransitionStrategy
assignments.put(ms, aPoint); assignments.put(ms, aPoint);
} }
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, assignments.get(ms))); listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, assignments.get(ms)));
} }
@Override @Override
public void reachedAttractionPoint(SimLocationActuator ms) { public void reachedAttractionPoint(SimLocationActuator ms) {
//Nothing to do.
} }
@Override @Override
......
package de.tud.kom.p2psim.impl.topology.movement.modularosm.transition;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.PositionVector;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.BasicAttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
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.Location;
import java.util.*;
/**
* Created by Clemens on 15.02.2017.
*/
public class RandomInAreaTransitionStrategy implements ITransitionStrategy
{
private Random random;
private LinkedHashSet<AttractionPoint> aPoints = new LinkedHashSet<>();
private Map<SimLocationActuator, AttractionPoint> assignments = new HashMap<>();
private Map<SimLocationActuator, AttractionPoint> currentTarget = new HashMap<>();
private List<AttractionAssignmentListener> listeners = new LinkedList<>();
private int defaultRadius;
public RandomInAreaTransitionStrategy()
{
random = Randoms.getRandom(this.getClass());
}
@Override
public AttractionPoint getAssignment(SimLocationActuator comp)
{
return currentTarget.get(comp);
}
@Override
public void addAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.add(listener);
}
@Override
public void removeAttractionAssignmentListener(AttractionAssignmentListener listener)
{
listeners.remove(listener);
}
@Override
public void setAttractionPoints(Collection<AttractionPoint> attractionPoints) {
aPoints.addAll(attractionPoints);
}
@Override
public Set<AttractionPoint> getAllAttractionPoints() {
return aPoints;
}
@Override
public void addComponent(SimLocationActuator ms) {
if(!assignments.containsKey(ms))
{
AttractionPoint aPoint = aPoints.iterator().next();
assignments.put(ms, aPoint);
currentTarget.put(ms, nextRandomPosition(aPoint, defaultRadius));
}
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
}
@Override
public void reachedAttractionPoint(SimLocationActuator ms) {
currentTarget.put(ms, nextRandomPosition(assignments.get(ms), defaultRadius));
listeners.forEach(listener -> listener.updatedAttractionAssignment(ms, currentTarget.get(ms)));
}
@Override
public void updateTargetAttractionPoint(SimLocationActuator comp, AttractionPoint attractionPoint) {
assignments.put(comp, attractionPoint);
currentTarget.put(comp, nextRandomPosition(attractionPoint, defaultRadius));
listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
}
public void updateTargetAttractionPoint(SimLocationActuator comp, AttractionPoint attractionPoint, int radius)
{
assignments.put(comp, attractionPoint);
currentTarget.put(comp, nextRandomPosition(attractionPoint, radius));
listeners.forEach(listener -> listener.updatedAttractionAssignment(comp, attractionPoint));
}
public void setDefaultRadius(int radius)
{
this.defaultRadius = radius;
}
private BasicAttractionPoint nextRandomPosition(Location center, int radius)
{
double x = center.getLongitude();
double y = center.getLatitude();
double newX = -1;
double newY = -1;
int tries = 0;
while(newX < 0.0 || newX > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getX()
|| newY < 0.0 || newY > Binder.getComponentOrNull(Topology.class).getWorldDimensions().getY())
{
double calcRadius = random.nextDouble() * radius;
double calcAngle = random.nextDouble() * 360;
newX = x + Math.sin(calcAngle) * calcRadius;
newY = y + Math.cos(calcAngle) * calcRadius;
tries++;
if(tries > 100) throw new AssertionError("Unable to find a valid target destination within <100 tries.");
}
Monitor.log(this.getClass(), Monitor.Level.DEBUG, "Next random position is " + newX + " / " + newY);
return new BasicAttractionPoint("RNDPOS", new PositionVector(newX, newY));
}
}
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