Merge branch 'main' into restart

This commit is contained in:
Douglas Gillespie 2024-06-20 09:47:26 +01:00 committed by GitHub
commit 5cdf408f84
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
656 changed files with 40032 additions and 8292 deletions

View File

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

70
.gitignore vendored
View File

@ -41,3 +41,73 @@ settings.xml
.classpath
.classpath
.classpath
.metadata/version.ini
.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
.metadata/.plugins/org.eclipse.ui.intro/introstate
.metadata/.plugins/org.eclipse.tips.ide/dialog_settings.xml
.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup
.metadata/.plugins/org.eclipse.m2e.logback/logback.2.1.100.20230106-1511.xml
.metadata/.plugins/org.eclipse.m2e.core/workspaceState.ser
.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml
.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml
.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat
.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache
.metadata/.plugins/org.eclipse.jdt.core/javaLikeNames.txt
.metadata/.plugins/org.eclipse.jdt.core/externalFilesCache
.metadata/.plugins/org.eclipse.jdt.core/assumedExternalFilesCache
.metadata/.plugins/org.eclipse.egit.core/.org.eclipse.egit.core.cmp/.settings/org.eclipse.core.resources.prefs
.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.m2e.discovery.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources
.metadata/.plugins/org.eclipse.core.resources/.root/1.tree
.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version
.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index
.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version
.metadata/.plugins/org.eclipse.core.resources/.projects/.org.eclipse.egit.core.cmp/.location
.metadata/.lock
.metadata/version.ini
.metadata/.plugins/org.eclipse.ui.workbench/workingsets.xml
.metadata/.plugins/org.eclipse.ui.intro/introstate
.metadata/.plugins/org.eclipse.tips.ide/dialog_settings.xml
.metadata/.plugins/org.eclipse.oomph.setup/workspace.setup
.metadata/.plugins/org.eclipse.m2e.logback/logback.2.1.100.20230106-1511.xml
.metadata/.plugins/org.eclipse.m2e.core/workspaceState.ser
.metadata/.plugins/org.eclipse.jdt.ui/QualifiedTypeNameHistory.xml
.metadata/.plugins/org.eclipse.jdt.ui/OpenTypeHistory.xml
.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
.metadata/.plugins/org.eclipse.jdt.core/variablesAndContainers.dat
.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache
.metadata/.plugins/org.eclipse.jdt.core/javaLikeNames.txt
.metadata/.plugins/org.eclipse.jdt.core/externalFilesCache
.metadata/.plugins/org.eclipse.jdt.core/assumedExternalFilesCache
.metadata/.plugins/org.eclipse.egit.core/.org.eclipse.egit.core.cmp/.settings/org.eclipse.core.resources.prefs
.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.workbench.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.m2e.discovery.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs
.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.core.resources.prefs
.metadata/.plugins/org.eclipse.core.resources/.safetable/org.eclipse.core.resources
.metadata/.plugins/org.eclipse.core.resources/.root/1.tree
.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.version
.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/properties.index
.metadata/.plugins/org.eclipse.core.resources/.root/.indexes/history.version
.settings/org.eclipse.jdt.core.prefs
.settings/org.eclipse.core.resources.prefs
.classpath
.classpath
.project
.classpath
.classpath
.classpath
.classpath
.classpath
.classpath
.settings/org.eclipse.jdt.core.prefs

0
.metadata/.lock Normal file
View File

View File

@ -0,0 +1,3 @@
eclipse.preferences.version=1
encoding=UTF-8
version=1

View File

@ -0,0 +1,7 @@
eclipse.preferences.version=1
org.eclipse.jdt.ui.formatterprofiles.version=23
spelling_locale=en_GB
spelling_locale_initialized=true
typefilter_migrated_2=true
useAnnotationsPrefPage=true
useQuickDiffPrefPage=true

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
org.eclipse.m2e.discovery.pref.projects=

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
platformState=1678968029917
quickStart=false
tipsAndTricks=true

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
showIntro=false

View File

@ -0,0 +1,12 @@
//org.eclipse.ui.commands/state/org.eclipse.ui.navigator.resources.nested.changeProjectPresentation/org.eclipse.ui.commands.radioState=false
PLUGINS_NOT_ACTIVATED_ON_STARTUP=;org.eclipse.m2e.discovery;
eclipse.preferences.version=1
org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_BG_END=41,41,41
org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_BG_START=43,44,45
org.eclipse.ui.workbench.ACTIVE_NOFOCUS_TAB_TEXT_COLOR=204,204,204
org.eclipse.ui.workbench.ACTIVE_TAB_BG_END=41,41,41
org.eclipse.ui.workbench.ACTIVE_TAB_BG_START=43,44,45
org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR=221,221,221
org.eclipse.ui.workbench.INACTIVE_TAB_BG_END=49,53,56
org.eclipse.ui.workbench.INACTIVE_TAB_BG_START=59,64,66
org.eclipse.ui.workbench.INACTIVE_TAB_TEXT_COLOR=187,187,187

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -0,0 +1 @@
java

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<typeInfoHistroy/>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<qualifiedTypeNameHistroy/>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<section name="Workbench">
<section name="org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart">
<item key="group_libraries" value="true"/>
<item key="layout" value="2"/>
<item key="rootMode" value="1"/>
<item key="linkWithEditor" value="false"/>
<item key="memento" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#x0A;&lt;packageExplorer group_libraries=&quot;1&quot; layout=&quot;2&quot; linkWithEditor=&quot;0&quot; rootMode=&quot;1&quot; workingSetName=&quot;Aggregate for window 1678968099026&quot;&gt;&#x0A;&lt;customFilters userDefinedPatternsEnabled=&quot;false&quot;&gt;&#x0A;&lt;xmlDefinedFilters&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.StaticsFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.buildship.ui.packageexplorer.filter.gradle.buildfolder&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.NonJavaProjectsFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer_patternFilterId_.*&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.NonSharedProjectsFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.SyntheticMembersFilter&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.ContainedLibraryFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.internal.ui.PackageExplorer.HideInnerClassFilesFilter&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.internal.ui.PackageExplorer.EmptyInnerPackageFilter&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.m2e.MavenModuleFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.buildship.ui.packageexplorer.filter.gradle.subProject&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.ClosedProjectsFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.DeprecatedMembersFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.EmptyLibraryContainerFilter&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.PackageDeclarationFilter&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.ImportDeclarationFilter&quot; isEnabled=&quot;true&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.NonJavaElementFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.LibraryFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.CuAndClassFileFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.internal.ui.PackageExplorer.EmptyPackageFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.NonPublicFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.LocalTypesFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;child filterId=&quot;org.eclipse.jdt.ui.PackageExplorer.FieldsFilter&quot; isEnabled=&quot;false&quot;/&gt;&#x0A;&lt;/xmlDefinedFilters&gt;&#x0A;&lt;/customFilters&gt;&#x0A;&lt;/packageExplorer&gt;"/>
</section>
</section>

View File

