mirror of
https://github.com/PAMGuard/PAMGuard.git
synced 2025-04-28 11:07:22 +00:00

Cleanup of imports, whitespace, etc. across all of PAMGuard. No other changes to code apart from this automatic cleanup.
1262 lines
39 KiB
Java
1262 lines
39 KiB
Java
package Array;
|
|
|
|
import java.awt.Frame;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.ObjectInputStream;
|
|
import java.io.ObjectOutputStream;
|
|
import java.io.Serializable;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
|
|
import javax.swing.JFrame;
|
|
|
|
import Array.importHydrophoneData.HydrophoneImport;
|
|
import Array.importHydrophoneData.StreamerImport;
|
|
import Array.layoutFX.ArrayGUIFX;
|
|
import Array.plot.ArrayPlotProviderFX;
|
|
import Array.sensors.swing.ArraySensorPanelProvider;
|
|
import GPS.GPSControl;
|
|
import GPS.GPSDataBlock;
|
|
import GPS.GpsData;
|
|
import GPS.GpsDataUnit;
|
|
import PamController.PamControlledUnit;
|
|
import PamController.PamControlledUnitGUI;
|
|
import PamController.PamControlledUnitSettings;
|
|
import PamController.PamController;
|
|
import PamController.PamControllerInterface;
|
|
import PamController.PamGUIManager;
|
|
import PamController.PamSettingManager;
|
|
import PamController.PamSettings;
|
|
import PamController.masterReference.MasterReferencePoint;
|
|
import PamController.positionreference.PositionReference;
|
|
import PamModel.PamModuleInfo;
|
|
import PamUtils.PamUtils;
|
|
import PamView.PamControlledGUISwing;
|
|
import PamView.WrapperControlledGUISwing;
|
|
import PamView.importData.ImportDataSystem;
|
|
import PamguardMVC.PamDataUnit;
|
|
import PamguardMVC.PamObservable;
|
|
import PamguardMVC.PamObserver;
|
|
import dataPlotsFX.data.TDDataProviderRegisterFX;
|
|
import pamMaths.PamQuaternion;
|
|
import pamMaths.PamVector;
|
|
import userDisplay.UserDisplayControl;
|
|
|
|
/**
|
|
* Manager for different array configurations. Each array configuration is
|
|
* stored in it's own serialised file, which is separate from other Pam Settings
|
|
* so that they can be stored, emailed around, etc. In it' main serialised file
|
|
* controlled by PamSettingsManager, Pamguard keeps a list of recently used arrays.
|
|
* <p>
|
|
* The dialog ArrayDialog allows the user to load arrays from file, create new arrays,
|
|
* edit arrays, etc.
|
|
*
|
|
* @author Doug Gillespie
|
|
* @see Array.PamArray
|
|
*
|
|
*/
|
|
public class ArrayManager extends PamControlledUnit implements PamSettings, PamObserver, PositionReference {
|
|
|
|
/**
|
|
* No array specified
|
|
*/
|
|
public static final int ARRAY_TYPE_NONE = 0;
|
|
/**
|
|
* Point array (single phone or multiple phones at same point)
|
|
*/
|
|
public static final int ARRAY_TYPE_POINT = 1;
|
|
/**
|
|
* Line array of two or more elements
|
|
*/
|
|
public static final int ARRAY_TYPE_LINE = 2;
|
|
/**
|
|
* Three or more Hydrophones all in the same plane
|
|
*/
|
|
public static final int ARRAY_TYPE_PLANE = 3;
|
|
/**
|
|
* Four or more hydrophones not in the same plane.
|
|
*/
|
|
public static final int ARRAY_TYPE_VOLUME = 4;
|
|
|
|
private static ArrayManager singleInstance = null;
|
|
|
|
private HydrophoneProcess hydrophonesProcess;
|
|
|
|
private static final String arrayFileType = "paf";
|
|
|
|
ArrayList<PamArray> recentArrays;
|
|
|
|
// private DepthControl depthControl;
|
|
|
|
private ImportDataSystem<Hydrophone> hydrophoneImportManager;
|
|
|
|
private ImportDataSystem<ArrayList<Double>> streamerImportManager;
|
|
|
|
/**
|
|
* The FGX GUI for the array manager
|
|
*/
|
|
private ArrayGUIFX arrayGUIFX;
|
|
|
|
/**
|
|
* The array manager.
|
|
*/
|
|
public static String arrayManagerType = "Array Manager";
|
|
|
|
/**
|
|
* The Swing GUI for the array manager,.
|
|
*/
|
|
private PamControlledGUISwing arrayGUISwing;
|
|
|
|
public static final double DEFAULT_HYDROPHONE_SENSITIVITY = -170;
|
|
public static final double DEFAULT_PREAMP_GAIN = 0;
|
|
|
|
|
|
private ArrayManager(String unitName) {
|
|
super(arrayManagerType, "Array Manager");
|
|
|
|
/*
|
|
* set this immediately to stop it calling back into itself when the process is added
|
|
* causing the getArrayManager() to be called over and over.
|
|
*/
|
|
singleInstance = this;
|
|
|
|
|
|
/*
|
|
* Move these lines here from the getArrayManager() static function which was a daft place to have them
|
|
* and also make sure they are created before the arrays are loaded from memory.
|
|
*/
|
|
hydrophonesProcess=new HydrophoneProcess(this);
|
|
addPamProcess(hydrophonesProcess);
|
|
|
|
PamSettingManager.getInstance().registerSettings(this);
|
|
|
|
// // if it hasn't created an array by now, do so !
|
|
if (recentArrays == null || recentArrays.size() == 0) {
|
|
createDefaultArray();
|
|
}
|
|
|
|
//enable importing of time stamped hydrophone and streamer data if in viewer mode.
|
|
if (isViewer){
|
|
hydrophoneImportManager= new ImportDataSystem<Hydrophone>(new HydrophoneImport(hydrophonesProcess.getHydrophoneDataBlock()));
|
|
hydrophoneImportManager.setName("Hydrophone Data Import");
|
|
streamerImportManager = new ImportDataSystem<ArrayList<Double>>(new StreamerImport(hydrophonesProcess.getStreamerDataBlock()));
|
|
streamerImportManager.setName("Streamer Data Import");
|
|
}
|
|
// need to do a bit more to initialise the current array !
|
|
setCurrentArray(recentArrays.get(0));
|
|
|
|
UserDisplayControl.addUserDisplayProvider(new ArraySensorPanelProvider());
|
|
|
|
TDDataProviderRegisterFX.getInstance().registerDataInfo(new ArrayPlotProviderFX(getStreamerDatabBlock()));
|
|
}
|
|
|
|
private void createDefaultArray() {
|
|
addArray(PamArray.createSimpleArray("Basic Linear Array", 0, -5, 3, 2, DEFAULT_HYDROPHONE_SENSITIVITY, DEFAULT_PREAMP_GAIN, new double[] {0, 20000}));
|
|
}
|
|
|
|
|
|
@Override
|
|
public PamObserver getObserverObject() {
|
|
return this;
|
|
}
|
|
|
|
public static ArrayManager getArrayManager() {
|
|
if (singleInstance == null) {
|
|
singleInstance = new ArrayManager(null);
|
|
singleInstance.addModuleInfo(); //needed for FX
|
|
PamController.getInstance().addControlledUnit(singleInstance);
|
|
}
|
|
return singleInstance;
|
|
}
|
|
|
|
private boolean initComplete = false;
|
|
@Override
|
|
public void notifyModelChanged(int changeType) {
|
|
if (changeType == PamControllerInterface.INITIALIZATION_COMPLETE) {
|
|
initComplete = true;
|
|
}
|
|
getCurrentArray().notifyModelChanged(changeType, initComplete);
|
|
|
|
if (changeType == PamControllerInterface.INITIALIZATION_COMPLETE) {
|
|
// create data units and save - is this needed in the viewer ?
|
|
// if (PamController.getInstance().getRunMode() == PamController.RUN_NORMAL) {
|
|
hydrophonesProcess.createArrayData();
|
|
// }
|
|
}
|
|
|
|
if (changeType == PamControllerInterface.OFFLINE_DATA_LOADED){
|
|
if (isViewer) {
|
|
getHydrophoneDataBlock().clearChannelIterators();
|
|
}
|
|
}
|
|
|
|
if (changeType == PamControllerInterface.HYDROPHONE_ARRAY_CHANGED){
|
|
if (isViewer) {
|
|
getHydrophoneDataBlock().clearChannelIterators();
|
|
}
|
|
}
|
|
|
|
if (changeType == PamControllerInterface.GLOBAL_MEDIUM_UPDATE){
|
|
this.getCurrentArray().setSpeedOfSound(this.getPamController().getGlobalMediumManager().getDefaultSoundSpeed());
|
|
this.getCurrentArray().setDefaultSensitivity(this.getPamController().getGlobalMediumManager().getDefaultRecieverSens());
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* @return Returns the arrayFileType.
|
|
*/
|
|
public static String getArrayFileType() {
|
|
return arrayFileType;
|
|
}
|
|
|
|
/**
|
|
* @return Returns the recentArrays.
|
|
*/
|
|
public ArrayList<PamArray> getRecentArrays() {
|
|
return recentArrays;
|
|
}
|
|
|
|
public int getArrayCount() {
|
|
if (recentArrays == null || recentArrays.size() == 0) return 0;
|
|
return recentArrays.size();
|
|
}
|
|
|
|
public void showArrayDialog(Frame parentFrame) {
|
|
PamArray selectedArray = ArrayDialog.showDialog(parentFrame, singleInstance);
|
|
|
|
//WARNING: need to make sure that the notify model changed is at the end of this function. It must be called after all hydrophone data loading
|
|
//and saving has occured, otherwise we don't clear channel iterators from the hydrophone dateblock and end up with concurrent modification exceptions in
|
|
//localiser modules.
|
|
if (selectedArray != null) {
|
|
hydrophonesProcess.createArrayData();
|
|
// need to tell all modules that the array may have changed.
|
|
PamController.getInstance().notifyModelChanged(PamControllerInterface.HYDROPHONE_ARRAY_CHANGED);
|
|
}
|
|
|
|
}
|
|
|
|
public void addArray(PamArray newArray) {
|
|
if (recentArrays == null) {
|
|
recentArrays = new ArrayList<PamArray>();
|
|
}
|
|
recentArrays.add(newArray);
|
|
}
|
|
|
|
public void setCurrentArray(PamArray array) {
|
|
if (array == null) return;
|
|
recentArrays.remove(array);
|
|
array.setArrayShape(this.getArrayShape(array));
|
|
array.getHydrophoneLocator();
|
|
recentArrays.add(0, array);
|
|
}
|
|
|
|
public boolean removeArray(PamArray newArray) {
|
|
if (recentArrays == null) return false;
|
|
return recentArrays.remove(newArray);
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see PamController.PamSettings#GetSettingsReference()
|
|
*/
|
|
@Override
|
|
public Serializable getSettingsReference() {
|
|
/*
|
|
* Save the entire array classes in the serialised file
|
|
* but there will still be facilities for storing individual
|
|
* arrays in their own files for backup and export
|
|
*/
|
|
if (recentArrays == null) {
|
|
return null;
|
|
}
|
|
for (PamArray array:recentArrays) {
|
|
array.prepareToSerialize();
|
|
}
|
|
return new ArrayParameters(recentArrays);
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see PamController.PamSettings#GetSettingsVersion()
|
|
*/
|
|
@Override
|
|
public long getSettingsVersion() {
|
|
return ArrayParameters.serialVersionUID;
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see PamController.PamSettings#GetUnitName()
|
|
*/
|
|
@Override
|
|
public String getUnitName() {
|
|
return "Array Manager";
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see PamController.PamSettings#getUnitType()
|
|
*/
|
|
@Override
|
|
public String getUnitType() {
|
|
return "Array Manager";
|
|
}
|
|
|
|
/* (non-Javadoc)
|
|
* @see PamController.PamSettings#RestoreSettings(PamController.PamControlledUnitSettings)
|
|
*/
|
|
@Override
|
|
public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) {
|
|
try {
|
|
if (pamControlledUnitSettings.getSettings() != null) {
|
|
ArrayList<PamArray> oldArrays;
|
|
Object settings = pamControlledUnitSettings.getSettings();
|
|
if (settings instanceof ArrayParameters) {
|
|
oldArrays = ((ArrayParameters) settings).getArrayList();
|
|
}
|
|
else {
|
|
oldArrays = (ArrayList<PamArray>) pamControlledUnitSettings.getSettings();
|
|
}
|
|
/**
|
|
* Need to make a hard copy so that the cloning initiates the depth inversion fix !
|
|
*/
|
|
recentArrays = new ArrayList<PamArray>();
|
|
for (int i = 0; i < oldArrays.size(); i++) {
|
|
recentArrays.add(oldArrays.get(i).clone());
|
|
}
|
|
|
|
for (PamArray array:recentArrays) {
|
|
array.arrayDeserialized();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception Ex) {
|
|
Ex.printStackTrace();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @return Returns the currentArray.
|
|
*/
|
|
public PamArray getCurrentArray() {
|
|
if (recentArrays == null || recentArrays.size() == 0) {
|
|
createDefaultArray();
|
|
if (recentArrays == null || recentArrays.size() == 0) {
|
|
return null;
|
|
}
|
|
}
|
|
return recentArrays.get(0);
|
|
}
|
|
|
|
static public PamArray loadArrayFromFile(String fileName) {
|
|
try {
|
|
ObjectInputStream file = new ObjectInputStream(new FileInputStream(fileName));
|
|
PamArray array = (PamArray) file.readObject();
|
|
return array;
|
|
} catch (Exception Ex) {
|
|
Ex.printStackTrace();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
static public boolean saveArrayToFile(PamArray array) {
|
|
|
|
// should put some stuff in so that if arrayFile is null, it asks for a name
|
|
if (array.getArrayFile() == null) return false;
|
|
try {
|
|
ObjectOutputStream file = new ObjectOutputStream(new FileOutputStream(array.getArrayFile()));
|
|
file.writeObject(array);
|
|
} catch (Exception Ex) {
|
|
System.out.println(Ex);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// /**
|
|
// * @return the depthControl
|
|
// */
|
|
// public DepthControl getDepthControl() {
|
|
// return depthControl;
|
|
// }
|
|
//
|
|
// /**
|
|
// * @param depthControl the depthControl to set
|
|
// */
|
|
// public void setDepthControl(DepthControl depthControl) {
|
|
// if (this.depthControl != null && this.depthControl != depthControl) {
|
|
// this.depthControl.getDepthDataBlock().deleteObserver(this);
|
|
// }
|
|
// this.depthControl = depthControl;
|
|
// if (depthControl != null) {
|
|
// depthControl.getDepthDataBlock().addObserver(this);
|
|
// }
|
|
// }
|
|
|
|
@Override
|
|
public String getObserverName() {
|
|
return "Array Manager";
|
|
}
|
|
|
|
@Override
|
|
public long getRequiredDataHistory(PamObservable o, Object arg) {
|
|
// would be better to work out how long the Gps data are being kept for and do the same
|
|
return 3600*1000;
|
|
}
|
|
|
|
@Override
|
|
public void noteNewSettings() {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void removeObservable(PamObservable o) {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void setSampleRate(float sampleRate, boolean notify) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public void masterClockUpdate(long milliSeconds, long sampleNumber) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public void addData(PamObservable o, PamDataUnit arg) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
@Override
|
|
public void updateData(PamObservable o, PamDataUnit arg) {
|
|
|
|
}
|
|
|
|
/**
|
|
* @return the type of the current array (point, planar, line, etc)
|
|
*/
|
|
public int getArrayType() {
|
|
return getArrayShape(getCurrentArray());
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param phones
|
|
* @return the type of a sub array of the current array (point, planar, line, etc)
|
|
*/
|
|
public int getArrayType(int phones) {
|
|
return getArrayShape(getCurrentArray(), phones);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param array a PAMGUARD array
|
|
* @return the type of an array (point, plane, etc)
|
|
*/
|
|
public int getArrayShape(PamArray array) {
|
|
if (array == null) {
|
|
return ARRAY_TYPE_NONE;
|
|
}
|
|
int nPhones = array.getHydrophoneCount();
|
|
int phones = PamUtils.makeChannelMap(nPhones);
|
|
return getArrayShape(array, phones);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param array a PAMGUARD array
|
|
* @param phones a sub array of phones in the pam array.
|
|
* @return the type of an array (point, plane, etc)
|
|
*/
|
|
public int getArrayShape(PamArray array, int phones) {
|
|
if (array == null || phones == 0) {
|
|
return ARRAY_TYPE_NONE;
|
|
}
|
|
phones = getSpatiallyUniquePhones(array, phones);
|
|
int nPhones = PamUtils.getNumChannels(phones);
|
|
if (nPhones <= 1) {
|
|
return ARRAY_TYPE_POINT;
|
|
}
|
|
/**
|
|
* Need an array of phones, but need to exclude any which
|
|
* are at the exact same place as existing ones. So for
|
|
* each phone, look back through the list and see if
|
|
* its really unique.
|
|
*/
|
|
PamVector phoneVec;
|
|
PamVector[] phoneVectors = new PamVector[nPhones];
|
|
int iPhone, jPhone, iStreamer, jStreamer;
|
|
int uniquePhones = 0;
|
|
boolean matches;
|
|
for (int i = 0; i < nPhones; i++) {
|
|
iPhone = PamUtils.getNthChannel(i, phones);
|
|
iStreamer = array.getStreamerForPhone(iPhone);
|
|
phoneVec = array.getAbsHydrophoneVector(iPhone,0);
|
|
matches = false;
|
|
for (int j = 0; j < uniquePhones; j++) {
|
|
jPhone = PamUtils.getNthChannel(j, phones);
|
|
jStreamer = array.getStreamerForPhone(jPhone);
|
|
if (phoneVec.equals(phoneVectors[j]) & jStreamer == iStreamer) {
|
|
matches = true;
|
|
break;
|
|
}
|
|
}
|
|
if (matches) {
|
|
continue;
|
|
}
|
|
phoneVectors[uniquePhones++] = phoneVec;
|
|
}
|
|
nPhones = uniquePhones;
|
|
phoneVectors = Arrays.copyOf(phoneVectors, nPhones);
|
|
|
|
int nPairs = nPhones * (nPhones-1) / 2;
|
|
int zeroPoints = 0;
|
|
int iPair = 0;
|
|
PamVector[] pairVectors = new PamVector[nPairs];
|
|
for (int i = 0; i < nPhones; i++) {
|
|
for (int j = i+1; j < nPhones; j++) {
|
|
pairVectors[iPair++] = phoneVectors[j].sub(phoneVectors[i]);
|
|
}
|
|
}
|
|
// now test for the various types.
|
|
if (nPhones == 2) {
|
|
return ARRAY_TYPE_LINE;
|
|
}
|
|
// will also be a line if all interpair vectors
|
|
// are in a line.
|
|
if (areInLine(pairVectors)) {
|
|
return ARRAY_TYPE_LINE;
|
|
}
|
|
/*
|
|
* May be a plane !
|
|
*/
|
|
if (nPhones == 3) {
|
|
return ARRAY_TYPE_PLANE;
|
|
}
|
|
if (areOnPlane(pairVectors)) {
|
|
return ARRAY_TYPE_PLANE;
|
|
}
|
|
return ARRAY_TYPE_VOLUME;
|
|
}
|
|
|
|
/**
|
|
* Take a list of phones and return a list of ones
|
|
* which are at unique positions.
|
|
* @param array hydrophone array
|
|
* @param phones bitmap of hydrophone numbers
|
|
* @return bitmap of hydrophones which have a unique position.
|
|
*/
|
|
public int getSpatiallyUniquePhones(PamArray array, int phones) {
|
|
int nPhones = PamUtils.getNumChannels(phones);
|
|
int iPhone, jPhone, iStream, jStream;
|
|
int uniqueList = 0;
|
|
PamVector iVec, jVec;
|
|
boolean unique;
|
|
for (int i = 0; i < nPhones; i++) {
|
|
unique = true;
|
|
iPhone = PamUtils.getNthChannel(i, phones);
|
|
iStream = array.getStreamerForPhone(iPhone);
|
|
iVec = array.getAbsHydrophoneVector(iPhone,-1);
|
|
if (iVec == null) continue;
|
|
for (int j = i+1; j < nPhones; j++) {
|
|
jPhone = PamUtils.getNthChannel(j, phones);
|
|
jStream = array.getStreamerForPhone(jPhone);
|
|
jVec = array.getAbsHydrophoneVector(jPhone,-1);
|
|
if (jVec == null || jStream != iStream) continue;
|
|
if (iVec.equals(jVec)) {
|
|
unique = false;
|
|
}
|
|
}
|
|
if (unique) {
|
|
uniqueList |= (1<<iPhone);
|
|
}
|
|
}
|
|
return uniqueList;
|
|
}
|
|
|
|
/**
|
|
* Get the principle direction vectors for the current array
|
|
* @return Array of vectors pointing along the array principle axes.
|
|
*/
|
|
public PamVector[] getArrayDirections() {
|
|
PamArray array = getCurrentArray();
|
|
return getArrayDirections(array);
|
|
}
|
|
|
|
/**
|
|
* Get the principle direction vectors for a sub set of hydrophones
|
|
* within the current array
|
|
* @param phones bitmap of hydrophones
|
|
* @return Array of vectors pointing along the array principle axes.
|
|
*/
|
|
public PamVector[] getArrayDirection(int phones) {
|
|
PamArray array = getCurrentArray();
|
|
return getArrayDirections(array, phones);
|
|
}
|
|
|
|
/**
|
|
* Get a set of vectors which define the principle coordinates of an array
|
|
* @param array array
|
|
* @return array of vectors
|
|
*
|
|
*/
|
|
public PamVector[] getArrayDirections(PamArray array) {
|
|
int nPhones = array.getHydrophoneCount();
|
|
int phones = PamUtils.makeChannelMap(nPhones);
|
|
return getArrayDirections(array, phones);
|
|
}
|
|
/**
|
|
* Get a set of vectors which define the principle components of an array.
|
|
* <p>For a point array, null is returned
|
|
* <p>For a line array a vector pointing along the array in the direction closest
|
|
* to the y axis
|
|
* <p>For a planar array a vector pointing as closely as possible to the y axis
|
|
* and a second vector, perpendicular to the first, obeying a right hand rule, in
|
|
* the plane will be returned.
|
|
* <p>For a volumetric array, the above + the third vector (vec product of the other two).
|
|
*
|
|
*
|
|
* @param array Pamguard array
|
|
* @param phones phones included in a sub array.
|
|
* @return up to three vectors defining the components of the array.
|
|
*/
|
|
public PamVector[] getArrayDirections(PamArray array, int phones) {
|
|
phones = getSpatiallyUniquePhones(array, phones);
|
|
int nPhones = PamUtils.getNumChannels(phones);
|
|
if (nPhones <= 0) {
|
|
return null;
|
|
}
|
|
PamVector[] arrayVectors = getArrayVectors(array, phones);
|
|
int arrayType = getArrayShape(array, phones);
|
|
switch(arrayType) {
|
|
case ARRAY_TYPE_POINT:
|
|
return null;
|
|
case ARRAY_TYPE_LINE:
|
|
return getLineArrayVector(arrayVectors);
|
|
case ARRAY_TYPE_PLANE:
|
|
return getPlaneArrayVectors(arrayVectors);
|
|
case ARRAY_TYPE_VOLUME:
|
|
return getVolumeArrayVectors(arrayVectors);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private PamVector[] getLineArrayVector(PamVector[] arrayVectors) {
|
|
// we know they are in a line, so just take the first two.
|
|
PamVector[] vectors = new PamVector[1];
|
|
vectors[0] = arrayVectors[1].sub(arrayVectors[0]);
|
|
// want to line up along the positive direction of an axis if at all
|
|
// possible.
|
|
int ax = vectors[0].getPrincipleAxis();
|
|
if (vectors[0].dotProd(PamVector.getCartesianAxes(ax)) < 0) {
|
|
vectors[0] = vectors[0].times(-1);
|
|
}
|
|
vectors[0] = vectors[0].getUnitVector();
|
|
return vectors;
|
|
}
|
|
|
|
private PamVector[] getPlaneArrayVectors(PamVector[] arrayVectors) {
|
|
PamVector[] vectors = new PamVector[2];
|
|
PamVector[] vectorPairs = PamVector.getVectorPairs(arrayVectors);
|
|
int nPairs = vectorPairs.length;
|
|
int[] closestAxis = new int[nPairs];
|
|
double[] closestAngle = new double[nPairs];
|
|
for (int i = 0; i < nPairs; i++) {
|
|
closestAxis[i] = vectorPairs[i].getPrincipleAxis();
|
|
closestAngle[i] = vectorPairs[i].absAngle(PamVector.getCartesianAxes(closestAxis[i]));
|
|
}
|
|
// need to find the direction vector for the plane.
|
|
// can do this by finding any non zero vector product.
|
|
PamVector planePerpendicular = null;
|
|
for (int i = 0; i < nPairs; i++) {
|
|
for (int j = (i+1); j < nPairs; j++) {
|
|
if (!vectorPairs[i].isParallel(vectorPairs[j])) {
|
|
planePerpendicular = vectorPairs[i].vecProd(vectorPairs[j]);
|
|
break;
|
|
}
|
|
}
|
|
if (planePerpendicular == null) {
|
|
break;
|
|
}
|
|
}
|
|
if (planePerpendicular == null) {
|
|
planePerpendicular = PamVector.getZAxis().clone();
|
|
}
|
|
|
|
// find the closest pair to each of the three axis.
|
|
int[] closestPair = new int[3];
|
|
PamVector axis;
|
|
double closest;
|
|
double ang;
|
|
for (int ax = 0; ax < 3; ax++) {
|
|
closestPair[ax] = -1;
|
|
axis = PamVector.getCartesianAxes(ax);
|
|
closest = Double.MAX_VALUE;
|
|
for (int i = 0; i < nPairs; i++) {
|
|
if (closestAxis[i] != ax) {
|
|
continue;
|
|
}
|
|
if (closestAngle[i] < closest) {
|
|
closest = closestAngle[i];
|
|
closestPair[ax] = i;
|
|
}
|
|
}
|
|
}
|
|
// try to line up the first vector on the y axis, then x, then z
|
|
int startPair = -1;
|
|
if (closestPair[1] >= 0) {
|
|
startPair = closestPair[1];
|
|
}
|
|
else if (closestPair[0] >= 0) {
|
|
startPair = closestPair[0];
|
|
}
|
|
else {
|
|
startPair = closestPair[2];
|
|
}
|
|
if (startPair < 0) {
|
|
return null;
|
|
}
|
|
vectors[0] = vectorPairs[startPair];
|
|
if (vectors[0].angle(PamVector.getCartesianAxes(closestAxis[startPair])) > Math.PI/2) {
|
|
vectors[0] = vectors[0].times(-1);
|
|
}
|
|
// second vector must be perpendicular to first one and also
|
|
// to the plane perpendicular.
|
|
vectors[1] = vectors[0].vecProd(planePerpendicular);
|
|
int closestAx = vectors[1].getPrincipleAxis();
|
|
if (vectors[1].angle(PamVector.getCartesianAxes(closestAx)) > Math.PI/2) {
|
|
vectors[1] = vectors[1].times(-1);
|
|
}
|
|
vectors[0] = vectors[0].getUnitVector();
|
|
vectors[1] = vectors[1].getUnitVector();
|
|
|
|
|
|
return vectors;
|
|
}
|
|
|
|
|
|
private PamVector[] getVolumeArrayVectors(PamVector[] arrayVectors) {
|
|
PamVector[] vectors = new PamVector[3];
|
|
for (int i = 0; i < 3; i++) {
|
|
vectors[i] = PamVector.getCartesianAxes(i).clone();
|
|
}
|
|
return vectors;
|
|
}
|
|
|
|
public PamVector[] getArrayVectors(PamArray array, int phones) {
|
|
int nPhones = PamUtils.getNumChannels(phones);
|
|
PamVector[] arrayVectors = new PamVector[nPhones];
|
|
int iPhone;
|
|
for (int i = 0; i < nPhones; i++) {
|
|
iPhone = PamUtils.getNthChannel(i, phones);
|
|
arrayVectors[i] = array.getAbsHydrophoneVector(iPhone,0);
|
|
}
|
|
return arrayVectors;
|
|
}
|
|
|
|
public static String getArrayTypeString(int arrayType) {
|
|
switch (arrayType) {
|
|
case ARRAY_TYPE_NONE:
|
|
return "No Hydrophones";
|
|
case ARRAY_TYPE_POINT:
|
|
return "Point Array";
|
|
case ARRAY_TYPE_LINE:
|
|
return "Line Array";
|
|
case ARRAY_TYPE_PLANE:
|
|
return "Planar Array";
|
|
case ARRAY_TYPE_VOLUME:
|
|
return "Volumetric Array";
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Test to see if a load of inter-pair vectors are in line or not.
|
|
* @param pvs inter-hydrophone vectors.
|
|
* @return true if they all line up.
|
|
*/
|
|
private boolean areInLine(PamVector[] pvs) {
|
|
int nPairs = pvs.length;
|
|
for (int i = 0; i < nPairs; i++) {
|
|
for (int j = i+1; j < nPairs; j++) {
|
|
if (!pvs[i].isInLine(pvs[j])) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Check to see if inter pair vectors define a volume
|
|
* or just a plane.
|
|
* @param pvs array of inter phone vectors
|
|
* @return true if there is significant volume.
|
|
*/
|
|
private boolean areOnPlane(PamVector[] pvs) {
|
|
double vol = getMaxVolume(pvs);
|
|
return (vol == 0);
|
|
}
|
|
|
|
private double getMaxVolume(PamVector[] pvs) {
|
|
int nPairs = pvs.length;
|
|
double maxVol = 0;
|
|
double vol;
|
|
for (int i = 0; i < nPairs; i++) {
|
|
for (int j = i+1; j < nPairs; j++) {
|
|
for (int k = j+1; k < nPairs; k++) {
|
|
vol = pvs[i].tripleDotProduct(pvs[j], pvs[k]);
|
|
maxVol = Math.max(maxVol, vol);
|
|
}
|
|
}
|
|
}
|
|
return maxVol;
|
|
}
|
|
|
|
/**
|
|
* Called from the network receiver to create and assign some specific hydrophone streamer within an
|
|
* array and to clone a streamer to make a new one if necessary
|
|
* @param buoyStats
|
|
*/
|
|
// @Deprecated
|
|
// public void checkBuoyHydropneStreamer(BuoyStatusDataUnit buoyStats) {
|
|
// if (buoyStats.getHydrophoneStreamer() != null) {
|
|
// // no need to do anything if it' already found it's streamer.
|
|
// return;
|
|
// }
|
|
// // check that we're using the correct hydrophone locator.
|
|
// PamArray currentArray = getCurrentArray();
|
|
// HydrophoneLocator locator = currentArray.getHydrophoneLocator();
|
|
//// if (locator == null || locator.getClass() != NetworkHydrophoneLocator.class) {
|
|
//// currentArray.setArrayType(PamArray.ARRAY_TYPE_TOWED);
|
|
//// currentArray.setArrayLocator(2);
|
|
//// }
|
|
//
|
|
// // now try to find a streamer with that buoy id.
|
|
// Streamer streamer = currentArray.findStreamer(buoyStats.getBuoyName());
|
|
// if (streamer != null) {
|
|
// buoyStats.setHydrophoneStreamer(streamer);
|
|
// return;
|
|
// }
|
|
//
|
|
// // try the first streamer - see if it's already assigned to any buoy, it not grab it.
|
|
// Streamer firstStreamer = currentArray.getStreamer(0);
|
|
// if (firstStreamer != null && firstStreamer.getBuoyId1() == null) {
|
|
// buoyStats.setHydrophoneStreamer(firstStreamer);
|
|
// return;
|
|
// }
|
|
// // else will have to clone that first streamer, hydrophones and all !!!
|
|
// int nStreamers = currentArray.getNumStreamers();
|
|
// if (firstStreamer != null) {
|
|
// streamer = new Streamer(firstStreamer, nStreamers, buoyStats.getBuoyId1());
|
|
// }
|
|
// else {
|
|
// streamer = new Streamer(nStreamers);
|
|
// }
|
|
// int streamerId = currentArray.addStreamer(streamer);
|
|
// buoyStats.setHydrophoneStreamer(streamer);
|
|
//
|
|
// // clone the hydrophones attached to that streamer.
|
|
// Hydrophone oldPhone, newPhone;
|
|
// int n = currentArray.getHydrophoneCount();
|
|
// for (int i = 0; i < n; i++) {
|
|
// oldPhone = currentArray.getHydrophone(i);
|
|
// if (oldPhone.getStreamerId() != 0) {
|
|
// continue;
|
|
// }
|
|
// newPhone = new Hydrophone(currentArray.getHydrophoneCount(), oldPhone.getX() + 10*streamerId, oldPhone.getY(), oldPhone.getZ(),
|
|
// oldPhone.getType(), oldPhone.getSensitivity(), oldPhone.getBandwidth().clone(), oldPhone.getPreampGain());
|
|
// newPhone.setdX(oldPhone.getdX());
|
|
// newPhone.setdY(oldPhone.getdY());
|
|
// newPhone.setdZ(oldPhone.getdZ());
|
|
// newPhone.setStreamerId(streamerId);
|
|
// currentArray.addHydrophone(newPhone);
|
|
// }
|
|
// }
|
|
|
|
// public ArrayDialog getArrayDialog() {
|
|
// System.out.println("static array dialog: "+singleInstance.arrayDialog);
|
|
// System.out.println("this: "+ arrayDialog);
|
|
// return arrayDialog;
|
|
// }
|
|
|
|
public HydrophoneDataBlock getHydrophoneDataBlock() {
|
|
return hydrophonesProcess.getHydrophoneDataBlock();
|
|
}
|
|
|
|
public StreamerDataBlock getStreamerDatabBlock() {
|
|
return hydrophonesProcess.getStreamerDataBlock();
|
|
}
|
|
|
|
public HydrophoneSQLLogging getHydrophoneSQLLogging() {
|
|
return hydrophonesProcess.getHydrophoneSQLlogging();
|
|
}
|
|
|
|
// public void setArrayDialog(ArrayDialog arrayDialog) {
|
|
// this.arrayDialog=arrayDialog;
|
|
// }
|
|
/**
|
|
* Gets the GPS data block, if there is one. If no datablock is present then returns null;
|
|
* @return reference to the gps data block (if there is one)
|
|
*/
|
|
public static GPSDataBlock getGPSDataBlock() {
|
|
// go right to the main gps data block for this,
|
|
GPSControl gpsControl = (GPSControl) PamController.getInstance().findControlledUnit(GPSControl.gpsUnitType);
|
|
if (gpsControl == null) {
|
|
return null;
|
|
}
|
|
return gpsControl.getGpsDataBlock();
|
|
}
|
|
|
|
public void showHydrophoneImportDialog(JFrame guiFrame) {
|
|
hydrophoneImportManager.showImportDialog();
|
|
}
|
|
|
|
public void showStreamerImportDialog(JFrame guiFrame) {
|
|
streamerImportManager.showImportDialog();
|
|
}
|
|
|
|
// /**
|
|
// * Get the current geometry for a data unit's hydrophones.
|
|
// * @param dataUnits list of data units
|
|
// * @return current geometry.
|
|
// */
|
|
// public SnapshotGeometry getSnapshotGeometry(PamDataUnit dataUnit) {
|
|
// /**
|
|
// * first work out the total number of channels involved
|
|
// * and try to individually link data units back to the
|
|
// * acquisition process, just in case this ever gets used
|
|
// * with different daq's (I don't think this is even possible
|
|
// * but might as well allow for it).
|
|
// * Aiming to end up with an array of channels and an array
|
|
// * of hydrophone numbers.
|
|
// * PhoneNo's will end up with a -1 if no hydrophone is assigned
|
|
// * to a channel (again, this should never happen).
|
|
// */
|
|
// int nChan = PamUtils.getNumChannels(dataUnit.getChannelBitmap());
|
|
// int[] phoneNos = new int[nChan];
|
|
// int[] chanNos = new int[nChan];
|
|
// int iC = 0;
|
|
// int chMap = dataUnit.getChannelBitmap();
|
|
// int phoneMap = chMap;
|
|
// PamProcess sourceProcess = dataUnit.getParentDataBlock().getSourceProcess();
|
|
// if (sourceProcess instanceof AcquisitionProcess) {
|
|
// AcquisitionProcess ap = (AcquisitionProcess) sourceProcess;
|
|
// phoneMap = ap.getAcquisitionControl().ChannelsToHydrophones(chMap);
|
|
// }
|
|
// int uChans = PamUtils.getNumChannels(chMap);
|
|
// for (int c = 0; c < uChans; c++) {
|
|
// chanNos[iC] = PamUtils.getNthChannel(c, chMap);
|
|
// phoneNos[iC] = PamUtils.getNthChannel(c, phoneMap);
|
|
// iC++;
|
|
// }
|
|
// long now = dataUnit.getTimeMilliseconds();
|
|
// /*
|
|
// * Now get the array geometry for that list of hydrophones.
|
|
// * Annoyingly, a lot of the geometry functions are based around
|
|
// * phone bitmaps. however we need to be a bit wary of them since there
|
|
// * is a small chance that a hydrophone may get repeated somehow.
|
|
// */
|
|
// PamArray currentArray = getCurrentArray();
|
|
// double[][] geometry = new double[nChan][];
|
|
// double[] centre = new double[3];
|
|
// int nGood = 0;
|
|
// GpsData referenceLatLong = currentArray.getHydrophoneLocator().getReferenceLatLong(now);
|
|
//
|
|
// // arrayHeading = currentArray.getHydrophoneLocator().get
|
|
// for (int i = 0; i < nChan; i++) {
|
|
// if (phoneNos[i] >= 0) {
|
|
// geometry[i] = currentArray.getAbsHydrophoneVector(phoneNos[i], now).getVector();
|
|
// if (geometry[i] != null) {
|
|
// nGood++;
|
|
// for (int p = 0; p < 3; p++) {
|
|
// centre[p] += geometry[i][p];
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// if (nGood > 0) {
|
|
// for (int p = 0; p < 3; p++) {
|
|
// centre[p] /= nGood;
|
|
// }
|
|
// }
|
|
//
|
|
// SnapshotGeometry sg = new SnapshotGeometry(currentArray, now, chanNos, phoneNos, referenceLatLong, centre, geometry);
|
|
// return sg;
|
|
// }
|
|
|
|
/**
|
|
* Make an ordered set of geometry data for the given hydrophones.
|
|
* data rows will be null if a hydrophone isn't used.
|
|
*
|
|
* Geometry is all returned in cartesian coordinates relative to
|
|
* the reference point which is the position of the first hydrophone streamer.
|
|
*
|
|
* All individual hydrophones have their pitch, roll and everything else added
|
|
* within this function.
|
|
*
|
|
* @param hydrophoneMap bitmap of used hydrophones
|
|
* @return geometry data.
|
|
*/
|
|
public SnapshotGeometry getSnapshotGeometry(int hydrophoneMap, long timeMillis) {
|
|
|
|
PamArray currentArray = getCurrentArray();
|
|
if (currentArray == null) {
|
|
return null;
|
|
}
|
|
boolean getSpacingErrors = true;
|
|
int nPhones = PamUtils.getNumChannels(hydrophoneMap);
|
|
int maxPhone = PamUtils.getHighestChannel(hydrophoneMap);
|
|
int[] hydrophoneList = new int[nPhones];
|
|
int[] streamerList = new int[maxPhone+1];
|
|
PamVector[] geometry = new PamVector[maxPhone+1];
|
|
PamVector[] streamerError = new PamVector[maxPhone+1];
|
|
PamVector[] hydrophoneError = new PamVector[maxPhone+1];
|
|
double[] centre = new double[3];
|
|
// GpsData referenceLatLong = currentArray.getHydrophoneLocator().getReferenceLatLong(timeMillis);
|
|
int nGood = 0;
|
|
int lastStreamerId = -1;
|
|
GpsData firstStreamerPos = null, streamerPos = null;
|
|
PamQuaternion streamerQuaternion = null;
|
|
double streamerHead = 0, streamerPitch = 0, streamerRoll = 0;
|
|
PamVector streamerOffestFromFirst = null;
|
|
PamVector streamerErrorVec = null;
|
|
for (int i = 0; i <= maxPhone; i++) {
|
|
if ((1<<i & hydrophoneMap) == 0) {
|
|
continue;
|
|
}
|
|
int streamerId = currentArray.getStreamerForPhone(i);
|
|
if (streamerId != lastStreamerId) {
|
|
lastStreamerId = streamerId;
|
|
Streamer streamer = currentArray.getStreamer(streamerId);
|
|
streamerPos = streamer.getHydrophoneLocator().getStreamerLatLong(timeMillis); // getReferenceLatLong(timeMillis);
|
|
if (streamerPos == null) {
|
|
return null;
|
|
}
|
|
streamerErrorVec = streamer.getErrorVector();
|
|
streamerHead = streamerPos.getHeading();
|
|
streamerPitch = streamerPos.getPitch();
|
|
streamerRoll = streamerPos.getRoll();
|
|
// System.out.printf("HPR = %5.1f, %5.1f, %5.1f\n", streamerHead, streamerPitch, streamerRoll);
|
|
if (streamerPitch != 0. || streamerRoll != 0.) {
|
|
streamerQuaternion = new PamQuaternion(Math.toRadians(streamerHead), Math.toRadians(streamerPitch), Math.toRadians(streamerRoll));
|
|
streamerErrorVec = PamVector.rotateVector(streamerErrorVec, streamerQuaternion);
|
|
}
|
|
else {
|
|
streamerQuaternion = null;
|
|
streamerErrorVec = streamerErrorVec.rotate(-Math.toRadians(streamerHead));
|
|
}
|
|
if (firstStreamerPos == null) {
|
|
firstStreamerPos = streamerPos;
|
|
}
|
|
else {
|
|
// work out the difference in position from this streamer to the
|
|
// first one and use that as an offset. ....
|
|
streamerOffestFromFirst = new PamVector(firstStreamerPos.distanceTo(streamerPos));
|
|
}
|
|
}
|
|
/**
|
|
* Rotate the hydrophone about the centre of it's streamer.
|
|
*/
|
|
// Hydrophone hydrophone = currentArray.getHiddenHydrophone(i);
|
|
Hydrophone hydrophone = currentArray.getHydrophone(i, timeMillis);
|
|
|
|
|
|
|
|
if (hydrophone == null) {
|
|
continue;
|
|
}
|
|
PamVector hydrophoneVec = hydrophone.getVector();
|
|
PamVector hydrophoneErrorVec = hydrophone.getErrorVector();
|
|
|
|
if (streamerQuaternion != null) {
|
|
hydrophoneVec = PamVector.rotateVector(hydrophoneVec, streamerQuaternion);
|
|
hydrophoneErrorVec = PamVector.rotateVector(hydrophoneErrorVec, streamerQuaternion);
|
|
}
|
|
else if (streamerHead != 0) {
|
|
hydrophoneVec = hydrophoneVec.rotate(-Math.toRadians(streamerHead));
|
|
hydrophoneErrorVec = hydrophoneErrorVec.rotate(-Math.toRadians(streamerHead));
|
|
}
|
|
if (streamerOffestFromFirst != null) {
|
|
hydrophoneVec = hydrophoneVec.add(streamerOffestFromFirst);
|
|
}
|
|
|
|
geometry[i] = hydrophoneVec;
|
|
hydrophoneList[nGood] = i;
|
|
streamerList[i] = lastStreamerId;
|
|
hydrophoneError[i] = hydrophoneErrorVec;
|
|
streamerError[i] = streamerErrorVec;
|
|
nGood++;
|
|
for (int p = 0; p < 3; p++) {
|
|
centre[p] += geometry[i].getCoordinate(p);
|
|
}
|
|
}
|
|
|
|
if (nGood > 0) {
|
|
for (int p = 0; p < 3; p++) {
|
|
centre[p] /= nGood;
|
|
}
|
|
return new SnapshotGeometry(currentArray, timeMillis, streamerList, hydrophoneList, firstStreamerPos,
|
|
new PamVector(centre), geometry, streamerError, hydrophoneError);
|
|
}
|
|
else {
|
|
return getMasterReferenceGeometry(timeMillis);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Create a snapshot geometry from the master reference position, which will either be the GPS data, or
|
|
* the centre point of the array. Worst case is that it ends up as 0,0,0
|
|
* @param timeMillis
|
|
* @return
|
|
*/
|
|
private SnapshotGeometry getMasterReferenceGeometry(long timeMillis) {
|
|
GPSControl gpsControl = GPSControl.getGpsControl();
|
|
GpsData referencePoint = null;
|
|
if (gpsControl != null) {
|
|
GpsDataUnit shipPos = gpsControl.getShipPosition(timeMillis, true);
|
|
if (shipPos != null) {
|
|
referencePoint = shipPos.getGpsData();
|
|
}
|
|
}
|
|
if (referencePoint == null && MasterReferencePoint.getFixTime() != null && MasterReferencePoint.getLatLong() != null) {
|
|
// running out of options, so fall back to the master reference point, interpolated (probably has zero speeed)
|
|
referencePoint = new GpsData(MasterReferencePoint.getFixTime(), MasterReferencePoint.getLatLong()).getPredictedGPSData(timeMillis);
|
|
}
|
|
if (referencePoint == null) {
|
|
return null;
|
|
}
|
|
SnapshotGeometry snapgeom = new SnapshotGeometry(getCurrentArray(), timeMillis, null, null, referencePoint, new PamVector(0,0,0), null, null, null);
|
|
return snapgeom;
|
|
}
|
|
|
|
//
|
|
// public SnapshotGeometry getSubDetectionGeometry(PamDataUnit superDataUnit) {
|
|
// /**
|
|
// * first work out the total number of channels involved
|
|
// * and try to individually link data units back to the
|
|
// * acquisition process, just in case this ever gets used
|
|
// * with different daq's (I don't think this is even possible
|
|
// * but might as well allow for it).
|
|
// * Aiming to end up with an array of channels and an array
|
|
// * of hydrophone numbers.
|
|
// * PhoneNo's will end up with a -1 if no hydrophone is assigned
|
|
// * to a channel (again, this should never happen).
|
|
// *
|
|
// * It can get a bit complicated having the hydrophones in an odd order
|
|
// * but this can .
|
|
// */
|
|
// int nChan = 0;
|
|
// int nSubs = superDataUnit.getSubDetectionsCount();
|
|
// for (int i = 0; i < nSubs; i++) {
|
|
// PamDataUnit dataUnit = superDataUnit.getSubDetection(i);
|
|
// nChan += PamUtils.getNumChannels(dataUnit.getChannelBitmap());
|
|
// }
|
|
// int[] phoneNos = new int[nChan];
|
|
// int[] chanNos = new int[nChan];
|
|
// int iC = 0;
|
|
// for (int i = 0; i < nSubs; i++) {
|
|
// PamDataUnit dataUnit = superDataUnit.getSubDetection(i);
|
|
// int chMap = dataUnit.getChannelBitmap();
|
|
// int phoneMap = chMap;
|
|
// PamProcess sourceProcess = dataUnit.getParentDataBlock().getSourceProcess();
|
|
// if (sourceProcess instanceof AcquisitionProcess) {
|
|
// AcquisitionProcess ap = (AcquisitionProcess) sourceProcess;
|
|
// phoneMap = ap.getAcquisitionControl().ChannelsToHydrophones(chMap);
|
|
// }
|
|
// int uChans = PamUtils.getNumChannels(chMap);
|
|
// for (int c = 0; c < uChans; c++) {
|
|
// chanNos[iC] = PamUtils.getNthChannel(c, chMap);
|
|
// phoneNos[iC] = PamUtils.getNthChannel(c, phoneMap);
|
|
// iC++;
|
|
// }
|
|
// }
|
|
// long now = superDataUnit.getTimeMilliseconds();
|
|
// /*
|
|
// * Now get the array geometry for that list of hydrophones.
|
|
// * Annoyingly, a lot of the geometry functions are based around
|
|
// * phone bitmaps. however we need to be a bit wary of them since there
|
|
// * is a small chance that a hydrophone may get repeated somehow.
|
|
// */
|
|
// PamArray currentArray = getCurrentArray();
|
|
// double[][] geometry = new double[nChan][];
|
|
// double[] centre = new double[3];
|
|
// int nGood = 0;
|
|
// GpsData referenceLatLong = currentArray.getHydrophoneLocator().getReferenceLatLong(now);
|
|
//
|
|
// // arrayHeading = currentArray.getHydrophoneLocator().get
|
|
// for (int i = 0; i < nChan; i++) {
|
|
// if (phoneNos[i] >= 0) {
|
|
// geometry[i] = currentArray.getAbsHydrophoneVector(phoneNos[i], now).getVector();
|
|
// if (geometry[i] != null) {
|
|
// nGood++;
|
|
// for (int p = 0; p < 3; p++) {
|
|
// centre[p] += geometry[i][p];
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
// if (nGood > 0) {
|
|
// for (int p = 0; p < 3; p++) {
|
|
// centre[p] /= nGood;
|
|
// }
|
|
// }
|
|
//
|
|
// SnapshotGeometry sg = new SnapshotGeometry(currentArray, now, chanNos, phoneNos, referenceLatLong, centre, geometry);
|
|
// return sg;
|
|
// }
|
|
|
|
/**
|
|
* Add module info to the array manager. Need to do this to add icon which is used in data model.
|
|
*/
|
|
private void addModuleInfo(){
|
|
//need to add module info due to fact array manager is a special case
|
|
PamModuleInfo arrayModuleInfo=new PamModuleInfo("ArrayManager", "Array Manager", ArrayManager.class);
|
|
arrayModuleInfo.setCoreModule(true);
|
|
this.setPamModuleInfo(arrayModuleInfo);
|
|
}
|
|
|
|
@Override
|
|
public PamControlledUnitGUI getGUI(int flag) {
|
|
if (flag==PamGUIManager.FX) {
|
|
if (arrayGUIFX == null) {
|
|
arrayGUIFX= new ArrayGUIFX(this);
|
|
}
|
|
return arrayGUIFX;
|
|
}
|
|
if (flag==PamGUIManager.SWING) {
|
|
if (arrayGUISwing == null) {
|
|
arrayGUISwing= new WrapperControlledGUISwing(this);
|
|
}
|
|
return arrayGUISwing;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public GpsData getReferencePosition(long timeMillis) {
|
|
int hMap = PamUtils.makeChannelMap(getCurrentArray().getHydrophoneCount());
|
|
SnapshotGeometry sg = getSnapshotGeometry(hMap, timeMillis);
|
|
return sg.getReferenceGPS();
|
|
}
|
|
|
|
@Override
|
|
public String getReferenceName() {
|
|
return getUnitName();
|
|
}
|
|
|
|
@Override
|
|
public void receiveSourceNotification(int type, Object object) {
|
|
// don't do anything by default
|
|
}
|
|
|
|
|
|
|
|
}
|