Rewrote the traffic history visualization with blue arrows that fade

away based on their age. Age is calculated from the simulation time
so the fade depends on the simulation speed.
This commit is contained in:
Adam Dunkels 2012-06-05 08:07:47 +02:00
parent cce3628440
commit bd86a807c8

View File

@ -34,6 +34,7 @@ package se.sics.cooja.plugins.skins;
import java.awt.Color; import java.awt.Color;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Point; import java.awt.Point;
import java.awt.Polygon;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
@ -73,24 +74,22 @@ import se.sics.cooja.radiomediums.AbstractRadioMedium;
public class TrafficVisualizerSkin implements VisualizerSkin { public class TrafficVisualizerSkin implements VisualizerSkin {
private static Logger logger = Logger.getLogger(TrafficVisualizerSkin.class); private static Logger logger = Logger.getLogger(TrafficVisualizerSkin.class);
private static final boolean DRAW_ARROWS = true;
private static final Color COLOR_HISTORY = new Color(100, 100, 100, 100);
private Simulation simulation = null; private Simulation simulation = null;
private Visualizer visualizer = null; private Visualizer visualizer = null;
private Box counters; private Box counters;
private final static int HISTORY_SIZE = 16; private final int MAX_HISTORY_SIZE = 200;
private boolean showHistory = false; private boolean showHistory = true;
private ArrayDeque<RadioConnection> history = new ArrayDeque<RadioConnection>(); private ArrayDeque<RadioConnectionArrow> history = new ArrayDeque<RadioConnectionArrow>();
private AbstractRadioMedium radioMedium; private AbstractRadioMedium radioMedium;
private Observer radioObserver, radioMediumObserver; private Observer radioObserver, radioMediumObserver;
public void setActive(Simulation simulation, Visualizer vis) { public void setActive(final Simulation simulation, Visualizer vis) {
if (!(simulation.getRadioMedium() instanceof AbstractRadioMedium)) { if (!(simulation.getRadioMedium() instanceof AbstractRadioMedium)) {
logger.fatal("Radio medium type not supported: " + simulation.getRadioMedium()); logger.fatal("Radio medium type not supported: "
+ simulation.getRadioMedium());
return; return;
} }
this.radioMedium = (AbstractRadioMedium) simulation.getRadioMedium(); this.radioMedium = (AbstractRadioMedium) simulation.getRadioMedium();
@ -99,7 +98,8 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
final JLabel txCounter = new JLabel("TX: " + radioMedium.COUNTER_TX); final JLabel txCounter = new JLabel("TX: " + radioMedium.COUNTER_TX);
final JLabel rxCounter = new JLabel("RX: " + radioMedium.COUNTER_RX); final JLabel rxCounter = new JLabel("RX: " + radioMedium.COUNTER_RX);
final JLabel interferedCounter = new JLabel("INT: " + radioMedium.COUNTER_INTERFERED); final JLabel interferedCounter = new JLabel("INT: "
+ radioMedium.COUNTER_INTERFERED);
counters = Box.createHorizontalBox(); counters = Box.createHorizontalBox();
counters.add(txCounter); counters.add(txCounter);
@ -119,11 +119,8 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
if (showHistory) { if (showHistory) {
RadioConnection last = radioMedium.getLastConnection(); RadioConnection last = radioMedium.getLastConnection();
if (last != null) { if (last != null && history.size() < MAX_HISTORY_SIZE) {
history.add(last); history.add(new RadioConnectionArrow(last));
while (history.size() > HISTORY_SIZE) {
history.removeFirst();
}
} }
} }
visualizer.repaint(); visualizer.repaint();
@ -141,6 +138,7 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
r.addObserver(radioObserver); r.addObserver(radioObserver);
} }
} }
public void moteWasRemoved(Mote mote) { public void moteWasRemoved(Mote mote) {
Radio r = mote.getInterfaces().getRadio(); Radio r = mote.getInterfaces().getRadio();
if (r != null) { if (r != null) {
@ -156,6 +154,26 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
} }
} }
simulation.addMillisecondObserver(new Observer() {
public void update(Observable obs, Object obj) {
if((simulation.getSimulationTimeMillis() % 100) == 0) {
RadioConnectionArrow[] historyArr = history.toArray(new RadioConnectionArrow[0]);
if(historyArr.length > 0) {
visualizer.repaint();
}
for (RadioConnectionArrow connArrow : historyArr) {
if (connArrow == null) {
continue;
}
connArrow.increaseAge();
if(connArrow.getAge() >= connArrow.getMaxAge()) {
history.remove(connArrow);
}
}
}
}
});
/* Register menu actions */ /* Register menu actions */
visualizer.registerSimulationMenuAction(ToggleHistoryAction.class); visualizer.registerSimulationMenuAction(ToggleHistoryAction.class);
} }
@ -182,35 +200,38 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
} }
public Color[] getColorOf(Mote mote) { public Color[] getColorOf(Mote mote) {
if (simulation == null) {
/* Skin was never activated */
return null; return null;
} }
Radio moteRadio = mote.getInterfaces().getRadio(); private Polygon arrowPoly = new Polygon();
if (moteRadio == null) { private void drawArrow(Graphics g, int xSource, int ySource, int xDest, int yDest, int delta) {
return null; double dx = xSource - xDest;
double dy = ySource - yDest;
double dir = Math.atan2(dx, dy);
double len = Math.sqrt(dx * dx + dy * dy);
dx /= len;
dy /= len;
len -= delta;
xDest = xSource - (int) (dx * len);
yDest = ySource - (int) (dy * len);
g.drawLine(xDest, yDest, xSource, ySource);
final int size = 8;
arrowPoly.reset();
arrowPoly.addPoint(xDest, yDest);
arrowPoly.addPoint(xDest + xCor(size, dir + 0.5), yDest + yCor(size, dir + 0.5));
arrowPoly.addPoint(xDest + xCor(size, dir - 0.5), yDest + yCor(size, dir - 0.5));
arrowPoly.addPoint(xDest, yDest);
g.fillPolygon(arrowPoly);
} }
if (!moteRadio.isRadioOn()) { private int yCor(int len, double dir) {
return new Color[] { Color.GRAY }; return (int)(0.5 + len * Math.cos(dir));
} }
if (moteRadio.isTransmitting()) { private int xCor(int len, double dir) {
return new Color[] { Color.BLUE }; return (int)(0.5 + len * Math.sin(dir));
} }
if (moteRadio.isInterfered()) {
return new Color[] { Color.RED };
}
if (moteRadio.isReceiving()) {
return new Color[] { Color.GREEN };
}
return null;
}
public void paintBeforeMotes(Graphics g) { public void paintBeforeMotes(Graphics g) {
if (simulation == null) { if (simulation == null) {
/* Skin was never activated */ /* Skin was never activated */
@ -219,18 +240,20 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
if (showHistory) { if (showHistory) {
/* Paint history in gray */ /* Paint history in gray */
RadioConnection[] historyArr = history.toArray(new RadioConnection[0]); RadioConnectionArrow[] historyArr = history.toArray(new RadioConnectionArrow[0]);
for (RadioConnection conn : historyArr) { for (RadioConnectionArrow connArrow : historyArr) {
if (conn == null) { if (connArrow == null) {
continue; continue;
} }
g.setColor(COLOR_HISTORY); float colorHistoryIndex = (float)connArrow.getAge() / (float)connArrow.getMaxAge();
Radio source = conn.getSource(); g.setColor(new Color(colorHistoryIndex, colorHistoryIndex, 1.0f));
Point sourcePoint = visualizer.transformPositionToPixel(source.getPosition()); Radio source = connArrow.getConnection().getSource();
for (Radio destRadio : conn.getDestinations()) { Point sourcePoint = visualizer.transformPositionToPixel(source
.getPosition());
for (Radio destRadio : connArrow.getConnection().getDestinations()) {
Position destPos = destRadio.getPosition(); Position destPos = destRadio.getPosition();
Point destPoint = visualizer.transformPositionToPixel(destPos); Point destPoint = visualizer.transformPositionToPixel(destPos);
g.drawLine(sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y); drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y, 8);
} }
} }
} }
@ -244,24 +267,15 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
continue; continue;
} }
Radio source = conn.getSource(); Radio source = conn.getSource();
Point sourcePoint = visualizer.transformPositionToPixel(source.getPosition()); Point sourcePoint = visualizer.transformPositionToPixel(source
.getPosition());
for (Radio destRadio : conn.getDestinations()) { for (Radio destRadio : conn.getDestinations()) {
if (destRadio == null) { if (destRadio == null) {
continue; continue;
} }
Position destPos = destRadio.getPosition(); Position destPos = destRadio.getPosition();
Point destPoint = visualizer.transformPositionToPixel(destPos); Point destPoint = visualizer.transformPositionToPixel(destPos);
g.drawLine(sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y); drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y, 8);
/* Draw arrows */
if (DRAW_ARROWS) {
Point centerPoint = new Point(
destPoint.x/2 + sourcePoint.x/2,
destPoint.y/2 + sourcePoint.y/2
);
int startAngle = (int) (-180 * Math.atan2(destPoint.y - sourcePoint.y, destPoint.x - sourcePoint.x)/Math.PI - 90);
g.drawArc(centerPoint.x-5, centerPoint.y-5, 10, 10, startAngle, 180);
}
} }
} }
} }
@ -303,4 +317,26 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
public Visualizer getVisualizer() { public Visualizer getVisualizer() {
return visualizer; return visualizer;
} }
private class RadioConnectionArrow {
private RadioConnection conn;
private int age;
private final int MAX_AGE = 10;
RadioConnectionArrow(RadioConnection conn) {
this.conn = conn;
this.age = 0;
}
public void increaseAge() {
age++;
}
public int getAge() {
return age;
}
public RadioConnection getConnection() {
return conn;
}
public int getMaxAge() {
return MAX_AGE;
}
}
} }