mirror of
https://github.com/PAMGuard/PAMGuard.git
synced 2024-11-25 08:32:32 +00:00
Merge branch 'main' into main
This commit is contained in:
commit
c607f17449
@ -6,7 +6,7 @@
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
|
70
.gitignore
vendored
70
.gitignore
vendored
@ -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
0
.metadata/.lock
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
|
BIN
.metadata/.plugins/org.eclipse.core.resources/.root/1.tree
Normal file
BIN
.metadata/.plugins/org.eclipse.core.resources/.root/1.tree
Normal file
Binary file not shown.
Binary file not shown.
@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding=UTF-8
|
||||
version=1
|
@ -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
|
@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.m2e.discovery.pref.projects=
|
@ -0,0 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
platformState=1678968029917
|
||||
quickStart=false
|
||||
tipsAndTricks=true
|
@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
showIntro=false
|
@ -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
|
2360
.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
Normal file
2360
.metadata/.plugins/org.eclipse.e4.workbench/workbench.xmi
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
Binary file not shown.
BIN
.metadata/.plugins/org.eclipse.jdt.core/externalFilesCache
Normal file
BIN
.metadata/.plugins/org.eclipse.jdt.core/externalFilesCache
Normal file
Binary file not shown.
@ -0,0 +1 @@
|
||||
java
|
BIN
.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache
Normal file
BIN
.metadata/.plugins/org.eclipse.jdt.core/nonChainingJarsCache
Normal file
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<typeInfoHistroy/>
|
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<qualifiedTypeNameHistroy/>
|
10
.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
Normal file
10
.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml
Normal 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="<?xml version="1.0" encoding="UTF-8"?>
<packageExplorer group_libraries="1" layout="2" linkWithEditor="0" rootMode="1" workingSetName="Aggregate for window 1678968099026">
<customFilters userDefinedPatternsEnabled="false">
<xmlDefinedFilters>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.StaticsFilter" isEnabled="false"/>
<child filterId="org.eclipse.buildship.ui.packageexplorer.filter.gradle.buildfolder" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.NonJavaProjectsFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer_patternFilterId_.*" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.NonSharedProjectsFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.SyntheticMembersFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.ContainedLibraryFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.internal.ui.PackageExplorer.HideInnerClassFilesFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.internal.ui.PackageExplorer.EmptyInnerPackageFilter" isEnabled="true"/>
<child filterId="org.eclipse.m2e.MavenModuleFilter" isEnabled="false"/>
<child filterId="org.eclipse.buildship.ui.packageexplorer.filter.gradle.subProject" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.ClosedProjectsFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.DeprecatedMembersFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.EmptyLibraryContainerFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.PackageDeclarationFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.ImportDeclarationFilter" isEnabled="true"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.NonJavaElementFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.LibraryFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.CuAndClassFileFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.internal.ui.PackageExplorer.EmptyPackageFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.NonPublicFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.LocalTypesFilter" isEnabled="false"/>
<child filterId="org.eclipse.jdt.ui.PackageExplorer.FieldsFilter" isEnabled="false"/>
</xmlDefinedFilters>
</customFilters>
</packageExplorer>"/>
|
||||
</section>
|
||||
</section>
|
BIN
.metadata/.plugins/org.eclipse.m2e.core/workspaceState.ser
Normal file
BIN
.metadata/.plugins/org.eclipse.m2e.core/workspaceState.ser
Normal file
Binary file not shown.
@ -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>
|
@ -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"/>
|
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section name="Workbench">
|
||||
</section>
|
2
.metadata/.plugins/org.eclipse.ui.intro/introstate
Normal file
2
.metadata/.plugins/org.eclipse.ui.intro/introstate
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<state reopen="false"/>
|
@ -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
3
.metadata/version.ini
Normal 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
|
2
.project
2
.project
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>PamGuard Main Tethys</name>
|
||||
<name>PAMGuard</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -3,16 +3,17 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.pamguard</groupId>
|
||||
<artifactId>Pamguard</artifactId>
|
||||
<name>Pamguard Java12+</name>
|
||||
<version>2.02.10bd</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>
|
||||
|
BIN
nullPamguardSettings_20171106_185953.psfx
Normal file
BIN
nullPamguardSettings_20171106_185953.psfx
Normal file
Binary file not shown.
BIN
nullPamguardSettings_20240401_141954.psfx
Normal file
BIN
nullPamguardSettings_20240401_141954.psfx
Normal file
Binary file not shown.
BIN
nullPamguardSettings_20240401_143317.psfx
Normal file
BIN
nullPamguardSettings_20240401_143317.psfx
Normal file
Binary file not shown.
202
pom.xml
202
pom.xml
@ -1,13 +1,12 @@
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.pamguard</groupId>
|
||||
<artifactId>Pamguard</artifactId>
|
||||
<version>2.02.10bd</version>
|
||||
<name>Pamguard Java12+</name>
|
||||
<description>Pamguard for Java 12+, using Maven to control dependcies</description>
|
||||
<version>2.02.11d</version>
|
||||
<name>Pamguard</name>
|
||||
<description>Pamguard using Maven to control dependencies</description>
|
||||
<url>www.pamguard.org</url>
|
||||
<organization>
|
||||
<name>Sea Mammal Research Unit, University of St. Andrews</name>
|
||||
@ -16,17 +15,20 @@
|
||||
|
||||
|
||||
<properties>
|
||||
<javafx.version>16</javafx.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<javafx.version>21</javafx.version>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- Tethys version control -->
|
||||
<jaxb.runtime.version>2.4.0-b180830.0438</jaxb.runtime.version>
|
||||
<jaxb.api.version>2.4.0-b180830.0359</jaxb.api.version>
|
||||
<jaxb.xjc.version>2.4.0-b180830.0438</jaxb.xjc.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<!-- Define where the source and test directories are -->
|
||||
<sourceDirectory>${basedir}/src</sourceDirectory>
|
||||
<testSourceDirectory>${basedir}/src/test</testSourceDirectory> <!-- where the Unit tets are located -->
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src</directory>
|
||||
@ -37,10 +39,9 @@
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
|
||||
<!-- original maven compiler definition - uses the JRE's javac compiler, not the one Eclipse uses
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
@ -54,19 +55,15 @@
|
||||
https://wiki.eclipse.org/JDT/FAQ#Can_I_use_JDT_outside_Eclipse_to_compile_Java_code.3F
|
||||
https://wiki.eclipse.org/Tycho/FAQ#Can_I_use_the_Tycho_compiler_support_in_non-OSGi_projects.2C_too.3F
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<version>3.12.1</version>
|
||||
<configuration>
|
||||
|
||||
<!-- set compiler to use Java version 11 API https://docs.oracle.com/javase/9/tools/javac.htm#JSWOR627 -->
|
||||
<release>11</release>
|
||||
<release>21</release>
|
||||
<compilerId>jdt</compilerId>
|
||||
<compilerArguments>
|
||||
<properties>.settings/org.eclipse.jdt.core.prefs</properties> <!-- make sure to use same params as what Eclipse uses -->
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/org.eclipse.tycho/tycho-compiler-jdt -->
|
||||
<dependency>
|
||||
@ -75,18 +72,13 @@
|
||||
<version>1.5.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</plugin>
|
||||
|
||||
<!-- Set up javafx properly. -->
|
||||
<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>
|
||||
|
||||
<!-- Maven Shade plugin - for creating the uberjar / fatjar -->
|
||||
@ -136,6 +128,7 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
|
||||
<!-- The Maven-JDEPS plugin, to analyze necessary JDK dependencies. See
|
||||
this site for details: https://maven.apache.org/plugins/maven-jdeps-plugin/index.html -->
|
||||
<plugin>
|
||||
@ -163,7 +156,6 @@
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
<!-- this deletes all the dependencies in the local repository and downloads them again.
|
||||
Run a Maven > Update after doing this in order to properly reset the dependencies. Also, you
|
||||
will need to add the 3 jar files (x3, JasioHost and jave) back into the local repository after
|
||||
@ -188,8 +180,9 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
|
||||
</plugins>
|
||||
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
@ -242,7 +235,6 @@
|
||||
|
||||
<!-- ************************* Extra Repositories ************************************* -->
|
||||
<repositories>
|
||||
|
||||
<!-- Project repo to hold the custom jar files that are not available in Maven. Do
|
||||
this so that we don't have to do the extra step of manually installing jar files in the local repo -->
|
||||
<repository>
|
||||
@ -257,23 +249,6 @@
|
||||
<url>file://${project.basedir}/repo</url>
|
||||
</repository>
|
||||
|
||||
<!-- Repo for Jamie's code -->
|
||||
<!-- IMPORTANT: SOMEHOW THIS REPO INTERFERES WITH THE
|
||||
JAVAFX DEPENDENCIES. Don't understand how, but it
|
||||
does. If Maven is not downloading the JavaFX dependencies
|
||||
and is instead throwing errors, try commenting out this
|
||||
repository. Let Maven download the JavaFX files, and
|
||||
then uncomment this repo again.
|
||||
Same thing seems to be occurring if I try to update the postgresql library. -->
|
||||
<!-- <repository> -->
|
||||
<!-- <snapshots> -->
|
||||
<!-- <enabled>false</enabled> -->
|
||||
<!-- </snapshots> -->
|
||||
<!-- <id>central</id> -->
|
||||
<!-- <name>a0u0ltozdsehx-artifactory-primary-0-releases</name> -->
|
||||
<!-- <url>https://jmachund.jfrog.io/artifactory/jpam2</url> -->
|
||||
<!-- </repository> -->
|
||||
|
||||
<!-- Repo for netCDF -->
|
||||
<repository>
|
||||
<snapshots>
|
||||
@ -296,14 +271,12 @@
|
||||
|
||||
<!-- Repo for Renjin Script Engine -->
|
||||
<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>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
@ -328,18 +301,14 @@
|
||||
<dependency>
|
||||
<groupId>io.github.macster110</groupId>
|
||||
<artifactId>jpamutils</artifactId>
|
||||
<version>0.0.56</version>
|
||||
<version>0.0.59</version>
|
||||
</dependency>
|
||||
|
||||
<!--jpam project - Deep learning java library
|
||||
DG has commented this out since there are problems with access to the maven repo
|
||||
on JDJM's Github. For now a jar file is included in the build and we'll go back to
|
||||
Maven when we can ... DG 15 Jan 2022.
|
||||
Repo for jpam code- this used for deep learning [15:17] Jamie MacAulay-->
|
||||
<!--jpam project - Deep learning java library -->
|
||||
<dependency>
|
||||
<groupId>io.github.macster110</groupId>
|
||||
<artifactId>jdl4pam</artifactId>
|
||||
<version>0.0.94</version>
|
||||
<version>0.0.99a</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/gov.nist.math/jama -->
|
||||
@ -401,11 +370,11 @@
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Decorates JavaFX components-->
|
||||
<!-- Decorates JavaFX components with error icons if inputs are incorrect-->
|
||||
<dependency>
|
||||
<groupId>net.synedra</groupId>
|
||||
<artifactId>validatorfx</artifactId>
|
||||
<version>0.4.0</version>
|
||||
<version>0.4.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
|
||||
@ -461,7 +430,7 @@
|
||||
<dependency>
|
||||
<groupId>org.controlsfx</groupId>
|
||||
<artifactId>controlsfx</artifactId>
|
||||
<version>11.0.0</version>
|
||||
<version>11.2.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.openjfx</groupId>
|
||||
@ -492,49 +461,52 @@
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-javafx</artifactId>
|
||||
<version>12.2.0</version>
|
||||
<version>12.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Ikonli FontAwesome5 font pack https://kordamp.org/ikonli/cheat-sheet-fontawesome5.html -->
|
||||
<!--
|
||||
<!-- Icon symbol pack for swing icons . -->
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-fontawesome5-pack</artifactId>
|
||||
<version>12.2.0</version>
|
||||
<artifactId>ikonli-swing</artifactId>
|
||||
<version>12.3.1</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<!-- Ikonli MaterialDesign2 (Latest) font pack https://kordamp.org/ikonli/cheat-sheet-materialdesign2.html -->
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-materialdesign2-pack</artifactId>
|
||||
<version>12.2.0</version>
|
||||
<version>12.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/net.sf.geographiclib/GeographicLib-Java -->
|
||||
<!-- Ikonli File Icons (Latest) font pack https://kordamp.org/ikonli/cheat-sheet-materialdesign2.html -->
|
||||
<dependency>
|
||||
<groupId>org.kordamp.ikonli</groupId>
|
||||
<artifactId>ikonli-fileicons-pack</artifactId>
|
||||
<version>12.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/net.sf.geographiclib/GeographicLib-Java
|
||||
Used in the video range module-->
|
||||
<dependency>
|
||||
<groupId>net.sf.geographiclib</groupId>
|
||||
<artifactId>GeographicLib-Java</artifactId>
|
||||
<version>1.50</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.jogamp.gluegen/gluegen -->
|
||||
<!-- https://mvnrepository.com/artifact/org.jogamp.gluegen/gluegen
|
||||
<dependency>
|
||||
<groupId>org.jogamp.gluegen</groupId>
|
||||
<artifactId>gluegen-rt-main</artifactId>
|
||||
<version>2.3.2</version>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/java3d/j3dutils -->
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/java3d/j3dcore -->
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.healthmarketscience.jackcess/jackcess -->
|
||||
<!-- https://mvnrepository.com/artifact/com.healthmarketscience.jackcess/jackcess
|
||||
<dependency>
|
||||
<groupId>com.healthmarketscience.jackcess</groupId>
|
||||
<artifactId>jackcess</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
|
||||
<dependency>
|
||||
@ -543,12 +515,12 @@
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.jogamp.jogl/jogl-all-main -->
|
||||
<!-- https://mvnrepository.com/artifact/org.jogamp.jogl/jogl-all-main
|
||||
<dependency>
|
||||
<groupId>org.jogamp.jogl</groupId>
|
||||
<artifactId>jogl-all-main</artifactId>
|
||||
<version>2.3.2</version>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
|
||||
<!-- NOT SURE IF WE NEED THE JAXB LIBRARIES HERE - NO ERRORS WHEN REMOVED
|
||||
<dependency>
|
||||
@ -624,12 +596,6 @@
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.diffplug.matsim/matfilerw -->
|
||||
<dependency>
|
||||
<groupId>com.diffplug.matsim</groupId>
|
||||
<artifactId>matfilerw</artifactId>
|
||||
<version>3.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.drewnoakes/metadata-extractor -->
|
||||
<dependency>
|
||||
@ -691,7 +657,8 @@
|
||||
<version>42.2.24</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.renjin/renjin-script-engine -->
|
||||
<!-- https://mvnrepository.com/artifact/org.renjin/renjin-script-engine
|
||||
Used to export data to R structures-->
|
||||
<dependency>
|
||||
<groupId>org.renjin</groupId>
|
||||
<artifactId>renjin-script-engine</artifactId>
|
||||
@ -716,6 +683,7 @@
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.docx4j/docx4j-JAXB-ReferenceImpl -->
|
||||
<!-- note that we are excluding slf4j-api here, because if we don't then one of the
|
||||
transitive dependencies of docx4j (jcl-over-slf4j) will try to load an older
|
||||
@ -741,14 +709,14 @@
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.28.0</version>
|
||||
<version>3.45.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/net.sf.ucanaccess/ucanaccess -->
|
||||
<dependency>
|
||||
<groupId>net.sf.ucanaccess</groupId>
|
||||
<artifactId>ucanaccess</artifactId>
|
||||
<version>5.0.1</version>
|
||||
<version>4.0.4</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/nz.ac.waikato.cms.weka/weka-dev -->
|
||||
@ -788,6 +756,7 @@
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
|
||||
<!-- From NilusXMLGenerator POM at https://bitbucket.org/tethysacousticmetadata/nilusxmlgenerator/src/master/-->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
@ -809,92 +778,112 @@
|
||||
<artifactId>jaxb-xjc</artifactId>
|
||||
<version>${jaxb.xjc.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- dependencies copied from TethysJavaClient -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-multipart</artifactId>
|
||||
<version>1.18.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>3.10-beta1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>1.18.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-apache-client</artifactId>
|
||||
<version>1.18.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.miglayout</groupId>
|
||||
<artifactId>miglayout</artifactId>
|
||||
<version>3.7.4</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.juliusdavies</groupId>
|
||||
<artifactId>not-yet-commons-ssl</artifactId>
|
||||
<version>0.3.11</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>javax.ws.rs-api</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>2.2.11</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.2.11</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>activation</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-core</artifactId>
|
||||
<version>2.2.11</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.core</groupId>
|
||||
<artifactId>jersey-common</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>1.9</version>
|
||||
</dependency>
|
||||
|
||||
<!-- dependencies copied from TethysJavaClient END -->
|
||||
|
||||
<!-- not in Maven repository
|
||||
you may need to copy files from your downloaded PAMGuard source code, e.g. C:\Users\*yourreposfolder*\source\repos\PAMGuardPAMGuard\repo\pamguard\org\x3\2.2.2 to
|
||||
C:\Users\*yourusername*\.m2\repository\pamguard\org\x3\2.2.2-->
|
||||
<dependency>
|
||||
<groupId>pamguard.org</groupId>
|
||||
<artifactId>x3</artifactId>
|
||||
<version>2.2.7</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Also not in Maven, so you may need to copy the javaclient and nilus folders from
|
||||
<!-- Thethy library not in Maven central, so you may need to copy the javaclient and nilus folders from
|
||||
e.g. C:\Users\dg50\source\repos\**your projectfolder**\repo\tethys\org
|
||||
to C:\Users\dg50\.m2\repository\tethys\org -->
|
||||
|
||||
<dependency>
|
||||
<groupId>tethys.org</groupId>
|
||||
<artifactId>nilus</artifactId>
|
||||
@ -907,6 +896,18 @@ to C:\Users\dg50\.m2\repository\tethys\org -->
|
||||
<version>3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
X3 library for decompressing sud files. Not in Maven repository
|
||||
you may need to copy files from your downloaded PAMGuard source code,
|
||||
e.g. C:\Users\*yourreposfolder*\source\repos\PAMGuardPAMGuard\repo\pamguard\org\x3\2.2.2 to
|
||||
C:\Users\*yourusername*\.m2\repository\pamguard\org\x3\2.2.2
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.pamguard</groupId>
|
||||
<artifactId>x3</artifactId>
|
||||
<version>2.2.7</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/it.sauronsoftware/jave -->
|
||||
<dependency>
|
||||
@ -954,13 +955,20 @@ to C:\Users\dg50\.m2\repository\tethys\org -->
|
||||
<version>1.6.5-1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Theme for JavaFX -->
|
||||
|
||||
<!-- Extra 3D bits for JavaFX -->
|
||||
<dependency>
|
||||
<groupId>org.fxyz3d</groupId>
|
||||
<artifactId>fxyz3d</artifactId>
|
||||
<version>0.6.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Atlanta style for JavaFX -->
|
||||
<dependency>
|
||||
<groupId>io.github.mkpaz</groupId>
|
||||
<artifactId>atlantafx-base</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
72
readme.md
72
readme.md
@ -1,5 +1,73 @@
|
||||
This is the main code repository for the PAMGuard software.
|
||||
# PAMGuard
|
||||
PAMGuard is a bioacoustics analysis program designed for use in real time research contexts and for the processing of large datasets. PAMGuard provides users access to a suite of state-of-the-art auotmated analysis algorithms alongside displays for visualisation data and a comprehensive data management systems.
|
||||
|
||||
This repository was created on 7 January 2022 from sourceforge SVN repository at https://sourceforge.net/p/pamguard/svn/HEAD/tree/ revision r6278.
|
||||
# Why do we need PAMGuard?
|
||||
PAMGuard fufills two main requirements within marine bioacoustics
|
||||
|
||||
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.
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -147,7 +147,12 @@ public class CheckWavHeadersPane extends PamBorderPane {
|
||||
else {
|
||||
folderName.setText(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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -51,6 +51,8 @@ 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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -397,6 +397,8 @@ public class HydrophoneElementDialog extends PamDialog {
|
||||
dz.setText(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean getParams() {
|
||||
|
||||
double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();
|
||||
|
@ -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);
|
||||
}
|
||||
@ -276,11 +279,13 @@ 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());
|
||||
// System.out.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: " + 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();
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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,13 +34,15 @@ import PamguardMVC.PamDataUnit;
|
||||
*
|
||||
* @author Jamie Macaulay
|
||||
*/
|
||||
public class HydrophoneImport extends DataImport<ArrayList<Double>>{
|
||||
public class HydrophoneImport extends DataImport<Hydrophone>{
|
||||
|
||||
String[] extensionStrings={".csv"};
|
||||
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
|
||||
*/
|
||||
@ -80,7 +89,7 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
|
||||
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;
|
||||
|
||||
@ -118,10 +127,12 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
|
||||
|
||||
if (filePath.endsWith(".mat")){
|
||||
|
||||
hydrophonePositions=importPositionsFromMatlab(filePath);
|
||||
ArrayList<Hydrophone> hydrophonePositions = importPositionsFromMatlab(filePath);
|
||||
|
||||
if (hydrophonePositions==null) errorCode=ERROR_LOADING_MATLAB_STRUCT;
|
||||
|
||||
return hydrophonePositions;
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -129,17 +140,23 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
|
||||
}
|
||||
|
||||
/**
|
||||
* 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){
|
||||
public ArrayList<Hydrophone> convertToHydrophoneList(ArrayList<ArrayList<Double>> importData){
|
||||
|
||||
ArrayList<ArrayList<Double>> hydrophonesAll=new ArrayList<ArrayList<Double>>();
|
||||
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++){
|
||||
|
||||
@ -156,20 +173,34 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
|
||||
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);
|
||||
// tempArray.add((double) j);
|
||||
hydrophonesAll.add(hydrophone);
|
||||
// System.out.println("TempArray: "+tempArray);
|
||||
|
||||
}
|
||||
@ -179,10 +210,64 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
|
||||
|
||||
|
||||
|
||||
|
||||
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,21 +286,21 @@ 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) {
|
||||
public PamDataUnit createDataUnit(Hydrophone hydrophone) {
|
||||
|
||||
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);
|
||||
// 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;
|
||||
|
||||
@ -231,4 +316,13 @@ public class HydrophoneImport extends DataImport<ArrayList<Double>>{
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
586
src/Array/layoutFX/Array3DPane.java
Normal file
586
src/Array/layoutFX/Array3DPane.java
Normal 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);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
15
src/Array/layoutFX/ArrayChangeListener.java
Normal file
15
src/Array/layoutFX/ArrayChangeListener.java
Normal 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);
|
||||
|
||||
}
|
@ -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();
|
||||
|
@ -1,39 +1,385 @@
|
||||
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;
|
||||
|
||||
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
|
||||
@ -42,4 +388,13 @@ public class ArraySettingsPane extends SettingsPane<PamArray >{
|
||||
|
||||
}
|
||||
|
||||
private class HydrophoneArray3DPane extends Array3DPane {
|
||||
|
||||
@Override
|
||||
public void hydrophoneSelected(Hydrophone hydrophone) {
|
||||
hydrophonePane.selectHydrophone(hydrophone);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
58
src/Array/layoutFX/DefaultHydrophone.java
Normal file
58
src/Array/layoutFX/DefaultHydrophone.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
116
src/Array/layoutFX/HydrophoneProperty.java
Normal file
116
src/Array/layoutFX/HydrophoneProperty.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
589
src/Array/layoutFX/HydrophoneSettingsPane.java
Normal file
589
src/Array/layoutFX/HydrophoneSettingsPane.java
Normal 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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
412
src/Array/layoutFX/HydrophonesPane.java
Normal file
412
src/Array/layoutFX/HydrophonesPane.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
104
src/Array/layoutFX/InterpChoicePane.java
Normal file
104
src/Array/layoutFX/InterpChoicePane.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
160
src/Array/layoutFX/InterpSettingsPane.java
Normal file
160
src/Array/layoutFX/InterpSettingsPane.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
119
src/Array/layoutFX/PropogationPane.java
Normal file
119
src/Array/layoutFX/PropogationPane.java
Normal 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
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
162
src/Array/layoutFX/SensorSourcePane.java
Normal file
162
src/Array/layoutFX/SensorSourcePane.java
Normal 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;
|
||||
}
|
||||
}
|
121
src/Array/layoutFX/StreamerProperty.java
Normal file
121
src/Array/layoutFX/StreamerProperty.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
752
src/Array/layoutFX/StreamerSettingsPane.java
Normal file
752
src/Array/layoutFX/StreamerSettingsPane.java
Normal 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;
|
||||
|
||||
}
|
||||
}
|
315
src/Array/layoutFX/StreamersPane.java
Normal file
315
src/Array/layoutFX/StreamersPane.java
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
|
||||
}
|
||||
|
97
src/Array/streamerOrigin/StaticHydrophonePane.java
Normal file
97
src/Array/streamerOrigin/StaticHydrophonePane.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -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 Pane getSettingsPane() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
@ -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,13 +35,13 @@ 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();
|
||||
@ -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);
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -152,8 +152,7 @@ public class ModelControlPanel {
|
||||
@Override
|
||||
//settings panel
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
model.getSettingsPane();
|
||||
|
||||
model.getAlgorithmSettingsPane();
|
||||
//AWT implementation.
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -185,7 +185,7 @@ public class Chi2TimeDelays implements MinimisationFunction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time delays. Each row is a set fo delays from N synchronised hydrophones. Different rows
|
||||
* Set the time delays. Each row is a set for delays from N synchronised hydrophones. Different rows
|
||||
* can have different numbers of synchronised hydrophones.
|
||||
* @param timeDelays - a set of time delays in seconds.
|
||||
*/
|
||||
|
@ -18,17 +18,19 @@ import PamUtils.CoordUtils;
|
||||
import org.apache.commons.math3.ml.clustering.Cluster;
|
||||
import org.apache.commons.math3.ml.clustering.DoublePoint;
|
||||
import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer;
|
||||
|
||||
|
||||
/**
|
||||
* Markov chain Monte Carlo (MCMC) is a minimisation technique used widely in a variety of field, from finding exo planets,
|
||||
* to solving complex intergals.
|
||||
* <p>
|
||||
* This is an advanced and highly computationally intensive localisation algorithm based on MCMC methods. For a good description see;
|
||||
* This is a highly computationally intensive localisation algorithm based on MCMC methods. For a good description see;
|
||||
* The Transit Light Curve (TLC) Project.I. Four Consecutive Transits of the Exoplanet XO-1b Matthew J. Holman1
|
||||
* <p>
|
||||
* This is an abstract class and requires a chi2 function to operate.
|
||||
* A chi2 function is required to define the minimisation problem.
|
||||
* <p>
|
||||
* Multiple MCMC chains can and should be run. These are executed on different threads to take advantage of multi-core processing as much as possible.
|
||||
* Even so a large number of chains or large observation set can result in significant processing times.
|
||||
* Multiple MCMC chains can and should be run. These are executed on different threads to take advantage of multi-core processing if possible.
|
||||
* Even so, a large number of chains or large observation set can result in significant processing times.
|
||||
* <p>
|
||||
* Results are analysed for convergence and final locations packed into an MCMCTDResults class.
|
||||
*
|
||||
@ -117,7 +119,7 @@ public class MCMC implements MinimisationAlgorithm {
|
||||
double newChi;
|
||||
|
||||
ArrayList<Double> successChi=new ArrayList<Double>(settings.numberOfJumps/5);
|
||||
ArrayList<double[]> successJump=new ArrayList<double[]>(settings.numberOfJumps/5);
|
||||
ArrayList<float[]> successJump=new ArrayList<float[]>(settings.numberOfJumps/5);
|
||||
|
||||
// System.out.println("Start MCMC milliseconds: "+ System.currentTimeMillis());
|
||||
|
||||
@ -143,7 +145,7 @@ public class MCMC implements MinimisationAlgorithm {
|
||||
chainPos=potentialNewJump;
|
||||
currentChi=newChi;
|
||||
successChi.add(newChi);
|
||||
successJump.add(chainPos);
|
||||
successJump.add(PamArrayUtils.double2Float(chainPos));
|
||||
//System.out.println(ChainPos);
|
||||
//System.out.println(NewChi);
|
||||
//System.out.println(ObservedTimeDelays);
|
||||
@ -153,7 +155,7 @@ public class MCMC implements MinimisationAlgorithm {
|
||||
chainPos=potentialNewJump;
|
||||
currentChi=newChi;
|
||||
successChi.add(newChi);
|
||||
successJump.add(chainPos);
|
||||
successJump.add(PamArrayUtils.double2Float(chainPos));
|
||||
//System.out.println(ChainPos);
|
||||
//System.out.println(NewChi);
|
||||
//System.out.println(ObservedTimeDelays);
|
||||
@ -164,7 +166,7 @@ public class MCMC implements MinimisationAlgorithm {
|
||||
|
||||
ChainResult chainResult=new ChainResult(successJump, successChi);
|
||||
chainResult= analyseChain( chainResult);
|
||||
chainResult.nDim=this.chi2.getDim();
|
||||
chainResult.nDim=chi2.getDim();
|
||||
// System.out.println("Chain results is: " + chainResult.mean[0] + " " + chainResult.mean[1] + " " + chainResult.mean[2]);
|
||||
// System.out.println("End MCMC millis: "+ System.currentTimeMillis());
|
||||
|
||||
@ -184,7 +186,7 @@ public class MCMC implements MinimisationAlgorithm {
|
||||
* @param successJump - list of successful jumps
|
||||
* @param successChi - list of successful chi2 values.
|
||||
*/
|
||||
public ChainResult(ArrayList<double[]> successJump, ArrayList<Double> successChi) {
|
||||
public ChainResult(ArrayList<float[]> successJump, ArrayList<Double> successChi) {
|
||||
this.successJump=successJump;
|
||||
this.successChi=successChi;
|
||||
}
|
||||
@ -197,7 +199,7 @@ public class MCMC implements MinimisationAlgorithm {
|
||||
/**
|
||||
* A list of points of the successful jumps.
|
||||
*/
|
||||
public ArrayList<double[]> successJump;
|
||||
public ArrayList<float[]> successJump;
|
||||
|
||||
/**
|
||||
* The number of dimensions.
|
||||
@ -584,7 +586,7 @@ public class MCMC implements MinimisationAlgorithm {
|
||||
//find min value
|
||||
int minIndex = chainResult.successChi.indexOf(Collections.min(chainResult.successChi));
|
||||
minChi2=chainResult.successChi.get(minIndex);
|
||||
minChi2Pos=chainResult.successJump.get(minIndex);
|
||||
minChi2Pos=PamArrayUtils.float2Double(chainResult.successJump.get(minIndex));
|
||||
|
||||
break;
|
||||
}
|
||||
@ -728,19 +730,19 @@ public class MCMC implements MinimisationAlgorithm {
|
||||
*/
|
||||
private EllipticalError getLocError(ArrayList<ChainResult> data) {
|
||||
|
||||
ArrayList<double[]> successJumpAll = new ArrayList<double[]>();
|
||||
List<double[]> successJump;
|
||||
ArrayList<float[]> successJumpAll = new ArrayList<float[]>();
|
||||
List<float[]> successJump;
|
||||
for (int i=0; i<data.size(); i++) {
|
||||
successJump = data.get(i).successJump.subList((int) this.settings.percentageToIgnore*data.get(i).successJump.size(),
|
||||
data.get(i).successJump.size()-1);
|
||||
successJumpAll.addAll(successJump);
|
||||
}
|
||||
|
||||
double[][] results= new double[successJumpAll.size()][3];
|
||||
float[][] results= new float[successJumpAll.size()][3];
|
||||
results=successJumpAll.toArray(results);
|
||||
|
||||
//Elliptical error
|
||||
EllipticalError ellError= new EllipticalError(results);
|
||||
EllipticalError ellError= new EllipticalError(PamArrayUtils.float2Double(results));
|
||||
|
||||
return ellError;
|
||||
}
|
||||
|
@ -6,6 +6,12 @@ import PamModel.parametermanager.ManagedParameters;
|
||||
import PamModel.parametermanager.PamParameterSet;
|
||||
import PamModel.parametermanager.PamParameterSet.ParameterSetType;
|
||||
|
||||
/**
|
||||
* Paramters for running a Marklov chain Monte Carlo algorithm.
|
||||
*
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class MCMCParams2 implements Serializable, Cloneable, ManagedParameters {
|
||||
|
||||
public static final long serialVersionUID = 3L;
|
||||
@ -30,7 +36,7 @@ public class MCMCParams2 implements Serializable, Cloneable, ManagedParameters
|
||||
public int numberOfJumps=250000; //int
|
||||
|
||||
/**
|
||||
* Where in paramter space the chains should start. Each value in the array is for one dimension. When
|
||||
* Where in parameter space the chains should start. Each value in the array is for one dimension. When
|
||||
* chains start a random number between the two numbers is chosen as the start position in that dimension for the
|
||||
* chain.
|
||||
*/
|
||||
@ -42,11 +48,11 @@ public class MCMCParams2 implements Serializable, Cloneable, ManagedParameters
|
||||
public int numberOfChains=4; //int
|
||||
|
||||
/**
|
||||
* Use cyclindrical jumps.
|
||||
* Use cylindrical jumps.
|
||||
*/
|
||||
public boolean cylindricalCoOrdinates = false;
|
||||
/**
|
||||
* Set the chain jump size- sets the jump size of all dimensions to the input jumpsize
|
||||
* Set the chain jump size- sets the jump size of all dimensions to the input jump size.
|
||||
* @param jumpsize the jump size for all dimensions.
|
||||
* @param nDim the number of dimensions.
|
||||
*/
|
||||
@ -59,8 +65,8 @@ public class MCMCParams2 implements Serializable, Cloneable, ManagedParameters
|
||||
|
||||
/**
|
||||
* Set chain start dispersion to one value for all dimensions. The start dispersion is a random number centered
|
||||
* on zero and from a distribution with a size defined by the dispersion input paramater.
|
||||
* @param dispersion the chain start dispersion for all dimensions. element 1 is th
|
||||
* on zero and from a distribution with a size defined by the dispersion input parameter.
|
||||
* @param dispersion the chain start dispersion for all dimensions.
|
||||
*/
|
||||
public double[][] setChainDispersion(double dispersion, int nDim){
|
||||
chainStartDispersion=new double[nDim][2];
|
||||
@ -87,11 +93,20 @@ public class MCMCParams2 implements Serializable, Cloneable, ManagedParameters
|
||||
public double percentageToIgnore=0.7; //%
|
||||
|
||||
|
||||
//cluster analysis;
|
||||
/**
|
||||
* The type of cluster analysis to use to merge the different chains if they converge on the same or ambiguous results. See K_MEANS and NONE constants.
|
||||
*/
|
||||
public int clusterAnalysis=K_MEANS;
|
||||
|
||||
/**
|
||||
* Do not attempt to cluster the chains.
|
||||
*/
|
||||
public static final int NONE=0;
|
||||
|
||||
|
||||
/**
|
||||
* Use K_MEANS to cluster the different chains
|
||||
*/
|
||||
public static final int K_MEANS=1;
|
||||
|
||||
public Integer nKMeans=2; //int
|
||||
@ -99,12 +114,12 @@ public class MCMCParams2 implements Serializable, Cloneable, ManagedParameters
|
||||
public double maxClusterSize=5; //meters
|
||||
|
||||
/**
|
||||
* The number of times to perform a kmeans algorithm on results The algorithm starts clusters at random locations.
|
||||
* The number of times to perform a k-means algorithm on results The algorithm starts clusters at random locations.
|
||||
*/
|
||||
public int kmeanAttempts=10;
|
||||
|
||||
/**
|
||||
* The number of iterations for each kmeans attempt. Kmeans converges to a result but requires a certain number of iteration to
|
||||
* The number of iterations for each k-means attempt. K-means converges to a result but requires a certain number of iteration to
|
||||
* do so.
|
||||
*/
|
||||
public int kmeansIterations=20;
|
||||
|
@ -6,6 +6,7 @@ import javax.vecmath.Point3f;
|
||||
|
||||
import Localiser.algorithms.genericLocaliser.MCMC.MCMC.ChainResult;
|
||||
import Localiser.algorithms.locErrors.EllipticalError;
|
||||
import PamUtils.PamArrayUtils;
|
||||
|
||||
public class MCMCResult {
|
||||
|
||||
@ -122,18 +123,90 @@ public class MCMCResult {
|
||||
public ArrayList<ArrayList<Point3f>> getJumps() {
|
||||
ArrayList<ArrayList<Point3f>> jumps=new ArrayList<ArrayList<Point3f>>();
|
||||
ArrayList<Point3f> chainJumps;
|
||||
double[] ajump;
|
||||
float[] ajump;
|
||||
for (int i=0; i<this.data.size(); i++) {
|
||||
chainJumps= new ArrayList<Point3f>();
|
||||
for (int j=0; j<this.data.get(i).successJump.size(); j++) {
|
||||
ajump= this.data.get(i).successJump.get(j);
|
||||
chainJumps.add(new Point3f((float) ajump[0], (float) ajump[1], (float) ajump[2]));
|
||||
chainJumps.add(new Point3f(ajump[0], ajump[1], ajump[2]));
|
||||
}
|
||||
jumps.add(chainJumps);
|
||||
}
|
||||
return jumps;
|
||||
}
|
||||
|
||||
|
||||
public double[][] getJumpsd() {
|
||||
return getJumpsd(1);
|
||||
}
|
||||
|
||||
public double[][] getJumpsf() {
|
||||
return getJumpsd(1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the jumps for the MCMC algorithm in double[][] format. This is for legacy code.
|
||||
* @param div - reduce the data by div times (e.g. for plotting).
|
||||
* @return the MCMC jumps from all chains.
|
||||
*/
|
||||
public double[][] getJumpsd(int div) {
|
||||
|
||||
if (div<1) div = 1;
|
||||
|
||||
// int nJumps = 0;
|
||||
// for (int i=0; i<this.data.size(); i++) {
|
||||
// nJumps = (int) (nJumps + Math.floor(this.data.get(i).successJump.size()/div)+1);
|
||||
// }
|
||||
//
|
||||
int nJumps = 0;
|
||||
for (int i=0; i<this.data.size(); i++) {
|
||||
for (int j=0; j<this.data.get(i).successJump.size(); j=j+div) {
|
||||
nJumps++;
|
||||
}
|
||||
}
|
||||
double[][] jumps = new double[nJumps][];
|
||||
|
||||
double[] ajump;
|
||||
int n=0;
|
||||
for (int i=0; i<this.data.size(); i++) {
|
||||
for (int j=0; j<this.data.get(i).successJump.size(); j=j+div) {
|
||||
ajump= PamArrayUtils.float2Double(this.data.get(i).successJump.get(j));
|
||||
jumps[n] = ajump;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return jumps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the jumps for the MCMC algorithm in double[][] format. This is for legacy code.
|
||||
* @param div - reduce the data by div times (e.g. for plotting).
|
||||
* @return the MCMC jumps from all chains.
|
||||
*/
|
||||
public float[][] getJumpsf(int div) {
|
||||
|
||||
if (div<1) div =1;
|
||||
|
||||
int nJumps = 0;
|
||||
for (int i=0; i<this.data.size(); i++) {
|
||||
nJumps = nJumps + this.data.get(i).successJump.size();
|
||||
}
|
||||
float[][] jumps = new float[(int) Math.floor(nJumps/div)][];
|
||||
|
||||
float[] ajump;
|
||||
int n=0;
|
||||
for (int i=0; i<this.data.size(); i=i++) {
|
||||
for (int j=0; j<this.data.get(i).successJump.size(); j=j+div) {
|
||||
ajump= this.data.get(i).successJump.get(j);
|
||||
jumps[n] = ajump;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return jumps;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,8 +20,12 @@ import Localiser.algorithms.locErrors.LikilihoodError;
|
||||
import Localiser.algorithms.locErrors.LocaliserError;
|
||||
|
||||
/**
|
||||
* Time delay based simplex method for localisation. Note that a lot of the code here has been referenced directly from static MCMC functions. This is because both MCMC and Simplex are based on the forward time delay problem
|
||||
* hence are mathematically very similar. Simplex is much faster than MCMC but does not provide a full 3D probability distribution.
|
||||
* Time delay based simplex method for localisation. Note that a lot of the code
|
||||
* here has been referenced directly from static MCMC functions. This is because
|
||||
* both MCMC and Simplex are based on the forward time delay problem hence are
|
||||
* mathematically very similar. Simplex is much faster than MCMC but does not
|
||||
* provide a full 3D probability distribution.
|
||||
*
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
|
@ -10,8 +10,10 @@ import java.awt.geom.Point2D;
|
||||
|
||||
import PamUtils.Coordinate3d;
|
||||
import PamUtils.LatLong;
|
||||
import PamUtils.PamArrayUtils;
|
||||
import PamView.TransformShape;
|
||||
import PamView.GeneralProjector;
|
||||
import PamguardMVC.PamConstants;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import pamMaths.PamVector;
|
||||
|
||||
@ -28,15 +30,20 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
|
||||
*/
|
||||
private EllipticalError ellipticalError;
|
||||
|
||||
public EllipticalError getEllipticalError() {
|
||||
return ellipticalError;
|
||||
}
|
||||
|
||||
public static final int DRAW_LINES = 1;
|
||||
public static final int DRAW_OVALS = 2;
|
||||
private int drawType = DRAW_OVALS;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for drawing an ellipsoid.
|
||||
* @param ellipticalError
|
||||
*/
|
||||
EllipseLocErrorDraw(EllipticalError ellipticalError){
|
||||
protected EllipseLocErrorDraw(EllipticalError ellipticalError){
|
||||
this.ellipticalError=ellipticalError;
|
||||
}
|
||||
|
||||
@ -55,6 +62,8 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public TransformShape drawLinesOnMap(Graphics g, PamDataUnit pamDetection, LatLong errorOrigin,
|
||||
GeneralProjector generalProjector, Color ellipseColor) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
@ -102,20 +111,27 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public TransformShape drawOvalsOnMap(Graphics g, PamDataUnit pamDetection, LatLong errorOrigin,
|
||||
GeneralProjector generalProjector, Color ellipseColor) {
|
||||
|
||||
|
||||
//this is 2D- need to make a slice through the ellipse and get the localisation points.
|
||||
double[] errors2D=ellipticalError.getErrorEllipse2D(ErrorEllipse.PLANE_XY_PROJ);
|
||||
// if (1>0) return null;
|
||||
|
||||
if (errors2D==null) return null;
|
||||
|
||||
|
||||
if (errors2D[0] > PamConstants.EARTH_RADIUS_METERS || errors2D[1] > PamConstants.EARTH_RADIUS_METERS) {
|
||||
return null; //don't draw infintie stuff - causes nasty errors.
|
||||
}
|
||||
// System.out.println("Draw ovals on map");
|
||||
// System.out.println("EllipseLocErrorDraw: draw ellipse:"+errors2D[0]+" "+errors2D[1]+" "+Math.toDegrees(errors2D[2]));
|
||||
|
||||
//System.out.println("Plot errors: perp: "+ perpError+ " horz: "+horzError+ " " + errorDirection);
|
||||
Graphics2D g2d = (Graphics2D)g;
|
||||
|
||||
if (errors2D==null) return null;
|
||||
|
||||
//draw oval
|
||||
// //need to work out the size of the horizontal error.
|
||||
// perpError=Math.max(perpError, 100);
|
||||
@ -140,7 +156,7 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
|
||||
|
||||
//draw the ellipse and rotate.
|
||||
Ellipse2D oval=new Ellipse2D.Double(errorOriginXY.getX()-horzErrPix/2, errorOriginXY.getY()-perpErrPix/2, horzErrPix, perpErrPix);
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 5 * 0.1f));
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 5 * 0.05f));
|
||||
g2d.setPaint(ellipseColor.brighter());
|
||||
|
||||
if (!Double.isNaN(errorDirection)) g2d.rotate(-paintAngle, errorOriginXY.getX(), errorOriginXY.getY());
|
||||
@ -158,4 +174,8 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
|
||||
|
||||
}
|
||||
|
||||
public int getDrawType() {
|
||||
return drawType;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ public class EllipticalError implements LocaliserError {
|
||||
errorEllipse = new ErrorEllipse(errors, angles);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public double getError(PamVector errorDirection) {
|
||||
return errorEllipse.getErrorMagnitude(errorDirection.getUnitVector().getVector());
|
||||
@ -78,7 +80,7 @@ public class EllipticalError implements LocaliserError {
|
||||
|
||||
/**
|
||||
* Get the 2D elliptical error.
|
||||
* @param planeXy - the plane on whihc to find the ellipse for.
|
||||
* @param planeXy - the plane on which to find the ellipse for.
|
||||
* @return the elliptical error.
|
||||
*/
|
||||
public double[] getErrorEllipse2D(int planeXy) {
|
||||
@ -111,6 +113,9 @@ public class EllipticalError implements LocaliserError {
|
||||
@Override
|
||||
public String getStringResult() {
|
||||
String description="";
|
||||
if (errorEllipse==null) {
|
||||
return "Elliptical error is null";
|
||||
}
|
||||
if (!errorEllipse.is3D()){
|
||||
description+=String.format("<i>&ensp 2D Elliptical error: <br>&ensp Radii: ");
|
||||
for (int i=0; i<errorEllipse.getEllipseDim().length; i++){
|
||||
|
@ -14,10 +14,13 @@ import org.apache.commons.math3.stat.correlation.Covariance;
|
||||
|
||||
|
||||
/**
|
||||
* Class for calculating errors from localisation data. An error ellipse describes N dimensional error based on a scatter of points or
|
||||
* chi2 surface. The dimensions and rotation of the ellipse describe the distribution of error. Note that although an ellipse will often be a satisfactory
|
||||
* description of an error surface, in some cases it will not adequately represent errors. e.g. a linear array produces a doughnut shaped error
|
||||
* surface which would not be described well by an ellipse.
|
||||
* Class for calculating errors from localisation data. An error ellipse
|
||||
* describes N dimensional error based on a scatter of points or chi2 surface.
|
||||
* The dimensions and rotation of the ellipse describe the distribution of
|
||||
* error. Note that although an ellipse will often be a satisfactory description
|
||||
* of an error surface, in some cases it will not adequately represent errors.
|
||||
* e.g. a linear array produces a doughnut shaped error surface which would not
|
||||
* be described well by an ellipse.
|
||||
*
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
@ -41,17 +44,17 @@ public class ErrorEllipse {
|
||||
public static final int PLANE_ZX=2;
|
||||
|
||||
/**
|
||||
*Project the ellipse ontpo the XY plane- the extremties oif the ellipse are kept
|
||||
*Project the ellipse ontpo the XY plane- the extremities of the ellipse are kept
|
||||
*/
|
||||
public static final int PLANE_XY_PROJ=3;
|
||||
|
||||
/**
|
||||
*Project the ellipse ontpo the Yz plane- the extremties oif the ellipse are kept
|
||||
*Project the ellipse ontpo the Yz plane- the extremities of the ellipse are kept
|
||||
*/
|
||||
public static final int PLANE_ZY_PROJ=4;
|
||||
|
||||
/**
|
||||
*Project the ellipse ontpo the ZX plane- the extremties oif the ellipse are kept
|
||||
*Project the ellipse ontpo the ZX plane- the extremities of the ellipse are kept
|
||||
*/
|
||||
public static final int PLANE_ZX_PROJ=5;
|
||||
|
||||
@ -88,13 +91,12 @@ public class ErrorEllipse {
|
||||
* The dimensions of the ellipse/ellipsoid. This is generally a,b for 2D and a, b, c for 3D
|
||||
* the ellipse/ellipsoid is described by x^2/a + y^2/b+ z^2/c =1. c is -1 if a 2D ellipse.
|
||||
*/
|
||||
private double[] ellipseDim;
|
||||
private double[] ellipseDim = new double[]{0,0,0};
|
||||
|
||||
/**
|
||||
* The angle of the ellipsoid in RADIANS. Angles are euler angles and in order heading pitch and roll.
|
||||
*/
|
||||
private double[] angles;
|
||||
|
||||
private double[] angles = new double[]{0,0,0};
|
||||
|
||||
/**
|
||||
* Generate an error ellipse from a set of points. The dimensions of the error ellipse is by
|
||||
@ -164,6 +166,10 @@ public class ErrorEllipse {
|
||||
return;
|
||||
}
|
||||
|
||||
if (points.length<3) {
|
||||
return;
|
||||
}
|
||||
|
||||
Covariance cov= new Covariance(points, false);
|
||||
|
||||
// System.out.println("Coveriance");
|
||||
@ -191,7 +197,7 @@ public class ErrorEllipse {
|
||||
/**
|
||||
* Calculate the error ellipse from eigenvalues and eigenvectors.
|
||||
* @param eigenVal - matrix the eigenvalues - this is the size of the ellipse
|
||||
* @param eigenVec - matrix eigenvectors- the direction of the ellispe. Not necassarily in order.
|
||||
* @param eigenVec - matrix eigenvectors- the direction of the ellipse. Not necassarily in order.
|
||||
*/
|
||||
private void calcErrorEllipse(RealMatrix eigenVal, RealMatrix eigenVec){
|
||||
|
||||
@ -339,8 +345,10 @@ public class ErrorEllipse {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*FIXME - this needs work to make sure roll works
|
||||
* Get the ellipse projected onto a 3D plane.
|
||||
* @return an array. array [0] is the first radii. array[1] is the second radii. array[2] is the rotation irelative to the plane in radians.
|
||||
* @return an array. array [0] is the first radii. array[1] is the second radii. array[2] is the rotation relative to the plane in RADIANS.
|
||||
*/
|
||||
public double[] getErrorEllipse2D(int planeType){
|
||||
|
||||
@ -356,7 +364,7 @@ public class ErrorEllipse {
|
||||
}
|
||||
else {
|
||||
if(errorEllipseXY==null){
|
||||
//here we calculate and save the prjection- once saved the projection is never
|
||||
//here we calculate and save the projection- once saved the projection is never
|
||||
//recalculated.
|
||||
errorEllipseXY = calc2DEllipse(planeType);
|
||||
if (errorEllipseXY == null) return null;
|
||||
@ -365,7 +373,7 @@ public class ErrorEllipse {
|
||||
data[0]=errorEllipseXY.getEllipseDim()[0];
|
||||
data[1]=errorEllipseXY.getEllipseDim()[1];
|
||||
data[2]=errorEllipseXY.getAngles()[0];
|
||||
//System.out.println("ErrorEllipse: data: "+data[0]+ " "+data[1]+" "+data[1] + " Ellipse largest vector: "+getEllipseDim()[0]);
|
||||
//System.out.println("ErrorEllipse: data: "+data[0]+ " "+data[1]+" "+data[2] + " Ellipse largest vector: "+getEllipseDim()[0]);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -388,7 +396,7 @@ public class ErrorEllipse {
|
||||
|
||||
|
||||
/**
|
||||
* Claculate a 2D projec tion of the 3D ellipse.
|
||||
* Calculate a 2D projection of the 3D ellipse.
|
||||
* @param planeType
|
||||
* @return
|
||||
*/
|
||||
@ -426,8 +434,10 @@ public class ErrorEllipse {
|
||||
dim1=0;
|
||||
dim2=1;
|
||||
|
||||
//22 Aug 2023 - dim[1] was using sin instead of cos - for projecting onto a 2d plane cos
|
||||
//is the correct trig function to use.
|
||||
dim[0]=this.ellipseDim[0]*Math.cos(this.angles[1]); //the major axis on 2D
|
||||
dim[1]=this.ellipseDim[1]*Math.sin(this.angles[2]); //the minor Axis.
|
||||
dim[1]=this.ellipseDim[1]*Math.cos(this.angles[2]); //the minor Axis.
|
||||
angles[0]=this.angles[0];
|
||||
|
||||
break;
|
||||
@ -450,13 +460,11 @@ public class ErrorEllipse {
|
||||
ErrorEllipse errorEllipse2D=new ErrorEllipse(dim, angles);
|
||||
|
||||
return errorEllipse2D;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a projection of the ellipse into 2D. The prjection is a defined plane slicing throug the center of the ellipse
|
||||
* Generate a projection of the ellipse into 2D. The projection is a defined plane slicing through the center of the ellipse
|
||||
* @param planeType - the type of plane. PLANE_XY, PLANE_ZY, PLANE_ZX
|
||||
* @return the 2D projection of the ellipse onto a plane.
|
||||
*/
|
||||
|
@ -1,10 +1,10 @@
|
||||
package Localiser.algorithms.locErrors;
|
||||
|
||||
public class ErrorEllipseXMLData extends ErrorXMLData {
|
||||
public class ErrorEllipseJSONData extends ErrorJSONData {
|
||||
|
||||
private EllipticalError ellipticalError;
|
||||
|
||||
public ErrorEllipseXMLData(EllipticalError ellipticalError) {
|
||||
public ErrorEllipseJSONData(EllipticalError ellipticalError) {
|
||||
this.ellipticalError = ellipticalError;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package Localiser.algorithms.locErrors;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public abstract class ErrorXMLData {
|
||||
public abstract class ErrorJSONData {
|
||||
|
||||
|
||||
protected static final DecimalFormat errorDigitFormat = new DecimalFormat("0.###E0");
|
@ -42,7 +42,7 @@ public class LikilihoodError extends EllipticalError {
|
||||
super();
|
||||
this.chi2=chi2;
|
||||
this.point=point;
|
||||
super.setErrorEllipse(chi2SurftoErrorEllipse( chi2, point, 3));
|
||||
super.setErrorEllipse(chi2SurftoErrorEllipse(point, 3));
|
||||
}
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ public class LikilihoodError extends EllipticalError {
|
||||
super();
|
||||
this.chi2=chi2;
|
||||
this.point=point;
|
||||
super.setErrorEllipse(chi2SurftoErrorEllipse( chi2, point, nDim));
|
||||
super.setErrorEllipse(chi2SurftoErrorEllipse(point, nDim));
|
||||
}
|
||||
|
||||
|
||||
@ -62,17 +62,17 @@ public class LikilihoodError extends EllipticalError {
|
||||
* @param nDim - the number of dimensions. 2 or 3.
|
||||
* @return the approximate 3D ellipse which represents the error.
|
||||
*/
|
||||
private ErrorEllipse chi2SurftoErrorEllipse(MinimisationFunction chi2, double[] point, int nDim){
|
||||
private ErrorEllipse chi2SurftoErrorEllipse(double[] point, int nDim){
|
||||
ErrorEllipse errorEllipse;
|
||||
if (nDim==2){
|
||||
errorEllipse = chi2SurfToErrorEllipse2D(chi2, point);
|
||||
errorEllipse = chi2SurfToErrorEllipse2D( point);
|
||||
}
|
||||
else if (nDim==3){
|
||||
errorEllipse = chi2SurfToErrorEllipse3D(chi2, point);
|
||||
errorEllipse = chi2SurfToErrorEllipse3D (point);
|
||||
if (errorEllipse==null) {
|
||||
//maight have failed due to a 3D model trying to fit a 2D problem and therefore
|
||||
//heading off to infinity...
|
||||
errorEllipse = chi2SurfToErrorEllipse2D(chi2, point);
|
||||
errorEllipse = chi2SurfToErrorEllipse2D( point);
|
||||
}
|
||||
}
|
||||
else{
|
||||
@ -90,7 +90,7 @@ public class LikilihoodError extends EllipticalError {
|
||||
* @param point - the point on the surface to search around for error.
|
||||
* @return the approximate 3D ellipse which represents the error.
|
||||
*/
|
||||
private ErrorEllipse chi2SurfToErrorEllipse2D(MinimisationFunction chi2, double[] point2) {
|
||||
private ErrorEllipse chi2SurfToErrorEllipse2D(double[] point2) {
|
||||
|
||||
//create a set of numbers around a sphere;
|
||||
double angleBin=(2*Math.PI)/nSpherePoints;
|
||||
@ -100,14 +100,14 @@ public class LikilihoodError extends EllipticalError {
|
||||
int ind=-1;
|
||||
for (int i=0; i<nSpherePoints; i++){
|
||||
//now because the sphere has a radius of 1, all the points are already unit vectors.
|
||||
curvatureError=getLLCurvature(chi2, point, PamVector.fromHeadAndSlant(Math.toDegrees(angleBin*i), 0));
|
||||
curvatureError=getLLCurvature(point, PamVector.fromHeadAndSlant(Math.toDegrees(angleBin*i), 0));
|
||||
if (curvatureError>max){
|
||||
max=curvatureError;
|
||||
ind=i; //record index of max value;
|
||||
}
|
||||
}
|
||||
|
||||
double[] dim={max, getLLCurvature(chi2, point, PamVector.fromHeadAndSlant(Math.toDegrees(angleBin*ind)+90, 0)),-1 };
|
||||
double[] dim={max, getLLCurvature(point, PamVector.fromHeadAndSlant(Math.toDegrees(angleBin*ind)+90, 0)),-1 };
|
||||
double[] angles={angleBin*ind, 0,0};
|
||||
|
||||
for (int i=0; i<dim.length; i++){
|
||||
@ -130,7 +130,7 @@ public class LikilihoodError extends EllipticalError {
|
||||
* @param point - the point on the surface to search around for error.
|
||||
* @return the approximate 3D ellipse which represents the error. Returns null if it is not possible to calculate an error.
|
||||
*/
|
||||
private ErrorEllipse chi2SurfToErrorEllipse3D(MinimisationFunction chi2, double[] point){
|
||||
private ErrorEllipse chi2SurfToErrorEllipse3D(double[] point){
|
||||
//first, find the largest error.
|
||||
|
||||
//create a set of numbers around a sphere;
|
||||
@ -141,7 +141,7 @@ public class LikilihoodError extends EllipticalError {
|
||||
int ind=-1;
|
||||
for (int i=0; i<spherePoints.length; i++){
|
||||
//now because the sphere has a radius of 1, all the points are already unit vectors.
|
||||
curvatureError=getLLCurvature(chi2, point, new PamVector(spherePoints[i]));
|
||||
curvatureError=getLLCurvature(point, new PamVector(spherePoints[i]));
|
||||
//System.out.printf("Curve error %d = %3.2f\n", i, curvatureError);
|
||||
if (curvatureError>max){
|
||||
max=curvatureError;
|
||||
@ -171,7 +171,7 @@ public class LikilihoodError extends EllipticalError {
|
||||
Vector3D location3D=plane.getPointAt(vector2D, 0);
|
||||
|
||||
// get the max error in this plane.
|
||||
curvatureError=getLLCurvature(chi2, point, new PamVector(location3D.toArray()));
|
||||
curvatureError=getLLCurvature(point, new PamVector(location3D.toArray()));
|
||||
if (curvatureError>maxPlane){
|
||||
maxPlane=curvatureError;
|
||||
indPlane=n; //record index of max value;
|
||||
@ -203,7 +203,7 @@ public class LikilihoodError extends EllipticalError {
|
||||
ArrayList<Vector3D> vectors=new ArrayList<Vector3D>();
|
||||
vectors.add(firstEigenvector.scalarMultiply(max)); //have already calculated error in previous steps.
|
||||
vectors.add(secondVector.scalarMultiply(maxPlane)); //have already calculated error in previous steps.
|
||||
vectors.add(thirdVector.scalarMultiply(getLLCurvature( chi2, point, new PamVector(thirdVector.toArray()))));
|
||||
vectors.add(thirdVector.scalarMultiply(getLLCurvature( point, new PamVector(thirdVector.toArray()))));
|
||||
|
||||
//create an error ellipse.
|
||||
ErrorEllipse errorEllipse=new ErrorEllipse(vectors);
|
||||
@ -240,7 +240,7 @@ public class LikilihoodError extends EllipticalError {
|
||||
* direction specified and in the opposite direction. Curvature is expressed as 1 standard deviation
|
||||
* error
|
||||
*/
|
||||
private double getLLCurvature(MinimisationFunction chi2, double[] point, PamVector errorVector) {
|
||||
private double getLLCurvature(double[] point, PamVector errorVector) {
|
||||
|
||||
double dis = 10; //the jump along the chi2 surface.
|
||||
double err = 0;
|
||||
|
@ -42,10 +42,7 @@ public class SimpleError implements LocaliserError {
|
||||
* @param xyzError - an array of the x/perpindicular y/parallel and z error in meters {x y z}
|
||||
*/
|
||||
public SimpleError(Double xyzError[]) {
|
||||
simpleErrorDraw=new SimpleLocErrorDraw(this);
|
||||
perpindiuclarError=xyzError[0];
|
||||
parallelError=xyzError[1];
|
||||
zError=xyzError[2];
|
||||
this(xyzError, 0.);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,14 +1,13 @@
|
||||
package Localiser.algorithms.locErrors;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
public class SimpleErrorXMLData extends ErrorXMLData {
|
||||
public class SimpleErrorJSONData extends ErrorJSONData {
|
||||
|
||||
private String errorType;
|
||||
private double[] errorData;
|
||||
|
||||
|
||||
public SimpleErrorXMLData(String errorType, double[] errorData) {
|
||||
public SimpleErrorJSONData(String errorType, double[] errorData) {
|
||||
this.errorType = errorType;
|
||||
this.errorData = errorData;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user