@ -0,0 +1,41 @@
<configuration scan="true">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%date [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>OFF</level> <!-- change to DEBUG to mimic '-consolelog' behaviour -->
</filter>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${org.eclipse.m2e.log.dir}/0.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
<FileNamePattern>${org.eclipse.m2e.log.dir}/%i.log</FileNamePattern>
<MinIndex>1</MinIndex>
<MaxIndex>10</MaxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%date [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="EclipseLog" class="org.eclipse.m2e.logback.appender.EclipseLogAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
</appender>
<appender name="MavenConsoleLog" class="org.eclipse.m2e.logback.appender.MavenConsoleAppender">
</appender>
<root level="INFO">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
<appender-ref ref="EclipseLog" />
<appender-ref ref="MavenConsoleLog" />
</root>
</configuration>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<setup:Workspace
xmi:version="2.0"
xmlns:xmi="http://www.omg.org/XMI"
xmlns:setup="http://www.eclipse.org/oomph/setup/1.0"
name="workspace"/>

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<section name="Workbench">
</section>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<state reopen="false"/>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<workingSetManager>
<workingSet editPageId="org.eclipse.jdt.internal.ui.DynamicSourcesWorkingSet" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1678968098501_0" label="Java Main Sources" name="Java Main Sources"/>
<workingSet editPageId="org.eclipse.jdt.internal.ui.DynamicSourcesWorkingSet" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1678968098508_1" label="Java Test Sources" name="Java Test Sources"/>
<workingSet aggregate="true" factoryID="org.eclipse.ui.internal.WorkingSetFactory" id="1678968099026_2" label="Window Working Set" name="Aggregate for window 1678968099026"/>
</workingSetManager>

3
.metadata/version.ini Normal file
View File

@ -0,0 +1,3 @@
#Thu Mar 16 12:01:36 GMT 2023
org.eclipse.core.runtime=2
org.eclipse.platform=4.27.0.v20230302-0300

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>PamGuard Main Tethys</name>
<name>PAMGuard</name>
<comment></comment>
<projects>
</projects>

View File

@ -1,4 +1,5 @@
eclipse.preferences.version=1
encoding//src/rawDeepLearningClassifer/segmenter/SegmenterProcess.java=UTF-8
encoding//src/test/resources=UTF-8
encoding/<project>=UTF-8
encoding/src=UTF-8

View File

@ -1,9 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@ -13,4 +13,4 @@ org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=11
org.eclipse.jdt.core.compiler.source=17

View File

@ -387,8 +387,11 @@ PamguardBeta_ViewerMode.exe):</p>
<h1><a name="_LATEST_VERSION_2.02.03"></a><a name="_VERSION_2.02.07_January"></a><a
name="_Latest_Version_2.02.10"></a><em><span style='font-size:12.0pt;
font-family:"Cambria",serif;font-style:normal'><a
href="#_Version_2.02.10_January">Latest Version 2.02.10 January 2024</a></span></em></h1>
font-family:"Cambria",serif;font-style:normal'><a href="#_Version_2.02.11_April">Latest
Version 2.02.11 April 2024</a></span></em></h1>
<h1><em><span style='font-size:12.0pt;font-family:"Cambria",serif;font-style:
normal'><a href="#_Version_2.02.10_January">Version 2.02.10 January 2024</a></span></em></h1>
<h1><em><span style='font-size:12.0pt;font-family:"Cambria",serif;font-style:
normal'><a href="#_Version_2.02.09_June">Version 2.02.09 June 2023</a></span></em></h1>
@ -461,14 +464,47 @@ Version 2.00.10 June 2017</a></span></h1>
<h1><a name="_Latest_Version_2.02.03_1"></a><a name="_Latest_Version_2.02.05"></a><a
name="_Latest_Version_2.02.06"></a><a name="_Latest_Version_2.02.07"></a><a
name="_Latest_Version_2.02.08"></a><a name="_Version_2.02.09_June"></a><a
name="_Version_2.02.10_January"></a>Version 2.02.10 January 2024</h1>
name="_Version_2.02.10_January"></a><a name="_Version_2.02.11_April"></a>Version
2.02.11 April 2024</h1>
<p class=MsoNormal>&nbsp;</p>
<h2>New Features</h2>
<p class=MsoNormal>Click detector: Remembers locations of displays and doesnt
continually reset them. </p>
<p class=MsoNormal>Help for Matched Click Classifier</p>
<h2>Bug Fixes</h2>
<p class=MsoNormal>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. </p>
<p class=MsoNormal>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. </p>
<p class=MsoNormal>Lookup tables: fix feature which was causing table entries
to repeat. </p>
<p class=MsoNormal>Click Train Detector: Add exception handlers to avoid errors
as PAMGuard stops / restarts. </p>
<p class=MsoNormal>Group Detection starts and ends: Check data integrity
function fixed and now inserts correct times of start and ends of events into
database. </p>
<h1>Version 2.02.10 January 2024</h1>
<h2><span lang=EN-US>New Features</span></h2>
<p class=MsoNormal><b><span lang=EN-US>Importing modules</span></b><span
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
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. </span></p>
@ -496,9 +532,9 @@ correctly saving updated bearings to the database. Now fixed. </span></p>
<p class=MsoNormal><b><span lang=EN-US>ROCCA Classifier fixes</span></b></p>
<p class=MsoNormal><span lang=EN-US>Allow Rocca to run without classifiers:
Fixed bug that threw an error if no classifier files were &nbsp;specified in
Rocca Params dialog</span></p>
<p class=MsoNormal><span lang=EN-US>Allow Rocca to run without classifiers: Fixed
bug that threw an error if no classifier files were &nbsp;specified in Rocca
Params dialog</span></p>
<p class=MsoNormal><span lang=EN-US>Fix memory issue with
RoccaContourDataBlocks not being released for garbage collection</span></p>
@ -596,9 +632,9 @@ angle offsets applied to static hydrophones in viewer mode. This is now fixed. <
<p class=MsoNormal><span lang=EN-US>Click tool bar: Correctly shows event
selection options even if no species classification options are in place. </span></p>
<p class=MsoNormal><span lang=EN-US>Fixed Landmarks: Earlier versions were losing
these every time PAMGuard started or new data were loaded in viewer mode. Now
fixed. </span></p>
<p class=MsoNormal><span lang=EN-US>Fixed Landmarks: Earlier versions were
losing these every time PAMGuard started or new data were loaded in viewer
mode. Now fixed. </span></p>
<p class=MsoNormal><span lang=EN-US>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.</span></p>
<p class=MsoNormal><span lang=EN-US>See major release notes for V 2.02.01
below. </span></p>
<p class=MsoNormal><span lang=EN-US>Bug 495: TD FX display throws NullPointerException
if user has removed all data units and then moves mouse over display area.</span></p>
<p class=MsoNormal><span lang=EN-US>Bug 495: TD FX display throws
NullPointerException if user has removed all data units and then moves mouse
over display area.</span></p>
<h1><a name="_Latest_Version_2.02.01"></a><span lang=EN-US>Version 2.02.01
October 2021</span></h1>
@ -791,11 +828,11 @@ font-family:"Times New Roman",serif'>&nbsp;</span></p>
<h2>File Format Change</h2>
<p class=MsoNormal>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.</p>
<p class=MsoNormal>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.</p>
<p class=MsoNormal style='margin-bottom:0cm'><span style='font-size:12.0pt;
font-family:"Times New Roman",serif'>&nbsp;</span></p>
@ -1181,10 +1218,10 @@ lang=EN-US> </span>Add functionality for bluetooth headsets. </p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>2. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span
lang=EN-US> </span>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). </p>
lang=EN-US> </span>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). </p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>3. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span
@ -1415,9 +1452,9 @@ be compatible with this version, and vice-versa.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>2. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
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.</p>
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.</p>
<!-- ************************************************************************************************************************** --><!-- ************************************************************************************************************************** -->
@ -1706,8 +1743,8 @@ with installation and use of this version.</span></p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>1. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>Bug 338. Problem displaying coastlines and bathymetric contours around the
dateline (+/- 180 longitude) in the map.</p>
</span>Bug 338. Problem displaying coastlines and bathymetric contours around
the dateline (+/- 180 longitude) in the map.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>2. </span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -2218,8 +2255,8 @@ UID
<p class=MsoNormal><span lang=EN-US>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. </span></p>
@ -2295,8 +2332,8 @@ Hawaii/Temperate Pacific/North Atlantic datasets. This has been corrected.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>2.</span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>Bug 320. Pamguard stopped reading Click Detector Event data from database
when target motion analysis information was encountered. Corrected.</p>
</span>Bug 320. Pamguard stopped reading Click Detector Event data from
database when target motion analysis information was encountered. Corrected.</p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>3.</span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -2578,9 +2615,9 @@ main click detector display. </span></p>
<p class=MsoNormal><b><span lang=EN-US>Target Motion Analysis</span></b></p>
<p class=MsoNormal><span lang=EN-US>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:</span></p>
<p class=MsoNormal><span lang=EN-US>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:</span></p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>1.</span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -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. </span></p>
<h1><a name="_Latest_Version_1.15.02"></a><span lang=EN-US>Version 1.15.02 March
2016</span></h1>
<h1><a name="_Latest_Version_1.15.02"></a><span lang=EN-US>Version 1.15.02
March 2016</span></h1>
<p class=MsoNormal>A number of small bug fixes following release of 1.15.00.</p>
@ -2905,13 +2942,13 @@ for details. </span></p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>3.</span><span
lang=EN-US style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span><span lang=EN-US>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
</span><span lang=EN-US>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. </span></p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span lang=EN-US>4.</span><span
@ -3018,8 +3055,8 @@ allocation to allow more memory for the database interface. Hopefully Fixed. </p
<p class=MsoListParagraph style='margin-left:38.25pt;text-indent:-20.25pt'><span
lang=EN-AU>9.</span><span lang=EN-AU style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>Bug 239. <span lang=EN-AU>Fixed bug in the DIFAR module that was
incorrectly preventing cross-fixes for some calls.</span></p>
</span>Bug 239. <span lang=EN-AU>Fixed bug in the DIFAR module that was incorrectly
preventing cross-fixes for some calls.</span></p>
<p class=MsoNormal>Details of these bugs can be found at <a
href="https://sourceforge.net/p/pamguard/bugs">https://sourceforge.net/p/pamguard/bugs</a></p>
@ -3210,8 +3247,9 @@ to read on a time. Fixed</p>
<p class=MsoNormal><i>Menu Layout</i></p>
<p class=MsoNormal>The PAMGuard menus have been rearranged into a more intuitive
grouping which we believe will help users find functionality more easily. </p>
<p class=MsoNormal>The PAMGuard menus have been rearranged into a more
intuitive grouping which we believe will help users find functionality more
easily. </p>
<p class=MsoNormal>'Detection' menu has been renamed to 'Settings' since many
menu items within this menu were not directly to do with 'Detection'.</p>
@ -3302,9 +3340,9 @@ of third octave noise bands. See online help for details. </p>
<p class=MsoNormal><i>Filtered Noise Measurement</i> (Sound Processing Group)</p>
<p class=MsoNormal>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. </p>
<p class=MsoNormal>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. </p>
<p class=MsoNormal><i>Envelope Tracing</i> (Beta Only, Sound Processing Group)</p>
@ -3340,10 +3378,11 @@ different. Details are available in the online help. </p>
<p class=MsoNormal><i>FLAC File Support</i></p>
<p class=MsoNormal>Can now read raw audio data direct from FLAC files. <a
href="http://en.wikipedia.org/wiki/FLAC">FLAC</a> 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. </p>
href="http://en.wikipedia.org/wiki/FLAC">FLAC</a> 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. </p>
<p class=MsoNormal><i>Sound Recorder Module</i></p>
@ -3476,9 +3515,9 @@ to these menus to provide additional information to users. &nbsp;</p>
<p class=MsoNormal style='margin-left:36.0pt'><i>Radar Display</i></p>
<p class=MsoNormal style='margin-left:36.0pt'>Functionality has been added to
the radar display so that bearings can be shown relative to either the vessel
or to true North. </p>
<p class=MsoNormal style='margin-left:36.0pt'>Functionality has been added to the
radar display so that bearings can be shown relative to either the vessel or to
true North. </p>
<p class=MsoNormal style='margin-left:36.0pt'>Better control of data in viewer
mode, making is easy to scroll through and view data for short time periods. </p>
@ -4116,8 +4155,8 @@ Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>This results in a major speed up of data exchange between modules and can
lead to a x4 improvement in overall performance. </p>
</span>This results in a major speed up of data exchange between modules and
can lead to a x4 improvement in overall performance. </p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -4230,9 +4269,9 @@ Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>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. </p>
</span>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. </p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -4263,11 +4302,11 @@ Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>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.&nbsp; </p>
</span>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.&nbsp; </p>
<p class=MsoListParagraph style='text-indent:-18.0pt'><span style='font-family:
Symbol'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -4335,8 +4374,8 @@ online help. </p>
<p class=MsoNormal><b>PAMGUARD Mixed Mode operation</b></p>
<p class=MsoNormal>Analyses data from wav or AIF file and synchronises it with
GPS data reloaded from a database so that detected sounds may be correctly
<p class=MsoNormal>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'>'</span><span style='font-size:7.0pt;font-family:"Times New Roman",serif
<p class=MsoNormal>&nbsp;</p>
<p class=MsoNormal><a name="_Toc312065304"></a><a name="_Toc312063949"></a><span
class=Heading2Char><span style='font-size:13.0pt'>1.0Beta 22 Jan 2008 - Pamguard
starts two releases, core and beta release</span></span>, </p>
class=Heading2Char><span style='font-size:13.0pt'>1.0Beta 22 Jan 2008 -
Pamguard starts two releases, core and beta release</span></span>, </p>
<p class=MsoNormal>this is the beta release</p>

