renamed arm (advanced radio medium) to mrm
This commit is contained in:
parent
33bea3a025
commit
6464228219
18 changed files with 0 additions and 6861 deletions
|
@ -1,39 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<project name="COOJA ARM" default="compile" basedir=".">
|
||||
<property name="java" location="java"/>
|
||||
<property name="build" location="build"/>
|
||||
<property name="lib" location="lib"/>
|
||||
<property name="cooja_jar" value="../../dist/cooja.jar"/>
|
||||
|
||||
<target name="init">
|
||||
<tstamp/>
|
||||
</target>
|
||||
|
||||
<target name="compile" depends="init">
|
||||
<mkdir dir="${build}"/>
|
||||
<javac srcdir="${java}" destdir="${build}">
|
||||
<classpath>
|
||||
<pathelement path="."/>
|
||||
<pathelement location="${cooja_jar}"/>
|
||||
<pathelement location="${lib}/jfreechart-1.0.1.jar"/>
|
||||
<pathelement location="${lib}/jcommon-1.0.0.jar"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="clean" depends="init">
|
||||
<delete dir="${build}"/>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="clean, init, compile">
|
||||
<jar destfile="${lib}/arm.jar" basedir="${build}">
|
||||
<fileset dir="${build}"/>
|
||||
<fileset dir="images"/>
|
||||
<manifest>
|
||||
<attribute name="Class-Path" value="."/>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
</project>
|
|
@ -1,2 +0,0 @@
|
|||
se.sics.cooja.GUI.RADIOMEDIUMS = + se.sics.arm.AdvancedRadioMedium
|
||||
se.sics.cooja.GUI.JARFILES = + arm.jar jfreechart-1.0.1.jar jcommon-1.0.0.jar
|
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB |
|
@ -1,658 +0,0 @@
|
|||
package se.sics.arm;
|
||||
|
||||
import java.util.*;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jdom.Element;
|
||||
|
||||
import se.sics.cooja.*;
|
||||
import se.sics.cooja.interfaces.*;
|
||||
|
||||
/**
|
||||
* This is the main class of the COOJA Advanced Radio Medium (ARM) package.
|
||||
*
|
||||
* ARM is meant to be a replacement for the simpler radio mediums available in
|
||||
* COOJA. It is packet based and uses a 2D ray-tracing approach to approximate
|
||||
* signal strength attenuations between simulated radios. Currently the
|
||||
* ray-tracing only supports reflections and refractions through homogeneous
|
||||
* obstacles.
|
||||
*
|
||||
* ARM provides a number of plugins for example a plugin for visualizing radio
|
||||
* environments, and a plugin for configuring the radio medium.
|
||||
*
|
||||
* When a radio transmits data the area of interference around it will be
|
||||
* occupied for a time depending on the length of the packet sent. If the entire
|
||||
* transmission is completed without any interference the packet will be
|
||||
* delivered, otherwise nothing will be delivered.
|
||||
*
|
||||
* Future work includes adding diffractions and scattering support.
|
||||
*
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
@ClassDescription("Advanced Radio Medium (ARM)")
|
||||
public class AdvancedRadioMedium extends RadioMedium {
|
||||
private static Logger logger = Logger.getLogger(AdvancedRadioMedium.class);
|
||||
|
||||
private ChannelModel currentChannelModel = null;
|
||||
private Observer simulationObserver = null;
|
||||
private Simulation mySimulation = null;
|
||||
|
||||
// Registered members of radio medium
|
||||
private Vector<ARMMember> registeredMembers = new Vector<ARMMember>();
|
||||
|
||||
private Vector<RadioTransmission> allTransmissions = new Vector<RadioTransmission>();
|
||||
private Vector<RadioTransfer> allTransfers = new Vector<RadioTransfer>();
|
||||
private Vector<RadioInterference> allInterferences = new Vector<RadioInterference>();
|
||||
|
||||
|
||||
/**
|
||||
* Notifies observers when this radio medium is starting or has finished a packet delivery.
|
||||
*/
|
||||
private TransmissionsObservable radioActivityObservable = new TransmissionsObservable();
|
||||
|
||||
/**
|
||||
* Notifies observers when this radio medium has changed settings.
|
||||
*/
|
||||
private SettingsObservable settingsObservable = new SettingsObservable();
|
||||
|
||||
/**
|
||||
* Listens to all registered radios, and fetches any new incoming radio packets.
|
||||
*/
|
||||
private Observer radioObserver = new Observer() {
|
||||
public void update(Observable radio, Object obj) {
|
||||
Radio sendingRadio = (Radio) radio;
|
||||
if (sendingRadio.getLastEvent() != Radio.RadioEvent.TRANSMISSION_STARTED)
|
||||
return;
|
||||
|
||||
// Locate corresponding member
|
||||
ARMMember sendingMember = null;
|
||||
for (ARMMember member: registeredMembers) {
|
||||
if (member.radio == radio) {
|
||||
sendingMember = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sendingMember == null) {
|
||||
logger.fatal("ARM: Could not locate radio member - is radio registered? " + radio);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that member is not receiving data
|
||||
if (sendingMember.isListeningOnTransmission()) {
|
||||
logger.fatal("ARM: Radio is trying to send data but is currently receiving! This must be fixed in Contiki!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that member is not already sending data
|
||||
for (RadioTransmission transmission: allTransmissions) {
|
||||
if (transmission.source == sendingMember) {
|
||||
logger.fatal("ARM: Radio is trying to send data but is already sending! This must be fixed in Contiki!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int transmissionEndTime = sendingRadio.getTransmissionEndTime();
|
||||
|
||||
// Create transmission
|
||||
byte[] packetToSend = sendingRadio.getLastPacketTransmitted();
|
||||
RadioTransmission transmission = new RadioTransmission(sendingMember, transmissionEndTime, packetToSend);
|
||||
allTransmissions.add(transmission);
|
||||
radioActivityObservable.notifyRadioActivityChanged(); // Need to notify observers
|
||||
|
||||
double sendingX = sendingMember.position.getXCoordinate();
|
||||
double sendingY = sendingMember.position.getYCoordinate();
|
||||
Random random = new Random();
|
||||
|
||||
// Calculate how the other radios will be affected by this packet
|
||||
for (ARMMember member: registeredMembers) {
|
||||
// Ignore this sending radio
|
||||
if (member != sendingMember) {
|
||||
double receivingX = member.position.getXCoordinate();
|
||||
double receivingY = member.position.getYCoordinate();
|
||||
|
||||
double[] probData = currentChannelModel.getProbability(sendingX, sendingY, receivingX, receivingY, -Double.MAX_VALUE);
|
||||
|
||||
//logger.info("Probability of reception is " + probData[0]);
|
||||
//logger.info("Signal strength at destination is " + probData[1]);
|
||||
if (random.nextFloat() < probData[0]) {
|
||||
// Connection successful (if not interfered later)
|
||||
//logger.info("OK, creating connection and starting to transmit");
|
||||
tryCreateTransmission(transmission, member, probData[1]);
|
||||
} else if (probData[1] > 100) { // TODO Impossible value, what should it be?!
|
||||
// Transmission is only interference at destination
|
||||
tryCreateInterference(transmission, member, probData[1]);
|
||||
} else {
|
||||
//logger.info("Signal to low to be considered interference");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new Advanced Radio Medium (ARM).
|
||||
*/
|
||||
public AdvancedRadioMedium() {
|
||||
|
||||
// Create the channel model
|
||||
currentChannelModel = new ChannelModel();
|
||||
|
||||
// Register temporary plugins
|
||||
logger.info("Registering ARM plugins");
|
||||
GUI.currentGUI.registerTemporaryPlugin(AreaViewer.class);
|
||||
GUI.currentGUI.registerTemporaryPlugin(FormulaViewer.class);
|
||||
}
|
||||
|
||||
// -- Radio Medium standard methods --
|
||||
|
||||
public void registerMote(Mote mote, Simulation sim) {
|
||||
registerRadioInterface(mote.getInterfaces().getRadio(), mote.getInterfaces().getPosition(), sim);
|
||||
}
|
||||
|
||||
public void unregisterMote(Mote mote, Simulation sim) {
|
||||
unregisterRadioInterface(mote.getInterfaces().getRadio(), sim);
|
||||
}
|
||||
|
||||
public void registerRadioInterface(Radio radio, Position position, Simulation sim) {
|
||||
if (radio == null || position == null) {
|
||||
logger.fatal("Could not register radio: " + radio + " @ " + position);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are not already tick observering simulation, we should be
|
||||
if (simulationObserver == null) {
|
||||
mySimulation = sim;
|
||||
simulationObserver = new Observer() {
|
||||
public void update(Observable obs, Object obj) {
|
||||
// Check if any transmission is active in the radio medium
|
||||
if (allTransmissions.isEmpty())
|
||||
return;
|
||||
|
||||
Vector<RadioTransmission> uncompletedTransmissions = new Vector<RadioTransmission>();
|
||||
Vector<RadioTransmission> completedTransmissions = new Vector<RadioTransmission>();
|
||||
|
||||
// Check if any transmission has completed
|
||||
for (RadioTransmission transmission: allTransmissions) {
|
||||
if (transmission.isCompleted()) {
|
||||
completedTransmissions.add(transmission);
|
||||
} else {
|
||||
uncompletedTransmissions.add(transmission);
|
||||
}
|
||||
}
|
||||
|
||||
if (completedTransmissions.isEmpty())
|
||||
// Nothing to do
|
||||
return;
|
||||
|
||||
// At least one transmission has completed - deliver data for associated transfers
|
||||
for (RadioTransmission transmission: completedTransmissions) {
|
||||
// Unregister interferences of this transmission source
|
||||
Vector<RadioInterference> intfToUnregister = new Vector<RadioInterference>();
|
||||
for (RadioInterference interference: allInterferences) {
|
||||
if (interference.mySource == transmission) {
|
||||
intfToUnregister.add(interference);
|
||||
}
|
||||
}
|
||||
for (RadioInterference interference: intfToUnregister)
|
||||
unregisterInterference(interference);
|
||||
|
||||
// Deliver data and unregister transmission
|
||||
Vector<RadioTransfer> transToUnregister = new Vector<RadioTransfer>();
|
||||
for (RadioTransfer transfer: allTransfers) {
|
||||
if (transfer.mySource == transmission) {
|
||||
if (!transfer.interferenceDestroyedConnection()) {
|
||||
// Don't interfer connection
|
||||
} else {
|
||||
transfer.myDestination.radio.interferReception(0);
|
||||
}
|
||||
transToUnregister.add(transfer);
|
||||
}
|
||||
}
|
||||
for (RadioTransfer transfer: transToUnregister)
|
||||
unregisterTransmission(transfer);
|
||||
}
|
||||
|
||||
allTransmissions = uncompletedTransmissions;
|
||||
radioActivityObservable.notifyRadioActivityChanged(); // Need to notify observers
|
||||
|
||||
// Update all radio signal strengths
|
||||
for (ARMMember member: registeredMembers) {
|
||||
member.updateHeardSignalStrength();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sim.addTickObserver(simulationObserver);
|
||||
}
|
||||
|
||||
// Save both radio and its position, and also register us as an observer to the radio
|
||||
ARMMember member = new ARMMember(radio, position);
|
||||
registeredMembers.add(member);
|
||||
radio.addObserver(radioObserver);
|
||||
radio.setCurrentSignalStrength(currentChannelModel.getParameterDoubleValue(("bg_noise_mean")));
|
||||
|
||||
// Settings have changed - notify observers
|
||||
settingsObservable.notifySettingsChanged();
|
||||
}
|
||||
|
||||
public void unregisterRadioInterface(Radio radioToRemove, Simulation sim) {
|
||||
// Find corresponding radio member and remove it
|
||||
ARMMember memberToRemove = null;
|
||||
for (ARMMember member: registeredMembers) {
|
||||
if (member.radio == radioToRemove) {
|
||||
memberToRemove = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (memberToRemove != null) {
|
||||
registeredMembers.remove(memberToRemove);
|
||||
} else
|
||||
logger.warn("ARM: Could not unregister radio: " + radioToRemove);
|
||||
|
||||
// Settings have changed - notify observers
|
||||
settingsObservable.notifySettingsChanged();
|
||||
}
|
||||
|
||||
public void addRadioMediumObserver(Observer observer) {
|
||||
// Add radio traffic observer to this radio medium
|
||||
radioActivityObservable.addObserver(observer);
|
||||
}
|
||||
|
||||
public void deleteRadioMediumObserver(Observer observer) {
|
||||
// Remove observer from this radio medium
|
||||
radioActivityObservable.deleteObserver(observer);
|
||||
}
|
||||
|
||||
public RadioConnection[] getLastTickConnections() {
|
||||
logger.fatal("ARM: getLastTickConnections() not implemented");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setConnectionLogger(ConnectionLogger connection) {
|
||||
logger.fatal("ARM: setConnectionLogger() not implemented");
|
||||
}
|
||||
|
||||
public Collection<Element> getConfigXML() {
|
||||
// Just forwarding to current channel model
|
||||
return currentChannelModel.getConfigXML();
|
||||
}
|
||||
|
||||
public boolean setConfigXML(Collection<Element> configXML) {
|
||||
// Just forwarding to current channel model
|
||||
return currentChannelModel.setConfigXML(configXML);
|
||||
}
|
||||
|
||||
|
||||
// -- Advanced Radio Medium specific methods --
|
||||
|
||||
/**
|
||||
* Adds an observer which is notified when this radio medium has
|
||||
* changed settings, such as added or removed radios.
|
||||
*
|
||||
* @param obs New observer
|
||||
*/
|
||||
public void addSettingsObserver(Observer obs) {
|
||||
settingsObservable.addObserver(obs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an earlier registered setting observer.
|
||||
*
|
||||
* @param osb
|
||||
* Earlier registered observer
|
||||
*/
|
||||
public void deleteSettingsObserver(Observer obs) {
|
||||
settingsObservable.deleteObserver(obs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns position of given radio.
|
||||
*
|
||||
* @param radio Registered radio
|
||||
* @return Position of given radio
|
||||
*/
|
||||
public Position getRadioPosition(Radio radio) {
|
||||
// Find radio, and return its position
|
||||
for (ARMMember member: registeredMembers) {
|
||||
if (member.radio == radio) {
|
||||
return member.position;
|
||||
}
|
||||
}
|
||||
logger.fatal("ARM: Given radio is not registered!");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Number of registered radios.
|
||||
*/
|
||||
public int getRegisteredRadioCount() {
|
||||
return registeredMembers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns radio at given index.
|
||||
*
|
||||
* @param index Index of registered radio.
|
||||
* @return Radio at given index
|
||||
*/
|
||||
public Radio getRegisteredRadio(int index) {
|
||||
return registeredMembers.get(index).radio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current channel model object, responsible for
|
||||
* all probability and transmission calculations.
|
||||
*
|
||||
* @return Current channel model
|
||||
*/
|
||||
public ChannelModel getChannelModel() {
|
||||
return currentChannelModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tries to create a new transmission between given transmission and
|
||||
* destination. The given signal strength should be the incoming signal
|
||||
* strength at the destination. This value will be used after the transmission
|
||||
* is completed in order to compare the connection with any interference.
|
||||
*
|
||||
* @param source
|
||||
* @param destination
|
||||
* @param signalStrength
|
||||
* @return
|
||||
*/
|
||||
public void tryCreateTransmission(RadioTransmission source, ARMMember destination, double signalStrength) {
|
||||
// Check if destination is already listening to a connection
|
||||
if (destination.isListeningOnTransmission()) {
|
||||
RadioInterference newInterference = new RadioInterference(source, destination, signalStrength);
|
||||
destination.heardInterferences.add(newInterference);
|
||||
|
||||
registerInterference(newInterference);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new transmission
|
||||
RadioTransfer newTransmission = new RadioTransfer(source, destination, signalStrength);
|
||||
destination.heardTransmission = newTransmission;
|
||||
|
||||
registerTransmission(newTransmission);
|
||||
}
|
||||
|
||||
public void tryCreateInterference(RadioTransmission source, ARMMember destination, double signalStrength) {
|
||||
RadioInterference newInterference = new RadioInterference(source, destination, signalStrength);
|
||||
destination.heardInterferences.add(newInterference);
|
||||
|
||||
registerInterference(newInterference);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ARM radio transmission.
|
||||
*/
|
||||
class RadioTransmission {
|
||||
ARMMember source = null;
|
||||
int endTime = 0;
|
||||
byte[] dataToTransfer = null;
|
||||
|
||||
public RadioTransmission(ARMMember source, int endTime, byte[] dataToTransfer) {
|
||||
this.source = source;
|
||||
|
||||
this.endTime = endTime;
|
||||
|
||||
this.dataToTransfer = dataToTransfer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if no longer transmitting.
|
||||
*/
|
||||
public boolean isCompleted() {
|
||||
return mySimulation.getSimulationTime() >= endTime;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ARM radio interference
|
||||
*/
|
||||
class RadioInterference {
|
||||
RadioTransmission mySource;
|
||||
ARMMember myDestination;
|
||||
double interferenceSignalStrength;
|
||||
|
||||
public RadioInterference(RadioTransmission transmission, ARMMember destination, double signalStrength) {
|
||||
this.mySource = transmission;
|
||||
this.myDestination = destination;
|
||||
this.interferenceSignalStrength = signalStrength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if interference is no more.
|
||||
*/
|
||||
public boolean isOld() {
|
||||
return mySource.isCompleted();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ARM radio transfers
|
||||
*/
|
||||
class RadioTransfer {
|
||||
RadioTransmission mySource;
|
||||
ARMMember myDestination;
|
||||
double transmissionSignalStrength;
|
||||
double maxInterferenceSignalStrength;
|
||||
|
||||
public RadioTransfer(RadioTransmission source, ARMMember destination, double signalStrength) {
|
||||
this.mySource = source;
|
||||
this.myDestination = destination;
|
||||
this.transmissionSignalStrength = signalStrength;
|
||||
maxInterferenceSignalStrength = -Double.MAX_VALUE;
|
||||
|
||||
destination.radio.receivePacket(source.dataToTransfer, source.endTime);
|
||||
destination.radio.setCurrentSignalStrength(signalStrength);
|
||||
}
|
||||
|
||||
public void addInterference(double signalStrength) {
|
||||
if (signalStrength > maxInterferenceSignalStrength) {
|
||||
maxInterferenceSignalStrength = signalStrength;
|
||||
}
|
||||
myDestination.radio.setCurrentSignalStrength(Math.max(
|
||||
maxInterferenceSignalStrength, transmissionSignalStrength));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if transmission is completed.
|
||||
*/
|
||||
public boolean isOld() {
|
||||
return mySource.isCompleted();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if interference destroyed transmission
|
||||
*/
|
||||
public boolean interferenceDestroyedConnection() {
|
||||
if (maxInterferenceSignalStrength + 30 > transmissionSignalStrength) {
|
||||
// Recalculating probability of delivery
|
||||
double[] probData = currentChannelModel.getProbability(
|
||||
mySource.source.position.getXCoordinate(),
|
||||
mySource.source.position.getYCoordinate(),
|
||||
myDestination.position.getXCoordinate(),
|
||||
myDestination.position.getYCoordinate(),
|
||||
maxInterferenceSignalStrength);
|
||||
// logger.info("Transfer was interfered, recalculating probability of success: " + probData[0]);
|
||||
|
||||
if (new Random().nextFloat() >= probData[0]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class used for keeping track transceivers.
|
||||
*/
|
||||
class ARMMember {
|
||||
Radio radio = null;
|
||||
Position position = null;
|
||||
|
||||
private RadioTransfer heardTransmission;
|
||||
private Vector<RadioInterference> heardInterferences = new Vector<RadioInterference>();
|
||||
double currentSignalStrength = -Double.MAX_VALUE;
|
||||
|
||||
public ARMMember(Radio radio, Position position) {
|
||||
this.radio = radio;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public boolean isListeningOnTransmission() {
|
||||
if (heardTransmission == null)
|
||||
return false;
|
||||
|
||||
if (heardTransmission.isOld()) {
|
||||
heardTransmission = null;
|
||||
}
|
||||
|
||||
return heardTransmission != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates current incoming signal strength at this radio.
|
||||
* Observe, does not alter any transmissions!
|
||||
*/
|
||||
public void updateHeardSignalStrength() {
|
||||
double maxSignalStrength = -Double.MAX_VALUE;
|
||||
|
||||
// Get maximum interference and also update interference list
|
||||
Vector<RadioInterference> newInterferences = new Vector<RadioInterference>();
|
||||
for (RadioInterference interference: heardInterferences) {
|
||||
if (!interference.isOld()) {
|
||||
newInterferences.add(interference);
|
||||
maxSignalStrength = Math.max(maxSignalStrength,
|
||||
interference.interferenceSignalStrength);
|
||||
}
|
||||
}
|
||||
heardInterferences = newInterferences;
|
||||
|
||||
if (heardTransmission != null && !heardTransmission.isOld()) {
|
||||
maxSignalStrength = Math.max(maxSignalStrength,
|
||||
heardTransmission.transmissionSignalStrength);
|
||||
} else
|
||||
heardTransmission = null;
|
||||
|
||||
// Noise level
|
||||
maxSignalStrength = Math.max(maxSignalStrength, currentChannelModel
|
||||
.getParameterDoubleValue("bg_noise_mean"));
|
||||
|
||||
currentSignalStrength = maxSignalStrength;
|
||||
radio.setCurrentSignalStrength(currentSignalStrength);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void registerInterference(RadioInterference interference) {
|
||||
allInterferences.add(interference);
|
||||
|
||||
updateInterferences();
|
||||
radioActivityObservable.notifyRadioActivityChanged(); // Need to notify observers
|
||||
}
|
||||
|
||||
public void registerTransmission(RadioTransfer transmission) {
|
||||
allTransfers.add(transmission);
|
||||
|
||||
updateInterferences();
|
||||
radioActivityObservable.notifyRadioActivityChanged(); // Need to notify observers
|
||||
}
|
||||
|
||||
public void unregisterInterference(RadioInterference interference) {
|
||||
updateInterferences();
|
||||
|
||||
allInterferences.remove(interference);
|
||||
radioActivityObservable.notifyRadioActivityChanged(); // Need to notify observers
|
||||
}
|
||||
|
||||
public void unregisterTransmission(RadioTransfer transmission) {
|
||||
updateInterferences();
|
||||
|
||||
allTransfers.remove(transmission);
|
||||
radioActivityObservable.notifyRadioActivityChanged(); // Need to notify observers
|
||||
}
|
||||
|
||||
private void updateInterferences() {
|
||||
// We need to check impact of interferences on transmissions
|
||||
for (RadioTransfer transmission: allTransfers) {
|
||||
for (RadioInterference interference: allInterferences) {
|
||||
if (interference.myDestination == transmission.myDestination) {
|
||||
transmission.addInterference(interference.interferenceSignalStrength);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TransmissionsObservable extends Observable {
|
||||
private void notifyRadioActivityChanged() {
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsObservable extends Observable {
|
||||
private void notifySettingsChanged() {
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current active transmissions
|
||||
*/
|
||||
public Vector<RadioTransmission> getCurrentTransmissions() {
|
||||
return allTransmissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current active transmissions
|
||||
*/
|
||||
public RadioTransmission[] getCurrentTransmissionsArray() {
|
||||
return allTransmissions.toArray(new RadioTransmission[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current active interferences
|
||||
*/
|
||||
public Vector<RadioInterference> getCurrentInterferences() {
|
||||
return allInterferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current active interferences
|
||||
*/
|
||||
public RadioInterference[] getCurrentInterferencesArray() {
|
||||
return allInterferences.toArray(new RadioInterference[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current active transfers
|
||||
*/
|
||||
public Vector<RadioTransfer> getCurrentTransfers() {
|
||||
return allTransfers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current active transfers
|
||||
*/
|
||||
public RadioTransfer[] getCurrentTransfersArray() {
|
||||
return allTransfers.toArray(new RadioTransfer[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,385 +0,0 @@
|
|||
package se.sics.arm;
|
||||
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* This class represents an angle interval.
|
||||
*
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
class AngleInterval {
|
||||
private static Logger logger = Logger.getLogger(AngleInterval.class);
|
||||
|
||||
// Sub intervals all between 0 and 2*PI
|
||||
Vector<Interval> subIntervals;
|
||||
|
||||
/**
|
||||
* Creates a new angle interval.
|
||||
*
|
||||
* @param startAngle Start angle (rad)
|
||||
* @param endAngle End angle (rad) (> start angle)
|
||||
*/
|
||||
public AngleInterval(double startAngle, double endAngle) {
|
||||
subIntervals = new Vector<Interval>();
|
||||
|
||||
if (endAngle < startAngle) {
|
||||
|
||||
} else if (endAngle - startAngle >= 2*Math.PI) {
|
||||
subIntervals.add(new Interval(0, 2*Math.PI));
|
||||
} else {
|
||||
while (startAngle < 0)
|
||||
startAngle += 2*Math.PI;
|
||||
while (endAngle < 0)
|
||||
endAngle += 2*Math.PI;
|
||||
startAngle %= 2*Math.PI;
|
||||
endAngle %= 2*Math.PI;
|
||||
|
||||
Interval tempInterval;
|
||||
if (startAngle < endAngle) {
|
||||
tempInterval = new Interval(startAngle, endAngle);
|
||||
if (!tempInterval.isEmpty())
|
||||
subIntervals.add(tempInterval);
|
||||
} else {
|
||||
tempInterval = new Interval(startAngle, 2*Math.PI);
|
||||
if (!tempInterval.isEmpty())
|
||||
subIntervals.add(tempInterval);
|
||||
tempInterval = new Interval(0, endAngle);
|
||||
if (!tempInterval.isEmpty())
|
||||
subIntervals.add(tempInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new intervals consisting of this interval with the given interval removed.
|
||||
* These can either be null (if entire interval was removed),
|
||||
* one interval (if upper or lower part, or nothing was removed) or two intervals
|
||||
* (if middle part of interval was removed).
|
||||
*
|
||||
* @param intervalToSubtract Other interval
|
||||
* @return New intervals
|
||||
*/
|
||||
public Vector<AngleInterval> subtract(AngleInterval intervalToSubtract) {
|
||||
Vector<Interval> afterSubtractionIntervals = new Vector<Interval>();
|
||||
|
||||
// Before subtraction
|
||||
afterSubtractionIntervals.addAll(subIntervals);
|
||||
|
||||
if (intervalToSubtract == null) {
|
||||
Vector<AngleInterval> ret = new Vector<AngleInterval>();
|
||||
ret.add(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Subtract every subinterval each
|
||||
for (int i=0; i < intervalToSubtract.subIntervals.size(); i++) {
|
||||
Interval subIntervalToSubtract = intervalToSubtract.subIntervals.get(i);
|
||||
Vector<Interval> newAfterSubtractionIntervals = new Vector<Interval>();
|
||||
|
||||
for (int j=0; j < afterSubtractionIntervals.size(); j++) {
|
||||
Vector<Interval> tempIntervals = afterSubtractionIntervals.get(j).subtract(subIntervalToSubtract);
|
||||
if (tempIntervals != null)
|
||||
newAfterSubtractionIntervals.addAll(tempIntervals);
|
||||
}
|
||||
|
||||
afterSubtractionIntervals = newAfterSubtractionIntervals;
|
||||
}
|
||||
|
||||
Vector<AngleInterval> newAngleIntervals = new Vector<AngleInterval>();
|
||||
for (int i=0; i < afterSubtractionIntervals.size(); i++) {
|
||||
if (afterSubtractionIntervals.get(i) != null && !afterSubtractionIntervals.get(i).isEmpty())
|
||||
newAngleIntervals.add(
|
||||
new AngleInterval(afterSubtractionIntervals.get(i).getLow(), afterSubtractionIntervals.get(i).getHigh())
|
||||
);
|
||||
}
|
||||
|
||||
return newAngleIntervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intersection of this interval with
|
||||
* the given.
|
||||
*
|
||||
* @param interval Other interval
|
||||
* @return Intersection
|
||||
*/
|
||||
public AngleInterval intersectWith(AngleInterval interval) {
|
||||
Vector<Interval> afterIntersectionIntervals = new Vector<Interval>();
|
||||
|
||||
// Intersect all subintervals, keep all results
|
||||
for (int i=0; i < interval.subIntervals.size(); i++) {
|
||||
for (int j=0; j < subIntervals.size(); j++) {
|
||||
Interval temp = interval.subIntervals.get(i).intersectWith(subIntervals.get(j));
|
||||
if (temp != null && !temp.isEmpty())
|
||||
afterIntersectionIntervals.add(temp);
|
||||
}
|
||||
}
|
||||
|
||||
if (afterIntersectionIntervals.size() > 2) {
|
||||
logger.fatal("AngleInterval.intersectWith() error!");
|
||||
} else if (afterIntersectionIntervals.size() == 2) {
|
||||
|
||||
// The interval (y-x) is divided into:
|
||||
// y -> 2*PI
|
||||
// 0 -> x
|
||||
Interval interval1 = afterIntersectionIntervals.get(0);
|
||||
Interval interval2 = afterIntersectionIntervals.get(1);
|
||||
|
||||
if (interval1.getLow() == 0)
|
||||
return new AngleInterval(
|
||||
interval2.getLow(), interval1.getHigh() + 2*Math.PI
|
||||
);
|
||||
else
|
||||
return new AngleInterval(
|
||||
interval1.getLow(), interval2.getHigh() + 2*Math.PI
|
||||
);
|
||||
|
||||
} else if (afterIntersectionIntervals.size() == 1) {
|
||||
return new AngleInterval(
|
||||
afterIntersectionIntervals.firstElement().getLow(),
|
||||
afterIntersectionIntervals.firstElement().getHigh()
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns start angle of this interval.
|
||||
* This angle is always > 0 and < the end angle.
|
||||
*
|
||||
* @return Start angle
|
||||
*/
|
||||
public double getStartAngle() {
|
||||
if (subIntervals == null || subIntervals.isEmpty()) {
|
||||
logger.warn("Getting start angle of null angle interval!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (subIntervals.size() > 2) {
|
||||
logger.warn("Getting start angle of malformed angle interval!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (subIntervals.size() == 1) {
|
||||
return subIntervals.firstElement().getLow();
|
||||
}
|
||||
|
||||
// The interval (y-x) is divided into:
|
||||
// y -> 2*PI
|
||||
// 0 -> x
|
||||
Interval interval1 = subIntervals.get(0);
|
||||
Interval interval2 = subIntervals.get(1);
|
||||
|
||||
if (interval1.getLow() == 0)
|
||||
return interval2.getLow();
|
||||
else
|
||||
return interval1.getLow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns end angle of this interval.
|
||||
* This angle is always > start angle, and may be > 2*PI.
|
||||
*
|
||||
* @return End angle
|
||||
*/
|
||||
public double getEndAngle() {
|
||||
if (subIntervals == null || subIntervals.isEmpty()) {
|
||||
logger.warn("Getting start angle of null angle interval!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (subIntervals.size() > 2) {
|
||||
logger.warn("Getting start angle of malformed angle interval!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (subIntervals.size() == 1) {
|
||||
return subIntervals.firstElement().getHigh();
|
||||
}
|
||||
|
||||
// The interval (y-x) is divided into:
|
||||
// y -> 2*PI
|
||||
// 0 -> x
|
||||
Interval interval1 = subIntervals.get(0);
|
||||
Interval interval2 = subIntervals.get(1);
|
||||
|
||||
if (interval1.getLow() == 0)
|
||||
return interval1.getHigh() + 2*Math.PI;
|
||||
else
|
||||
return interval2.getHigh() + 2*Math.PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Size of interval (rad)
|
||||
*/
|
||||
public double getSize() {
|
||||
double size = 0;
|
||||
for (int i=0; i < subIntervals.size(); i++)
|
||||
size += subIntervals.get(i).getSize();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given interval is a subset of this interval.
|
||||
*
|
||||
* @param interval Other interval
|
||||
* @return True if this interval contains given interval
|
||||
*/
|
||||
public boolean contains(AngleInterval interval) {
|
||||
// Check that all parts of argument is contained by any part of this
|
||||
for (int i=0; i < interval.subIntervals.size(); i++) {
|
||||
boolean contained = false;
|
||||
for (int j=0; j < subIntervals.size(); j++) {
|
||||
if (subIntervals.get(j).contains(interval.subIntervals.get(i))) {
|
||||
contained = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!contained)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the two intervals intersect.
|
||||
*
|
||||
* @param interval Other interval
|
||||
* @return True if this interval intersects given interval
|
||||
*/
|
||||
public boolean intersects(AngleInterval interval) {
|
||||
return (intersectWith(interval) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if interval defined is of no size.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
if (subIntervals.isEmpty())
|
||||
return true;
|
||||
if (getSize() <= 0.001)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String retString = "";
|
||||
for (int i=0; i < subIntervals.size(); i++) {
|
||||
if (!retString.equals(""))
|
||||
retString = retString.concat(" && ");
|
||||
|
||||
retString = retString.concat("(");
|
||||
retString = retString.concat(Math.toDegrees(subIntervals.get(i).getLow()) + " -> " + Math.toDegrees(subIntervals.get(i).getHigh()));
|
||||
retString = retString.concat(")");
|
||||
}
|
||||
|
||||
return retString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a line starting at given start point and
|
||||
* in the given direction.
|
||||
* This line may be used when calculating intersection points.
|
||||
*
|
||||
* @param startPoint Start point
|
||||
* @param angle Line direction (rad)
|
||||
* @return Line
|
||||
*/
|
||||
public static Line2D getDirectedLine(Point2D startPoint, double angle, double length) {
|
||||
return new Line2D.Double(
|
||||
startPoint.getX(),
|
||||
startPoint.getY(),
|
||||
startPoint.getX() + length*Math.cos(angle),
|
||||
startPoint.getY() + length*Math.sin(angle)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an angle interval of the given line seen from
|
||||
* the given reference point.
|
||||
*
|
||||
* @param refPoint Reference point
|
||||
* @param line Line to measure angle against
|
||||
* @return Angle interval (-pi <-> pi)
|
||||
*/
|
||||
public static AngleInterval getAngleIntervalOfLine(Point2D refPoint, Line2D line) {
|
||||
// Create angle interval of this line
|
||||
double x1 = line.getX1() - refPoint.getX();
|
||||
double y1 = line.getY1() - refPoint.getY();
|
||||
double x2 = line.getX2() - refPoint.getX();
|
||||
double y2 = line.getY2() - refPoint.getY();
|
||||
|
||||
double angle1 = Math.atan2(y1, x1);
|
||||
double angle2 = Math.atan2(y2, x2);
|
||||
|
||||
// If interval is bigger than PI, line angles must wrap
|
||||
if (Math.abs(angle1 - angle2) > Math.PI) {
|
||||
if (angle1 < 0)
|
||||
angle1 += 2*Math.PI;
|
||||
else
|
||||
angle2 += 2*Math.PI;
|
||||
}
|
||||
|
||||
return new AngleInterval(
|
||||
Math.min(angle1, angle2), Math.max(angle1, angle2)
|
||||
);
|
||||
}
|
||||
|
||||
public boolean equals(Object object) {
|
||||
if (object == null)
|
||||
return false;
|
||||
|
||||
AngleInterval interval = (AngleInterval) object;
|
||||
return (interval.getStartAngle() == this.getStartAngle() && interval.getEndAngle() == this.getEndAngle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts given interval from all intervals in given vector.
|
||||
* This method never returns null (but empty vectors).
|
||||
*
|
||||
* @param initialIntervals Initial intervals
|
||||
* @param interval Interval to subtract
|
||||
* @return New intervals
|
||||
*/
|
||||
public static Vector<AngleInterval> subtract(Vector<AngleInterval> initialIntervals, AngleInterval interval) {
|
||||
Vector<AngleInterval> newIntervals = new Vector<AngleInterval>();
|
||||
|
||||
for (int i=0; i < initialIntervals.size(); i++) {
|
||||
Vector<AngleInterval> tempIntervals = initialIntervals.get(i).subtract(interval);
|
||||
if (tempIntervals != null) {
|
||||
newIntervals.addAll(tempIntervals);
|
||||
}
|
||||
}
|
||||
|
||||
return newIntervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intersects given interval with all intervals in given vector.
|
||||
* This method never returns null (but empty vectors).
|
||||
*
|
||||
* @param initialIntervals Initial intervals
|
||||
* @param interval Interval to intersect
|
||||
* @return New intervals
|
||||
*/
|
||||
public static Vector<AngleInterval> intersect(Vector<AngleInterval> initialIntervals, AngleInterval interval) {
|
||||
Vector<AngleInterval> newIntervals = new Vector<AngleInterval>();
|
||||
|
||||
for (int i=0; i < initialIntervals.size(); i++) {
|
||||
AngleInterval tempInterval = initialIntervals.get(i).intersectWith(interval);
|
||||
if (tempInterval != null) {
|
||||
newIntervals.add(tempInterval);
|
||||
}
|
||||
}
|
||||
|
||||
return newIntervals;
|
||||
}
|
||||
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,583 +0,0 @@
|
|||
package se.sics.arm;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jdom.Element;
|
||||
|
||||
import se.sics.cooja.*;
|
||||
|
||||
/**
|
||||
* This plugin allows a user to reconfigure current radio channel parameters.
|
||||
*
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
@ClassDescription("ARM - Formula Viewer")
|
||||
@VisPluginType(VisPluginType.SIM_PLUGIN)
|
||||
public class FormulaViewer extends se.sics.cooja.VisPlugin {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static Logger logger = Logger.getLogger(FormulaViewer.class);
|
||||
|
||||
private Simulation currentSimulation;
|
||||
private AdvancedRadioMedium currentRadioMedium;
|
||||
private ChannelModel currentChannelModel;
|
||||
|
||||
private static Dimension labelDimension = new Dimension(240, 20);
|
||||
private static NumberFormat doubleFormat = NumberFormat.getNumberInstance();
|
||||
private static NumberFormat integerFormat = NumberFormat.getIntegerInstance();
|
||||
|
||||
private Vector<JFormattedTextField> allIntegerParameters = new Vector<JFormattedTextField>();
|
||||
private Vector<JFormattedTextField> allDoubleParameters = new Vector<JFormattedTextField>();
|
||||
private Vector<JCheckBox> allBooleanParameters = new Vector<JCheckBox>();
|
||||
|
||||
private JPanel areaGeneral;
|
||||
private JPanel areaTransmitter;
|
||||
private JPanel areaReceiver;
|
||||
private JPanel areaRayTracer;
|
||||
private JPanel areaShadowing;
|
||||
|
||||
/**
|
||||
* Creates a new formula viewer.
|
||||
*
|
||||
* @param simulationToVisualize Simulation which holds the ARM channel model.
|
||||
*/
|
||||
public FormulaViewer(Simulation simulationToVisualize) {
|
||||
super("Advanced Radio Medium - Formula Viewer");
|
||||
|
||||
currentSimulation = simulationToVisualize;
|
||||
currentRadioMedium = (AdvancedRadioMedium) currentSimulation.getRadioMedium();
|
||||
currentChannelModel = currentRadioMedium.getChannelModel();
|
||||
|
||||
// -- Create and add GUI components --
|
||||
JPanel allComponents = new JPanel();
|
||||
allComponents.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
allComponents.setLayout(new BoxLayout(allComponents, BoxLayout.Y_AXIS));
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(allComponents);
|
||||
scrollPane.setPreferredSize(new Dimension(500,400));
|
||||
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
setContentPane(scrollPane);
|
||||
|
||||
JPanel collapsableArea;
|
||||
|
||||
// General parameters
|
||||
collapsableArea = createCollapsableArea("General parameters", allComponents);
|
||||
areaGeneral = collapsableArea;
|
||||
|
||||
addBooleanParameter(
|
||||
"apply_random",
|
||||
currentChannelModel.getParameterDescription("apply_random"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterBooleanValue("apply_random")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"snr_threshold",
|
||||
currentChannelModel.getParameterDescription("snr_threshold"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("snr_threshold")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"bg_noise_mean",
|
||||
currentChannelModel.getParameterDescription("bg_noise_mean"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("bg_noise_mean")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"bg_noise_var",
|
||||
currentChannelModel.getParameterDescription("bg_noise_var"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("bg_noise_var")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"system_gain_mean",
|
||||
currentChannelModel.getParameterDescription("system_gain_mean"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("system_gain_mean")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"system_gain_var",
|
||||
currentChannelModel.getParameterDescription("system_gain_var"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("system_gain_var")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"wavelength",
|
||||
currentChannelModel.getParameterDescription("wavelength"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("wavelength")
|
||||
);
|
||||
|
||||
// Transmitter parameters
|
||||
collapsableArea = createCollapsableArea("Transmitter parameters", allComponents);
|
||||
areaTransmitter = collapsableArea;
|
||||
|
||||
addDoubleParameter(
|
||||
"tx_power",
|
||||
currentChannelModel.getParameterDescription("tx_power"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("tx_power")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"tx_antenna_gain",
|
||||
currentChannelModel.getParameterDescription("tx_antenna_gain"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("tx_antenna_gain")
|
||||
);
|
||||
|
||||
// Receiver parameters
|
||||
collapsableArea = createCollapsableArea("Receiver parameters", allComponents);
|
||||
areaReceiver = collapsableArea;
|
||||
|
||||
addDoubleParameter(
|
||||
"rx_sensitivity",
|
||||
currentChannelModel.getParameterDescription("rx_sensitivity"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("rx_sensitivity")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"rx_antenna_gain",
|
||||
currentChannelModel.getParameterDescription("rx_antenna_gain"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("rx_antenna_gain")
|
||||
);
|
||||
|
||||
// Ray Tracer parameters
|
||||
collapsableArea = createCollapsableArea("Ray Tracer parameters", allComponents);
|
||||
areaRayTracer = collapsableArea;
|
||||
|
||||
addBooleanParameter(
|
||||
"rt_disallow_direct_path",
|
||||
currentChannelModel.getParameterDescription("rt_disallow_direct_path"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterBooleanValue("rt_disallow_direct_path")
|
||||
);
|
||||
|
||||
addBooleanParameter(
|
||||
"rt_ignore_non_direct",
|
||||
currentChannelModel.getParameterDescription("rt_ignore_non_direct"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterBooleanValue("rt_ignore_non_direct")
|
||||
);
|
||||
|
||||
addBooleanParameter(
|
||||
"rt_fspl_on_total_length",
|
||||
currentChannelModel.getParameterDescription("rt_fspl_on_total_length"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterBooleanValue("rt_fspl_on_total_length")
|
||||
);
|
||||
|
||||
addIntegerParameter(
|
||||
"rt_max_rays",
|
||||
currentChannelModel.getParameterDescription("rt_max_rays"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterIntegerValue("rt_max_rays")
|
||||
);
|
||||
|
||||
addIntegerParameter(
|
||||
"rt_max_refractions",
|
||||
currentChannelModel.getParameterDescription("rt_max_refractions"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterIntegerValue("rt_max_refractions")
|
||||
);
|
||||
|
||||
addIntegerParameter(
|
||||
"rt_max_reflections",
|
||||
currentChannelModel.getParameterDescription("rt_max_reflections"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterIntegerValue("rt_max_reflections")
|
||||
);
|
||||
|
||||
addIntegerParameter(
|
||||
"rt_max_diffractions",
|
||||
currentChannelModel.getParameterDescription("rt_max_diffractions"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterIntegerValue("rt_max_diffractions")
|
||||
);
|
||||
|
||||
/* addBooleanParameter(
|
||||
"rt_use_scattering",
|
||||
currentChannelModel.getParameterDescription("rt_use_scattering"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterBooleanValue("rt_use_scattering")
|
||||
);
|
||||
*/
|
||||
addDoubleParameter(
|
||||
"rt_refrac_coefficient",
|
||||
currentChannelModel.getParameterDescription("rt_refrac_coefficient"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("rt_refrac_coefficient")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"rt_reflec_coefficient",
|
||||
currentChannelModel.getParameterDescription("rt_reflec_coefficient"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("rt_reflec_coefficient")
|
||||
);
|
||||
|
||||
addDoubleParameter(
|
||||
"rt_diffr_coefficient",
|
||||
currentChannelModel.getParameterDescription("rt_diffr_coefficient"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("rt_diffr_coefficient")
|
||||
);
|
||||
|
||||
/* addDoubleParameter(
|
||||
"rt_scatt_coefficient",
|
||||
currentChannelModel.getParameterDescription("rt_scatt_coefficient"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("rt_scatt_coefficient")
|
||||
);
|
||||
*/
|
||||
// Shadowing parameters
|
||||
collapsableArea = createCollapsableArea("Shadowing parameters", allComponents);
|
||||
areaShadowing = collapsableArea;
|
||||
|
||||
addDoubleParameter(
|
||||
"obstacle_attenuation",
|
||||
currentChannelModel.getParameterDescription("obstacle_attenuation"),
|
||||
collapsableArea,
|
||||
currentChannelModel.getParameterDoubleValue("obstacle_attenuation")
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Add channel model observer responsible to keep all GUI components synched
|
||||
currentChannelModel.addSettingsObserver(channelModelSettingsObserver);
|
||||
|
||||
// Set initial size etc.
|
||||
pack();
|
||||
setVisible(true);
|
||||
|
||||
// Tries to select this plugin
|
||||
try {
|
||||
setSelected(true);
|
||||
} catch (java.beans.PropertyVetoException e) {
|
||||
// Could not select
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new collapsable area which may be used for holding model parameters.
|
||||
* @param title Title of area
|
||||
* @param contentPane Where this area should be added
|
||||
* @return New empty collapsable area
|
||||
*/
|
||||
private JPanel createCollapsableArea(String title, Container contentPane) {
|
||||
// Create panels
|
||||
JPanel holdingPanel = new JPanel() {
|
||||
public Dimension getMaximumSize() {
|
||||
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
|
||||
}
|
||||
};
|
||||
holdingPanel.setLayout(new BoxLayout(holdingPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
final JPanel collapsableArea = new JPanel() {
|
||||
public Dimension getMaximumSize() {
|
||||
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
|
||||
}
|
||||
};
|
||||
collapsableArea.setLayout(new BoxLayout(collapsableArea, BoxLayout.Y_AXIS));
|
||||
collapsableArea.setVisible(false);
|
||||
|
||||
JPanel titlePanel = new JPanel(new BorderLayout()) {
|
||||
public Dimension getMaximumSize() {
|
||||
return new Dimension(super.getMaximumSize().width, getPreferredSize().height);
|
||||
}
|
||||
};
|
||||
|
||||
titlePanel.add(BorderLayout.WEST, new JLabel(title));
|
||||
JCheckBox collapseCheckBox = new JCheckBox("show settings", false);
|
||||
collapseCheckBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (((JCheckBox) e.getSource()).isSelected())
|
||||
collapsableArea.setVisible(true);
|
||||
else
|
||||
collapsableArea.setVisible(false);
|
||||
}
|
||||
});
|
||||
collapsableArea.putClientProperty("my_checkbox", collapseCheckBox);
|
||||
|
||||
titlePanel.add(BorderLayout.EAST, collapseCheckBox);
|
||||
|
||||
collapsableArea.setBorder(
|
||||
BorderFactory.createLineBorder(Color.LIGHT_GRAY)
|
||||
);
|
||||
collapsableArea.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
|
||||
holdingPanel.add(titlePanel);
|
||||
holdingPanel.add(collapsableArea);
|
||||
|
||||
contentPane.add(holdingPanel);
|
||||
return collapsableArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds a panel with a label and a
|
||||
* text field which accepts doubles.
|
||||
*
|
||||
* @param id Identifier of new parameter
|
||||
* @param description Description of new parameter
|
||||
* @param contentPane Where to add created panel
|
||||
* @param initialValue Initial value
|
||||
* @return Text field in created panel
|
||||
*/
|
||||
private JFormattedTextField addDoubleParameter(String id, String description, Container contentPane, double initialValue) {
|
||||
JPanel panel = new JPanel();
|
||||
JLabel label;
|
||||
JFormattedTextField textField;
|
||||
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
|
||||
panel.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
panel.add(Box.createHorizontalStrut(10));
|
||||
panel.add(label = new JLabel(description));
|
||||
label.setPreferredSize(labelDimension);
|
||||
panel.add(Box.createHorizontalGlue());
|
||||
panel.add(textField = new JFormattedTextField(doubleFormat));
|
||||
textField.setValue(new Double(initialValue));
|
||||
textField.setColumns(4);
|
||||
textField.putClientProperty("id", id);
|
||||
textField.addPropertyChangeListener("value", new PropertyChangeListener() {
|
||||
public void propertyChange(PropertyChangeEvent e) {
|
||||
Object sourceObject = e.getSource();
|
||||
Double newValue = ((Number) e.getNewValue()).doubleValue();
|
||||
String id = (String) ((JFormattedTextField) sourceObject).getClientProperty("id");
|
||||
currentChannelModel.setParameterValue(id, newValue);
|
||||
}
|
||||
});
|
||||
allDoubleParameters.add(textField);
|
||||
|
||||
contentPane.add(panel);
|
||||
|
||||
return textField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds a panel with a label and a
|
||||
* text field which accepts integers.
|
||||
*
|
||||
* @param id Identifier of new parameter
|
||||
* @param description Description of new parameter
|
||||
* @param contentPane Where to add created panel
|
||||
* @param initialValue Initial value
|
||||
* @return Text field in created panel
|
||||
*/
|
||||
private JFormattedTextField addIntegerParameter(String id, String description, Container contentPane, int initialValue) {
|
||||
JPanel panel = new JPanel();
|
||||
JLabel label;
|
||||
JFormattedTextField textField;
|
||||
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
|
||||
panel.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
panel.add(Box.createHorizontalStrut(10));
|
||||
panel.add(label = new JLabel(description));
|
||||
label.setPreferredSize(labelDimension);
|
||||
panel.add(Box.createHorizontalGlue());
|
||||
panel.add(textField = new JFormattedTextField(integerFormat));
|
||||
textField.setValue(new Double(initialValue));
|
||||
textField.setColumns(4);
|
||||
textField.putClientProperty("id", id);
|
||||
textField.addPropertyChangeListener("value", new PropertyChangeListener() {
|
||||
public void propertyChange(PropertyChangeEvent e) {
|
||||
Object sourceObject = e.getSource();
|
||||
Integer newValue = ((Number) e.getNewValue()).intValue();
|
||||
String id = (String) ((JFormattedTextField) sourceObject).getClientProperty("id");
|
||||
currentChannelModel.setParameterValue(id, newValue);
|
||||
}
|
||||
});
|
||||
|
||||
allIntegerParameters.add(textField);
|
||||
|
||||
contentPane.add(panel);
|
||||
|
||||
return textField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds a panel with a label and a
|
||||
* boolean checkbox.
|
||||
*
|
||||
* @param id Identifier of new parameter
|
||||
* @param description Description of new parameter
|
||||
* @param contentPane Where to add created panel
|
||||
* @param initialValue Initial value
|
||||
* @return Checkbox in created panel
|
||||
*/
|
||||
private JCheckBox addBooleanParameter(String id, String description, Container contentPane, boolean initialValue) {
|
||||
JPanel panel = new JPanel();
|
||||
JLabel label;
|
||||
JCheckBox checkBox;
|
||||
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
|
||||
panel.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
panel.add(Box.createHorizontalStrut(10));
|
||||
panel.add(label = new JLabel(description));
|
||||
label.setPreferredSize(labelDimension);
|
||||
panel.add(Box.createHorizontalGlue());
|
||||
panel.add(checkBox = new JCheckBox());
|
||||
checkBox.setSelected(initialValue);
|
||||
checkBox.putClientProperty("id", id);
|
||||
checkBox.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JCheckBox source = (JCheckBox) e.getSource();
|
||||
currentChannelModel.setParameterValue(
|
||||
(String) source.getClientProperty("id"),
|
||||
new Boolean(source.isSelected())
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
allBooleanParameters.add(checkBox);
|
||||
|
||||
contentPane.add(panel);
|
||||
|
||||
return checkBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and adds a panel with a description label.
|
||||
*
|
||||
* @param description Description of new parameter
|
||||
* @param contentPane Where to add created panel
|
||||
* @return Created label
|
||||
*/
|
||||
private JLabel addLabelParameter(String description, Container contentPane) {
|
||||
JPanel panel = new JPanel();
|
||||
JLabel label;
|
||||
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
|
||||
panel.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
panel.add(Box.createHorizontalStrut(10));
|
||||
panel.add(label = new JLabel(description));
|
||||
label.setPreferredSize(labelDimension);
|
||||
panel.add(Box.createHorizontalGlue());
|
||||
|
||||
contentPane.add(panel);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens to settings changes in the channel model.
|
||||
* If it changes, all GUI parameters are updated accordingly.
|
||||
*/
|
||||
private Observer channelModelSettingsObserver = new Observer() {
|
||||
public void update(Observable obs, Object obj) {
|
||||
// Update all integers
|
||||
for (int i=0; i < allIntegerParameters.size(); i++) {
|
||||
JFormattedTextField textField = (JFormattedTextField) allIntegerParameters.get(i);
|
||||
String id = (String) textField.getClientProperty("id");
|
||||
textField.setValue(currentChannelModel.getParameterValue(id));
|
||||
}
|
||||
|
||||
// Update all doubles
|
||||
for (int i=0; i < allDoubleParameters.size(); i++) {
|
||||
JFormattedTextField textField = (JFormattedTextField) allDoubleParameters.get(i);
|
||||
String id = (String) textField.getClientProperty("id");
|
||||
textField.setValue(currentChannelModel.getParameterValue(id));
|
||||
}
|
||||
|
||||
// Update all booleans
|
||||
for (int i=0; i < allBooleanParameters.size(); i++) {
|
||||
JCheckBox checkBox = (JCheckBox) allBooleanParameters.get(i);
|
||||
String id = (String) checkBox.getClientProperty("id");
|
||||
checkBox.setSelected(currentChannelModel.getParameterBooleanValue(id));
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
};
|
||||
|
||||
public void closePlugin() {
|
||||
// Remove the channel model observer
|
||||
if (currentChannelModel != null && channelModelSettingsObserver != null) {
|
||||
currentChannelModel.deleteSettingsObserver(channelModelSettingsObserver);
|
||||
} else {
|
||||
logger.fatal("Can't remove channel model observer: " + channelModelSettingsObserver);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns XML elements representing the current configuration.
|
||||
*
|
||||
* @see #setConfigXML(Collection)
|
||||
* @return XML element collection
|
||||
*/
|
||||
public Collection<Element> getConfigXML() {
|
||||
Vector<Element> config = new Vector<Element>();
|
||||
Element element;
|
||||
|
||||
element = new Element("show_general");
|
||||
element.setText(Boolean.toString(areaGeneral.isVisible()));
|
||||
config.add(element);
|
||||
element = new Element("show_transmitter");
|
||||
element.setText(Boolean.toString(areaTransmitter.isVisible()));
|
||||
config.add(element);
|
||||
element = new Element("show_receiver");
|
||||
element.setText(Boolean.toString(areaReceiver.isVisible()));
|
||||
config.add(element);
|
||||
element = new Element("show_raytracer");
|
||||
element.setText(Boolean.toString(areaRayTracer.isVisible()));
|
||||
config.add(element);
|
||||
element = new Element("show_shadowing");
|
||||
element.setText(Boolean.toString(areaShadowing.isVisible()));
|
||||
config.add(element);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration depending on the given XML elements.
|
||||
*
|
||||
* @see #getConfigXML()
|
||||
* @param configXML
|
||||
* Config XML elements
|
||||
* @return True if config was set successfully, false otherwise
|
||||
*/
|
||||
public boolean setConfigXML(Collection<Element> configXML) {
|
||||
for (Element element : configXML) {
|
||||
if (element.getName().equals("show_general")) {
|
||||
JCheckBox checkBox = (JCheckBox) areaGeneral.getClientProperty("my_checkbox");
|
||||
checkBox.setSelected(Boolean.parseBoolean(element.getText()));
|
||||
checkBox.getActionListeners()[0].actionPerformed(new ActionEvent(checkBox,
|
||||
ActionEvent.ACTION_PERFORMED, ""));
|
||||
} else if (element.getName().equals("show_transmitter")) {
|
||||
JCheckBox checkBox = (JCheckBox) areaTransmitter.getClientProperty("my_checkbox");
|
||||
checkBox.setSelected(Boolean.parseBoolean(element.getText()));
|
||||
checkBox.getActionListeners()[0].actionPerformed(new ActionEvent(checkBox,
|
||||
ActionEvent.ACTION_PERFORMED, ""));
|
||||
} else if (element.getName().equals("show_receiver")) {
|
||||
JCheckBox checkBox = (JCheckBox) areaReceiver.getClientProperty("my_checkbox");
|
||||
checkBox.setSelected(Boolean.parseBoolean(element.getText()));
|
||||
checkBox.getActionListeners()[0].actionPerformed(new ActionEvent(checkBox,
|
||||
ActionEvent.ACTION_PERFORMED, ""));
|
||||
} else if (element.getName().equals("show_raytracer")) {
|
||||
JCheckBox checkBox = (JCheckBox) areaRayTracer.getClientProperty("my_checkbox");
|
||||
checkBox.setSelected(Boolean.parseBoolean(element.getText()));
|
||||
checkBox.getActionListeners()[0].actionPerformed(new ActionEvent(checkBox,
|
||||
ActionEvent.ACTION_PERFORMED, ""));
|
||||
} else if (element.getName().equals("show_shadowing")) {
|
||||
JCheckBox checkBox = (JCheckBox) areaShadowing.getClientProperty("my_checkbox");
|
||||
checkBox.setSelected(Boolean.parseBoolean(element.getText()));
|
||||
checkBox.getActionListeners()[0].actionPerformed(new ActionEvent(checkBox,
|
||||
ActionEvent.ACTION_PERFORMED, ""));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
package se.sics.arm;
|
||||
|
||||
import java.util.Vector;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* This class represents a interval. Some operations on these intervals exist,
|
||||
* such as intersecting a interval with another and subtracting an interval from
|
||||
* another.
|
||||
*
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
class Interval {
|
||||
private static Logger logger = Logger.getLogger(Interval.class);
|
||||
|
||||
private double lowValue;
|
||||
private double highValue;
|
||||
|
||||
/**
|
||||
* Creates a new double interval.
|
||||
* The given low value must be lower than the given high value.
|
||||
*
|
||||
* @param lowValue Low interval border (< End interval border)
|
||||
* @param highValue High interval border
|
||||
*/
|
||||
public Interval(double lowValue, double highValue) {
|
||||
this.lowValue = Math.min(lowValue, highValue);
|
||||
this.highValue = highValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new values of interval
|
||||
*
|
||||
* @param newLow New low value
|
||||
* @param newHigh New high value
|
||||
*/
|
||||
public void setInterval(double newLow, double newHigh) {
|
||||
lowValue = newLow;
|
||||
highValue = newHigh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Low border value
|
||||
*/
|
||||
public double getLow() {
|
||||
return lowValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return High border value
|
||||
*/
|
||||
public double getHigh() {
|
||||
return highValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Size of interval
|
||||
*/
|
||||
public double getSize() {
|
||||
return highValue - lowValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intersection between this interval and the given
|
||||
* interval or null if no intersection exists.
|
||||
*
|
||||
* @param interval Other interval
|
||||
* @return Intersection interval
|
||||
*/
|
||||
public Interval intersectWith(Interval interval) {
|
||||
// Given interval higher than this interval
|
||||
if (highValue <= interval.getLow())
|
||||
return null;
|
||||
|
||||
// Given interval lower than this interval
|
||||
if (lowValue >= interval.getHigh())
|
||||
return null;
|
||||
|
||||
// Given interval covers this interval
|
||||
if (lowValue >= interval.getLow() &&
|
||||
highValue <= interval.getHigh())
|
||||
return this;
|
||||
|
||||
// Given interval inside this interval
|
||||
if (lowValue <= interval.getLow() &&
|
||||
highValue >= interval.getHigh())
|
||||
return interval;
|
||||
|
||||
// Given interval overlaps lower part of this interval
|
||||
if (lowValue >= interval.getLow() &&
|
||||
highValue >= interval.getHigh())
|
||||
return new Interval(lowValue, interval.getHigh());
|
||||
|
||||
// Given interval overlaps upper part of this interval
|
||||
if (lowValue <= interval.getLow() &&
|
||||
highValue <= interval.getHigh())
|
||||
return new Interval(interval.getLow(), highValue);
|
||||
|
||||
logger.fatal("DoubleInterval.intersectWithInterval(), error!");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given interval is a subset of this interval.
|
||||
*
|
||||
* @param interval Other interval
|
||||
* @return True if this interval contains the given interval
|
||||
*/
|
||||
public boolean contains(Interval interval) {
|
||||
return getLow() <= interval.getLow() && getHigh() >= interval.getHigh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new intervals consisting of this interval with the given interval removed.
|
||||
* These can either be null (if entire interval was removed),
|
||||
* one interval (if upper or lower part, or nothing was removed) or two intervals
|
||||
* (if middle part of interval was removed).
|
||||
*
|
||||
* @param interval Other interval
|
||||
* @return New intervals
|
||||
*/
|
||||
public Vector<Interval> subtract(Interval interval) {
|
||||
Vector<Interval> returnIntervals = new Vector<Interval>();
|
||||
|
||||
// Given interval higher than this interval
|
||||
if (highValue <= interval.getLow()) {
|
||||
returnIntervals.add(this);
|
||||
return returnIntervals;
|
||||
}
|
||||
|
||||
// Given interval lower than this interval
|
||||
if (lowValue >= interval.getHigh()) {
|
||||
returnIntervals.add(this);
|
||||
return returnIntervals;
|
||||
}
|
||||
|
||||
// Given interval covers this interval
|
||||
if (lowValue >= interval.getLow() &&
|
||||
highValue <= interval.getHigh()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Given interval inside this interval
|
||||
if (lowValue <= interval.getLow() &&
|
||||
highValue >= interval.getHigh()) {
|
||||
returnIntervals.add(new Interval(lowValue, interval.getLow()));
|
||||
returnIntervals.add(new Interval(interval.getHigh(), highValue));
|
||||
return returnIntervals;
|
||||
}
|
||||
|
||||
// Given interval overlaps lower part of this interval
|
||||
if (lowValue >= interval.getLow() &&
|
||||
highValue >= interval.getHigh()) {
|
||||
returnIntervals.add(new Interval(interval.getHigh(), highValue));
|
||||
return returnIntervals;
|
||||
}
|
||||
|
||||
// Given interval overlaps upper part of this interval
|
||||
if (lowValue <= interval.getLow() &&
|
||||
highValue <= interval.getHigh()) {
|
||||
returnIntervals.add(new Interval(lowValue, interval.getLow()));
|
||||
return returnIntervals;
|
||||
}
|
||||
|
||||
logger.fatal("DoubleInterval.subtractInterval(), error!");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts given interval from all intervals in given vector.
|
||||
* This method never returns null (but empty vectors).
|
||||
*
|
||||
* @param initialIntervals Initial intervals
|
||||
* @param interval Interval to subtract
|
||||
* @return New intervals
|
||||
*/
|
||||
static public Vector<Interval> subtract(Vector<Interval> initialIntervals, Interval interval) {
|
||||
Vector<Interval> newIntervals = new Vector<Interval>();
|
||||
for (int i=0; i < initialIntervals.size(); i++) {
|
||||
Vector<Interval> tempIntervals = initialIntervals.get(i).subtract(interval);
|
||||
if (tempIntervals != null)
|
||||
newIntervals.addAll(tempIntervals);
|
||||
}
|
||||
return newIntervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if interval does not have a length.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
if (highValue <= lowValue)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (isEmpty())
|
||||
return "Double interval: (null)";
|
||||
else
|
||||
return "Double interval: " +
|
||||
getLow() +
|
||||
" -> " +
|
||||
getHigh();
|
||||
}
|
||||
}
|
|
@ -1,621 +0,0 @@
|
|||
package se.sics.arm;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.geom.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jdom.Element;
|
||||
|
||||
/**
|
||||
* This class represents an area with obstacles.
|
||||
* Obstacles may only be of rectangular shape.
|
||||
*
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
class ObstacleWorld {
|
||||
private static Logger logger = Logger.getLogger(ObstacleWorld.class);
|
||||
|
||||
// All registered obstacles
|
||||
private Vector<Rectangle2D> allObstacles = null;
|
||||
|
||||
// All registered obstacles, with spatial information
|
||||
private int spatialResolution = 10;
|
||||
private Vector<Rectangle2D>[][] allObstaclesSpatial = new Vector[spatialResolution][spatialResolution];
|
||||
private boolean obstaclesOrganized = false;
|
||||
|
||||
// Outer bounds of all obstacles
|
||||
private Rectangle2D outerBounds = null;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new obstacle world without any obstacles.
|
||||
*/
|
||||
public ObstacleWorld() {
|
||||
// No obstacles present so far
|
||||
allObstacles = new Vector<Rectangle2D>();
|
||||
|
||||
for (int x=0; x < spatialResolution; x++)
|
||||
for (int y=0; y < spatialResolution; y++)
|
||||
allObstaclesSpatial[x][y] = new Vector<Rectangle2D>();
|
||||
|
||||
outerBounds = new Rectangle2D.Double(0,0,0,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The total number of registered obstacles
|
||||
*/
|
||||
public int getNrObstacles() {
|
||||
return allObstacles.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used to find extreme coordinates of all obstacles.
|
||||
*
|
||||
* @return Outer bounds of all registered obstacles
|
||||
*/
|
||||
public Rectangle2D getOuterBounds() {
|
||||
return outerBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns obstacle registered at given position.
|
||||
* The coordinates of an obstacles should never
|
||||
* be changed directly on an object returned by this method.
|
||||
*
|
||||
* @param i Obstacle position
|
||||
* @return Obstacle at given position
|
||||
*/
|
||||
public Rectangle2D getObstacle(int i) {
|
||||
return allObstacles.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All registered obstacles
|
||||
*/
|
||||
public Vector<Rectangle2D> getAllObstacles() {
|
||||
return allObstacles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns at least all registered obstacles that contains given point.
|
||||
* Note that obstacles close to but not containing the point may also
|
||||
* be returned.
|
||||
*
|
||||
* @param center Center point
|
||||
* @return All obstacles containing or near center
|
||||
*/
|
||||
public Vector<Rectangle2D> getAllObstaclesNear(Point2D center) {
|
||||
double boxWidth = outerBounds.getWidth() / (double) spatialResolution;
|
||||
double boxHeight = outerBounds.getHeight() / (double) spatialResolution;
|
||||
double areaStartX = outerBounds.getMinX();
|
||||
double areaStartY = outerBounds.getMinY();
|
||||
|
||||
double centerX = (center.getX() - areaStartX)/boxWidth;
|
||||
double centerY = (center.getY() - areaStartY)/boxHeight;
|
||||
|
||||
Vector<Rectangle2D> allNearObstacles = new Vector<Rectangle2D>();
|
||||
|
||||
Point pointToAdd = new Point((int) centerX, (int) centerY);
|
||||
if (pointToAdd.x >= 0 &&
|
||||
pointToAdd.x < allObstaclesSpatial.length &&
|
||||
pointToAdd.y >= 0 &&
|
||||
pointToAdd.y < allObstaclesSpatial[0].length)
|
||||
allNearObstacles.addAll(allObstaclesSpatial[pointToAdd.x][pointToAdd.y]);
|
||||
|
||||
// Add borders if needed
|
||||
boolean addedXBorder = false;
|
||||
boolean addedYBorder = false;
|
||||
if (Math.floor(centerX) == centerX) {
|
||||
pointToAdd = new Point((int) centerX-1, (int) centerY);
|
||||
if (pointToAdd.x >= 0 &&
|
||||
pointToAdd.x < allObstaclesSpatial.length &&
|
||||
pointToAdd.y >= 0 &&
|
||||
pointToAdd.y < allObstaclesSpatial[0].length) {
|
||||
allNearObstacles.addAll(allObstaclesSpatial[pointToAdd.x][pointToAdd.y]);
|
||||
addedXBorder = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.floor(centerY) == centerY) {
|
||||
pointToAdd = new Point((int) centerX, (int) centerY-1);
|
||||
if (pointToAdd.x >= 0 &&
|
||||
pointToAdd.x < allObstaclesSpatial.length &&
|
||||
pointToAdd.y >= 0 &&
|
||||
pointToAdd.y < allObstaclesSpatial[0].length) {
|
||||
allNearObstacles.addAll(allObstaclesSpatial[pointToAdd.x][pointToAdd.y]);
|
||||
addedYBorder = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (addedXBorder && addedYBorder) {
|
||||
pointToAdd = new Point((int) centerX-1, (int) centerY-1);
|
||||
allNearObstacles.addAll(allObstaclesSpatial[pointToAdd.x][pointToAdd.y]);
|
||||
}
|
||||
|
||||
return allNearObstacles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns at least all registered obstacles inside the given angle
|
||||
* interval when at the given center point. Note that obstacles partly or
|
||||
* completely outside the interval may also be returned.
|
||||
* All obstacles are preferably returned in order of distance from given
|
||||
* center point, although this is not guaranteed.
|
||||
*
|
||||
* @param center Center point
|
||||
* @param angleInterval Angle interval
|
||||
* @return All obstacles in given angle interval
|
||||
*/
|
||||
public Vector<Rectangle2D> getAllObstaclesInAngleInterval(Point2D center, AngleInterval angleInterval) {
|
||||
Vector<Rectangle2D> obstaclesToReturn = new Vector<Rectangle2D>();
|
||||
if (!obstaclesOrganized) {
|
||||
reorganizeSpatialObstacles();
|
||||
}
|
||||
|
||||
double boxWidth = outerBounds.getWidth() / (double) spatialResolution;
|
||||
double boxHeight = outerBounds.getHeight() / (double) spatialResolution;
|
||||
double areaStartX = outerBounds.getMinX();
|
||||
double areaStartY = outerBounds.getMinY();
|
||||
|
||||
// Calculate which boxes to check (and in which order)
|
||||
Point centerInArray = new Point(
|
||||
(int) ((center.getX() - areaStartX)/boxWidth),
|
||||
(int) ((center.getY() - areaStartY)/boxHeight)
|
||||
);
|
||||
Vector<Point> pointsToCheck = new Vector<Point>();
|
||||
|
||||
int currentDistance = 0;
|
||||
while (currentDistance < 2*spatialResolution) {
|
||||
|
||||
if (currentDistance > 0) {
|
||||
int currentX = centerInArray.x - currentDistance;
|
||||
int currentY = centerInArray.y - currentDistance;
|
||||
|
||||
// Step right
|
||||
while (currentX < centerInArray.x + currentDistance) {
|
||||
if (currentX >= 0 &&
|
||||
currentX < allObstaclesSpatial.length &&
|
||||
currentY >= 0 &&
|
||||
currentY < allObstaclesSpatial[0].length)
|
||||
pointsToCheck.add(new Point(currentX, currentY));
|
||||
currentX++;
|
||||
}
|
||||
|
||||
// Step right
|
||||
while (currentY < centerInArray.y + currentDistance) {
|
||||
if (currentX >= 0 &&
|
||||
currentX < allObstaclesSpatial.length &&
|
||||
currentY >= 0 &&
|
||||
currentY < allObstaclesSpatial[0].length)
|
||||
pointsToCheck.add(new Point(currentX, currentY));
|
||||
currentY++;
|
||||
}
|
||||
|
||||
// Step left
|
||||
while (currentX > centerInArray.x - currentDistance) {
|
||||
if (currentX >= 0 &&
|
||||
currentX < allObstaclesSpatial.length &&
|
||||
currentY >= 0 &&
|
||||
currentY < allObstaclesSpatial[0].length)
|
||||
pointsToCheck.add(new Point(currentX, currentY));
|
||||
currentX--;
|
||||
}
|
||||
|
||||
// Step up
|
||||
while (currentY > centerInArray.y - currentDistance) {
|
||||
if (currentX >= 0 &&
|
||||
currentX < allObstaclesSpatial.length &&
|
||||
currentY >= 0 &&
|
||||
currentY < allObstaclesSpatial[0].length)
|
||||
pointsToCheck.add(new Point(currentX, currentY));
|
||||
currentY--;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (centerInArray.x >= 0 &&
|
||||
centerInArray.x < allObstaclesSpatial.length &&
|
||||
centerInArray.y >= 0 &&
|
||||
centerInArray.y < allObstaclesSpatial[0].length) {
|
||||
pointsToCheck.add(new Point(centerInArray.x, centerInArray.y));
|
||||
}
|
||||
}
|
||||
currentDistance++;
|
||||
}
|
||||
|
||||
for (int pointNr=0; pointNr < pointsToCheck.size(); pointNr++) {
|
||||
// Check which obstacles should be in this box
|
||||
boolean hit = false;
|
||||
int x = pointsToCheck.get(pointNr).x;
|
||||
int y = pointsToCheck.get(pointNr).y;
|
||||
|
||||
// Test if we are inside test box
|
||||
if (!hit) {
|
||||
if (new Rectangle2D.Double(
|
||||
areaStartX + x*boxWidth,
|
||||
areaStartY + y*boxHeight,
|
||||
boxWidth,
|
||||
boxHeight).contains(center)) {
|
||||
hit = true;
|
||||
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++) {
|
||||
if (!obstaclesToReturn.contains(allObstaclesSpatial[x][y].get(i)))
|
||||
obstaclesToReturn.add(allObstaclesSpatial[x][y].get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test first diagonal
|
||||
if (!hit) {
|
||||
AngleInterval testInterval = AngleInterval.getAngleIntervalOfLine(
|
||||
center,
|
||||
new Line2D.Double(
|
||||
areaStartX + x*boxWidth,
|
||||
areaStartY + y*boxHeight,
|
||||
areaStartX + (x+1)*boxWidth,
|
||||
areaStartY + (y+1)*boxHeight)
|
||||
);
|
||||
if (testInterval.intersects(angleInterval)) {
|
||||
hit = true;
|
||||
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++) {
|
||||
if (!obstaclesToReturn.contains(allObstaclesSpatial[x][y].get(i)))
|
||||
obstaclesToReturn.add(allObstaclesSpatial[x][y].get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test second diagonal
|
||||
if (!hit) {
|
||||
AngleInterval testInterval = AngleInterval.getAngleIntervalOfLine(
|
||||
center,
|
||||
new Line2D.Double(
|
||||
areaStartX + x*boxWidth,
|
||||
areaStartY + (y+1)*boxHeight,
|
||||
areaStartX + (x+1)*boxWidth,
|
||||
areaStartY + y*boxHeight)
|
||||
);
|
||||
if (testInterval.intersects(angleInterval)) {
|
||||
hit = true;
|
||||
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++) {
|
||||
if (!obstaclesToReturn.contains(allObstaclesSpatial[x][y].get(i)))
|
||||
obstaclesToReturn.add(allObstaclesSpatial[x][y].get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obstaclesToReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all registered obstacles.
|
||||
*/
|
||||
public void removeAll() {
|
||||
allObstacles.removeAllElements();
|
||||
for (int x=0; x < spatialResolution; x++)
|
||||
for (int y=0; y < spatialResolution; y++)
|
||||
allObstaclesSpatial[x][y].removeAllElements();
|
||||
|
||||
outerBounds = new Rectangle2D.Double(0,0,0,0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true of given point is on a corner of
|
||||
* any of the structures build from the obstacles.
|
||||
* Internally this method checks how many of four point
|
||||
* close to and located around given point (diagonally) are
|
||||
* inside any obstacle.
|
||||
* This method returns true if exactly one point is inside an obstacle.
|
||||
*
|
||||
* @param point Point to check
|
||||
* @return True of point is on a corner, false otherwise
|
||||
*/
|
||||
public boolean pointIsNearCorner(Point2D point) {
|
||||
double boxWidth = outerBounds.getWidth() / (double) spatialResolution;
|
||||
double boxHeight = outerBounds.getHeight() / (double) spatialResolution;
|
||||
double areaStartX = outerBounds.getMinX();
|
||||
double areaStartY = outerBounds.getMinY();
|
||||
|
||||
// Which obstacles should be checked
|
||||
Point centerInArray = new Point(
|
||||
(int) ((point.getX() - areaStartX)/boxWidth),
|
||||
(int) ((point.getY() - areaStartY)/boxHeight)
|
||||
);
|
||||
Vector<Rectangle2D> allObstaclesToCheck = null;
|
||||
if (centerInArray.x < 0)
|
||||
centerInArray.x = 0;
|
||||
if (centerInArray.x >= spatialResolution)
|
||||
centerInArray.x = spatialResolution-1;
|
||||
if (centerInArray.y < 0)
|
||||
centerInArray.y = 0;
|
||||
if (centerInArray.y >= spatialResolution)
|
||||
centerInArray.y = spatialResolution-1;
|
||||
|
||||
allObstaclesToCheck = allObstaclesSpatial[centerInArray.x][centerInArray.y];
|
||||
|
||||
if (allObstaclesToCheck.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the four point to check
|
||||
double deltaDistance = 0.01; // 1 cm TODO Change this?
|
||||
Point2D point1 = new Point2D.Double(point.getX() - deltaDistance, point.getY() - deltaDistance);
|
||||
Point2D point2 = new Point2D.Double(point.getX() - deltaDistance, point.getY() + deltaDistance);
|
||||
Point2D point3 = new Point2D.Double(point.getX() + deltaDistance, point.getY() - deltaDistance);
|
||||
Point2D point4 = new Point2D.Double(point.getX() + deltaDistance, point.getY() + deltaDistance);
|
||||
|
||||
int containedPoints = 0;
|
||||
Enumeration<Rectangle2D> allObstaclesToCheckEnum = allObstaclesToCheck.elements();
|
||||
while (allObstaclesToCheckEnum.hasMoreElements()) {
|
||||
Rectangle2D obstacleToCheck = allObstaclesToCheckEnum.nextElement();
|
||||
if (obstacleToCheck.contains(point1))
|
||||
containedPoints++;
|
||||
if (obstacleToCheck.contains(point2))
|
||||
containedPoints++;
|
||||
if (obstacleToCheck.contains(point3))
|
||||
containedPoints++;
|
||||
if (obstacleToCheck.contains(point4))
|
||||
containedPoints++;
|
||||
|
||||
// Abort if already to many contained points
|
||||
if (containedPoints > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (containedPoints == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if specified obstacle can be merged with any existing obstacle
|
||||
* in order to reduce the total number of obstacles. And in that case a merge
|
||||
* is performed and this method returns the new obstacle object.
|
||||
* The checking is performed by looping through all existing obstacles and
|
||||
* for each one comparing the union area of it and the given obstacle to the
|
||||
* area sum of the two. And since obstacles are not allowed to overlap, if the
|
||||
* union area is equal to the area sum, they can be merged.
|
||||
* If a merge is performed, another may be made possible so this method
|
||||
* should be looped until returning null.
|
||||
*
|
||||
* This method does not notify observers of changes made!
|
||||
*
|
||||
* @return New object of a merge was performed, null otherwise
|
||||
*/
|
||||
private Rectangle2D mergeObstacle(Rectangle2D mergeObstacle) {
|
||||
double mergeObstacleArea = mergeObstacle.getWidth() * mergeObstacle.getHeight();
|
||||
double mergeObstacleTolerance = mergeObstacleArea * 0.01; // 1%
|
||||
|
||||
// Loop through all existing obstacles (but ignore itself)
|
||||
for (int i=0; i < getNrObstacles(); i++) {
|
||||
Rectangle2D existingObstacle = getObstacle(i);
|
||||
if (!existingObstacle.equals(mergeObstacle)) {
|
||||
double existingObstacleArea = existingObstacle.getWidth() * existingObstacle.getHeight();
|
||||
Rectangle2D unionObstacle = existingObstacle.createUnion(mergeObstacle);
|
||||
double unionArea = unionObstacle.getWidth() * unionObstacle.getHeight();
|
||||
|
||||
// Fault-tolerance
|
||||
double faultTolerance = Math.min(mergeObstacleTolerance, existingObstacleArea*0.01);
|
||||
|
||||
// Compare areas
|
||||
if (unionArea - faultTolerance <= existingObstacleArea + mergeObstacleArea) {
|
||||
// Remove both old obstacles, add union
|
||||
removeObstacle(mergeObstacle);
|
||||
removeObstacle(existingObstacle);
|
||||
addObstacle(unionObstacle, false);
|
||||
|
||||
obstaclesOrganized = false;
|
||||
return unionObstacle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new obstacle with given attributes.
|
||||
* This method will try to merge this obstacle with other already existing obstacles.
|
||||
*
|
||||
* @param startX Start X coordinate
|
||||
* @param startY Start Y coordinate
|
||||
* @param width Width
|
||||
* @param height Height
|
||||
*/
|
||||
public void addObstacle(double startX, double startY, double width, double height) {
|
||||
addObstacle(startX, startY, width, height, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new obstacle with given attributes.
|
||||
* This method will, depending on given argument, try to merge
|
||||
* this obstacle with other already existing obstacles.
|
||||
*
|
||||
* @param startX Start X coordinate
|
||||
* @param startY Start Y coordinate
|
||||
* @param width Width
|
||||
* @param height Height
|
||||
* @param merge Should this obstacle, if possible, be merged with existing obstacles
|
||||
*/
|
||||
public void addObstacle(double startX, double startY, double width, double height, boolean merge) {
|
||||
Rectangle2D newRect = new Rectangle2D.Double(startX, startY, width, height);
|
||||
addObstacle(newRect, merge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a given obstacle.
|
||||
* This method will try to merge this obstacle with other already existing obstacles.
|
||||
*
|
||||
* @param obstacle New obstacle
|
||||
*/
|
||||
public void addObstacle(Rectangle2D obstacle) {
|
||||
addObstacle(obstacle, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a given obstacle.
|
||||
* This method will, depending on the given argument, try to
|
||||
* merge this obstacle with other already existing obstacles.
|
||||
*
|
||||
* @param obstacle New obstacle
|
||||
*/
|
||||
public void addObstacle(Rectangle2D obstacle, boolean merge) {
|
||||
// TODO Should we keep the rounding?
|
||||
obstacle.setRect(
|
||||
Math.round(obstacle.getMinX()*1000.0) / 1000.0,
|
||||
Math.round(obstacle.getMinY()*1000.0) / 1000.0,
|
||||
Math.round(obstacle.getWidth()*1000.0) / 1000.0,
|
||||
Math.round(obstacle.getHeight()*1000.0) / 1000.0
|
||||
);
|
||||
|
||||
allObstacles.add(obstacle);
|
||||
outerBounds = outerBounds.createUnion(obstacle);
|
||||
|
||||
if (merge) {
|
||||
// Check if obstacle can be merged with another obstacle
|
||||
Rectangle2D mergedObstacle = mergeObstacle(obstacle);
|
||||
|
||||
// Keep merging...
|
||||
while (mergedObstacle != null)
|
||||
mergedObstacle = mergeObstacle(mergedObstacle);
|
||||
}
|
||||
|
||||
obstaclesOrganized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given obstacle, if it exists.
|
||||
*
|
||||
* @param obstacle Obstacle to remove
|
||||
*/
|
||||
public void removeObstacle(Rectangle2D obstacle) {
|
||||
allObstacles.remove(obstacle);
|
||||
|
||||
recreateOuterBounds();
|
||||
obstaclesOrganized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method recreates the outer bounds of
|
||||
* this obstacle area by checking all registered
|
||||
* obstacles.
|
||||
* This method should never have to be called directly
|
||||
* by a user.
|
||||
*/
|
||||
public void recreateOuterBounds() {
|
||||
outerBounds = new Rectangle2D.Double(0,0,0,0);
|
||||
for (int i=0; i < allObstacles.size(); i++) {
|
||||
outerBounds = outerBounds.createUnion(allObstacles.get(i));
|
||||
}
|
||||
obstaclesOrganized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorganizes all registered obstacles in order to speed up
|
||||
* searches for obstacles in spatial areas.
|
||||
* This method is run automatically
|
||||
*/
|
||||
public void reorganizeSpatialObstacles() {
|
||||
// Remove all spatial obstacles
|
||||
for (int x=0; x < spatialResolution; x++)
|
||||
for (int y=0; y < spatialResolution; y++)
|
||||
allObstaclesSpatial[x][y].removeAllElements();
|
||||
|
||||
double boxWidth = outerBounds.getWidth() / (double) spatialResolution;
|
||||
double boxHeight = outerBounds.getHeight() / (double) spatialResolution;
|
||||
double currentBoxMinX = outerBounds.getMinX();
|
||||
double currentBoxMinY = outerBounds.getMinY();
|
||||
|
||||
// For each box, add obstacles that belong there
|
||||
for (int x=0; x < spatialResolution; x++)
|
||||
for (int y=0; y < spatialResolution; y++) {
|
||||
// Check which obstacles should be in this box
|
||||
Rectangle2D boxToCheck = new Rectangle2D.Double(currentBoxMinX + x*boxWidth, currentBoxMinY + y*boxHeight, boxWidth, boxHeight);
|
||||
for (int i=0; i < allObstacles.size(); i++) {
|
||||
if (allObstacles.get(i).intersects(boxToCheck)) {
|
||||
allObstaclesSpatial[x][y].add(allObstacles.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obstaclesOrganized = true;
|
||||
|
||||
//printObstacleGridToConsole();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a description of all obstacles to the console
|
||||
*/
|
||||
public void printObstacleGridToConsole() {
|
||||
logger.info("<<<<<<< printObstacleGridToConsole >>>>>>>");
|
||||
logger.info(". Number of obstacles:\t" + getNrObstacles());
|
||||
logger.info(". Outer boundary min:\t" + getOuterBounds().getMinX() + ", " + getOuterBounds().getMinY());
|
||||
logger.info(". Outer boundary max:\t" + getOuterBounds().getMaxX() + ", " + getOuterBounds().getMaxY());
|
||||
|
||||
Vector<Rectangle2D> uniqueSpatialObstacles = new Vector<Rectangle2D>();
|
||||
for (int x=0; x < spatialResolution; x++)
|
||||
for (int y=0; y < spatialResolution; y++)
|
||||
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++)
|
||||
if (!uniqueSpatialObstacles.contains(allObstaclesSpatial[x][y].get(i)))
|
||||
uniqueSpatialObstacles.add(allObstaclesSpatial[x][y].get(i));
|
||||
logger.info(". Unique spatial obstacles:\t" + uniqueSpatialObstacles.size());
|
||||
|
||||
int allSpatialObstacles = 0;
|
||||
for (int x=0; x < spatialResolution; x++)
|
||||
for (int y=0; y < spatialResolution; y++)
|
||||
for (int i=0; i < allObstaclesSpatial[x][y].size(); i++)
|
||||
allSpatialObstacles++;
|
||||
logger.debug(". All spatial obstacles:\t" + allSpatialObstacles);
|
||||
|
||||
logger.info(". Spatial map counts:");
|
||||
for (int y=0; y < spatialResolution; y++) {
|
||||
for (int x=0; x < spatialResolution; x++) {
|
||||
System.out.print(allObstaclesSpatial[x][y].size() + " ");
|
||||
}
|
||||
System.out.println("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns XML elements representing the current obstacles.
|
||||
*
|
||||
* @see #setConfigXML(Collection)
|
||||
* @return XML elements representing the obstacles
|
||||
*/
|
||||
public Collection<Element> getConfigXML() {
|
||||
Vector<Element> config = new Vector<Element>();
|
||||
Element element;
|
||||
|
||||
for (Rectangle2D rect: allObstacles) {
|
||||
element = new Element("obst");
|
||||
element.setText(rect.getMinX() + ";" + rect.getMinY() + ";" + rect.getWidth() + ";" + rect.getHeight());
|
||||
config.add(element);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current obstacles depending on the given XML elements.
|
||||
*
|
||||
* @see #getConfigXML()
|
||||
* @param configXML
|
||||
* Config XML elements
|
||||
* @return True if config was set successfully, false otherwise
|
||||
*/
|
||||
public boolean setConfigXML(Collection<Element> configXML) {
|
||||
for (Element element : configXML) {
|
||||
if (element.getName().equals("obst")) {
|
||||
String rectValues[] = element.getText().split(";");
|
||||
Rectangle2D newObst = new Rectangle2D.Double(
|
||||
Double.parseDouble(rectValues[0]),
|
||||
Double.parseDouble(rectValues[1]),
|
||||
Double.parseDouble(rectValues[2]),
|
||||
Double.parseDouble(rectValues[3]));
|
||||
this.addObstacle(newObst, false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
package se.sics.arm;
|
||||
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
/**
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
class RayData {
|
||||
|
||||
enum RayType { ORIGIN, REFRACTION, REFLECTION, DIFFRACTION, DESTINATION }
|
||||
RayType type;
|
||||
|
||||
private Point2D sourcePoint = null;
|
||||
private Line2D line = null;
|
||||
|
||||
private int limitOverall = 0;
|
||||
private int limitRefracted = 0;
|
||||
private int limitReflected = 0;
|
||||
private int limitDiffracted = 0;
|
||||
|
||||
/**
|
||||
* Creates a new ray data instance.
|
||||
* A ray can be of the following types:
|
||||
*
|
||||
* ORIGIN - starting at source point, line should be null
|
||||
* REFRACTED - ray was refracted at an obstacle,
|
||||
* source is intersection point with obstacle, line should be null
|
||||
* REFLECTED - an interval of rays is reflected at given line,
|
||||
* the source point should be a "psuedo-source" is located behind it
|
||||
* (as if one was looking from given source point through given line)
|
||||
* DIFFRACTED - a ray is diffracted at given source point,
|
||||
* line should be null
|
||||
* DESTINATION
|
||||
* @param type Type of ray (one of the above)
|
||||
* @param sourcePoint See above
|
||||
* @param line See above (may be null)
|
||||
* @param limitOverall Maximum numbers of sub rays this ray may produce
|
||||
* @param limitRefracted Maximum numbers of refracted sub rays this ray may produce
|
||||
* @param limitReflected Maximum numbers of reflected sub rays this ray may produce
|
||||
* @param limitDiffracted Maximum numbers of diffracted sub rays this ray may produce
|
||||
*/
|
||||
public RayData(
|
||||
RayType type,
|
||||
Point2D sourcePoint,
|
||||
Line2D line,
|
||||
int limitOverall,
|
||||
int limitRefracted,
|
||||
int limitReflected,
|
||||
int limitDiffracted
|
||||
) {
|
||||
this.type = type;
|
||||
this.sourcePoint = sourcePoint;
|
||||
this.line = line;
|
||||
this.limitOverall = limitOverall;
|
||||
this.limitRefracted = limitRefracted;
|
||||
this.limitReflected = limitReflected;
|
||||
this.limitDiffracted = limitDiffracted;
|
||||
}
|
||||
|
||||
public RayType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Point2D getSourcePoint() {
|
||||
return sourcePoint;
|
||||
}
|
||||
|
||||
public Line2D getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public int getSubRaysLimit() {
|
||||
return Math.min(limitOverall, limitRefracted + limitReflected + limitDiffracted);
|
||||
}
|
||||
|
||||
public int getRefractedSubRaysLimit() {
|
||||
return Math.min(limitOverall, limitRefracted);
|
||||
}
|
||||
|
||||
public int getReflectedSubRaysLimit() {
|
||||
return Math.min(limitOverall, limitReflected);
|
||||
}
|
||||
|
||||
public int getDiffractedSubRaysLimit() {
|
||||
return Math.min(limitOverall, limitDiffracted);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package se.sics.arm;
|
||||
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* @author Fredrik Osterlind
|
||||
*/
|
||||
public class RayPath {
|
||||
private Vector<Point2D> points = new Vector<Point2D>();
|
||||
private Vector<RayData.RayType> types = new Vector<RayData.RayType>();
|
||||
|
||||
public void addPoint(Point2D point, RayData.RayType type) {
|
||||
points.insertElementAt(point, 0);
|
||||
types.insertElementAt(type, 0);
|
||||
}
|
||||
|
||||
public int getSubPathCount() {
|
||||
return points.size() - 1;
|
||||
}
|
||||
|
||||
public Line2D getSubPath(int pos) {
|
||||
return new Line2D.Double(points.get(pos), points.get(pos + 1));
|
||||
}
|
||||
|
||||
public Point2D getPoint(int i) {
|
||||
return points.get(i);
|
||||
}
|
||||
|
||||
public RayData.RayType getType(int i) {
|
||||
return types.get(i);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (points.size() != types.size())
|
||||
return "Malformed ray path (differing sizes)";
|
||||
|
||||
if (points.size() == 0)
|
||||
return "Empty ray path";
|
||||
|
||||
if (types.firstElement() != RayData.RayType.ORIGIN && types.lastElement() != RayData.RayType.ORIGIN)
|
||||
return "Malformed ray path (not closed)";
|
||||
|
||||
if (types.firstElement() != RayData.RayType.DESTINATION && types.lastElement() != RayData.RayType.DESTINATION)
|
||||
return "Malformed ray path (not closed)";
|
||||
|
||||
if (types.firstElement() == types.lastElement())
|
||||
return "Malformed ray path (last == first element)";
|
||||
|
||||
String retVal = "";
|
||||
for (int i=0; i < types.size(); i++) {
|
||||
RayData.RayType currentType = types.get(i);
|
||||
if (currentType == RayData.RayType.DESTINATION)
|
||||
retVal = retVal + " DEST ";
|
||||
else if (currentType == RayData.RayType.DIFFRACTION)
|
||||
retVal = retVal + " DIFF ";
|
||||
else if (currentType == RayData.RayType.ORIGIN)
|
||||
retVal = retVal + " ORIG ";
|
||||
else if (currentType == RayData.RayType.REFLECTION)
|
||||
retVal = retVal + " REFL ";
|
||||
else if (currentType == RayData.RayType.REFRACTION)
|
||||
retVal = retVal + " REFR ";
|
||||
else
|
||||
retVal = retVal + " ???? ";
|
||||
}
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,216 +0,0 @@
|
|||
package statistics;
|
||||
|
||||
//Gaussian CDF Taylor approximation
|
||||
//Code borrowed from http://www1.fpl.fs.fed.us/distributions.html 19/9 2006
|
||||
|
||||
/**
|
||||
*
|
||||
*This class contains routines to calculate the
|
||||
*normal cumulative distribution function (CDF) and
|
||||
*its inverse.
|
||||
*
|
||||
*@version .5 --- June 7, 1996
|
||||
*@version .6 --- January 10, 2001 (normcdf added)
|
||||
*
|
||||
*/
|
||||
|
||||
public class CDF_Normal extends Object {
|
||||
|
||||
/**
|
||||
*
|
||||
*This method calculates the normal cdf inverse function.
|
||||
*<p>
|
||||
*Let PHI(x) be the normal cdf. Suppose that Q calculates
|
||||
*1.0 - PHI(x), and that QINV calculates QINV(p) for p in (0.0,.5].
|
||||
*Then for p .le. .5, x = PHIINV(p) = -QINV(p).
|
||||
*For p .gt. .5, x = PHIINV(p) = QINV(1.0 - p).
|
||||
*The formula for approximating QINV is taken from Abramowitz and Stegun,
|
||||
*Handbook of Mathematical Functions, Dover, 9th printing,
|
||||
*formula 26.2.3, page 933. The error in x is claimed to
|
||||
*be less than 4.5e-4 in absolute value.
|
||||
*
|
||||
*@param p p must lie between 0 and 1. xnormi returns
|
||||
* the normal cdf inverse evaluated at p.
|
||||
*
|
||||
*@author Steve Verrill
|
||||
*@version .5 --- June 7, 1996
|
||||
*
|
||||
*/
|
||||
|
||||
// FIX: Eventually I should build in a check that p lies in (0,1)
|
||||
|
||||
public static double xnormi(double p) {
|
||||
|
||||
double arg,t,t2,t3,xnum,xden,qinvp,x,pc;
|
||||
|
||||
final double c[] = {2.515517,
|
||||
.802853,
|
||||
.010328};
|
||||
|
||||
final double d[] = {1.432788,
|
||||
.189269,
|
||||
.001308};
|
||||
|
||||
if (p <= .5) {
|
||||
|
||||
arg = -2.0*Math.log(p);
|
||||
t = Math.sqrt(arg);
|
||||
t2 = t*t;
|
||||
t3 = t2*t;
|
||||
|
||||
xnum = c[0] + c[1]*t + c[2]*t2;
|
||||
xden = 1.0 + d[0]*t + d[1]*t2 + d[2]*t3;
|
||||
qinvp = t - xnum/xden;
|
||||
x = -qinvp;
|
||||
|
||||
return x;
|
||||
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
pc = 1.0 - p;
|
||||
arg = -2.0*Math.log(pc);
|
||||
t = Math.sqrt(arg);
|
||||
t2 = t*t;
|
||||
t3 = t2*t;
|
||||
|
||||
xnum = c[0] + c[1]*t + c[2]*t2;
|
||||
xden = 1.0 + d[0]*t + d[1]*t2 + d[2]*t3;
|
||||
x = t - xnum/xden;
|
||||
|
||||
return x;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*This method calculates the normal cumulative distribution function.
|
||||
*<p>
|
||||
*It is based upon algorithm 5666 for the error function, from:<p>
|
||||
*<pre>
|
||||
* Hart, J.F. et al, 'Computer Approximations', Wiley 1968
|
||||
*</pre>
|
||||
*<p>
|
||||
*The FORTRAN programmer was Alan Miller. The documentation
|
||||
*in the FORTRAN code claims that the function is "accurate
|
||||
*to 1.e-15."<p>
|
||||
*Steve Verrill
|
||||
*translated the FORTRAN code (the March 30, 1986 version)
|
||||
*into Java. This translation was performed on January 10, 2001.
|
||||
*
|
||||
*@param z The method returns the value of the normal
|
||||
* cumulative distribution function at z.
|
||||
*
|
||||
*@version .5 --- January 10, 2001
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Here is a copy of the documentation in the FORTRAN code:
|
||||
|
||||
SUBROUTINE NORMP(Z, P, Q, PDF)
|
||||
C
|
||||
C Normal distribution probabilities accurate to 1.e-15.
|
||||
C Z = no. of standard deviations from the mean.
|
||||
C P, Q = probabilities to the left & right of Z. P + Q = 1.
|
||||
C PDF = the probability density.
|
||||
C
|
||||
C Based upon algorithm 5666 for the error function, from:
|
||||
C Hart, J.F. et al, 'Computer Approximations', Wiley 1968
|
||||
C
|
||||
C Programmer: Alan Miller
|
||||
C
|
||||
C Latest revision - 30 March 1986
|
||||
C
|
||||
|
||||
*/
|
||||
|
||||
public static double normp(double z) {
|
||||
|
||||
double zabs;
|
||||
double p;
|
||||
double expntl,pdf;
|
||||
|
||||
final double p0 = 220.2068679123761;
|
||||
final double p1 = 221.2135961699311;
|
||||
final double p2 = 112.0792914978709;
|
||||
final double p3 = 33.91286607838300;
|
||||
final double p4 = 6.373962203531650;
|
||||
final double p5 = .7003830644436881;
|
||||
final double p6 = .3526249659989109E-01;
|
||||
|
||||
final double q0 = 440.4137358247522;
|
||||
final double q1 = 793.8265125199484;
|
||||
final double q2 = 637.3336333788311;
|
||||
final double q3 = 296.5642487796737;
|
||||
final double q4 = 86.78073220294608;
|
||||
final double q5 = 16.06417757920695;
|
||||
final double q6 = 1.755667163182642;
|
||||
final double q7 = .8838834764831844E-1;
|
||||
|
||||
final double cutoff = 7.071;
|
||||
final double root2pi = 2.506628274631001;
|
||||
|
||||
zabs = Math.abs(z);
|
||||
|
||||
// |z| > 37
|
||||
|
||||
if (z > 37.0) {
|
||||
|
||||
p = 1.0;
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
if (z < -37.0) {
|
||||
|
||||
p = 0.0;
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
// |z| <= 37.
|
||||
|
||||
expntl = Math.exp(-.5*zabs*zabs);
|
||||
|
||||
pdf = expntl/root2pi;
|
||||
|
||||
// |z| < cutoff = 10/sqrt(2).
|
||||
|
||||
if (zabs < cutoff) {
|
||||
|
||||
p = expntl*((((((p6*zabs + p5)*zabs + p4)*zabs + p3)*zabs +
|
||||
p2)*zabs + p1)*zabs + p0)/(((((((q7*zabs + q6)*zabs +
|
||||
q5)*zabs + q4)*zabs + q3)*zabs + q2)*zabs + q1)*zabs +
|
||||
q0);
|
||||
|
||||
} else {
|
||||
|
||||
p = pdf/(zabs + 1.0/(zabs + 2.0/(zabs + 3.0/(zabs + 4.0/
|
||||
(zabs + 0.65)))));
|
||||
|
||||
}
|
||||
|
||||
if (z < 0.0) {
|
||||
|
||||
return p;
|
||||
|
||||
} else {
|
||||
|
||||
p = 1.0 - p;
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package statistics;
|
||||
|
||||
// Gaussian CDF Taylor approximation
|
||||
// Code borrowed from http://www.cs.princeton.edu/introcs/21function/Gaussian.java.html 19/9 2006
|
||||
|
||||
/*************************************************************************
|
||||
* Compilation: javac Gaussian.java
|
||||
* Execution: java Gaussian x mu sigma
|
||||
*
|
||||
* Function to compute the Gaussian pdf (probability density function)
|
||||
* and the Gaussian cdf (cumulative density function)
|
||||
*
|
||||
* % java Gaussian 820 1019 209
|
||||
* 0.17050966869132111
|
||||
*
|
||||
* % java Gaussian 1500 1019 209
|
||||
* 0.9893164837383883
|
||||
*
|
||||
* % java Gaussian 1500 1025 231
|
||||
* 0.9801220907365489
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
public class Gaussian {
|
||||
|
||||
// return phi(x) = standard Gaussian pdf
|
||||
public static double phi(double x) {
|
||||
return Math.exp(-x*x / 2) / Math.sqrt(2 * Math.PI);
|
||||
}
|
||||
|
||||
// return phi(x) = Gaussian pdf with mean mu and stddev sigma
|
||||
public static double phi(double x, double mu, double sigma) {
|
||||
return phi((x - mu) / sigma) / sigma;
|
||||
}
|
||||
|
||||
// return Phi(z) = standard Gaussian cdf using Taylor approximation
|
||||
public static double Phi(double z) {
|
||||
if (z < -8.0) return 0.0;
|
||||
if (z > 8.0) return 1.0;
|
||||
double sum = 0.0, term = z;
|
||||
for (int i = 3; sum + term != sum; i += 2) {
|
||||
sum = sum + term;
|
||||
term = term * z * z / i;
|
||||
}
|
||||
return 0.5 + sum * phi(z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// return Phi(z, mu, sigma) = Gaussian cdf with mean mu and stddev sigma
|
||||
public static double Phi(double z, double mu, double sigma) {
|
||||
return Phi((z - mu) / sigma);
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
double z = Double.parseDouble(args[0]);
|
||||
double mu = Double.parseDouble(args[1]);
|
||||
double sigma = Double.parseDouble(args[2]);
|
||||
System.out.println(Phi(z, mu, sigma));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package statistics;
|
||||
|
||||
public class GaussianWrapper {
|
||||
|
||||
/**
|
||||
* Returns standard Gaussian cdf approximation based on algortihm for error function.
|
||||
*
|
||||
* @param value Value
|
||||
* @return Probability
|
||||
*/
|
||||
public static double cdfErrorAlgo(double value) {
|
||||
return CDF_Normal.normp(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Gaussian cdf approximation based on algorithm for error function.
|
||||
*
|
||||
* @param value Value
|
||||
* @param mean Mean value
|
||||
* @param stdDev Standard deviance
|
||||
* @return Probability
|
||||
*/
|
||||
public static double cdfErrorAlgo(double value, double mean, double stdDev) {
|
||||
return CDF_Normal.normp((value - mean) / stdDev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns standard Gaussian cdf using Taylor approximation.
|
||||
*
|
||||
* @param value Value
|
||||
* @return Probability
|
||||
*/
|
||||
public static double cdfTaylor(double value) {
|
||||
return Gaussian.Phi(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Gaussian cdf using Taylor approximation .
|
||||
*
|
||||
* @param value Value
|
||||
* @param mean Mean value
|
||||
* @param stdDev Standard deviance
|
||||
* @return Probability
|
||||
*/
|
||||
public static double cdfTaylor(double value, double mean, double stdDev) {
|
||||
return Gaussian.Phi(value, mean, stdDev);
|
||||
}
|
||||
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue