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;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
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.io.File;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import javax.swing.*;
import java.util.Collection;
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 org.apache.log4j.Logger;
import org.jdom.Element;
import se.sics.cooja.*;
import se.sics.cooja.interfaces.*;
import se.sics.cooja.ClassDescription;
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.
@ -128,7 +185,7 @@ public class AreaViewer extends VisPlugin {
private boolean inSelectMode = true;
private boolean inTrackMode = false;
private Vector<Line2D> trackedComponents = null;
private ChannelModel.TrackedSignalComponents trackedComponents = null;
// Coloring variables
private JPanel coloringIntervalPanel = null;
@ -148,6 +205,8 @@ public class AreaViewer extends VisPlugin {
private JRadioButton noneButton = null;
private JRadioButton trackModeButton;
/**
* Initializes an AreaViewer.
*
@ -196,12 +255,13 @@ public class AreaViewer extends VisPlugin {
zoomModeButton.setActionCommand("set zoom mode");
zoomModeButton.addActionListener(canvasModeHandler);
JRadioButton trackModeButton = new JRadioButton ("track rays");
trackModeButton = new JRadioButton ("track rays");
trackModeButton.setAlignmentY(Component.BOTTOM_ALIGNMENT);
trackModeButton.setContentAreaFilled(false);
trackModeButton.setActionCommand("set track rays mode");
trackModeButton.addActionListener(canvasModeHandler);
trackModeButton.setEnabled(false);
ButtonGroup group = new ButtonGroup();
group.add(selectModeButton);
group.add(panModeButton);
@ -565,19 +625,36 @@ public class AreaViewer extends VisPlugin {
/**
* 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) {
if (popUpToolTip != null) {
popUpToolTip.hide();
popUpToolTip = null;
}
}
public void mouseExited(MouseEvent e) {
}
public void mouseClicked(MouseEvent e) {
public void mousePressed(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) {
Vector<Radio> hitRadios = trackClickedRadio(e.getPoint());
if (hitRadios == null || hitRadios.size() == 0) {
if (e.getButton() != MouseEvent.BUTTON1) {
selectedRadio = null;
channelImage = null;
trackModeButton.setEnabled(false);
canvas.repaint();
}
return;
@ -589,39 +666,47 @@ public class AreaViewer extends VisPlugin {
if (selectedRadio == null || !hitRadios.contains(selectedRadio)) {
selectedRadio = hitRadios.firstElement();
trackModeButton.setEnabled(true);
} else {
// Select next in list
selectedRadio = hitRadios.get(
(hitRadios.indexOf(selectedRadio)+1) % hitRadios.size()
);
trackModeButton.setEnabled(true);
}
channelImage = null;
canvas.repaint();
} else if (inTrackMode && selectedRadio != null) {
// Calculate real clicked position
return;
}
/* Track */
if (inTrackMode && selectedRadio != null) {
double realClickedX = e.getX() / currentZoomX - currentPanX;
double realClickedY = e.getY() / currentZoomY - currentPanY;
Position radioPosition = currentRadioMedium.getRadioPosition(selectedRadio);
Position radioPosition = selectedRadio.getPosition();
final double radioX = radioPosition.getXCoordinate();
final double radioY = radioPosition.getYCoordinate();
trackedComponents = currentChannelModel.getRaysOfTransmission(radioX, radioY, realClickedX, realClickedY);
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
selectedRadio = null;
channelImage = null;
trackModeButton.setEnabled(false);
canvas.repaint();
}
};
@ -1616,7 +1702,7 @@ public class AreaViewer extends VisPlugin {
final double height = canvas.getHeight() / currentZoomY;
// Get sending radio position
Position radioPosition = currentRadioMedium.getRadioPosition(selectedRadio);
Position radioPosition = selectedRadio.getPosition();
final double radioX = radioPosition.getXCoordinate();
final double radioY = radioPosition.getYCoordinate();
@ -1990,7 +2076,7 @@ public class AreaViewer extends VisPlugin {
// Translate to real world radio position
Radio radio = currentRadioMedium.getRegisteredRadio(i);
Position radioPosition = currentRadioMedium.getRadioPosition(radio);
Position radioPosition = radio.getPosition();
g2d.translate(
radioPosition.getXCoordinate(),
radioPosition.getYCoordinate()
@ -2129,16 +2215,14 @@ public class AreaViewer extends VisPlugin {
g2d.setStroke(new BasicStroke((float) 0.0));
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));
Line2D originalLine = trackedComponents.get(i);
Line2D newLine = new Line2D.Double(
originalLine.getX1()*100.0,
originalLine.getY1()*100.0,
originalLine.getX2()*100.0,
originalLine.getY2()*100.0
l.getX1()*100.0,
l.getY1()*100.0,
l.getX2()*100.0,
l.getY2()*100.0
);
g2d.draw(newLine);
}
}
@ -2167,7 +2251,7 @@ public class AreaViewer extends VisPlugin {
for (int i=0; i < currentRadioMedium.getRegisteredRadioCount(); i++) {
Radio testRadio = currentRadioMedium.getRegisteredRadio(i);
Position testPosition = currentRadioMedium.getRadioPosition(testRadio);
Position testPosition = testRadio.getPosition();
if (realClickedX > testPosition.getXCoordinate() - realIconHalfWidth &&
realClickedX < testPosition.getXCoordinate() + realIconHalfWidth &&

View file

@ -33,6 +33,7 @@ package se.sics.mrm;
import java.awt.geom.*;
import java.util.*;
import javax.swing.tree.DefaultMutableTreeNode;
import org.apache.log4j.Logger;
import org.jdom.Element;
@ -65,9 +66,13 @@ public class ChannelModel {
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
private boolean inLoggingMode = false;
private Vector<Line2D> savedRays = null;
private Vector<Vector<Line2D>> calculatedVisibleSides = new Vector<Vector<Line2D>>();
private Vector<Point2D> calculatedVisibleSidesSources = new Vector<Point2D>();
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
Vector<RayPath> allPaths = getConnectingPaths(source, dest, visibleLinesTree);
if (inLoggingMode) {
logger.info("Saved rays:");
if (logMode) {
logInfo.append("Signal components:\n");
Enumeration<RayPath> pathsEnum = allPaths.elements();
while (pathsEnum.hasMoreElements()) {
RayPath currentPath = pathsEnum.nextElement();
logger.info("* " + currentPath);
logInfo.append("* " + currentPath + "\n");
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)
totalPathGain += Math.pow(10, pathGain[i]/10.0)*Math.cos(2*Math.PI * pathModdedLengths[i]/wavelength);
if (inLoggingMode) {
logger.info("Adding ray path with gain " + pathGain[i] + " and phase " + (2*Math.PI * pathModdedLengths[i]/wavelength));
if (logMode) {
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;
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
totalPathGain = 10*Math.log10(Math.abs(totalPathGain));
if (inLoggingMode) {
logger.info("Total path gain:\t" + totalPathGain);
logger.info("Delay spread:\t" + delaySpread);
logger.info("RMS Delay spread:\t" + delaySpreadRMS);
if (logMode) {
logInfo.append("\nTotal path gain: " + String.format("%2.3f", totalPathGain) + " dB\n");
logInfo.append("Delay spread: " + String.format("%2.3f", delaySpread) + "\n");
logInfo.append("RMS delay spread: " + String.format("%2.3f", delaySpreadRMS) + "\n");
}
// - Calculate received power -
@ -1520,8 +1526,8 @@ public class ChannelModel {
double transmitterGain = getParameterDoubleValue("tx_antenna_gain"); // TODO Should depend on angle
double receivedPower = outputPower + systemGain + transmitterGain + totalPathGain;
if (inLoggingMode) {
logger.info("Resulting received signal strength:\t" + receivedPower + " (" + accumulatedVariance + ")");
if (logMode) {
logInfo.append("\nReceived signal strength: " + String.format("%2.3f", receivedPower) + " dB (variance " + accumulatedVariance + ")\n");
}
if (dataType == TransmissionData.DELAY_SPREAD || dataType == TransmissionData.DELAY_SPREAD_RMS) {
@ -1531,6 +1537,11 @@ public class ChannelModel {
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
* 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 destX Destination position X
* @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
inLoggingMode = true;
savedRays = new Vector<Line2D>();
logInfo = new StringBuilder();
loggedRays = new ArrayList<Line2D>();
// Calculate rays, ignore power
/* TODO Include background noise? */
logMode = true;
getProbability(sourceX, sourceY, destX, destY, -Double.MAX_VALUE);
logMode = false;
inLoggingMode = false;
return savedRays;
tsc.log = logInfo.toString();
tsc.components = loggedRays;
logInfo = null;
loggedRays = null;
return tsc;
}
/**
@ -1601,8 +1618,8 @@ public class ChannelModel {
snrData[0] -= noiseMean;
snrData[1] += noiseVariance;
if (inLoggingMode) {
logger.info("SNR at receiver:\t" + snrData[0] + " (" + snrData[1] + ")");
if (logMode) {
logInfo.append("\nReceived SNR: " + String.format("%2.3f", snrData[0]) + " (variance " + snrData[1] + ")\n");
}
return snrData;
}
@ -1634,9 +1651,10 @@ public class ChannelModel {
double rxSensitivity = getParameterDoubleValue("rx_sensitivity");
// Check signal strength against receiver sensitivity and interference
if (rxSensitivity > signalStrength - snrMean && threshold < rxSensitivity + snrMean - signalStrength) {
if (inLoggingMode) {
logger.info("Signal to low for receiver sensitivity, increasing threshold");
if (rxSensitivity > signalStrength - snrMean &&
threshold < rxSensitivity + snrMean - signalStrength) {
if (logMode) {
logInfo.append("Weak signal: increasing threshold\n");
}
// Keeping snr variance but increasing theshold to sensitivity
@ -1660,8 +1678,9 @@ public class ChannelModel {
double probReception = 1 - GaussianWrapper.cdfErrorAlgo(
threshold, snrMean, snrStdDev);
if (inLoggingMode) {
logger.info("Probability of reception: " + probReception);
if (logMode) {
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