View File

@ -3,16 +3,17 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.pamguard</groupId>
<artifactId>Pamguard</artifactId>
<name>Pamguard Java12+</name>
<version>2.02.10b</version>
<description>Pamguard for Java 12+, using Maven to control dependcies</description>
<name>Pamguard</name>
<version>2.02.11d</version>
<description>Pamguard using Maven to control dependencies</description>
<url>www.pamguard.org</url>
<organization>
<name>Sea Mammal Research Unit, University of St. Andrews</name>
<url>http://www.smru.st-andrews.ac.uk</url>
</organization>
<build>
<sourceDirectory>src</sourceDirectory>
<sourceDirectory>${basedir}/src</sourceDirectory>
<testSourceDirectory>${basedir}/src/test</testSourceDirectory>
<resources>
<resource>
<directory>src</directory>
@ -54,7 +55,7 @@
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<version>3.12.1</version>
<dependencies>
<dependency>
<groupId>org.eclipse.tycho</groupId>
@ -63,22 +64,14 @@
</dependency>
</dependencies>
<configuration>
<release>11</release>
<release>21</release>
<compilerId>jdt</compilerId>
<compilerArguments>
<properties>.settings/org.eclipse.jdt.core.prefs</properties>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<configuration>
<source>17</source>
<target>17</target>
<release>17</release>
</configuration>
<version>0.0.8</version>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
@ -165,11 +158,8 @@
<url>https://artifacts.unidata.ucar.edu/repository/unidata-all/</url>
</repository>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>bedatadriven</id>
<name>bedatadriven_renjin</name>
<name>bedatadriven public repo</name>
<url>https://nexus.bedatadriven.com/content/groups/public/</url>
</repository>
<repository>
@ -198,7 +188,7 @@
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javafx.version>16</javafx.version>
<javafx.version>21</javafx.version>
<jaxb.runtime.version>2.4.0-b180830.0438</jaxb.runtime.version>
<jaxb.xjc.version>2.4.0-b180830.0438</jaxb.xjc.version>
<jaxb.api.version>2.4.0-b180830.0359</jaxb.api.version>

Binary file not shown.

Binary file not shown.

Binary file not shown.

1536
pom.xml

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -1,9 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<<<<<<<< HEAD:repo/tethys/org/javaclient/3.0/javaclient-3.0.pom
<groupId>tethys.org</groupId>
<artifactId>javaclient</artifactId>
<version>3.0</version>
========
<groupId>pamguard.org</groupId>
<artifactId>x3</artifactId>
<version>2.2.6</version>
>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.6/x3-2.2.6.pom
<description>POM was created from install:install-file</description>
</project>

View File

@ -2,8 +2,14 @@
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<<<<<<<< HEAD:repo/tethys/org/nilus/3.0/nilus-3.0.pom
<groupId>tethys.org</groupId>
<artifactId>nilus</artifactId>
<version>3.0</version>
========
<groupId>pamguard.org</groupId>
<artifactId>x3</artifactId>
<version>2.2.7</version>
>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom
<description>POM was created from install:install-file</description>
</project>

View File

@ -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

View File

@ -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

View File

@ -2,8 +2,14 @@
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<<<<<<<< HEAD:repo/tethys/org/javaclient/3.0/javaclient-3.0.pom
<groupId>tethys.org</groupId>
<artifactId>javaclient</artifactId>
<version>3.0</version>
========
<groupId>pamguard.org</groupId>
<artifactId>x3</artifactId>
<version>2.2.6</version>
>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.6/x3-2.2.6.pom
<description>POM was created from install:install-file</description>
</project>

