removing old visualizer plugins.
(replaced by a generic visualizer with skin support)
This commit is contained in:
parent
96fbf3b853
commit
5c38c82608
|
@ -1,136 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* $Id: VisBattery.java,v 1.5 2008/10/28 15:36:25 fros4943 Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
package se.sics.cooja.plugins;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.*;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import se.sics.cooja.*;
|
|
||||||
import se.sics.cooja.interfaces.Battery;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Battery Visualizer indicates mote energy levels by painting them in
|
|
||||||
* different colors. The mote is painted in a grayscale where white is max
|
|
||||||
* energy and black is no energy left. If a mote has no battery interface or
|
|
||||||
* infinite energy, it is painted blue. If a mote is dead it is painted red.
|
|
||||||
*
|
|
||||||
* A VisBattery observers both the simulation and all mote batteries.
|
|
||||||
*
|
|
||||||
* @author Fredrik Osterlind
|
|
||||||
*/
|
|
||||||
@ClassDescription("Battery Visualizer")
|
|
||||||
@PluginType(PluginType.SIM_PLUGIN)
|
|
||||||
public class VisBattery extends Visualizer2D {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private static Logger logger = Logger.getLogger(VisBattery.class);
|
|
||||||
|
|
||||||
private Simulation simulation;
|
|
||||||
|
|
||||||
private Observer simObserver = null; // Watches simulation changes
|
|
||||||
private Observer batteryObserver = null; // Watches mote battery changes
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new battery visualizer.
|
|
||||||
*
|
|
||||||
* @param simulationToVisualize
|
|
||||||
* Simulation to visualize
|
|
||||||
*/
|
|
||||||
public VisBattery(Simulation simulationToVisualize, GUI gui) {
|
|
||||||
super(simulationToVisualize, gui);
|
|
||||||
setTitle("Battery Visualizer");
|
|
||||||
|
|
||||||
simulation = simulationToVisualize;
|
|
||||||
|
|
||||||
// Always observe all motes in simulation
|
|
||||||
batteryObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
getCurrentCanvas().repaint();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
simulation.addObserver(simObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
// Register (or reregister) as observer on all motes
|
|
||||||
for (int i = 0; i < simulation.getMotesCount(); i++) {
|
|
||||||
Battery battery = simulation.getMote(i).getInterfaces().getBattery();
|
|
||||||
if (battery != null) {
|
|
||||||
battery.addObserver(batteryObserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
simObserver.update(null, null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color[] getColorOf(Mote mote) {
|
|
||||||
if (mote.getState() == Mote.State.DEAD) {
|
|
||||||
return new Color[]{Color.RED};
|
|
||||||
}
|
|
||||||
|
|
||||||
Battery battery = mote.getInterfaces().getBattery();
|
|
||||||
if (battery == null) {
|
|
||||||
return new Color[]{Color.BLUE};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (battery.hasInfiniteEnergy()) {
|
|
||||||
return new Color[]{Color.BLUE};
|
|
||||||
}
|
|
||||||
|
|
||||||
double currentEnergy = battery.getEnergyLeftRatio();
|
|
||||||
|
|
||||||
if (currentEnergy < 0.0) {
|
|
||||||
return new Color[]{Color.RED};
|
|
||||||
}
|
|
||||||
|
|
||||||
int grayValue = (int) (255 * currentEnergy);
|
|
||||||
return new Color[]{new Color(grayValue, grayValue, grayValue)};
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closePlugin() {
|
|
||||||
if (simObserver != null) {
|
|
||||||
simulation.deleteObserver(simObserver);
|
|
||||||
|
|
||||||
// Delete all state observers
|
|
||||||
for (int i = 0; i < simulation.getMotesCount(); i++) {
|
|
||||||
Battery battery = simulation.getMote(i).getInterfaces().getBattery();
|
|
||||||
if (battery != null) {
|
|
||||||
battery.deleteObserver(batteryObserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.closePlugin();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* $Id: VisState.java,v 1.6 2009/03/10 21:20:39 fros4943 Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
package se.sics.cooja.plugins;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.*;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import se.sics.cooja.*;
|
|
||||||
import se.sics.cooja.Mote.State;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A State Visualizer indicates mote states by painting them in different colors.
|
|
||||||
* Active motes are green, sleeping motes are gray and dead motes are read.
|
|
||||||
*
|
|
||||||
* The inner color indicates the mote type.
|
|
||||||
*
|
|
||||||
* A VisState observes both the simulation and all mote states.
|
|
||||||
*
|
|
||||||
* @author Fredrik Osterlind
|
|
||||||
*/
|
|
||||||
@ClassDescription("State Visualizer")
|
|
||||||
@PluginType(PluginType.SIM_STANDARD_PLUGIN)
|
|
||||||
public class VisState extends Visualizer2D {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private static Logger logger = Logger.getLogger(VisState.class);
|
|
||||||
|
|
||||||
private Simulation simulation;
|
|
||||||
|
|
||||||
private static final Color moteTypeColors[] = new Color[] {
|
|
||||||
Color.MAGENTA,
|
|
||||||
Color.CYAN,
|
|
||||||
Color.ORANGE,
|
|
||||||
Color.GREEN,
|
|
||||||
Color.BLUE,
|
|
||||||
Color.RED,
|
|
||||||
Color.YELLOW,
|
|
||||||
};
|
|
||||||
|
|
||||||
private Observer simObserver = null; // Watches simulation changes
|
|
||||||
private Observer stateObserver = null; // Watches mote state changes
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new state visualizer.
|
|
||||||
*
|
|
||||||
* @param simulationToVisualize Simulation to visualize
|
|
||||||
*/
|
|
||||||
public VisState(Simulation simulationToVisualize, GUI gui) {
|
|
||||||
super(simulationToVisualize, gui);
|
|
||||||
setTitle("State Visualizer");
|
|
||||||
|
|
||||||
simulation = simulationToVisualize;
|
|
||||||
|
|
||||||
// Always observe all motes in simulation
|
|
||||||
stateObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
getCurrentCanvas().repaint();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
simulation.addObserver(simObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
// Register (or reregister) as observer on all motes
|
|
||||||
for (int i=0; i < simulation.getMotesCount(); i++) {
|
|
||||||
Mote mote = simulation.getMote(i);
|
|
||||||
if (mote != null) {
|
|
||||||
mote.addStateObserver(stateObserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
simObserver.update(null, null);
|
|
||||||
|
|
||||||
setLocation(
|
|
||||||
gui.getDesktopPane().getWidth() - getWidth(),
|
|
||||||
0);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color[] getColorOf(Mote mote) {
|
|
||||||
Color[] returnColors = new Color[2];
|
|
||||||
|
|
||||||
// If mote is sleeping, make outer circle blue
|
|
||||||
if (mote.getState() == Mote.State.LPM) {
|
|
||||||
returnColors[1] = Color.GRAY;
|
|
||||||
} else if (mote.getState() == State.DEAD) {
|
|
||||||
returnColors[1] = Color.RED;
|
|
||||||
} else {
|
|
||||||
returnColors[1] = Color.GREEN; // make outer circle green
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Associate different colors with different mote types
|
|
||||||
MoteType[] allTypes = simulation.getMoteTypes();
|
|
||||||
int numberOfTypes = allTypes.length;
|
|
||||||
|
|
||||||
for (int colCounter=0; colCounter < numberOfTypes && colCounter < moteTypeColors.length; colCounter++) {
|
|
||||||
if (mote.getType() == allTypes[colCounter]) {
|
|
||||||
returnColors[0] = moteTypeColors[colCounter];
|
|
||||||
return returnColors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
returnColors[0] = Color.WHITE;
|
|
||||||
return returnColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closePlugin() {
|
|
||||||
if (simObserver != null) {
|
|
||||||
simulation.deleteObserver(simObserver);
|
|
||||||
|
|
||||||
// Delete all state observers
|
|
||||||
for (int i=0; i < simulation.getMotesCount(); i++) {
|
|
||||||
Mote mote = simulation.getMote(i);
|
|
||||||
if (mote != null) {
|
|
||||||
mote.deleteStateObserver(stateObserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.closePlugin();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,239 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* $Id: VisTraffic.java,v 1.6 2007/02/28 09:50:00 fros4943 Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
package se.sics.cooja.plugins;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.*;
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import se.sics.cooja.*;
|
|
||||||
import se.sics.cooja.interfaces.Position;
|
|
||||||
import se.sics.cooja.interfaces.Radio;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Traffic Visualizer visualizes radio traffic by painting lines between
|
|
||||||
* communicating motes.
|
|
||||||
*
|
|
||||||
* A VisTraffic observers the current simulation radio medium.
|
|
||||||
*
|
|
||||||
* @author Fredrik Osterlind
|
|
||||||
*/
|
|
||||||
@ClassDescription("Traffic Visualizer")
|
|
||||||
@PluginType(PluginType.SIM_PLUGIN)
|
|
||||||
public class VisTraffic extends Visualizer2D {
|
|
||||||
protected boolean USE_ALPHA = false;
|
|
||||||
|
|
||||||
protected boolean USE_HISTORY = true;
|
|
||||||
|
|
||||||
protected int MAX_PAINTED_CONNS = 50;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(VisTraffic.class);
|
|
||||||
|
|
||||||
private RadioMedium radioMedium;
|
|
||||||
|
|
||||||
public Vector<PaintedConnection> allPaintedConnections = new Vector<PaintedConnection>();
|
|
||||||
|
|
||||||
private Simulation simulation;
|
|
||||||
|
|
||||||
private Observer radioObserver = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new VisTraffic visualizer.
|
|
||||||
*
|
|
||||||
* @param simulationToVisualize
|
|
||||||
* Simulation to visualize
|
|
||||||
*/
|
|
||||||
public VisTraffic(Simulation simulationToVisualize, GUI gui) {
|
|
||||||
super(simulationToVisualize, gui);
|
|
||||||
setTitle("Traffic Visualizer");
|
|
||||||
simulation = simulationToVisualize;
|
|
||||||
|
|
||||||
radioMedium = simulationToVisualize.getRadioMedium();
|
|
||||||
|
|
||||||
// Listen to radio medium and paint any new data transfers
|
|
||||||
simulationToVisualize.getRadioMedium().addRadioMediumObserver(
|
|
||||||
radioObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
if (radioMedium == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
final RadioConnection[] connsToAdd = radioMedium
|
|
||||||
.getLastTickConnections();
|
|
||||||
if (connsToAdd != null && connsToAdd.length > 0) {
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (!USE_HISTORY)
|
|
||||||
allPaintedConnections.clear();
|
|
||||||
|
|
||||||
for (RadioConnection conn : connsToAdd) {
|
|
||||||
if (conn != null) {
|
|
||||||
Color connColor = getColorOf(conn);
|
|
||||||
int duration = getDurationOf(conn);
|
|
||||||
if (connColor != null && duration > 0)
|
|
||||||
allPaintedConnections.add(0, new PaintedConnection(
|
|
||||||
conn, duration, connColor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentCanvas().repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Paints given connection on given graphics.
|
|
||||||
*
|
|
||||||
* @param connection
|
|
||||||
* Connection
|
|
||||||
* @param g2d
|
|
||||||
* Graphics to paint on
|
|
||||||
*/
|
|
||||||
protected void paintConnection(PaintedConnection connection, Graphics g2d) {
|
|
||||||
Point sourcePixelPosition = transformPositionToPixel(connection.radioConnection.getSource().getPosition());
|
|
||||||
g2d.setColor(connection.getColor(simulation.isRunning()));
|
|
||||||
for (Radio destRadio : connection.radioConnection.getDestinations()) {
|
|
||||||
Position destPosition = destRadio.getPosition();
|
|
||||||
Point destPixelPosition = transformPositionToPixel(destPosition);
|
|
||||||
g2d.drawLine(sourcePixelPosition.x, sourcePixelPosition.y,
|
|
||||||
destPixelPosition.x, destPixelPosition.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns color the given connection should be painted in. If returned color
|
|
||||||
* is null, the connection will not be painted.
|
|
||||||
*
|
|
||||||
* @param connection
|
|
||||||
* Connection
|
|
||||||
* @return Color
|
|
||||||
*/
|
|
||||||
protected Color getColorOf(RadioConnection connection) {
|
|
||||||
return Color.BLACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns duration the given connection should be visible. If negative, the
|
|
||||||
* connection will not be painted. Observe that the duration is the number of
|
|
||||||
* repaints, not related to time.
|
|
||||||
*
|
|
||||||
* @param connection
|
|
||||||
* Connection
|
|
||||||
* @return Duration in repaints
|
|
||||||
*/
|
|
||||||
protected int getDurationOf(RadioConnection connection) {
|
|
||||||
return 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closePlugin() {
|
|
||||||
super.closePlugin();
|
|
||||||
|
|
||||||
// Remove radio observer
|
|
||||||
radioMedium.deleteRadioMediumObserver(radioObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color[] getColorOf(Mote m) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void visualizeSimulation(Graphics g) {
|
|
||||||
|
|
||||||
// Clean up old connections
|
|
||||||
Vector<PaintedConnection> newPaintedConnections = new Vector<PaintedConnection>();
|
|
||||||
for (PaintedConnection conn : allPaintedConnections)
|
|
||||||
if (!conn.shouldBeRemoved())
|
|
||||||
newPaintedConnections.add(conn);
|
|
||||||
allPaintedConnections = newPaintedConnections;
|
|
||||||
if (allPaintedConnections.size() > MAX_PAINTED_CONNS)
|
|
||||||
allPaintedConnections.setSize(MAX_PAINTED_CONNS);
|
|
||||||
|
|
||||||
for (PaintedConnection conn : allPaintedConnections)
|
|
||||||
paintConnection(conn, (Graphics2D) g);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PaintedConnection {
|
|
||||||
public RadioConnection radioConnection;
|
|
||||||
|
|
||||||
private int duration;
|
|
||||||
|
|
||||||
private int colorVal;
|
|
||||||
|
|
||||||
private int repaintsLeft;
|
|
||||||
|
|
||||||
private Color staticColor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param conn
|
|
||||||
* Radio connection to visualize
|
|
||||||
* @param duration
|
|
||||||
* Number of repaints
|
|
||||||
* @param color
|
|
||||||
* Base color of painted connection
|
|
||||||
*/
|
|
||||||
public PaintedConnection(RadioConnection conn, int duration, Color color) {
|
|
||||||
radioConnection = conn;
|
|
||||||
colorVal = color.getRGB() & 0xffffff;
|
|
||||||
repaintsLeft = duration;
|
|
||||||
this.duration = duration;
|
|
||||||
staticColor = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get color this connection should be painted in.
|
|
||||||
*
|
|
||||||
* @param isRunning
|
|
||||||
* True if current simulation is running
|
|
||||||
* @return Color
|
|
||||||
*/
|
|
||||||
public Color getColor(boolean isRunning) {
|
|
||||||
if (isRunning)
|
|
||||||
repaintsLeft--;
|
|
||||||
|
|
||||||
if (!USE_ALPHA)
|
|
||||||
return staticColor;
|
|
||||||
|
|
||||||
int alpha = 127 + 128 * repaintsLeft / duration;
|
|
||||||
return new Color(colorVal | (alpha << 24), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldBeRemoved() {
|
|
||||||
return repaintsLeft <= 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,345 +0,0 @@
|
||||||
package se.sics.cooja.plugins;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.Point;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.awt.event.MouseListener;
|
|
||||||
import java.util.Observable;
|
|
||||||
import java.util.Observer;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import javax.swing.JSpinner;
|
|
||||||
import javax.swing.SpinnerNumberModel;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
|
|
||||||
import se.sics.cooja.ClassDescription;
|
|
||||||
import se.sics.cooja.GUI;
|
|
||||||
import se.sics.cooja.Mote;
|
|
||||||
import se.sics.cooja.PluginType;
|
|
||||||
import se.sics.cooja.RadioConnection;
|
|
||||||
import se.sics.cooja.Simulation;
|
|
||||||
import se.sics.cooja.contikimote.interfaces.ContikiRadio;
|
|
||||||
import se.sics.cooja.interfaces.Position;
|
|
||||||
import se.sics.cooja.interfaces.Radio;
|
|
||||||
import se.sics.cooja.plugins.Visualizer2D;
|
|
||||||
import se.sics.cooja.radiomediums.UDGM;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visualizes radio traffic in the UDGM radio medium.
|
|
||||||
* Allows a user to change the collective TX/interference ranges,
|
|
||||||
* and the TX/RX success ratio.
|
|
||||||
*
|
|
||||||
* Sending motes are blue, receiving motes are green and motes that hear noise
|
|
||||||
* are painted red. Motes without radios are painted gray, and the rest are
|
|
||||||
* white.
|
|
||||||
*
|
|
||||||
* @author Fredrik Osterlind
|
|
||||||
*/
|
|
||||||
@ClassDescription("UDGM Visualizer")
|
|
||||||
@PluginType(PluginType.SIM_PLUGIN)
|
|
||||||
public class VisUDGM extends Visualizer2D {
|
|
||||||
private JSpinner txRangeSpinner = null;
|
|
||||||
private JSpinner interferenceRangeSpinner = null;
|
|
||||||
private JSpinner successRatioTxSpinner = null;
|
|
||||||
private JSpinner successRatioRxSpinner = null;
|
|
||||||
|
|
||||||
private UDGM radioMedium = null;
|
|
||||||
private Observer radioMediumObserver;
|
|
||||||
|
|
||||||
private Mote selectedMote = null;
|
|
||||||
|
|
||||||
private class RangeMenuAction implements MoteMenuAction {
|
|
||||||
public boolean isEnabled(Mote mote) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription(Mote mote) {
|
|
||||||
return "Change transmission ranges";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doAction(Mote mote) {
|
|
||||||
txRangeSpinner.setVisible(true);
|
|
||||||
interferenceRangeSpinner.setVisible(true);
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private class SuccessRatioMenuAction implements MoteMenuAction {
|
|
||||||
public boolean isEnabled(Mote mote) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription(Mote mote) {
|
|
||||||
return "Change transmission success ratio";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void doAction(Mote mote) {
|
|
||||||
successRatioTxSpinner.setVisible(true);
|
|
||||||
successRatioRxSpinner.setVisible(true);
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public VisUDGM(Simulation sim, GUI gui) {
|
|
||||||
super(sim, gui);
|
|
||||||
setTitle("UDGM Visualizer");
|
|
||||||
|
|
||||||
radioMedium = (UDGM) sim.getRadioMedium();
|
|
||||||
|
|
||||||
// Create spinners for changing ranges
|
|
||||||
SpinnerNumberModel transmissionModel = new SpinnerNumberModel();
|
|
||||||
transmissionModel.setValue(new Double(radioMedium.TRANSMITTING_RANGE));
|
|
||||||
transmissionModel.setStepSize(new Double(1.0)); // 1m
|
|
||||||
transmissionModel.setMinimum(new Double(0.0));
|
|
||||||
|
|
||||||
SpinnerNumberModel interferenceModel = new SpinnerNumberModel();
|
|
||||||
interferenceModel.setValue(new Double(radioMedium.INTERFERENCE_RANGE));
|
|
||||||
interferenceModel.setStepSize(new Double(1.0)); // 1m
|
|
||||||
interferenceModel.setMinimum(new Double(0.0));
|
|
||||||
|
|
||||||
SpinnerNumberModel successRatioTxModel = new SpinnerNumberModel();
|
|
||||||
successRatioTxModel.setValue(new Double(radioMedium.SUCCESS_RATIO_TX));
|
|
||||||
successRatioTxModel.setStepSize(new Double(0.001)); // 0.1%
|
|
||||||
successRatioTxModel.setMinimum(new Double(0.0));
|
|
||||||
successRatioTxModel.setMaximum(new Double(1.0));
|
|
||||||
|
|
||||||
SpinnerNumberModel successRatioRxModel = new SpinnerNumberModel();
|
|
||||||
successRatioRxModel.setValue(new Double(radioMedium.SUCCESS_RATIO_RX));
|
|
||||||
successRatioRxModel.setStepSize(new Double(0.001)); // 0.1%
|
|
||||||
successRatioRxModel.setMinimum(new Double(0.0));
|
|
||||||
successRatioRxModel.setMaximum(new Double(1.0));
|
|
||||||
|
|
||||||
JSpinner.NumberEditor editor;
|
|
||||||
txRangeSpinner = new JSpinner(transmissionModel);
|
|
||||||
editor = new JSpinner.NumberEditor(txRangeSpinner, "0m");
|
|
||||||
txRangeSpinner.setEditor(editor);
|
|
||||||
interferenceRangeSpinner = new JSpinner(interferenceModel);
|
|
||||||
editor = new JSpinner.NumberEditor(interferenceRangeSpinner, "0m");
|
|
||||||
interferenceRangeSpinner.setEditor(editor);
|
|
||||||
successRatioTxSpinner = new JSpinner(successRatioTxModel);
|
|
||||||
editor = new JSpinner.NumberEditor(successRatioTxSpinner, "0.0%");
|
|
||||||
successRatioTxSpinner.setEditor(editor);
|
|
||||||
successRatioRxSpinner = new JSpinner(successRatioRxModel);
|
|
||||||
editor = new JSpinner.NumberEditor(successRatioRxSpinner, "0.0%");
|
|
||||||
successRatioRxSpinner.setEditor(editor);
|
|
||||||
|
|
||||||
|
|
||||||
((JSpinner.DefaultEditor) txRangeSpinner.getEditor()).getTextField().setColumns(5);
|
|
||||||
((JSpinner.DefaultEditor) interferenceRangeSpinner.getEditor()).getTextField().setColumns(5);
|
|
||||||
((JSpinner.DefaultEditor) successRatioTxSpinner.getEditor()).getTextField().setColumns(5);
|
|
||||||
((JSpinner.DefaultEditor) successRatioRxSpinner.getEditor()).getTextField().setColumns(5);
|
|
||||||
txRangeSpinner.setToolTipText("Transmitting range (m)");
|
|
||||||
interferenceRangeSpinner.setToolTipText("Interference range (m)");
|
|
||||||
successRatioTxSpinner.setToolTipText("Transmission success ratio (%)");
|
|
||||||
successRatioRxSpinner.setToolTipText("Reception success ratio (%)");
|
|
||||||
|
|
||||||
txRangeSpinner.addChangeListener(new ChangeListener() {
|
|
||||||
public void stateChanged(ChangeEvent e) {
|
|
||||||
radioMedium.TRANSMITTING_RANGE = ((SpinnerNumberModel)
|
|
||||||
txRangeSpinner.getModel()).getNumber().doubleValue();
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
interferenceRangeSpinner.addChangeListener(new ChangeListener() {
|
|
||||||
public void stateChanged(ChangeEvent e) {
|
|
||||||
radioMedium.INTERFERENCE_RANGE = ((SpinnerNumberModel)
|
|
||||||
interferenceRangeSpinner.getModel()).getNumber().doubleValue();
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
successRatioTxSpinner.addChangeListener(new ChangeListener() {
|
|
||||||
public void stateChanged(ChangeEvent e) {
|
|
||||||
radioMedium.SUCCESS_RATIO_TX = ((SpinnerNumberModel)
|
|
||||||
successRatioTxSpinner.getModel()).getNumber().doubleValue();
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
successRatioRxSpinner.addChangeListener(new ChangeListener() {
|
|
||||||
public void stateChanged(ChangeEvent e) {
|
|
||||||
radioMedium.SUCCESS_RATIO_RX = ((SpinnerNumberModel)
|
|
||||||
successRatioRxSpinner.getModel()).getNumber().doubleValue();
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
getCurrentCanvas().add(txRangeSpinner);
|
|
||||||
getCurrentCanvas().add(interferenceRangeSpinner);
|
|
||||||
getCurrentCanvas().add(successRatioTxSpinner);
|
|
||||||
getCurrentCanvas().add(successRatioRxSpinner);
|
|
||||||
|
|
||||||
txRangeSpinner.setVisible(false);
|
|
||||||
interferenceRangeSpinner.setVisible(false);
|
|
||||||
successRatioTxSpinner.setVisible(false);
|
|
||||||
successRatioRxSpinner.setVisible(false);
|
|
||||||
|
|
||||||
/* Enable user to select mote by mouse click */
|
|
||||||
getCurrentCanvas().addMouseListener(new MouseListener() {
|
|
||||||
public void mouseExited(MouseEvent e) { }
|
|
||||||
public void mouseEntered(MouseEvent e) { }
|
|
||||||
public void mouseReleased(MouseEvent e) { }
|
|
||||||
public void mouseClicked(MouseEvent e) { }
|
|
||||||
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
Vector<Mote> clickedMotes = findMotesAtPosition(e.getX(), e.getY());
|
|
||||||
if (clickedMotes == null || clickedMotes.size() == 0) {
|
|
||||||
selectedMote = null;
|
|
||||||
txRangeSpinner.setVisible(false);
|
|
||||||
interferenceRangeSpinner.setVisible(false);
|
|
||||||
successRatioTxSpinner.setVisible(false);
|
|
||||||
successRatioRxSpinner.setVisible(false);
|
|
||||||
repaint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Several motes may have been clicked: select another one */
|
|
||||||
if (clickedMotes.contains(selectedMote)) {
|
|
||||||
int pos = clickedMotes.indexOf(selectedMote);
|
|
||||||
if (pos < clickedMotes.size() - 1) {
|
|
||||||
selectedMote = clickedMotes.get(pos + 1);
|
|
||||||
} else {
|
|
||||||
selectedMote = clickedMotes.firstElement();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
selectedMote = clickedMotes.firstElement();
|
|
||||||
}
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register change ranges and change success ratio action
|
|
||||||
addMoteMenuAction(new RangeMenuAction());
|
|
||||||
addMoteMenuAction(new SuccessRatioMenuAction());
|
|
||||||
|
|
||||||
// Observe radio medium
|
|
||||||
radioMedium.addRadioMediumObserver(radioMediumObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
getCurrentCanvas().repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closePlugin() {
|
|
||||||
super.closePlugin();
|
|
||||||
radioMedium.deleteRadioMediumObserver(radioMediumObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color[] getColorOf(Mote mote) {
|
|
||||||
Radio moteRadio = mote.getInterfaces().getRadio();
|
|
||||||
if (moteRadio == null) {
|
|
||||||
return new Color[] { Color.BLACK };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mote.getState() == Mote.State.DEAD) {
|
|
||||||
return new Color[] { Color.BLACK };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedMote != null && mote == selectedMote) {
|
|
||||||
return new Color[] { Color.CYAN };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moteRadio instanceof ContikiRadio && !((ContikiRadio) moteRadio).isOn()) {
|
|
||||||
return new Color[] { Color.GRAY };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moteRadio.isTransmitting()) {
|
|
||||||
return new Color[] { Color.BLUE };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moteRadio.isInterfered()) {
|
|
||||||
return new Color[] { Color.RED };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moteRadio.isReceiving()) {
|
|
||||||
return new Color[] { Color.GREEN };
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Color[] { Color.WHITE };
|
|
||||||
}
|
|
||||||
|
|
||||||
public void visualizeSimulation(Graphics g) {
|
|
||||||
|
|
||||||
/* Paint transmission and interference range for select mote */
|
|
||||||
if (selectedMote != null) {
|
|
||||||
Position motePos = selectedMote.getInterfaces().getPosition();
|
|
||||||
|
|
||||||
Point pixelCoord = transformPositionToPixel(motePos);
|
|
||||||
int x = pixelCoord.x;
|
|
||||||
int y = pixelCoord.y;
|
|
||||||
|
|
||||||
// Fetch current output power indicator (scale with as percent)
|
|
||||||
if (selectedMote.getInterfaces().getRadio() != null) {
|
|
||||||
Radio selectedRadio = selectedMote.getInterfaces().getRadio();
|
|
||||||
double moteInterferenceRange =
|
|
||||||
radioMedium.INTERFERENCE_RANGE
|
|
||||||
* ((double) selectedRadio.getCurrentOutputPowerIndicator()
|
|
||||||
/ (double) selectedRadio.getOutputPowerIndicatorMax());
|
|
||||||
double moteTransmissionRange =
|
|
||||||
radioMedium.TRANSMITTING_RANGE
|
|
||||||
* ((double) selectedRadio.getCurrentOutputPowerIndicator()
|
|
||||||
/ (double) selectedRadio.getOutputPowerIndicatorMax());
|
|
||||||
|
|
||||||
Point translatedZero = transformPositionToPixel(0.0, 0.0, 0.0);
|
|
||||||
Point translatedInterference = transformPositionToPixel(moteInterferenceRange, moteInterferenceRange, 0.0);
|
|
||||||
Point translatedTransmission = transformPositionToPixel(moteTransmissionRange, moteTransmissionRange, 0.0);
|
|
||||||
|
|
||||||
translatedInterference.x = Math.abs(translatedInterference.x - translatedZero.x);
|
|
||||||
translatedInterference.y = Math.abs(translatedInterference.y - translatedZero.y);
|
|
||||||
translatedTransmission.x = Math.abs(translatedTransmission.x - translatedZero.x);
|
|
||||||
translatedTransmission.y = Math.abs(translatedTransmission.y - translatedZero.y);
|
|
||||||
|
|
||||||
// Interference
|
|
||||||
g.setColor(Color.DARK_GRAY);
|
|
||||||
g.fillOval(
|
|
||||||
x - translatedInterference.x,
|
|
||||||
y - translatedInterference.y,
|
|
||||||
2 * translatedInterference.x,
|
|
||||||
2 * translatedInterference.y);
|
|
||||||
|
|
||||||
// Transmission
|
|
||||||
g.setColor(Color.GREEN);
|
|
||||||
g.fillOval(
|
|
||||||
x - translatedTransmission.x,
|
|
||||||
y - translatedTransmission.y,
|
|
||||||
2 * translatedTransmission.x,
|
|
||||||
2 * translatedTransmission.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let parent paint motes
|
|
||||||
super.visualizeSimulation(g);
|
|
||||||
|
|
||||||
/* Paint active connections in black */
|
|
||||||
RadioConnection[] conns = radioMedium.getActiveConnections();
|
|
||||||
if (conns != null) {
|
|
||||||
g.setColor(Color.BLACK);
|
|
||||||
for (RadioConnection conn : conns) {
|
|
||||||
Point sourcePoint = transformPositionToPixel(conn.getSource().getPosition());
|
|
||||||
for (Radio destRadio : conn.getDestinations()) {
|
|
||||||
Position destPos = destRadio.getPosition();
|
|
||||||
Point destPoint = transformPositionToPixel(destPos);
|
|
||||||
g.drawLine(sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Paint past connections in gray */
|
|
||||||
conns = radioMedium.getLastTickConnections();
|
|
||||||
if (conns != null) {
|
|
||||||
g.setColor(Color.GRAY);
|
|
||||||
for (RadioConnection conn : conns) {
|
|
||||||
Point sourcePoint = transformPositionToPixel(conn.getSource().getPosition());
|
|
||||||
for (Radio dest : conn.getDestinations()) {
|
|
||||||
Position destPos = dest.getPosition();
|
|
||||||
Point destPoint = transformPositionToPixel(destPos);
|
|
||||||
g.drawLine(sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,879 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* $Id: Visualizer2D.java,v 1.16 2009/02/26 13:29:30 fros4943 Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
package se.sics.cooja.plugins;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.datatransfer.DataFlavor;
|
|
||||||
import java.awt.datatransfer.Transferable;
|
|
||||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
|
||||||
import java.awt.dnd.DnDConstants;
|
|
||||||
import java.awt.dnd.DropTarget;
|
|
||||||
import java.awt.dnd.DropTargetDragEvent;
|
|
||||||
import java.awt.dnd.DropTargetDropEvent;
|
|
||||||
import java.awt.dnd.DropTargetEvent;
|
|
||||||
import java.awt.dnd.DropTargetListener;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.Timer;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import se.sics.cooja.*;
|
|
||||||
import se.sics.cooja.GUI.MoteRelation;
|
|
||||||
import se.sics.cooja.interfaces.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visualizer2D is an abstract mote visualizer for simulations. All motes are
|
|
||||||
* painted in the XY-plane, as seen from positive Z axis.
|
|
||||||
*
|
|
||||||
* An implementation of this class must colorize the different motes, each mote
|
|
||||||
* has two different colors; inner and outer.
|
|
||||||
*
|
|
||||||
* By right-clicking the mouse on a mote a popup menu will be displayed. From
|
|
||||||
* this menu mote plugins can be started. or the mote can be moved. Each
|
|
||||||
* implementation may also register its own actions to be accessed from this
|
|
||||||
* menu.
|
|
||||||
*
|
|
||||||
* A Visualizer2D observers both the simulation and all mote positions.
|
|
||||||
*
|
|
||||||
* @author Fredrik Osterlind
|
|
||||||
*/
|
|
||||||
@ClassDescription("2D Mote Visualizer")
|
|
||||||
@PluginType(PluginType.SIM_PLUGIN)
|
|
||||||
public abstract class Visualizer2D extends VisPlugin {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private static Logger logger = Logger.getLogger(Visualizer2D.class);
|
|
||||||
|
|
||||||
private double factorXCoordToPixel;
|
|
||||||
private double factorYCoordToPixel;
|
|
||||||
private double smallestXCoord;
|
|
||||||
private double smallestYCoord;
|
|
||||||
|
|
||||||
private GUI myGUI = null;
|
|
||||||
private Simulation simulation = null;
|
|
||||||
private final JPanel canvas;
|
|
||||||
private Visualizer2D myPlugin;
|
|
||||||
|
|
||||||
private static final int CANVAS_BORDER_WIDTH = 25;
|
|
||||||
private static final int MOTE_RADIUS = 8;
|
|
||||||
|
|
||||||
private boolean moteIsBeingMoved = false;
|
|
||||||
private long moteMoveBeginTime = -1;
|
|
||||||
private Mote moteToMove = null;
|
|
||||||
private Cursor moveCursor = new Cursor(Cursor.MOVE_CURSOR);
|
|
||||||
|
|
||||||
private Observer simObserver = null; // Watches simulation changes
|
|
||||||
private Observer posObserver = null; // Watches position changes
|
|
||||||
|
|
||||||
private Observer moteHighligtObserver = null;
|
|
||||||
private Observer moteRelationsObserver = null;
|
|
||||||
private Mote highlightedMote = null;
|
|
||||||
private Color highlightColor = Color.GRAY;
|
|
||||||
private Timer highlightTimer = null;
|
|
||||||
|
|
||||||
public interface MoteMenuAction {
|
|
||||||
public boolean isEnabled(Mote mote);
|
|
||||||
public String getDescription(Mote mote);
|
|
||||||
public void doAction(Mote mote);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MoveMoteMenuAction implements MoteMenuAction {
|
|
||||||
public boolean isEnabled(Mote mote) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public String getDescription(Mote mote) {
|
|
||||||
return "Move " + mote;
|
|
||||||
}
|
|
||||||
public void doAction(Mote mote) {
|
|
||||||
moteMoveBeginTime = -1;
|
|
||||||
beginMoveRequest(mote);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private class ButtonClickMoteMenuAction implements MoteMenuAction {
|
|
||||||
public boolean isEnabled(Mote mote) {
|
|
||||||
return mote.getInterfaces().getButton() != null
|
|
||||||
&& !mote.getInterfaces().getButton().isPressed();
|
|
||||||
}
|
|
||||||
public String getDescription(Mote mote) {
|
|
||||||
return "Click button on " + mote;
|
|
||||||
}
|
|
||||||
public void doAction(Mote mote) {
|
|
||||||
mote.getInterfaces().getButton().clickButton();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private class DeleteMoteMenuAction implements MoteMenuAction {
|
|
||||||
public boolean isEnabled(Mote mote) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public String getDescription(Mote mote) {
|
|
||||||
return "Delete " + mote;
|
|
||||||
}
|
|
||||||
public void doAction(Mote mote) {
|
|
||||||
simulation.removeMote(mote);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private class ShowLEDMoteMenuAction implements MoteMenuAction {
|
|
||||||
public boolean isEnabled(Mote mote) {
|
|
||||||
return mote.getInterfaces().getLED() != null;
|
|
||||||
}
|
|
||||||
public String getDescription(Mote mote) {
|
|
||||||
return "Show LEDs on " + mote;
|
|
||||||
}
|
|
||||||
public void doAction(Mote mote) {
|
|
||||||
LED led = mote.getInterfaces().getLED();
|
|
||||||
if (led == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract description (input to plugin) */
|
|
||||||
String desc = GUI.getDescriptionOf(mote.getInterfaces().getLED());
|
|
||||||
|
|
||||||
MoteInterfaceViewer viewer =
|
|
||||||
(MoteInterfaceViewer) simulation.getGUI().startPlugin(
|
|
||||||
MoteInterfaceViewer.class,
|
|
||||||
simulation.getGUI(),
|
|
||||||
simulation,
|
|
||||||
mote);
|
|
||||||
viewer.setSelectedInterface(desc);
|
|
||||||
viewer.pack();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private class ShowSerialMoteMenuAction implements MoteMenuAction {
|
|
||||||
public boolean isEnabled(Mote mote) {
|
|
||||||
SerialPort serialPort = null;
|
|
||||||
for (MoteInterface intf: mote.getInterfaces().getInterfaces()) {
|
|
||||||
try {
|
|
||||||
/* Try casting to serial port */
|
|
||||||
serialPort = (SerialPort) intf;
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public String getDescription(Mote mote) {
|
|
||||||
return "Show serial port on " + mote;
|
|
||||||
}
|
|
||||||
public void doAction(Mote mote) {
|
|
||||||
SerialPort serialPort = null;
|
|
||||||
for (MoteInterface intf: mote.getInterfaces().getInterfaces()) {
|
|
||||||
try {
|
|
||||||
/* Try casting to serial port */
|
|
||||||
serialPort = (SerialPort) intf;
|
|
||||||
break;
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serialPort == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract description (input to plugin) */
|
|
||||||
String desc = GUI.getDescriptionOf(serialPort);
|
|
||||||
|
|
||||||
MoteInterfaceViewer viewer =
|
|
||||||
(MoteInterfaceViewer) simulation.getGUI().startPlugin(
|
|
||||||
MoteInterfaceViewer.class,
|
|
||||||
simulation.getGUI(),
|
|
||||||
simulation,
|
|
||||||
mote);
|
|
||||||
viewer.setSelectedInterface(desc);
|
|
||||||
viewer.pack();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private Vector<MoteMenuAction> menuActions = new Vector<MoteMenuAction>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers as an simulation observer and initializes the canvas.
|
|
||||||
*
|
|
||||||
* @param simulationToVisualize
|
|
||||||
* Simulation to visualize
|
|
||||||
*/
|
|
||||||
public Visualizer2D(Simulation simulationToVisualize, GUI gui) {
|
|
||||||
super("Visualizer2D", gui);
|
|
||||||
|
|
||||||
myGUI = gui;
|
|
||||||
myPlugin = this;
|
|
||||||
|
|
||||||
// Set initial bounds of frame
|
|
||||||
this.setBounds(150, 150, 300, 300);
|
|
||||||
setVisible(true);
|
|
||||||
|
|
||||||
simulation = simulationToVisualize;
|
|
||||||
|
|
||||||
// Create "canvas" to paint on
|
|
||||||
canvas = new JPanel() {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
public void paintComponent(Graphics g) {
|
|
||||||
super.paintComponent(g);
|
|
||||||
visualizeSimulation(g);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
canvas.setPreferredSize(new Dimension(getSize().width - 16,
|
|
||||||
getSize().height - 38));
|
|
||||||
canvas.setBorder(BorderFactory.createLineBorder(Color.GREEN, 2));
|
|
||||||
canvas.setBackground(Color.WHITE);
|
|
||||||
calculateTransformations();
|
|
||||||
|
|
||||||
this.setContentPane(canvas);
|
|
||||||
|
|
||||||
// Detect general simulation changes
|
|
||||||
posObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
calculateTransformations();
|
|
||||||
canvas.repaint();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
simulation.addObserver(simObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
canvas.setPreferredSize(new Dimension(getSize().width - 16,
|
|
||||||
getSize().height - 38));
|
|
||||||
|
|
||||||
// Register (or reregister) as observer on all mote positions
|
|
||||||
for (int i = 0; i < simulation.getMotesCount(); i++) {
|
|
||||||
Position posIntf = simulation.getMote(i).getInterfaces()
|
|
||||||
.getPosition();
|
|
||||||
if (posIntf != null) {
|
|
||||||
posIntf.addObserver(posObserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
calculateTransformations();
|
|
||||||
canvas.repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
simObserver.update(null, null);
|
|
||||||
|
|
||||||
// Detect mote highligts
|
|
||||||
myGUI.addMoteHighlightObserver(moteHighligtObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
if (!(obj instanceof Mote)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (highlightTimer != null && highlightTimer.isRunning()) {
|
|
||||||
highlightTimer.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
highlightTimer = new Timer(100, null);
|
|
||||||
highlightedMote = (Mote) obj;
|
|
||||||
highlightTimer.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
// Decrease delay
|
|
||||||
if (highlightTimer.getDelay() < 90) {
|
|
||||||
highlightTimer.stop();
|
|
||||||
highlightedMote = null;
|
|
||||||
repaint();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toggle color
|
|
||||||
if (highlightColor == Color.GRAY) {
|
|
||||||
highlightColor = Color.CYAN;
|
|
||||||
} else {
|
|
||||||
highlightColor = Color.GRAY;
|
|
||||||
}
|
|
||||||
highlightTimer.setDelay(highlightTimer.getDelay()-1);
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
highlightTimer.start();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Paint mote relations */
|
|
||||||
myGUI.addMoteRelationsObserver(moteRelationsObserver = new Observer() {
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
canvas.addMouseMotionListener(new MouseMotionListener() {
|
|
||||||
public void mouseMoved(MouseEvent e) {
|
|
||||||
myPlugin.handleMoveRequest(e.getPoint().x, e.getPoint().y, false);
|
|
||||||
}
|
|
||||||
public void mouseDragged(MouseEvent e) {
|
|
||||||
myPlugin.handleMoveRequest(e.getPoint().x, e.getPoint().y, false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Detect mouse events
|
|
||||||
canvas.addMouseListener(new MouseListener() {
|
|
||||||
public void mousePressed(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y);
|
|
||||||
} else if (SwingUtilities.isLeftMouseButton(e)){
|
|
||||||
//myPlugin.handleMoveRequest(e.getPoint().x, e.getPoint().y, false);
|
|
||||||
beginMoveRequest(e.getPoint().x, e.getPoint().y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void mouseReleased(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y);
|
|
||||||
} else {
|
|
||||||
myPlugin.handleMoveRequest(e.getPoint().x, e.getPoint().y, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void mouseEntered(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void mouseExited(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void mouseClicked(MouseEvent e) {
|
|
||||||
if (e.isPopupTrigger()) {
|
|
||||||
myPlugin.handlePopupRequest(e.getPoint().x, e.getPoint().y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Detect component events
|
|
||||||
addComponentListener(new ComponentListener() {
|
|
||||||
public void componentMoved(ComponentEvent ce) {
|
|
||||||
// NOP
|
|
||||||
}
|
|
||||||
public void componentShown(ComponentEvent ce) {
|
|
||||||
// NOP
|
|
||||||
}
|
|
||||||
public void componentHidden(ComponentEvent ce) {
|
|
||||||
// NOP
|
|
||||||
}
|
|
||||||
public void componentResized(ComponentEvent ce) {
|
|
||||||
canvas.setPreferredSize(new Dimension(getSize().width - 16,
|
|
||||||
getSize().height - 38));
|
|
||||||
calculateTransformations();
|
|
||||||
canvas.repaint();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add menu action for moving motes
|
|
||||||
addMoteMenuAction(new MoveMoteMenuAction());
|
|
||||||
|
|
||||||
/* Add some commonly used mote interface actions */
|
|
||||||
addMoteMenuAction(new ButtonClickMoteMenuAction());
|
|
||||||
addMoteMenuAction(new ShowLEDMoteMenuAction());
|
|
||||||
addMoteMenuAction(new ShowSerialMoteMenuAction());
|
|
||||||
|
|
||||||
// Add menu action for deleting mote
|
|
||||||
addMoteMenuAction(new DeleteMoteMenuAction());
|
|
||||||
|
|
||||||
try {
|
|
||||||
setSelected(true);
|
|
||||||
} catch (java.beans.PropertyVetoException e) {
|
|
||||||
// Could not select
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drag and drop files to motes */
|
|
||||||
DropTargetListener dTargetListener = new DropTargetListener() {
|
|
||||||
public void dragEnter(DropTargetDragEvent dtde) {
|
|
||||||
if (acceptOrRejectDrag(dtde)) {
|
|
||||||
dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
|
|
||||||
} else {
|
|
||||||
dtde.rejectDrag();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void dragExit(DropTargetEvent dte) {
|
|
||||||
}
|
|
||||||
public void dropActionChanged(DropTargetDragEvent dtde) {
|
|
||||||
if (acceptOrRejectDrag(dtde)) {
|
|
||||||
dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
|
|
||||||
} else {
|
|
||||||
dtde.rejectDrag();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void dragOver(DropTargetDragEvent dtde) {
|
|
||||||
if (acceptOrRejectDrag(dtde)) {
|
|
||||||
dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
|
|
||||||
} else {
|
|
||||||
dtde.rejectDrag();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void drop(DropTargetDropEvent dtde) {
|
|
||||||
Transferable transferable = dtde.getTransferable();
|
|
||||||
|
|
||||||
/* Only accept single files */
|
|
||||||
File file = null;
|
|
||||||
if (!transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
|
|
||||||
dtde.rejectDrop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<Object> transferList = Arrays.asList(
|
|
||||||
transferable.getTransferData(DataFlavor.javaFileListFlavor)
|
|
||||||
);
|
|
||||||
if (transferList.size() != 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<File> list = (List<File>) transferList.get(0);
|
|
||||||
if (list.size() != 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file = list.get(0);
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (file == null || !file.exists()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDropFile(file, dtde.getLocation());
|
|
||||||
}
|
|
||||||
private boolean acceptOrRejectDrag(DropTargetDragEvent dtde) {
|
|
||||||
Transferable transferable = dtde.getTransferable();
|
|
||||||
|
|
||||||
/* Make sure one, and only one, mote exists under mouse pointer */
|
|
||||||
Point point = dtde.getLocation();
|
|
||||||
Vector<Mote> motes = findMotesAtPosition(point.x, point.y);
|
|
||||||
if (motes == null || motes.size() != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only accept single files */
|
|
||||||
File file;
|
|
||||||
if (!transferable.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
List<Object> transferList = Arrays.asList(
|
|
||||||
transferable.getTransferData(DataFlavor.javaFileListFlavor)
|
|
||||||
);
|
|
||||||
if (transferList.size() != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
List<File> list = (List<File>) transferList.get(0);
|
|
||||||
if (list.size() != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
file = list.get(0);
|
|
||||||
} catch (UnsupportedFlavorException e) {
|
|
||||||
return false;
|
|
||||||
} catch (IOException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract file extension */
|
|
||||||
return isDropFileAccepted(file);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
canvas.setDropTarget(
|
|
||||||
new DropTarget(canvas, DnDConstants.ACTION_COPY_OR_MOVE, dTargetListener, true, null)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add new mote menu action.
|
|
||||||
*
|
|
||||||
* @see MoteMenuAction
|
|
||||||
* @param menuAction Menu action
|
|
||||||
*/
|
|
||||||
public void addMoteMenuAction(MoteMenuAction menuAction) {
|
|
||||||
menuActions.add(menuAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handlePopupRequest(final int x, final int y) {
|
|
||||||
final Vector<Mote> foundMotes = findMotesAtPosition(x, y);
|
|
||||||
if (foundMotes == null || foundMotes.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JPopupMenu pickMoteMenu = new JPopupMenu();
|
|
||||||
pickMoteMenu.add(new JLabel("Select action:"));
|
|
||||||
pickMoteMenu.add(new JSeparator());
|
|
||||||
|
|
||||||
// Add 'show mote plugins'-actions
|
|
||||||
for (final Mote mote : foundMotes) {
|
|
||||||
pickMoteMenu.add(simulation.getGUI().createMotePluginsSubmenu(mote));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the rest of the actions
|
|
||||||
for (final MoteMenuAction menuAction : menuActions) {
|
|
||||||
for (final Mote mote : foundMotes) {
|
|
||||||
if (menuAction.isEnabled(mote)) {
|
|
||||||
JMenuItem menuItem = new JMenuItem(menuAction.getDescription(mote));
|
|
||||||
menuItem.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
menuAction.doAction(mote);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
pickMoteMenu.add(menuItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show menu
|
|
||||||
Point pos = new Point(canvas.getLocationOnScreen().x + x, canvas
|
|
||||||
.getLocationOnScreen().y
|
|
||||||
+ y);
|
|
||||||
pickMoteMenu.setLocation(pos.x, pos.y);
|
|
||||||
pickMoteMenu.setInvoker(canvas);
|
|
||||||
pickMoteMenu.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void beginMoveRequest(final int x, final int y) {
|
|
||||||
final Vector<Mote> foundMotes = findMotesAtPosition(x, y);
|
|
||||||
if (foundMotes == null || foundMotes.size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
moteMoveBeginTime = System.currentTimeMillis();
|
|
||||||
beginMoveRequest(foundMotes.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void beginMoveRequest(Mote moteToMove) {
|
|
||||||
moteIsBeingMoved = true;
|
|
||||||
this.moteToMove = moteToMove;
|
|
||||||
canvas.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleMoveRequest(final int x, final int y,
|
|
||||||
boolean wasJustReleased) {
|
|
||||||
|
|
||||||
if (!moteIsBeingMoved) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wasJustReleased) {
|
|
||||||
// Still moving mote
|
|
||||||
canvas.setCursor(moveCursor);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stopped moving mote
|
|
||||||
canvas.setCursor(Cursor.getDefaultCursor());
|
|
||||||
moteIsBeingMoved = false;
|
|
||||||
|
|
||||||
Position newXYValues = transformPixelToPositon(new Point(x, y));
|
|
||||||
|
|
||||||
if (moteMoveBeginTime <= 0 || System.currentTimeMillis() - moteMoveBeginTime > 300) {
|
|
||||||
int returnValue = JOptionPane.showConfirmDialog(myPlugin, "Move mote to"
|
|
||||||
+ "\nX=" + newXYValues.getXCoordinate() + "\nY="
|
|
||||||
+ newXYValues.getYCoordinate() + "\nZ="
|
|
||||||
+ moteToMove.getInterfaces().getPosition().getZCoordinate());
|
|
||||||
|
|
||||||
if (returnValue == JOptionPane.OK_OPTION) {
|
|
||||||
moteToMove.getInterfaces().getPosition().setCoordinates(
|
|
||||||
newXYValues.getXCoordinate(), newXYValues.getYCoordinate(),
|
|
||||||
moteToMove.getInterfaces().getPosition().getZCoordinate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
moteMoveBeginTime = -1;
|
|
||||||
moteToMove = null;
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all motes at given position.
|
|
||||||
*
|
|
||||||
* @param clickedX
|
|
||||||
* X coordinate
|
|
||||||
* @param clickedY
|
|
||||||
* Y coordinate
|
|
||||||
* @return All motes at given position
|
|
||||||
*/
|
|
||||||
protected Vector<Mote> findMotesAtPosition(int clickedX, int clickedY) {
|
|
||||||
double xCoord = factorXPixelToCoord(clickedX);
|
|
||||||
double yCoord = factorYPixelToCoord(clickedY);
|
|
||||||
|
|
||||||
Vector<Mote> motesFound = new Vector<Mote>();
|
|
||||||
|
|
||||||
// Calculate painted mote radius in coordinates
|
|
||||||
double paintedMoteWidth = factorXPixelToCoord(MOTE_RADIUS)
|
|
||||||
- factorXPixelToCoord(0);
|
|
||||||
double paintedMoteHeight = factorYPixelToCoord(MOTE_RADIUS)
|
|
||||||
- factorYPixelToCoord(0);
|
|
||||||
|
|
||||||
for (int i = 0; i < simulation.getMotesCount(); i++) {
|
|
||||||
Position pos = simulation.getMote(i).getInterfaces().getPosition();
|
|
||||||
|
|
||||||
// Transform to unit circle before checking if mouse hit this mote
|
|
||||||
double distanceX = Math.abs(xCoord - pos.getXCoordinate())
|
|
||||||
/ paintedMoteWidth;
|
|
||||||
double distanceY = Math.abs(yCoord - pos.getYCoordinate())
|
|
||||||
/ paintedMoteHeight;
|
|
||||||
|
|
||||||
if (distanceX * distanceX + distanceY * distanceY <= 1) {
|
|
||||||
motesFound.add(simulation.getMote(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (motesFound.size() == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return motesFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get colors a certain mote should be painted with. May be overridden to get
|
|
||||||
* a different color scheme.
|
|
||||||
*
|
|
||||||
* Normally this method returns an array of two colors, one for the state
|
|
||||||
* (outer circle), the other for the type (inner circle).
|
|
||||||
*
|
|
||||||
* If this method only returns one color, the entire mote will be painted
|
|
||||||
* using that.
|
|
||||||
*
|
|
||||||
* @param mote
|
|
||||||
* Mote to paint
|
|
||||||
* @return Color[] { Inner color, Outer color }
|
|
||||||
*/
|
|
||||||
abstract public Color[] getColorOf(Mote mote);
|
|
||||||
|
|
||||||
protected void visualizeSimulation(Graphics g) {
|
|
||||||
Mote[] allMotes = simulation.getMotes();
|
|
||||||
for (Mote mote: allMotes) {
|
|
||||||
Color moteColors[] = getColorOf(mote);
|
|
||||||
Position motePos = mote.getInterfaces().getPosition();
|
|
||||||
|
|
||||||
Point pixelCoord = transformPositionToPixel(motePos);
|
|
||||||
int x = pixelCoord.x;
|
|
||||||
int y = pixelCoord.y;
|
|
||||||
|
|
||||||
if (mote == highlightedMote) {
|
|
||||||
g.setColor(highlightColor);
|
|
||||||
g.fillOval(x - MOTE_RADIUS, y - MOTE_RADIUS, 2 * MOTE_RADIUS,
|
|
||||||
2 * MOTE_RADIUS);
|
|
||||||
} else if (mote == moteToMove) {
|
|
||||||
// Don't fill mote
|
|
||||||
} else if (moteColors.length >= 2) {
|
|
||||||
g.setColor(moteColors[0]);
|
|
||||||
g.fillOval(x - MOTE_RADIUS, y - MOTE_RADIUS, 2 * MOTE_RADIUS,
|
|
||||||
2 * MOTE_RADIUS);
|
|
||||||
|
|
||||||
g.setColor(moteColors[1]);
|
|
||||||
g.fillOval(x - MOTE_RADIUS / 2, y - MOTE_RADIUS / 2, MOTE_RADIUS,
|
|
||||||
MOTE_RADIUS);
|
|
||||||
|
|
||||||
} else if (moteColors.length >= 1) {
|
|
||||||
g.setColor(moteColors[0]);
|
|
||||||
g.fillOval(x - MOTE_RADIUS, y - MOTE_RADIUS, 2 * MOTE_RADIUS,
|
|
||||||
2 * MOTE_RADIUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
g.setColor(Color.BLACK);
|
|
||||||
g.drawOval(x - MOTE_RADIUS, y - MOTE_RADIUS, 2 * MOTE_RADIUS,
|
|
||||||
2 * MOTE_RADIUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Paint mote relations */
|
|
||||||
MoteRelation[] relations = simulation.getGUI().getMoteRelations();
|
|
||||||
for (MoteRelation r: relations) {
|
|
||||||
Position sourcePos = r.source.getInterfaces().getPosition();
|
|
||||||
Position destPos = r.dest.getInterfaces().getPosition();
|
|
||||||
|
|
||||||
Point sourcePoint = transformPositionToPixel(sourcePos);
|
|
||||||
Point destPoint = transformPositionToPixel(destPos);
|
|
||||||
|
|
||||||
Point middlePoint = new Point(
|
|
||||||
(destPoint.x*9 + sourcePoint.x*1)/10,
|
|
||||||
(destPoint.y*9 + sourcePoint.y*1)/10
|
|
||||||
);
|
|
||||||
|
|
||||||
/* "Arrow body" is painted gray */
|
|
||||||
g.setColor(Color.LIGHT_GRAY);
|
|
||||||
g.drawLine(sourcePoint.x, sourcePoint.y, middlePoint.x, middlePoint.y);
|
|
||||||
|
|
||||||
/* "Arrow head" is painted black */
|
|
||||||
g.setColor(Color.BLACK);
|
|
||||||
g.drawLine(middlePoint.x, middlePoint.y, destPoint.x, destPoint.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recalculate size of canvas and factors for transforming between real and
|
|
||||||
* pixel coordinates. This method is called every time this frame is resized
|
|
||||||
* or created.
|
|
||||||
*/
|
|
||||||
protected void calculateTransformations() {
|
|
||||||
if (simulation.getMotesCount() == 0) {
|
|
||||||
smallestXCoord = 0;
|
|
||||||
smallestYCoord = 0;
|
|
||||||
factorXCoordToPixel = 1;
|
|
||||||
factorYCoordToPixel = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double biggestXCoord, biggestYCoord;
|
|
||||||
|
|
||||||
Position motePos = simulation.getMote(0).getInterfaces().getPosition();
|
|
||||||
smallestXCoord = biggestXCoord = motePos.getXCoordinate();
|
|
||||||
smallestYCoord = biggestYCoord = motePos.getYCoordinate();
|
|
||||||
|
|
||||||
// Get extreme coordinates
|
|
||||||
for (int i = 0; i < simulation.getMotesCount(); i++) {
|
|
||||||
motePos = simulation.getMote(i).getInterfaces().getPosition();
|
|
||||||
|
|
||||||
if (motePos.getXCoordinate() < smallestXCoord) {
|
|
||||||
smallestXCoord = motePos.getXCoordinate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (motePos.getXCoordinate() > biggestXCoord) {
|
|
||||||
biggestXCoord = motePos.getXCoordinate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (motePos.getYCoordinate() < smallestYCoord) {
|
|
||||||
smallestYCoord = motePos.getYCoordinate();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (motePos.getYCoordinate() > biggestYCoord) {
|
|
||||||
biggestYCoord = motePos.getYCoordinate();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((biggestXCoord - smallestXCoord) == 0) {
|
|
||||||
factorXCoordToPixel = 1;
|
|
||||||
} else {
|
|
||||||
factorXCoordToPixel = ((double) canvas.getPreferredSize().width - 2 * CANVAS_BORDER_WIDTH)
|
|
||||||
/ (biggestXCoord - smallestXCoord);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((biggestYCoord - smallestYCoord) == 0) {
|
|
||||||
factorYCoordToPixel = 1;
|
|
||||||
} else {
|
|
||||||
factorYCoordToPixel = ((double) canvas.getPreferredSize().height - 2 * CANVAS_BORDER_WIDTH)
|
|
||||||
/ (biggestYCoord - smallestYCoord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms a real-world position to a pixel which can be painted onto the
|
|
||||||
* current sized canvas.
|
|
||||||
*
|
|
||||||
* @param pos
|
|
||||||
* Real-world position
|
|
||||||
* @return Pixel coordinates
|
|
||||||
*/
|
|
||||||
public Point transformPositionToPixel(Position pos) {
|
|
||||||
return new Point(factorXCoordToPixel(pos.getXCoordinate()),
|
|
||||||
factorYCoordToPixel(pos.getYCoordinate()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms real-world coordinates to a pixel which can be painted onto the
|
|
||||||
* current sized canvas.
|
|
||||||
*
|
|
||||||
* @param x Real world X
|
|
||||||
* @param y Real world Y
|
|
||||||
* @param z Real world Z (ignored)
|
|
||||||
* @return Pixel coordinates
|
|
||||||
*/
|
|
||||||
public Point transformPositionToPixel(double x, double y, double z) {
|
|
||||||
return new Point(factorXCoordToPixel(x), factorYCoordToPixel(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms a pixel coordinate to a real-world. Z-value will always be 0.
|
|
||||||
*
|
|
||||||
* @param pixelPos
|
|
||||||
* On-screen pixel coordinate
|
|
||||||
* @return Real world coordinate (z=0).
|
|
||||||
*/
|
|
||||||
public Position transformPixelToPositon(Point pixelPos) {
|
|
||||||
Position dummyPosition = new Position(null);
|
|
||||||
dummyPosition.setCoordinates(factorXPixelToCoord(pixelPos.x),
|
|
||||||
factorYPixelToCoord(pixelPos.y), 0.0);
|
|
||||||
return dummyPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return The current canvas to paint on
|
|
||||||
*/
|
|
||||||
public JPanel getCurrentCanvas() {
|
|
||||||
return canvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int factorXCoordToPixel(double xCoordinate) {
|
|
||||||
return (int) ((xCoordinate - smallestXCoord) * factorXCoordToPixel + CANVAS_BORDER_WIDTH);
|
|
||||||
}
|
|
||||||
private int factorYCoordToPixel(double yCoordinate) {
|
|
||||||
return (int) ((yCoordinate - smallestYCoord) * factorYCoordToPixel)
|
|
||||||
+ CANVAS_BORDER_WIDTH;
|
|
||||||
}
|
|
||||||
private double factorXPixelToCoord(int xPixel) {
|
|
||||||
return ((xPixel - CANVAS_BORDER_WIDTH) / factorXCoordToPixel)
|
|
||||||
+ smallestXCoord;
|
|
||||||
}
|
|
||||||
private double factorYPixelToCoord(int yPixel) {
|
|
||||||
return ((yPixel - CANVAS_BORDER_WIDTH) / factorYCoordToPixel)
|
|
||||||
+ smallestYCoord;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closePlugin() {
|
|
||||||
if (moteHighligtObserver != null) {
|
|
||||||
myGUI.deleteMoteHighlightObserver(moteHighligtObserver);
|
|
||||||
}
|
|
||||||
if (moteRelationsObserver != null) {
|
|
||||||
myGUI.deleteMoteRelationsObserver(moteRelationsObserver);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (simObserver != null) {
|
|
||||||
simulation.deleteObserver(simObserver);
|
|
||||||
|
|
||||||
for (int i = 0; i < simulation.getMotesCount(); i++) {
|
|
||||||
Position posIntf = simulation.getMote(i).getInterfaces().getPosition();
|
|
||||||
if (posIntf != null) {
|
|
||||||
posIntf.deleteObserver(posObserver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isDropFileAccepted(File file) {
|
|
||||||
return true; /* TODO */
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void handleDropFile(File file, Point point) {
|
|
||||||
logger.fatal("Drag and drop not implemented: " + file);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue