tracked components shown in tooltip

This commit is contained in:
Fredrik Osterlind 2011-02-21 18:06:41 +01:00
parent 1378fd11c4
commit 148dbc7fb7
2 changed files with 176 additions and 73 deletions

View File

@ -31,22 +31,79 @@
package se.sics.mrm; package se.sics.mrm;
import java.awt.*; import java.awt.BasicStroke;
import java.awt.event.*; import java.awt.BorderLayout;
import java.awt.geom.*; import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.net.URL; import java.net.URL;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.*; import java.util.Collection;
import javax.swing.*; import java.util.Enumeration;
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JToolTip;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.ProgressMonitor;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.jdom.Element; import org.jdom.Element;
import se.sics.cooja.*; import se.sics.cooja.ClassDescription;
import se.sics.cooja.interfaces.*; import se.sics.cooja.GUI;
import se.sics.cooja.PluginType;
import se.sics.cooja.RadioConnection;
import se.sics.cooja.Simulation;
import se.sics.cooja.VisPlugin;
import se.sics.cooja.interfaces.Position;
import se.sics.cooja.interfaces.Radio;
/** /**
* The class AreaViewer belongs to the MRM package. * The class AreaViewer belongs to the MRM package.
@ -128,7 +185,7 @@ public class AreaViewer extends VisPlugin {
private boolean inSelectMode = true; private boolean inSelectMode = true;
private boolean inTrackMode = false; private boolean inTrackMode = false;
private Vector<Line2D> trackedComponents = null; private ChannelModel.TrackedSignalComponents trackedComponents = null;
// Coloring variables // Coloring variables
private JPanel coloringIntervalPanel = null; private JPanel coloringIntervalPanel = null;
@ -148,6 +205,8 @@ public class AreaViewer extends VisPlugin {
private JRadioButton noneButton = null; private JRadioButton noneButton = null;
private JRadioButton trackModeButton;
/** /**
* Initializes an AreaViewer. * Initializes an AreaViewer.
* *
@ -196,11 +255,12 @@ public class AreaViewer extends VisPlugin {
zoomModeButton.setActionCommand("set zoom mode"); zoomModeButton.setActionCommand("set zoom mode");
zoomModeButton.addActionListener(canvasModeHandler); zoomModeButton.addActionListener(canvasModeHandler);
JRadioButton trackModeButton = new JRadioButton ("track rays"); trackModeButton = new JRadioButton ("track rays");
trackModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT); trackModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
trackModeButton.setContentAreaFilled(false); trackModeButton.setContentAreaFilled(false);
trackModeButton.setActionCommand("set track rays mode"); trackModeButton.setActionCommand("set track rays mode");
trackModeButton.addActionListener(canvasModeHandler); trackModeButton.addActionListener(canvasModeHandler);
trackModeButton.setEnabled(false);
ButtonGroup group = new ButtonGroup(); ButtonGroup group = new ButtonGroup();
group.add(selectModeButton); group.add(selectModeButton);
@ -565,19 +625,36 @@ public class AreaViewer extends VisPlugin {
/** /**
* Listens to mouse event on canvas * Listens to mouse event on canvas
*/ */
private MouseListener canvasMouseHandler = new MouseListener() { private MouseAdapter canvasMouseHandler = new MouseAdapter() {
private Popup popUpToolTip = null;
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
if (popUpToolTip != null) {
popUpToolTip.hide();
popUpToolTip = null;
}
} }
public void mouseExited(MouseEvent e) {
} public void mousePressed(MouseEvent e) {
public void mouseClicked(MouseEvent e) { if (popUpToolTip != null) {
popUpToolTip.hide();
popUpToolTip = null;
}
/* Zoom & Pan */
lastHandledPosition = new Point(e.getX(), e.getY());
zoomCenterX = e.getX() / currentZoomX - currentPanX;
zoomCenterY = e.getY() / currentZoomY - currentPanY;
zoomCenterPoint = e.getPoint();
/* Select */
if (inSelectMode) { if (inSelectMode) {
Vector<Radio> hitRadios = trackClickedRadio(e.getPoint()); Vector<Radio> hitRadios = trackClickedRadio(e.getPoint());
if (hitRadios == null || hitRadios.size() == 0) { if (hitRadios == null || hitRadios.size() == 0) {
if (e.getButton() != MouseEvent.BUTTON1) { if (e.getButton() != MouseEvent.BUTTON1) {
selectedRadio = null; selectedRadio = null;
channelImage = null; channelImage = null;
trackModeButton.setEnabled(false);
canvas.repaint(); canvas.repaint();
} }
return; return;
@ -589,39 +666,47 @@ public class AreaViewer extends VisPlugin {
if (selectedRadio == null || !hitRadios.contains(selectedRadio)) { if (selectedRadio == null || !hitRadios.contains(selectedRadio)) {
selectedRadio = hitRadios.firstElement(); selectedRadio = hitRadios.firstElement();
trackModeButton.setEnabled(true);
} else { } else {
// Select next in list
selectedRadio = hitRadios.get( selectedRadio = hitRadios.get(
(hitRadios.indexOf(selectedRadio)+1) % hitRadios.size() (hitRadios.indexOf(selectedRadio)+1) % hitRadios.size()
); );
trackModeButton.setEnabled(true);
} }
channelImage = null; channelImage = null;
canvas.repaint(); canvas.repaint();
} else if (inTrackMode && selectedRadio != null) { return;
// Calculate real clicked position }
/* Track */
if (inTrackMode && selectedRadio != null) {
double realClickedX = e.getX() / currentZoomX - currentPanX; double realClickedX = e.getX() / currentZoomX - currentPanX;
double realClickedY = e.getY() / currentZoomY - currentPanY; double realClickedY = e.getY() / currentZoomY - currentPanY;
Position radioPosition = currentRadioMedium.getRadioPosition(selectedRadio); Position radioPosition = selectedRadio.getPosition();
final double radioX = radioPosition.getXCoordinate(); final double radioX = radioPosition.getXCoordinate();
final double radioY = radioPosition.getYCoordinate(); final double radioY = radioPosition.getYCoordinate();
trackedComponents = currentChannelModel.getRaysOfTransmission(radioX, radioY, realClickedX, realClickedY); trackedComponents = currentChannelModel.getRaysOfTransmission(radioX, radioY, realClickedX, realClickedY);
canvas.repaint(); canvas.repaint();
/* Show popup */
JToolTip t = AreaViewer.this.createToolTip();
String logHtml =
"<html>" +
trackedComponents.log.replace("\n", "<br>") +
"</html>";
t.setTipText(logHtml);
if (t.getTipText() == null || t.getTipText().equals("")) {
return;
}
popUpToolTip = PopupFactory.getSharedInstance().getPopup(
AreaViewer.this, t, e.getXOnScreen(), e.getYOnScreen());
popUpToolTip.show();
} }
}
public void mouseEntered(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
lastHandledPosition = new Point(e.getX(), e.getY());
// Set zoom center (real world)
zoomCenterX = e.getX() / currentZoomX - currentPanX;
zoomCenterY = e.getY() / currentZoomY - currentPanY;
zoomCenterPoint = e.getPoint();
} }
}; };
@ -1523,6 +1608,7 @@ public class AreaViewer extends VisPlugin {
// Clear selected radio (if any selected) and radio medium coverage // Clear selected radio (if any selected) and radio medium coverage
selectedRadio = null; selectedRadio = null;
channelImage = null; channelImage = null;
trackModeButton.setEnabled(false);
canvas.repaint(); canvas.repaint();
} }
}; };
@ -1616,7 +1702,7 @@ public class AreaViewer extends VisPlugin {
final double height = canvas.getHeight() / currentZoomY; final double height = canvas.getHeight() / currentZoomY;
// Get sending radio position // Get sending radio position
Position radioPosition = currentRadioMedium.getRadioPosition(selectedRadio); Position radioPosition = selectedRadio.getPosition();
final double radioX = radioPosition.getXCoordinate(); final double radioX = radioPosition.getXCoordinate();
final double radioY = radioPosition.getYCoordinate(); final double radioY = radioPosition.getYCoordinate();
@ -1990,7 +2076,7 @@ public class AreaViewer extends VisPlugin {
// Translate to real world radio position // Translate to real world radio position
Radio radio = currentRadioMedium.getRegisteredRadio(i); Radio radio = currentRadioMedium.getRegisteredRadio(i);
Position radioPosition = currentRadioMedium.getRadioPosition(radio); Position radioPosition = radio.getPosition();
g2d.translate( g2d.translate(
radioPosition.getXCoordinate(), radioPosition.getXCoordinate(),
radioPosition.getYCoordinate() radioPosition.getYCoordinate()
@ -2129,16 +2215,14 @@ public class AreaViewer extends VisPlugin {
g2d.setStroke(new BasicStroke((float) 0.0)); g2d.setStroke(new BasicStroke((float) 0.0));
Random random = new Random(); /* Do not use main random generator */ Random random = new Random(); /* Do not use main random generator */
for (int i=0; i < trackedComponents.size(); i++) { for (Line2D l: trackedComponents.components) {
g2d.setColor(new Color(255, random.nextInt(255), random.nextInt(255), 255)); g2d.setColor(new Color(255, random.nextInt(255), random.nextInt(255), 255));
Line2D originalLine = trackedComponents.get(i);
Line2D newLine = new Line2D.Double( Line2D newLine = new Line2D.Double(
originalLine.getX1()*100.0, l.getX1()*100.0,
originalLine.getY1()*100.0, l.getY1()*100.0,
originalLine.getX2()*100.0, l.getX2()*100.0,
originalLine.getY2()*100.0 l.getY2()*100.0
); );
g2d.draw(newLine); g2d.draw(newLine);
} }
} }
@ -2167,7 +2251,7 @@ public class AreaViewer extends VisPlugin {
for (int i=0; i < currentRadioMedium.getRegisteredRadioCount(); i++) { for (int i=0; i < currentRadioMedium.getRegisteredRadioCount(); i++) {
Radio testRadio = currentRadioMedium.getRegisteredRadio(i); Radio testRadio = currentRadioMedium.getRegisteredRadio(i);
Position testPosition = currentRadioMedium.getRadioPosition(testRadio); Position testPosition = testRadio.getPosition();
if (realClickedX > testPosition.getXCoordinate() - realIconHalfWidth && if (realClickedX > testPosition.getXCoordinate() - realIconHalfWidth &&
realClickedX < testPosition.getXCoordinate() + realIconHalfWidth && realClickedX < testPosition.getXCoordinate() + realIconHalfWidth &&

View File

@ -33,6 +33,7 @@ package se.sics.mrm;
import java.awt.geom.*; import java.awt.geom.*;
import java.util.*; import java.util.*;
import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultMutableTreeNode;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.jdom.Element; import org.jdom.Element;
@ -65,9 +66,13 @@ public class ChannelModel {
private ObstacleWorld myObstacleWorld = new ObstacleWorld(); private ObstacleWorld myObstacleWorld = new ObstacleWorld();
/* Log mode: visualize signal components */
private boolean logMode = false;
private StringBuilder logInfo = null;
private ArrayList<Line2D> loggedRays = null;
// Ray tracing components temporary vector // Ray tracing components temporary vector
private boolean inLoggingMode = false;
private Vector<Line2D> savedRays = null;
private Vector<Vector<Line2D>> calculatedVisibleSides = new Vector<Vector<Line2D>>(); private Vector<Vector<Line2D>> calculatedVisibleSides = new Vector<Vector<Line2D>>();
private Vector<Point2D> calculatedVisibleSidesSources = new Vector<Point2D>(); private Vector<Point2D> calculatedVisibleSidesSources = new Vector<Point2D>();
private Vector<Line2D> calculatedVisibleSidesLines = new Vector<Line2D>(); private Vector<Line2D> calculatedVisibleSidesLines = new Vector<Line2D>();
@ -1352,14 +1357,14 @@ public class ChannelModel {
// Calculate all paths from source to destination, using above calculated tree // Calculate all paths from source to destination, using above calculated tree
Vector<RayPath> allPaths = getConnectingPaths(source, dest, visibleLinesTree); Vector<RayPath> allPaths = getConnectingPaths(source, dest, visibleLinesTree);
if (inLoggingMode) { if (logMode) {
logger.info("Saved rays:"); logInfo.append("Signal components:\n");
Enumeration<RayPath> pathsEnum = allPaths.elements(); Enumeration<RayPath> pathsEnum = allPaths.elements();
while (pathsEnum.hasMoreElements()) { while (pathsEnum.hasMoreElements()) {
RayPath currentPath = pathsEnum.nextElement(); RayPath currentPath = pathsEnum.nextElement();
logger.info("* " + currentPath); logInfo.append("* " + currentPath + "\n");
for (int i=0; i < currentPath.getSubPathCount(); i++) { for (int i=0; i < currentPath.getSubPathCount(); i++) {
savedRays.add(currentPath.getSubPath(i)); loggedRays.add(currentPath.getSubPath(i));
} }
} }
} }
@ -1481,12 +1486,13 @@ public class ChannelModel {
// Using Rician fading approach, TODO Only one best signal considered - combine these? (need two limits) // Using Rician fading approach, TODO Only one best signal considered - combine these? (need two limits)
totalPathGain += Math.pow(10, pathGain[i]/10.0)*Math.cos(2*Math.PI * pathModdedLengths[i]/wavelength); totalPathGain += Math.pow(10, pathGain[i]/10.0)*Math.cos(2*Math.PI * pathModdedLengths[i]/wavelength);
if (inLoggingMode) { if (logMode) {
logger.info("Adding ray path with gain " + pathGain[i] + " and phase " + (2*Math.PI * pathModdedLengths[i]/wavelength)); logInfo.append("Signal component: " + String.format("%2.3f", pathGain[i]) + " dB, phase " + String.format("%2.3f", (2*/*Math.PI* */ pathModdedLengths[i]/wavelength)) + " pi\n");
} }
} else if (inLoggingMode) { } else if (logMode) {
/* TODO Log mode affects result? */
pathModdedLengths[i] = (pathLengths[i] - pathLengths[bestSignalNr]) % wavelength; pathModdedLengths[i] = (pathLengths[i] - pathLengths[bestSignalNr]) % wavelength;
logger.info("Not adding ray path with gain " + pathGain[i] + " and phase " + (2*Math.PI * pathModdedLengths[i]/wavelength)); logInfo.append("(IGNORED) Signal component: " + String.format("%2.3f", pathGain[i]) + " dB, phase " + String.format("%2.3f", (2*/*Math.PI* */ pathModdedLengths[i]/wavelength)) + " pi\n");
} }
} }
@ -1499,10 +1505,10 @@ public class ChannelModel {
// Convert back to dB // Convert back to dB
totalPathGain = 10*Math.log10(Math.abs(totalPathGain)); totalPathGain = 10*Math.log10(Math.abs(totalPathGain));
if (inLoggingMode) { if (logMode) {
logger.info("Total path gain:\t" + totalPathGain); logInfo.append("\nTotal path gain: " + String.format("%2.3f", totalPathGain) + " dB\n");
logger.info("Delay spread:\t" + delaySpread); logInfo.append("Delay spread: " + String.format("%2.3f", delaySpread) + "\n");
logger.info("RMS Delay spread:\t" + delaySpreadRMS); logInfo.append("RMS delay spread: " + String.format("%2.3f", delaySpreadRMS) + "\n");
} }
// - Calculate received power - // - Calculate received power -
@ -1520,8 +1526,8 @@ public class ChannelModel {
double transmitterGain = getParameterDoubleValue("tx_antenna_gain"); // TODO Should depend on angle double transmitterGain = getParameterDoubleValue("tx_antenna_gain"); // TODO Should depend on angle
double receivedPower = outputPower + systemGain + transmitterGain + totalPathGain; double receivedPower = outputPower + systemGain + transmitterGain + totalPathGain;
if (inLoggingMode) { if (logMode) {
logger.info("Resulting received signal strength:\t" + receivedPower + " (" + accumulatedVariance + ")"); logInfo.append("\nReceived signal strength: " + String.format("%2.3f", receivedPower) + " dB (variance " + accumulatedVariance + ")\n");
} }
if (dataType == TransmissionData.DELAY_SPREAD || dataType == TransmissionData.DELAY_SPREAD_RMS) { if (dataType == TransmissionData.DELAY_SPREAD || dataType == TransmissionData.DELAY_SPREAD_RMS) {
@ -1531,6 +1537,11 @@ public class ChannelModel {
return new double[] {receivedPower, accumulatedVariance}; return new double[] {receivedPower, accumulatedVariance};
} }
public class TrackedSignalComponents {
ArrayList<Line2D> components;
String log;
}
/** /**
* Returns all rays from given source to given destination if a transmission * Returns all rays from given source to given destination if a transmission
* were to be made. The resulting rays depend on the current settings and may * were to be made. The resulting rays depend on the current settings and may
@ -1540,20 +1551,26 @@ public class ChannelModel {
* @param sourceY Source position Y * @param sourceY Source position Y
* @param destX Destination position X * @param destX Destination position X
* @param destY Destination position Y * @param destY Destination position Y
* @return All resulting rays of a simulated transmission from source to destination * @return Signal components and printable description
*/ */
public Vector<Line2D> getRaysOfTransmission(double sourceX, double sourceY, double destX, double destY) { public TrackedSignalComponents getRaysOfTransmission(double sourceX, double sourceY, double destX, double destY) {
TrackedSignalComponents tsc = new TrackedSignalComponents();
// Reset current rays vector logInfo = new StringBuilder();
inLoggingMode = true; loggedRays = new ArrayList<Line2D>();
savedRays = new Vector<Line2D>();
// Calculate rays, ignore power /* TODO Include background noise? */
logMode = true;
getProbability(sourceX, sourceY, destX, destY, -Double.MAX_VALUE); getProbability(sourceX, sourceY, destX, destY, -Double.MAX_VALUE);
logMode = false;
inLoggingMode = false; tsc.log = logInfo.toString();
tsc.components = loggedRays;
return savedRays; logInfo = null;
loggedRays = null;
return tsc;
} }
/** /**
@ -1601,8 +1618,8 @@ public class ChannelModel {
snrData[0] -= noiseMean; snrData[0] -= noiseMean;
snrData[1] += noiseVariance; snrData[1] += noiseVariance;
if (inLoggingMode) { if (logMode) {
logger.info("SNR at receiver:\t" + snrData[0] + " (" + snrData[1] + ")"); logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " (variance " + snrData[1] + ")\n");
} }
return snrData; return snrData;
} }
@ -1634,9 +1651,10 @@ public class ChannelModel {
double rxSensitivity = getParameterDoubleValue("rx_sensitivity"); double rxSensitivity = getParameterDoubleValue("rx_sensitivity");
// Check signal strength against receiver sensitivity and interference // Check signal strength against receiver sensitivity and interference
if (rxSensitivity > signalStrength - snrMean && threshold < rxSensitivity + snrMean - signalStrength) { if (rxSensitivity > signalStrength - snrMean &&
if (inLoggingMode) { threshold < rxSensitivity + snrMean - signalStrength) {
logger.info("Signal to low for receiver sensitivity, increasing threshold"); if (logMode) {
logInfo.append("Weak signal: increasing threshold\n");
} }
// Keeping snr variance but increasing theshold to sensitivity // Keeping snr variance but increasing theshold to sensitivity
@ -1660,8 +1678,9 @@ public class ChannelModel {
double probReception = 1 - GaussianWrapper.cdfErrorAlgo( double probReception = 1 - GaussianWrapper.cdfErrorAlgo(
threshold, snrMean, snrStdDev); threshold, snrMean, snrStdDev);
if (inLoggingMode) { if (logMode) {
logger.info("Probability of reception: " + probReception); logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " (variance " + snrData[1] + ")\n");
logInfo.append("Reception probability: " + String.format("%1.1f%%", 100*probReception) + "\n");
} }
// Returns probabilities // Returns probabilities