View File

@ -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

View File

@ -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>=

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2,8 +2,14 @@
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<<<<<<<< HEAD:repo/tethys/org/nilus/3.0/nilus-3.0.pom
<groupId>tethys.org</groupId>
<artifactId>nilus</artifactId>
<version>3.0</version>
========
<groupId>pamguard.org</groupId>
<artifactId>x3</artifactId>
<version>2.2.7</version>
>>>>>>>> upstream/main:repo/pamguard/org/x3/2.2.7/x3-2.2.7.pom
<description>POM was created from install:install-file</description>
</project>

View File

@ -7,6 +7,6 @@
<versions>
<version>3.0</version>
</versions>
<lastUpdated>20231221111413</lastUpdated>
<lastUpdated>20240307115557</lastUpdated>
</versioning>
</metadata>

View File

@ -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();

View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -290,7 +290,7 @@ public class AcquisitionPaneFX extends SettingsPane<AcquisitionParameters>{
//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();

View File

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

View File

@ -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();
}

View File

@ -193,20 +193,18 @@ public class FolderInputPane extends DAQSettingsPane<FolderInputParameters>{
//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);
});

View File

@ -30,8 +30,7 @@ public class OfflineDAQPane extends SettingsPane<OfflineFileParameters>{
private PamBorderPane mainPane;
public OfflineDAQPane(OfflineFileDataStore acquisitionControl,
AcquisitionPaneFX acquisitionPaneFX){
public OfflineDAQPane(OfflineFileDataStore acquisitionControl){
super(null);
this.mainPane= new PamBorderPane();
mainPane.setCenter(createOfflinePane());

View File

@ -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<PamAudioFileLoader> getAudioFileLoaders() {
return this.pamAudioFileTypes;

View File

@ -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();
}
}

View File

@ -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) {

View File

@ -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;

View File

@ -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);
}
}

View File

@ -10,13 +10,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.JFrame;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import pamMaths.PamQuaternion;
import pamMaths.PamVector;
import userDisplay.UserDisplayControl;
import depthReadout.DepthControl;
import Array.importHydrophoneData.HydrophoneImport;
import Array.importHydrophoneData.StreamerImport;
import Array.layoutFX.ArrayGUIFX;
@ -91,7 +87,7 @@ public class ArrayManager extends PamControlledUnit implements PamSettings, PamO
// private DepthControl depthControl;
private ImportDataSystem<ArrayList<Double>> hydrophoneImportManager;
private ImportDataSystem<Hydrophone> hydrophoneImportManager;
private ImportDataSystem<ArrayList<Double>> streamerImportManager;
@ -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<ArrayList<Double>>(new HydrophoneImport(hydrophonesProcess.getHydrophoneDataBlock()));
hydrophoneImportManager= new ImportDataSystem<Hydrophone>(new HydrophoneImport(hydrophonesProcess.getHydrophoneDataBlock()));
hydrophoneImportManager.setName("Hydrophone Data Import");
streamerImportManager = new ImportDataSystem<ArrayList<Double>>(new StreamerImport(hydrophonesProcess.getStreamerDataBlock()));
streamerImportManager.setName("Streamer Data Import");
@ -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);
}

View File

@ -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;
}

View File

@ -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<HydrophoneDataUnit> {
@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<HydrophoneDataUnit> {
}
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<HydrophoneDataUnit> {
}
newdifference = Math.abs(startTime- preceedingUnit.getTimeMilliseconds());
if (newdifference > difference) {
// System.out.println("Hydrophone datablock: newDifference: " + newdifference + " " + unit.getHydrophone().getZ());
return unit;
}
else {

View File

@ -397,6 +397,8 @@ public class HydrophoneElementDialog extends PamDialog {
dz.setText(null);
}
}
boolean getParams() {
double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();

View File

@ -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();

View File

@ -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,

View File

@ -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");
}

View File

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

View File

@ -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.
* <p>
PAMGUARD co-rdinate system is
* <p>
* x points right
* <p>
* y points north or into the screen
* <p>
* z is height and points up
* <p><p>
* This is different from the JavAFX 3D system in which
* <p>
* x points right
* <p>
* y points down
* <p>
* z points into the screen
* <p>
* 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<HydrophoneSphere> hydrophonesSpheres = new ArrayList<HydrophoneSphere>();
/**
* 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<MouseEvent>() {
@Override public void handle(MouseEvent me) {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseOldX = me.getSceneX();
mouseOldY = me.getSceneY();
}
});
scene.setOnScroll(new EventHandler<ScrollEvent>() {
@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<MouseEvent>() {
@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<Hydrophone> hydrophones = array.getHydrophoneArray();
//draw hydrophones
HydrophoneSphere sphere;
Streamer streamer;
hydrophonesSpheres.clear();
for (int i=0; i<hydrophones.size(); i++){
//get the streamer for the hydrophone
streamer = array.getStreamer(hydrophones.get(i).getStreamerId());
double x = (hydrophones.get(i).getX() + streamer.getCoordinate(0));
double y = (hydrophones.get(i).getY() + streamer.getCoordinate(1));
double z = -(hydrophones.get(i).getZ() + streamer.getCoordinate(2));
sphere=new HydrophoneSphere(hydrophoneSize*scaleFactor);
sphere.setTranslateX(x*scaleFactor);
sphere.setTranslateY(z*scaleFactor);
sphere.setTranslateZ(y*scaleFactor);
Color col = Color.RED;
final PhongMaterial aMaterial = new PhongMaterial();
aMaterial.setDiffuseColor(col);
aMaterial.setSpecularColor(col.brighter());
sphere.setMaterial(aMaterial);
sphere.setHydrophone(hydrophones.get(i));
// System.out.println("Add hydrophone: " + x + " " + y + " " +z);
hydrophonesSpheres.add(sphere);
arrayGroup.getChildren().add(sphere);
ArrayList<Point3D> streamerPoints=new ArrayList<Point3D>();
//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<ArrayList<ArrayPos>> 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<pos.get(i).size(); j++){
// drawArray(pos.get(i).get(j));
// }
// }
//
// //System.out.println("Draw 3D hydrophone array");
// }
// /**
// * Draw an array.
// * @param arrayPos - hydrophone and streamer positions in the same co-ordinate frame as the reference frame.
// */
// private void drawArray(ArrayPos arrayPos){
//
// final PhongMaterial redMaterial = new PhongMaterial();
// redMaterial.setDiffuseColor(DEFAULT_HYDRO_COL);
// redMaterial.setSpecularColor(DEFAULT_HYDRO_COL.brighter());
//
// final PhongMaterial greenMaterial = new PhongMaterial();
// greenMaterial.setDiffuseColor(DEFAULT_SENSOR_COL);
// greenMaterial.setSpecularColor(DEFAULT_SENSOR_COL.brighter());
//
// //draw hydrophones
// Sphere sphere;
// for (int i=0; i<arrayPos.getTransformHydrophonePos().size(); i++){
// sphere=new Sphere(settings.hydrophoneSize*scaleFactor);
// sphere.setTranslateX(arrayPos.getTransformHydrophonePos().get(i)[0]*scaleFactor);
// sphere.setTranslateY(-arrayPos.getTransformHydrophonePos().get(i)[2]*scaleFactor);
// sphere.setTranslateZ(arrayPos.getTransformHydrophonePos().get(i)[1]*scaleFactor);
//
// Color hydroCol = settings.hydrophoneColours[arrayPos.getHArray().getHydrophones().get(i).channel.get()];
//
// if (hydroCol == null) {
// sphere.setMaterial(redMaterial);
// }
// else {
// final PhongMaterial aMaterial = new PhongMaterial();
// aMaterial.setDiffuseColor(hydroCol);
// aMaterial.setSpecularColor(hydroCol.brighter());
// sphere.setMaterial(aMaterial);
//
// }
// arrayGroup.getChildren().add(sphere);
//
// }
//
//
//
// //draw streamer
// PolyLine3D polyLine3D;
// ArrayList<Point3D> streamerPoints;
//
// for (int i=0; i<arrayPos.getTransformStreamerPositions().size(); i++){
// if (arrayPos.getTransformStreamerPositions().get(i)==null) return;
// streamerPoints=new ArrayList<Point3D>();
// for (int j=0; j<arrayPos.getTransformStreamerPositions().get(i).size(); j++){
//
// //TODO- use cylinder for line
// // Cylinder cylinder=createConnection(arrayPos.getTransformStreamerPositions().get(i).get(j).multiply(scaleFactor), arrayPos.getTransformStreamerPositions().get(i).get(j+1).multiply(scaleFactor),0.2*scaleFactor);
// // arrayGroup.getChildren().add(cylinder);
//
// //need to convert to fxyz 3D point - stupid but no work around.
// Point3D newPoint=new Point3D((float) (arrayPos.getTransformStreamerPositions().get(i).get(j).getX()*scaleFactor),
// (float) (-arrayPos.getTransformStreamerPositions().get(i).get(j).getZ()*scaleFactor), (float) (arrayPos.getTransformStreamerPositions().get(i).get(j).getY()*scaleFactor));
// streamerPoints.add(newPoint);
// }
// polyLine3D=new PolyLine3D(streamerPoints, 4, Color.BLUE);
// arrayGroup.getChildren().add(polyLine3D);
// }
//
// }
}

