Merge pull request #769 from ejoerns/pull-req/cooja-traffic-vis

[Cooja] TrafficVisualizerSkin modifications
This commit is contained in:
Fredrik Österlind 2014-08-13 13:13:01 +02:00
commit 6fec61bf7c
1 changed files with 78 additions and 47 deletions

View File

@ -33,7 +33,9 @@ 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.awt.Polygon;
import java.util.ArrayList; import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
@ -60,54 +62,51 @@ import org.contikios.cooja.radiomediums.AbstractRadioMedium;
@ClassDescription("Radio traffic") @ClassDescription("Radio traffic")
@SupportedArguments(radioMediums = {AbstractRadioMedium.class}) @SupportedArguments(radioMediums = {AbstractRadioMedium.class})
public class TrafficVisualizerSkin implements VisualizerSkin { public class TrafficVisualizerSkin implements VisualizerSkin {
private static Logger logger = Logger.getLogger(TrafficVisualizerSkin.class); private static final Logger logger = Logger.getLogger(TrafficVisualizerSkin.class);
private final int MAX_HISTORY_SIZE = 200; private final int MAX_HISTORY_SIZE = 200;
private final float TRANSMITTED_COLOR_RGB[] = Color.BLUE.getRGBColorComponents(null);
private final float UNTRANSMITTED_COLOR_RGB[] = Color.RED.getRGBColorComponents(null);
private boolean active = false; private boolean active = false;
private Simulation simulation = null; private Simulation simulation = null;
private Visualizer visualizer = null; private Visualizer visualizer = null;
private AbstractRadioMedium radioMedium = null; private AbstractRadioMedium radioMedium = null;
private ArrayList<RadioConnectionArrow> historyList = new ArrayList<RadioConnectionArrow>(); private final List<RadioConnectionArrow> historyList = new LinkedList<>();
private RadioConnectionArrow[] history = null;
private Observer radioMediumObserver = new Observer() { private Observer radioMediumObserver = new Observer() {
@Override
public void update(Observable obs, Object obj) { public void update(Observable obs, Object obj) {
RadioConnection last = radioMedium.getLastConnection(); RadioConnection last = radioMedium.getLastConnection();
if (last != null && historyList.size() < MAX_HISTORY_SIZE) { if (last != null && historyList.size() < MAX_HISTORY_SIZE) {
historyList.add(new RadioConnectionArrow(last)); synchronized(historyList) {
history = historyList.toArray(new RadioConnectionArrow[0]); historyList.add(new RadioConnectionArrow(last));
visualizer.repaint(500); visualizer.repaint(500);
}
} }
} }
}; };
private TimeEvent ageArrowsTimeEvent = new TimeEvent(0) {
private final TimeEvent ageArrowsTimeEvent = new TimeEvent(0) {
@Override
public void execute(long t) { public void execute(long t) {
if (!active) { if (!active) {
return; return;
} }
if (historyList.size() > 0) { if (historyList.size() > 0) {
boolean hasOld = false;
/* Increase age */ synchronized (historyList) {
for (RadioConnectionArrow connArrow : historyList) { /* Increase age and remove too old arrows */
connArrow.increaseAge(); Iterator<RadioConnectionArrow> iter = historyList.iterator();
if(connArrow.getAge() >= connArrow.getMaxAge()) { while (iter.hasNext()) {
hasOld = true; RadioConnectionArrow rca = iter.next();
} /* Try to increase age and remove if max age was reached */
} if (!rca.increaseAge()) {
iter.remove();
/* Remove too old arrows */
if (hasOld) {
RadioConnectionArrow[] historyArr = historyList.toArray(new RadioConnectionArrow[0]);
for (RadioConnectionArrow connArrow : historyArr) {
if(connArrow.getAge() >= connArrow.getMaxAge()) {
historyList.remove(connArrow);
} }
} }
historyArr = historyList.toArray(new RadioConnectionArrow[0]);
} }
visualizer.repaint(500); visualizer.repaint(500);
@ -118,6 +117,7 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
} }
}; };
@Override
public void setActive(final Simulation simulation, Visualizer vis) { public void setActive(final Simulation simulation, Visualizer vis) {
this.radioMedium = (AbstractRadioMedium) simulation.getRadioMedium(); this.radioMedium = (AbstractRadioMedium) simulation.getRadioMedium();
this.simulation = simulation; this.simulation = simulation;
@ -125,9 +125,9 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
this.active = true; this.active = true;
simulation.invokeSimulationThread(new Runnable() { simulation.invokeSimulationThread(new Runnable() {
@Override
public void run() { public void run() {
historyList.clear(); historyList.clear();
history = null;
/* Start observing radio medium for transmissions */ /* Start observing radio medium for transmissions */
radioMedium.addRadioMediumObserver(radioMediumObserver); radioMedium.addRadioMediumObserver(radioMediumObserver);
@ -138,6 +138,7 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
}); });
} }
@Override
public void setInactive() { public void setInactive() {
this.active = false; this.active = false;
if (simulation == null) { if (simulation == null) {
@ -149,11 +150,12 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
radioMedium.deleteRadioMediumObserver(radioMediumObserver); radioMedium.deleteRadioMediumObserver(radioMediumObserver);
} }
@Override
public Color[] getColorOf(Mote mote) { public Color[] getColorOf(Mote mote) {
return null; return null;
} }
private Polygon arrowPoly = new Polygon(); private final Polygon arrowPoly = new Polygon();
private void drawArrow(Graphics g, int xSource, int ySource, int xDest, int yDest, int delta) { private void drawArrow(Graphics g, int xSource, int ySource, int xDest, int yDest, int delta) {
double dx = xSource - xDest; double dx = xSource - xDest;
double dy = ySource - yDest; double dy = ySource - yDest;
@ -183,52 +185,81 @@ public class TrafficVisualizerSkin implements VisualizerSkin {
return (int)(0.5 + len * Math.sin(dir)); return (int)(0.5 + len * Math.sin(dir));
} }
@Override
public void paintBeforeMotes(Graphics g) { public void paintBeforeMotes(Graphics g) {
RadioConnectionArrow[] historyCopy = history; synchronized (historyList) {
if (historyCopy == null) { for (RadioConnectionArrow connArrow : historyList) {
return; float colorHistoryIndex = 1.0f - connArrow.getAge();
} Radio source = connArrow.getConnection().getSource();
for (RadioConnectionArrow connArrow : historyCopy) { Point sourcePoint = visualizer.transformPositionToPixel(source.getPosition());
float colorHistoryIndex = (float)connArrow.getAge() / (float)connArrow.getMaxAge(); /* If there is no destination, paint red circles to indicate untransmitted message */
g.setColor(new Color(colorHistoryIndex, colorHistoryIndex, 1.0f)); if (connArrow.getConnection().getDestinations().length == 0) {
Radio source = connArrow.getConnection().getSource(); g.setColor(new Color(UNTRANSMITTED_COLOR_RGB[0], UNTRANSMITTED_COLOR_RGB[1], UNTRANSMITTED_COLOR_RGB[2], colorHistoryIndex));
Point sourcePoint = visualizer.transformPositionToPixel(source.getPosition()); g.drawOval(sourcePoint.x - 20, sourcePoint.y - 20, 40, 40);
for (Radio destRadio : connArrow.getConnection().getDestinations()) { g.drawOval(sourcePoint.x - 30, sourcePoint.y - 30, 60, 60);
Position destPos = destRadio.getPosition(); continue;
Point destPoint = visualizer.transformPositionToPixel(destPos); }
drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y, 8); g.setColor(new Color(TRANSMITTED_COLOR_RGB[0], TRANSMITTED_COLOR_RGB[1], TRANSMITTED_COLOR_RGB[2], colorHistoryIndex));
for (Radio destRadio : connArrow.getConnection().getDestinations()) {
Position destPos = destRadio.getPosition();
Point destPoint = visualizer.transformPositionToPixel(destPos);
drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y, 8);
}
} }
} }
} }
@Override
public void paintAfterMotes(Graphics g) { public void paintAfterMotes(Graphics g) {
} }
@Override
public Visualizer getVisualizer() { public Visualizer getVisualizer() {
return visualizer; return visualizer;
} }
private static class RadioConnectionArrow { private static class RadioConnectionArrow {
private RadioConnection conn;
private int age;
private static final int MAX_AGE = 10; private static final int MAX_AGE = 10;
private final RadioConnection conn;
private int age;
RadioConnectionArrow(RadioConnection conn) { RadioConnectionArrow(RadioConnection conn) {
this.conn = conn; this.conn = conn;
this.age = 0; this.age = 0;
} }
public void increaseAge() {
/**
* Increases age of radio connection if possible or indicates max age.
*
* @return true if max age was not reached yet, false, if max age was
* reached
*/
public boolean increaseAge() {
if (age < MAX_AGE) { if (age < MAX_AGE) {
age++; age++;
return true;
} else {
return false;
} }
} }
public int getAge() {
return age; /**
* Returns relative age of radio connection
*
* @return Relative age (0.0 - 1.0)
*/
public float getAge() {
return (float) age / (float) MAX_AGE;
} }
/**
* Returns radio connection
*
* @return radio connection
*/
public RadioConnection getConnection() { public RadioConnection getConnection() {
return conn; return conn;
} }
public int getMaxAge() {
return MAX_AGE;
}
} }
} }