+name="_Version_2.02.10_January">Version
+2.02.11 April 2024
+
+
+
+
New Features
+
+
Click detector: Remembers locations of displays and doesnt
+continually reset them.
+
+
Help for Matched Click Classifier
+
+
Bug Fixes
+
+
Linking clicks to offline clicks table. We had a database
+that had become corrupted so added code to relink offline clicks to their corresponding
+clicks from binary data.
+
+
Drawing non-acoustic data: Data that were not associated
+with any hydrophones, e.g. visual sightings in Logger forms were not drawing on
+the map. This fixed and PAMGuard will use the vessels GPS position as
+reference.
+
+
Lookup tables: fix feature which was causing table entries
+to repeat.
Group Detection starts and ends: Check data integrity
+function fixed and now inserts correct times of start and ends of events into
+database.
+
+
Version 2.02.10 January 2024
New Features
Importing modules from other configurations: New options from file menu allowing
-import of specific modules, or module settings from other configurations. E.g.
-if you had three similar configurations and had set one of them up with a new
+lang=EN-US> from other configurations: New options from file menu allowing import
+of specific modules, or module settings from other configurations. E.g. if you
+had three similar configurations and had set one of them up with a new
detector, or got the click classifier settings set up just right in one of
those configurations, you can import the additional modules or the click
detector settings easily into the other configurations.
@@ -496,9 +532,9 @@ correctly saving updated bearings to the database. Now fixed.
ROCCA Classifier fixes
-
Allow Rocca to run without classifiers:
-Fixed bug that threw an error if no classifier files were specified in
-Rocca Params dialog
+
Allow Rocca to run without classifiers: Fixed
+bug that threw an error if no classifier files were specified in Rocca
+Params dialog
Fix memory issue with
RoccaContourDataBlocks not being released for garbage collection
@@ -596,9 +632,9 @@ angle offsets applied to static hydrophones in viewer mode. This is now fixed. <
Click tool bar: Correctly shows event
selection options even if no species classification options are in place.
-
Fixed Landmarks: Earlier versions were losing
-these every time PAMGuard started or new data were loaded in viewer mode. Now
-fixed.
+
Fixed Landmarks: Earlier versions were
+losing these every time PAMGuard started or new data were loaded in viewer
+mode. Now fixed.
ROCCA: Fixed (another) memory leak which
caused PAMGuard to crash when processing large data sets with the ROCCA
@@ -767,8 +803,9 @@ the TF FX display to crash if no data were displayed.
See major release notes for V 2.02.01
below.
-
Bug 495: TD FX display throws NullPointerException
-if user has removed all data units and then moves mouse over display area.
+
Bug 495: TD FX display throws
+NullPointerException if user has removed all data units and then moves mouse
+over display area.
Version 2.02.01
October 2021
@@ -791,11 +828,11 @@ font-family:"Times New Roman",serif'>
File Format Change
-
Changes have been made to the binary file format to support the
-output of additional noise outputs for certain detectors (See below). Binary
-files created with this version will not be compatible with earlier versions
-2.01.### and below. This version will read and may convert earlier format
-binary files.
+
Changes have been made to the binary file format to support
+the output of additional noise outputs for certain detectors (See below).
+Binary files created with this version will not be compatible with earlier
+versions 2.01.### and below. This version will read and may convert earlier
+format binary files.
@@ -1181,10 +1218,10 @@ lang=EN-US> Add functionality for bluetooth headsets.
2. Add user-facing option to adjust the startup delay for the
-time-correction (Global Time module). This provides a workaround to speed up
-analysis of thousands of wav files (i.e. by setting startup delay to 0 instead
-of default value of 2000 ms).
+lang=EN-US> Add user-facing option to adjust the startup delay for the time-correction
+(Global Time module). This provides a workaround to speed up analysis of
+thousands of wav files (i.e. by setting startup delay to 0 instead of default
+value of 2000 ms).
3.
2.
-Java 12 is better at handling Windows scaling issues on high-DPI displays.
-Beyond that, users should not notice much of a difference between this version
-and previous beta releases.
+Java 12 is better at handling Windows scaling issues on high-DPI displays. Beyond
+that, users should not notice much of a difference between this version and
+previous beta releases.
@@ -1706,8 +1743,8 @@ with installation and use of this version.
1.
-Bug 338. Problem displaying coastlines and bathymetric contours around the
-dateline (+/- 180 longitude) in the map.
+Bug 338. Problem displaying coastlines and bathymetric contours around
+the dateline (+/- 180 longitude) in the map.
2.
@@ -2218,8 +2255,8 @@ UID
If old data are opened with the PAMGuard
viewer they will automatically be converted. For safety, the original binary
files will not be overwritten and the new data will be placed in a new folder
-on your computer with the same path as the old data, but suffixed with _WithUID,
-e.g. if your binary data were previously stored in the folder
+on your computer with the same path as the old data, but suffixed with
+_WithUID, e.g. if your binary data were previously stored in the folder
C:\MySurvey\binarydata the new data will be written to
C:\MySurvey\binarydata_WithUID.
@@ -2295,8 +2332,8 @@ Hawaii/Temperate Pacific/North Atlantic datasets. This has been corrected.
2.
-Bug 320. Pamguard stopped reading Click Detector Event data from database
-when target motion analysis information was encountered. Corrected.
+Bug 320. Pamguard stopped reading Click Detector Event data from
+database when target motion analysis information was encountered. Corrected.
3.
@@ -2578,9 +2615,9 @@ main click detector display.
Target Motion Analysis
-
A major piece of work has been undertaken
-to improve the Target Motion tracking with PAMGuard. Details are available in
-the online help. Users of the Click Detector will notice the following changes:
+
A major piece of work has been undertaken to
+improve the Target Motion tracking with PAMGuard. Details are available in the
+online help. Users of the Click Detector will notice the following changes:
1.
@@ -2752,8 +2789,8 @@ being imported into the new database. Problem 2 was that indexing of imported
click events in the new database was incorrect. Both these issues have now been
fixed.
-
Version 1.15.02 March
-2016
+
Version 1.15.02
+March 2016
A number of small bug fixes following release of 1.15.00.
@@ -2905,13 +2942,13 @@ for details.
3.
-GPS Loading into PAMGuard Viewer. This has been modified
-so that the rules governing GPS data collection and storage also apply when
-loading data from the database. For instance, if you've stored all GPS data,
-you've probably got a record every second in the database which can create
-memory overflows if you try to load a lot of data in the viewer. You can now
-tell PAMGuard to only load a data point every n seconds which will reduce the
-number of points loaded. Useful when making large scale overview maps of a
+GPS Loading into PAMGuard Viewer. This has been
+modified so that the rules governing GPS data collection and storage also apply
+when loading data from the database. For instance, if you've stored all GPS
+data, you've probably got a record every second in the database which can
+create memory overflows if you try to load a lot of data in the viewer. You can
+now tell PAMGuard to only load a data point every n seconds which will reduce
+the number of points loaded. Useful when making large scale overview maps of a
survey.
4.9.
-Bug 239. Fixed bug in the DIFAR module that was
-incorrectly preventing cross-fixes for some calls.
+Bug 239. Fixed bug in the DIFAR module that was incorrectly
+preventing cross-fixes for some calls.
This module, developed by Douglas Gillespie, measures noise levels
-in a single frequency band using a variety of filter functions. See online help
-for details.
+
This module, developed by Douglas Gillespie, measures noise
+levels in a single frequency band using a variety of filter functions. See
+online help for details.
@@ -3340,10 +3378,11 @@ different. Details are available in the online help.
FLAC File Support
Can now read raw audio data direct from FLAC files. FLAC is a lossless compression algorithm
-for audio data. Files, or folders of files are accessed in the same way as WAV
-and AIFF files in the Sound Acquisition module. In a future release we also
-hope to provide support for writing FLAC files from the sound recorder module.
+href="http://en.wikipedia.org/wiki/FLAC">FLAC is a lossless compression
+algorithm for audio data. Files, or folders of files are accessed in the same
+way as WAV and AIFF files in the Sound Acquisition module. In a future release
+we also hope to provide support for writing FLAC files from the sound recorder
+module.
Sound Recorder Module
@@ -3476,9 +3515,9 @@ to these menus to provide additional information to users.
Radar Display
-
Functionality has been added to
-the radar display so that bearings can be shown relative to either the vessel
-or to true North.
+
Functionality has been added to the
+radar display so that bearings can be shown relative to either the vessel or to
+true North.
Better control of data in viewer
mode, making is easy to scroll through and view data for short time periods.
@@ -4116,8 +4155,8 @@ Symbol'>''
-This results in a major speed up of data exchange between modules and can
-lead to a x4 improvement in overall performance.
+This results in a major speed up of data exchange between modules and
+can lead to a x4 improvement in overall performance.
'
@@ -4230,9 +4269,9 @@ Symbol'>''
-Channel lists in output data streams of Decimator and other modules fixed,
-so that when channel numbers change, downstream modules configurations get the
-correct list of available channels.
+Channel lists in output data streams of Decimator and other modules
+fixed, so that when channel numbers change, downstream modules configurations
+get the correct list of available channels.
'
@@ -4263,11 +4302,11 @@ Symbol'>''
-New menu functionality by right clicking on any of the tabs of the main
-tab control will allow the user to copy the tab contents to the system
-clipboard from where it can be copied into other programs (e.g. Word,
-Powerpoint, etc.).Some modules, such as the map, have this implemented in other
-menus (right click) and also allow printing.
+New menu functionality by right clicking on any of the tabs of the main tab
+control will allow the user to copy the tab contents to the system clipboard
+from where it can be copied into other programs (e.g. Word, Powerpoint,
+etc.).Some modules, such as the map, have this implemented in other menus
+(right click) and also allow printing.
'
@@ -4335,8 +4374,8 @@ online help.
PAMGUARD Mixed Mode operation
-
Analyses data from wav or AIF file and synchronises it with
-GPS data reloaded from a database so that detected sounds may be correctly
+
Analyses data from wav or AIF file and synchronises it with GPS
+data reloaded from a database so that detected sounds may be correctly
localised. Multiple display frames - enables PAMGUARD GUI to be split into
multiple display windows, displayed on multiple monitors if desired. Enables
the operator to simultaneously view the map and the click detector for example,
@@ -4855,8 +4894,8 @@ Symbol'>'1.0Beta 22 Jan 2008 - Pamguard
-starts two releases, core and beta release,
+class=Heading2Char>1.0Beta 22 Jan 2008 -
+Pamguard starts two releases, core and beta release,
this is the beta release
diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml
index 73fb08dd..e135ce29 100644
--- a/dependency-reduced-pom.xml
+++ b/dependency-reduced-pom.xml
@@ -3,16 +3,17 @@
4.0.0org.pamguardPamguard
- Pamguard Java12+
- 2.02.10b
- Pamguard for Java 12+, using Maven to control dependcies
+ Pamguard
+ 2.02.11d
+ Pamguard using Maven to control dependencieswww.pamguard.orgSea Mammal Research Unit, University of St. Andrewshttp://www.smru.st-andrews.ac.uk
- src
+ ${basedir}/src
+ ${basedir}/src/testsrc
@@ -54,7 +55,7 @@
maven-compiler-plugin
- 3.8.1
+ 3.12.1org.eclipse.tycho
@@ -63,22 +64,14 @@
- 11
+ 21jdt
-
- .settings/org.eclipse.jdt.core.prefs
- org.openjfxjavafx-maven-plugin
- 0.0.6
-
-
- 17
- 17
-
+ 0.0.8maven-shade-plugin
@@ -165,11 +158,8 @@
https://artifacts.unidata.ucar.edu/repository/unidata-all/
-
- false
- bedatadriven
- bedatadriven_renjin
+ bedatadriven public repohttps://nexus.bedatadriven.com/content/groups/public/
@@ -198,7 +188,7 @@
1111UTF-8
- 16
+ 212.4.0-b180830.04382.4.0-b180830.04382.4.0-b180830.0359
diff --git a/nullPamguardSettings_20171106_185953.psfx b/nullPamguardSettings_20171106_185953.psfx
new file mode 100644
index 00000000..b2e2bed1
Binary files /dev/null and b/nullPamguardSettings_20171106_185953.psfx differ
diff --git a/nullPamguardSettings_20240401_141954.psfx b/nullPamguardSettings_20240401_141954.psfx
new file mode 100644
index 00000000..4896ca9b
Binary files /dev/null and b/nullPamguardSettings_20240401_141954.psfx differ
diff --git a/nullPamguardSettings_20240401_143317.psfx b/nullPamguardSettings_20240401_143317.psfx
new file mode 100644
index 00000000..a77426c4
Binary files /dev/null and b/nullPamguardSettings_20240401_143317.psfx differ
diff --git a/pom.xml b/pom.xml
index bbb2fbe6..dd3572a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,13 +1,12 @@
-
4.0.0org.pamguardPamguard
- 2.02.10ad
- Pamguard Java12+
- Pamguard for Java 12+, using Maven to control dependcies
+ 2.02.11d
+ Pamguard
+ Pamguard using Maven to control dependencieswww.pamguard.orgSea Mammal Research Unit, University of St. Andrews
@@ -15,80 +14,73 @@
-
- 16
- 11
- 11
- UTF-8
- 2.4.0-b180830.0438
+
+ UTF-8
+ 21
+ 11
+ 11
+
+ 2.4.0-b180830.04382.4.0-b180830.03592.4.0-b180830.0438
-
-
-
- src
-
-
- src
-
- META-INF/*.SF,META-INF/*.DSA,META-INF/*.RSA
- **/*.java
- jars/*.*
-
-
-
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.1
-
-
-
- 11
- jdt
-
- .settings/org.eclipse.jdt.core.prefs
-
-
-
-
-
-
- org.eclipse.tycho
- tycho-compiler-jdt
- 1.5.1
-
-
-
-
-
-
- org.openjfx
- javafx-maven-plugin
- 0.0.6
-
-
- 17
- 17
-
-
+
+
+
+ ${basedir}/src
+ ${basedir}/src/test
+
+
+ src
+
+ META-INF/*.SF,META-INF/*.DSA,META-INF/*.RSA
+ **/*.java
+ jars/*.*
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.12.1
+
+
+ 21
+ jdt
+
+
+
+
+ org.eclipse.tycho
+ tycho-compiler-jdt
+ 1.5.1
+
+
+
+
+
+
+ org.openjfx
+ javafx-maven-plugin
+ 0.0.8
+
+
@@ -135,114 +127,114 @@
-
+
+
-
- com.github.marschall
- jdeps-maven-plugin
- 0.5.1
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
- 3.1.1
-
-
- copy-dependencies
- package
-
- copy-dependencies
-
-
- ${project.build.directory}/tempDependencies
- false
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- org.eclipse.m2e
- lifecycle-mapping
- 1.0.0
-
-
-
-
-
-
- org.apache.maven.plugins
-
-
- maven-dependency-plugin
-
-
- [3.1.1,)
-
-
-
- purge-local-repository
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- com.github.marschall
- jdeps-maven-plugin
- 0.5.1
-
-
-
-
-
-
-
-
+ this site for details: https://maven.apache.org/plugins/maven-jdeps-plugin/index.html -->
+
+ com.github.marschall
+ jdeps-maven-plugin
+ 0.5.1
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.1.1
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/tempDependencies
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.eclipse.m2e
+ lifecycle-mapping
+ 1.0.0
+
+
+
+
+
+
+ org.apache.maven.plugins
+
+
+ maven-dependency-plugin
+
+
+ [3.1.1,)
+
+
+
+ purge-local-repository
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.github.marschall
+ jdeps-maven-plugin
+ 0.5.1
+
+
+
+
+
+
+
@@ -256,35 +248,18 @@
file://${project.basedir}/repo
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- false
-
- unidata-all
- Unidata netCDF
- https://artifacts.unidata.ucar.edu/repository/unidata-all/
-
-
-
+
+
+ false
+
+ unidata-all
+ Unidata netCDF
+ https://artifacts.unidata.ucar.edu/repository/unidata-all/
+
+
+
-
-
-
-
- false
-
- bedatadriven
- bedatadriven_renjin
- https://nexus.bedatadriven.com/content/groups/public/
-
-
-
-
- false
-
- talan
- talan
- https://nexus.talanlabs.com/content/repositories/releases/
-
-
-
- central
- https://repo1.maven.org/maven2
-
-
-
+
+
+
+ bedatadriven
+ bedatadriven public repo
+ https://nexus.bedatadriven.com/content/groups/public/
+
+
+
+
+
+ false
+
+ talan
+ talan
+ https://nexus.talanlabs.com/content/repositories/releases/
+
+
+
+ central
+ https://repo1.maven.org/maven2
+
+
+
-
-
+
+
+
+
+
+ io.github.macster110
+ jpamutils
+ 0.0.59
+
-
-
- io.github.macster110
- jpamutils
- 0.0.56
-
-
-
-
- io.github.macster110
- jdl4pam
- 0.0.94
-
-
-
-
- gov.nist.math
- jama
- 1.0.3
-
-
-
-
+
+ io.github.macster110
+ jdl4pam
+ 0.0.99a
+
+
+
+
+ gov.nist.math
+ jama
+ 1.0.3
+
+
+
+
-
- org.openjfx
- javafx-controls
- ${javafx.version}
-
+
+ org.openjfx
+ javafx-controls
+ ${javafx.version}
+
-
-
+
-
- org.openjfx
- javafx-swing
- ${javafx.version}
-
-
-
-
+
-
- org.openjfx
- javafx-media
- ${javafx.version}
-
+
+ org.openjfx
+ javafx-media
+ ${javafx.version}
+
-
-
+
-
- org.openjfx
- javafx-web
- ${javafx.version}
-
+
+ org.openjfx
+ javafx-web
+ ${javafx.version}
+
+
+
+
+ net.synedra
+ validatorfx
+ 0.4.2
+
+
+
+
+ org.apache.commons
+ commons-compress
+ 1.19
+
-
-
- net.synedra
- validatorfx
- 0.4.0
-
-
-
-
- org.apache.commons
- commons-compress
- 1.19
-
-
-
-
- org.apache.commons
- commons-csv
- 1.7
-
-
-
-
- commons-io
- commons-io
- 2.6
-
-
-
-
- org.apache.commons
- commons-lang3
- 3.9
-
-
-
-
- org.apache.commons
- commons-math3
- 3.6.1
-
-
-
-
- org.apache.commons
- commons-math
- 2.2
-
-
-
-
- commons-net
- commons-net
- 3.6
-
-
-
-
- org.controlsfx
- controlsfx
- 11.0.0
-
-
- org.openjfx
- javafx-base
-
-
- org.openjfx
- javafx-controls
-
-
- org.openjfx
- javafx-graphics
-
-
- org.openjfx
- javafx-media
-
-
- org.openjfx
- javafx-web
-
-
-
-
-
-
+
+ org.apache.commons
+ commons-csv
+ 1.7
+
+
+
+
+ commons-io
+ commons-io
+ 2.6
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.9
+
+
+
+
+ org.apache.commons
+ commons-math3
+ 3.6.1
+
+
+
+
+ org.apache.commons
+ commons-math
+ 2.2
+
+
+
+
+ commons-net
+ commons-net
+ 3.6
+
+
+
+
+ org.controlsfx
+ controlsfx
+ 11.2.0
+
+
+ org.openjfx
+ javafx-base
+
+
+ org.openjfx
+ javafx-controls
+
+
+ org.openjfx
+ javafx-graphics
+
+
+ org.openjfx
+ javafx-media
+
+
+ org.openjfx
+ javafx-web
+
+
+
+
+
+
-
- org.kordamp.ikonli
- ikonli-javafx
- 12.2.0
-
-
-
-
+
+ org.kordamp.ikonli
+ ikonli-swing
+ 12.3.1
+
+
+
org.kordamp.ikonli
- ikonli-fontawesome5-pack
- 12.2.0
+ ikonli-materialdesign2-pack
+ 12.3.1
+
+
+
+
+ org.kordamp.ikonli
+ ikonli-fileicons-pack
+ 12.3.1
- -->
-
-
- org.kordamp.ikonli
- ikonli-materialdesign2-pack
- 12.2.0
-
+
+
+ net.sf.geographiclib
+ GeographicLib-Java
+ 1.50
+
+
+
+
-
-
- net.sf.geographiclib
- GeographicLib-Java
- 1.50
-
-
-
-
- org.jogamp.gluegen
- gluegen-rt-main
- 2.3.2
-
-
-
-
-
-
-
-
- com.healthmarketscience.jackcess
- jackcess
- 3.0.1
-
-
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.10.1
-
-
-
-
- org.jogamp.jogl
- jogl-all-main
- 2.3.2
-
-
-
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.10.1
+
+
+
+
+
-
-
-
- org.jflac
- jflac-codec
- 1.5.2
-
-
-
-
- javax.help
- javahelp
- 2.0.05
-
-
-
-
- net.java.dev.jna
- jna
- 5.5.0
-
-
+
+
+
+ org.jflac
+ jflac-codec
+ 1.5.2
+
+
+
+
+ javax.help
+ javahelp
+ 2.0.05
+
+
+
+
+ net.java.dev.jna
+ jna
+ 5.5.0
+
+
-
- net.java.dev.jna
- jna-platform
- 5.5.0
-
+
+ net.java.dev.jna
+ jna-platform
+ 5.5.0
+
+
+
+
+ com.jcraft
+ jsch
+ 0.1.55
+
+
+
+
+ com.fazecast
+ jSerialComm
+ 2.5.3
+
-
-
- com.jcraft
- jsch
- 0.1.55
-
+
+
+ edu.emory.mathcs
+ JTransforms
+ 2.4
+
-
-
- com.fazecast
- jSerialComm
- 2.5.3
-
+
+
+ com.sun.mail
+ javax.mail
+ 1.6.2
+
-
-
- edu.emory.mathcs
- JTransforms
- 2.4
-
-
-
- com.sun.mail
- javax.mail
- 1.6.2
-
+
+
+ com.drewnoakes
+ metadata-extractor
+ 2.12.0
+
-
-
- com.diffplug.matsim
- matfilerw
- 3.1.1
-
+
+
+ mysql
+ mysql-connector-java
+ 8.0.18
+
-
-
- com.drewnoakes
- metadata-extractor
- 2.12.0
-
-
-
-
- mysql
- mysql-connector-java
- 8.0.18
-
-
-
-
-
+
+
-
+
+ com.google.protobuf
+ protobuf-java
+ 3.17.0
+
+
+
+
+
+ edu.ucar
+ netcdfAll
+ 4.6.14
+
+ com.google.protobufprotobuf-java
- 3.17.0
-
+
+
+ com.google.protobuf
+ protobuf-java-util
+
+
+ compile
+
-
-
-
- edu.ucar
- netcdfAll
- 4.6.14
-
-
- com.google.protobuf
- protobuf-java
-
-
- com.google.protobuf
- protobuf-java-util
-
-
- compile
-
+
+
+ com.opencsv
+ opencsv
+ 5.0
+
-
-
- com.opencsv
- opencsv
- 5.0
-
+
-
+
+
+ org.postgresql
+ postgresql
+ 42.2.24
+
-
-
- org.postgresql
- postgresql
- 42.2.24
-
-
-
-
- org.renjin
- renjin-script-engine
- 0.9.2725
-
-
-
+
+ org.renjin
+ renjin-script-engine
+ 0.9.2725
+
+
+
-
- org.slf4j
- slf4j-api
- 1.8.0-beta4
-
-
-
-
-
- org.slf4j
- slf4j-nop
- 1.8.0-beta4
-
+
+ org.slf4j
+ slf4j-nop
+ 1.8.0-beta4
+
+
+
-
-
-
+
-
-
- org.docx4j
- docx4j-JAXB-ReferenceImpl
- 11.1.3
-
-
+
-
-
- org.xerial
- sqlite-jdbc
- 3.28.0
-
+
+
+ org.xerial
+ sqlite-jdbc
+ 3.45.3.0
+
-
-
- net.sf.ucanaccess
- ucanaccess
- 5.0.1
-
+
+
+ net.sf.ucanaccess
+ ucanaccess
+ 4.0.4
+
-
-
- nz.ac.waikato.cms.weka
- weka-dev
- 3.7.7
-
+
+
+ nz.ac.waikato.cms.weka
+ weka-dev
+ 3.7.7
+
-
-
- javax.vecmath
- vecmath
- 1.5.2
-
+
+
+ javax.vecmath
+ vecmath
+ 1.5.2
+
-
-
-
+
+
+
+
+ org.eclipse.persistence
+ org.eclipse.persistence.moxy
+ 2.5.0
+
+
+ javax.xml.bind
+ jaxb-api
+ ${jaxb.api.version}
+
+
+ org.glassfish.jaxb
+ jaxb-runtime
+ ${jaxb.runtime.version}
+
+
+ org.glassfish.jaxb
+ jaxb-xjc
+ ${jaxb.xjc.version}
+
+
+
+
+
+ com.sun.jersey.contribs
+ jersey-multipart
+ 1.18.1
+
+
+
+
+ commons-cli
+ commons-cli
+ 1.2
+
+
+
+
+ org.apache.poi
+ poi
+ 3.10-beta1
+
+
+
+
+ com.sun.jersey
+ jersey-client
+ 1.18.1
+
+
+
+
+ com.sun.jersey.contribs
+ jersey-apache-client
+ 1.18.1
+
+
+
+
+ com.miglayout
+ miglayout
+ 3.7.4
+
+
+
+
+ ca.juliusdavies
+ not-yet-commons-ssl
+ 0.3.11
+
+
+
+
+ javax.ws.rs
+ javax.ws.rs-api
+ 2.1.1
+
+
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.2.11
+
+
+
+
+ com.sun.xml.bind
+ jaxb-impl
+ 2.2.11
+
+
+
+
+ javax.activation
+ activation
+ 1.1
+
+
+
+
+ org.glassfish.jaxb
+ jaxb-core
+ 2.2.11
+
+
+
+
+ org.glassfish.jersey.core
+ jersey-common
+ 2.2
+
+
+
+
+ org.apache.commons
+ commons-text
+ 1.9
+
+
+
+
+
+
+
+ tethys.org
+ nilus
+ 3.0
+
-
-
- org.eclipse.persistence
- org.eclipse.persistence.moxy
- 2.5.0
-
-
- javax.xml.bind
- jaxb-api
- ${jaxb.api.version}
-
-
- org.glassfish.jaxb
- jaxb-runtime
- ${jaxb.runtime.version}
-
-
- org.glassfish.jaxb
- jaxb-xjc
- ${jaxb.xjc.version}
-
-
-
- com.sun.jersey.contribs
- jersey-multipart
- 1.18.1
-
-
- commons-cli
- commons-cli
- 1.2
-
-
- org.apache.poi
- poi
- 3.10-beta1
-
-
- com.sun.jersey
- jersey-client
- 1.18.1
-
-
- com.sun.jersey.contribs
- jersey-apache-client
- 1.18.1
-
-
- com.miglayout
- miglayout
- 3.7.4
-
-
- ca.juliusdavies
- not-yet-commons-ssl
- 0.3.11
-
-
- javax.ws.rs
- javax.ws.rs-api
- 2.1.1
-
-
- javax.xml.bind
- jaxb-api
- 2.2.11
-
-
- com.sun.xml.bind
- jaxb-impl
- 2.2.11
-
-
- javax.activation
- activation
- 1.1
-
-
- org.glassfish.jaxb
- jaxb-core
- 2.2.11
-
-
- org.glassfish.jersey.core
- jersey-common
- 2.2
-
-
- org.apache.commons
- commons-text
- 1.9
-
+
+ tethys.org
+ javaclient
+ 3.0
+
-
-
+
- pamguard.org
+ org.pamguardx32.2.7
-
+
+
+
+ it.sauronsoftware
+ jave
+ 1.0.2
+
+
+
+
+ com.synthbot
+ jasiohost
+ 1.0.0
+
-
- tethys.org
- nilus
- 3.0
-
-
-
- tethys.org
- javaclient
- 3.0
-
-
-
-
-
- it.sauronsoftware
- jave
- 1.0.2
-
-
-
-
- com.synthbot
- jasiohost
- 1.0.0
-
-
-
-
+
+
+
+
+ org.springframework
+ spring-core
+ 5.2.3.RELEASE
+
+
+
+
+
+ com.1stleg
+ jnativehook
+ 2.1.0
+
+
+
+
+
+ org.swinglabs.swingx
+ swingx-all
+ 1.6.5-1
+
-
-
- org.springframework
- spring-core
- 5.2.3.RELEASE
-
+
+
+
+ org.fxyz3d
+ fxyz3d
+ 0.6.0
+
+
+
+
+ io.github.mkpaz
+ atlantafx-base
+ 2.0.1
+
-
-
-
- com.1stleg
- jnativehook
- 2.1.0
-
-
-
-
-
- org.swinglabs.swingx
- swingx-all
- 1.6.5-1
-
-
-
-
- io.github.mkpaz
- atlantafx-base
- 1.0.0
-
-
-
-
+
\ No newline at end of file
diff --git a/readme.md b/readme.md
index a63ea137..721b10db 100644
--- a/readme.md
+++ b/readme.md
@@ -1,5 +1,73 @@
-This is the main code repository for the PAMGuard software.
+# PAMGuard
+PAMGuard is a bioacoustics analysis program designed for use in real time research contexts and for the processing of large datasets. PAMGuard provides users access to a suite of state-of-the-art auotmated analysis algorithms alongside displays for visualisation data and a comprehensive data management systems.
-This repository was created on 7 January 2022 from sourceforge SVN repository at https://sourceforge.net/p/pamguard/svn/HEAD/tree/ revision r6278.
+# Why do we need PAMGuard?
+PAMGuard fufills two main requirements within marine bioacoustics
-If you are a PAMGuard developer, you should clone and branch this repository and share with any collaborators in your own workspace. When your work is ready, contact the PAMGuard team to have your changes merged back into this repo.
+1) **Real time operation** - Almost all PAMGuard features and modules work in real time - this allows scientists and industry to detect, classify and loclaise animals in real time on a standard consumer laptop, enabling mitigations and research survey without expensive bespoke software solutions and the transparncy of open source software.
+
+2) **Processing and visuslisation of large datasets** -
+
+
+## Installation
+PAMGuard is available on Windows and can be downloaded from the [PAMGuard website](www.pamguard.org). Note that we are considering MacOS installers but they are not available at this time.
+
+## Tutorial
+PAMGuard is a modular program with two modes; real-time and viewer. Typically a user will start with real-time model, either in the field collecting data or post processing sound files from a recorder. Once data are processed, users move on to viewer mode where data can be explored and further processed.
+
+Upon opening PAMGuard for the first time you are greeted with a blank screen. You must add a series of modules to create the desired acosutic workflow. For example if processing sound files then first add the Sound Acquisition module **_File->Add Modules->Sound Processing->Sound Acquisition_**. Then add the desired detection algorothms e.g. **_File->Add Modules->Detector->Click Detectors_**. Some modules (such as the click detector) have their own displays, others are added to more generalised displays. For example, the whislte and moan detector module shows detections on a spectrgram display. First add a new tab using **_File->Add Modules->Displays->User Display**. Click on the user display tab and then from the top menu select **_User display-> New Spectrgram_**. Right click on the added spectrgram and select whistle and moan contours to show whistle detections overlaid on the raw spectrgram.
+
+Make sure to add the database and binary file storage modules **_File->Add Modules->Utilities->..._**) to save data then press the run button (red button) and data will process. PAMGuard can handle huge datasets so runing might take hours or even days. Progress is shown on the bottom of the screen.
+
+## Features
+
+### Hardware integration
+PAMGuard connects with hardware such as various GPS and AIS systems and a multitude of different sound cards (e.g. [National Instruments](www.ni.com) devices, [SAIL DAQ cards](www.smruconsulting.com/contact-us), almost all ASIO sound cards and standard computer sound cards) for real time data collection and processing. PAMGuard also works with some very bespoke hardware such as [DIFAR Sonobuoys]();
+
+### Real time operation
+PAMGuard takes advanatge of multi-core processors to run multiple signal processing automatic analysis algorithms in real time to detect whales, dolphins, bats etc. Data are shown in different displayes, including interactive spectrograms and maps. You might be using PAMGuard for simply viewing a spectrgram and making recordings or running deep learning algorithms for multiple species and loclaising the results to view locations on a map. Whatever acosutic workflow a user creates, PAMGuard can run it in real time.
+
+### Support for compressed audio
+PAMGuard supports processing audio data from standard files (e.g. wav, aif) and also compressed files (e.g. .flac and .sud). Notew that sud files are created on SoundTraps widely used marine recorders and can be read by PAMGuard without decompressing - PAMGuard will automtically import click detections if present in sud files. PAMGuard also supports importing detection data from CPODs and FPODs.
+
+### Comprehensive data management system
+PAMGuard is designed to collect/process data from large acosutic datasets. PAMGuard stores data in an SQLite databases and "Binary" files. The database stores important metadata such as when data has been processed and some low volume data streams such as GPS. Binary files are not human readbale but efficient to access - PAMGuard stores detection data (e.g. clicks, whistles, noise, etc) in these files. this allows PAMGuard to rapidly access data from large datasets. Data from binary files can be viewed in PAMGuard viewer mode or can be exported to MATLAB using the PAMGuard-MATLAB library or the exported to R using the R PAMBinaries package.
+
+### Access to detection and classification algorithms
+PAMGuard allows users to inegrate automated detection and classification algorithms directly into their acosutic workflow. There are a multitude of differwent algorothms to choose from, including a basic click detector, whislte and moan detector, GPL detector, click train detectors and many others. The idea behind PAMGuard is allow researchers to access open source state-of-the-art algorithms devleoped within the scientific community - if you want to contribute and get your algorithm into PAMGuard get in touch.
+
+###Localisation
+PAMGuard has a mutltude of different options for acoustic loclaisation. There's a comprehesnive beam forming module for beam forming arrays, a large aperture localiser for 3D loclaisation and target motion analysis for towed hydrophone arrays.
+
+###Soundscape analysis
+PAMGuard has a noise band (which supports third octave noise bands) and long term spectral average module for soundscape analysis.
+
+### GIS
+Almsot all detection data can be visualised on a map. PAMGaurd also supports plotting GPS and AIS data.
+
+### Suite of data visualisation tools
+An important aspect of PAMGuard is the ability for users to explore porcessed data. This is
+
+### Advanced manual annotation
+The displays within PAMGuard support a variety of manual annottion tools. A simple spectrogram
+
+### Deep learning integration
+
+### Meatadata standard and Tethys compatibility
+
+## Feature roadmap
+There's lots of features we would like to add to PAMGuard. If you want to add a feature you can either code it up yourself in Java and submit a pull request or get in touch with us to discuss how to it might be integrated. Some smaller features might be in our roadmap anyway but larger features usually require funding. Some features we are thinking about (but do not necassarily have time for yet) are;
+
+* Support for decidecade noise bands (base 10 filter bank) in noise band monitor to meet Euopean standards
+* Capabaility to export data directly from PAMGaurd e.g. as MAT files.
+* Automated test suite to make releases more stable. Note that unit and integration tests are also being slowly incorporated.
+
+## Development
+This is the main code repository for the PAMGuard software and was created on 7 January 2022 from a [sourceforge SVN repository](https://sourceforge.net/p/pamguard/svn/HEAD/tree/) revision r6278.
+
+If you are a PAMGuard developer, you should clone and branch this repository and share with any collaborators in your own workspace. When your work is ready, contact the PAMGuard team to have your changes merged back into this repo.
+
+PAMGuard uses Maven as build tool.
+
+# Organisation and License
+PAMGuard is open source under an MIT license. It is currently primarily managed by the Sea Mammal Research Unit within the [University of St Andrews](https://www.st-andrews.ac.uk/). Please get in touch if you have any questions.
diff --git a/repo/pamguard/org/x3/2.2.6/x3-2.2.6.pom b/repo/pamguard/org/x3/2.2.6/x3-2.2.6.pom
index 609bc1d5..8d48a0d5 100644
--- a/repo/pamguard/org/x3/2.2.6/x3-2.2.6.pom
+++ b/repo/pamguard/org/x3/2.2.6/x3-2.2.6.pom
@@ -1,9 +1,15 @@
-4.0.0
+<<<<<<<< HEAD:repo/tethys/org/javaclient/3.0/javaclient-3.0.pom
+ tethys.org
+ javaclient
+ 3.0
+========
pamguard.orgx32.2.6
+>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.6/x3-2.2.6.pom
POM was created from install:install-file
diff --git a/repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom b/repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom
index 7eeede30..dc2f63cc 100644
--- a/repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom
+++ b/repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom
@@ -2,8 +2,14 @@
4.0.0
+<<<<<<<< HEAD:repo/tethys/org/nilus/3.0/nilus-3.0.pom
+ tethys.org
+ nilus
+ 3.0
+========
pamguard.orgx32.2.7
+>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom
POM was created from install:install-file
diff --git a/repo/tethys/org/javaclient/3.0/javaclient-3.0-javadoc.jar.lastUpdated b/repo/tethys/org/javaclient/3.0/javaclient-3.0-javadoc.jar.lastUpdated
new file mode 100644
index 00000000..17ccf4ee
--- /dev/null
+++ b/repo/tethys/org/javaclient/3.0/javaclient-3.0-javadoc.jar.lastUpdated
@@ -0,0 +1,16 @@
+#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
+#Thu Mar 07 12:09:00 GMT 2024
+@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1705320262317
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1705320259110
+https\://repo1.maven.org/maven2/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.error=
+https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error=
+https\://nexus.bedatadriven.com/content/groups/public/.error=
+https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1705320260572
+https\://repo1.maven.org/maven2/.lastUpdated=1705320262598
+https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact tethys.org\:javaclient\:jar\:javadoc\:3.0 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.lastUpdated=1705569305037
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error=
+https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1705320262257
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.lastUpdated=1709813340827
diff --git a/repo/tethys/org/javaclient/3.0/javaclient-3.0-sources.jar.lastUpdated b/repo/tethys/org/javaclient/3.0/javaclient-3.0-sources.jar.lastUpdated
new file mode 100644
index 00000000..6544bcc1
--- /dev/null
+++ b/repo/tethys/org/javaclient/3.0/javaclient-3.0-sources.jar.lastUpdated
@@ -0,0 +1,16 @@
+#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
+#Thu Mar 07 12:08:16 GMT 2024
+@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1703957320119
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.error=
+https\://repo1.maven.org/maven2/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1705074190844
+https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error=
+https\://nexus.bedatadriven.com/content/groups/public/.error=
+https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1703957319870
+https\://repo1.maven.org/maven2/.lastUpdated=1703957320395
+https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact tethys.org\:javaclient\:jar\:sources\:3.0 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.lastUpdated=1703957318729
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error=
+https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1703957320102
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.lastUpdated=1709813296623
diff --git a/repo/tethys/org/javaclient/3.0/javaclient-3.0.pom b/repo/tethys/org/javaclient/3.0/javaclient-3.0.pom
index 80fee21c..8d48a0d5 100644
--- a/repo/tethys/org/javaclient/3.0/javaclient-3.0.pom
+++ b/repo/tethys/org/javaclient/3.0/javaclient-3.0.pom
@@ -2,8 +2,14 @@
4.0.0
+<<<<<<<< HEAD:repo/tethys/org/javaclient/3.0/javaclient-3.0.pom
tethys.orgjavaclient3.0
+========
+ pamguard.org
+ x3
+ 2.2.6
+>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.6/x3-2.2.6.pom
POM was created from install:install-file
diff --git a/repo/tethys/org/javaclient/3.0/m2e-lastUpdated.properties b/repo/tethys/org/javaclient/3.0/m2e-lastUpdated.properties
new file mode 100644
index 00000000..db908e36
--- /dev/null
+++ b/repo/tethys/org/javaclient/3.0/m2e-lastUpdated.properties
@@ -0,0 +1,15 @@
+#Thu Mar 07 12:09:00 GMT 2024
+bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|javadoc=1709813340828
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo|javadoc=1705320262599
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo|javadoc=1709813340828
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo|javadoc=1705569305040
+talan|https\://nexus.talanlabs.com/content/repositories/releases/|sources=1709813296626
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo|sources=1709813296626
+bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|sources=1709813296626
+unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|sources=1709813296626
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo|sources=1703957320396
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo|sources=1705074190848
+talan|https\://nexus.talanlabs.com/content/repositories/releases/|javadoc=1709813340828
+central|https\://repo1.maven.org/maven2|sources=1709813296626
+unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|javadoc=1709813340828
+central|https\://repo1.maven.org/maven2|javadoc=1709813340828
diff --git a/repo/tethys/org/nilus/3.0/_remote.repositories b/repo/tethys/org/nilus/3.0/_remote.repositories
index a5060b8b..de3047e4 100644
--- a/repo/tethys/org/nilus/3.0/_remote.repositories
+++ b/repo/tethys/org/nilus/3.0/_remote.repositories
@@ -1,4 +1,4 @@
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
-#Thu Dec 21 11:14:13 GMT 2023
+#Thu Mar 07 11:55:57 GMT 2024
nilus-3.0.pom>=
nilus-3.0.jar>=
diff --git a/repo/tethys/org/nilus/3.0/m2e-lastUpdated.properties b/repo/tethys/org/nilus/3.0/m2e-lastUpdated.properties
index 8382f138..5e4193d5 100644
--- a/repo/tethys/org/nilus/3.0/m2e-lastUpdated.properties
+++ b/repo/tethys/org/nilus/3.0/m2e-lastUpdated.properties
@@ -1,11 +1,15 @@
-#Thu Dec 21 16:45:12 GMT 2023
-bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|javadoc=1703177112968
-talan|https\://nexus.talanlabs.com/content/repositories/releases/|javadoc=1703177112968
+#Thu Jan 18 09:15:05 GMT 2024
+bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|javadoc=1705569305022
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo|javadoc=1705320259098
repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo|javadoc=1703177112968
-central|https\://repo1.maven.org/maven2|sources=1703157324238
-unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|javadoc=1703177112968
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo|javadoc=1705569305022
repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo|sources=1703157324238
-talan|https\://nexus.talanlabs.com/content/repositories/releases/|sources=1703157324238
-bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|sources=1703157324238
-unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|sources=1703157324238
-central|https\://repo1.maven.org/maven2|javadoc=1703177112968
+talan|https\://nexus.talanlabs.com/content/repositories/releases/|sources=1705074190830
+bedatadriven|https\://nexus.bedatadriven.com/content/groups/public/|sources=1705074190830
+unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|sources=1705074190830
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo|sources=1703957318711
+repo|file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo|sources=1705074190830
+talan|https\://nexus.talanlabs.com/content/repositories/releases/|javadoc=1705569305022
+central|https\://repo1.maven.org/maven2|sources=1705074190830
+unidata-all|https\://artifacts.unidata.ucar.edu/repository/unidata-all/|javadoc=1705569305022
+central|https\://repo1.maven.org/maven2|javadoc=1705569305022
diff --git a/repo/tethys/org/nilus/3.0/nilus-3.0-javadoc.jar.lastUpdated b/repo/tethys/org/nilus/3.0/nilus-3.0-javadoc.jar.lastUpdated
index 34e39dc5..1faf7573 100644
--- a/repo/tethys/org/nilus/3.0/nilus-3.0-javadoc.jar.lastUpdated
+++ b/repo/tethys/org/nilus/3.0/nilus-3.0-javadoc.jar.lastUpdated
@@ -1,12 +1,16 @@
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
-#Thu Dec 21 16:45:12 GMT 2023
+#Thu Jan 18 09:15:05 GMT 2024
@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1703177112601
https\://repo1.maven.org/maven2/.error=
-file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.error=
-file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.lastUpdated=1703177110940
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1705320259096
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.error=
https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error=
https\://nexus.bedatadriven.com/content/groups/public/.error=
-https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1703177112519
https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1703177112101
https\://repo1.maven.org/maven2/.lastUpdated=1703177112965
https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact tethys.org\:nilus\:jar\:javadoc\:3.0 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.lastUpdated=1705569305018
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.lastUpdated=1703177110940
+https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1703177112519
diff --git a/repo/tethys/org/nilus/3.0/nilus-3.0-sources.jar.lastUpdated b/repo/tethys/org/nilus/3.0/nilus-3.0-sources.jar.lastUpdated
index 8ceb547f..6dbbc1bb 100644
--- a/repo/tethys/org/nilus/3.0/nilus-3.0-sources.jar.lastUpdated
+++ b/repo/tethys/org/nilus/3.0/nilus-3.0-sources.jar.lastUpdated
@@ -1,12 +1,16 @@
#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
-#Thu Dec 21 11:15:24 GMT 2023
+#Fri Jan 12 15:43:10 GMT 2024
@default-talan-https\://nexus.talanlabs.com/content/repositories/releases/.lastUpdated=1703157323819
https\://repo1.maven.org/maven2/.error=
-file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.error=
-file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.lastUpdated=1703157322932
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.lastUpdated=1705074190824
https\://artifacts.unidata.ucar.edu/repository/unidata-all/.error=
https\://nexus.bedatadriven.com/content/groups/public/.error=
-https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1703157323770
https\://artifacts.unidata.ucar.edu/repository/unidata-all/.lastUpdated=1703157323508
https\://repo1.maven.org/maven2/.lastUpdated=1703157324237
https\://nexus.talanlabs.com/content/repositories/releases/.error=Could not transfer artifact tethys.org\:nilus\:jar\:sources\:3.0 from/to talan (https\://nexus.talanlabs.com/content/repositories/releases/)\: nexus.talanlabs.com
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG/repo/.lastUpdated=1703957318705
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardPAMGuard/repo/.error=
+file\://C\:\\Users\\dg50\\source\\repos\\PAMGuardDG_2/repo/.lastUpdated=1703157322932
+https\://nexus.bedatadriven.com/content/groups/public/.lastUpdated=1703157323770
diff --git a/repo/tethys/org/nilus/3.0/nilus-3.0.jar b/repo/tethys/org/nilus/3.0/nilus-3.0.jar
index 195d268e..c00ba775 100644
Binary files a/repo/tethys/org/nilus/3.0/nilus-3.0.jar and b/repo/tethys/org/nilus/3.0/nilus-3.0.jar differ
diff --git a/repo/tethys/org/nilus/3.0/nilus-3.0.pom b/repo/tethys/org/nilus/3.0/nilus-3.0.pom
index ba47dee9..dc2f63cc 100644
--- a/repo/tethys/org/nilus/3.0/nilus-3.0.pom
+++ b/repo/tethys/org/nilus/3.0/nilus-3.0.pom
@@ -2,8 +2,14 @@
4.0.0
+<<<<<<<< HEAD:repo/tethys/org/nilus/3.0/nilus-3.0.pom
tethys.orgnilus3.0
+========
+ pamguard.org
+ x3
+ 2.2.7
+>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom
POM was created from install:install-file
diff --git a/repo/tethys/org/nilus/maven-metadata-local.xml b/repo/tethys/org/nilus/maven-metadata-local.xml
index d053c39d..0aa256c5 100644
--- a/repo/tethys/org/nilus/maven-metadata-local.xml
+++ b/repo/tethys/org/nilus/maven-metadata-local.xml
@@ -7,6 +7,6 @@
3.0
- 20231221111413
+ 20240307115557
diff --git a/src/Acquisition/FileInputSystem.java b/src/Acquisition/FileInputSystem.java
index 2727ca05..33779534 100644
--- a/src/Acquisition/FileInputSystem.java
+++ b/src/Acquisition/FileInputSystem.java
@@ -429,6 +429,8 @@ public class FileInputSystem extends DaqSystem implements ActionListener, PamSe
// acquisitionDialog.NotifyChange();
if (file.isFile() && !file.isHidden() && acquisitionDialog != null) {
try {
+
+ System.out.println("FileInputSystem - interpretNewFile");
AudioInputStream audioStream = PamAudioFileManager.getInstance().getAudioInputStream(file);
// // Get additional information from the header if it's a wav file.
@@ -600,6 +602,8 @@ public class FileInputSystem extends DaqSystem implements ActionListener, PamSe
audioStream.close();
}
+ System.out.println("FileInputSystem - prepareInputFile");
+
audioStream = PamAudioFileManager.getInstance().getAudioInputStream(currentFile);
if (audioStream instanceof SudAudioInputStream) {
@@ -810,6 +814,10 @@ public class FileInputSystem extends DaqSystem implements ActionListener, PamSe
protected void collectFlacData() {
FileInputStream fileStream;
try {
+ File currFile = getCurrentFile();
+ if (currFile == null) {
+ return;
+ }
fileStream = new FileInputStream(getCurrentFile());
} catch (FileNotFoundException e) {
e.printStackTrace();
diff --git a/src/Acquisition/FolderInputSystem.java b/src/Acquisition/FolderInputSystem.java
index 7b20311e..c8c2d872 100644
--- a/src/Acquisition/FolderInputSystem.java
+++ b/src/Acquisition/FolderInputSystem.java
@@ -602,6 +602,7 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D
@Override
public File getCurrentFile() {
//System.out.println("All files: " + allFiles);
+// System.out.printf("Folder: getCurrentfile. on %d of %d\n", currentFile, allFiles.size());
if (allFiles != null && allFiles.size() > currentFile) {
return allFiles.get(currentFile);
}
@@ -689,7 +690,7 @@ public class FolderInputSystem extends FileInputSystem implements PamSettings, D
}
if (currentFile < allFiles.size()) {
// only restart if the file ended - not if it stopped
- if (getStreamStatus() == STREAM_ENDED) {
+ if (getStreamStatus() == STREAM_ENDED && PamController.getInstance().isManualStop() == false) {
// System.out.println(String.format("Start new file timer (file %d/%d)",currentFile+1,allFiles.size()));
newFileTimer.start();
}
diff --git a/src/Acquisition/filedate/FileDateDialogStrip.java b/src/Acquisition/filedate/FileDateDialogStrip.java
index 836850e6..c695f6de 100644
--- a/src/Acquisition/filedate/FileDateDialogStrip.java
+++ b/src/Acquisition/filedate/FileDateDialogStrip.java
@@ -1,6 +1,7 @@
package Acquisition.filedate;
import java.awt.BorderLayout;
+import java.awt.Color;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@@ -15,7 +16,11 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
+import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
+import org.kordamp.ikonli.swing.FontIcon;
+
import PamUtils.PamCalendar;
+import PamView.component.PamSettingsIconButton;
import PamView.dialog.PamGridBagContraints;
/**
@@ -35,7 +40,9 @@ public class FileDateDialogStrip {
private JButton settingsButton;
- private ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+// private ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+ public static FontIcon settingsIcon = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY);
+
private Window parent;
diff --git a/src/Acquisition/filedate/StandardFileDate.java b/src/Acquisition/filedate/StandardFileDate.java
index 53033f60..54f6d998 100644
--- a/src/Acquisition/filedate/StandardFileDate.java
+++ b/src/Acquisition/filedate/StandardFileDate.java
@@ -135,6 +135,8 @@ public class StandardFileDate implements FileDate, PamSettings {
@Override
public long getTimeFromFile(File file) {
+// System.out.println("Get time from file: getTimeFromFile" );
+
// if the user wants to force the local PC time, return immediately
if (settings.isForcePCTime()) return 0;
diff --git a/src/Acquisition/layoutFX/AcquisitionPaneFX.java b/src/Acquisition/layoutFX/AcquisitionPaneFX.java
index 7f866f7c..59400599 100644
--- a/src/Acquisition/layoutFX/AcquisitionPaneFX.java
+++ b/src/Acquisition/layoutFX/AcquisitionPaneFX.java
@@ -290,7 +290,7 @@ public class AcquisitionPaneFX extends SettingsPane{
//custom pane for each aquisition system.
systemPane=new PamBorderPane();
- offlineDAQPaneFX= new OfflineDAQPane(acquisitionControl, this);
+ offlineDAQPaneFX= new OfflineDAQPane(acquisitionControl);
//the main pane is for reference only in viewer mode.
Pane samplingPane=createSamplingPane();
diff --git a/src/Acquisition/layoutFX/CheckWavHeadersPane.java b/src/Acquisition/layoutFX/CheckWavHeadersPane.java
index c97cd6d4..4f849e86 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);
@@ -159,6 +164,7 @@ public class CheckWavHeadersPane extends PamBorderPane {
private int countFiles(File folder) {
+ if (folder == null) return 0;
int nF = 0;
File[] files = folder.listFiles(new PamAudioFileFilter());
if (files == null) return 0;
diff --git a/src/Acquisition/layoutFX/FileDataDialogStripFX.java b/src/Acquisition/layoutFX/FileDataDialogStripFX.java
index e4fae902..7658f7da 100644
--- a/src/Acquisition/layoutFX/FileDataDialogStripFX.java
+++ b/src/Acquisition/layoutFX/FileDataDialogStripFX.java
@@ -215,7 +215,7 @@ public class FileDataDialogStripFX extends PamBorderPane {
popOver.show(advSettingsButton);
((Parent) popOver.getSkin().getNode()).getStylesheets()
- .add(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getSlidingDialogCSS());
+ .addAll(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getSlidingDialogCSS());
advDatePane.setParams();
}
diff --git a/src/Acquisition/layoutFX/FolderInputPane.java b/src/Acquisition/layoutFX/FolderInputPane.java
index d815fd06..cf0b0e3e 100644
--- a/src/Acquisition/layoutFX/FolderInputPane.java
+++ b/src/Acquisition/layoutFX/FolderInputPane.java
@@ -193,20 +193,18 @@ public class FolderInputPane extends DAQSettingsPane{
//TODO
});
- browseFileButton.setGraphic(Glyph.create("FontAwesome|FILES_ALT").
- size(PamGuiManagerFX.iconSize).color(Color.WHITE.darker()));
+ browseFileButton.setGraphic(PamGlyphDude.createPamIcon("mdi2f-file-multiple", PamGuiManagerFX.iconSize));
browseFileButton.prefHeightProperty().bind(fileSelectBox.heightProperty()); //make browse button same height as combo box.
- browseFileButton.setMinWidth(35);
+ browseFileButton.setMinWidth(40);
browseFileButton.setOnAction( (action) ->{
selectFolder(false);
});
browseFileButton.setTooltip(new Tooltip("Select a folder of files"));
- browseFolderButton.setGraphic(Glyph.create("FontAwesome|FOLDER").
- size(PamGuiManagerFX.iconSize).color(Color.WHITE.darker()));
+ browseFolderButton.setGraphic(PamGlyphDude.createPamIcon("mdi2f-folder", PamGuiManagerFX.iconSize));
browseFolderButton.prefHeightProperty().bind(fileSelectBox.heightProperty()); //make browse button same height as combo box.
- browseFolderButton.setMinWidth(35);
+ browseFolderButton.setMinWidth(40);
browseFolderButton.setOnAction( (action) ->{
selectFolder(true);
});
diff --git a/src/Acquisition/layoutFX/OfflineDAQPane.java b/src/Acquisition/layoutFX/OfflineDAQPane.java
index f5ff7726..56cb2003 100644
--- a/src/Acquisition/layoutFX/OfflineDAQPane.java
+++ b/src/Acquisition/layoutFX/OfflineDAQPane.java
@@ -30,8 +30,7 @@ public class OfflineDAQPane extends SettingsPane{
private PamBorderPane mainPane;
- public OfflineDAQPane(OfflineFileDataStore acquisitionControl,
- AcquisitionPaneFX acquisitionPaneFX){
+ public OfflineDAQPane(OfflineFileDataStore acquisitionControl){
super(null);
this.mainPane= new PamBorderPane();
mainPane.setCenter(createOfflinePane());
diff --git a/src/Acquisition/pamAudio/PamAudioFileManager.java b/src/Acquisition/pamAudio/PamAudioFileManager.java
index 76fc6910..bf13f904 100644
--- a/src/Acquisition/pamAudio/PamAudioFileManager.java
+++ b/src/Acquisition/pamAudio/PamAudioFileManager.java
@@ -135,7 +135,7 @@ public class PamAudioFileManager {
}
if (stream == null) {
- System.err.println("PamAudioFileManager: unable to open an AudioStream for " + file.getName());
+ System.err.println("PamAudioFileManager: unable to open an AudioStream for " + file.getName() + " size: " + file.length());
}
return stream;
@@ -153,7 +153,7 @@ public class PamAudioFileManager {
}
/**
- * Get the audio file filter
+ * Get the audio file filter.
*
* @return the audio file filter.
*/
@@ -164,7 +164,7 @@ public class PamAudioFileManager {
/**
* Get the current audio file
*
- * @return a list oif the current audio loaders.
+ * @return a list of the current audio loaders.
*/
public ArrayList getAudioFileLoaders() {
return this.pamAudioFileTypes;
diff --git a/src/Acquisition/pamAudio/WavAudioFile.java b/src/Acquisition/pamAudio/WavAudioFile.java
index 77d07b54..e8789da0 100644
--- a/src/Acquisition/pamAudio/WavAudioFile.java
+++ b/src/Acquisition/pamAudio/WavAudioFile.java
@@ -254,7 +254,7 @@ public class WavAudioFile implements PamAudioFileLoader {
@Override
public AudioInputStream getAudioStream(File soundFile) {
- if (soundFile.exists() == false) return null;
+ if (soundFile.exists() == false || soundFile.length()<44) return null;
if (soundFile != null && isSoundFile(soundFile)) {
try {
return WavFileInputStream.openInputStream(soundFile);
@@ -262,7 +262,7 @@ public class WavAudioFile implements PamAudioFileLoader {
catch (UnsupportedAudioFileException | IOException e) {
e.printStackTrace();
// don't do anything and it will try the built in Audiosystem
- System.err.println("Could not open wav file: trying default audio stream: " + soundFile.getName());
+ System.err.println("Could not open wav file: trying default audio stream: " + soundFile.getName() + " " + soundFile.length());
}
}
try {
@@ -276,9 +276,24 @@ public class WavAudioFile implements PamAudioFileLoader {
}
- public boolean isSoundFile(File soundFile) {
+ public static boolean isSoundFile(File soundFile) {
String extension = FileUtils.getExtension(soundFile.getName());
- return (extension.equals(".wav"));
+ //2023-03-12 - for some reason this was .wav
+ return (extension.equals("wav"));
+ }
+
+
+ public static void main(String args[]) {
+
+ File wavFile = new File("E:\\SoundNet\\1chan_analysis\\pamguard\\67150826\\mf_wav\\20180529\\PAM_20180529_055114_000.wav");
+ try {
+ WavFileInputStream.openInputStream(wavFile);
+ System.out.println("Wav file opened successfully: " + isSoundFile(wavFile));
+
+ } catch (UnsupportedAudioFileException | IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
}
diff --git a/src/Acquisition/pamAudio/WavFileInputStream.java b/src/Acquisition/pamAudio/WavFileInputStream.java
index a0f2c0e5..fbb2126a 100644
--- a/src/Acquisition/pamAudio/WavFileInputStream.java
+++ b/src/Acquisition/pamAudio/WavFileInputStream.java
@@ -51,13 +51,15 @@ public class WavFileInputStream extends AudioInputStream {
if (wavHeader.readHeader(windowsFile) == false) {
throw new UnsupportedAudioFileException("Unsupprted wav file format in " + file.getName());
}
+
+
long nFrames = wavHeader.getDataSize() / wavHeader.getBlockAlign();
//29/03/2017 Found that the block align read from header was wrong in SoundTrap. This solves the problem and is still OK for normal
//wav files (this is in fact tha standard emthod for calculated blockalign)
int blockAlign = wavHeader.getNChannels() * (wavHeader.getBitsPerSample() / 8);
- //System.out.println("NFRAMES: " + nFrames + " "+ wavHeader.getDataSize() + " " + wavHeader.getBlockAlign() + " "+blockAlign );
+// System.out.println("NFRAMES: " + nFrames + " "+ wavHeader.getDataSize() + " " + wavHeader.getBlockAlign() + " "+blockAlign );
Encoding encoding = getEncoding(wavHeader.getFmtTag());
if (encoding == null) {
diff --git a/src/Acquisition/sud/SUDFileTime.java b/src/Acquisition/sud/SUDFileTime.java
index 92ac94ca..c0ccc16b 100644
--- a/src/Acquisition/sud/SUDFileTime.java
+++ b/src/Acquisition/sud/SUDFileTime.java
@@ -45,11 +45,17 @@ public class SUDFileTime {
// return Long.MIN_VALUE;
// }
// long t = sudMap.getFirstChunkTimeMillis();
+ System.out.println("Error getting time from SUD file: " + file==null? null : (file.getName() + " size: " + file.length() / (1024 * 1024) + " MB"));
+
long t = SudAudioInputStream.quickFileTime(file);
t=t/1000; //turn to milliseconds.
- if (t != 0) {
+ if (t > 0) {
sudTime = t;
}
+ else {
+ //an error has occurred
+ System.err.println("Error getting time from SUD file: " + file==null? null : (file.getName() + " size: " + file.length() / (1024 * 1024) + " MB"));
+ }
// sudAudioInputStream.addSudFileListener((chunkID, sudChunk)->{
// ChunkHeader chunkHead = sudChunk.chunkHeader;
diff --git a/src/Acquisition/sud/SUDNotificationManager.java b/src/Acquisition/sud/SUDNotificationManager.java
index 28bed217..b34758f2 100644
--- a/src/Acquisition/sud/SUDNotificationManager.java
+++ b/src/Acquisition/sud/SUDNotificationManager.java
@@ -59,7 +59,7 @@ public class SUDNotificationManager implements SUDNotificationHandler {
@Override
public void interpretNewFile(String newFile, SudAudioInputStream sudAudioStream) {
for (SUDNotificationHandler handler : handlers) {
- handler.interpretNewFile(newFile, sudAudioStream);
+ handler.interpretNewFile(newFile, sudAudioStream);
}
}
diff --git a/src/Array/ArrayManager.java b/src/Array/ArrayManager.java
index 6a605fff..3fa7a21a 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;
@@ -91,7 +87,7 @@ public class ArrayManager extends PamControlledUnit implements PamSettings, PamO
// private DepthControl depthControl;
- private ImportDataSystem> hydrophoneImportManager;
+ private ImportDataSystem hydrophoneImportManager;
private ImportDataSystem> streamerImportManager;
@@ -140,7 +136,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");
@@ -1054,12 +1050,17 @@ public class ArrayManager extends PamControlledUnit implements PamSettings, PamO
/**
* Rotate the hydrophone about the centre of it's streamer.
*/
- Hydrophone hydrophone = currentArray.getHiddenHydrophone(i);
+// Hydrophone hydrophone = currentArray.getHiddenHydrophone(i);
+ Hydrophone hydrophone = currentArray.getHydrophone(i, timeMillis);
+
+
+
if (hydrophone == null) {
continue;
}
PamVector hydrophoneVec = hydrophone.getVector();
PamVector hydrophoneErrorVec = hydrophone.getErrorVector();
+
if (streamerQuaternion != null) {
hydrophoneVec = PamVector.rotateVector(hydrophoneVec, streamerQuaternion);
hydrophoneErrorVec = PamVector.rotateVector(hydrophoneErrorVec, streamerQuaternion);
@@ -1111,7 +1112,7 @@ public class ArrayManager extends PamControlledUnit implements PamSettings, PamO
referencePoint = shipPos.getGpsData();
}
}
- if (referencePoint == null) {
+ if (referencePoint == null && MasterReferencePoint.getFixTime() != null && MasterReferencePoint.getLatLong() != null) {
// running out of options, so fall back to the master reference point, interpolated (probably has zero speeed)
referencePoint = new GpsData(MasterReferencePoint.getFixTime(), MasterReferencePoint.getLatLong()).getPredictedGPSData(timeMillis);
}
diff --git a/src/Array/Hydrophone.java b/src/Array/Hydrophone.java
index c2f82bd5..be3b11f8 100644
--- a/src/Array/Hydrophone.java
+++ b/src/Array/Hydrophone.java
@@ -203,7 +203,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
/**
* @return error on the hydrophone x coordinate.
*/
- protected double getdX() {
+ public double getdX() {
return getCoordinateError(0);
}
@@ -211,7 +211,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
* Set the error on the hydrophone x coordinate
* @param error error in metres.
*/
- protected void setdX(double error) {
+ public void setdX(double error) {
setCoordinateError(0, error);
}
@@ -219,7 +219,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
/**
* @return error on the hydrophone y coordinate.
*/
- protected double getdY() {
+ public double getdY() {
return getCoordinateError(1);
}
@@ -227,14 +227,14 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
* Set the error on the hydrophone y coordinate
* @param error error in metres.
*/
- protected void setdY(double error) {
+ public void setdY(double error) {
setCoordinateError(1, error);
}
/**
* @return error on the hydrophone depth coordinate.
*/
- protected double getdZ(){
+ public double getdZ(){
return getCoordinateError(2);
}
@@ -242,19 +242,19 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
* Set the error on the hydrophone z coordinate
* @param error error in metres.
*/
- protected void setdZ(double error) {
+ public void setdZ(double error) {
setCoordinateError(2, error);
}
- protected double getX() {
+ public double getX() {
return coordinate[0];
}
- protected void setX(double x) {
+ public void setX(double x) {
this.coordinate[0] = x;
}
- protected double getY() {
+ public double getY() {
return coordinate[1];
}
@@ -289,7 +289,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
return y2;
}
- protected void setY(double y) {
+ public void setY(double y) {
this.coordinate[1] = y;
}
@@ -297,7 +297,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
return coordinate[2];
}
- protected void setZ(double z) {
+ public void setZ(double z) {
this.coordinate[2] = z;
}
@@ -316,7 +316,7 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
// need to explicity create a new copy of the double[3] coordinate
// and the double[2] bandwidth
Hydrophone h = (Hydrophone) super.clone();
- h.setBandwidth(Arrays.copyOf(getBandwidth(), h.getBandwidth().length));
+ h.setBandwidth(getBandwidth() == null ? null : Arrays.copyOf(getBandwidth(), h.getBandwidth().length));
h.setCoordinate(Arrays.copyOf(getCoordinates(), 3));
h.setCoordinateErrors(Arrays.copyOf(getCoordinateErrors(), 3));
h.checkDepthInversion();
@@ -379,14 +379,14 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
/**
* @return Returns the iD.
*/
- protected int getID() {
+ public int getID() {
return iD;
}
/**
* @param id The iD to set.
*/
- protected void setID(int id) {
+ public void setID(int id) {
iD = id;
}
//
@@ -427,11 +427,11 @@ public class Hydrophone implements Serializable, Cloneable, ManagedParameters {
this.symbol = symbol;
}
- protected int getStreamerId() {
+ public int getStreamerId() {
return streamerId;
}
- protected void setStreamerId(int streamerId) {
+ public void setStreamerId(int streamerId) {
this.streamerId = streamerId;
}
diff --git a/src/Array/HydrophoneDataBlock.java b/src/Array/HydrophoneDataBlock.java
index 43ec7fb3..a5c17785 100644
--- a/src/Array/HydrophoneDataBlock.java
+++ b/src/Array/HydrophoneDataBlock.java
@@ -5,6 +5,7 @@ import java.util.ListIterator;
import GPS.NavDataSynchronisation;
import pamScrollSystem.ViewLoadObserver;
import PamController.PamController;
+import PamUtils.PamCalendar;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import PamguardMVC.dataOffline.OfflineDataLoadInfo;
@@ -68,6 +69,11 @@ public class HydrophoneDataBlock extends PamDataBlock {
@Override
public boolean loadViewerData(OfflineDataLoadInfo offlineDataLoadInfo,
ViewLoadObserver loadObserver) {
+
+// if (offlineDataLoadInfo!=null) {
+// System.out.print("Load Hydrophones: " + ((offlineDataLoadInfo.getEndMillis() - offlineDataLoadInfo.getStartMillis())/1000/60/60 + " hours"));
+// System.out.print("From: " +PamCalendar.formatDateTime(offlineDataLoadInfo.getStartMillis()) + " to " + PamCalendar.formatDateTime(offlineDataLoadInfo.getEndMillis()));
+// }
/**
* Always put in default data units at time zero.
*/
@@ -103,6 +109,7 @@ public class HydrophoneDataBlock extends PamDataBlock {
}
unit = listIterator.previous();
difference = Math.abs(startTime - unit.getTimeMilliseconds());
+
while (listIterator.hasPrevious()) {
preceedingUnit = listIterator.previous();
if (preceedingUnit.getHydrophone().getID()!=ihydrophone) {
@@ -110,6 +117,7 @@ public class HydrophoneDataBlock extends PamDataBlock {
}
newdifference = Math.abs(startTime- preceedingUnit.getTimeMilliseconds());
if (newdifference > difference) {
+// System.out.println("Hydrophone datablock: newDifference: " + newdifference + " " + unit.getHydrophone().getZ());
return unit;
}
else {
diff --git a/src/Array/HydrophoneElementDialog.java b/src/Array/HydrophoneElementDialog.java
index a3f482cd..76eabacd 100644
--- a/src/Array/HydrophoneElementDialog.java
+++ b/src/Array/HydrophoneElementDialog.java
@@ -397,6 +397,8 @@ public class HydrophoneElementDialog extends PamDialog {
dz.setText(null);
}
}
+
+
boolean getParams() {
double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();
diff --git a/src/Array/PamArray.java b/src/Array/PamArray.java
index a116108d..8bc8fd8d 100644
--- a/src/Array/PamArray.java
+++ b/src/Array/PamArray.java
@@ -39,6 +39,7 @@ import PamModel.parametermanager.PamParameterSet.ParameterSetType;
import PamModel.parametermanager.PrivatePamParameterData;
import PamUtils.LatLong;
import PamUtils.PamArrayUtils;
+import PamUtils.PamCalendar;
import PamView.PamSymbol;
import PamguardMVC.ChannelIterator;
import PamguardMVC.PamConstants;
@@ -265,7 +266,9 @@ public class PamArray implements Serializable, Cloneable, ManagedParameters {
}
protected Hydrophone getHydrophone(int iPhone, long timeMilliseconds) {
- // Debug.println("PAMArray: Get hydrophone coords: " + timeMilliseconds + " iPhone: " + iPhone);
+// System.out.println("PAMArray: Get hydrophone coords: " + PamCalendar.formatDateTime(timeMilliseconds) + " iPhone: " + iPhone);
+
+
if (hydrophoneInterpolation == ORIGIN_USE_LATEST) {
return getHydrophone(iPhone);
}
@@ -275,12 +278,14 @@ public class PamArray implements Serializable, Cloneable, ManagedParameters {
//FIXME - for some reason the above lines were always returning the first hydrophone in the datablock ^
HydrophoneDataUnit hdu = ArrayManager.getArrayManager().getHydrophoneDataBlock().getClosestHydrophone(timeMilliseconds, iPhone);
+
+// System.out.println("PAMArray: hdu: " + hdu + " " + (hdu==null? null: PamCalendar.formatDateTime(hdu.getTimeMilliseconds()) + " Z" + hdu.getHydrophone().getdZ()));
if (hdu != null) {
- // Debug.println("PAMArray: found unit: " + hdu.getTimeMilliseconds());
- // long firstTime = ArrayManager.getArrayManager().getHydrophoneDataBlock().getFirstUnit().getTimeMilliseconds();
- // long lastTime = ArrayManager.getArrayManager().getHydrophoneDataBlock().getLastUnit().getTimeMilliseconds();
- // Debug.println("PAMArray: found unit: " + firstTime + " " + lastTime + " no: units: " + ArrayManager.getArrayManager().getHydrophoneDataBlock().getUnitsCount());
+// System.out.println("PAMArray: found unit: " + hdu.getTimeMilliseconds());
+// long firstTime = ArrayManager.getArrayManager().getHydrophoneDataBlock().getFirstUnit().getTimeMilliseconds();
+// long lastTime = ArrayManager.getArrayManager().getHydrophoneDataBlock().getLastUnit().getTimeMilliseconds();
+// System.out.println("PAMArray: found unit: " + firstTime + " " + lastTime + " no: units: " + ArrayManager.getArrayManager().getHydrophoneDataBlock().getUnitsCount());
// TODO should maybe do something here to average out two hydrophones if interpolation option is selected.
return hdu.getHydrophone();
}
@@ -1305,7 +1310,6 @@ public class PamArray implements Serializable, Cloneable, ManagedParameters {
* @return
*/
public int addStreamer(Streamer streamer) {
-
synchronized (streamers) {
streamers.add(streamer);
checkStreamerIndexes();
diff --git a/src/Array/Streamer.java b/src/Array/Streamer.java
index 7910da0f..f7fad355 100644
--- a/src/Array/Streamer.java
+++ b/src/Array/Streamer.java
@@ -571,7 +571,7 @@ public class Streamer implements Serializable, Cloneable, ManagedParameters {
/**
* Make a streamer data unit and add it to the data block.
*/
- protected void makeStreamerDataUnit() {
+ public void makeStreamerDataUnit() {
StreamerDataUnit sdu = new StreamerDataUnit(PamCalendar.getTimeInMillis(), this);
ArrayManager.getArrayManager().getStreamerDatabBlock().addPamData(sdu);
}
@@ -667,8 +667,8 @@ public class Streamer implements Serializable, Cloneable, ManagedParameters {
*/
@Override
public String toString() {
- return super.toString() + "; OriginSettings: " + getOriginSettings().toString() + "," + getHydrophoneOrigin().getOriginSettings().toString() +
- "; Locator " + getLocatorSettings().toString();
+ return super.toString() + "; OriginSettings: " + getOriginSettings()==null ? "null" : getOriginSettings().toString() + "," + getHydrophoneOrigin().getOriginSettings().toString() +
+ "; Locator " + getLocatorSettings()==null ? "null" : getLocatorSettings().toString();
}
public static Streamer getAverage(Streamer sd1,
diff --git a/src/Array/StreamerDialog.java b/src/Array/StreamerDialog.java
index 73a81469..52bea18c 100644
--- a/src/Array/StreamerDialog.java
+++ b/src/Array/StreamerDialog.java
@@ -318,7 +318,7 @@ public class StreamerDialog extends PamDialog {
PamDialog.setDoubleValue(heading, defaultStreamer.getHeading(), "%3.1f");
PamDialog.setDoubleValue(pitch, defaultStreamer.getPitch(), "%3.1f");
PamDialog.setDoubleValue(roll, defaultStreamer.getRoll(), "%3.1f");
-
+
interpolationPanel.setSelection(currentArray.getOriginInterpolation());
ArraySensorFieldType[] sensorFields = ArraySensorFieldType.values();
@@ -376,6 +376,9 @@ public class StreamerDialog extends PamDialog {
defaultStreamer.setStreamerName(streamerName.getText());
int im = interpolationPanel.getSelection();
+
+ System.out.println("GetParams: INTERPOLATION SELECTION: " + currentArray.getOriginInterpolation());
+
if (im < 0) {
return showWarning("Invalid interpolation selection");
}
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/Array3DPane.java b/src/Array/layoutFX/Array3DPane.java
new file mode 100644
index 00000000..f7b9c8b4
--- /dev/null
+++ b/src/Array/layoutFX/Array3DPane.java
@@ -0,0 +1,586 @@
+package Array.layoutFX;
+
+import pamViewFX.fxNodes.PamBorderPane;
+
+
+import java.util.ArrayList;
+import org.fxyz3d.geometry.Point3D;
+import org.fxyz3d.shapes.composites.PolyLine3D;
+
+import Array.Hydrophone;
+import Array.PamArray;
+import Array.Streamer;
+import javafx.event.EventHandler;
+import javafx.scene.AmbientLight;
+import javafx.scene.DepthTest;
+import javafx.scene.Group;
+import javafx.scene.Node;
+import javafx.scene.PerspectiveCamera;
+import javafx.scene.SceneAntialiasing;
+import javafx.scene.SubScene;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.input.PickResult;
+import javafx.scene.input.ScrollEvent;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.PhongMaterial;
+import javafx.scene.shape.Box;
+import javafx.scene.shape.Shape3D;
+import javafx.scene.shape.Sphere;
+import javafx.scene.text.Text;
+import javafx.scene.transform.Rotate;
+import javafx.scene.transform.Translate;
+
+/**
+ * Create a 3D visualisation of the array.
+ *
+ PAMGUARD co-rdinate system is
+ *
+ * x points right
+ *
+ * y points north or into the screen
+ *
+ * z is height and points up
+ *
+ * This is different from the JavAFX 3D system in which
+ *
+ * x points right
+ *
+ * y points down
+ *
+ * z points into the screen
+ *
+ * Thus the source code for this class is a little bit more complex. By convention the co-ordinate system is only changed for display purposes and remains
+ * in PAMGUARD format throughout the rest of code.
+ * @author Jamie Macaulay
+ *
+ */
+public class Array3DPane extends PamBorderPane {
+
+ public static final Color DEFAULT_HYDRO_COL = Color.RED;
+
+ // private static final Color DEFAULT_SENSOR_COL = Color.LIMEGREEN;
+
+ private double scaleFactor=20;
+
+ private double axisSize=10*scaleFactor;
+
+ //keep track of mouse positions
+ double mousePosX;
+ double mousePosY;
+ double mouseOldX;
+ double mouseOldY;
+ double mouseDeltaX;
+ double mouseDeltaY;
+
+ /**
+ * This is the group which rotates
+ */
+ Group root3D;
+
+ /**
+ * Group which holds array shapes.
+ */
+ Group arrayGroup;
+
+ /**
+ * Group which holds axis and other non changing bits.
+ */
+ Group axisGroup;
+
+ /**
+ * The camera transforms
+ */
+ private Rotate rotateY;
+ private Rotate rotateX;
+ private Translate translate;
+
+ /**
+ * The size of the hydrophone for the 3D display.
+ */
+ private double hydrophoneSize = 0.5;
+
+ /**
+ * Holds a list of hydrophone spheres
+ */
+ private ArrayList hydrophonesSpheres = new ArrayList();
+
+ /**
+ * Allow rotation
+ */
+ private boolean allowRotate = true;
+
+ private Text xText;
+
+ private Text yText;
+
+ private Text zText;
+
+ private Box yAxis;
+
+ private Shape3D ySphere;
+
+
+ public Array3DPane(){
+
+ // Create and position camera
+ PerspectiveCamera camera = new PerspectiveCamera(true);
+ camera.setFarClip(20000);
+ camera.setNearClip(0.1);
+// camera.setDepthTest(DepthTest.ENABLE);
+ camera.getTransforms().addAll (
+ rotateY=new Rotate(-45, Rotate.Y_AXIS),
+ rotateX=new Rotate(-45, Rotate.X_AXIS),
+ translate=new Translate(0, 0, -2000));
+
+ //create main 3D group
+ root3D=new Group();
+ axisGroup=buildAxes(axisSize); //create axis group
+ arrayGroup=new Group();
+
+ root3D.getChildren().add(arrayGroup);
+ root3D.getChildren().add(axisGroup);
+
+
+ AmbientLight light = new AmbientLight();
+ light.setColor(Color.WHITE);
+ Group lightGroup = new Group();
+ lightGroup.getChildren().add(light);
+ root3D.getChildren().add(lightGroup);
+
+ //Use a SubScene to mix 3D and 2D stuff.
+ //note- make sure depth buffer in sub scene is enabled.
+ SubScene subScene = new SubScene(root3D, 500,400, true, SceneAntialiasing.BALANCED);
+ subScene.widthProperty().bind(this.widthProperty());
+ subScene.heightProperty().bind(this.heightProperty());
+ subScene.setDepthTest(DepthTest.ENABLE);
+
+ subScene.setOnMouseClicked((MouseEvent me) -> {
+ mousePosX = me.getSceneX();
+ mousePosY = me.getSceneY();
+ PickResult pr = me.getPickResult();
+ // System.out.println("Picked something sphere: " + pr);
+
+ //clear selected radius
+ for (HydrophoneSphere sphere : hydrophonesSpheres) {
+ sphere.setRadius(hydrophoneSize*scaleFactor);
+ }
+
+ if(pr!=null && pr.getIntersectedNode() != null && pr.getIntersectedNode() instanceof Sphere){
+
+ //make the selected sphere slightly larger
+ HydrophoneSphere s = (HydrophoneSphere) pr.getIntersectedNode();
+ s.setRadius(hydrophoneSize*scaleFactor*1.2);
+
+ hydrophoneSelected(s.getHydrophone());
+
+ // System.out.println("Picked a sphere: " + pr);
+ // distance=pr.getIntersectedDistance();
+ // s = (Sphere) pr.getIntersectedNode();
+ // isPicking=true;
+ // vecIni = unProjectDirection(mousePosX, mousePosY, scene.getWidth(),scene.getHeight());
+ }
+ });
+
+ //note the fill is actually quite important because if you don't have it mouse rotations etc
+ //onyl work if you select a 3D shape
+ subScene.setFill(Color.TRANSPARENT);
+ subScene.setCamera(camera);
+
+ //handle mouse events for sub scene
+ handleMouse(subScene);
+
+ resetView();
+
+ //create new group to add sub scene to
+ Group group = new Group();
+ group.getChildren().add(subScene);
+
+ //add group to window.
+ this.setCenter(group);
+ this.setDepthTest(DepthTest.ENABLE);
+
+ }
+
+ /**
+ * Called whenever a hydrophone is selected.
+ * @param hydrophone - the selected hydrophone.
+ */
+ public void hydrophoneSelected(Hydrophone hydrophone) {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * Create a 3D axis with default colours set.
+ * @param- size of the axis
+ */
+ public Group buildAxes(double axisSize) {
+ return buildAxes( axisSize,Color.RED, Color.RED,
+ Color.GREEN, Color.GREEN,
+ Color.BLUE, Color.BLUE,
+ Color.WHITE);
+ }
+
+
+ /**
+ * Create a 3D axis.
+ * @param- size of the axis
+ */
+ public Group buildAxes(double axisSize, Color xAxisDiffuse, Color xAxisSpectacular,
+ Color yAxisDiffuse, Color yAxisSpectacular,
+ Color zAxisDiffuse, Color zAxisSpectacular,
+ Color textColour) {
+
+ Group axisGroup=new Group();
+
+ double length = 2d*axisSize;
+ double width = axisSize/100d;
+ double radius = 2d*axisSize/100d;
+
+
+ final PhongMaterial redMaterial = new PhongMaterial();
+ redMaterial.setDiffuseColor(xAxisDiffuse);
+ redMaterial.setSpecularColor(xAxisSpectacular);
+ final PhongMaterial greenMaterial = new PhongMaterial();
+ greenMaterial.setDiffuseColor(yAxisDiffuse);
+ greenMaterial.setSpecularColor( yAxisSpectacular);
+ final PhongMaterial blueMaterial = new PhongMaterial();
+ blueMaterial.setDiffuseColor(zAxisDiffuse);
+ blueMaterial.setSpecularColor(zAxisSpectacular);
+
+ xText=new Text("x");
+ xText.setStyle("-fx-font: 20px Tahoma; -fx-fill: white;");
+ xText.setFill(textColour);
+ xText.setStroke(textColour);
+
+ yText=new Text("z");
+ yText.setStyle("-fx-font: 20px Tahoma; -fx-fill: white;");
+ yText.setFill(textColour);
+ yText.setStroke(textColour);
+
+ zText=new Text("y");
+ zText.setStyle("-fx-font: 20px Tahoma; -fx-fill: white;");
+ zText.setFill(textColour);
+ zText.setStroke(textColour);
+
+ xText.setTranslateX(axisSize+5);
+ xText.setTranslateZ(1); //dunno why but shifting a little in z is required to see colour
+
+ yText.setTranslateY(-(axisSize+5));
+ yText.setTranslateZ(1); //dunno why but shifting a little in z is required to see colour
+
+ zText.setTranslateZ(axisSize+5);
+
+ Sphere xSphere = new Sphere(radius);
+ ySphere = new Sphere(radius);
+ Sphere zSphere = new Sphere(radius);
+ xSphere.setMaterial(redMaterial);
+ ySphere.setMaterial(greenMaterial);
+ zSphere.setMaterial(blueMaterial);
+
+ xSphere.setTranslateX(axisSize);
+ ySphere.setTranslateY(-axisSize);
+ zSphere.setTranslateZ(axisSize);
+
+ Box xAxis = new Box(length, width, width);
+ yAxis = new Box(width, length, width);
+ Box zAxis = new Box(width, width, length);
+ xAxis.setMaterial(redMaterial);
+ yAxis.setMaterial(greenMaterial);
+ zAxis.setMaterial(blueMaterial);
+
+ axisGroup.getChildren().addAll(xAxis, yAxis, zAxis);
+ axisGroup.getChildren().addAll(xText, yText, zText);
+ axisGroup.getChildren().addAll(xSphere, ySphere, zSphere);
+
+
+ return axisGroup;
+ }
+
+
+ private void handleMouse(SubScene scene) {
+
+ scene.setOnMousePressed(new EventHandler() {
+
+ @Override public void handle(MouseEvent me) {
+ mousePosX = me.getSceneX();
+ mousePosY = me.getSceneY();
+ mouseOldX = me.getSceneX();
+ mouseOldY = me.getSceneY();
+ }
+ });
+
+ scene.setOnScroll(new EventHandler() {
+ @Override public void handle(ScrollEvent event) {
+ // System.out.println("Scroll Event: "+event.getDeltaX() + " "+event.getDeltaY());
+ translate.setZ(translate.getZ()+ event.getDeltaY() *0.001*translate.getZ()); // +
+ }
+ });
+
+
+ scene.setOnMouseDragged(new EventHandler() {
+
+
+ @Override
+ public void handle(MouseEvent me) {
+ mouseOldX = mousePosX;
+ mouseOldY = mousePosY;
+ mousePosX = me.getSceneX();
+ mousePosY = me.getSceneY();
+ mouseDeltaX = (mousePosX - mouseOldX);
+ mouseDeltaY = (mousePosY - mouseOldY);
+
+ double modifier = 1.0;
+ double modifierFactor = 0.1;
+
+ if (me.isControlDown()) {
+ modifier = 0.1;
+ }
+ if (me.isShiftDown()) {
+ modifier = 10.0;
+ }
+ if (me.isPrimaryButtonDown() && allowRotate) {
+ rotateY.setAngle(rotateY.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0); // +
+ rotateX.setAngle(rotateX.getAngle() - mouseDeltaY * modifierFactor * modifier * 2.0); // -
+
+// System.out.println("Rotation: x: " + rotateX.getAngle() + " y: " + rotateY.getAngle());
+ }
+ if (me.isSecondaryButtonDown()) {
+ translate.setX(translate.getX() -mouseDeltaX * modifierFactor * modifier * 5);
+ translate.setY(translate.getY() - mouseDeltaY * modifierFactor * modifier * 5); // +
+ }
+
+
+ }
+ });
+ }
+
+ /**
+ * Draw the hydrophone array.
+ * @param array - the hydrophone array to draw.
+ */
+ public void drawArray(PamArray array) {
+
+ // System.out.println("DRAW ARRAY: " + array);
+
+ //clear the array
+ arrayGroup.getChildren().removeAll(arrayGroup.getChildren());
+
+ ArrayList hydrophones = array.getHydrophoneArray();
+
+ //draw hydrophones
+ HydrophoneSphere sphere;
+ Streamer streamer;
+ hydrophonesSpheres.clear();
+ for (int i=0; i streamerPoints=new ArrayList();
+ //now plot a line from the streamer to the hydrophone
+ Point3D newPoint;
+
+ newPoint=new Point3D(x*scaleFactor, z*scaleFactor, y*scaleFactor);
+ streamerPoints.add(newPoint);
+
+ newPoint =new Point3D(streamer.getCoordinate(0)*scaleFactor, -streamer.getCoordinate(2)*scaleFactor, streamer.getCoordinate(1)*scaleFactor);
+ streamerPoints.add(newPoint);
+
+ //System.out.println("Streamer points: " + streamerPoints.size());
+
+ PolyLine3D polyLine3D=new PolyLine3D(streamerPoints, 4f, Color.DODGERBLUE);
+ arrayGroup.getChildren().add(polyLine3D);
+ }
+ }
+
+
+ private class HydrophoneSphere extends Sphere {
+
+ Hydrophone hydrophone;
+
+ public Hydrophone getHydrophone() {
+ return hydrophone;
+ }
+
+
+
+ public void setHydrophone(Hydrophone hydrophone) {
+ this.hydrophone = hydrophone;
+ }
+
+ public HydrophoneSphere() {
+ super();
+ }
+
+ public HydrophoneSphere(double radius) {
+ super(radius);
+ }
+
+ }
+
+ /**
+ * Sets the pane to show hydrophones in 2D or 3D.
+ * @param set3D - true to set to 3D
+ */
+ public void set3D(boolean set3D) {
+
+ double textRotation =0;
+
+ if (set3D) {
+ allowRotate=true;
+ xText.setRotate(0);
+ rotateY.setAngle(-45);
+ rotateX.setAngle(-45);
+ }
+ else {
+ allowRotate=false;
+ rotateY.setAngle(0);
+ rotateX.setAngle(270);
+ textRotation=-90;
+ }
+
+ //confusing because the yaxis is the z axis in JavaFX...
+ yText.setVisible(set3D);
+ yAxis.setVisible(set3D);
+ ySphere.setVisible(set3D);
+
+
+ xText.setRotate(textRotation);
+ xText.setRotationAxis(new javafx.geometry.Point3D(1,0,0));
+
+ yText.setRotationAxis(new javafx.geometry.Point3D(1,0,0));
+ yText.setRotate(textRotation);
+
+ zText.setRotationAxis(new javafx.geometry.Point3D(1,0,0));
+ zText.setRotate(textRotation);
+
+
+ }
+
+ /**
+ * Reset to the defulat view.
+ */
+ public void resetView() {
+
+ translate.setX(0);
+ translate.setY(0);
+ translate.setZ( -2000);
+
+ if (allowRotate) {
+ rotateY.setAngle(-45);
+ rotateX.setAngle(-45);
+ }
+ }
+
+ // /**
+ // * Draw the entire array
+ // * @param pos - hydrophone and streamer positions in the same co-ordinate frame as the reference frame.
+ // */
+ // public void drawArrays(ArrayList> pos){
+ //
+ // arrayGroup.getChildren().removeAll(arrayGroup.getChildren());
+ //
+ // if (pos==null){
+ // System.err.println("Array3DPane: Hydrophone positions are null");
+ // return;
+ // }
+ //
+ // for (int i=0; i< pos.size(); i++){
+ // for (int j=0; j streamerPoints;
+ //
+ // for (int i=0; i();
+ // for (int j=0; j
+ *
+ */
public class ArraySettingsPane extends SettingsPane{
+ /**
+ * Minimum size of the 3D pane.
+ */
+ private static final double MIN_3D_WIDTH = 450;
+
+ /**
+ * Minimum height of the 3D pane.
+ */
+ private static final double MIN_3D_HEIGHT = 600;
+
+ /**
+ * Pane for adding or removing streamers.
+ */
+ private StreamersPane streamerPane;
+
+ private PamBorderPane mainPane;
+
+ /**
+ * Pane for adding or removing hydrophones.
+ */
+ private HydrophonesPane hydrophonePane;
+
+ // private Pane holder;
+
+ private Label hydrophoneLabel;
+
+ /**
+ * Pane which shows a 3D representation of the hydrophone array.
+ */
+ private Array3DPane array3DPane;
+
+ private PropogationPane propogationPane;
+
+ private Label recivierDiagramLabel;
+
+ /**
+ * Pane with controls to change speed of sound.
+ */
+ private SettingsPane environmentalPane;
+
+ private FileChooser fileChooser;
+
+ //a copy of the current array
+ private PamArray currentArray;
+
public ArraySettingsPane() {
super(null);
- // TODO Auto-generated constructor stub
+
+ mainPane=new PamBorderPane();
+
+ mainPane.setCenter(createArrayPane());
+ // mainPane.setStyle("-fx-background-color: red;");
+ mainPane.setMaxWidth(Double.MAX_VALUE);
+ mainPane.setMinWidth(1100);
+ mainPane.setStyle("-fx-padding: 0,0,0,0");
+
+
+ recivierDiagramLabel = new Label("Hydrophone Diagram");
+ PamGuiManagerFX.titleFont1style(recivierDiagramLabel);
+ recivierDiagramLabel.setPadding(new Insets(5,5,5,5));
+
+ Label environmentLabel = new Label("Environment");
+ PamGuiManagerFX.titleFont1style(environmentLabel);
+ environmentLabel.setPadding(new Insets(0,0,5,0)); //little more space under this label
+
+ environmentalPane = createEnvironmentPane();
+
+ PamVBox rightPane = new PamVBox();
+ rightPane.setSpacing(5);
+
+ Pane hydrophone3DPane = create3DPane();
+ rightPane.getChildren().addAll(recivierDiagramLabel, hydrophone3DPane, environmentLabel, new PamBorderPane(environmentalPane.getContentNode()));
+ VBox.setVgrow(hydrophone3DPane, Priority.ALWAYS);
+
+ mainPane.setRight(rightPane);
+
+ // streamerPane.getStreamerTable().getItems().addListener((ListChangeListener super StreamerProperty>) c->{
+ // //the streamer table has changed and so the streamer needs changed
+ // System.out.println("Streamer Changed!!!");
+ // });
+
+ streamerPane.addStreamerListener((x,y)->{
+ PamArray array = getParams(new PamArray("temp_array: ", null)) ;
+ System.out.println("Streamer changed!");
+ array3DPane.drawArray(array);
+ });
+
+ hydrophonePane.addStreamerListener((x,y)->{
+ PamArray array = getParams(new PamArray("temp_array: ", null)) ;
+ System.out.println("Hydrophone changed!" + array.getHydrophoneCount());
+ array3DPane.drawArray(array);
+ });
+
+ // mainPane.setMinWidth(800);
+
+ // mainPane.setCenter(createArrayPane());
+ //
+ // mainPane.getAdvPane().setCenter(new Label("Advanced Settings"));
+
+
+ // //mainPane.getFront().setStyle("-fx-background-color: grey;");
+ // mainPane.setStyle("-fx-background-color: red;");
+ //
+ // FlipPane aflipPane = new FlipPane();
+ // aflipPane.setStyle("-fx-background-color: red;");
+ //
+ // PamHBox stackPane = new PamHBox();
+ // stackPane.setStyle("-fx-background-color: red;");
+ //
+ // Button button = new Button();
+ // button.setOnAction((action)->{
+ // System.out.println(" 1 " + stackPane.getPadding());
+ // System.out.println(" 2 " +PamBorderPane.getMargin(stackPane));
+ // System.out.println(" 3 " + holder.getPadding());
+ // });
+ //
+ // stackPane.getChildren().add(button);
+ //
+ //
+ // mainPane.setPadding(new Insets(0,0,0,0));
+
+
+ // holder = new StackPane();
+ // holder.getChildren().add(mainPane);
+ // holder.setStyle("-fx-padding: 0,0,0,0");
+
}
+ private Pane create3DPane() {
+
+ StackPane stackPane = new StackPane();
+ this.array3DPane = new HydrophoneArray3DPane();
+
+ //important because the 3D pane has not default size
+ stackPane.setMinWidth(MIN_3D_WIDTH);
+ stackPane.setMinHeight(MIN_3D_HEIGHT);
+
+ // stackPane.prefHeightProperty().bind(mainPane.heightProperty().subtract(100));
+
+ stackPane.getChildren().add(array3DPane);
+
+
+ //add buttons
+ ToggleButton b1 = new ToggleButton("2D");
+ ToggleButton b2 = new ToggleButton("3D");
+
+ b1.setOnAction((action)->{
+ array3DPane.set3D(false);
+ });
+
+ b2.setOnAction((action)->{
+ array3DPane.set3D(true);
+ });
+
+
+ SegmentedButton segmentedButton = new SegmentedButton();
+ segmentedButton.getButtons().addAll(b1, b2);
+ segmentedButton.setPadding(new Insets(5,5,5,5));
+ segmentedButton.setMinWidth(100);
+
+ StackPane.setAlignment(segmentedButton, Pos.TOP_RIGHT);
+ stackPane.getChildren().add(segmentedButton);
+
+
+ final ContextMenu contextMenu = new ContextMenu();
+ final MenuItem item1 = new MenuItem("Reset");
+ item1.setOnAction((action)->{
+ array3DPane.resetView();
+ });
+ contextMenu.getItems().add(item1);
+ segmentedButton.setContextMenu(contextMenu);
+
+// stackPane.setOnContextMenuRequested(e ->
+// contextMenu.show(stackPane, e.getScreenX(), e.getScreenY()));
+
+
+ b2.setSelected(true);
+
+ return stackPane;
+ }
+
+ /**
+ * Create the environment pane.
+ * @return the environment pane.
+ */
+ private SettingsPane createEnvironmentPane() {
+ this.propogationPane = new PropogationPane();
+ return propogationPane;
+ }
+
+ /**
+ * Create the main pane.
+ * @return the main array pane.
+ */
+ private Pane createArrayPane() {
+
+ Label arrayLabel = new Label("Array");
+ arrayLabel.setPadding(new Insets(5,5,5,5));
+ PamGuiManagerFX.titleFont1style(arrayLabel);
+
+ //holds the array label and also some button for import and export.
+ PamHBox arrayImportExportBox = new PamHBox();
+ arrayImportExportBox.setSpacing(5);
+ arrayImportExportBox.setAlignment(Pos.CENTER_LEFT);
+ arrayImportExportBox.setPadding(new Insets(5,0,0,0));
+
+ fileChooser = new FileChooser();
+ fileChooser.setTitle("Open Resource File");
+ fileChooser.getExtensionFilters().addAll(
+ new ExtensionFilter("PAMGuard Array Files", "*.paf"));
+
+ PamButton importButton = new PamButton("Import...");
+ importButton.setOnAction((action)->{
+ importArray();
+ });
+ importButton.setGraphic(PamGlyphDude.createPamIcon("mdi2f-file-import", PamGuiManagerFX.iconSize));
+ importButton.setTooltip(new Tooltip("Import array settings from a .pgaf file"));
+
+ PamButton exportButton = new PamButton("Export...");
+ exportButton.setOnAction((action)->{
+ exportArray();
+ });
+ exportButton.setGraphic(PamGlyphDude.createPamIcon("mdi2f-file-export", PamGuiManagerFX.iconSize));
+ exportButton.setTooltip(new Tooltip("Export array settings to a .pgaf file"));
+
+ //balnk region to make it look nicer
+ Region blank = new Region();
+ blank.setPrefWidth(70);
+
+ arrayImportExportBox.getChildren().addAll(importButton, exportButton, blank);
+
+ PamBorderPane titleHolder = new PamBorderPane();
+ titleHolder.setLeft(arrayLabel);
+ titleHolder.setRight(arrayImportExportBox);
+
+ //the streamer pane for changing streamer settings.
+ streamerPane = new StreamersPane();
+ streamerPane.setMaxWidth(Double.MAX_VALUE);
+
+ hydrophoneLabel = new Label("Hydrophones");
+ PamGuiManagerFX.titleFont1style(hydrophoneLabel);
+ hydrophoneLabel.setPadding(new Insets(5,5,5,5));
+
+ hydrophonePane = new HydrophonesPane();
+ hydrophonePane.setMaxWidth(Double.MAX_VALUE);
+
+ // PamButton advancedButton = new PamButton();
+ // advancedButton.setOnAction((action)->{
+ // mainPane.flipToBack();
+ // });
+ // advancedButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-cog"));
+
+ // PamHBox advancedPane = new PamHBox();
+ // advancedPane.setSpacing(5);
+ // advancedPane.setAlignment(Pos.CENTER_RIGHT);
+ // advancedPane.getChildren().addAll(new Label("Advanced"), advancedButton);
+
+ PamVBox vBox = new PamVBox();
+ vBox.setSpacing(5);
+ vBox.getChildren().addAll(titleHolder, streamerPane, hydrophoneLabel,
+ hydrophonePane);
+
+ return vBox;
+ }
+
+ /**
+ * Select a file to export array settings to.
+ */
+ private void exportArray() {
+ File file = fileChooser.showSaveDialog(getFXWindow());
+ if (file==null) return;
+ PamArray pamArray = getParams(new PamArray("saved_array: ", null));
+ boolean isSaved = ArrayManager.saveArrayToFile(pamArray);
+ if (isSaved==false) {
+ PamDialogFX.showError("Unable to save the array file to \n" + file.toString());
+ }
+ }
+
+ /**
+ * Select a file to import array settings
+ */
+ private void importArray() {
+ File file = fileChooser.showOpenDialog(getFXWindow());
+ if (file==null) return;
+ PamArray pamArray = ArrayManager.loadArrayFromFile(file.getPath());
+ this.setParams(pamArray);
+ }
+
+ /**
+ * Set correct text for the receiver in the current medium (e.g. air or water);
+ */
+ private void setReceieverLabels() {
+ hydrophonePane.setRecieverLabels();
+ streamerPane.setRecieverLabels();
+
+ hydrophoneLabel.setText(PamController.getInstance().getGlobalMediumManager().getRecieverString(true) + "s");
+ recivierDiagramLabel.setText(PamController.getInstance().getGlobalMediumManager().getRecieverString(true) + " diagram");
+ // if (singleInstance!=null) {
+ // singleInstance.setTitle("Pamguard "+ PamController.getInstance().getGlobalMediumManager().getRecieverString(false) +" array");
+ // }
+ }
+
+
@Override
- public PamArray getParams(PamArray currParams) {
- // TODO Auto-generated method stub
- return null;
+ public PamArray getParams(PamArray currParams) {
+
+ if (currParams==null) currParams = this.currentArray;
+
+ currParams = streamerPane.getParams(currParams);
+ currParams = hydrophonePane.getParams(currParams);
+ currParams.setHydrophoneInterpolation(hydrophonePane.getHydrophoneInterp());
+ currParams = environmentalPane.getParams(currParams);
+ // System.out.println("Array settings pane: No. streamers: " + currParams.getStreamerCount());
+ return currParams;
}
@Override
public void setParams(PamArray input) {
- // TODO Auto-generated method stub
-
+ this.currentArray = input.clone();
+ // System.out.println("Hydrophone array is: "+ input);
+ setReceieverLabels();
+ hydrophonePane.setParams(input);
+ streamerPane.setParams(input);
+ environmentalPane.setParams(input);
+
+ //draw the array
+ array3DPane.drawArray(input);
}
@Override
public String getName() {
- // TODO Auto-generated method stub
return "Array Parameters";
}
@Override
public Node getContentNode() {
- // TODO Auto-generated method stub
- return new Label("TODO: The Array Manager needs an FX GUI");
+
+ return mainPane;
}
@Override
public void paneInitialized() {
// TODO Auto-generated method stub
-
+
+ }
+
+ private class HydrophoneArray3DPane extends Array3DPane {
+
+ @Override
+ public void hydrophoneSelected(Hydrophone hydrophone) {
+ hydrophonePane.selectHydrophone(hydrophone);
+ }
+
}
}
diff --git a/src/Array/layoutFX/DefaultHydrophone.java b/src/Array/layoutFX/DefaultHydrophone.java
new file mode 100644
index 00000000..5d571775
--- /dev/null
+++ b/src/Array/layoutFX/DefaultHydrophone.java
@@ -0,0 +1,58 @@
+package Array.layoutFX;
+
+/**
+ * Default hydrophone parameters.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public enum DefaultHydrophone {
+
+ SoundTrap600HF("SoundTrap 600 HF", -176., 0), SoundTrap300HF("SoundTrap 300 HF", -176., 0), HydroMoth_1_0_0("HydroMoth 1.0.0", -180., 0);
+
+ /**
+ * The name of the hydrophones.
+ */
+ private String name;
+
+
+ /**
+ * The sensitivity of the hydrophone in dB re 1V/uPa.
+ */
+ private double sens;
+
+ /**
+ * The gain in dB.
+ */
+ private double gain;
+
+ /**
+ * The name of the hydrophone.
+ * @param name - the name of the hydrophone.
+ * @param sens - the sensitivity of the hydrophone.
+ * @param gain - the gain of the hydrophone.
+ */
+ DefaultHydrophone(String name, double sens, double gain) {
+ this.name = name;
+ this.sens = sens;
+ this.gain = gain;
+
+ }
+
+ /**
+ * The sensitivity of the hydrophone in dB re 1V/uPa.
+ */
+ public double getSens() {
+ return sens;
+ }
+
+
+ /**
+ * The gain in dB.
+ */
+ public double getGain() {
+ return gain;
+ }
+
+
+}
diff --git a/src/Array/layoutFX/HydrophoneProperty.java b/src/Array/layoutFX/HydrophoneProperty.java
new file mode 100644
index 00000000..72679010
--- /dev/null
+++ b/src/Array/layoutFX/HydrophoneProperty.java
@@ -0,0 +1,116 @@
+package Array.layoutFX;
+
+import Array.Hydrophone;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+
+
+/**
+ * Property class for a hydrophone object.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class HydrophoneProperty {
+
+ SimpleDoubleProperty x = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty y = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty z = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty xErr = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty yErr = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty zErr = new SimpleDoubleProperty();
+
+ SimpleIntegerProperty id = new SimpleIntegerProperty();
+
+ private Hydrophone hydrophone;
+
+ public HydrophoneProperty(Hydrophone hydrophone) {
+ setHydrophone(hydrophone);
+ }
+
+ public void setHydrophone(Hydrophone hydrophone) {
+ this.hydrophone = hydrophone;
+
+
+ x .set(hydrophone.getX());
+ y .set(hydrophone.getY());
+ z .set(hydrophone.getZ());
+
+ xErr .set(hydrophone.getdX());
+ yErr .set(hydrophone.getdY());
+ zErr .set(hydrophone.getdZ());
+
+ id.set(hydrophone.getID());
+ }
+
+ /**
+ * The x-coordinate property.
+ * @return the x coordintae property.
+ */
+ public SimpleDoubleProperty getX() {
+ return x;
+ }
+
+ /**
+ * The y-coordinate property.
+ * @return the y coordintae property.
+ */
+ public SimpleDoubleProperty getY() {
+ return y;
+ }
+
+ /**
+ * The z-coordinate property.
+ * @return the z coordintae property.
+ */
+ public SimpleDoubleProperty getZ() {
+ return z;
+ }
+
+ public SimpleIntegerProperty getID() {
+ return id;
+ }
+
+ public Hydrophone getHydrophone() {
+ //incase table data changes.
+ this.hydrophone.setID(this.id.get());
+ this.hydrophone.setX(x.get());
+ this.hydrophone.setY(y.get());
+ this.hydrophone.setZ(z.get());
+ this.hydrophone.setdX(xErr.get());
+ this.hydrophone.setdY(yErr.get());
+ this.hydrophone.setdZ(xErr.get());
+
+ 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
new file mode 100644
index 00000000..0e8f4507
--- /dev/null
+++ b/src/Array/layoutFX/HydrophoneSettingsPane.java
@@ -0,0 +1,589 @@
+package Array.layoutFX;
+
+import Array.Hydrophone;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import Array.PamArray;
+import Array.Streamer;
+import PamController.PamController;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+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 javafx.scene.layout.Region;
+import net.synedra.validatorfx.Validator;
+import pamViewFX.PamGuiManagerFX;
+import pamViewFX.fxNodes.PamVBox;
+import pamViewFX.fxSettingsPanes.DynamicSettingsPane;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.PamGridPane;
+import pamViewFX.fxNodes.PamHBox;
+import pamViewFX.fxNodes.PamSpinner;
+import pamViewFX.validator.PamValidator;
+
+/**
+ * The settings pane for a single hydrophones.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class HydrophoneSettingsPane extends DynamicSettingsPane {
+
+ private static final double COLUMN_0_WIDTH = 120;
+
+
+ private final static double MAX_TEXTFIELD_WIDTH = 80;
+
+ /**
+ *
+ * Check inputs in real time
+ */
+ PamValidator validator = new PamValidator();
+
+
+ @Override
+ public String getName() {
+ return "Hydrophone Settings";
+ }
+
+ @Override
+ public Node getContentNode() {
+ return mainPane;
+ }
+
+ @Override
+ public void paneInitialized() {
+ // TODO Auto-generated method stub
+
+ }
+
+ private TextField iD;
+
+ private TextField yPos;
+ private TextField xPos;
+ private TextField zPos;
+
+ private TextField yPosErr;
+ private TextField xPosErr;
+ private TextField zPosErr;
+
+ private PamSpinner hSens;
+ private PamSpinner preampGain;
+
+ private ComboBox streamers;
+ private ChoiceBox defaultArrays;
+ private TextField nameField;
+
+ private PamArray currentArray;
+
+ ///Labels which might change name if in air or water (i.e. hydrophone or microphone).
+
+ private Labeled depthLabel;
+
+ private Labeled depthLabel2;
+
+ private Label recieverIDLabel;
+
+ private Label recieverTypeLabel;
+
+ private Label recieverSensLabel;
+
+ private Label dBSensLabel;
+
+ private boolean ressetHydrophoneType = false;
+
+ /**
+ * The main holder pane.
+ */
+ private PamBorderPane mainPane;
+
+ private InterpChoicePane interpPane;
+
+ private ComboBox defaultHydro;
+
+ //create the dialog
+ public HydrophoneSettingsPane() {
+ super(null);
+
+ PamVBox holderPane = new PamVBox();
+ holderPane.setSpacing(5);
+
+
+ recieverIDLabel = new Label("General");
+ PamGuiManagerFX.titleFont2style(recieverIDLabel);
+
+ Label coOrdLabel = new Label("Coordinates");
+ PamGuiManagerFX.titleFont2style(coOrdLabel);
+
+ Label interpLabel = new Label("Interpolation");
+ PamGuiManagerFX.titleFont2style(interpLabel);
+
+ interpPane = new InterpChoicePane();
+
+ PamHBox interpHolder = new PamHBox();
+ interpHolder.setSpacing(5);
+ interpHolder.setAlignment(Pos.CENTER_LEFT);
+ interpHolder.getChildren().addAll(new Label("Method"), interpPane);
+
+ holderPane.getChildren().addAll(recieverIDLabel, createGeneralPane(), coOrdLabel, createPositionPane(), interpLabel, interpHolder);
+
+ mainPane = new PamBorderPane();
+ mainPane.setCenter(holderPane);
+ }
+
+ //
+ // public Boolean getParams(){
+ // array.nameProperty().setValue(nameField.getText());
+ // array.hArrayTypeProperty().setValue(arrayType.getValue());
+ // try {
+ // array.xPosProperty().setValue(Double.valueOf(xPos.getText()));
+ // array.yPosProperty().setValue(Double.valueOf(yPos.getText()));
+ // array.zPosProperty().setValue(Double.valueOf(zPos.getText()));
+ // }
+ // catch (Exception e){
+ // System.err.println("Invalid field in Array Dialog");
+ // return false;
+ // }
+ // return true;
+ // }
+ //
+ // public void setParams(Hydrophone hydrophone){
+ //
+ // iD.setText(String.format("%d", hydrophone.getID()));
+ // streamers.getItems().clear();
+ //
+ // //set thre text values for the recieevrs.
+ //// setRecieverLabelText();
+ // if (currentArray != null) {
+ // Streamer s;
+ // for (int i = 0; i < currentArray.getNumStreamers(); i++) {
+ // s = currentArray.getStreamer(i);
+ // streamers.getItems().add(String.format("Streamer %d, x=%3.1f", i, s.getX()));
+ // }
+ // }
+ // if (hydrophone.getStreamerId() < currentArray.getNumStreamers()) {
+ // streamers.getSelectionModel().select(hydrophone.getStreamerId());
+ // }
+ // hSens.setText(String.format("%.1f", hydrophone.getSensitivity()-PamController.getInstance().getGlobalMediumManager().getdBSensOffset()));
+ // preampGain.setText(String.format("%.1f", hydrophone.getPreampGain()));
+ // // bandwidth0.setText(String.format("%.1f", hydrophone.getBandwidth()[0]));
+ // // bandwidth1.setText(String.format("%.1f", hydrophone.getBandwidth()[1]));
+ //
+ //
+ //// this.array=array;
+ //// nameField.setText(hydrophone.getType());
+ // parentArrayComboBox.setValue(array.get);
+ //
+ // //attachmentComboBox.setItems(ArrayModelControl.getInstance().getArrays());
+ // parentArrayComboBox.setValue(array.parentHArrayProperty().getValue());
+ //
+ // xPos.setText(Double.toString(hydrophone.);
+ // yPos.setText(Double.toString(array.yPosProperty().get()));
+ // zPos.setText(Double.toString(array.zPosProperty().get()));
+ //
+ // createArrayPane(array);
+ //
+ // }
+
+
+ /**
+ * Set the receiver labels depending on whether air or water is being used.
+ */
+ private void setGeneralInfoLabelText() {
+ String recieverString = PamController.getInstance().getGlobalMediumManager().getRecieverString();
+ String dbSens = PamController.getInstance().getGlobalMediumManager().getdBSensString();
+
+ recieverIDLabel.setText(recieverString+ " ID Info");
+ recieverTypeLabel.setText(recieverString + " type ");
+ recieverSensLabel.setText(recieverString + " sens ");
+ dBSensLabel.setText(dbSens);
+ }
+
+
+ /**
+ * Set the receiver labels depending on whether air or water is being used.
+ */
+ private void setCoordsText() {
+ String recieverDepthString = PamController.getInstance().getGlobalMediumManager().getZString();
+
+ depthLabel.setText(recieverDepthString + " ");
+
+ switch (PamController.getInstance().getGlobalMediumManager().getCurrentMedium()) {
+ case Air:
+ depthLabel2.setText(" m (height above streamer)");
+ break;
+ case Water:
+ depthLabel2.setText(" m (depth below streamer)");
+ break;
+ }
+
+ }
+
+
+
+
+ /**
+ * Create the pane to allow users to change the position of hydrophones
+ */
+ private Pane createGeneralPane() {
+
+ PamGridPane mainControls=new PamGridPane();
+ mainControls.setHgap(5);
+ mainControls.setVgap(5);
+
+
+ int gridy = 0;
+ Label parentArrayLabel = new Label("Parent Array");
+ 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_LEFT);
+ defaultHydro = new ComboBox();
+
+ for (int i=0; i{
+ //don't want to trigger this if we are programtically setting it back
+ if (defaultHydro.getSelectionModel().getSelectedIndex() <= 0 || ressetHydrophoneType) {
+ //do nothing.
+ return;
+ }
+ ressetHydrophoneType=true;
+ hSens.getValueFactory().setValue(Double.valueOf(DefaultHydrophone.values()[defaultHydro.getSelectionModel().getSelectedIndex()-1].getSens()));
+ preampGain.getValueFactory().setValue(Double.valueOf(DefaultHydrophone.values()[defaultHydro.getSelectionModel().getSelectedIndex()-1].getGain()));
+ ressetHydrophoneType=false;
+ });
+
+ mainControls.add(defaultHydro, 1, gridy);
+
+ gridy++;
+ mainControls.add(recieverSensLabel = new Label(""), 0, gridy);
+ recieverSensLabel.setAlignment(Pos.CENTER_LEFT);
+ hSens = new PamSpinner(-Double.MAX_VALUE, Double.MAX_VALUE, -200., 1.);
+ hSens.setEditable(true);
+
+ hSens.valueProperty().addListener((obs, oldval, newVal)->{
+ if (ressetHydrophoneType) return;
+ ressetHydrophoneType = true; //make sure we don't trigger anything when resetting the combo box
+ defaultHydro.getSelectionModel().select(0);
+ ressetHydrophoneType= false;
+ });
+
+ mainControls.add(hSens, 1, gridy);
+ mainControls.add(dBSensLabel = new Label(""), 2, gridy);
+
+
+ gridy++;
+ Label preAmpLabel = new Label("Preamplifier gain");
+ mainControls.add(preAmpLabel, 0, gridy);
+ 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;
+ ressetHydrophoneType = true;//make sure we don't trigger anything when resetting the combo box
+ defaultHydro.getSelectionModel().select(0);
+ ressetHydrophoneType= false;
+ });
+ preampGain.setEditable(true);
+
+
+ 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();
+
+
+ return mainControls;
+ }
+
+ /**
+ * Create the pane to allow users to change the position of hydrophones
+ */
+ private Pane createPositionPane(){
+
+ double sectionPadding=15;
+
+
+ PamVBox mainControls=new PamVBox();
+ mainControls.setSpacing(5);
+
+ Insets h;
+
+ Label nameLabel=new Label("Array Name");
+ nameLabel.setPadding(new Insets(5,0,0,0));
+ nameField=new TextField();
+
+ //parent array.
+ Label parentArrayLabel=new Label("Parent Streamer");
+ parentArrayLabel.setPadding(new Insets(sectionPadding,0,0,0));
+
+ PamGridPane positionPane = new PamGridPane();
+ positionPane.setHgap(5);
+ positionPane.setVgap(5);
+
+ ColumnConstraints rc = new ColumnConstraints(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE, MAX_TEXTFIELD_WIDTH);
+ //this sets all text fields to the correct width - but of naff hack but what grid pane needs to work.
+ for (int i=1; i<5; i++) {
+ positionPane.getColumnConstraints().add(rc);
+ }
+
+ double maxWidth =10;
+
+ xPos=new TextField();
+ xPos.textProperty().addListener((obsVal, oldVal, newVal)->{
+ notifySettingsListeners();
+ });
+ xPos.setMaxWidth(maxWidth);
+ addTextValidator(xPos, "x position", validator);
+
+ yPos=new TextField();
+ yPos.setMaxWidth(maxWidth);
+ addTextValidator(yPos, "y position", validator);
+ yPos.textProperty().addListener((obsVal, oldVal, newVal)->{
+ notifySettingsListeners();
+ });
+
+ zPos=new TextField();
+ zPos.setMaxWidth(maxWidth);
+ zPos.textProperty().addListener((obsVal, oldVal, newVal)->{
+ notifySettingsListeners();
+ });
+
+ addTextValidator(zPos, "z position", validator);
+ depthLabel = new Label("Depth");
+ depthLabel.setAlignment(Pos.CENTER);
+
+ xPosErr=new TextField();
+ xPosErr.setMaxWidth(50);
+ addTextValidator(xPosErr, "x error",validator);
+ yPosErr=new TextField();
+ yPosErr.setMaxWidth(50);
+ addTextValidator(yPosErr, "y error",validator);
+ zPosErr=new TextField();
+ zPosErr.setMaxWidth(50);
+ depthLabel2 = new Label(""); //changes with air or water mode.
+ depthLabel2.setAlignment(Pos.CENTER);
+ addTextValidator(zPosErr, "z error", validator);
+
+ int col=0;
+ int row =0;
+
+ Label xLabel = new Label("x");
+ xLabel.setAlignment(Pos.CENTER);
+
+ Label yLabel = new Label("y");
+ yLabel.setAlignment(Pos.CENTER);
+
+ col=1;
+ positionPane.add(xLabel, col++, row);
+ positionPane.add(yLabel, col++, row);
+ positionPane.add(depthLabel, col++, row);
+
+ 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);
+ // positionPane.getColumnConstraints().add(col1);
+
+ // Label positionLabel = new Label("Coordinates");
+ // 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();
+
+ return mainControls;
+
+ }
+
+
+
+ /**
+ * Creates a text filed and adds a validator to check that the input is OK.
+ * @return
+ */
+ protected static void addTextValidator(TextField userTextField, String description, Validator validator) {
+ //userTextField.setPrefColumnCount(8);
+
+ validator.createCheck()
+ .dependsOn(description, userTextField.textProperty())
+ .withMethod(c -> {
+ String posVal = c.get(description);
+
+ /**
+ * Ok, this is weird. So if the c.error is called then somehow it messes up
+ * the sizing of the pane i.e. it does not resize..
+ */
+
+ try {
+ if (posVal.isEmpty() || Double.valueOf(posVal)==null) {
+ c.error("The input for " + description + " is invalid");
+ }
+ }
+ catch (Exception e) {
+ c.error("The input for " + description + " is invalid");
+ }
+ })
+ .decorates(userTextField).immediate();
+ }
+
+
+
+ @Override
+ public void setParams(Hydrophone hydrophone) {
+
+ //parent array stuff.
+
+ //iD.setText(String.format("%d", hydrophone.getID()));
+
+ streamers.getItems().clear();
+
+ //set thre text values for the recieevrs.
+ setGeneralInfoLabelText();
+ if (currentArray != null) {
+ Streamer s;
+ for (int i = 0; i < currentArray.getNumStreamers(); i++) {
+ s = currentArray.getStreamer(i);
+ streamers.getItems().add(String.format("Streamer %d, x=%3.1f", i, s.getX()));
+ }
+ }
+ if (hydrophone.getStreamerId() < currentArray.getNumStreamers()) {
+ streamers.getSelectionModel().select(hydrophone.getStreamerId());
+ }
+
+ //hydrophone stuff
+ hSens.getValueFactory().setValue(hydrophone.getSensitivity()-PamController.getInstance().getGlobalMediumManager().getdBSensOffset());
+ preampGain.getValueFactory().setValue(hydrophone.getPreampGain());
+
+ double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();
+ setCoordsText();
+
+ interpPane.setSelection(currentArray.getHydrophoneInterpolation());
+
+ xPos.setText(Double.toString(hydrophone.getX()));
+ yPos.setText(Double.toString(hydrophone.getY()));
+ zPos.setText(Double.toString(zCoeff*hydrophone.getZ()));
+ xPosErr.setText(Double.toString(hydrophone.getdX()));
+ yPosErr.setText(Double.toString(hydrophone.getdY()));
+ zPosErr.setText(Double.toString(hydrophone.getdZ()));
+
+ }
+
+
+ @Override
+ public Hydrophone getParams(Hydrophone hydrophone) {
+ double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();
+
+ try {
+ //hydrophone.setID(Integer.valueOf(iD.getText()));
+ //hydrophone.setType(type.getText());
+ hydrophone.setStreamerId(streamers.getSelectionModel().getSelectedIndex());
+ hydrophone.setSensitivity(hSens.getValue()+PamController.getInstance().getGlobalMediumManager().getdBSensOffset());
+ hydrophone.setPreampGain(preampGain.getValue());
+// double[] bw = new double[2];
+ // bw[0] = Double.valueOf(bandwidth0.getText());
+ // bw[1] = Double.valueOf(bandwidth1.getText());
+ // hydrophone.setBandwidth(bw);
+
+ hydrophone.setX(Double.valueOf(xPos.getText()));
+ hydrophone.setY(Double.valueOf(yPos.getText()));
+ hydrophone.setZ(zCoeff*Double.valueOf(zPos.getText()));
+ hydrophone.setdX(Double.valueOf(xPosErr.getText()));
+ hydrophone.setdY(Double.valueOf(yPosErr.getText()));
+ hydrophone.setdZ(Double.valueOf(zPosErr.getText()));
+
+ int hi = interpPane.getSelection();
+ if (hi >= 0) {
+ this.currentArray.setHydrophoneInterpolation(interpPane.getSelectedInterpType());
+ }
+ }
+ catch (Exception Ex) {
+ System.err.println("There is a problem with one of the parameters in the hydrophone panel");
+ return null;
+ }
+ return hydrophone;
+ }
+
+ /**
+ * Set the current array associated with the hydrophone.
+ * @param currentArray - the current array.
+ */
+ public void setCurrentArray(PamArray currentArray) {
+ this.currentArray= currentArray;
+
+ }
+
+ public void setRecieverLabels() {
+ setGeneralInfoLabelText();
+
+ }
+
+
+
+
+
+
+}
diff --git a/src/Array/layoutFX/HydrophonesPane.java b/src/Array/layoutFX/HydrophonesPane.java
new file mode 100644
index 00000000..4d574fa4
--- /dev/null
+++ b/src/Array/layoutFX/HydrophonesPane.java
@@ -0,0 +1,412 @@
+package Array.layoutFX;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import Array.Hydrophone;
+import Array.PamArray;
+import PamController.PamController;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.geometry.Insets;
+import javafx.scene.control.Button;
+import javafx.scene.control.Dialog;
+import javafx.scene.control.TableCell;
+import javafx.scene.layout.Pane;
+import javafx.scene.paint.Color;
+import javafx.util.Callback;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.cell.TextFieldTableCell;
+import javafx.util.converter.IntegerStringConverter;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.PamColorsFX;
+import pamViewFX.fxNodes.flipPane.PamFlipPane;
+import pamViewFX.fxNodes.table.TableSettingsPane;
+
+/**
+ * Table which allows users to add and edit hydrophones.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class HydrophonesPane extends PamBorderPane {
+
+
+ static final double defaultx = 0.;
+ static final double defaulty = 0.;
+ static final double defaultz = 0.;
+ static final double defaultxErr = 0.;
+ static final double defaultyErr = 0.;
+ static final double defaultzErr = 0.;
+ static final String defaulttype = "Unknown";
+ static final double defaultsensitivity = -201;
+
+ /**
+ * Reference to the current array
+ */
+ protected PamArray currentArray;
+
+ /**
+ * The current hydrophone data.
+ */
+ private HydrophoneProperty currentHydrophoneData;
+
+
+ /**
+ * A list of all the current hydrophones.
+ */
+ ObservableList hydrophoneList = FXCollections.observableArrayList();
+
+
+ /**
+ * The hydrophone array table.
+ */
+ private HydrophoneTable tableArrayPane;
+
+ private PamFlipPane pamFlipePane;
+
+ /**
+ * Settings pane for a single hydrophone.
+ */
+ private HydrophoneSettingsPane hydrophonePane = new HydrophoneSettingsPane();
+
+ /**
+ * A list of listeners which are called whenever a hydrophone is added removed or changed.
+ */
+ public ArrayList hydrophoneChangeListeners = new ArrayList();
+
+ public HydrophonesPane() {
+
+ tableArrayPane = new HydrophoneTable(hydrophoneList);
+
+ tableArrayPane.setPadding(new Insets(5,5,5,5));
+
+ pamFlipePane = new PamFlipPane();
+ pamFlipePane.getAdvLabel().setText(PamController.getInstance().getGlobalMediumManager().getRecieverString());
+ // pamFlipePane.minWidthProperty().bind(this.widthProperty());
+ // pamFlipePane.setStyle("-fx-background-color: green;");
+
+
+ ((Pane) hydrophonePane.getContentNode()).setPadding(new Insets(5,5,5,15));
+
+ pamFlipePane.setAdvPaneContent(hydrophonePane.getContentNode());
+ pamFlipePane.setFrontContent(tableArrayPane);
+
+ pamFlipePane.getFront().setPadding(new Insets(5,5,5,10));
+
+ pamFlipePane.backButtonProperty().addListener((obsval, oldVal, newVal)->{
+
+ // System.out.println("Hello back button pressed: " + newVal.intValue());
+ //the flip pane
+ if (newVal.intValue()==PamFlipPane.OK_BACK_BUTTON) {
+
+ Hydrophone hydro = hydrophonePane.getParams(currentHydrophoneData.getHydrophone());
+
+ if (hydro==null) {
+ //the warning dialog is shown in the streamer settings pane
+ return;
+ }
+
+ // 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);
+
+ notifyHydrophoneListeners(currentHydrophoneData);
+
+ //need to refresh table to show symbol.
+ tableArrayPane.getTableView().refresh();
+ //
+ // System.out.println("Table size: " + tableArrayPane.getTableView().getItems().size());
+ // for (int i=0; i {
+
+
+ /**
+ * The z table
+ */
+ private TableColumn z;
+
+ public HydrophoneTable(ObservableList hydrophoneData) {
+ super(hydrophoneData);
+
+ z = new TableColumn("depth");
+ z.setCellValueFactory(cellData -> cellData.getValue().getZ().multiply(PamController.getInstance().getGlobalMediumManager().getZCoeff()));
+ z.setEditable(true);
+
+ //need to set up all the rows.
+ TableColumn hydroID = new TableColumn("ID");
+ hydroID.setCellValueFactory(cellData -> cellData.getValue().getID().asObject());
+ hydroID.setEditable(false);
+
+ // Default cell factory provides text field for editing and converts text in text field to int.
+ Callback, TableCell> defaultCellFactory =
+ TextFieldTableCell.forTableColumn(new IntegerStringConverter());
+
+ // Cell factory implementation that uses default cell factory above, and augments the implementation
+ // by updating the value of the looked-up color cell-selection-color for the cell when the item changes:
+ Callback, TableCell> cellFactory = col -> {
+ TableCell cell = defaultCellFactory.call(col);
+ cell.itemProperty().addListener((obs, oldValue, newValue) -> {
+// System.out.println("Hello set colour: " + newValue);
+ if (newValue == null) {
+ cell.setStyle("cell-selection-color: -fx-selection-bar ;");
+ } else {
+ Color color = createColor(newValue.intValue());
+ String formattedColor = formatColor(color);
+// cell.setStyle("cell-selection-color: "+ formattedColor + " ;");
+ cell.setStyle("-fx-background: "+ formattedColor + " ;");
+ cell.setStyle("-fx-background-color: "+ formattedColor + " ;");
+// System.out.println("Hello set style: " + formattedColor);
+ }
+ });
+ return cell;
+ };
+
+ hydroID.setCellFactory(cellFactory);
+
+
+ TableColumn x = new TableColumn("x");
+ x.setCellValueFactory(cellData -> cellData.getValue().getX());
+ x.setEditable(true);
+
+ TableColumn y = new TableColumn("y");
+ y.setCellValueFactory(cellData -> cellData.getValue().getY());
+ y.setEditable(true);
+
+
+ TableColumn posColumn=new TableColumn("Position (m)");
+ posColumn.getColumns().addAll(x, y, z);
+
+ TableColumn xErr = new TableColumn("x");
+ xErr.setCellValueFactory(cellData -> cellData.getValue().getXErr());
+ xErr.setEditable(true);
+
+ TableColumn yErr = new TableColumn("y");
+ yErr.setCellValueFactory(cellData -> cellData.getValue().getYErr());
+ yErr.setEditable(true);
+
+ TableColumn zErr = new TableColumn("z");
+ zErr.setCellValueFactory(cellData -> cellData.getValue().getZErr());
+ zErr.setEditable(true);
+
+ TableColumn errorColumn=new TableColumn("Errors (m)");
+ errorColumn.getColumns().addAll(xErr, yErr, zErr);
+
+ getTableView().getColumns().addAll(hydroID, posColumn, errorColumn);
+
+ }
+
+
+ // Create color based on int value. Just use value as hue, full saturation and brightness:
+ private Color createColor(int i) {
+ //get channel colour and add a bit of transparancy to make less abnoxious
+ return PamColorsFX.getInstance().getChannelColor(i).deriveColor(1, 1, 1, 0.5);
+
+// return Color.hsb(x, 1.0, 1.0);
+ }
+
+ // Format color as string for CSS (#rrggbb format, values in hex).
+ private String formatColor(Color c) {
+ int r = (int) (255 * c.getRed());
+ int g = (int) (255 * c.getGreen());
+ int b = (int) (255 * c.getBlue());
+ return String.format("#%02x%02x%02x", r, g, b);
+ }
+
+ @Override
+ public void dialogClosed(HydrophoneProperty data) {
+ System.out.println("Get hydrophone paramters");
+ Hydrophone hydro = hydrophonePane.getParams(data.getHydrophone());
+ data.setHydrophone(hydro);
+ }
+
+ @Override
+ public Dialog createSettingsDialog(HydrophoneProperty data) {
+ //we do not use dialogs here- sliding pane instead.
+ // setClassifierPane(data);
+ pamFlipePane.flipToBack();
+ return null;
+ }
+
+ @Override
+ public void editData(HydrophoneProperty data){
+ // setClassifierPane(data);
+
+ pamFlipePane.getAdvLabel().setText("Hydrophone " + data.getID().get() + " Settings");
+
+ hydrophonePane.setCurrentArray(currentArray);
+ hydrophonePane.setParams(data.getHydrophone());
+
+ currentHydrophoneData = data;
+
+ pamFlipePane.flipToBack();
+ }
+
+
+ private PamArray getCurrentArray() {
+ return currentArray;
+ }
+
+ /**
+ * Get the button which closes the hiding pane.
+ * @return button which closes the hiding pane.
+ */
+ public Button getFlipPaneCloseButton() {
+ return pamFlipePane.getBackButton();
+ }
+
+ @Override
+ public void createNewData(){
+ HydrophoneProperty hydrophone = createDefaultHydrophoneProperty(hydrophoneList.size());
+ //create a new classifier.
+ hydrophoneList.add(hydrophone);
+ notifyHydrophoneListeners(hydrophone);
+ }
+
+
+ @Override
+ public void deleteData(HydrophoneProperty data){
+ super.deleteData(data);
+ //the ID number for hydrophone sis actually important for where they are in the list. Bit a legacy issue but no
+ //point in messes everything up to fix. So, when a hydrophone is deleted must update all the ID numbers.
+
+ updateIDNumbers();
+
+ notifyHydrophoneListeners(data);
+ }
+
+ /**
+ * Update the ID numbers.
+ */
+ private void updateIDNumbers() {
+ for (int i=0; i getZColumn() {
+ return z;
+ }
+
+ /**
+ * Get the current streamers.
+ * @return the current streamers.
+ */
+ public ObservableList getHydrophones() {
+ return getData();
+ }
+
+
+ }
+
+ public void setParams(PamArray currentArray) {
+ this.currentArray=currentArray;
+
+ tableArrayPane.getHydrophones().clear();
+
+ for (int i=0; i getHydrophoneList() {
+ return hydrophoneList;
+ }
+
+ public void setHydrophoneList(ObservableList hydrophoneList) {
+ this.hydrophoneList = hydrophoneList;
+ }
+
+ public void setRecieverLabels() {
+ tableArrayPane.getZColumn().setText(PamController.getInstance().getGlobalMediumManager().getZString());
+ hydrophonePane.setRecieverLabels();
+ }
+
+ /**
+ * Add a listener which is called whenever a hydrophone is added, removed or changed.
+ * @param e - the listener to add
+ */
+ public void addStreamerListener(ArrayChangeListener e) {
+ hydrophoneChangeListeners.add(e);
+
+ }
+
+ /**
+ * Select the current hydrophone in table.
+ */
+ public void selectHydrophone(Hydrophone hydrophone) {
+ //select the current hydrophone in the table
+ tableArrayPane.getTableView().getSelectionModel().select(hydrophone.getID());
+ }
+
+ public void setCurrentArray(PamArray currentArray) {
+ this.currentArray=currentArray;
+
+ }
+
+ /**
+ * Get the hydrophone interpolation. Note that this is stored in the
+ * currentArray because the interpolator must be the same for all hydrophones.
+ *
+ * @return the inteprolation selection.
+ */
+ public int getHydrophoneInterp() {
+ return currentArray.getHydrophoneInterpolation();
+ }
+
+}
diff --git a/src/Array/layoutFX/InterpChoicePane.java b/src/Array/layoutFX/InterpChoicePane.java
new file mode 100644
index 00000000..b5e7613b
--- /dev/null
+++ b/src/Array/layoutFX/InterpChoicePane.java
@@ -0,0 +1,104 @@
+package Array.layoutFX;
+
+import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
+import javafx.scene.control.ChoiceBox;
+import javafx.util.StringConverter;
+
+
+
+/**
+ * Choice box which allows selection of interpolation options.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class InterpChoicePane extends InterpSettingsPane {
+
+ /**
+ * Interp choice box.
+ */
+ private ChoiceBox interpChoiceBox;
+
+ public InterpChoicePane() {
+
+ interpChoiceBox = new ChoiceBox();
+ interpChoiceBox.getItems().addAll(interpChoice);
+ interpChoiceBox.setMaxWidth(Double.MAX_VALUE);
+
+ interpChoiceBox.setConverter(new StringConverter<>() {
+ @Override
+ public String toString(Integer item) {
+ if (item ==null) return "null";
+ return getInterpString(item);
+ }
+
+ @Override
+ public Integer fromString(String unused) {
+ throw new UnsupportedOperationException();
+ }
+ });
+
+ this.setCenter(interpChoiceBox);
+
+ }
+
+ public void setSelection(int option) {
+
+ System.out.println("Select interp option: " + option);
+
+ interpChoiceBox.getSelectionModel().select(Integer.valueOf(option));
+
+ // useLatest.setSelected(option == PamArray.ORIGIN_USE_LATEST);
+ // useInterpolate.setSelected(option == PamArray.ORIGIN_INTERPOLATE);
+ // usePrevious.setSelected(option == PamArray.ORIGIN_USE_PRECEEDING);
+ }
+
+ public int getSelection() {
+ int sel = getSelectedInterpType();
+ if (((1< {
+
+ Pane mainPane;
+
+ private TextField speedOfSound;
+
+ private TextField speedOfSoundError;
+
+ private PamValidator validator;
+
+
+ public PropogationPane() {
+ super(null);
+ validator= new PamValidator();
+ mainPane = createEnvironmentPane();
+ }
+
+ /**
+ * Create the pane for setting propogation conditions.
+ * @return the pane with controls to change environmental variables.
+ */
+ private Pane createEnvironmentPane() {
+ speedOfSound = new TextField();
+ speedOfSound.setPrefColumnCount(6);
+
+ validator.createCheck()
+ .dependsOn("speed_of_sound", speedOfSound.textProperty())
+ .withMethod(c -> {
+ try {
+ String posVal = c.get("speed_of_sound");
+ if (posVal.isEmpty() || Double.valueOf(posVal)==null) {
+ c.error("The input for speed of sound is invalid");
+ }
+ }
+ catch (Exception e) {
+ c.error("The input for speed of sound is invalid");
+ }
+ })
+ .decorates(speedOfSound).immediate();
+
+
+ speedOfSoundError = new TextField();
+ speedOfSoundError.setPrefColumnCount(4);
+
+ validator.createCheck()
+ .dependsOn("speed_of_sound_error", speedOfSoundError.textProperty())
+ .withMethod(c -> {
+ try {
+ String posVal = c.get("speed_of_sound_error");
+ if (posVal.isEmpty() || Double.valueOf(posVal)==null) {
+ c.error("The input for speed of sound error is invalid");
+ }
+ }
+ catch (Exception e) {
+ c.error("The input for speed of sound is invalid");
+ }
+ })
+ .decorates(speedOfSoundError).immediate();
+
+ PamHBox hBox = new PamHBox();
+ hBox.setSpacing(5);
+ hBox.setAlignment(Pos.CENTER);
+
+
+ hBox.getChildren().addAll(new Label("Speed of sound"), speedOfSound, new Label("\u00B1"), speedOfSoundError, new Label("m/s"));
+
+ return hBox;
+ }
+
+ @Override
+ public PamArray getParams(PamArray currParams) {
+ if (validator.containsErrors()) return null;
+
+ currParams.setSpeedOfSound(Double.valueOf(speedOfSound.getText()));
+ currParams.setSpeedOfSoundError(Double.valueOf(speedOfSoundError.getText()));
+ return currParams;
+ }
+
+ @Override
+ public void setParams(PamArray input) {
+ //set the current params.
+ speedOfSound.setText(String.valueOf(input.getSpeedOfSound()));
+ speedOfSoundError.setText(String.valueOf(input.getSpeedOfSoundError()));
+ }
+
+ @Override
+ public String getName() {
+ return "Propogation pane";
+ }
+
+ @Override
+ public Node getContentNode() {
+ return mainPane;
+ }
+
+ @Override
+ public void paneInitialized() {
+ // TODO Auto-generated method stub
+
+ }
+
+
+
+}
diff --git a/src/Array/layoutFX/SensorSourcePane.java b/src/Array/layoutFX/SensorSourcePane.java
new file mode 100644
index 00000000..9c6f61f0
--- /dev/null
+++ b/src/Array/layoutFX/SensorSourcePane.java
@@ -0,0 +1,162 @@
+package Array.layoutFX;
+
+import java.util.ArrayList;
+
+import Array.sensors.ArrayParameterType;
+import Array.sensors.ArraySensorDataBlock;
+import Array.sensors.ArraySensorDataUnit;
+import Array.sensors.ArraySensorFieldType;
+import PamController.PamController;
+import PamguardMVC.PamDataBlock;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.Node;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Tooltip;
+
+public class SensorSourcePane {
+
+ private ArraySensorFieldType sensorType;
+
+ private ComboBox sensorDropDown;
+
+ private ArrayList currentBlocks;
+
+ private boolean defaultOption;
+
+ private boolean fixedOption;
+
+ private int nSpecials;
+
+ private ArrayParameterType[] specialTypes = new ArrayParameterType[2];
+
+ public SensorSourcePane(ArraySensorFieldType sensorType, boolean fixedOption, boolean defaultOption) {
+ this.sensorType = sensorType;
+ this.fixedOption = fixedOption;
+ this.defaultOption = defaultOption;
+ sensorDropDown = new ComboBox<>();
+ fillDropDown();
+ sensorDropDown.setTooltip(new Tooltip("Sensor updates for " + sensorType.toString()));
+ }
+
+ /**
+ * Get the type of sensor.
+ * @return the type of sensor.
+ */
+ public ArraySensorFieldType getSensorType() {
+ return sensorType;
+ }
+
+ public void setOnAction(EventHandler e) {
+ sensorDropDown.setOnAction(e);
+ }
+
+ public void fillDropDown() {
+ currentBlocks = getDataBlocks();
+ sensorDropDown.getItems().clear();
+ nSpecials = 0;
+ if (fixedOption) {
+ sensorDropDown.getItems().add("Fixed Value");
+ specialTypes[nSpecials++] = ArrayParameterType.FIXED;
+ }
+ if (defaultOption) {
+ sensorDropDown.getItems().add("Default value");
+ specialTypes[nSpecials++] = ArrayParameterType.DEFAULT;
+ }
+ for (PamDataBlock aBlock : currentBlocks) {
+ sensorDropDown.getItems().add(aBlock.getDataName());
+ }
+ }
+
+ /**
+ * Set the type of parameter being used, fixed, default or sensor
+ * @param paramType
+ */
+ public void setParameterType(ArrayParameterType paramType) {
+ for (int i = 0; i < nSpecials; i++) {
+ if (paramType == specialTypes[i]) {
+ sensorDropDown.getSelectionModel().select(i);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Get the type of parameter being used, fixed, default or sensor
+ * @return
+ */
+ public ArrayParameterType getParameterType() {
+ int ind = sensorDropDown.getSelectionModel().getSelectedIndex();
+ if (ind < 0) {
+ return null;
+ }
+ if (ind < nSpecials) {
+ return specialTypes[ind];
+ }
+ return ArrayParameterType.SENSOR;
+ }
+
+ /**
+ * Set the selected datablock for sensor data. Before calling this, you should call
+ * fillDropDown to make sure list of blocks is up to date.
+ * @param aDataBlock datablock to select
+ * @return true if that block was selected OK, i.e. it was in the list.
+ */
+ public boolean setDataBlock(PamDataBlock aDataBlock) {
+ if (currentBlocks == null) {
+ return false;
+ }
+ int ind = currentBlocks.indexOf(aDataBlock);
+ if (ind < 0) {
+ return false;
+ }
+ sensorDropDown.getSelectionModel().select(ind+nSpecials); // offset by 1 to allow for null option.
+ return true;
+ }
+
+ /**
+ *
+ * @return Currently selected datablock for this sensor (can be null)
+ */
+ public PamDataBlock getDataBlock() {
+ int ind = sensorDropDown.getSelectionModel().getSelectedIndex();
+ if (ind <= 0 || currentBlocks == null) {
+ return null;
+ }
+ else {
+ return currentBlocks.get(ind-nSpecials);
+ }
+ }
+
+ /**
+ * Get the sensor pane.
+ * @return the sensor pane
+ */
+ public Node getPane() {
+ return sensorDropDown;
+ }
+
+ /**
+ * Get a list of datablocks that might be able to provide info on this
+ * sensor field type
+ * @return
+ */
+ private ArrayList getDataBlocks() {
+ ArrayList allDataBlocks = PamController.getInstance().getDataBlocks(ArraySensorDataUnit.class, true);
+ ArrayList sensBlocks = new ArrayList<>();
+ if (allDataBlocks == null) {
+ return sensBlocks;
+ }
+ // go through take out the ones that support this sensor.
+ for (PamDataBlock aBlock : allDataBlocks) {
+ if (aBlock instanceof ArraySensorDataBlock == false) {
+ continue;
+ }
+ ArraySensorDataBlock sensBlock = (ArraySensorDataBlock) aBlock;
+ if (sensBlock.hasSensorField(sensorType)) {
+ sensBlocks.add(aBlock);
+ }
+ }
+ return sensBlocks;
+ }
+}
diff --git a/src/Array/layoutFX/StreamerProperty.java b/src/Array/layoutFX/StreamerProperty.java
new file mode 100644
index 00000000..eb82adc5
--- /dev/null
+++ b/src/Array/layoutFX/StreamerProperty.java
@@ -0,0 +1,121 @@
+package Array.layoutFX;
+
+import Array.Streamer;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.property.SimpleStringProperty;
+
+
+/**
+ * Property class for a Streamer. Create property bindings for certain Streamer values which allows
+ * for much easier integration into UI components in JavaFX.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class StreamerProperty {
+
+ /**
+ * The simple name property.
+ */
+ private SimpleStringProperty name = new SimpleStringProperty();
+
+ private SimpleStringProperty reference = new SimpleStringProperty();
+
+ private SimpleStringProperty origin = new SimpleStringProperty();
+
+ /**
+ * Get the x, y and z.
+ */
+ private SimpleDoubleProperty x = new SimpleDoubleProperty();
+
+ private SimpleDoubleProperty y = new SimpleDoubleProperty();
+
+ private SimpleDoubleProperty z = new SimpleDoubleProperty();
+
+
+ private Streamer streamer;
+
+ private SimpleIntegerProperty streamerIDProperty = new SimpleIntegerProperty();
+
+ public StreamerProperty(Streamer streamer) {
+ setStreamer( streamer);
+ }
+
+ public void setStreamer(Streamer streamer) {
+ this.streamer = streamer;
+ name.setValue(streamer.getStreamerName());
+ x.setValue(streamer.getX());
+ y.setValue(streamer.getY());
+ z.setValue(streamer.getZ());
+ streamerIDProperty.setValue(streamer.getStreamerIndex());
+ reference.setValue(streamer.getHydrophoneLocator() != null ? streamer.getHydrophoneLocator().getName() : "null");
+ origin.setValue(streamer.getHydrophoneOrigin() != null ? streamer.getHydrophoneOrigin().getName() : "null");
+
+ }
+
+ public SimpleStringProperty getName() {
+ return name;
+ }
+
+ public void setName(SimpleStringProperty name) {
+ this.name = name;
+ }
+
+ public SimpleDoubleProperty getX() {
+ return x;
+ }
+
+ public void setX(SimpleDoubleProperty x) {
+ this.x = x;
+ }
+
+ public SimpleDoubleProperty getY() {
+ return y;
+ }
+
+ public void setY(SimpleDoubleProperty y) {
+ this.y = y;
+ }
+
+ public SimpleDoubleProperty getZ() {
+ return z;
+ }
+
+ public void setZ(SimpleDoubleProperty z) {
+ this.z = z;
+ }
+
+
+ public Streamer getStreamer() {
+ return streamer;
+ }
+
+ /**
+ * Get the index property of the streamer.
+ * @return the streamer index.
+ */
+ public SimpleIntegerProperty getID() {
+ return streamerIDProperty;
+ }
+
+ /**
+ * Get the reference property.
+ * @return the reference property.
+ */
+ public SimpleStringProperty getHydrophineLocator() {
+ return reference;
+ }
+
+
+ /**
+ * Get the origin string property.
+ * @return the origin string property.
+ */
+ public SimpleStringProperty getHydrophoneOrigin() {
+ return origin;
+ }
+
+
+
+}
diff --git a/src/Array/layoutFX/StreamerSettingsPane.java b/src/Array/layoutFX/StreamerSettingsPane.java
new file mode 100644
index 00000000..f2880f52
--- /dev/null
+++ b/src/Array/layoutFX/StreamerSettingsPane.java
@@ -0,0 +1,752 @@
+package Array.layoutFX;
+
+import org.controlsfx.control.PopOver;
+
+import Array.HydrophoneLocator;
+import Array.HydrophoneLocators;
+import Array.PamArray;
+import Array.Streamer;
+import Array.sensors.ArrayParameterType;
+import Array.sensors.ArraySensorFieldType;
+import Array.streamerOrigin.HydrophoneOriginMethod;
+import Array.streamerOrigin.HydrophoneOriginMethods;
+import Array.streamerOrigin.HydrophoneOriginSystem;
+import Array.streamerOrigin.OriginDialogComponent;
+import Array.streamerOrigin.OriginSettings;
+import PamController.PamController;
+import PamController.SettingsPane;
+import PamUtils.LatLong;
+import PamguardMVC.PamDataBlock;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import pamViewFX.PamGuiManagerFX;
+import pamViewFX.fxGlyphs.PamGlyphDude;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.PamButton;
+import pamViewFX.fxNodes.PamGridPane;
+import pamViewFX.fxNodes.PamHBox;
+import pamViewFX.fxNodes.PamVBox;
+import pamViewFX.validator.PamValidator;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.ColumnConstraints;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.Region;
+import net.synedra.validatorfx.Validator;
+
+
+/**
+ * A JavaFX settings pane for a streamer.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class StreamerSettingsPane extends SettingsPane {
+
+ private final static double MAX_TEXTFIELD_WIDTH = 80;
+
+
+ public PamBorderPane mainPane;
+
+ /**
+ * Combo Box which shows which origin methods are available.
+ */
+ private ComboBox originMethod;
+
+ /**
+ * The origin pane;
+ */
+ private PamBorderPane originPane;
+
+ /**
+ * The default streamer
+ */
+ public Streamer defaultStreamer;
+
+
+ /**
+ * The current array
+ */
+ private PamArray currentArray;
+
+ /**
+ * The current origin methods
+ */
+ private HydrophoneOriginMethod currentOriginMethod;
+
+ /*
+ * The current origin method pane.
+ */
+ private Pane currentOriginComponent;
+
+ /**
+ * Interpolation panel
+ */
+ private InterpChoicePane interpPane;
+
+
+ private TextField xPos;
+
+
+ private Validator validator = new PamValidator();
+
+
+ private TextField yPos;
+
+
+ private TextField zPos;
+
+
+ private TextField zPosErr;
+
+
+ private TextField xPosErr;
+
+
+ private Label depthLabel;
+
+
+ private TextField yPosErr;
+
+
+ private Label depthLabel2;
+
+
+ private TextField heading;
+
+
+ private TextField roll;
+
+
+ private TextField pitch;
+
+
+ private ComboBox localiserMethod;
+
+
+ private SensorSourcePane[] sensorComponents;
+
+
+ private Label depthSensorLabel;
+
+
+ /**
+ * Button for extra origin parameters.
+ */
+ private PamButton originButton;
+
+
+
+ public StreamerSettingsPane() {
+ super(null);
+
+ mainPane = new PamBorderPane();
+ mainPane.setCenter(getStreamerPane());
+
+ }
+
+ /**
+ * Create the streamer pane
+ * @return get the pane.
+ */
+ private Pane getStreamerPane(){
+
+ String reciever = PamController.getInstance().getGlobalMediumManager().getRecieverString();
+
+ Label label = new Label("Geo-reference Position");
+ PamGuiManagerFX.titleFont2style(label);
+
+ //holds advanced setings for new origin methods.
+ originPane = new PamBorderPane();
+ PopOver popOver = new PopOver();
+ popOver.setContentNode(originPane);
+
+ originMethod = new ComboBox();
+ originButton = new PamButton();
+ originButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-crosshairs-gps"));
+ originButton.setOnAction((a)->{
+ popOver.show(originButton);
+ });
+ originMethod.setMaxWidth(Double.MAX_VALUE);
+
+ PamHBox originHolder = new PamHBox();
+ originHolder.setSpacing(5);
+ originHolder.setAlignment(Pos.CENTER_LEFT);
+ originHolder.getChildren().addAll(originMethod,originButton);
+ originHolder.setMaxWidth(Double.MAX_VALUE);
+ HBox.setHgrow(originMethod, Priority.ALWAYS);
+
+ int n = HydrophoneOriginMethods.getInstance().getCount();
+ for (int i = 0; i < n; i++) {
+ originMethod.getItems().add(HydrophoneOriginMethods.getInstance().getMethod(i));
+ }
+
+ Label hydroMovementLabel = new Label(reciever +" Movement Model");
+
+ //listener for when a new origin method is called.
+ originMethod.setOnAction((action)->{
+ newOriginMethod();
+ });
+
+ interpPane = new InterpChoicePane();
+ Label inteprlabel = new Label("Interpolation");
+ PamGuiManagerFX.titleFont2style(inteprlabel);
+
+ PamHBox interpBox = new PamHBox();
+ interpBox.setSpacing(5);
+ Label interpMethodLabel = new Label("Method");
+
+ Region spacer = new Region();
+ spacer.prefWidthProperty().bind(originButton.widthProperty());
+ interpBox.getChildren().addAll(interpMethodLabel, interpPane, spacer);
+ interpBox.setAlignment(Pos.CENTER_LEFT);
+ interpBox.setMaxWidth(Double.MAX_VALUE);
+ interpPane.setMaxWidth(Double.MAX_VALUE);
+ HBox.setHgrow(interpPane, Priority.ALWAYS);
+
+ //add all stuff to the holder
+ PamVBox holder = new PamVBox();
+ holder.getChildren().addAll(label, originHolder, hydroMovementLabel, createLocatorPane(), inteprlabel, interpBox);
+ holder.setSpacing(5);
+
+
+ return holder;
+
+ }
+
+ /**
+ * Create the locator pane.
+ * @return the pane containing controls.
+ */
+ public Pane createLocatorPane() {
+
+ localiserMethod = new ComboBox<>();
+ int n = HydrophoneLocators.getInstance().getCount();
+ for (int i = 0; i < n; i++) {
+ localiserMethod.getItems().add(HydrophoneLocators.getInstance().getSystem(i));
+ }
+ localiserMethod.setMaxWidth(Double.MAX_VALUE);
+
+ PamHBox loclaiserMethodHolder = new PamHBox();
+ loclaiserMethodHolder.setSpacing(5);
+ loclaiserMethodHolder.setAlignment(Pos.CENTER_LEFT);
+ Label spacer = new Label();
+ spacer.prefWidthProperty().bind(originButton.widthProperty());
+ loclaiserMethodHolder.getChildren().addAll(localiserMethod, spacer);
+ loclaiserMethodHolder.setMaxWidth(Double.MAX_VALUE);
+ HBox.setHgrow(localiserMethod, Priority.ALWAYS);
+
+ //hydrophone position and
+ PamGridPane positionPane = new PamGridPane();
+ positionPane.setHgap(5);
+ positionPane.setVgap(5);
+
+ ColumnConstraints rc = new ColumnConstraints(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE, MAX_TEXTFIELD_WIDTH);
+
+ //Orientation pane.
+ //create data sources for sensors.
+ ArraySensorFieldType[] sensorFields = ArraySensorFieldType.values();
+ sensorComponents = new SensorSourcePane[sensorFields.length];
+ //EnableOrientation eo = new EnableOrientation();
+ for (int i = 0; i < sensorFields.length; i++) {
+ sensorComponents[i] = new SensorSourcePane(sensorFields[i], true, sensorFields[i] != ArraySensorFieldType.HEIGHT);
+ sensorComponents[i].setOnAction((e)->{
+ enableOrientationPane();
+ });
+ }
+ PamButton button = new PamButton("Sensors");
+ button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-compass-outline", PamGuiManagerFX.iconSize));
+
+ PopOver popOver = new PopOver(createSensorPane());
+ popOver.setDetachable(true);
+
+ button.setOnAction((a)->{
+ popOver.show(button);
+ });
+
+
+ //this sets all text fields to the correct width - but of naff hack but what grid pane needs to work.
+ for (int i=1; i<5; i++) {
+ positionPane.getColumnConstraints().add(rc);
+ }
+
+ xPos=new TextField();
+ xPos.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(xPos, "x position", validator);
+ yPos=new TextField();
+ yPos.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(yPos, "y position", validator);
+ zPos=new TextField();
+ zPos.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(zPos, "z position", validator);
+
+
+ depthLabel = new Label("Depth");
+ depthLabel.setAlignment(Pos.CENTER);
+
+ depthSensorLabel = new Label("Depth Sensor");
+ depthSensorLabel.setAlignment(Pos.CENTER);
+
+
+ xPosErr=new TextField();
+ xPosErr.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(xPosErr, "x error", validator);
+ yPosErr=new TextField();
+ yPosErr.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(yPosErr, "y error", validator);
+ zPosErr=new TextField();
+ zPosErr.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ depthLabel2 = new Label(""); //changes with air or water mode.
+ depthLabel2.setAlignment(Pos.CENTER);
+ HydrophoneSettingsPane.addTextValidator(zPosErr, "z error", validator);
+
+ int col=0;
+ int row=0;
+
+
+ Label xLabel = new Label("x");
+ xLabel.setAlignment(Pos.CENTER);
+
+ Label yLabel = new Label("y");
+ yLabel.setAlignment(Pos.CENTER);
+
+ //Orientations
+
+ String degsLab = LatLong.deg + " ";
+
+
+ col=1;
+ positionPane.add(xLabel, col++, row);
+ positionPane.add(yLabel, col++, row);
+ positionPane.add(depthLabel, col++, row);
+ col++;
+ positionPane.add(depthSensorLabel, col++, row);
+
+ 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);
+ positionPane.add(sensorComponents[ArraySensorFieldType.HEIGHT.ordinal()].getPane(), 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);
+
+ //Orientation
+ col=1;
+ row++;
+
+ Label headingLabel = new Label("Heading");
+ headingLabel.setAlignment(Pos.CENTER);
+
+ Label pitchLabel = new Label("Pitch");
+ pitchLabel.setAlignment(Pos.CENTER);
+
+ Label rolllabel = new Label("Roll");
+ rolllabel.setAlignment(Pos.CENTER);
+
+
+ positionPane.add(headingLabel, col++, row);
+ positionPane.add(pitchLabel, col++, row);
+ positionPane.add(rolllabel, col++, row);
+
+ row++;
+
+ heading = new TextField();
+ heading.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(heading, "heading", validator);
+
+ pitch = new TextField();
+ pitch.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(pitch, "pitch", validator);
+
+ roll = new TextField();
+ roll.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(roll, "roll", validator);
+
+ col=0;
+
+ Label orientation = new Label("Orientation");
+ positionPane.add(orientation, col++, row);
+ positionPane.add(heading, col++, row);
+ positionPane.add(pitch, col++, row);
+ positionPane.add(roll, col++, row);
+ positionPane.add(new Label(degsLab), col++, row);
+
+
+ positionPane.add(button, col++, row);
+
+ PamVBox holder= new PamVBox();
+ holder.setSpacing(5);
+ holder.getChildren().addAll(loclaiserMethodHolder, positionPane);
+
+ return holder;
+ }
+
+ /**
+ * Enables or disables controls in the orientation pane.
+ */
+ private void enableOrientationPane() {
+ for (int i=0; i=currentOriginMethod.getAllowedInterpolationMethods()) {
+ System.err.println("Streamer setParams: Origin interpolator value of " + currentArray.getOriginInterpolation() + " not allowed for origin method - setting to first allowed method:");
+ interpPane.setSelection(0);
+ }
+ else {
+ interpPane.setSelection(currentArray.getOriginInterpolation());
+ }
+
+ System.out.println("Streamer setParams: selected interp: " + interpPane.getSelectedInterpType());
+
+
+ ArraySensorFieldType[] sensorFields = ArraySensorFieldType.values();
+ for (int i = 0; i < sensorFields.length; i++) {
+ ArrayParameterType fieldType = defaultStreamer.getOrientationTypes(sensorFields[i]);
+ String fieldDataBlock = defaultStreamer.getSensorDataBlocks(sensorFields[i]);
+ sensorComponents[i].setParameterType(fieldType);
+ if (fieldType == ArrayParameterType.SENSOR && fieldDataBlock != null) {
+ sensorComponents[i].setDataBlock(PamController.getInstance().getDataBlockByLongName(fieldDataBlock));
+ }
+ }
+
+ setRecieverLabels() ;
+ enableControls();
+
+ }
+
+ private String orientation2Text(Double ang) {
+ if (ang == null) return String.valueOf(0.0);
+ else return String.format("%3.1f", ang);
+ }
+
+ @Override
+ public String getName() {
+ return "Streamer Pane";
+ }
+
+ @Override
+ public Node getContentNode() {
+ return mainPane;
+ }
+
+ @Override
+ public void paneInitialized() {
+
+ }
+
+ public void setRecieverLabels() {
+ String recieverDepthString = PamController.getInstance().getGlobalMediumManager().getZString();
+
+ depthLabel.setText(recieverDepthString );
+ depthSensorLabel.setText(recieverDepthString + " Sensor");
+
+ }
+
+ private Double getDoubleValue(TextField textField) {
+ String txt = textField.getText();
+ if (txt == null || txt.length() == 0) {
+ return null;
+ }
+ Double val;
+ try {
+ val = Double.valueOf(txt);
+ return val;
+ }
+ catch (NumberFormatException e) {
+ System.err.println("Invalid orientation information: " + txt);
+ return null;
+ }
+ }
+
+ public void setCurrentArray(PamArray currentArray2) {
+ this.currentArray=currentArray2;
+
+ }
+}
diff --git a/src/Array/layoutFX/StreamersPane.java b/src/Array/layoutFX/StreamersPane.java
new file mode 100644
index 00000000..b5adf047
--- /dev/null
+++ b/src/Array/layoutFX/StreamersPane.java
@@ -0,0 +1,315 @@
+package Array.layoutFX;
+
+import java.util.ArrayList;
+
+import Array.PamArray;
+import Array.Streamer;
+import PamController.PamController;
+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.control.TableView;
+import javafx.scene.layout.Pane;
+import javafx.geometry.Insets;
+
+/**
+ * A pane for setting up hydrophones. Note that this is entirely separate from PAMGuard so can be used in
+ * other projects.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class StreamersPane 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();
+
+ /**
+ * A list of listeners which are called whenever a streamer is added removed or changed.
+ */
+ public ArrayList streamerChangeListeners = new ArrayList();
+
+
+ public StreamersPane() {
+
+ tableArrayPane = new BasicArrayTable(streamerData);
+
+ tableArrayPane.setPadding(new Insets(5,5,5,5));
+ this.setCenter(tableArrayPane);
+
+ pamFlipePane = new PamFlipPane();
+ pamFlipePane.getAdvLabel().setText("Streamer");
+ pamFlipePane.setMaxWidth(Double.MAX_VALUE);
+
+ ((Pane) streamerPane.getContentNode()).setPadding(new Insets(5,5,5,15));
+
+ pamFlipePane.setAdvPaneContent(streamerPane.getContentNode());
+ pamFlipePane.setFrontContent(tableArrayPane);
+
+ pamFlipePane.getFront().setPadding(new Insets(5,5,5,10));
+ pamFlipePane.setAdvLabelEditable(true);
+ pamFlipePane.getPostAdvLabel().setText("Settings");
+
+
+ pamFlipePane.backButtonProperty().addListener((obsval, oldVal, newVal)->{
+
+// System.out.println("Hello back button pressed: " + newVal.intValue());
+
+ //the flip pane
+ if (newVal.intValue()==PamFlipPane.OK_BACK_BUTTON) {
+
+ Streamer streamer = streamerPane.getParams(currentStreamerData.getStreamer());
+
+ if (streamer==null) {
+ //the warning dialog is shown in the streamer settings pane
+ return;
+ }
+
+ streamer.setStreamerName(pamFlipePane.getAdvLabel().getText());
+
+ currentStreamerData.setStreamer(streamer);
+
+ notifyStreamerListeners(currentStreamerData);
+// System.out.println("Update streamer: " + tableArrayPane.getStreamers().indexOf(currentStreamerData) + " no. streamers: " + currentArray.getNumStreamers());
+
+ //need to refresh table to show symbol.
+ tableArrayPane.getTableView().refresh();
+
+ if (streamer != null) {
+ streamer.setupLocator(currentArray);
+ streamer.makeStreamerDataUnit();
+ //update the streamer in the current array
+ }
+ }
+ });
+
+ this.setCenter(pamFlipePane);
+
+ }
+
+ /**
+ * Notify the streamer listeners of a change
+ * @param streamer - the changed streamer
+ */
+ public void notifyStreamerListeners(StreamerProperty streamer) {
+ for (ArrayChangeListener listener: streamerChangeListeners) {
+ listener.arrayChanged(ArrayChangeListener.STREAMER_CHANGE, streamer);
+ }
+ }
+
+ /**
+ * Class which extends TableSettingsPane and creates a sliding pane instead of a dialog when an item is added.
+ * @author Jamie Macaulay
+ *
+ */
+ class BasicArrayTable extends TableSettingsPane {
+
+ private TableColumn z;
+
+
+ public BasicArrayTable(ObservableList data) {
+ super(data);
+ //need to set up all the rows.
+ 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(true);
+
+
+ TableColumn x = new TableColumn("x");
+ x.setCellValueFactory(cellData -> cellData.getValue().getX());
+ x.setEditable(false);
+
+ TableColumn y = new TableColumn("y");
+ y.setCellValueFactory(cellData -> cellData.getValue().getY());
+ y.setEditable(false);
+
+ z = new TableColumn("depth");
+ z.setCellValueFactory(cellData -> cellData.getValue().getZ().multiply(PamController.getInstance().getGlobalMediumManager().getZCoeff()));
+ z.setEditable(false);
+
+ TableColumn posColumn=new TableColumn("Position (m)");
+ posColumn.getColumns().addAll(x, y, z);
+
+ TableColumn reference = new TableColumn("Reference");
+ reference.setCellValueFactory(cellData -> cellData.getValue().getHydrophoneOrigin());
+ reference.setEditable(true);
+
+ TableColumn locator = new TableColumn("Locator");
+ locator.setCellValueFactory(cellData -> cellData.getValue().getHydrophineLocator());
+ locator.setEditable(true);
+
+ TableColumn geoColumn=new TableColumn("Geo-reference");
+ geoColumn.getColumns().addAll(reference, locator);
+
+
+ getTableView().getColumns().addAll(streamerID, name, posColumn, geoColumn);
+
+ }
+
+ /**
+ * Get the current streamers.
+ * @return the current streamers.
+ */
+ public ObservableList getStreamers() {
+ return getData();
+ }
+
+ @Override
+ public void dialogClosed(StreamerProperty data) {
+ Streamer hydro = streamerPane.getParams(data.getStreamer());
+ data.setStreamer(hydro);
+ }
+
+ @Override
+ public Dialog createSettingsDialog(StreamerProperty data) {
+ //we do not use dialogs here- sliding pane instead.
+ // setClassifierPane(data);
+ // showFlipPane(true);
+ pamFlipePane.flipToBack();
+ return null;
+ }
+
+ @Override
+ public void editData(StreamerProperty data){
+ //edit streamer data.
+ if (data.getName() == null){
+ pamFlipePane.getAdvLabel().setText("Streamer " + data.getID().get());
+ }
+
+ streamerPane.setCurrentArray(currentArray);
+ streamerPane.setParams(data.getStreamer());
+
+ currentStreamerData = data;
+
+ pamFlipePane.flipToBack();
+ }
+
+ @Override
+ public void createNewData(){
+ StreamerProperty newStreamer = createDefaultStreamerProperty();
+ //create a new classifier.
+ streamerData.add(newStreamer);
+ //add to the current array.
+ currentArray.addStreamer(newStreamer.getStreamer());
+ System.out.println("Create new streamer: " + currentArray.getNumStreamers());
+
+ notifyStreamerListeners(newStreamer);
+
+ }
+
+ @Override
+ public void deleteData(StreamerProperty data){
+ super.deleteData(data);
+ notifyStreamerListeners(null);
+ }
+
+ private StreamerProperty createDefaultStreamerProperty() {
+ Streamer streamer = new Streamer(1, 0.,0.,0.,0.,0.,0.);
+ return new StreamerProperty(streamer);
+ }
+
+ public TableColumn getZColumn() {
+ return z;
+ }
+
+
+ }
+
+ /**
+ * Set the parameters for the streamer pane.
+ * @param currentArray - the current array.
+ */
+ public void setParams(PamArray currentArray) {
+
+ this.currentArray=currentArray.clone();
+
+ System.out.println("Set params streamer: " + currentArray.getNumStreamers());
+
+ tableArrayPane.getStreamers().clear();
+
+ for (int i=0; itableArrayPane.getStreamers().size()) {
+ currParams.removeStreamer(currParams.getStreamerCount()-1);
+ }
+
+// currentArray.updateStreamer(tableArrayPane.getStreamers().indexOf(currentStreamerData), streamer);
+
+ return currParams;
+ }
+
+ public void setRecieverLabels() {
+ tableArrayPane.getZColumn().setText(PamController.getInstance().getGlobalMediumManager().getZString());
+ streamerPane.setRecieverLabels();
+ }
+
+ public TableView getStreamerTable() {
+ return tableArrayPane.getTableView();
+ }
+
+ /**
+ * Add a listener which is called whenever a streamer is added, removed or changed.
+ * @param e - the listener to add
+ */
+ public void addStreamerListener(ArrayChangeListener e) {
+ this.streamerChangeListeners.add(e);
+ }
+
+ public void setCurrentArray(PamArray currentArray) {
+ this.currentArray=currentArray;
+
+ }
+
+
+}
diff --git a/src/Array/streamerOrigin/OriginDialogComponent.java b/src/Array/streamerOrigin/OriginDialogComponent.java
index f6ab058b..26dbcb79 100644
--- a/src/Array/streamerOrigin/OriginDialogComponent.java
+++ b/src/Array/streamerOrigin/OriginDialogComponent.java
@@ -1,7 +1,15 @@
package Array.streamerOrigin;
import PamView.dialog.DialogComponent;
+import javafx.scene.layout.Pane;
public abstract class OriginDialogComponent implements DialogComponent{
+ /**
+ * Get a JavaFX pane for the origin method.
+ * @return the JavaFX pane.
+ */
+ public abstract Pane getSettingsPane();
+
+
}
diff --git a/src/Array/streamerOrigin/StaticHydrophonePane.java b/src/Array/streamerOrigin/StaticHydrophonePane.java
new file mode 100644
index 00000000..fc85a583
--- /dev/null
+++ b/src/Array/streamerOrigin/StaticHydrophonePane.java
@@ -0,0 +1,97 @@
+package Array.streamerOrigin;
+
+import GPS.GpsData;
+import GPS.GpsDataUnit;
+import PamUtils.LatLong;
+import javafx.scene.control.Label;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.utilityPanes.LatLongPane;
+
+/**
+ * JavaFX settings pane for a static hydrophones.
+ */
+public class StaticHydrophonePane extends PamBorderPane {
+
+ /**
+ * Reference to static origin mwthod.
+ */
+ private StaticOriginMethod staticOriginMethod;
+
+ LatLongPane latLongPane;
+
+ public StaticHydrophonePane(StaticOriginMethod staticOriginMethod) {
+
+ this.staticOriginMethod=staticOriginMethod;
+
+ latLongPane = new LatLongPane("Static streamer position");
+ this.setCenter(latLongPane.getContentNode());
+
+ }
+
+
+ public void setParams() {
+ GpsDataUnit dataUnit = getStaticOriginSettings().getStaticPosition();
+ if (dataUnit == null) {
+ setLatLong(null);
+ }
+ else {
+ GpsData gpsData = dataUnit.getGpsData();
+ setLatLong(gpsData);
+ }
+
+// if (gpsData == null) {
+// return;
+// }
+// else {
+// setLatLong(gpsData);
+// }
+
+ }
+
+ private StaticOriginSettings getStaticOriginSettings() {
+ return ((StaticOriginSettings) staticOriginMethod.getOriginSettings());
+ }
+
+
+ public boolean getParams() {
+
+ LatLong latLong = latLongPane.getParams(null);
+
+ if (latLong==null) {
+ System.err.println("StaticHydrophonePane: latitude and longitude is null");
+ return false;
+ }
+
+ if (getStaticOriginSettings()==null) {
+ System.err.println("StaticHydrophonePane: static origin is null");
+ return false;
+ }
+
+ //set
+ getStaticOriginSettings().setStaticPosition(staticOriginMethod.getStreamer(), new GpsData(latLong));
+//
+// boolean ok = getStaticOriginSettings()!= null && getStaticOriginSettings() .getStaticPosition() != null;
+//
+// System.out.println("StaticHydrophonePane: Get params from static origin 1 : " + getStaticOriginSettings());
+//
+// System.out.println("StaticHydrophonePane: Get params from static origin 2: " + getStaticOriginSettings() .getStaticPosition());
+
+ return true;
+ }
+
+ /**
+ * Just set the lat long without resetting the heading.
+ * @param latLong
+ */
+ private void setLatLong(LatLong latLong) {
+ if (latLong==null) {
+ //create a default latitude and longitude - Rockall (why not).
+ LatLong latLongdefault = new LatLong();
+ latLongdefault.setLatitude(57.595833333333);
+ latLongdefault.setLongitude(-13.686944444444);
+ latLongPane.setParams(latLongdefault);
+ }
+ else latLongPane.setParams(latLong);
+ }
+
+}
diff --git a/src/Array/streamerOrigin/StaticOriginMethod.java b/src/Array/streamerOrigin/StaticOriginMethod.java
index 8c413c9c..4f42c922 100644
--- a/src/Array/streamerOrigin/StaticOriginMethod.java
+++ b/src/Array/streamerOrigin/StaticOriginMethod.java
@@ -29,10 +29,11 @@ import PamUtils.LatLongDialog;
import PamUtils.PamCalendar;
import PamView.dialog.PamDialog;
import PamView.dialog.PamGridBagContraints;
+import javafx.scene.layout.Pane;
public class StaticOriginMethod extends HydrophoneOriginMethod {
- private StaticHydrophoneDialogComponent staticHydrophoneDialogComponent;
+ private StaticHydrophoneComponent staticHydrophoneDialogComponent;
private StaticOriginSettings staticOriginSettings = new StaticOriginSettings();
@@ -48,12 +49,107 @@ public class StaticOriginMethod extends HydrophoneOriginMethod {
@Override
public OriginDialogComponent getDialogComponent() {
if (staticHydrophoneDialogComponent == null) {
- staticHydrophoneDialogComponent = new StaticHydrophoneDialogComponent();
+ staticHydrophoneDialogComponent = new StaticHydrophoneComponent();
}
return staticHydrophoneDialogComponent;
}
+ @Override
+ public OriginSettings getOriginSettings() {
+ return staticOriginSettings;
+ }
+
+ @Override
+ public void setOriginSettings(OriginSettings originSettings) {
+ staticOriginSettings = (StaticOriginSettings) originSettings;
+ }
+
+ @Override
+ public boolean prepare() {
+ return true;
+ }
+
+ @Override
+ public StreamerDataUnit getLastStreamerData() {
+ StreamerDataBlock streamerDataBlock = ArrayManager.getArrayManager().getStreamerDatabBlock();
+ StreamerDataUnit sdu = streamerDataBlock.getLastUnit(1< iter = getGpsDataBlock().getListIterator(timeMilliseconds, 0, PamDataBlock.MATCH_BEFORE, PamDataBlock.POSITION_BEFORE);
+ if (iter == null) {
+ return null;
+ }
if (iter.hasNext()) {
pointBefore = iter.next();
}
diff --git a/src/Localiser/LocaliserModel.java b/src/Localiser/LocaliserModel.java
index c0f7ae13..58f3a298 100644
--- a/src/Localiser/LocaliserModel.java
+++ b/src/Localiser/LocaliserModel.java
@@ -27,7 +27,7 @@ public interface LocaliserModel {
public String getToolTipText();
/**
- * The type of localisation information the localizer can accept. e.g. bearings, time delays etc. The types are
+ * The type of localisation information the localiser can accept. e.g. bearings, time delays etc. The types are
* defined in the AbstractLocalisation class.
* @return integer bitmap of the type of localisation information the localiser can use.
*/
@@ -35,20 +35,20 @@ public interface LocaliserModel {
/**
* Get the settings pane for the localiser. Allows users to change localiser settings.
- * @return the settings pane for the loclaiser.
+ * @return the settings pane for the localiser.
*/
- public LocaliserPane> getSettingsPane();
+ public LocaliserPane> getAlgorithmSettingsPane();
/**
- * True if the model has paramaters to set. If has the loclaiser has a settings pane it will have
+ * True if the model has parameters to set. If has the localiser has a settings pane it will have
* parameters. This generally puts an extra button onto a display panel.
*/
public boolean hasParams();
/**
* Run the localisation model. Once completed the results are added to the AbstractLoclaisation class of the input PamDataUnit.
- * Note that algorithms may run on a separate thread. Once processing has finished the notifyModelFinished function is called with
+ *Note that algorithms may run on a separate thread. Once processing has finished the notifyModelFinished function is called with
* a progress of 1;.
* @param pamDataUnit the pamDataUnit. This can be a super unit if multiple detections are required.
* @param addLoc automatically add the localisation result to the data unit, replacing it's current localisation info.
@@ -56,7 +56,7 @@ public interface LocaliserModel {
public AbstractLocalisation runModel(T pamDataUnit, DetectionGroupOptions detectionGroupOptions, boolean addLoc);
/**
- * This should be called whenever the localiser has finished processing and, if the loclaisation process is long, then updates progress.
+ * This should be called whenever the localiser has finished processing and, if the localisation process is long, then updates progress.
*/
public void notifyModelProgress(double progress);
diff --git a/src/Localiser/LocaliserPane.java b/src/Localiser/LocaliserPane.java
index 4ca335cf..e275a3f8 100644
--- a/src/Localiser/LocaliserPane.java
+++ b/src/Localiser/LocaliserPane.java
@@ -1,5 +1,17 @@
package Localiser;
-public interface LocaliserPane {
+import PamController.SettingsPane;
+
+public abstract class LocaliserPane extends SettingsPane {
+
+ public LocaliserPane() {
+ super(null);
+ // TODO Auto-generated constructor stub
+ }
+
+
+
+
+
}
diff --git a/src/Localiser/ModelControlPanel.java b/src/Localiser/ModelControlPanel.java
index 21172a14..2b63bfa6 100644
--- a/src/Localiser/ModelControlPanel.java
+++ b/src/Localiser/ModelControlPanel.java
@@ -152,8 +152,7 @@ public class ModelControlPanel {
@Override
//settings panel
public void actionPerformed(ActionEvent arg0) {
- model.getSettingsPane();
-
+ model.getAlgorithmSettingsPane();
//AWT implementation.
}
}
diff --git a/src/Localiser/algorithms/Correlations.java b/src/Localiser/algorithms/Correlations.java
index 7b726338..294ad138 100644
--- a/src/Localiser/algorithms/Correlations.java
+++ b/src/Localiser/algorithms/Correlations.java
@@ -258,6 +258,8 @@ public class Correlations {
correlationValue = newPeak[1];
return newPeak[0];
}
+
+
/**
* Measure the time delay between pulses on two channels. Inputs in this case are the
* spectrum data (most of the cross correlation is done in the frequency domain)
diff --git a/src/Localiser/algorithms/genericLocaliser/Chi2TimeDelays.java b/src/Localiser/algorithms/genericLocaliser/Chi2TimeDelays.java
index 093d8fd7..c757c009 100644
--- a/src/Localiser/algorithms/genericLocaliser/Chi2TimeDelays.java
+++ b/src/Localiser/algorithms/genericLocaliser/Chi2TimeDelays.java
@@ -185,7 +185,7 @@ public class Chi2TimeDelays implements MinimisationFunction {
}
/**
- * Set the time delays. Each row is a set fo delays from N synchronised hydrophones. Different rows
+ * Set the time delays. Each row is a set for delays from N synchronised hydrophones. Different rows
* can have different numbers of synchronised hydrophones.
* @param timeDelays - a set of time delays in seconds.
*/
diff --git a/src/Localiser/algorithms/genericLocaliser/MCMC/MCMC.java b/src/Localiser/algorithms/genericLocaliser/MCMC/MCMC.java
index a1ebc80b..1413e943 100644
--- a/src/Localiser/algorithms/genericLocaliser/MCMC/MCMC.java
+++ b/src/Localiser/algorithms/genericLocaliser/MCMC/MCMC.java
@@ -18,17 +18,19 @@ import PamUtils.CoordUtils;
import org.apache.commons.math3.ml.clustering.Cluster;
import org.apache.commons.math3.ml.clustering.DoublePoint;
import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer;
+
+
/**
* Markov chain Monte Carlo (MCMC) is a minimisation technique used widely in a variety of field, from finding exo planets,
* to solving complex intergals.
*
-* This is an advanced and highly computationally intensive localisation algorithm based on MCMC methods. For a good description see;
+* This is a highly computationally intensive localisation algorithm based on MCMC methods. For a good description see;
* The Transit Light Curve (TLC) Project.I. Four Consecutive Transits of the Exoplanet XO-1b Matthew J. Holman1
*
-* This is an abstract class and requires a chi2 function to operate.
+* A chi2 function is required to define the minimisation problem.
*
-* Multiple MCMC chains can and should be run. These are executed on different threads to take advantage of multi-core processing as much as possible.
-* Even so a large number of chains or large observation set can result in significant processing times.
+* Multiple MCMC chains can and should be run. These are executed on different threads to take advantage of multi-core processing if possible.
+* Even so, a large number of chains or large observation set can result in significant processing times.
*
* Results are analysed for convergence and final locations packed into an MCMCTDResults class.
*
@@ -117,7 +119,7 @@ public class MCMC implements MinimisationAlgorithm {
double newChi;
ArrayList successChi=new ArrayList(settings.numberOfJumps/5);
- ArrayList successJump=new ArrayList(settings.numberOfJumps/5);
+ ArrayList successJump=new ArrayList(settings.numberOfJumps/5);
// System.out.println("Start MCMC milliseconds: "+ System.currentTimeMillis());
@@ -143,7 +145,7 @@ public class MCMC implements MinimisationAlgorithm {
chainPos=potentialNewJump;
currentChi=newChi;
successChi.add(newChi);
- successJump.add(chainPos);
+ successJump.add(PamArrayUtils.double2Float(chainPos));
//System.out.println(ChainPos);
//System.out.println(NewChi);
//System.out.println(ObservedTimeDelays);
@@ -153,7 +155,7 @@ public class MCMC implements MinimisationAlgorithm {
chainPos=potentialNewJump;
currentChi=newChi;
successChi.add(newChi);
- successJump.add(chainPos);
+ successJump.add(PamArrayUtils.double2Float(chainPos));
//System.out.println(ChainPos);
//System.out.println(NewChi);
//System.out.println(ObservedTimeDelays);
@@ -164,7 +166,7 @@ public class MCMC implements MinimisationAlgorithm {
ChainResult chainResult=new ChainResult(successJump, successChi);
chainResult= analyseChain( chainResult);
- chainResult.nDim=this.chi2.getDim();
+ chainResult.nDim=chi2.getDim();
// System.out.println("Chain results is: " + chainResult.mean[0] + " " + chainResult.mean[1] + " " + chainResult.mean[2]);
// System.out.println("End MCMC millis: "+ System.currentTimeMillis());
@@ -184,7 +186,7 @@ public class MCMC implements MinimisationAlgorithm {
* @param successJump - list of successful jumps
* @param successChi - list of successful chi2 values.
*/
- public ChainResult(ArrayList successJump, ArrayList successChi) {
+ public ChainResult(ArrayList successJump, ArrayList successChi) {
this.successJump=successJump;
this.successChi=successChi;
}
@@ -197,7 +199,7 @@ public class MCMC implements MinimisationAlgorithm {
/**
* A list of points of the successful jumps.
*/
- public ArrayList successJump;
+ public ArrayList successJump;
/**
* The number of dimensions.
@@ -584,7 +586,7 @@ public class MCMC implements MinimisationAlgorithm {
//find min value
int minIndex = chainResult.successChi.indexOf(Collections.min(chainResult.successChi));
minChi2=chainResult.successChi.get(minIndex);
- minChi2Pos=chainResult.successJump.get(minIndex);
+ minChi2Pos=PamArrayUtils.float2Double(chainResult.successJump.get(minIndex));
break;
}
@@ -728,19 +730,19 @@ public class MCMC implements MinimisationAlgorithm {
*/
private EllipticalError getLocError(ArrayList data) {
- ArrayList successJumpAll = new ArrayList();
- List successJump;
+ ArrayList successJumpAll = new ArrayList();
+ List successJump;
for (int i=0; i> getJumps() {
ArrayList> jumps=new ArrayList>();
ArrayList chainJumps;
- double[] ajump;
+ float[] ajump;
for (int i=0; i();
for (int j=0; j0) return null;
+
+ if (errors2D==null) return null;
- //System.out.println("EllipseLocErrorDraw: draw ellipse:"+errors2D[0]+" "+errors2D[1]+" "+Math.toDegrees(errors2D[2]));
+
+ if (errors2D[0] > PamConstants.EARTH_RADIUS_METERS || errors2D[1] > PamConstants.EARTH_RADIUS_METERS) {
+ return null; //don't draw infintie stuff - causes nasty errors.
+ }
+// System.out.println("Draw ovals on map");
+// System.out.println("EllipseLocErrorDraw: draw ellipse:"+errors2D[0]+" "+errors2D[1]+" "+Math.toDegrees(errors2D[2]));
//System.out.println("Plot errors: perp: "+ perpError+ " horz: "+horzError+ " " + errorDirection);
Graphics2D g2d = (Graphics2D)g;
- if (errors2D==null) return null;
-
//draw oval
// //need to work out the size of the horizontal error.
// perpError=Math.max(perpError, 100);
@@ -140,7 +156,7 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
//draw the ellipse and rotate.
Ellipse2D oval=new Ellipse2D.Double(errorOriginXY.getX()-horzErrPix/2, errorOriginXY.getY()-perpErrPix/2, horzErrPix, perpErrPix);
- g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 5 * 0.1f));
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 5 * 0.05f));
g2d.setPaint(ellipseColor.brighter());
if (!Double.isNaN(errorDirection)) g2d.rotate(-paintAngle, errorOriginXY.getX(), errorOriginXY.getY());
@@ -158,4 +174,8 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
}
+ public int getDrawType() {
+ return drawType;
+ }
+
}
diff --git a/src/Localiser/algorithms/locErrors/EllipticalError.java b/src/Localiser/algorithms/locErrors/EllipticalError.java
index 501cbeb2..9fc25df5 100644
--- a/src/Localiser/algorithms/locErrors/EllipticalError.java
+++ b/src/Localiser/algorithms/locErrors/EllipticalError.java
@@ -51,6 +51,8 @@ public class EllipticalError implements LocaliserError {
errorEllipse = new ErrorEllipse(errors, angles);
}
+
+
@Override
public double getError(PamVector errorDirection) {
return errorEllipse.getErrorMagnitude(errorDirection.getUnitVector().getVector());
@@ -78,7 +80,7 @@ public class EllipticalError implements LocaliserError {
/**
* Get the 2D elliptical error.
- * @param planeXy - the plane on whihc to find the ellipse for.
+ * @param planeXy - the plane on which to find the ellipse for.
* @return the elliptical error.
*/
public double[] getErrorEllipse2D(int planeXy) {
@@ -111,6 +113,9 @@ public class EllipticalError implements LocaliserError {
@Override
public String getStringResult() {
String description="";
+ if (errorEllipse==null) {
+ return "Elliptical error is null";
+ }
if (!errorEllipse.is3D()){
description+=String.format("&ensp 2D Elliptical error: &ensp Radii: ");
for (int i=0; imax){
max=curvatureError;
ind=i; //record index of max value;
}
}
- double[] dim={max, getLLCurvature(chi2, point, PamVector.fromHeadAndSlant(Math.toDegrees(angleBin*ind)+90, 0)),-1 };
+ double[] dim={max, getLLCurvature(point, PamVector.fromHeadAndSlant(Math.toDegrees(angleBin*ind)+90, 0)),-1 };
double[] angles={angleBin*ind, 0,0};
for (int i=0; imax){
max=curvatureError;
@@ -171,7 +171,7 @@ public class LikilihoodError extends EllipticalError {
Vector3D location3D=plane.getPointAt(vector2D, 0);
// get the max error in this plane.
- curvatureError=getLLCurvature(chi2, point, new PamVector(location3D.toArray()));
+ curvatureError=getLLCurvature(point, new PamVector(location3D.toArray()));
if (curvatureError>maxPlane){
maxPlane=curvatureError;
indPlane=n; //record index of max value;
@@ -203,7 +203,7 @@ public class LikilihoodError extends EllipticalError {
ArrayList vectors=new ArrayList();
vectors.add(firstEigenvector.scalarMultiply(max)); //have already calculated error in previous steps.
vectors.add(secondVector.scalarMultiply(maxPlane)); //have already calculated error in previous steps.
- vectors.add(thirdVector.scalarMultiply(getLLCurvature( chi2, point, new PamVector(thirdVector.toArray()))));
+ vectors.add(thirdVector.scalarMultiply(getLLCurvature( point, new PamVector(thirdVector.toArray()))));
//create an error ellipse.
ErrorEllipse errorEllipse=new ErrorEllipse(vectors);
@@ -240,7 +240,7 @@ public class LikilihoodError extends EllipticalError {
* direction specified and in the opposite direction. Curvature is expressed as 1 standard deviation
* error
*/
- private double getLLCurvature(MinimisationFunction chi2, double[] point, PamVector errorVector) {
+ private double getLLCurvature(double[] point, PamVector errorVector) {
double dis = 10; //the jump along the chi2 surface.
double err = 0;
diff --git a/src/Localiser/algorithms/locErrors/SimpleError.java b/src/Localiser/algorithms/locErrors/SimpleError.java
index 02b64d88..2b00cb4a 100644
--- a/src/Localiser/algorithms/locErrors/SimpleError.java
+++ b/src/Localiser/algorithms/locErrors/SimpleError.java
@@ -42,10 +42,7 @@ public class SimpleError implements LocaliserError {
* @param xyzError - an array of the x/perpindicular y/parallel and z error in meters {x y z}
*/
public SimpleError(Double xyzError[]) {
- simpleErrorDraw=new SimpleLocErrorDraw(this);
- perpindiuclarError=xyzError[0];
- parallelError=xyzError[1];
- zError=xyzError[2];
+ this(xyzError, 0.);
}
/**
diff --git a/src/Localiser/algorithms/locErrors/SimpleErrorXMLData.java b/src/Localiser/algorithms/locErrors/SimpleErrorJSONData.java
similarity index 78%
rename from src/Localiser/algorithms/locErrors/SimpleErrorXMLData.java
rename to src/Localiser/algorithms/locErrors/SimpleErrorJSONData.java
index b2942829..afffd260 100644
--- a/src/Localiser/algorithms/locErrors/SimpleErrorXMLData.java
+++ b/src/Localiser/algorithms/locErrors/SimpleErrorJSONData.java
@@ -1,14 +1,13 @@
package Localiser.algorithms.locErrors;
-import java.text.DecimalFormat;
-public class SimpleErrorXMLData extends ErrorXMLData {
+public class SimpleErrorJSONData extends ErrorJSONData {
private String errorType;
private double[] errorData;
- public SimpleErrorXMLData(String errorType, double[] errorData) {
+ public SimpleErrorJSONData(String errorType, double[] errorData) {
this.errorType = errorType;
this.errorData = errorData;
}
diff --git a/src/Localiser/algorithms/locErrors/SimpleLocErrorDraw.java b/src/Localiser/algorithms/locErrors/SimpleLocErrorDraw.java
index 48c433be..148177ee 100644
--- a/src/Localiser/algorithms/locErrors/SimpleLocErrorDraw.java
+++ b/src/Localiser/algorithms/locErrors/SimpleLocErrorDraw.java
@@ -27,6 +27,7 @@ public class SimpleLocErrorDraw implements LocErrorGraphics {
@Override
public TransformShape drawOnMap(Graphics g, PamDataUnit pamDetection, LatLong errorOrigin,
GeneralProjector generalProjector, Color ellipseColor) {
+
g.setColor(ellipseColor);
if (simpleError == null) {
return null;
diff --git a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java
index d6908eca..59c166fd 100644
--- a/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java
+++ b/src/Localiser/algorithms/timeDelayLocalisers/bearingLoc/PairBearingLocaliser.java
@@ -214,7 +214,7 @@ public class PairBearingLocaliser implements BearingLocaliser {
private boolean resetArray(long timeMillis){
if (this.timeMillis!=timeMillis && currentArray.getHydrophoneLocator().isChangeable()){
- System.out.println("Reset PairBearingLocaliser");
+// System.out.println("Reset PairBearingLocaliser");
prepare(this.arrayElements, timeMillis, this.timingError);
return true;
}
diff --git a/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/Hyperbolic.java b/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/Hyperbolic.java
index 6aa2eaf7..4875aefa 100644
--- a/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/Hyperbolic.java
+++ b/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/Hyperbolic.java
@@ -17,6 +17,7 @@ import PamUtils.PamUtils;
*
* The hyperbolic localiser also includes an error estimation by sampling time delays from a distribution of errors. As a localisation has to
* occur for each sample, this drastically increases the computational time for the hyperbolic localiser.
+ *
* @author Jamie Macaulay
*
*/
@@ -62,7 +63,7 @@ public class Hyperbolic implements TimeDelayLocaliserModel {
* @param timeDelays - time delay values in seconds. Each is a list of time delays using to indexM1 and indexM2 conventions and corresponding to hydrophones in hydrophoneArray list.
* @param timeDelayErrors - time delay error values in seconds. Each is a list of time delay errors using to indexM1 and indexM2 conventions and corresponding to hydrophones in hydrophoneArray list.
* @param speedOfSound - the speed of sound in m/s
- * @param hyperbolicParams - hyperbolic paramaters to use for this instance of the localiser.
+ * @param hyperbolicParams - hyperbolic parameters to use for this instance of the localiser.
*/
public Hyperbolic(ArrayList> hydrophoneArray ,ArrayList> timeDelays, ArrayList< ArrayList> timeDelayErrors, float speedOfSound, HyperbolicParams hyperbolicParams){
this.speedOfSound=speedOfSound;
diff --git a/src/Localiser/controls/MCMCPane.java b/src/Localiser/controls/MCMCPane.java
new file mode 100644
index 00000000..8674a419
--- /dev/null
+++ b/src/Localiser/controls/MCMCPane.java
@@ -0,0 +1,305 @@
+package Localiser.controls;
+
+import Localiser.algorithms.genericLocaliser.MCMC.MCMCParams2;
+import PamController.SettingsPane;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.control.Spinner;
+import javafx.scene.control.ComboBox;
+
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Pane;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontWeight;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.PamGridPane;
+import pamViewFX.fxNodes.PamHBox;
+import pamViewFX.fxNodes.PamSpinner;
+import pamViewFX.fxNodes.PamVBox;
+
+public class MCMCPane extends SettingsPane {
+
+ private PamBorderPane mainPane;
+
+ private double JUMP_SPINNER_WIDTH = 60;
+
+
+ //controls
+ private PamSpinner numJumps;
+
+
+ private PamSpinner jumpXSpinner;
+ private PamSpinner jumpYSpinner;
+ private PamSpinner jumpZSpinner;
+
+ private PamSpinner startDispersion;
+ private PamSpinner numChains;
+ private ComboBox clustering;
+ private PamSpinner numkMeans;
+ private PamSpinner maxClustDist;
+
+ public MCMCPane() {
+ super(null);
+ mainPane = new PamBorderPane();
+ mainPane.setTop(createMCMCPane());
+
+ }
+
+ private Pane createMCMCPane() {
+ PamVBox vBox = new PamVBox();
+
+ PamGridPane gridPane = new PamGridPane();
+ gridPane.setHgap(5);
+ gridPane.setVgap(5);
+
+ int row = 0;
+ int col = 0;
+
+ Label chainTitleLabel = new Label("Markov chain settings");
+// PamGuiManagerFX.titleFont2style(chainTitleLabel);
+ chainTitleLabel.setFont(Font.font(null,FontWeight.BOLD, 11));
+
+ gridPane.add(chainTitleLabel, col, row);
+ GridPane.setColumnSpan(chainTitleLabel, 7);
+ row++;
+
+
+ col=0;
+ PamHBox chainHolder = new PamHBox();
+ chainHolder.setSpacing(5);
+ chainHolder.setAlignment(Pos.CENTER_LEFT);
+
+ Label label3 = new Label("Start");
+ label3.setAlignment(Pos.CENTER_RIGHT);
+ gridPane.add(label3, col, row);
+ col++;
+
+ chainHolder.getChildren().add(numChains = new PamSpinner(1,Integer.MAX_VALUE, 20, 1));
+ numChains.setEditable(true);
+ numChains.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ numChains.setMaxWidth(JUMP_SPINNER_WIDTH);
+
+ chainHolder.getChildren().add(new Label("chains seperated by"));
+
+ chainHolder.getChildren().add(startDispersion = new PamSpinner(0.,Double.MAX_VALUE, 100., 1.));
+ startDispersion.setEditable(true);
+ startDispersion.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ startDispersion.setMaxWidth(JUMP_SPINNER_WIDTH+10);
+
+ chainHolder.getChildren().add(new Label("m"));
+
+ gridPane.add(chainHolder, col, row);
+ GridPane.setColumnSpan(chainHolder, 7);
+
+ row++;
+ col=0;
+
+
+ //chain propertires
+
+ Label label = new Label("No. jumps");
+ label.setAlignment(Pos.CENTER_RIGHT);
+
+ gridPane.add(label, col, row);
+ col++;
+ gridPane.add(numJumps = new PamSpinner(10,Integer.MAX_VALUE, 2500000, 10000), col, row);
+ numJumps.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ GridPane.setColumnSpan(numJumps, 3);
+ numJumps.setEditable(true);
+ //mcmJumpSpinner.setMaxWidth(JUMP_SPINNER_WIDTH*2);
+
+ col+=col+2;
+ Label chainLabel = new Label("per chain");
+ gridPane.add(chainLabel, col, row);
+ GridPane.setColumnSpan(chainLabel, 3);
+
+ row++;
+ col=0;
+ Label label2 = new Label("Jump size x");
+ label2.setAlignment(Pos.CENTER_RIGHT);
+
+ gridPane.add(label2, col, row);
+ col++;
+
+
+ gridPane.add(jumpXSpinner = new PamSpinner(0.,Double.MAX_VALUE, 1., 0.5), col, row);
+ jumpXSpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ jumpXSpinner.setMaxWidth(JUMP_SPINNER_WIDTH);
+ jumpXSpinner.setEditable(true);
+ col++;
+
+ gridPane.add(new Label("y"), col, row);
+ col++;
+
+ gridPane.add(jumpYSpinner = new PamSpinner(0.,Double.MAX_VALUE, 1., 0.5), col, row);
+ jumpYSpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ jumpYSpinner.setMaxWidth(JUMP_SPINNER_WIDTH);
+ jumpYSpinner.setEditable(true);
+ col++;
+
+ gridPane.add(new Label("z"), col, row);
+ col++;
+
+ gridPane.add(jumpZSpinner = new PamSpinner(0.,Double.MAX_VALUE, 1., 0.5), col, row);
+ jumpZSpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ jumpZSpinner.setMaxWidth(JUMP_SPINNER_WIDTH);
+ jumpZSpinner.setEditable(true);
+ col++;
+
+ gridPane.add(new Label("m"), col, row);
+ row++;
+ col=0;
+
+
+
+ //chain clustering
+ Label clusterTitleLabel = new Label("Result clustering");
+ //PamGuiManagerFX.titleFont2style(clusterTitleLabel);
+ clusterTitleLabel.setFont(Font.font(null,FontWeight.BOLD, 11));
+
+ gridPane.add(clusterTitleLabel, col, row);
+ GridPane.setColumnSpan(clusterTitleLabel, 7);
+ row++;
+
+
+ row++;
+ col=0;
+ Label label5 = new Label("Clustering");
+ label5.setAlignment(Pos.CENTER_RIGHT);
+ gridPane.add(label5, col, row);
+ col++;
+ clustering = new ComboBox();
+ clustering.getItems().addAll("None", "kMeans");
+ clustering.getSelectionModel().select(1);
+ gridPane.add(clustering, col, row);
+
+ GridPane.setColumnSpan(clustering, 3);
+
+ clustering.setOnAction((action)->{
+ enableControls();
+ });
+
+
+ row++;
+ col=0;
+
+
+ //kmeans settings - TODO - would be better to have a custom pane for each clustering algorithm
+ //but not worth the effort until more clustering algorithms are implemented.
+ Label label6 = new Label("Start");
+ label6.setAlignment(Pos.CENTER_RIGHT);
+ gridPane.add(label6, col, row);
+ col++;
+
+
+ PamHBox kMeansHolder = new PamHBox();
+ kMeansHolder.setSpacing(5);
+ kMeansHolder.setAlignment(Pos.CENTER_LEFT);
+
+ kMeansHolder.getChildren().add(numkMeans = new PamSpinner(1,Integer.MAX_VALUE, 20, 1));
+ numkMeans.setEditable(true);
+ numkMeans.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ numkMeans.setMaxWidth(JUMP_SPINNER_WIDTH);
+
+
+ kMeansHolder.getChildren().add(new Label("k-means and merge at <"));
+ kMeansHolder.getChildren().add(maxClustDist = new PamSpinner(0.,Double.MAX_VALUE, 5., 1));
+ maxClustDist.setEditable(true);
+ maxClustDist.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ maxClustDist.setMaxWidth(JUMP_SPINNER_WIDTH);
+ kMeansHolder.getChildren().add(new Label("m"));
+
+ gridPane.add(kMeansHolder, col, row);
+ GridPane.setColumnSpan(kMeansHolder, 7);
+
+ vBox.getChildren().add(gridPane);
+
+ enableControls();
+
+ return vBox;
+ }
+
+ private void enableControls() {
+ //clustering
+ numkMeans.setDisable(true);
+ maxClustDist.setDisable(true);
+ switch (clustering.getSelectionModel().getSelectedIndex()) {
+ case MCMCParams2.K_MEANS:
+ numkMeans.setDisable(false);
+ maxClustDist.setDisable(false);
+ break;
+ case MCMCParams2.NONE:
+ break;
+ }
+ }
+
+ @Override
+ public MCMCParams2 getParams(MCMCParams2 currParams) {
+
+ //chain settings.
+ currParams.numberOfChains = numChains.getValue();
+ currParams.numberOfJumps = numJumps.getValue();
+
+ double[] jumpSize = new double[3];
+
+ jumpSize[0] = jumpXSpinner.getValue();
+ jumpSize[1] = jumpYSpinner.getValue();
+ jumpSize[2] = jumpZSpinner.getValue();
+
+ currParams.jumpSize = jumpSize;
+
+ //bit messy but works...
+ currParams.setChainDispersion(startDispersion.getValue(), 3);
+
+ //cluster settings
+ currParams.clusterAnalysis = clustering.getSelectionModel().getSelectedIndex();
+ currParams.kmeanAttempts = numkMeans.getValue();
+ currParams.maxClusterSize = maxClustDist.getValue();
+
+ return currParams;
+ }
+
+ @Override
+ public void setParams(MCMCParams2 currParams) {
+
+ //chain settings.
+ numJumps.getValueFactory().setValue(currParams.numberOfJumps);
+
+ jumpXSpinner.getValueFactory().setValue(currParams.jumpSize[0]);
+ jumpYSpinner.getValueFactory().setValue(currParams.jumpSize[1]);
+ jumpZSpinner.getValueFactory().setValue(currParams.jumpSize[2]);
+
+ numChains.getValueFactory().setValue(currParams.numberOfChains);
+
+ //bit messy but works...
+ startDispersion.getValueFactory().setValue(Math.abs(currParams.chainStartDispersion[0][0]));
+
+
+ //cluster settings
+ clustering.getSelectionModel().select(currParams.clusterAnalysis);
+ numkMeans.getValueFactory().setValue(currParams.kmeanAttempts);
+ maxClustDist.getValueFactory().setValue(currParams.maxClusterSize);
+
+ //enable the controls.
+ enableControls();
+ }
+
+ @Override
+ public String getName() {
+ return "MCMC Settings";
+ }
+
+ @Override
+ public Node getContentNode() {
+ return mainPane;
+ }
+
+ @Override
+ public void paneInitialized() {
+ // TODO Auto-generated method stub
+
+ }
+
+
+}
diff --git a/src/Localiser/detectionGroupLocaliser/DetectionGroupLocaliser2.java b/src/Localiser/detectionGroupLocaliser/DetectionGroupLocaliser2.java
index 1420233f..964d83ef 100644
--- a/src/Localiser/detectionGroupLocaliser/DetectionGroupLocaliser2.java
+++ b/src/Localiser/detectionGroupLocaliser/DetectionGroupLocaliser2.java
@@ -132,7 +132,7 @@ public class DetectionGroupLocaliser2 implements Local
}
@Override
- public LocaliserPane getSettingsPane() {
+ public LocaliserPane getAlgorithmSettingsPane() {
return locAlgorithm.getSettingsPane();
}
diff --git a/src/Localiser/detectionGroupLocaliser/GroupLocResult.java b/src/Localiser/detectionGroupLocaliser/GroupLocResult.java
index 2b6b1c24..4b361768 100644
--- a/src/Localiser/detectionGroupLocaliser/GroupLocResult.java
+++ b/src/Localiser/detectionGroupLocaliser/GroupLocResult.java
@@ -16,6 +16,7 @@ import targetMotionOld.TargetMotionModel;
*
* Result class for the a group localiser. Usually this will be a target motion localisation, however could also be a group of DIFAR buoys
* or other systems which uses a set of detections to localise animals.
+ *
* @author Doug Gillespie
*
*/
@@ -75,8 +76,6 @@ public class GroupLocResult implements Comparable, LocalisationC
*/
private int dim=3;
- private ArrayList> MCMCJumpResults;
-
/**
* @param latLong
* @param chi2
@@ -132,16 +131,7 @@ public class GroupLocResult implements Comparable, LocalisationC
return side;
}
- /**Not the correct place to store**/
- @Deprecated
- public void setMCMCJumps(ArrayList> MCMCResults){
- this.MCMCJumpResults=MCMCResults;
- }
- @Deprecated
- public ArrayList> getMCMCJumps(){
- return MCMCJumpResults;
- }
/**
diff --git a/src/Map/MapDetectionsDialog.java b/src/Map/MapDetectionsDialog.java
index bb85bdb9..ed79530d 100644
--- a/src/Map/MapDetectionsDialog.java
+++ b/src/Map/MapDetectionsDialog.java
@@ -1,6 +1,7 @@
package Map;
import java.awt.BorderLayout;
+import java.awt.Color;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@@ -16,7 +17,11 @@ import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
+import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
+import org.kordamp.ikonli.swing.FontIcon;
+
import PamController.PamController;
+import PamView.component.PamSettingsIconButton;
import PamView.dialog.PamDialog;
import PamguardMVC.PamDataBlock;
import PamguardMVC.dataSelector.DataSelector;
@@ -85,7 +90,8 @@ public class MapDetectionsDialog extends PamDialog {
MapDetectionData md;
- ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+// ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+ FontIcon settingsIcon = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY);
for (int i = 0; i < n; i++) {
md = mapDetectionsParameters.mapDetectionDatas.get(i);
diff --git a/src/Map/MapPanel.java b/src/Map/MapPanel.java
index 225f01ef..cc00acd2 100644
--- a/src/Map/MapPanel.java
+++ b/src/Map/MapPanel.java
@@ -30,7 +30,6 @@ import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
-import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
@@ -39,17 +38,14 @@ import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.text.DecimalFormat;
import java.util.ArrayList;
-import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;
-import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
-import pamScrollSystem.PamScrollSlider;
import Array.ArrayManager;
import Array.PamArray;
import Array.SnapshotGeometry;
@@ -61,7 +57,6 @@ import GPS.GpsData;
import GPS.GpsDataUnit;
import Map.gridbaselayer.GridbaseControl;
import Map.gridbaselayer.MapRasterImage;
-import PamController.PamControlledUnit;
import PamController.PamController;
import PamController.PamControllerInterface;
import PamController.masterReference.MasterReferencePoint;
@@ -83,7 +78,6 @@ import PamView.PamColors.PamColor;
import PamView.panel.JPanelWithPamKey;
import PamView.panel.KeyPanel;
import PamView.paneloverlay.OverlayCheckboxMenuItem;
-import PamView.paneloverlay.overlaymark.MarkDataMatcher;
import PamView.paneloverlay.overlaymark.MarkDataSelector;
import PamView.paneloverlay.overlaymark.MarkOverlayDraw;
import PamView.symbol.PamSymbolChooser;
@@ -1476,9 +1470,9 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana
plotDetectorMenu.add(menuItem);
plotDetectorMenu.addSeparator();
- ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
- ImageIcon settingsIconNot = new ImageIcon(
- ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
+// ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+// ImageIcon settingsIconNot = new ImageIcon(
+// ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
ArrayList mddList = simpleMapRef.mapDetectionsManager.getMapDetectionDatas();
for (int i = 0; i < mddList.size(); i++) {
diff --git a/src/NMEA/AcquireNmeaData.java b/src/NMEA/AcquireNmeaData.java
index e86d0ba2..0402017c 100644
--- a/src/NMEA/AcquireNmeaData.java
+++ b/src/NMEA/AcquireNmeaData.java
@@ -40,8 +40,6 @@ import java.util.Random;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
-import org.apache.commons.math3.analysis.function.Signum;
-
import serialComms.jserialcomm.PJSerialComm;
import serialComms.jserialcomm.PJSerialException;
import serialComms.jserialcomm.PJSerialLineListener;
diff --git a/src/PamController/DataIntegrityChecker.java b/src/PamController/DataIntegrityChecker.java
new file mode 100644
index 00000000..566298e4
--- /dev/null
+++ b/src/PamController/DataIntegrityChecker.java
@@ -0,0 +1,12 @@
+package PamController;
+
+/**
+ * Provides a set of functions that can check and repair data.
+ * @author dg50
+ *
+ */
+public interface DataIntegrityChecker {
+
+ public boolean checkDataStore();
+
+}
diff --git a/src/PamController/DataOutputStore.java b/src/PamController/DataOutputStore.java
index a3536410..05c88d66 100644
--- a/src/PamController/DataOutputStore.java
+++ b/src/PamController/DataOutputStore.java
@@ -29,4 +29,11 @@ public interface DataOutputStore extends OfflineDataStore {
*/
public boolean deleteDataFrom(long timeMillis);
+ /**
+ * Get a data integrity checker. This can be called at startup to see if there is a problem.
+ * @return
+ */
+ public DataIntegrityChecker getInegrityChecker();
+
+
}
diff --git a/src/PamController/PamController.java b/src/PamController/PamController.java
index 447c876e..981669b4 100644
--- a/src/PamController/PamController.java
+++ b/src/PamController/PamController.java
@@ -100,6 +100,7 @@ import PamguardMVC.uid.UIDManager;
import PamguardMVC.uid.UIDOnlineManager;
import PamguardMVC.uid.UIDViewerManager;
import binaryFileStorage.BinaryStore;
+import export.ExportOptions;
import PamguardMVC.debug.Debug;
/**
@@ -1099,7 +1100,8 @@ public class PamController implements PamControllerInterface, PamSettings {
* later in the AWT event queue.
*/
public void startLater() {
- SwingUtilities.invokeLater(new StartLater(true));
+// SwingUtilities.invokeLater(new StartLater(true));
+ startLater(true);
}
public void startLater(boolean saveSettings) {
@@ -1173,6 +1175,7 @@ public class PamController implements PamControllerInterface, PamSettings {
@Override
public void manualStop() {
lastStartStopButton = BUTTON_STOP;
+ setManualStop(true);
pamStop();
}
@@ -1186,6 +1189,7 @@ public class PamController implements PamControllerInterface, PamSettings {
@Override
public boolean pamStart() {
// Debug.println("PAMController: pamStart");
+ setManualStop(false);
return pamStart(true);
}
@@ -1453,13 +1457,13 @@ public class PamController implements PamControllerInterface, PamSettings {
for (int iU = 0; iU < pamControlledUnits.size(); iU++) {
pamControlledUnits.get(iU).pamHasStopped();
}
- guiFrameManager.pamEnded();
-
long stopTime = PamCalendar.getTimeInMillis();
saveEndSettings(stopTime);
setPamStatus(PAM_IDLE);
+ guiFrameManager.pamEnded();
+
// no good having this here since it get's called at the end of every file.
// if (GlobalArguments.getParam(PamController.AUTOEXIT) != null) {
//// can exit here, since we've auto started, can auto exit.
@@ -2688,13 +2692,23 @@ public class PamController implements PamControllerInterface, PamSettings {
}
/**
- * Respond to storage options dialog. Selects whethere data
+ * Respond to storage options dialog. Selects whether data
* are stored in binary, database or both
* @param parentFrame
*/
public void storageOptions(JFrame parentFrame) {
StorageOptions.getInstance().showDialog(parentFrame);
}
+
+ /**
+ * Show export options tp export data to other formats
+ * @param parentFrame
+ */
+ public void exportData(JFrame parentFrame) {
+ ExportOptions.getInstance().showDialog(parentFrame);
+
+ }
+
/**
* Return a verbose level for debug output
@@ -2937,4 +2951,6 @@ public class PamController implements PamControllerInterface, PamSettings {
return pamConfiguration;
}
+
+
}
diff --git a/src/PamController/PamguardVersionInfo.java b/src/PamController/PamguardVersionInfo.java
index 12814aa5..b40c4afa 100644
--- a/src/PamController/PamguardVersionInfo.java
+++ b/src/PamController/PamguardVersionInfo.java
@@ -16,7 +16,7 @@ public class PamguardVersionInfo {
* @return release type
*/
static public ReleaseType getReleaseType() {
- return ReleaseType.OTHER;
+ return ReleaseType.BETA;
}
/**
@@ -31,12 +31,12 @@ public class PamguardVersionInfo {
* Version number, major version.minorversion.sub-release.
* Note: can't go higher than sub-release 'f'
*/
- static public final String version = "2.02.10ad";
+ static public final String version = "2.02.11d";
/**
* Release date
*/
- static public final String date = "13 March 2024";
+ static public final String date = "30 May 2024";
// /**
// * Release type - Beta or Core
diff --git a/src/PamController/fileprocessing/ReprocessStoreChoice.java b/src/PamController/fileprocessing/ReprocessStoreChoice.java
index 6a6bd019..ec41f6b4 100644
--- a/src/PamController/fileprocessing/ReprocessStoreChoice.java
+++ b/src/PamController/fileprocessing/ReprocessStoreChoice.java
@@ -24,7 +24,7 @@ public enum ReprocessStoreChoice {
case DONTSSTART:
return "Don't start processing";
case OVERWRITEALL:
- return "Overwrite existing output data";
+ return "Overwrite all existing output data";
default:
break;
}
@@ -42,7 +42,7 @@ public enum ReprocessStoreChoice {
case DONTSSTART:
return "Processing will not start. Select alternative storage locations / databases and try again";
case OVERWRITEALL:
- return "Overwrite existing output data. Existing data will be deleted";
+ return "Overwrite existing output data. All existing data will be deleted";
default:
break;
}
diff --git a/src/PamController/settings/output/xml/PamguardXMLWriter.java b/src/PamController/settings/output/xml/PamguardXMLWriter.java
index f74edce0..2a71a250 100644
--- a/src/PamController/settings/output/xml/PamguardXMLWriter.java
+++ b/src/PamController/settings/output/xml/PamguardXMLWriter.java
@@ -570,6 +570,9 @@ public class PamguardXMLWriter implements PamSettings {
*/
private Element writeSettings(Document doc, PamSettings pamSettings, Object data, ArrayList