View File

@ -0,0 +1,15 @@
package Array.layoutFX;
public interface ArrayChangeListener {
int STREAMER_CHANGE = 0;
int HYDROPHONE_CHANGE = 1;
/**
* Called whenever a hydrophone or streamer changes.
* @param type - the type of change e.g. ArrayChangeListener.HYDROPHONE_CHANGE
* @param changedObject - the changed object - hydrophone or streamer property.
*/
public void arrayChanged(int type, Object changedObject);
}

View File

@ -7,6 +7,7 @@ import pamViewFX.PamControlledGUIFX;
/**
* JavaFX UI bits of the Array Manager.
*
* @author Jamie Macaulay
*
*/
@ -30,12 +31,17 @@ public class ArrayGUIFX extends PamControlledGUIFX {
if (arraySettingsPane==null) {
arraySettingsPane= new ArraySettingsPane();
}
System.out.println("The current array is "+ arrayManager.getCurrentArray());
arraySettingsPane.setParams(arrayManager.getCurrentArray());
return arraySettingsPane;
}
@Override
public void updateParams() {
System.out.println("The current array is "+ arrayManager.getCurrentArray());
PamArray newParams=arraySettingsPane.getParams(arrayManager.getCurrentArray());
if (newParams!=null) arrayManager.setCurrentArray(newParams);
//setup the controlled unit.
arrayManager.setupControlledUnit();

View File

@ -1,45 +1,400 @@
package Array.layoutFX;
import java.io.File;
import org.controlsfx.control.SegmentedButton;
import Array.ArrayManager;
import Array.Hydrophone;
import Array.PamArray;
import PamController.PamController;
import PamController.SettingsPane;
import javafx.scene.Node;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxGlyphs.PamGlyphDude;
import pamViewFX.fxNodes.PamVBox;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamButton;
import pamViewFX.fxNodes.PamHBox;
/**
* The main settings pane for settings up a hydrophone array.
*
* @author Jamie Macaulay
*
* @param <FlipPane>
*
*/
public class ArraySettingsPane extends SettingsPane<PamArray >{
/**
* 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<PamArray> 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<PamArray> 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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<Hydrophone> {
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<Double> hSens;
private PamSpinner<Double> preampGain;
private ComboBox<String> streamers;
private ChoiceBox<DefaultHydrophone> 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<String> 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<String>();
mainControls.add(streamers, 1, gridy);
gridy++;
mainControls.add(recieverTypeLabel = new Label(""), 0, gridy);
recieverTypeLabel.setAlignment(Pos.CENTER_LEFT);
defaultHydro = new ComboBox<String>();
for (int i=0; i<DefaultHydrophone.values().length; i++) {
defaultHydro.getItems().add(DefaultHydrophone.values()[i].toString());
}
defaultHydro.getItems().add(0, "User defined");
defaultHydro.getSelectionModel().select(0);
defaultHydro.setOnAction((action)->{
//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>(-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>(-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();
}
}

View File

@ -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<HydrophoneProperty> 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<ArrayChangeListener> hydrophoneChangeListeners = new ArrayList<ArrayChangeListener>();
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<tableArrayPane.getTableView().getItems().size(); i++) {
// System.out.println("Item : " + tableArrayPane.getTableView().getItems().get(i) + " " + currentHydrophoneData);
// }
}
});
this.setCenter(pamFlipePane);
}
/**
* Notify the hydrophone listeners of a change
* @param streamer - the changed streamer
*/
public void notifyHydrophoneListeners(HydrophoneProperty hydrophone) {
for (ArrayChangeListener listener: hydrophoneChangeListeners) {
listener.arrayChanged(ArrayChangeListener.HYDROPHONE_CHANGE, hydrophone);
}
}
/**
* Class which extends TableSettingsPane and creates a sliding pane instead of a dialog when an item is added.
* @author Jamie Macaulay
*
*/
class HydrophoneTable extends TableSettingsPane<HydrophoneProperty> {
/**
* The z table
*/
private TableColumn<HydrophoneProperty, Number> z;
public HydrophoneTable(ObservableList<HydrophoneProperty> hydrophoneData) {
super(hydrophoneData);
z = new TableColumn<HydrophoneProperty,Number>("depth");
z.setCellValueFactory(cellData -> cellData.getValue().getZ().multiply(PamController.getInstance().getGlobalMediumManager().getZCoeff()));
z.setEditable(true);
//need to set up all the rows.
TableColumn<HydrophoneProperty,Integer> hydroID = new TableColumn<HydrophoneProperty,Integer>("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<TableColumn<HydrophoneProperty, Integer>, TableCell<HydrophoneProperty, Integer>> 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<TableColumn<HydrophoneProperty, Integer>, TableCell<HydrophoneProperty, Integer>> cellFactory = col -> {
TableCell<HydrophoneProperty, Integer> 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<HydrophoneProperty,Number> x = new TableColumn<HydrophoneProperty,Number>("x");
x.setCellValueFactory(cellData -> cellData.getValue().getX());
x.setEditable(true);
TableColumn<HydrophoneProperty,Number> y = new TableColumn<HydrophoneProperty,Number>("y");
y.setCellValueFactory(cellData -> cellData.getValue().getY());
y.setEditable(true);
TableColumn posColumn=new TableColumn("Position (m)");
posColumn.getColumns().addAll(x, y, z);
TableColumn<HydrophoneProperty,Number> xErr = new TableColumn<HydrophoneProperty,Number>("x");
xErr.setCellValueFactory(cellData -> cellData.getValue().getXErr());
xErr.setEditable(true);
TableColumn<HydrophoneProperty,Number> yErr = new TableColumn<HydrophoneProperty,Number>("y");
yErr.setCellValueFactory(cellData -> cellData.getValue().getYErr());
yErr.setEditable(true);
TableColumn<HydrophoneProperty,Number> zErr = new TableColumn<HydrophoneProperty,Number>("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<HydrophoneProperty> 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<getData().size(); i++){
getData().get(i).id.set(i);
}
}
private HydrophoneProperty createDefaultHydrophoneProperty(int id) {
Hydrophone hydrophone = new Hydrophone(id, defaultx, defaulty,defaultz, defaultxErr, defaultyErr, defaultzErr, defaulttype, defaultsensitivity,
null, 0. );
return new HydrophoneProperty(hydrophone);
}
public TableColumn<HydrophoneProperty, Number> getZColumn() {
return z;
}
/**
* Get the current streamers.
* @return the current streamers.
*/
public ObservableList<HydrophoneProperty> getHydrophones() {
return getData();
}
}
public void setParams(PamArray currentArray) {
this.currentArray=currentArray;
tableArrayPane.getHydrophones().clear();
for (int i=0; i<currentArray.getHydrophoneCount(); i++) {
tableArrayPane.getHydrophones().add(new HydrophoneProperty(currentArray.getHiddenHydrophone(i)));
}
//update ID numbers just incase.
tableArrayPane.updateIDNumbers();
}
public synchronized PamArray getParams(PamArray currParams) {
currParams.clearArray();
Hydrophone hydrophone;
for (int i=0; i<tableArrayPane.getHydrophones().size(); i++) {
hydrophone = tableArrayPane.getHydrophones().get(i).getHydrophone();
hydrophone.setID(i);
currParams.addHydrophone(hydrophone);
}
return currParams;
}
/**
* Get the current hydrophone list.
* @return the current hydrophone list.
*/
public ObservableList<HydrophoneProperty> getHydrophoneList() {
return hydrophoneList;
}
public void setHydrophoneList(ObservableList<HydrophoneProperty> 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();
}
}

View File

@ -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<Integer> interpChoiceBox;
public InterpChoicePane() {
interpChoiceBox = new ChoiceBox<Integer>();
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<<sel) & allowedValues) == 0) {
PamDialogFX.showWarning("The selected interpolation is not available with the selected reference position");
return -1;
}
else {
return sel;
}
}
@Override
protected void enableControls() {
//get the current selection
Integer item = interpChoiceBox.getSelectionModel().getSelectedItem();
//clear items
interpChoiceBox.getItems().clear();
//set allowed values
for (int i=0; i<interpChoice.length ; i++) {
if ((allowedValues & (1<<interpChoice[i])) != 0){
interpChoiceBox.getItems().add(interpChoice[i]);
}
}
//reselect the previously selected item if possible.
if (interpChoiceBox.getItems().contains(item)) {
interpChoiceBox.getSelectionModel().select(item);
}
else {
interpChoiceBox.getSelectionModel().select(0);
}
}
@Override
protected int getSelectedInterpType() {
Integer choice = interpChoiceBox.getSelectionModel().getSelectedItem();
if (choice == null) {
return -1;
}
else return choice;
}
}

