Updates to FX GUI

This commit is contained in:
Jamie Mac 2023-10-09 14:56:12 +01:00
parent e1462537f7
commit e8fc75dc9e
27 changed files with 888 additions and 436 deletions

View File

@ -6,7 +6,7 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk-17.0.4.101-hotspot">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/Java 17">
<attributes>
<attribute name="module" value="true"/>
<attribute name="maven.pomderived" value="true"/>

View File

@ -15,8 +15,8 @@
<properties>
<javafx.version>16</javafx.version>
<maven.compiler.source>11</maven.compiler.source>
<javafx.version>17</javafx.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

View File

@ -147,7 +147,12 @@ public class CheckWavHeadersPane extends PamBorderPane {
else {
folderName.setText(folderInputSystem.getCurrentFolder());
}
folder = new File(folderInputSystem.getCurrentFolder());
if (folderInputSystem.getCurrentFolder()!=null){
folder = new File(folderInputSystem.getCurrentFolder());
}
else folder = null;
textArea.setText(" ");
allFiles.clear();
nFiles = countFiles(folder);

View File

@ -10,13 +10,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.JFrame;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import pamMaths.PamQuaternion;
import pamMaths.PamVector;
import userDisplay.UserDisplayControl;
import depthReadout.DepthControl;
import Array.importHydrophoneData.HydrophoneImport;
import Array.importHydrophoneData.StreamerImport;
import Array.layoutFX.ArrayGUIFX;
@ -89,7 +85,7 @@ public class ArrayManager extends PamControlledUnit implements PamSettings, PamO
// private DepthControl depthControl;
private ImportDataSystem<ArrayList<Double>> hydrophoneImportManager;
private ImportDataSystem<Hydrophone> hydrophoneImportManager;
private ImportDataSystem<ArrayList<Double>> streamerImportManager;
@ -138,7 +134,7 @@ public class ArrayManager extends PamControlledUnit implements PamSettings, PamO
//enable importing of time stamped hydrophone and streamer data if in viewer mode.
if (isViewer){
hydrophoneImportManager= new ImportDataSystem<ArrayList<Double>>(new HydrophoneImport(hydrophonesProcess.getHydrophoneDataBlock()));
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");

View File

@ -1,15 +1,22 @@
package Array.importHydrophoneData;
import java.io.IOException;
import java.util.ArrayList;
import Array.ArrayManager;
import Array.Hydrophone;
import Array.HydrophoneDataBlock;
import Array.HydrophoneDataUnit;
import PamUtils.PamCalendar;
import PamUtils.TxtFileUtils;
import PamView.importData.DataImport;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import us.hebi.matlab.mat.format.Mat5;
import us.hebi.matlab.mat.format.Mat5File;
import us.hebi.matlab.mat.types.Array;
import us.hebi.matlab.mat.types.Matrix;
import us.hebi.matlab.mat.types.Struct;
/**
* Class for importing hydrophone data from external file and saving to database.
@ -27,29 +34,31 @@ import PamguardMVC.PamDataUnit;
*
* @author Jamie Macaulay
*/
public class HydrophoneImport extends DataImport<ArrayList<Double>>{
String[] extensionStrings={".csv"};
public class HydrophoneImport extends DataImport<Hydrophone>{
String[] extensionStrings={".csv", ".mat"};
private ArrayList<ArrayList<Double>> hydrophonePositions;
private int errorCode;
private HydrophoneDataBlock hydrophoneDataBlock;
/**
* Streamer id to use if imported data has no streamer id info
*/
public static int defaultStreamerID=0;
// /**
// *Gain value to use if imported data has no gain info
// */
// public static int defaultGain=0; // use ArrayManager default instead
// /**
// *Sensitivity value to use if imported data has no sensitivty info
// */
// public static int defaultSens=-170; // use ArrayManager default instead
// /**
// *Gain value to use if imported data has no gain info
// */
// public static int defaultGain=0; // use ArrayManager default instead
// /**
// *Sensitivity value to use if imported data has no sensitivty info
// */
// public static int defaultSens=-170; // use ArrayManager default instead
/********NOT IMPLEMENTED YET*************
* Loads from a matlab structure with following format
* structure(i).time =time
@ -58,32 +67,32 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
*
*/
public final static int MATLAB_STRUCT_FORMAT=2;
/**
* Everything seems fine
*/
public final static int DATA_OK=3;
/**
* The data is far in the past or in the future
*/
public final static int ERROR_YEARS=4;
/**
* Something has gone wrong getting the csv file
*/
public final static int ERROR_LOADING_CSV=5;
/**
* Something has gone wrong loading the matlab structure
*/
public final static int ERROR_LOADING_MATLAB_STRUCT=6;
/**
* The number of hydrophones is not the same as the number of hydrophones in the curretn array manager.
* The number of hydrophones is not the same as the number of hydrophones in the current array manager.
*/
public final static int ERROR_NUMBER_OF_HYDROPHONES_ARRAY=7;
/**
* The number of hydrophones is different for different times.
*/
@ -95,11 +104,11 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
@Override
public ArrayList loadDataIntermediate(String filePath) {
if (filePath.endsWith(".csv")){
hydrophonePositions=TxtFileUtils.importCSVData(filePath);
if (hydrophonePositions==null || hydrophonePositions.size()==0 ) errorCode=ERROR_LOADING_CSV;
else{
//we now have two possibilities. either loading in a legacy file or loading in a list of hydrophones.
@ -112,77 +121,153 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
if ((hydrophonePositions.get(0).size()-1)%6==0){
return convertToHydrophoneList(hydrophonePositions);
}
}
}
if (filePath.endsWith(".mat")){
hydrophonePositions=importPositionsFromMatlab(filePath);
ArrayList<Hydrophone> hydrophonePositions = importPositionsFromMatlab(filePath);
if (hydrophonePositions==null) errorCode=ERROR_LOADING_MATLAB_STRUCT;
return hydrophonePositions;
}
return null;
}
/**
* Converts a 2D List of hydrophones into a 1D list of hydrophones.
* @param importData. Each row of the input array must have the following format. time, x0, y0,z0, x0Error, y0Error, z0Error,x1, y1,z1, x1Error, y1Error, z1Error,,..... and so on depending on the number of hydrophones.
* @return a list of hydrophones with the following format for each row. [0]=timeMilliss [1]=x [2]=y [3]=z [4]=xErr [5]=yErr [6]=zErr [7]=streamerId [8]=hydrophoneId;
* Converts a 2D List of hydrophones into a 1D list of hydrophone objecys.
*
* @param importData. Each row of the input array must have the following
* format. time, x0, y0,z0, x0Error, y0Error, z0Error,x1,
* y1,z1, x1Error, y1Error, z1Error,,..... and so on
* depending on the number of hydrophones.
* @return a list of hydrophone objects.
*/
public ArrayList<ArrayList<Double>> convertToHydrophoneList(ArrayList<ArrayList<Double>> importData){
ArrayList<ArrayList<Double>> hydrophonesAll=new ArrayList<ArrayList<Double>>();
public ArrayList<Hydrophone> convertToHydrophoneList(ArrayList<ArrayList<Double>> importData){
ArrayList<Hydrophone> hydrophonesAll=new ArrayList<Hydrophone>();
ArrayList<Double> tempArray;
Hydrophone hydrophone;
double[] cOordinates;
double [] cOordinateErrors;
double sensitivity;
double gain;
for (int i=0; i<importData.size(); i++){
for (int j=0; j<((importData.get(i).size()-1)/6); j++){
tempArray= new ArrayList<Double>();
cOordinates=new double[3];
cOordinateErrors=new double[3];
cOordinates[0]=importData.get(i).get(j*6+1);
cOordinates[1]=importData.get(i).get(j*6+2);
cOordinates[2]=importData.get(i).get(j*6+3);
cOordinateErrors[0]=importData.get(i).get(j*6+4);
cOordinateErrors[1]=importData.get(i).get(j*6+5);
cOordinateErrors[2]=importData.get(i).get(j*6+6);
tempArray.add(importData.get(i).get(0));
tempArray.add(cOordinates[0]);
tempArray.add(cOordinates[1]);
tempArray.add(cOordinates[2]);
tempArray.add(cOordinateErrors[0]);
tempArray.add(cOordinateErrors[1]);
tempArray.add(cOordinateErrors[2]);
sensitivity=ArrayManager.DEFAULT_HYDROPHONE_SENSITIVITY;
gain=ArrayManager.DEFAULT_PREAMP_GAIN;
hydrophone=new Hydrophone(j,
cOordinates[0], cOordinates[1],cOordinates[2],
cOordinateErrors[0], cOordinateErrors[1],cOordinateErrors[2],
"Unknown",
sensitivity,
new double[]{0, 20000},//meh
gain);
long timeMillis= (long) PamUtils.PamCalendar.excelSerialtoMillis(importData.get(i).get(0));
hydrophone.setTimeMillis(timeMillis);
// tempArray.add(importData.get(i).get(0));
// tempArray.add(cOordinates[0]);
// tempArray.add(cOordinates[1]);
// tempArray.add(cOordinates[2]);
// tempArray.add(cOordinateErrors[0]);
// tempArray.add(cOordinateErrors[1]);
// tempArray.add(cOordinateErrors[2]);
//set Streamer ID.
tempArray.add((double) defaultStreamerID);
// tempArray.add((double) defaultStreamerID);
//set hydrophoneID
// System.out.println("Hydrophone iD"+j);
tempArray.add((double) j);
hydrophonesAll.add(tempArray);
// System.out.println("TempArray: "+tempArray);
// System.out.println("Hydrophone iD"+j);
// tempArray.add((double) j);
hydrophonesAll.add(hydrophone);
// System.out.println("TempArray: "+tempArray);
}
}
return hydrophonesAll;
}
private ArrayList<ArrayList<Double>> importPositionsFromMatlab(
/**
* Import the hydrophone positions from a MATLAB mat file.
* @param filePath - the file path.
* @return an array of hydrophones.
*/
private static ArrayList<Hydrophone> importPositionsFromMatlab(
String filePath) {
// TODO- needs to be implemented.
try {
ArrayList<Hydrophone> hydrophones = new ArrayList<Hydrophone>();
Mat5File mat5 = Mat5.readFromFile(filePath);
Struct structArray = mat5.getArray("array_dimensions");
double sensitivity=ArrayManager.DEFAULT_HYDROPHONE_SENSITIVITY;
double gain=ArrayManager.DEFAULT_PREAMP_GAIN;
Matrix posStruct;
Matrix errStruct;
Matrix datetime;
// System.out.println("Number of structures: " + structArray.getNumElements());
Hydrophone hydrophone;
for (int i=0; i<structArray.getNumElements(); i++) {
//hydrophones in channel order.
posStruct= structArray.getMatrix("hydrophones", i);
//errors in channel order
errStruct= structArray.getMatrix("hydrophone_errors", i);
//channels
datetime = structArray.getMatrix("datetime", i);
if (posStruct.getNumElements()<=0) {
continue;
}
for (int j=0; j<posStruct.getNumRows(); j++) {
hydrophone =new Hydrophone(j,
posStruct.getDouble(j, 0), posStruct.getDouble(j, 1),posStruct.getDouble(j, 2),
errStruct.getDouble(j, 0), errStruct.getDouble(j, 1),errStruct.getDouble(j, 2),
"Unknown",
sensitivity,
new double[]{0, 20000},//meh
gain);
hydrophone.setTimeMillis(PamUtils.PamCalendar.dateNumtoMillis(datetime.getDouble(0)));
hydrophones.add(hydrophone);
}
}
return hydrophones;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@ -192,7 +277,7 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
}
@Override
public boolean isDataFormatOK(ArrayList<Double> dataLine) {
public boolean isDataFormatOK(Hydrophone hydrophone) {
// TODO might need to put some extra bits and bobs here eventually.
return true;
}
@ -201,34 +286,43 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
* For hydrophone data imported [0]=timeMilliss [1]=x [2]=y [3]=z [4]=xErr [5]=yErr [6]=zErr [7]=streamerId [8]=hydrophoneId [9]=sensitivity [10]=gain
*/
@Override
public PamDataUnit createDataUnit(ArrayList<Double> dataLine) {
double sensitivity=ArrayManager.DEFAULT_HYDROPHONE_SENSITIVITY;
double gain=ArrayManager.DEFAULT_PREAMP_GAIN;
if (dataLine.size()==10) {
gain=dataLine.get(10);
sensitivity=dataLine.get(9);
}
double[] bandwidth={0, 20000};
public PamDataUnit createDataUnit(Hydrophone hydrophone) {
Hydrophone hydrophone=new Hydrophone(dataLine.get(8).intValue(), dataLine.get(1), dataLine.get(2), dataLine.get(3), dataLine.get(4),dataLine.get(5), dataLine.get(6), "Unknown", sensitivity,
bandwidth, gain);
//need to convert from excel serial to millis.
long timeMillis= (long) PamUtils.PamCalendar.excelSerialtoMillis(dataLine.get(0));
hydrophone.setTimeMillis(timeMillis);
// double sensitivity=ArrayManager.DEFAULT_HYDROPHONE_SENSITIVITY;
// double gain=ArrayManager.DEFAULT_PREAMP_GAIN;
// if (dataLine.size()==10) {
// gain=dataLine.get(10);
// sensitivity=dataLine.get(9);
// }
// double[] bandwidth={0, 20000};
//
// Hydrophone hydrophone=new Hydrophone(dataLine.get(8).intValue(), dataLine.get(1), dataLine.get(2), dataLine.get(3), dataLine.get(4),dataLine.get(5), dataLine.get(6), "Unknown", sensitivity,
// bandwidth, gain);
// //need to convert from excel serial to millis.
// long timeMillis= (long) PamUtils.PamCalendar.excelSerialtoMillis(dataLine.get(0));
// hydrophone.setTimeMillis(timeMillis);
HydrophoneDataUnit hydrophoneDataUnit=new HydrophoneDataUnit(hydrophone);
return hydrophoneDataUnit;
}
@Override
public PamDataBlock getDataBlock() {
return hydrophoneDataBlock;
}
@Override
public String getDataUnitName(){
return "Hydrophone Units";
}
public static void main(String [] args) {
String file = "/Users/au671271/Desktop/test_array_data.mat";
ArrayList<Hydrophone> data = importPositionsFromMatlab(file);
System.out.println("Impotred data size: " + data.size());
System.out.println(data.get(0));
}
}

View File

@ -35,10 +35,17 @@ public class HydrophoneProperty {
public void setHydrophone(Hydrophone hydrophone) {
this.hydrophone = hydrophone;
x .set(hydrophone.getX());
y .set(hydrophone.getY());
z .set(hydrophone.getZ());
id.set(hydrophone.getStreamerId());
xErr .set(hydrophone.getdX());
yErr .set(hydrophone.getdY());
zErr .set(hydrophone.getdZ());
id.set(hydrophone.getID());
}
/**
@ -73,4 +80,28 @@ public class HydrophoneProperty {
return hydrophone;
}
/**
* The x-coordinate property.
* @return the x coordintae property.
*/
public SimpleDoubleProperty getXErr() {
return xErr;
}
/**
* The y-coordinate property.
* @return the y coordintae property.
*/
public SimpleDoubleProperty getYErr() {
return yErr;
}
/**
* The z-coordinate property.
* @return the z coordintae property.
*/
public SimpleDoubleProperty getZErr() {
return zErr;
}
}

View File

@ -13,9 +13,11 @@ import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Labeled;
import javafx.scene.control.TextField;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.Pane;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxNodes.PamVBox;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamGridPane;
import pamViewFX.fxNodes.PamSpinner;
import pamViewFX.validator.PamValidator;
@ -28,6 +30,8 @@ import pamViewFX.validator.PamValidator;
*/
public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
private static final double COLUMN_0_WIDTH = 100;
/**
*
* Check inputs in real time
@ -89,7 +93,7 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
/**
* The main holder pane.
*/
private PamVBox mainPane;
private PamBorderPane mainPane;
private InterpSettingsPane interpPane;
@ -99,8 +103,8 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
public HydrophoneSettingsPane() {
super(null);
mainPane = new PamVBox();
mainPane.setSpacing(5);
PamVBox holderPane = new PamVBox();
holderPane.setSpacing(5);
recieverIDLabel = new Label("General");
@ -114,7 +118,10 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
interpPane = new InterpSettingsPane();
mainPane.getChildren().addAll(recieverIDLabel, createGeneralPane(), coOrdLabel, createPositionPane(), interpLabel, interpPane);
holderPane.getChildren().addAll(recieverIDLabel, createGeneralPane(), coOrdLabel, createPositionPane(), interpLabel, interpPane);
mainPane = new PamBorderPane();
mainPane.setCenter(holderPane);
}
//
@ -181,7 +188,7 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
recieverIDLabel.setText(recieverString+ " ID Info");
recieverTypeLabel.setText(recieverString + " type ");
recieverSensLabel.setText(recieverString + " sensitivity ");
recieverSensLabel.setText(recieverString + " sens ");
dBSensLabel.setText(dbSens);
}
@ -216,17 +223,18 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
PamGridPane mainControls=new PamGridPane();
mainControls.setHgap(5);
mainControls.setVgap(5);
int gridy = 0;
Label parentArrayLabel = new Label("Parent Array");
parentArrayLabel.setAlignment(Pos.CENTER_RIGHT);
parentArrayLabel.setAlignment(Pos.CENTER_LEFT);
mainControls.add(parentArrayLabel, 0, gridy);
streamers = new ComboBox<String>();
mainControls.add(streamers, 1, gridy);
gridy++;
mainControls.add(recieverTypeLabel = new Label(""), 0, gridy);
recieverTypeLabel.setAlignment(Pos.CENTER_RIGHT);
recieverTypeLabel.setAlignment(Pos.CENTER_LEFT);
defaultHydro = new ComboBox<String>();
for (int i=0; i<DefaultHydrophone.values().length; i++) {
@ -251,7 +259,7 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
gridy++;
mainControls.add(recieverSensLabel = new Label(""), 0, gridy);
recieverSensLabel.setAlignment(Pos.CENTER_RIGHT);
recieverSensLabel.setAlignment(Pos.CENTER_LEFT);
hSens = new PamSpinner<Double>(-Double.MAX_VALUE, Double.MAX_VALUE, -200., 1.);
hSens.setEditable(true);
@ -269,7 +277,7 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
gridy++;
Label preAmpLabel = new Label("Preamplifier gain");
mainControls.add(preAmpLabel, 0, gridy);
preAmpLabel.setAlignment(Pos.CENTER_RIGHT);
preAmpLabel.setAlignment(Pos.CENTER_LEFT);
preampGain =new PamSpinner<Double>(-Double.MAX_VALUE, Double.MAX_VALUE, 0., 1.);
preampGain.valueProperty().addListener((obs, oldval, newVal)->{
if (ressetHydrophoneType) return;
@ -283,6 +291,11 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
mainControls.add(preampGain, 1, gridy);
mainControls.add(new Label("dB"), 2, gridy);
ColumnConstraints col1 = new ColumnConstraints();
col1.setMinWidth(COLUMN_0_WIDTH);
col1.setMaxWidth(COLUMN_0_WIDTH);
mainControls.getColumnConstraints().addAll(col1);
setGeneralInfoLabelText();
@ -292,7 +305,7 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
/**
* Create the pane to allow users to change the position of hydrophones
*/
private Pane createPositionPane( ){
private Pane createPositionPane(){
double sectionPadding=15;
@ -313,6 +326,7 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
PamGridPane positionPane = new PamGridPane();
positionPane.setHgap(5);
positionPane.setVgap(5);
double maxWidth =10;
@ -326,7 +340,7 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
zPos.setMaxWidth(maxWidth);
addTextValidator(zPos, "z position");
depthLabel = new Label("Depth");
depthLabel.setAlignment(Pos.CENTER_RIGHT);
depthLabel.setAlignment(Pos.CENTER);
xPosErr=new TextField();
xPosErr.setMaxWidth(50);
@ -337,33 +351,64 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
zPosErr=new TextField();
zPosErr.setMaxWidth(50);
depthLabel2 = new Label(""); //changes with air or water mode.
depthLabel2.setAlignment(Pos.CENTER);
addTextValidator(zPosErr, "z error");
int y=0;
int col=0;
int row =0;
Label xLabel = new Label("x");
xLabel.setAlignment(Pos.CENTER_RIGHT);
positionPane.add(xLabel, 0, y);
positionPane.add(xPos, 1, y);
positionPane.add(new Label("\u00B1"), 2, y);
positionPane.add(xPosErr, 3, y);
positionPane.add(new Label("m (right of streamer)"), 4, y);
y++;
xLabel.setAlignment(Pos.CENTER);
Label yLabel = new Label("y");
yLabel.setAlignment(Pos.CENTER_RIGHT);
positionPane.add(yLabel, 0, y);
positionPane.add(yPos, 1, y);
positionPane.add(new Label("\u00B1"), 2, y);
positionPane.add(yPosErr, 3, y);
positionPane.add(new Label("m (ahead of streamer)"), 4, y);
y++;
yLabel.setAlignment(Pos.CENTER);
col=1;
positionPane.add(xLabel, col++, row);
positionPane.add(yLabel, col++, row);
positionPane.add(depthLabel, col++, row);
positionPane.add(depthLabel, 0, y);
positionPane.add(zPos, 1, y);
positionPane.add(new Label("\u00B1"), 2, y);
positionPane.add(zPosErr, 3, y);
positionPane.add(depthLabel2, 4, y);
col=0;
row++;
Label positionLabel = new Label("Position");
positionPane.add(positionLabel, col++, row);
positionPane.add(xPos, col++, row);
positionPane.add(yPos, col++, row);
positionPane.add(zPos, col++, row);
positionPane.add(new Label("(m)"), col++, row);
col=0;
row++;
Label errLabel = new Label("Error");
positionPane.add(errLabel, col++, row);
positionPane.add(xPosErr, col++, row);
positionPane.add(yPosErr, col++, row);
positionPane.add(zPosErr, col++, row);
positionPane.add(new Label("(m)"), col++, row);
// positionPane.add(new Label("\u00B1"), col, 2);
// positionPane.add(xPosErr, col, 3);
// positionPane.add(new Label("m (right of streamer)"), col, 5);
col++;
// Label yLabel = new Label("y");
// yLabel.setAlignment(Pos.CENTER);
// positionPane.add(yLabel, col, 0);
// positionPane.add(yPos, col, 1);
// positionPane.add(new Label("\u00B1"), col, 2);
// positionPane.add(yPosErr, col, 3);
// positionPane.add(new Label("m (ahead of streamer)"), col, 4);
// col++;
//
//
// positionPane.add(depthLabel, col, 0);
// positionPane.add(zPos, col, 1);
// positionPane.add(new Label("\u00B1"), col, 2);
// positionPane.add(zPosErr, col, 3);
// positionPane.add(depthLabel2, col, 4);
// ColumnConstraints col1 = new ColumnConstraints();
// col1.setHgrow(Priority.ALWAYS);
@ -373,6 +418,12 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
// PamGuiManagerFX.titleFont2style(positionLabel);
mainControls.getChildren().addAll(positionPane);
ColumnConstraints col1 = new ColumnConstraints();
col1.setMinWidth(COLUMN_0_WIDTH);
col1.setMaxWidth(COLUMN_0_WIDTH);
positionPane.getColumnConstraints().addAll(col1);
setCoordsText();
@ -469,6 +520,8 @@ public class HydrophoneSettingsPane extends SettingsPane<Hydrophone> {
hydrophone.setdX(Double.valueOf(xPosErr.getText()));
hydrophone.setdY(Double.valueOf(yPosErr.getText()));
hydrophone.setdZ(Double.valueOf(zPosErr.getText()));
}
catch (Exception Ex) {
System.err.println("There is a problem with one of the parameters in the Coordinates panel");

View File

@ -68,7 +68,7 @@ public class HydrophonesPane extends PamBorderPane {
pamFlipePane = new PamFlipPane();
pamFlipePane.getAdvLabel().setText("Hydrophone Settings");
((Pane) hydrophonePane.getContentNode()).setPadding(new Insets(5,5,5,5));
((Pane) hydrophonePane.getContentNode()).setPadding(new Insets(5,5,5,15));
pamFlipePane.setAdvPaneContent(hydrophonePane.getContentNode());
pamFlipePane.setFrontContent(tableArrayPane);
@ -78,11 +78,21 @@ public class HydrophonesPane extends PamBorderPane {
pamFlipePane.flipFrontProperty().addListener((obsval, oldVal, newVal)->{
//the flip pane
if (newVal) {
Hydrophone hydro = hydrophonePane.getParams(currentHydrophoneData.getHydrophone());
// System.out.println("Hydro: " + currentHydrophoneData.getX().get()+ " " + currentHydrophoneData.getY().get() + " " + currentHydrophoneData.getZ().get() + " ID: " +hydro.getID());
// System.out.println("Hydro err: " + currentHydrophoneData.getXErr().get()+ " " + currentHydrophoneData.getYErr().get() + " " + currentHydrophoneData.getZErr().get());
currentHydrophoneData.setHydrophone(hydro);
//need to refresh table to show symbol.
tableArrayPane.getTableView().refresh();
//
// System.out.println("Table size: " + tableArrayPane.getTableView().getItems().size());
// for (int i=0; i<tableArrayPane.getTableView().getItems().size(); i++) {
// System.out.println("Item : " + tableArrayPane.getTableView().getItems().get(i) + " " + currentHydrophoneData);
// }
}
});
@ -98,38 +108,45 @@ public class HydrophonesPane extends PamBorderPane {
public HydrophoneTable(ObservableList<HydrophoneProperty> hydrophoneData) {
super(hydrophoneData);
//need to set up all the rows.
TableColumn<HydrophoneProperty,Number> streamerID = new TableColumn<HydrophoneProperty,Number>("ID");
streamerID.setCellValueFactory(cellData -> cellData.getValue().getID());
streamerID.setEditable(false);
TableColumn<HydrophoneProperty,Number> hydroID = new TableColumn<HydrophoneProperty,Number>("ID");
hydroID.setCellValueFactory(cellData -> cellData.getValue().getID());
hydroID.setEditable(false);
TableColumn<HydrophoneProperty,Number> x = new TableColumn<HydrophoneProperty,Number>("x (m)");
TableColumn<HydrophoneProperty,Number> x = new TableColumn<HydrophoneProperty,Number>("x");
x.setCellValueFactory(cellData -> cellData.getValue().getX());
x.setEditable(false);
TableColumn<HydrophoneProperty,Number> y = new TableColumn<HydrophoneProperty,Number>("y (m)");
TableColumn<HydrophoneProperty,Number> y = new TableColumn<HydrophoneProperty,Number>("y");
y.setCellValueFactory(cellData -> cellData.getValue().getY());
y.setEditable(false);
TableColumn<HydrophoneProperty,Number> z = new TableColumn<HydrophoneProperty,Number>("depth (m)");
TableColumn<HydrophoneProperty,Number> z = new TableColumn<HydrophoneProperty,Number>("depth");
z.setCellValueFactory(cellData -> cellData.getValue().getZ());
z.setEditable(false);
TableColumn<HydrophoneProperty,Number> xErr = new TableColumn<HydrophoneProperty,Number>("x error (m)");
x.setCellValueFactory(cellData -> cellData.getValue().getX());
x.setEditable(false);
TableColumn posColumn=new TableColumn("Position (m)");
posColumn.getColumns().addAll(x, y, z);
TableColumn<HydrophoneProperty,Number> yErr = new TableColumn<HydrophoneProperty,Number>("y error (m)");
y.setCellValueFactory(cellData -> cellData.getValue().getY());
y.setEditable(false);
TableColumn<HydrophoneProperty,Number> xErr = new TableColumn<HydrophoneProperty,Number>("x");
xErr.setCellValueFactory(cellData -> cellData.getValue().getXErr());
xErr.setEditable(false);
TableColumn<HydrophoneProperty,Number> zErr = new TableColumn<HydrophoneProperty,Number>("z error (m)");
z.setCellValueFactory(cellData -> cellData.getValue().getZ());
z.setEditable(false);
TableColumn<HydrophoneProperty,Number> yErr = new TableColumn<HydrophoneProperty,Number>("y");
yErr.setCellValueFactory(cellData -> cellData.getValue().getYErr());
yErr.setEditable(false);
TableColumn<HydrophoneProperty,Number> zErr = new TableColumn<HydrophoneProperty,Number>("z");
zErr.setCellValueFactory(cellData -> cellData.getValue().getZErr());
zErr.setEditable(false);
TableColumn errorColumn=new TableColumn("Errors (m)");
errorColumn.getColumns().addAll(xErr, yErr, zErr);
getTableView().getColumns().addAll(streamerID, x, y, z, xErr, yErr, zErr);
getTableView().getColumns().addAll(hydroID, posColumn, errorColumn);
}
@ -156,8 +173,7 @@ public class HydrophonesPane extends PamBorderPane {
hydrophonePane.setCurrentArray(currentArray);
hydrophonePane.setParams(data.getHydrophone());
currentHydrophoneData = data;
pamFlipePane.flipToBack();
@ -179,7 +195,6 @@ public class HydrophonesPane extends PamBorderPane {
@Override
public void createNewData(){
//create a new classifier.
// this.getDa
hydrophoneList.add(createDefaultHydrophoneProperty(hydrophoneList.size()));
}

View File

@ -4,6 +4,7 @@ import Array.PamArray;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamGridPane;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Tooltip;
import javafx.scene.control.ToggleGroup;
@ -12,15 +13,21 @@ import javafx.scene.control.ToggleGroup;
/**
* Dialog component used by both the streamer and the hydrophone dialogs
*
* @author Doug Gillespie
*
*/
public class InterpSettingsPane extends PamBorderPane {
private RadioButton useLatest, usePrevious, useInterpolate;
private int allowedValues = 0xFF; // bitmap of banned values !
ChoiceBox<String> interpBox;
public InterpSettingsPane() {
PamGridPane gridPane = new PamGridPane();
gridPane.setVgap(5);

View File

@ -6,8 +6,10 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.Dialog;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.flipPane.PamFlipPane;
import pamViewFX.fxNodes.table.TableSettingsPane;
import javafx.scene.control.TableColumn;
import javafx.scene.layout.Pane;
import javafx.geometry.Insets;
/**
@ -18,22 +20,63 @@ import javafx.geometry.Insets;
*
*/
public class StreamerPane extends PamBorderPane {
BasicArrayTable tableArrayPane;
ObservableList<StreamerProperty> streamerData = FXCollections.observableArrayList();
/**
* The current hydrophone array
*/
private PamArray currentArray;
/**
* The pam flip pane.
*/
private PamFlipPane pamFlipePane;
/**
* The current streamer data.
*/
private StreamerProperty currentStreamerData;
/**
* Settings pane for a single hydrophone.
*/
private StreamerSettingsPane streamerPane = new StreamerSettingsPane();
public StreamerPane() {
tableArrayPane = new BasicArrayTable(streamerData);
tableArrayPane.setPadding(new Insets(5,5,5,5));
this.setCenter(tableArrayPane);
tableArrayPane = new BasicArrayTable(streamerData);
tableArrayPane.setPadding(new Insets(5,5,5,5));
this.setCenter(tableArrayPane);
pamFlipePane = new PamFlipPane();
pamFlipePane.getAdvLabel().setText("Hydrophone Settings");
((Pane) streamerPane.getContentNode()).setPadding(new Insets(5,5,5,5));
pamFlipePane.setAdvPaneContent(streamerPane.getContentNode());
pamFlipePane.setFrontContent(tableArrayPane);
pamFlipePane.getFront().setPadding(new Insets(5,5,5,10));
pamFlipePane.flipFrontProperty().addListener((obsval, oldVal, newVal)->{
//the flip pane
if (newVal) {
Streamer hydro = streamerPane.getParams(currentStreamerData.getStreamer());
currentStreamerData.setStreamer(hydro);
//need to refresh table to show symbol.
tableArrayPane.getTableView().refresh();
}
});
this.setCenter(pamFlipePane);
}
/**
* Class which extends TableSettingsPane and creates a sliding pane instead of a dialog when an item is added.
* @author Jamie Macaulay
@ -47,29 +90,29 @@ public class StreamerPane extends PamBorderPane {
TableColumn<StreamerProperty,Number> streamerID = new TableColumn<StreamerProperty,Number>("ID");
streamerID.setCellValueFactory(cellData -> cellData.getValue().getID());
streamerID.setEditable(false);
TableColumn<StreamerProperty,String> name = new TableColumn<StreamerProperty,String>("Name");
name.setCellValueFactory(cellData -> cellData.getValue().getName());
name.setEditable(false);
TableColumn<StreamerProperty,Number> x = new TableColumn<StreamerProperty,Number>("x (m)");
x.setCellValueFactory(cellData -> cellData.getValue().getX());
x.setEditable(false);
TableColumn<StreamerProperty,Number> y = new TableColumn<StreamerProperty,Number>("y (m)");
y.setCellValueFactory(cellData -> cellData.getValue().getY());
y.setEditable(false);
TableColumn<StreamerProperty,Number> z = new TableColumn<StreamerProperty,Number>("z (m)");
z.setCellValueFactory(cellData -> cellData.getValue().getZ());
z.setEditable(false);
TableColumn<StreamerProperty,String> reference = new TableColumn<StreamerProperty,String>("Reference");
reference.setCellValueFactory(cellData -> cellData.getValue().getHydrophineLocator());
reference.setEditable(true);
TableColumn<StreamerProperty,String> locator = new TableColumn<StreamerProperty,String>("Locator");
locator.setCellValueFactory(cellData -> cellData.getValue().getHydrophineLocator());
locator.setEditable(true);
@ -87,14 +130,14 @@ public class StreamerPane extends PamBorderPane {
@Override
public Dialog<StreamerProperty> createSettingsDialog(StreamerProperty data) {
//we do not use dialogs here- sliding pane instead.
// setClassifierPane(data);
// showFlipPane(true);
// setClassifierPane(data);
// showFlipPane(true);
return null;
}
@Override
public void editData(StreamerProperty data){
// setClassifierPane(data);
// setClassifierPane(data);
//showFlipPane(true);
}
@ -109,7 +152,7 @@ public class StreamerPane extends PamBorderPane {
}
}
public void setParams(PamArray currentArray) {
this.currentArray=currentArray;
}

View File

@ -1832,23 +1832,16 @@ public class PamController implements PamControllerInterface, PamSettings {
* Updates the entire datamap.
*/
public void updateDataMap(){
System.out.println("updateDataMap:");
if (DBControlUnit.findDatabaseControl()==null) return;
System.out.println("updateDataMap: 1");
ArrayList<PamDataBlock> datablocks=getDataBlocks() ;
System.out.println("updateDataMap: 2");
DBControlUnit.findDatabaseControl().updateDataMap(datablocks);
System.out.println("updateDataMap: 3");
BinaryStore.findBinaryStoreControl().getDatagramManager().updateDatagrams();
System.out.println("updateDataMap: 4");
if (BinaryStore.findBinaryStoreControl()!=null) {
BinaryStore.findBinaryStoreControl().getDatagramManager().updateDatagrams();
}
notifyModelChanged(PamControllerInterface.EXTERNAL_DATA_IMPORTED);
}

View File

@ -950,6 +950,68 @@ public class PamArrayUtils {
return true;
}
/**
* Convert primitive long array to Long object array.
* @param arr - primitive long array
* @return a Long array
*/
public static Long[] primitive2Object(long[] arr) {
if (arr==null) return null;
Long[] arrL = new Long[arr.length];
for (int i=0; i<arr.length; i++) {
arrL[i]=arr[i];
}
return arrL;
}
/**
* Convert primitive double array to Double object array.
* @param arr - primitive double array
* @return a Double array
*/
public static Double[] primitive2Object(double[] arr) {
if (arr==null) return null;
Double[] arrL = new Double[arr.length];
for (int i=0; i<arr.length; i++) {
arrL[i]=arr[i];
}
return arrL;
}
/**
* Convert primitive int array to Integer object array.
* @param arr - primitive int array
* @return a Ineteger array
*/
public static Integer[] primitive2Object(int[] arr) {
if (arr==null) return null;
Integer[] arrL = new Integer[arr.length];
for (int i=0; i<arr.length; i++) {
arrL[i]=arr[i];
}
return arrL;
}
public static long[] object2Primitve(Long[] arr) {
if (arr==null) return null;
long[] arrL = new long[arr.length];
for (int i=0; i<arr.length; i++) {
arrL[i]=arr[i].longValue();
}
return arrL;
}

View File

@ -5,66 +5,95 @@ import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
/**
* This class is used to define what data to import and how to import it. It is used in conjunction with ImportDataSystem to create a generic system to load any type of data into a data block.
* This class is used to define what data to import and how to import it. It is
* used in conjunction with ImportDataSystem to create a generic system to load
* any type of data into a data block.
* <p>
* First getExtensionsStrings() defines which file types can be selected for import.
* First getExtensionsStrings() defines which file types can be selected for
* import.
* <p>
* Before loading in any data we need to perform pre-checks with the function performPreChecks(). This function is called before the load thread is called. Often this will remain blank but say you needed extra user imput then this function could be used
* to create another dialog box before the data is loaded.
* Before loading in any data we need to perform pre-checks with the function
* performPreChecks(). This function is called before the load thread is called.
* Often this will remain blank but say you needed extra user imput then this
* function could be used to create another dialog box before the data is
* loaded.
* <p>
* To create a new importer first we need to load a file into memory using the loadDataIntermediate(String filePath) function. This will create an ArrayList<T> were T is the type of data we're trying to save. So for example if you are loading in NMEA data then
* you would use create loadDataIntermediate(String filePath) which imports the file (filepath) and converts into an ArrayList of strings io.e ArrayList<String> such that T=String;
* To create a new importer first we need to load a file into memory using the
* loadDataIntermediate(String filePath) function. This will create an
* ArrayList<T> were T is the type of data we're trying to save. So for example
* if you are loading in NMEA data then you would use create
* loadDataIntermediate(String filePath) which imports the file (filepath) and
* converts into an ArrayList of strings io.e ArrayList<String> such that
* T=String;
* <p>
* Once the data has been loaded into memory it must be converted into a data unit and saved to a data block. The function createDataUnit(T dataLine) converts data into a PamDatUnit. This function would for example, convert an NMEA strings into a GPSDataUnit. The function
* isDataFormatOK() needs to be used to check that each T is in the correct format.
* Once the data has been loaded into memory it must be converted into a data
* unit and saved to a data block. The function createDataUnit(T dataLine)
* converts data into a PamDatUnit. This function would for example, convert an
* NMEA strings into a GPSDataUnit. The function isDataFormatOK() needs to be
* used to check that each T is in the correct format.
* <p>
*
* @author Jamie Macaulay
*
* @param <T> - the data type loaded from a file. This could be a String, ArrayList<String>, ArrayList<ArrayList<Double>> etc.
* @param <T> - the data type loaded from a file. This could be a String,
* ArrayList<String>, ArrayList<ArrayList<Double>> etc.
*/
public abstract class DataImport<T> {
public abstract class DataImport<T> {
public abstract ArrayList<T> loadDataIntermediate(String filePath);
/**
* Check that a row of imported data is in the correct format.
* Loads the file into memory - each element of the output array list is then processed.
* @param filePath - the filepath.
* @return a list of imported objects.
*/
public abstract ArrayList<T> loadDataIntermediate(String filePath);
/**
* Check that a row of imported data is in the correct format.
*
* @param dataLine-a row of data loaded from file
* @return true if the format is OK.
* @return true if the format is OK.
*/
public abstract boolean isDataFormatOK(T dataLine);
/**
* Use this function to perform any pre checks on data/ bring up extra dialog boxes before laoding data.
* @return true iof pre checks are OK.
* Use this function to perform any pre checks on data/ bring up extra dialog
* boxes before loading data.
*
* @return true iof pre checks are OK.
*/
public boolean performPreChecks(){ return true; }
public boolean performPreChecks() {
return true;
}
/**
* Create a data unit from the data loaded from the imported file.
* Create a data unit from the data loaded from the imported file.
*
* @param dataLine-a row of data loaded from file
* @return a data unit to be saved to the datablock.
* @return a data unit to be saved to the datablock.
*/
public abstract PamDataUnit createDataUnit(T dataLine);
/**
* Get the data block to to save data to.
* Get the data block to to save data to.
*
* @return
*/
@SuppressWarnings("rawtypes")
public abstract PamDataBlock getDataBlock();
/**
* Return the file extensions that can be loaded.
* @return an array of file extensions that can be loaded.
* Return the file extensions that can be loaded.
*
* @return an array of file extensions that can be loaded.
*/
public abstract String[] getExtensionsStrings();
/**
* The name of the data unit to appear on the dialog boxes.
* @return name of the data unit to be imported.
* The name of the data unit to appear on the dialog boxes.
*
* @return name of the data unit to be imported.
*/
public String getDataUnitName(){
public String getDataUnitName() {
return "Data Units";
}

View File

@ -288,7 +288,7 @@ public class ImportDataSystem<T> {
}
public void setSaveProgress(int prog){
System.out.println("prog "+prog);
//System.out.println("prog "+prog);
setProgress(prog);
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with Vectornator (http://vectornator.io/) -->
<svg height="100.0pt" stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;" version="1.1" viewBox="0 0 100 100" width="100.0pt" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs/>
<g id="Layer-1">
<path d="M7.12963 6.17629C7.12963 16.7196 8.80135 26.6021 11.5686 36.1015C16.8563 54.2534 26.1441 71.0068 35.4118 88.3002" fill="none" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="5.08575"/>
<path d="M29.8918 88.3002C29.8918 85.2497 32.3631 82.777 35.4118 82.777C38.4602 82.777 40.9316 85.2497 40.9316 88.3002C40.9316 91.3508 38.4602 93.8237 35.4118 93.8237C32.3631 93.8237 29.8918 91.3508 29.8918 88.3002Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.84398"/>
<path d="M15.6401 59.6294C15.6401 56.5791 18.1609 54.1062 21.2707 54.1062C24.3804 54.1062 26.9011 56.5791 26.9011 59.6294C26.9011 62.68 24.3804 65.1529 21.2707 65.1529C18.1609 65.1529 15.6401 62.68 15.6401 59.6294Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.84398"/>
<path d="M15.6401 59.6294C15.6401 56.5791 18.1609 54.1062 21.2707 54.1062C24.3804 54.1062 26.9011 56.5791 26.9011 59.6294C26.9011 62.68 24.3804 65.1529 21.2707 65.1529C18.1609 65.1529 15.6401 62.68 15.6401 59.6294Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.84398"/>
<path d="M57.9405 11.6997C57.9405 8.64919 60.4614 6.17629 63.5711 6.17629C66.6807 6.17629 69.2017 8.64919 69.2017 11.6997C69.2017 14.7501 66.6807 17.2231 63.5711 17.2231C60.4614 17.2231 57.9405 14.7501 57.9405 11.6997Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.84398"/>
<path d="M57.9405 30.4038C57.9405 27.3532 60.4614 24.8805 63.5711 24.8805C66.6807 24.8805 69.2017 27.3532 69.2017 30.4038C69.2017 33.4543 66.6807 35.9273 63.5711 35.9273C60.4614 35.9273 57.9405 33.4543 57.9405 30.4038Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.84398"/>
<path d="M81.6094 41.2789C81.6094 38.2283 84.1301 35.7554 87.2398 35.7554C90.3496 35.7554 92.8704 38.2283 92.8704 41.2789C92.8704 44.3293 90.3496 46.8022 87.2398 46.8022C84.1301 46.8022 81.6094 44.3293 81.6094 41.2789Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.84398"/>
<path d="M35.301 41.7148C35.301 38.6645 37.8217 36.1915 40.9316 36.1915C44.0412 36.1915 46.562 38.6645 46.562 41.7148C46.562 44.7654 44.0412 47.2383 40.9316 47.2383C37.8217 47.2383 35.301 44.7654 35.301 41.7148Z" fill="#000000" fill-rule="nonzero" opacity="1" stroke="#000000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.84398"/>
<path d="M37.2528 43.8891L63.5711 11.6997" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="5.2426"/>
<path d="M89.7145 41.7148L63.5711 11.6997" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="5.2426"/>
<path d="M40.9316 41.7148L88.4102 41.7148" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="5.2426"/>
<path d="M40.2154 41.9793L63.5711 30.4038" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="5.2426"/>
<path d="M88.5861 41.6194L64.8519 30.8155" fill="none" opacity="1" stroke="#000000" stroke-linecap="butt" stroke-linejoin="round" stroke-width="5.2426"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -9,6 +9,7 @@ import clickDetector.layoutFX.clickClassifiers.ClickClassifyPaneFX;
import javafx.geometry.HPos;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
@ -176,7 +177,7 @@ public class ClickSettingsPane extends SettingsPane<ClickParameters>{
/**
* The default pane width
*/
public static double PREF_PANE_WIDTH=560;
public static double PREF_PANE_WIDTH=600;
/**
@ -230,6 +231,7 @@ public class ClickSettingsPane extends SettingsPane<ClickParameters>{
//trigger pane
triggerFilter=new FilterPaneFX(Orientation.VERTICAL);
pamTabbedPane.getTabs().add(new Tab("Trigger Filter", triggerFilter.getContentNode()));
// //echo detection pane.
// echoDetection= new ClickEchoPane(clickControl);

View File

@ -45,7 +45,9 @@ public class ModuleIconFactory {
public Node getModuleNode(ModuleIcon icon){
switch (icon){
case ARRAY:
return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/array_manager.png")));
// return new ImageView(new Image(getClass().getResourceAsStream("/Resources/modules/array_manager.png")));
return getSVGIcon("/Resources/modules/Array Icon2.svg",Color.BLACK, 3);
case BINARY:
// return PamGlyphDude.createModuleGlyph(OctIcon.FILE_BINARY);
return PamGlyphDude.createModuleIcon("mdi2f-file-star-outline");

View File

@ -51,6 +51,7 @@ import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import javafx.stage.WindowEvent;
/**
@ -136,10 +137,10 @@ public class PamGuiManagerFX implements PAMControllerGUI, PamSettings {
private Scene scene;
private static PamGuiManagerFX instance;
public PamGuiManagerFX(PamController pamController, Object stage) {
this.pamController=pamController;
pamGuiSettings= new PAMGuiFXSettings();
@ -151,9 +152,18 @@ public class PamGuiManagerFX implements PAMControllerGUI, PamSettings {
start(primaryStage);
instance=this;
}
/**
* Get the instance of the PAMGuiManager
* @return the instance;
*/
public static PamGuiManagerFX getInstance() {
return instance;
}
@ -577,7 +587,6 @@ public class PamGuiManagerFX implements PAMControllerGUI, PamSettings {
public Stage getMainScene() {
// TODO Auto-generated method stub
return primaryStage;
}
@ -1022,6 +1031,10 @@ public class PamGuiManagerFX implements PAMControllerGUI, PamSettings {
}
public Window getPrimaryStage() {
return this.primaryStage;
}
}

View File

@ -114,6 +114,8 @@ public class PamFlipPane extends FlipPane {
this.flipToFront();
});
backButton.setStyle("-fx-background-radius: 0 5 5 0; -fx-border-radius: 0 5 5 0;");
//backButton.setPrefWidth(150);
PamBorderPane advPane = new PamBorderPane();

View File

@ -2,6 +2,7 @@ package pamViewFX.fxNodes.utilityPanes;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import PamController.PamController;
import PamController.SettingsPane;
@ -19,7 +20,7 @@ public class SettingsDialog<T> extends PamDialogFX<T>{
private SettingsPane<T> settingsPane;
public SettingsDialog(SettingsPane<T> settingsPane){
super(null, settingsPane.getName(), StageStyle.DECORATED);
super(PamGuiManagerFX.getInstance().getPrimaryStage() /*TODO - add stage*/, settingsPane.getName(), StageStyle.DECORATED);
this.setResizable(true);
this.settingsPane=settingsPane;
this.setContent(settingsPane.getContentNode());

View File

@ -28,7 +28,7 @@ public class GenericModelParams extends StandardModelParams implements Cloneable
ArrayList<DLTransfromParams> dlTransformParamsArr = new ArrayList<DLTransfromParams>();
//waveform transforms.
dlTransformParamsArr.add(new SimpleTransformParams(DLTransformType.DECIMATE, 96000.0));
dlTransformParamsArr.add(new SimpleTransformParams(DLTransformType.DECIMATE, 96000.0));
// dlTransformParamsArr.add(new SimpleTransformParams(DLTransformType.PREEMPHSIS, preemphases));
dlTransformParamsArr.add(new SimpleTransformParams(DLTransformType.SPECTROGRAM, 256, 100));
//in the python code they have an sfft of 129xN where N is the number of chunks. They then
@ -82,16 +82,62 @@ public class GenericModelParams extends StandardModelParams implements Cloneable
// }
return newParams;
}
@Override
public boolean equals(Object o) {
GenericModelParams params = (GenericModelParams) o;
//check the transforms are the same.
if (this.dlTransfromParams!=null && params.dlTransfromParams == null) {
return false;
}
if (params.dlTransfromParams!=null && this.dlTransfromParams == null) {
return false;
}
//iterate through the transofrms and check each one is equal.
if (this.dlTransfromParams!=null) {
if (this.dlTransfromParams.size()!=dlTransfromParams.size()) {
return false;
}
for (int i=0; i<this.dlTransfromParams.size();i++) {
if (!this.dlTransfromParams.get(i).equals(params.dlTransfromParams.get(i))) {
return false;
}
}
}
else {
//both transforms must be null and so can still be equal
}
// System.out.println("TRANSFORMS ARE EQUAL");
//check the rest.
boolean isEqual =
this.useDefaultSegLen == params.useDefaultSegLen &&
this.defaultSegmentLen.equals(params.defaultSegmentLen) &&
this.shape.equals(params.shape) &&
this.outputShape.equals(params.outputShape);
//Arrays.equals( this.classNames, params.classNames);
return isEqual;
}
@Override
public String toString() {
String info = super.toString();
info+= "------Model Info------\n";
info+= "Model Input Shape: ";
if (this.defaultShape!=null) {
if (this.shape!=null) {
for (int i=0; i<shape.length; i++) {
info+= " " + shape[i];
}
@ -102,6 +148,29 @@ public class GenericModelParams extends StandardModelParams implements Cloneable
}
info+= "Model Output Shape: ";
if (this.outputShape!=null) {
for (int i=0; i<outputShape.length; i++) {
info+= " " + outputShape[i];
}
info+= "\n";
}
else {
info+= "null\n";
}
info+= "Default Model Input Shape: ";
if (this.defaultShape!=null) {
for (int i=0; i<defaultShape.length; i++) {
info+= " " + defaultShape[i];
}
info+= "\n";
}
else {
info+= "null\n";
}
info+= "Default Model Output Shape: ";
if (this.defualtOuput!=null) {
for (int i=0; i<defualtOuput.length; i++) {
info+= " " + defualtOuput[i];

View File

@ -10,13 +10,18 @@ import java.util.ArrayList;
import org.jamdev.jdl4pam.transforms.DLTransform.DLTransformType;
import org.jamdev.jdl4pam.transforms.DLTransfromParams;
import org.jamdev.jdl4pam.transforms.SimpleTransformParams;
import org.jamdev.jdl4pam.transforms.jsonfile.DLTransformParser2;
import org.jamdev.jdl4pam.transforms.jsonfile.DLTransformsParser;
import org.json.JSONArray;
import org.json.JSONObject;
import PamUtils.PamArrayUtils;
import rawDeepLearningClassifier.dlClassification.DLClassName;
import rawDeepLearningClassifier.dlClassification.DLClassNameManager;
import ai.djl.ndarray.types.Shape;
/**
* Functions for saving and loading generic model metadata information. Note this
* does not load the model.
@ -43,23 +48,30 @@ public class GenericModelParser {
public static boolean writeGenericModelParams(File file, GenericModelParams params) {
try {
org.jamdev.jdl4pam.genericmodel.GenericModelParams paramsjpam = pgParams2JpamParams(params);
//this writes a new string - with the transforms in order. .
String jsOnObject = DLTransformsParser.writeJSONString(params.dlTransfromParams);
//wriote the JSON string using jdl4pam library.
JSONObject jsonObject = DLTransformParser2.writeJSONParams(paramsjpam);
//Now make a second JSON object with a load of the parameters that might be required by the model.
//'class_info': '{num_class : 2,name_class : noise,bat}', 'seg_size': '{size_ms : 4}'}
//set the class names.
JSONObject paramsObject = getJSonParamsObject(params);
String jsonString = paramsObject.toString().substring(0, paramsObject.toString().length()-1)
+ "," + jsOnObject.toString().substring(1, jsOnObject.toString().length()) ;
//2023/08/25 2.02.09a old format is now disabled
// //this writes a new string - with the transforms in order. .
// String jsOnObject = DLTransformsParser.writeJSONString(params.dlTransfromParams);
//
// //Now make a second JSON object with a load of the parameters that might be required by the model.
// //'class_info': '{num_class : 2,name_class : noise,bat}', 'seg_size': '{size_ms : 4}'}
//
// //set the class names.
// JSONObject paramsObject = getJSonParamsObject(params);
//
// String jsonString = paramsObject.toString().substring(0, paramsObject.toString().length()-1)
// + "," + jsOnObject.toString().substring(1, jsOnObject.toString().length()) ;
//
System.out.println(jsonString);
// System.out.println(jsonObject);
writeJSONToFile(file, jsonString, false);
writeJSONToFile(file, jsonObject.toString(), false);
return true;
}
@ -70,6 +82,82 @@ public class GenericModelParser {
return false;
}
/**
* Convert a generic params object from the jdl4pam library to a PAMGuard serializable params object.
* @param params - the jdl4pam params object.
* @param classNameManager - the class name manager for the PAMGuard params.
* @return PAMGuard equivalent params.
*/
private static GenericModelParams jpamParams2PGParmas(
org.jamdev.jdl4pam.genericmodel.GenericModelParams params, DLClassNameManager classNameManager) {
GenericModelParams genericParmas = new GenericModelParams();
genericParmas.shape = PamArrayUtils.primitive2Object(params.defaultInputShape.getShape());
genericParmas.outputShape = PamArrayUtils.primitive2Object(params.defaultOutputShape.getShape());
genericParmas.dlTransfromParams = params.dlTransforms;
genericParmas.defaultSegmentLen = params.segLen;
String[] classNames = params.classNames;
if (classNames!=null) {
genericParmas.numClasses = classNames.length;
if (classNameManager!=null) {
genericParmas.classNames = classNameManager.makeClassNames(classNames);
}
else {
genericParmas.classNames = new DLClassName[classNames.length];
for (int i=0; i<classNames.length; i++) {
genericParmas.classNames[i]=new DLClassName(classNames[i], (short) i);
}
}
}
return genericParmas;
}
private static org.jamdev.jdl4pam.genericmodel.GenericModelParams pgParams2JpamParams(GenericModelParams params) {
org.jamdev.jdl4pam.genericmodel.GenericModelParams jpamParams = new org.jamdev.jdl4pam.genericmodel.GenericModelParams();
jpamParams.classNames = dlClassNames2String(params.classNames);
jpamParams.dlTransforms = (ArrayList<DLTransfromParams>) params.dlTransfromParams;
if (params.shape!=null) {
jpamParams.defaultInputShape = new Shape(PamArrayUtils.object2Primitve(params.shape));
}
if (params.outputShape!=null) {
jpamParams.defaultOutputShape = new Shape(PamArrayUtils.object2Primitve(params.outputShape));
}
jpamParams.segLen = params.defaultSegmentLen;
return jpamParams;
}
private static String[] dlClassNames2String(DLClassName[] classNames) {
if (classNames==null) return null;
String[] classNamesS = new String[classNames.length];
int n =0;
for (DLClassName dlName : classNames) {
classNamesS[n] = dlName.className;
n++;
}
return classNamesS;
}
/**
* Write a JSON string to a JSON file.
* @param file - the file to write to.
@ -98,6 +186,7 @@ public class GenericModelParser {
* @param params - the parameters object.
* @return the JSONObject.
*/
@Deprecated
public static JSONObject getJSonParamsObject(GenericModelParams params) {
return getJSonParamsObject( params, new JSONObject());
}
@ -111,6 +200,7 @@ public class GenericModelParser {
* @param paramsobject - jsonObject to add params to.
* @return the JSONObject.
*/
@Deprecated
public static JSONObject getJSonParamsObject(GenericModelParams params, JSONObject paramsObject) {
//set the class names.
JSONObject classInfo = new JSONObject();
@ -175,18 +265,34 @@ public class GenericModelParser {
fileReader.close();
System.out.println(jsonData);
//DL transforms
ArrayList<DLTransfromParams> dlTransforms = DLTransformsParser.parseTransfromParams(jsonData);
//System.out.println("No. parsed transforms: " + dlTransforms.size());
//DL transforms
params.dlTransfromParams = dlTransforms;
//parse the data
params = parseJSOString(jsonData, params, classNameManager);
//Need to figure out if this is the new or old format.
JSONObject jsonObject = new JSONObject(jsonData);
boolean isParamsV2 =false;
//does the object have a version
if (jsonObject.has("version_info") ) {
JSONObject versionObject = jsonObject.getJSONObject("version_info");
//lots of JSON metadata might have a version number so to be absolutely sure...
if (versionObject.has("version")) {
isParamsV2=true;
}
}
if (isParamsV2) {
params = parseJSONObject( jsonObject, params,
classNameManager);
}
else {
params = parseJSONObject_legacy( jsonObject, params,
classNameManager);
}
return params;
} catch (FileNotFoundException e) {
@ -211,6 +317,49 @@ public class GenericModelParser {
return null;
}
/**
* Parse legacy JSON format.
* @param jsonObject - the JSONObject holding data
* @param paramsClone - parameters object to set fields to to set.
* @param classNameManager - the class names manager associated with the parameters.
* @return paramsClone with new settings.
*/
public static GenericModelParams parseJSONObject_legacy(JSONObject jsonObject, GenericModelParams paramsClone,
DLClassNameManager classNameManager) {
//DL transforms
ArrayList<DLTransfromParams> dlTransforms = DLTransformsParser.parseTransfromParams(jsonObject.toString());
//DL transforms
paramsClone.dlTransfromParams = dlTransforms;
parseJSONMetaData_legacy( jsonObject, paramsClone, classNameManager);
//System.out.println("No. parsed transforms: " + dlTransforms.size());
return paramsClone;
}
/**
* Parse JSON data containing transforms and model metadata.
* @param jsonObject - the JSONObject holding data
* @param paramsClone - parameters object to set fields to to set.
* @param classNameManager - the class names manager associated with the parameters.
* @return paramsClone with new settings.
*/
public static GenericModelParams parseJSONObject(JSONObject jsonObject, GenericModelParams paramsClone,
DLClassNameManager classNameManager) {
org.jamdev.jdl4pam.genericmodel.GenericModelParams params = DLTransformParser2.readJSONParams(jsonObject);
GenericModelParams pgParams = jpamParams2PGParmas(params, classNameManager);
return pgParams;
}
/**
@ -219,13 +368,9 @@ public class GenericModelParser {
* @param params - the parameters.
* @return the parameters class with new settings set.
*/
public static GenericModelParams parseJSOString(String jsonParamsString, GenericModelParams paramsClone,
public static GenericModelParams parseJSONMetaData_legacy(JSONObject jsonObject, GenericModelParams paramsClone,
DLClassNameManager classNameManager) {
JSONObject jsonObject = new JSONObject(jsonParamsString);
//the segment length information
System.out.println(jsonParamsString);
//System.out.println("SEG SIZE: " + jsonObject.getString(SEG_SIZE_STRING) + " " + jsonObject.isNull("size_ms"));

View File

@ -36,14 +36,14 @@ public class GenericModelWorker extends DLModelWorker<GenericPrediction> {
//System.out.println("RUN GENERIC MODEL: " + transformedDataStack[0][0][0]);
float[] results;
if (freqTransform)
results = genericModel.runModel2(transformedDataStack);
results = genericModel.runModel(transformedDataStack);
else {
//run a model if it is waveform info.
float[][] waveStack = new float[transformedDataStack.length][];
for (int i=0; i<waveStack.length; i++) {
waveStack[i] = transformedDataStack[i][0];
}
results = genericModel.runModel1(waveStack);
results = genericModel.runModel(waveStack);
}
//System.out.println("GENERIC MODEL RESULTS: " + results== null ? null : results.length);
return results;

View File

@ -1,20 +1,9 @@
package rawDeepLearningClassifier.dlClassification.genericModel;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.commons.io.FilenameUtils;
import org.jamdev.jdl4pam.genericmodel.SpectrogramTranslator;
import org.jamdev.jdl4pam.genericmodel.WaveformTranslator;
import org.jamdev.jdl4pam.genericmodel.GenericModel;
import ai.djl.MalformedModelException;
import ai.djl.Model;
import ai.djl.engine.Engine;
import ai.djl.inference.Predictor;
import ai.djl.ndarray.types.Shape;
import ai.djl.translate.TranslateException;
/**
@ -25,192 +14,11 @@ import ai.djl.translate.TranslateException;
* @author Jamie Macaulay
*
*/
public class PamGenericModel {
/**
* The currently loaded model
*/
private Model model;
/**
* The predictor for the model.
*/
Predictor<float[][][], float[]> specPredictor;
/**
* Predictor for the model for waveforms.
*/
Predictor<float[][], float[]> wavePredictor;
/**
* The input shape from the loaded model.
*/
private Shape inputShape = null;
/**
* The output shape from the model.
*/
private Shape outShape = null;
private SpectrogramTranslator specTranslator;
private WaveformTranslator waveTranslator;
public PamGenericModel(String modelPath) throws MalformedModelException, IOException{
//System.out.println("NEW GENERIC MODEL:");
File file = new File(modelPath);
//String modelPath = "/Users/au671271/Google Drive/Aarhus_research/PAMGuard_bats_2020/deep_learning/BAT/models/bats_denmark/BAT_4ms_256ft_8hop_128_NOISEAUG_40000_100000_-100_0_256000_JAMIE.pk";
Path modelDir = Paths.get(file.getAbsoluteFile().getParent()); //the directory of the file (in case the file is local this should also return absolute directory)
String modelName = file.getName();
String extension = FilenameUtils.getExtension(file.getAbsolutePath());
System.out.println("Generic Model: Available engines: " + Engine.getAllEngines());
Model model;
switch (extension) {
case "pb":
model = Model.newInstance(modelPath, "TensorFlow");
model.load(modelDir, modelName);
break;
case "py":
model = Model.newInstance(modelName);
model.load(modelDir, modelName);
break;
default:
//will try to load a model automatically - problematic but let's see.
model = Model.newInstance(modelPath);
break;
}
if (model == null) {
System.err.println("Generic Model: Could not load model: " + modelPath);
}
else {
if (model!=null && model.describeInput()!=null) {
System.out.println("Generic Model: Input: " + model.describeInput().toString());
inputShape = model.describeInput().get(0).getValue();
}
if (model!=null && model.describeOutput()!=null) {
System.out.println("Generic Model: Output: " + model.describeOutput().toString());
outShape = model.describeOutput().get(0).getValue();
}
this.model=model;
specTranslator = new SpectrogramTranslator(inputShape);
waveTranslator = new WaveformTranslator(model.describeInput());
//predictor for the model if using images as input
specPredictor = model.newPredictor(specTranslator);
//predictor for the model if using
wavePredictor = model.newPredictor(waveTranslator);
}
public class PamGenericModel extends GenericModel {
public PamGenericModel(String modelPath) throws MalformedModelException, IOException {
super(modelPath);
// TODO Auto-generated constructor stub
}
/**
* Get the predictor for spectrogram images.
* @return
*/
public Predictor<float[][][], float[]> getSpecPredictor() {
return specPredictor;
}
/***
* Get the predictor for the waveform input.
* @return the predictor for waveforms.
*/
public Predictor<float[][], float[]> getWavePredictor() {
return wavePredictor;
}
/**
* Get the model shape for the input.
* @return the input shape.
*/
public Shape getInputShape() {
return inputShape;
}
/**
* Set the input shape.
* @param inputShape - the input shape.
*/
public void setInputShape(Shape inputShape) {
this.inputShape = inputShape;
specTranslator.setShape(inputShape);
}
/**
* Get the output shape. The shape is null if the model does not specify shape.
* @return the output shape.
*/
public Shape getOutShape() {
return outShape;
}
/**
* Run the model on spectrogram images
* @param specImage - the spectrogram image [no. batches][image x][image y]
* @return the results
*/
public float[] runModel2(float[][][] specImage) {
try {
float[] results = specPredictor.predict(specImage);
//DLUtils.printArray(results);
return results;
} catch (TranslateException e) {
System.out.println("Error on model: ");
e.printStackTrace();
}
return null;
}
/**
* Run the model on a raw waveform data
* @param specImage - waveform data [no. batches][samples]
* @return the results
*/
public float[] runModel1(float[][] waveform) {
try {
float[] results = wavePredictor.predict(waveform);
//DLUtils.printArray(results);
return results;
} catch (TranslateException e) {
System.out.println("Error on model: ");
e.printStackTrace();
}
return null;
}
public Model getModel() {
return model;
}
public void setModel(Model model) {
this.model = model;
}
}

View File

@ -0,0 +1,59 @@
package test.java.rawDeepLearningClassifier;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.jupiter.api.Test;
import rawDeepLearningClassifier.dlClassification.genericModel.GenericModelParams;
import rawDeepLearningClassifier.dlClassification.genericModel.GenericModelParser;
/**
* Tests writing and reading JSON data from models.
* @author Jamie Macaulay
*
*/
class DLJSONParserTest {
@Test
void test() {
//load an old file
String relJSONpath = "./src/test/resources/rawDeepLearningClassifier/Generic/right_whale/legacy_format/right_whale_DL_settings.pdtf";
Path path = Paths.get(relJSONpath);
GenericModelParams genericParmas = new GenericModelParams();
genericParmas = GenericModelParser.readGenericModelParams(path.toFile(), genericParmas, null);
System.out.println("----------------- LEGACY ---------------");
System.out.println(genericParmas);
// write to a new file
relJSONpath = "./src/test/resources/rawDeepLearningClassifier/Generic/right_whale/right_whale_DL_settings.pdtf";
path = Paths.get(relJSONpath);
GenericModelParser.writeGenericModelParams(path.toFile(), genericParmas);
//open the new file
GenericModelParams genericParmas_new = GenericModelParser.readGenericModelParams(path.toFile(), genericParmas, null);
System.out.println("----------------- CURRENT ---------------");
System.out.println(genericParmas_new);
//now compare the paramters
assertEquals(genericParmas, genericParmas_new);
}
}

View File

@ -0,0 +1 @@
{"model_info":"{\"output_shape\":[-1,2],\"input_shape\":[-1,40,40,1]}","class_info":"{\"name_class\":\"Noise,Right Whale\",\"num_class\":2}","seg_size":"{\"size_ms\":2000}","load_audio":"{\"sr\":2000}","spectrogram":"{\"fft\":256,\"hop\":100}","freq_compression":"{\"bins\":40,\"fmin\":47,\"fmax\":357}","norm_row_sum":"{}"}

View File

@ -0,0 +1 @@
{"framework_info":{"framework":"Bespoke"},"model_info":{"output_shape":[-1,2],"input_shape":[-1,40,40,1]},"class_info":{"name_class":["Noise","Right Whale"],"num_class":2},"transforms":[{"name":"norm_row_sum","params":{}},{"name":"spectrogram","params":{"fft":256,"hop":100}},{"name":"load_audio","params":{"sr":2000}},{"name":"freq_compression","params":{"bins":40,"fmin":47,"fmax":357}}],"description":"Metadata for acoustic deep learning","version_info":{"version":1},"seg_size":{"size_ms":2000}}