From e8fc75dc9e4a9f204b5838300cdda5846a4549f1 Mon Sep 17 00:00:00 2001 From: Jamie Mac Date: Mon, 9 Oct 2023 14:56:12 +0100 Subject: [PATCH] Updates to FX GUI --- .classpath | 2 +- pom.xml | 4 +- .../layoutFX/CheckWavHeadersPane.java | 7 +- src/Array/ArrayManager.java | 8 +- .../HydrophoneImport.java | 250 ++++++++++++------ src/Array/layoutFX/HydrophoneProperty.java | 33 ++- .../layoutFX/HydrophoneSettingsPane.java | 117 +++++--- src/Array/layoutFX/HydrophonesPane.java | 55 ++-- src/Array/layoutFX/InterpSettingsPane.java | 7 + src/Array/layoutFX/StreamerPane.java | 85 ++++-- src/PamController/PamController.java | 13 +- src/PamUtils/PamArrayUtils.java | 62 +++++ src/PamView/importData/DataImport.java | 85 ++++-- src/PamView/importData/ImportDataSystem.java | 2 +- src/Resources/modules/Array Icon2.svg | 21 ++ .../layoutFX/ClickSettingsPane.java | 4 +- .../connectionNodes/ModuleIconFactory.java | 4 +- src/pamViewFX/PamGuiManagerFX.java | 17 +- .../fxNodes/flipPane/PamFlipPane.java | 2 + .../fxNodes/utilityPanes/SettingsDialog.java | 3 +- .../genericModel/GenericModelParams.java | 77 +++++- .../genericModel/GenericModelParser.java | 199 ++++++++++++-- .../genericModel/GenericModelWorker.java | 4 +- .../genericModel/PamGenericModel.java | 202 +------------- .../DLJSONParserTest.java | 59 +++++ .../right_whale_DL_settings.pdtf | 1 + .../right_whale/right_whale_DL_settings.pdtf | 1 + 27 files changed, 888 insertions(+), 436 deletions(-) create mode 100644 src/Resources/modules/Array Icon2.svg create mode 100644 src/test/java/rawDeepLearningClassifier/DLJSONParserTest.java create mode 100644 src/test/resources/rawDeepLearningClassifier/Generic/right_whale/legacy_format/right_whale_DL_settings.pdtf create mode 100644 src/test/resources/rawDeepLearningClassifier/Generic/right_whale/right_whale_DL_settings.pdtf diff --git a/.classpath b/.classpath index ba93b2e0..a5d40376 100644 --- a/.classpath +++ b/.classpath @@ -6,7 +6,7 @@ - + diff --git a/pom.xml b/pom.xml index 4c5b4ea7..52e9c9d5 100644 --- a/pom.xml +++ b/pom.xml @@ -15,8 +15,8 @@ - 16 - 11 + 17 + 17 11 diff --git a/src/Acquisition/layoutFX/CheckWavHeadersPane.java b/src/Acquisition/layoutFX/CheckWavHeadersPane.java index c97cd6d4..15e1785d 100644 --- a/src/Acquisition/layoutFX/CheckWavHeadersPane.java +++ b/src/Acquisition/layoutFX/CheckWavHeadersPane.java @@ -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); diff --git a/src/Array/ArrayManager.java b/src/Array/ArrayManager.java index 2de2069c..e77c6a22 100644 --- a/src/Array/ArrayManager.java +++ b/src/Array/ArrayManager.java @@ -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> hydrophoneImportManager; + private ImportDataSystem hydrophoneImportManager; private ImportDataSystem> 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>(new HydrophoneImport(hydrophonesProcess.getHydrophoneDataBlock())); + hydrophoneImportManager= new ImportDataSystem(new HydrophoneImport(hydrophonesProcess.getHydrophoneDataBlock())); hydrophoneImportManager.setName("Hydrophone Data Import"); streamerImportManager = new ImportDataSystem>(new StreamerImport(hydrophonesProcess.getStreamerDataBlock())); streamerImportManager.setName("Streamer Data Import"); diff --git a/src/Array/importHydrophoneData/HydrophoneImport.java b/src/Array/importHydrophoneData/HydrophoneImport.java index 93a924be..1d634d39 100644 --- a/src/Array/importHydrophoneData/HydrophoneImport.java +++ b/src/Array/importHydrophoneData/HydrophoneImport.java @@ -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>{ - - String[] extensionStrings={".csv"}; +public class HydrophoneImport extends DataImport{ + + String[] extensionStrings={".csv", ".mat"}; private ArrayList> 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>{ * */ 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>{ @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>{ if ((hydrophonePositions.get(0).size()-1)%6==0){ return convertToHydrophoneList(hydrophonePositions); } - + } } - + if (filePath.endsWith(".mat")){ - - hydrophonePositions=importPositionsFromMatlab(filePath); - + + ArrayList 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> convertToHydrophoneList(ArrayList> importData){ - - ArrayList> hydrophonesAll=new ArrayList>(); + public ArrayList convertToHydrophoneList(ArrayList> importData){ + + ArrayList hydrophonesAll=new ArrayList(); ArrayList tempArray; Hydrophone hydrophone; double[] cOordinates; double [] cOordinateErrors; + double sensitivity; + double gain; for (int i=0; i(); 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> importPositionsFromMatlab( + + /** + * Import the hydrophone positions from a MATLAB mat file. + * @param filePath - the file path. + * @return an array of hydrophones. + */ + private static ArrayList importPositionsFromMatlab( String filePath) { - // TODO- needs to be implemented. + + try { + + ArrayList hydrophones = new ArrayList(); + 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>{ } @Override - public boolean isDataFormatOK(ArrayList 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>{ * 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 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 data = importPositionsFromMatlab(file); + + System.out.println("Impotred data size: " + data.size()); + System.out.println(data.get(0)); + + } + } diff --git a/src/Array/layoutFX/HydrophoneProperty.java b/src/Array/layoutFX/HydrophoneProperty.java index 75b5780e..15dff55b 100644 --- a/src/Array/layoutFX/HydrophoneProperty.java +++ b/src/Array/layoutFX/HydrophoneProperty.java @@ -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; + } + } diff --git a/src/Array/layoutFX/HydrophoneSettingsPane.java b/src/Array/layoutFX/HydrophoneSettingsPane.java index 6a95223f..8d7bf27d 100644 --- a/src/Array/layoutFX/HydrophoneSettingsPane.java +++ b/src/Array/layoutFX/HydrophoneSettingsPane.java @@ -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 { + private static final double COLUMN_0_WIDTH = 100; + /** * * Check inputs in real time @@ -89,7 +93,7 @@ public class HydrophoneSettingsPane extends SettingsPane { /** * The main holder pane. */ - private PamVBox mainPane; + private PamBorderPane mainPane; private InterpSettingsPane interpPane; @@ -99,8 +103,8 @@ public class HydrophoneSettingsPane extends SettingsPane { 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 { 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 { 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 { 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(); 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(); for (int i=0; i { gridy++; mainControls.add(recieverSensLabel = new Label(""), 0, gridy); - recieverSensLabel.setAlignment(Pos.CENTER_RIGHT); + recieverSensLabel.setAlignment(Pos.CENTER_LEFT); hSens = new PamSpinner(-Double.MAX_VALUE, Double.MAX_VALUE, -200., 1.); hSens.setEditable(true); @@ -269,7 +277,7 @@ public class HydrophoneSettingsPane extends SettingsPane { 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.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 { 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 { /** * 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 { PamGridPane positionPane = new PamGridPane(); positionPane.setHgap(5); positionPane.setVgap(5); + double maxWidth =10; @@ -326,7 +340,7 @@ public class HydrophoneSettingsPane extends SettingsPane { 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 { 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 { // 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.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"); diff --git a/src/Array/layoutFX/HydrophonesPane.java b/src/Array/layoutFX/HydrophonesPane.java index 83b2bb42..e29ae2f3 100644 --- a/src/Array/layoutFX/HydrophonesPane.java +++ b/src/Array/layoutFX/HydrophonesPane.java @@ -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 hydrophoneData) { super(hydrophoneData); + //need to set up all the rows. - TableColumn streamerID = new TableColumn("ID"); - streamerID.setCellValueFactory(cellData -> cellData.getValue().getID()); - streamerID.setEditable(false); + TableColumn hydroID = new TableColumn("ID"); + hydroID.setCellValueFactory(cellData -> cellData.getValue().getID()); + hydroID.setEditable(false); - TableColumn x = new TableColumn("x (m)"); + TableColumn x = new TableColumn("x"); x.setCellValueFactory(cellData -> cellData.getValue().getX()); x.setEditable(false); - TableColumn y = new TableColumn("y (m)"); + TableColumn y = new TableColumn("y"); y.setCellValueFactory(cellData -> cellData.getValue().getY()); y.setEditable(false); - TableColumn z = new TableColumn("depth (m)"); + TableColumn z = new TableColumn("depth"); z.setCellValueFactory(cellData -> cellData.getValue().getZ()); z.setEditable(false); - TableColumn xErr = new TableColumn("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 yErr = new TableColumn("y error (m)"); - y.setCellValueFactory(cellData -> cellData.getValue().getY()); - y.setEditable(false); + TableColumn xErr = new TableColumn("x"); + xErr.setCellValueFactory(cellData -> cellData.getValue().getXErr()); + xErr.setEditable(false); - TableColumn zErr = new TableColumn("z error (m)"); - z.setCellValueFactory(cellData -> cellData.getValue().getZ()); - z.setEditable(false); + TableColumn yErr = new TableColumn("y"); + yErr.setCellValueFactory(cellData -> cellData.getValue().getYErr()); + yErr.setEditable(false); + + TableColumn zErr = new TableColumn("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())); } diff --git a/src/Array/layoutFX/InterpSettingsPane.java b/src/Array/layoutFX/InterpSettingsPane.java index 09896a35..cbe59282 100644 --- a/src/Array/layoutFX/InterpSettingsPane.java +++ b/src/Array/layoutFX/InterpSettingsPane.java @@ -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 interpBox; public InterpSettingsPane() { + PamGridPane gridPane = new PamGridPane(); gridPane.setVgap(5); diff --git a/src/Array/layoutFX/StreamerPane.java b/src/Array/layoutFX/StreamerPane.java index 5ced493f..588fe5c4 100644 --- a/src/Array/layoutFX/StreamerPane.java +++ b/src/Array/layoutFX/StreamerPane.java @@ -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 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 streamerID = new TableColumn("ID"); streamerID.setCellValueFactory(cellData -> cellData.getValue().getID()); streamerID.setEditable(false); - + TableColumn name = new TableColumn("Name"); name.setCellValueFactory(cellData -> cellData.getValue().getName()); name.setEditable(false); - - + + TableColumn x = new TableColumn("x (m)"); x.setCellValueFactory(cellData -> cellData.getValue().getX()); x.setEditable(false); - + TableColumn y = new TableColumn("y (m)"); y.setCellValueFactory(cellData -> cellData.getValue().getY()); y.setEditable(false); - + TableColumn z = new TableColumn("z (m)"); z.setCellValueFactory(cellData -> cellData.getValue().getZ()); z.setEditable(false); - + TableColumn reference = new TableColumn("Reference"); reference.setCellValueFactory(cellData -> cellData.getValue().getHydrophineLocator()); reference.setEditable(true); - + TableColumn locator = new TableColumn("Locator"); locator.setCellValueFactory(cellData -> cellData.getValue().getHydrophineLocator()); locator.setEditable(true); @@ -87,14 +130,14 @@ public class StreamerPane extends PamBorderPane { @Override public Dialog 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; } diff --git a/src/PamController/PamController.java b/src/PamController/PamController.java index 444bb19a..29b102fa 100644 --- a/src/PamController/PamController.java +++ b/src/PamController/PamController.java @@ -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 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); } diff --git a/src/PamUtils/PamArrayUtils.java b/src/PamUtils/PamArrayUtils.java index da293f30..3fa34a5f 100644 --- a/src/PamUtils/PamArrayUtils.java +++ b/src/PamUtils/PamArrayUtils.java @@ -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 - * First getExtensionsStrings() defines which file types can be selected for import. + * First getExtensionsStrings() defines which file types can be selected for + * import. *

- * 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. *

- * 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 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 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 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 such that + * T=String; *

- * 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. *

* * @author Jamie Macaulay * - * @param - the data type loaded from a file. This could be a String, ArrayList, ArrayList> etc. + * @param - the data type loaded from a file. This could be a String, + * ArrayList, ArrayList> etc. */ -public abstract class DataImport { +public abstract class DataImport { - public abstract ArrayList 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 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"; } diff --git a/src/PamView/importData/ImportDataSystem.java b/src/PamView/importData/ImportDataSystem.java index 8f166883..820dbfa9 100644 --- a/src/PamView/importData/ImportDataSystem.java +++ b/src/PamView/importData/ImportDataSystem.java @@ -288,7 +288,7 @@ public class ImportDataSystem { } public void setSaveProgress(int prog){ - System.out.println("prog "+prog); + //System.out.println("prog "+prog); setProgress(prog); } diff --git a/src/Resources/modules/Array Icon2.svg b/src/Resources/modules/Array Icon2.svg new file mode 100644 index 00000000..2ca3e501 --- /dev/null +++ b/src/Resources/modules/Array Icon2.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/clickDetector/layoutFX/ClickSettingsPane.java b/src/clickDetector/layoutFX/ClickSettingsPane.java index a62f3be0..131021d9 100644 --- a/src/clickDetector/layoutFX/ClickSettingsPane.java +++ b/src/clickDetector/layoutFX/ClickSettingsPane.java @@ -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{ /** * 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{ //trigger pane triggerFilter=new FilterPaneFX(Orientation.VERTICAL); pamTabbedPane.getTabs().add(new Tab("Trigger Filter", triggerFilter.getContentNode())); + // //echo detection pane. // echoDetection= new ClickEchoPane(clickControl); diff --git a/src/dataModelFX/connectionNodes/ModuleIconFactory.java b/src/dataModelFX/connectionNodes/ModuleIconFactory.java index 7ca0f765..50bcf046 100644 --- a/src/dataModelFX/connectionNodes/ModuleIconFactory.java +++ b/src/dataModelFX/connectionNodes/ModuleIconFactory.java @@ -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"); diff --git a/src/pamViewFX/PamGuiManagerFX.java b/src/pamViewFX/PamGuiManagerFX.java index f3de8029..3de57c40 100644 --- a/src/pamViewFX/PamGuiManagerFX.java +++ b/src/pamViewFX/PamGuiManagerFX.java @@ -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; + } + } diff --git a/src/pamViewFX/fxNodes/flipPane/PamFlipPane.java b/src/pamViewFX/fxNodes/flipPane/PamFlipPane.java index 78c1bb4b..508f4c6b 100644 --- a/src/pamViewFX/fxNodes/flipPane/PamFlipPane.java +++ b/src/pamViewFX/fxNodes/flipPane/PamFlipPane.java @@ -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(); diff --git a/src/pamViewFX/fxNodes/utilityPanes/SettingsDialog.java b/src/pamViewFX/fxNodes/utilityPanes/SettingsDialog.java index 7b8b88ca..eee2c9e5 100644 --- a/src/pamViewFX/fxNodes/utilityPanes/SettingsDialog.java +++ b/src/pamViewFX/fxNodes/utilityPanes/SettingsDialog.java @@ -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 extends PamDialogFX{ private SettingsPane settingsPane; public SettingsDialog(SettingsPane 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()); diff --git a/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelParams.java b/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelParams.java index ff15ebf0..74df33bb 100644 --- a/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelParams.java +++ b/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelParams.java @@ -28,7 +28,7 @@ public class GenericModelParams extends StandardModelParams implements Cloneable ArrayList dlTransformParamsArr = new ArrayList(); //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) 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 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 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")); diff --git a/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelWorker.java b/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelWorker.java index cbf2c410..8f9caec8 100644 --- a/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelWorker.java +++ b/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelWorker.java @@ -36,14 +36,14 @@ public class GenericModelWorker extends DLModelWorker { //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 specPredictor; - - - /** - * Predictor for the model for waveforms. - */ - Predictor 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 getSpecPredictor() { - return specPredictor; - } - - /*** - * Get the predictor for the waveform input. - * @return the predictor for waveforms. - */ - public Predictor 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; - } - - - - - } diff --git a/src/test/java/rawDeepLearningClassifier/DLJSONParserTest.java b/src/test/java/rawDeepLearningClassifier/DLJSONParserTest.java new file mode 100644 index 00000000..df8b4e89 --- /dev/null +++ b/src/test/java/rawDeepLearningClassifier/DLJSONParserTest.java @@ -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); + + + + } + +} diff --git a/src/test/resources/rawDeepLearningClassifier/Generic/right_whale/legacy_format/right_whale_DL_settings.pdtf b/src/test/resources/rawDeepLearningClassifier/Generic/right_whale/legacy_format/right_whale_DL_settings.pdtf new file mode 100644 index 00000000..d8858a7f --- /dev/null +++ b/src/test/resources/rawDeepLearningClassifier/Generic/right_whale/legacy_format/right_whale_DL_settings.pdtf @@ -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":"{}"} \ No newline at end of file diff --git a/src/test/resources/rawDeepLearningClassifier/Generic/right_whale/right_whale_DL_settings.pdtf b/src/test/resources/rawDeepLearningClassifier/Generic/right_whale/right_whale_DL_settings.pdtf new file mode 100644 index 00000000..551d3b4b --- /dev/null +++ b/src/test/resources/rawDeepLearningClassifier/Generic/right_whale/right_whale_DL_settings.pdtf @@ -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}} \ No newline at end of file