View File

@ -0,0 +1,160 @@
package Array.layoutFX;
import Array.PamArray;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamGridPane;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.Pane;
import javafx.scene.control.ToggleGroup;
/**
* Radio buttons which allow selection of interpolation options.
*
* @author Jamie Macaulay
*
*/
public class InterpSettingsPane extends PamBorderPane {
/**
* Interp choice.
*/
public static Integer[] interpChoice = new Integer[] {PamArray.ORIGIN_USE_LATEST,
PamArray.ORIGIN_INTERPOLATE, PamArray.ORIGIN_USE_PRECEEDING};
private RadioButton[] radioButton;
protected int allowedValues = 0xFF; // bitmap of banned values !
public InterpSettingsPane() {
this.setCenter(createInterpPane());
}
protected Pane createInterpPane() {
PamGridPane gridPane = new PamGridPane();
gridPane.setVgap(5);
int gridy=0;
radioButton = new RadioButton[interpChoice.length];
ToggleGroup group = new ToggleGroup();
for (int i=0; i<radioButton.length ; i++) {
gridPane.add(radioButton[i] = new RadioButton( getInterpString(interpChoice[i])), 0, gridy);
radioButton[i].setTooltip(new Tooltip( getInterpTip(interpChoice[i])));
gridy++;
radioButton[i].setToggleGroup(group);
}
return gridPane;
}
/**
* Get a description of the interpolation type for an interp-type flag.
* @param interpType - the interpolation type flag.
* @return a description of that interpolation methid.
*/
public String getInterpString(int interpType) {
String description = null;
switch ( interpType) {
case PamArray.ORIGIN_USE_LATEST:
description = "Use only the latest value";
break;
case PamArray.ORIGIN_INTERPOLATE:
description = "Interpolate between values";
break;
case PamArray.ORIGIN_USE_PRECEEDING:
description = "Use the location for the time preceeding each data unit";
break;
}
return description;
}
/**
* Get a description of the interpolation type for an interp-type flag.
* @param interpType - the interpolation type flag.
* @return a description of that interpolation methid.
*/
public String getInterpTip(int interpType) {
String description = null;
switch ( interpType) {
case PamArray.ORIGIN_USE_LATEST:
description = "Select this option if you have a simple static array in a single location for the entire data set";
break;
case PamArray.ORIGIN_INTERPOLATE:
description = "Select this option if you are storing multiple locations for slowely moving (i.e. not quite fixed) devices";
break;
case PamArray.ORIGIN_USE_PRECEEDING:
description = "Select this option if you have devices which are periodically moved from one spot to another";
break;
}
return description;
}
public void setSelection(int option) {
for (int i=0; i<interpChoice.length; i++) {
radioButton[i].setSelected(option == interpChoice[i]);
}
}
public int getSelection() {
int sel = getSelectedInterpType();
if (((1<<sel) & allowedValues) == 0) {
PamDialogFX.showWarning("The selected interpolation is not available with the selected reference position");
return -1;
}
else {
return sel;
}
}
/**
* @return the allowedValues
*/
protected int getAllowedValues() {
return allowedValues;
}
/**
* @param allowedValues the allowedValues to set
*/
protected void setAllowedValues(int allowedValues) {
this.allowedValues = allowedValues;
enableControls();
}
protected void enableControls() {
for (int i=0; i<interpChoice.length; i++) {
radioButton[i].setDisable((allowedValues & (1<<interpChoice[i])) == 0);
}
}
protected int getSelectedInterpType() {
for (int i=0; i<interpChoice.length; i++) {
if (radioButton[i].isSelected()) {
return interpChoice[i];
}
radioButton[i].setDisable((allowedValues & (1<<interpChoice[i])) == 0);
}
return -1;
}
}

View File

@ -0,0 +1,119 @@
package Array.layoutFX;
import Array.PamArray;
import PamController.SettingsPane;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import pamViewFX.fxNodes.PamHBox;
import pamViewFX.validator.PamValidator;
/**
* Pane for settings some basic environmental variables.
*/
public class PropogationPane extends SettingsPane<PamArray> {
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
}
}

View File

@ -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<String> sensorDropDown;
private ArrayList<PamDataBlock> 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<ActionEvent> 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<PamDataBlock> getDataBlocks() {
ArrayList<PamDataBlock> allDataBlocks = PamController.getInstance().getDataBlocks(ArraySensorDataUnit.class, true);
ArrayList<PamDataBlock> 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;
}
}

View File

@ -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;
}
}

View File

@ -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<Streamer> {
private final static double MAX_TEXTFIELD_WIDTH = 80;
public PamBorderPane mainPane;
/**
* Combo Box which shows which origin methods are available.
*/
private ComboBox<HydrophoneOriginSystem> 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<HydrophoneOriginSystem>();
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<sensorComponents.length; i++) {
if (sensorComponents[i]==null || sensorComponents[i].getParameterType()==null) continue;
boolean enable = sensorComponents[i].getParameterType().equals(ArrayParameterType.FIXED);
switch (sensorComponents[i].getSensorType()) {
case HEADING:
heading.setDisable(!enable);
break;
case HEIGHT:
break;
case PITCH:
pitch.setDisable(!enable);
break;
case ROLL:
roll.setDisable(!enable);
break;
default:
break;
}
}
}
/**
* Create a pane to set where sensor data comes from
* @return the sensor pane.
*/
private Pane createSensorPane() {
PamBorderPane pane = new PamBorderPane();
//hydrophone position and
PamGridPane positionPane = new PamGridPane();
positionPane.setHgap(5);
positionPane.setVgap(5);
int col=0;
int row=0;
positionPane.add(new Label("Heading"), col++, row);
positionPane.add(sensorComponents[ArraySensorFieldType.HEADING.ordinal()].getPane(), col++, row);
row++;
col=0;
positionPane.add(new Label("Pitch"), col++, row);
positionPane.add(sensorComponents[ArraySensorFieldType.PITCH.ordinal()].getPane(), col++, row);
row++;
col=0;
positionPane.add(new Label("Roll"), col++, row);
positionPane.add(sensorComponents[ArraySensorFieldType.ROLL.ordinal()].getPane(), col++, row);
Label orientLabel = new Label("Orientation Data");
PamGuiManagerFX.titleFont2style(orientLabel);
pane.setTop(orientLabel);
pane.setCenter(positionPane);
return pane;
}
/**
* Create a new origin method.
*/
public void newOriginMethod() {
int methInd = originMethod.getSelectionModel().getSelectedIndex();
if (methInd < 0) {
return;
}
HydrophoneOriginSystem currentSystem = HydrophoneOriginMethods.getInstance().getMethod(this.originMethod.getSelectionModel().getSelectedIndex());
currentOriginMethod = currentSystem.createMethod(currentArray, defaultStreamer);
try {
OriginSettings os = defaultStreamer.getOriginSettings(currentOriginMethod.getClass());
if (os != null) {
currentOriginMethod.setOriginSettings(os);
}
}
catch (Exception e) {
// will throw if it tries to set the wrong type of settings.
e.printStackTrace();
}
OriginDialogComponent mthDialogComponent = currentOriginMethod.getDialogComponent();
if (mthDialogComponent == null) {
originPane.getChildren().clear();
currentOriginComponent = null;
this.originButton.setDisable(true);
}
else {
this.originButton.setDisable(false);
Pane newComponent = mthDialogComponent.getSettingsPane();
if (currentOriginComponent != newComponent) {
originPane.setCenter(newComponent);
currentOriginComponent = newComponent;
mthDialogComponent.setParams();
}
}
enableControls();
}
private void enableControls() {
if (currentOriginMethod != null) {
System.out.println("Enable: selected interp: " + interpPane.getSelectedInterpType());
interpPane.setAllowedValues(currentOriginMethod.getAllowedInterpolationMethods());
System.out.println("Enable controls: " + interpPane.getSelectedInterpType());
if (interpPane.getSelectedInterpType()<0) {
interpPane.setSelection(0);
}
}
enableOrientationPane();
}
@Override
public Streamer getParams(Streamer currParams) {
// System.out.println("GETPARAMS: " + currParams);
double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();
try {
defaultStreamer.setX(Double.valueOf(xPos.getText()));
defaultStreamer.setY(Double.valueOf(yPos.getText()));
defaultStreamer.setZ(zCoeff*Double.valueOf(zPos.getText()));
defaultStreamer.setDx(Double.valueOf(xPosErr.getText()));
defaultStreamer.setDy(Double.valueOf(yPosErr.getText()));
defaultStreamer.setDz(Double.valueOf(zPosErr.getText()));
}
catch (NumberFormatException e) {
System.err.println("Streamer getParams: There is a problem with one of the position parameters in the streamer panel");
return null;
}
defaultStreamer.setStreamerName(currParams.getStreamerName());
int im = interpPane.getSelectedInterpType();
System.out.println("Streamer gwetParams: Origin interpolator: " + interpPane.getSelectedInterpType());
if (im < 0) {
System.err.println("Streamer getParams: There is an index problem with the interpolation selection streamer panel: index = " + im);
}
currentArray.setOriginInterpolation(im);
// try {
// streamer.setBuoyId1(Integer.valueOf(buoyId.getText()));
// }
// catch (NumberFormatException e) {
// streamer.setBuoyId1(null);
// }
HydrophoneLocator locator = HydrophoneLocators.getInstance().
getSystem(localiserMethod.getSelectionModel().getSelectedIndex()).getLocator(currentArray, defaultStreamer);
if (originPane != null) {
// MasterLocator masterLocator = currentArray.getMasterLocator();
// int streamerIndex = currentArray.indexOfStreamer(streamer);
// if (streamerIndex < 0) {
// streamerIndex = currentArray.getNumStreamers();
// }
// masterLocator.setHydrophoneLocator(streamerIndex, locator);
if (currentOriginMethod == null) {
System.err.println("Streamer getParams: No hydrophoneorigin method selected in streamer panel");
}
}
OriginDialogComponent mthDialogComponent = currentOriginMethod.getDialogComponent();
if (mthDialogComponent != null) {
if (mthDialogComponent.getParams() == false) {
System.err.println("Streamer: The origin settings pane returned false suggesting paramters are not correct.");
return null;
}
}
// defaultStreamer.setEnableOrientation(enableOrientation.isSelected());
// if (enableOrientation.isSelected()) {
defaultStreamer.setHeading(getDoubleValue(heading));
defaultStreamer.setPitch(getDoubleValue(pitch));
defaultStreamer.setRoll(getDoubleValue(roll));
// }
if (!heading.isDisable() && defaultStreamer.getHeading() == null) {
System.err.println("Streamer getParams: You must enter a fixed value for the streamer heading");
}
if (!pitch.isDisable() && defaultStreamer.getPitch() == null) {
System.err.println("Streamer getParams: You must enter a fixed value for the streamer pitch");
}
if (!roll.isDisable() && defaultStreamer.getRoll() == null) {
System.err.println("Streamer getParams: You must enter a fixed value for the streamer roll");
}
/**
* We may have large lists of the streamers which we meant to use the
* orientation data from or not. The enable orientation check box will enable or
* disable orientation for ALL streamers which are loaded into memory.
*/
// System.out.println("CURRENTORIGINMETHOD: " + currentOriginMethod);
// System.out.println("LOCATORMETHOD: " + locator);
defaultStreamer.setHydrophoneOrigin(currentOriginMethod);
defaultStreamer.setHydrophoneLocator(locator);
defaultStreamer.setOriginSettings(currentOriginMethod.getOriginSettings());
defaultStreamer.setLocatorSettings(locator.getLocatorSettings());
ArraySensorFieldType[] sensorFields = ArraySensorFieldType.values();
for (int i = 0; i < sensorFields.length; i++) {
ArrayParameterType fieldType = sensorComponents[i].getParameterType();
defaultStreamer.setOrientationTypes(sensorFields[i], fieldType);
if (fieldType == ArrayParameterType.SENSOR) {
PamDataBlock dataBlock = sensorComponents[i].getDataBlock();
defaultStreamer.setSensorDataBlocks(sensorFields[i], dataBlock == null ? null : dataBlock.getLongDataName());
}
}
return defaultStreamer;
}
@Override
public void setParams(Streamer input) {
if (input==null) {
System.out.print("Streamer setParams: The input streamer is null");
}
this.defaultStreamer=input;
// origin methods
// MasterLocator masterLocator = currentArray.getMasterLocator();
// int streamerIndex = currentArray.indexOfStreamer(streamer);
HydrophoneLocator hLocator = defaultStreamer.getHydrophoneLocator();
if (hLocator != null) {
int locatorIndex = HydrophoneLocators.getInstance().indexOfClass(hLocator.getClass());
localiserMethod.getSelectionModel().select(locatorIndex);
HydrophoneOriginMethod originMethod = defaultStreamer.getHydrophoneOrigin();
if (originMethod != null) {
int originIndex = HydrophoneOriginMethods.getInstance().indexOfClass(originMethod.getClass());
this.originMethod.getSelectionModel().select(originIndex);
}
}
else {
localiserMethod.getSelectionModel().select(0);
}
//streamerName.setText(defaultStreamer.getStreamerName());
xPos.setText(String.valueOf(defaultStreamer.getX()));
yPos.setText(String.valueOf(defaultStreamer.getY()));
zPos.setText(String.valueOf(PamController.getInstance().getGlobalMediumManager().getZCoeff()*defaultStreamer.getZ()));
xPosErr.setText(String.valueOf(defaultStreamer.getDx()));
yPosErr.setText(String.valueOf(defaultStreamer.getDy()));
zPosErr.setText(String.valueOf(defaultStreamer.getDz()));
// if (streamer.getBuoyId1() != null) {
// buoyId.setText(streamer.getBuoyId1().toString());
// }
// else {
// buoyId.setText("");
// }
HydrophoneOriginMethod mth = defaultStreamer.getHydrophoneOrigin();
if (mth==null) {
originMethod.getSelectionModel().select(0);
newOriginMethod();
mth = currentOriginMethod;
//defaultStreamer.setHydrophoneOrigin(HydrophoneOriginMethods.getInstance().getMethod(0).createMethod(currentArray, defaultStreamer));
}
OriginDialogComponent mthDialogComponent = mth.getDialogComponent();
if (mthDialogComponent != null) {
System.out.println("Streamer setParams: Set origin component: ");
mthDialogComponent.setParams();
}
// System.out.println("Streamer setParams: Set orientation: " + defaultStreamer.getHeading() + " " + defaultStreamer.getPitch() + " " + defaultStreamer.getRoll());
heading .setText(orientation2Text(defaultStreamer.getHeading()));
pitch .setText(orientation2Text(defaultStreamer.getPitch()));
roll .setText(orientation2Text(defaultStreamer.getRoll()));
System.out.println("Streamer setParams: Origin interpolator: " + currentArray.getOriginInterpolation() + " " + currentOriginMethod.getAllowedInterpolationMethods());
if (currentArray.getOriginInterpolation()<0 || currentArray.getOriginInterpolation()>=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;
}
}

View File

@ -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<StreamerProperty> streamerData = FXCollections.observableArrayList();
/**
* The current hydrophone array
*/
private PamArray currentArray;
/**
* The pam flip pane.
*/
private PamFlipPane pamFlipePane;
/**
* The current streamer data.
*/
private StreamerProperty currentStreamerData;
/**
* Settings pane for a single hydrophone.
*/
private StreamerSettingsPane streamerPane = new StreamerSettingsPane();
/**
* A list of listeners which are called whenever a streamer is added removed or changed.
*/
public ArrayList<ArrayChangeListener> streamerChangeListeners = new ArrayList<ArrayChangeListener>();
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<StreamerProperty> {
private TableColumn<StreamerProperty, Number> z;
public BasicArrayTable(ObservableList<StreamerProperty> data) {
super(data);
//need to set up all the rows.
TableColumn<StreamerProperty,Number> streamerID = new TableColumn<StreamerProperty,Number>("ID");
streamerID.setCellValueFactory(cellData -> cellData.getValue().getID());
streamerID.setEditable(false);
TableColumn<StreamerProperty,String> name = new TableColumn<StreamerProperty,String>("Name");
name.setCellValueFactory(cellData -> cellData.getValue().getName());
name.setEditable(true);
TableColumn<StreamerProperty,Number> x = new TableColumn<StreamerProperty,Number>("x");
x.setCellValueFactory(cellData -> cellData.getValue().getX());
x.setEditable(false);
TableColumn<StreamerProperty,Number> y = new TableColumn<StreamerProperty,Number>("y");
y.setCellValueFactory(cellData -> cellData.getValue().getY());
y.setEditable(false);
z = new TableColumn<StreamerProperty,Number>("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<StreamerProperty,String> reference = new TableColumn<StreamerProperty,String>("Reference");
reference.setCellValueFactory(cellData -> cellData.getValue().getHydrophoneOrigin());
reference.setEditable(true);
TableColumn<StreamerProperty,String> locator = new TableColumn<StreamerProperty,String>("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<StreamerProperty> getStreamers() {
return getData();
}
@Override
public void dialogClosed(StreamerProperty data) {
Streamer hydro = streamerPane.getParams(data.getStreamer());
data.setStreamer(hydro);
}
@Override
public Dialog<StreamerProperty> 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<StreamerProperty, Number> 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; i<currentArray.getStreamerCount(); i++) {
tableArrayPane.getStreamers().add(new StreamerProperty(currentArray.getStreamer(i)));
}
}
/**
* Get the parameters from the streamer pane.
* @param currParams - the current parameters.
* @return the PamArray with updated streamers.
*/
public PamArray getParams(PamArray currParams) {
//add all new streamers - bit weird because the PamArray requires that at least one streamer exists.
for (int i=0; i<tableArrayPane.getStreamers().size(); i++) {
if (i<currentArray.getStreamerCount()) {
currParams.updateStreamer(i,tableArrayPane.getStreamers().get(i).getStreamer());
}
else {
currParams.addStreamer(tableArrayPane.getStreamers().get(i).getStreamer());
}
}
while (currParams.getStreamerCount()>tableArrayPane.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<StreamerProperty> 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;
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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<<streamer.getStreamerIndex());
if (sdu == null) {
sdu = new StreamerDataUnit(PamCalendar.getTimeInMillis(), streamer);
//System.out.println("StaticOriginMethod: Streamer rotation: " +sdu.getGpsData().getQuaternion().toHeading());
}
return sdu;
}
@Override
public OriginIterator getGpsDataIterator(int wherefrom) {
return new StreamerDataIterator(wherefrom, streamer);
}
@Override
public Object getSynchronizationObject() {
return NavDataSynchronisation.getSynchobject();
}
/**
* GUI components for the static hydrophone locator. This returns a JavaFX or Swing component depending on the current GUI.
*/
private class StaticHydrophoneComponent extends OriginDialogComponent {
/**
* Swing component.
*/
private StaticHydrophoneDialogComponent staticHydrophoneDialog;
/**
* JavaFX pane for static hydrophones.
*/
private StaticHydrophonePane staticHydrophonePane;
@Override
public JComponent getComponent(Window owner) {
if (staticHydrophoneDialog==null) {
staticHydrophoneDialog = new StaticHydrophoneDialogComponent();
}
return staticHydrophoneDialog.getComponent(owner);
}
@Override
public void setParams() {
if (staticHydrophoneDialog!=null) {
staticHydrophoneDialog.setParams();
}
if (staticHydrophonePane!=null) {
staticHydrophonePane.setParams();
}
}
@Override
public boolean getParams() {
if (staticHydrophoneDialog!=null) {
return staticHydrophoneDialog.getParams();
}
if (staticHydrophonePane!=null) {
return staticHydrophonePane.getParams();
}
return false;
}
@Override
public Pane getSettingsPane() {
if (staticHydrophonePane==null) {
staticHydrophonePane = new StaticHydrophonePane(StaticOriginMethod.this);
}
return staticHydrophonePane;
}
}
/**
* Swing components for the static hydrophone locator.
*/
private class StaticHydrophoneDialogComponent extends OriginDialogComponent {
private JPanel outerPanel;
@ -268,41 +364,12 @@ public class StaticOriginMethod extends HydrophoneOriginMethod {
}
}
}
@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<<streamer.getStreamerIndex());
if (sdu == null) {
sdu = new StreamerDataUnit(PamCalendar.getTimeInMillis(), streamer);
//System.out.println("StaticOriginMethod: Streamer rotation: " +sdu.getGpsData().getQuaternion().toHeading());
@Override
public Pane getSettingsPane() {
// TODO Auto-generated method stub
return null;
}
return sdu;
}
@Override
public OriginIterator getGpsDataIterator(int wherefrom) {
return new StreamerDataIterator(wherefrom, streamer);
}
@Override
public Object getSynchronizationObject() {
return NavDataSynchronisation.getSynchobject();
}
}

View File

@ -267,6 +267,9 @@ public class GPSControl extends PamControlledUnit implements PamSettings, Positi
GpsDataUnit pointBefore = null, pointAfter = null;
synchronized (getGpsDataBlock().getSynchLock()) {
ListIterator<GpsDataUnit> iter = getGpsDataBlock().getListIterator(timeMilliseconds, 0, PamDataBlock.MATCH_BEFORE, PamDataBlock.POSITION_BEFORE);
if (iter == null) {
return null;
}
if (iter.hasNext()) {
pointBefore = iter.next();
}

View File

@ -27,7 +27,7 @@ public interface LocaliserModel<T extends PamDataUnit> {
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<T extends PamDataUnit> {
/**
* 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<T extends PamDataUnit> {
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);

View File

@ -1,5 +1,17 @@
package Localiser;
public interface LocaliserPane<T> {
import PamController.SettingsPane;
public abstract class LocaliserPane<T> extends SettingsPane<T> {
public LocaliserPane() {
super(null);
// TODO Auto-generated constructor stub
}
}

View File

@ -152,8 +152,7 @@ public class ModelControlPanel {
@Override
//settings panel
public void actionPerformed(ActionEvent arg0) {
model.getSettingsPane();
model.getAlgorithmSettingsPane();
//AWT implementation.
}
}

View File

@ -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)<p>

Some files were not shown because too many files have changed in this diff Show More