mirror of
https://github.com/PAMGuard/PAMGuard.git
synced 2024-11-21 22:52:22 +00:00
commit
97d26f8524
18
pom.xml
18
pom.xml
@ -270,14 +270,12 @@
|
||||
</repository>-->
|
||||
|
||||
<!-- Repo for Renjin Script Engine -->
|
||||
<repository>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
<id>bedatadriven</id>
|
||||
<name>bedatadriven_renjin</name>
|
||||
<url>https://nexus.bedatadriven.com/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>bedatadriven</id>
|
||||
<name>bedatadriven public repo</name>
|
||||
<url>https://nexus.bedatadriven.com/content/groups/public/</url>
|
||||
</repository>
|
||||
|
||||
|
||||
<repository>
|
||||
<snapshots>
|
||||
@ -310,7 +308,7 @@
|
||||
<dependency>
|
||||
<groupId>io.github.macster110</groupId>
|
||||
<artifactId>jdl4pam</artifactId>
|
||||
<version>0.0.98</version>
|
||||
<version>0.0.99</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/gov.nist.math/jama -->
|
||||
@ -711,7 +709,7 @@
|
||||
<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 -->
|
||||
|
74
readme.md
74
readme.md
@ -1,5 +1,73 @@
|
||||
This is the main code repository for the PAMGuard software.
|
||||
# PAMGuard
|
||||
PAMGuard is a bioacoustics analysis program designed for use in real time research contexts and for the processing of large datasets. PAMGuard provides users access to a suite of state-of-the-art auotmated analysis algorithms alongside displays for visualisation data and a comprehensive data management systems.
|
||||
|
||||
This repository was created on 7 January 2022 from sourceforge SVN repository at https://sourceforge.net/p/pamguard/svn/HEAD/tree/ revision r6278.
|
||||
# Why do we need PAMGuard?
|
||||
PAMGuard fufills two main requirements within marine bioacoustics
|
||||
|
||||
If you are a PAMGuard developer, you should clone and branch this repository and share with any collaborators in your own workspace. When your work is ready, contact the PAMGuard team to have your changes merged back into this repo.
|
||||
1) **Real time operation** - Almost all PAMGuard features and modules work in real time - this allows scientists and industry to detect, classify and loclaise animals in real time on a standard consumer laptop, enabling mitigations and research survey without expensive bespoke software solutions and the transparncy of open source software.
|
||||
|
||||
2) **Processing and visuslisation of large datasets** -
|
||||
|
||||
|
||||
## Installation
|
||||
PAMGuard is available on Windows and can be downloaded from the [PAMGuard website](www.pamguard.org). Note that we are considering MacOS installers but they are not available at this time.
|
||||
|
||||
## Tutorial
|
||||
PAMGuard is a modular program with two modes; real-time and viewer. Typically a user will start with real-time model, either in the field collecting data or post processing sound files from a recorder. Once data are processed, users move on to viewer mode where data can be explored and further processed.
|
||||
|
||||
Upon opening PAMGuard for the first time you are greeted with a blank screen. You must add a series of modules to create the desired acosutic workflow. For example if processing sound files then first add the Sound Acquisition module **_File->Add Modules->Sound Processing->Sound Acquisition_**. Then add the desired detection algorothms e.g. **_File->Add Modules->Detector->Click Detectors_**. Some modules (such as the click detector) have their own displays, others are added to more generalised displays. For example, the whislte and moan detector module shows detections on a spectrgram display. First add a new tab using **_File->Add Modules->Displays->User Display**. Click on the user display tab and then from the top menu select **_User display-> New Spectrgram_**. Right click on the added spectrgram and select whistle and moan contours to show whistle detections overlaid on the raw spectrgram.
|
||||
|
||||
Make sure to add the database and binary file storage modules **_File->Add Modules->Utilities->..._**) to save data then press the run button (red button) and data will process. PAMGuard can handle huge datasets so runing might take hours or even days. Progress is shown on the bottom of the screen.
|
||||
|
||||
## Features
|
||||
|
||||
### Hardware integration
|
||||
PAMGuard connects with hardware such as various GPS and AIS systems and a multitude of different sound cards (e.g. [National Instruments](www.ni.com) devices, [SAIL DAQ cards](www.smruconsulting.com/contact-us), almost all ASIO sound cards and standard computer sound cards) for real time data collection and processing. PAMGuard also works with some very bespoke hardware such as [DIFAR Sonobuoys]();
|
||||
|
||||
### Real time operation
|
||||
PAMGuard takes advanatge of multi-core processors to run multiple signal processing automatic analysis algorithms in real time to detect whales, dolphins, bats etc. Data are shown in different displayes, including interactive spectrograms and maps. You might be using PAMGuard for simply viewing a spectrgram and making recordings or running deep learning algorithms for multiple species and loclaising the results to view locations on a map. Whatever acosutic workflow a user creates, PAMGuard can run it in real time.
|
||||
|
||||
### Support for compressed audio
|
||||
PAMGuard supports processing audio data from standard files (e.g. wav, aif) and also compressed files (e.g. .flac and .sud). Notew that sud files are created on SoundTraps widely used marine recorders and can be read by PAMGuard without decompressing - PAMGuard will automtically import click detections if present in sud files. PAMGuard also supports importing detection data from CPODs and FPODs.
|
||||
|
||||
### Comprehensive data management system
|
||||
PAMGuard is designed to collect/process data from large acosutic datasets. PAMGuard stores data in an SQLite databases and "Binary" files. The database stores important metadata such as when data has been processed and some low volume data streams such as GPS. Binary files are not human readbale but efficient to access - PAMGuard stores detection data (e.g. clicks, whistles, noise, etc) in these files. this allows PAMGuard to rapidly access data from large datasets. Data from binary files can be viewed in PAMGuard viewer mode or can be exported to MATLAB using the PAMGuard-MATLAB library or the exported to R using the R PAMBinaries package.
|
||||
|
||||
### Access to detection and classification algorithms
|
||||
PAMGuard allows users to inegrate automated detection and classification algorithms directly into their acosutic workflow. There are a multitude of differwent algorothms to choose from, including a basic click detector, whislte and moan detector, GPL detector, click train detectors and many others. The idea behind PAMGuard is allow researchers to access open source state-of-the-art algorithms devleoped within the scientific community - if you want to contribute and get your algorithm into PAMGuard get in touch.
|
||||
|
||||
###Localisation
|
||||
PAMGuard has a mutltude of different options for acoustic loclaisation. There's a comprehesnive beam forming module for beam forming arrays, a large aperture localiser for 3D loclaisation and target motion analysis for towed hydrophone arrays.
|
||||
|
||||
###Soundscape analysis
|
||||
PAMGuard has a noise band (which supports third octave noise bands) and long term spectral average module for soundscape analysis.
|
||||
|
||||
### GIS
|
||||
Almsot all detection data can be visualised on a map. PAMGaurd also supports plotting GPS and AIS data.
|
||||
|
||||
### Suite of data visualisation tools
|
||||
An important aspect of PAMGuard is the ability for users to explore porcessed data. This is
|
||||
|
||||
### Advanced manual annotation
|
||||
The displays within PAMGuard support a variety of manual annottion tools. A simple spectrogram
|
||||
|
||||
### Deep learning integration
|
||||
|
||||
### Meatadata standard and Tethys compatibility
|
||||
|
||||
## Feature roadmap
|
||||
There's lots of features we would like to add to PAMGuard. If you want to add a feature you can either code it up yourself in Java and submit a pull request or get in touch with us to discuss how to it might be integrated. Some smaller features might be in our roadmap anyway but larger features usually require funding. Some features we are thinking about (but do not necassarily have time for yet) are;
|
||||
|
||||
* Support for decidecade noise bands (base 10 filter bank) in noise band monitor to meet Euopean standards
|
||||
* Capabaility to export data directly from PAMGaurd e.g. as MAT files.
|
||||
* Automated test suite to make releases more stable. Note that unit and integration tests are also being slowly incorporated.
|
||||
|
||||
## Development
|
||||
This is the main code repository for the PAMGuard software and was created on 7 January 2022 from a [sourceforge SVN repository](https://sourceforge.net/p/pamguard/svn/HEAD/tree/) revision r6278.
|
||||
|
||||
If you are a PAMGuard developer, you should clone and branch this repository and share with any collaborators in your own workspace. When your work is ready, contact the PAMGuard team to have your changes merged back into this repo.
|
||||
|
||||
PAMGuard uses Maven as build tool.
|
||||
|
||||
# Organisation and License
|
||||
PAMGuard is open source under an MIT license. It is currently primarily managed by the Sea Mammal Research Unit within the [University of St Andrews](https://www.st-andrews.ac.uk/). Please get in touch if you have any questions.
|
||||
|
@ -20,6 +20,7 @@ import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import PamUtils.PamCalendar;
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
import PamView.dialog.PamGridBagContraints;
|
||||
|
||||
/**
|
||||
@ -40,7 +41,7 @@ public class FileDateDialogStrip {
|
||||
private JButton settingsButton;
|
||||
|
||||
// private ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
public static FontIcon settingsIcon = FontIcon.of(MaterialDesignC.COG, 20, Color.DARK_GRAY);
|
||||
public static FontIcon settingsIcon = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY);
|
||||
|
||||
|
||||
private Window parent;
|
||||
|
@ -21,6 +21,7 @@ import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import PamController.PamController;
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
import PamView.dialog.PamDialog;
|
||||
import PamguardMVC.PamDataBlock;
|
||||
import PamguardMVC.dataSelector.DataSelector;
|
||||
@ -90,7 +91,7 @@ public class MapDetectionsDialog extends PamDialog {
|
||||
|
||||
MapDetectionData md;
|
||||
// ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
FontIcon settingsIcon = FontIcon.of(MaterialDesignC.COG, 20, Color.DARK_GRAY);
|
||||
FontIcon settingsIcon = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
md = mapDetectionsParameters.mapDetectionDatas.get(i);
|
||||
|
@ -30,7 +30,6 @@ import java.awt.MouseInfo;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
@ -39,17 +38,14 @@ import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import pamScrollSystem.PamScrollSlider;
|
||||
import Array.ArrayManager;
|
||||
import Array.PamArray;
|
||||
import Array.SnapshotGeometry;
|
||||
@ -61,7 +57,6 @@ import GPS.GpsData;
|
||||
import GPS.GpsDataUnit;
|
||||
import Map.gridbaselayer.GridbaseControl;
|
||||
import Map.gridbaselayer.MapRasterImage;
|
||||
import PamController.PamControlledUnit;
|
||||
import PamController.PamController;
|
||||
import PamController.PamControllerInterface;
|
||||
import PamController.masterReference.MasterReferencePoint;
|
||||
@ -83,7 +78,6 @@ import PamView.PamColors.PamColor;
|
||||
import PamView.panel.JPanelWithPamKey;
|
||||
import PamView.panel.KeyPanel;
|
||||
import PamView.paneloverlay.OverlayCheckboxMenuItem;
|
||||
import PamView.paneloverlay.overlaymark.MarkDataMatcher;
|
||||
import PamView.paneloverlay.overlaymark.MarkDataSelector;
|
||||
import PamView.paneloverlay.overlaymark.MarkOverlayDraw;
|
||||
import PamView.symbol.PamSymbolChooser;
|
||||
@ -1476,9 +1470,9 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana
|
||||
plotDetectorMenu.add(menuItem);
|
||||
plotDetectorMenu.addSeparator();
|
||||
|
||||
ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
ImageIcon settingsIconNot = new ImageIcon(
|
||||
ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
// ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
// ImageIcon settingsIconNot = new ImageIcon(
|
||||
// ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
|
||||
ArrayList<MapDetectionData> mddList = simpleMapRef.mapDetectionsManager.getMapDetectionDatas();
|
||||
for (int i = 0; i < mddList.size(); i++) {
|
||||
|
@ -100,6 +100,7 @@ import PamguardMVC.uid.UIDManager;
|
||||
import PamguardMVC.uid.UIDOnlineManager;
|
||||
import PamguardMVC.uid.UIDViewerManager;
|
||||
import binaryFileStorage.BinaryStore;
|
||||
import export.ExportOptions;
|
||||
import PamguardMVC.debug.Debug;
|
||||
|
||||
/**
|
||||
@ -2692,13 +2693,23 @@ public class PamController implements PamControllerInterface, PamSettings {
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to storage options dialog. Selects whethere data
|
||||
* Respond to storage options dialog. Selects whether data
|
||||
* are stored in binary, database or both
|
||||
* @param parentFrame
|
||||
*/
|
||||
public void storageOptions(JFrame parentFrame) {
|
||||
StorageOptions.getInstance().showDialog(parentFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show export options tp export data to other formats
|
||||
* @param parentFrame
|
||||
*/
|
||||
public void exportData(JFrame parentFrame) {
|
||||
ExportOptions.getInstance().showDialog(parentFrame);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a verbose level for debug output
|
||||
@ -2941,4 +2952,6 @@ public class PamController implements PamControllerInterface, PamSettings {
|
||||
return pamConfiguration;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -3,13 +3,16 @@ package PamUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.math.linear.Array2DRowRealMatrix;
|
||||
import org.apache.commons.math.linear.RealMatrix;
|
||||
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import us.hebi.matlab.mat.types.Matrix;
|
||||
|
||||
/**
|
||||
@ -176,6 +179,22 @@ public class PamArrayUtils {
|
||||
}
|
||||
return median;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the data unit with the lowest time in millis from a data unit list.
|
||||
* @param dataUnits - a data unit list.
|
||||
* @return the data unit with the lowest time in millis.
|
||||
*/
|
||||
public static PamDataUnit getMinTimeMillis(List<PamDataUnit> dataUnits) {
|
||||
// then
|
||||
PamDataUnit minByTime = dataUnits
|
||||
.stream()
|
||||
.min(Comparator.comparing(PamDataUnit::getTimeMilliseconds))
|
||||
.orElseThrow(NoSuchElementException::new);
|
||||
|
||||
return minByTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the median value of an array
|
||||
@ -419,6 +438,26 @@ public class PamArrayUtils {
|
||||
|
||||
return new double[] {min, max};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the minimum and maximum value of a 2D array.
|
||||
* @param arr - the array to find the maximum value of.
|
||||
* @return the minimum and maximum value in the array
|
||||
*/
|
||||
public static float[] minmax(float[][] arr) {
|
||||
float max = Float.NEGATIVE_INFINITY;
|
||||
float min = Float.POSITIVE_INFINITY;
|
||||
|
||||
for(int i=0; i<arr.length; i++) {
|
||||
for(int j=0; j<arr[i].length; j++) {
|
||||
max = Math.max(max, arr[i][j]);
|
||||
min = Math.min(min, arr[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
return new float[] {min, max};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -727,6 +766,17 @@ public class PamArrayUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an array to the console.
|
||||
* @param array to print
|
||||
*/
|
||||
public static void printArray(float[] array) {
|
||||
if (array==null) System.out.println("null");
|
||||
for (int i=0; i<array.length; i++) {
|
||||
System.out.println(i + ": " + array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Print an array to the console with no index numbers
|
||||
@ -814,14 +864,17 @@ public class PamArrayUtils {
|
||||
/**
|
||||
* Check whether there are duplicates within an array
|
||||
* @param the array.
|
||||
* @return true if there are duplicates.
|
||||
* @return true if the array is unique
|
||||
*/
|
||||
public static boolean unique(double[] array) {
|
||||
boolean duplicates=false;
|
||||
boolean duplicates=true;
|
||||
for (int j=0;j<array.length;j++)
|
||||
for (int k=j+1;k<array.length;k++)
|
||||
if (k!=j && array[k] == array[j])
|
||||
duplicates=true;
|
||||
if (k!=j && array[k] == array[j]) {
|
||||
//if
|
||||
duplicates=false;
|
||||
return duplicates;
|
||||
}
|
||||
return duplicates;
|
||||
}
|
||||
|
||||
@ -1161,6 +1214,7 @@ public class PamArrayUtils {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -14,7 +14,8 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A series of classes to load and import data stored in text files (includes .csv files)
|
||||
* Some functions to load and import data stored in text files (includes .csv files)
|
||||
*
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
|
@ -1,13 +1,17 @@
|
||||
package PamView;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
@ -19,21 +23,51 @@ public class PamAWTUtils {
|
||||
|
||||
/**
|
||||
* Disable an entire swing panel including all child components.
|
||||
* @param panel - the panel to disable
|
||||
* @param jComponent - the panel to disable
|
||||
* @param isEnabled true if enabled.
|
||||
*/
|
||||
public static void setPanelEnabled(JPanel panel, Boolean isEnabled) {
|
||||
panel.setEnabled(isEnabled);
|
||||
|
||||
Component[] components = panel.getComponents();
|
||||
|
||||
for (Component component : components) {
|
||||
if (component instanceof JPanel) {
|
||||
setPanelEnabled((JPanel) component, isEnabled);
|
||||
}
|
||||
component.setEnabled(isEnabled);
|
||||
}
|
||||
public static void setPanelEnabled(JComponent jComponent, Boolean isEnabled) {
|
||||
setPanelEnabled(jComponent, isEnabled? 1 :-1);
|
||||
}
|
||||
|
||||
// private static final Map<Component, Integer> componentAvailability = new WeakHashMap<Component, Integer>();
|
||||
|
||||
public static void setMoreEnabled(Component component) {
|
||||
setPanelEnabled(component, +1);
|
||||
}
|
||||
|
||||
public static void setMoreDisabled(Component component) {
|
||||
setPanelEnabled(component, -1);
|
||||
}
|
||||
|
||||
// val = 1 for enabling, val = -1 for disabling
|
||||
private static void setPanelEnabled(Component component, int val) {
|
||||
if (component != null) {
|
||||
|
||||
// final Integer oldValObj = componentAvailability.get(component);
|
||||
//
|
||||
// final int oldVal = (oldValObj == null)
|
||||
// ? 0
|
||||
// : oldValObj;
|
||||
//
|
||||
// final int newVal = oldVal + val;
|
||||
// componentAvailability.put(component, newVal);
|
||||
|
||||
int newVal = val;
|
||||
|
||||
if (newVal >= 0) {
|
||||
component.setEnabled(true);
|
||||
} else if (newVal < 0) {
|
||||
component.setEnabled(false);
|
||||
}
|
||||
if (component instanceof Container) {
|
||||
Container componentAsContainer = (Container) component;
|
||||
for (Component c : componentAsContainer.getComponents()) {
|
||||
setPanelEnabled(c,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the closest boundary of a shape to a point.
|
||||
|
@ -667,6 +667,13 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
|
||||
menuItem.addActionListener(new StorageOptions(getGuiFrame()));
|
||||
startMenuEnabler.addMenuItem(menuItem);
|
||||
fileMenu.add(menuItem);
|
||||
|
||||
if (isViewer) {
|
||||
menuItem = new JMenuItem("Export Data ...");
|
||||
menuItem.addActionListener(new ExportData(getGuiFrame()));
|
||||
startMenuEnabler.addMenuItem(menuItem);
|
||||
fileMenu.add(menuItem);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pamControllerInterface.getNumControlledUnits(); i++) {
|
||||
|
||||
@ -975,6 +982,19 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
|
||||
}
|
||||
}
|
||||
|
||||
class ExportData implements ActionListener {
|
||||
private JFrame parentFrame;
|
||||
|
||||
public ExportData(JFrame parentFrame) {
|
||||
super();
|
||||
this.parentFrame = parentFrame;
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
PamController.getInstance().exportData(parentFrame);
|
||||
}
|
||||
}
|
||||
|
||||
class MenuGeneralXMLExport implements ActionListener {
|
||||
private JFrame parentFrame;
|
||||
public MenuGeneralXMLExport(JFrame parentFrame) {
|
||||
@ -1164,6 +1184,7 @@ public class PamGui extends PamView implements WindowListener, PamSettings {
|
||||
pamControllerInterface.orderModules(frame);
|
||||
}
|
||||
}
|
||||
|
||||
class menuArray implements ActionListener {
|
||||
public void actionPerformed(ActionEvent ev){
|
||||
ArrayManager.getArrayManager().showArrayDialog(getGuiFrame());
|
||||
|
@ -1,6 +1,7 @@
|
||||
package PamView;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionEvent;
|
||||
@ -13,6 +14,10 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.Timer;
|
||||
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignP;
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignR;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import warnings.PamWarning;
|
||||
import warnings.SingleLineWarningDisplay;
|
||||
import warnings.WarningDisplay;
|
||||
@ -22,6 +27,7 @@ import PamController.PamControlledUnit;
|
||||
import PamController.PamController;
|
||||
import PamUtils.PamCalendar;
|
||||
import PamView.PamColors.PamColor;
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
import PamView.dialog.PamLabel;
|
||||
import PamView.panel.PamPanel;
|
||||
|
||||
@ -51,19 +57,20 @@ public class TopToolBar extends PamToolBar implements ColorManaged {
|
||||
|
||||
pamController = PamController.getInstance();
|
||||
if (pamController.getRunMode() == PamController.RUN_PAMVIEW) {
|
||||
add(startButton = new JButton(new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/playStart.png"))));
|
||||
add(startButton = new JButton(FontIcon.of(MaterialDesignP.PLAY, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY)));
|
||||
startButton.setDisabledIcon(FontIcon.of(MaterialDesignP.PLAY, PamSettingsIconButton.NORMAL_SIZE, Color.LIGHT_GRAY));
|
||||
startButton.setToolTipText("Start sound playback");
|
||||
add(stopButton = new JButton(new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/playPause.png"))));
|
||||
add(stopButton = new JButton(FontIcon.of(MaterialDesignP.PAUSE, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY)));
|
||||
stopButton.setDisabledIcon(FontIcon.of(MaterialDesignP.PAUSE, PamSettingsIconButton.NORMAL_SIZE, Color.LIGHT_GRAY));
|
||||
|
||||
stopButton.setToolTipText("Stop sound playback");
|
||||
}
|
||||
else {
|
||||
add(startButton = new JButton(new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/recordStart.png"))));
|
||||
add(startButton = new JButton(FontIcon.of(MaterialDesignR.RECORD_CIRCLE, PamSettingsIconButton.NORMAL_SIZE, Color.RED)));
|
||||
startButton.setDisabledIcon(FontIcon.of(MaterialDesignR.RECORD_CIRCLE, PamSettingsIconButton.NORMAL_SIZE, Color.LIGHT_GRAY));
|
||||
startButton.setToolTipText("Start PAM processing");
|
||||
add(stopButton = new JButton(new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/playPause.png"))));
|
||||
add(stopButton = new JButton(FontIcon.of(MaterialDesignP.PAUSE, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY)));
|
||||
stopButton.setDisabledIcon(FontIcon.of(MaterialDesignP.PAUSE, PamSettingsIconButton.NORMAL_SIZE, Color.LIGHT_GRAY));
|
||||
stopButton.setToolTipText("Stop PAM processing");
|
||||
}
|
||||
startButton.addActionListener(new StartButton());
|
||||
|
@ -2,21 +2,29 @@ package PamView.component;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import org.kordamp.ikonli.Ikon;
|
||||
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
public class PamSettingsIconButton extends JButton {
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final int SMALL_SIZE = 17;
|
||||
|
||||
public static final int NORMAL_SIZE = 20;
|
||||
|
||||
/**
|
||||
* The ikon enum for the the setting button
|
||||
*/
|
||||
public static Ikon SETTINGS_IKON = MaterialDesignC.COG;
|
||||
|
||||
|
||||
// private static final ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
private static final FontIcon settingsIcon = FontIcon.of(MaterialDesignC.COG, 20, Color.DARK_GRAY);
|
||||
private static final FontIcon settingsIcon = FontIcon.of(SETTINGS_IKON, NORMAL_SIZE, Color.DARK_GRAY);
|
||||
|
||||
/**
|
||||
* Create a simple square button using the given icon.
|
||||
|
@ -10,6 +10,8 @@ import javax.swing.JButton;
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
|
||||
/**
|
||||
* Standard settings button with the little cogwheel for use throughout Swing components.
|
||||
* @author dg50
|
||||
@ -27,7 +29,7 @@ public class SettingsButton extends JButton {
|
||||
}
|
||||
|
||||
private static Icon makeIcon() {
|
||||
return FontIcon.of(MaterialDesignC.COG, 20, Color.DARK_GRAY);
|
||||
return FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.SMALL_SIZE, Color.DARK_GRAY);
|
||||
// return new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,13 @@ import javax.swing.JCheckBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignP;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import PamView.PamColors;
|
||||
import PamView.PamColors.PamColor;
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
import PamView.dialog.PamButtonAlpha;
|
||||
import PamView.dialog.PamDialog;
|
||||
import PamView.panel.CornerLayoutContraint;
|
||||
@ -29,14 +34,18 @@ public class HidingDialog extends PamDialog {
|
||||
|
||||
JCheckBox pinButton;
|
||||
|
||||
private ImageIcon settings=new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
// private ImageIcon settings=new ImageIcon(ClassLoader
|
||||
// .getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
//
|
||||
// private ImageIcon pinImage = new ImageIcon(ClassLoader
|
||||
// .getSystemResource("Resources/pinbuttonwhite.png"));
|
||||
//
|
||||
// private ImageIcon pinHide = new ImageIcon(ClassLoader
|
||||
// .getSystemResource("Resources/deletewhite.png"));
|
||||
|
||||
private ImageIcon pinImage = new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/pinbuttonwhite.png"));
|
||||
|
||||
private ImageIcon pinHide = new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/deletewhite.png"));
|
||||
private static final FontIcon settings = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.SMALL_SIZE, Color.WHITE);
|
||||
private static final FontIcon pinImage = FontIcon.of(MaterialDesignP.PIN, PamSettingsIconButton.SMALL_SIZE, Color.WHITE);
|
||||
private static final FontIcon pinHide = FontIcon.of(MaterialDesignP.PIN_OFF, PamSettingsIconButton.SMALL_SIZE, Color.WHITE);
|
||||
|
||||
|
||||
public HidingDialog(Window parentFrame, HidingDialogPanel hidingDialogPanel, String title, boolean hasDefault) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package PamView.paneloverlay;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
@ -8,6 +9,10 @@ import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
import PamView.symbol.PamSymbolManager;
|
||||
import PamguardMVC.PamDataBlock;
|
||||
import PamguardMVC.dataSelector.DataSelector;
|
||||
@ -23,8 +28,12 @@ import PamguardMVC.dataSelector.DataSelector;
|
||||
public class OverlayCheckboxMenuItem extends JCheckBoxMenuItem {
|
||||
|
||||
|
||||
public static final ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
public static final ImageIcon settingsIconNot = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
// public static final ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
// public static final ImageIcon settingsIconNot = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
|
||||
private static final FontIcon settingsIcon = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.SMALL_SIZE, Color.DARK_GRAY);
|
||||
private static final FontIcon settingsIconNot = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.SMALL_SIZE, Color.WHITE);
|
||||
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
@ -5,16 +5,11 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import PamController.PamController;
|
||||
import PamView.GeneralProjector;
|
||||
import PamView.GeneralProjector.ParameterType;
|
||||
import PamView.GeneralProjector.ParameterUnits;
|
||||
import PamView.PanelOverlayDraw;
|
||||
import PamView.symbol.PamSymbolChooser;
|
||||
import PamView.symbol.PamSymbolManager;
|
||||
import PamguardMVC.DataBlockNameComparator;
|
||||
@ -33,9 +28,12 @@ import PamguardMVC.dataSelector.DataSelector;
|
||||
*/
|
||||
public abstract class OverlayDataManager<TOverlayInfoType extends OverlayDataInfo> implements OverlayDataObserver {
|
||||
|
||||
private ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
// private ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
// private ImageIcon settingsIconNot = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
|
||||
// private static final FontIcon settingsIcon = FontIcon.of(MaterialDesignC.COG, 16, Color.DARK_GRAY);
|
||||
// private static final FontIcon settingsIconNot = FontIcon.of(MaterialDesignC.COG, 16, Color.WHITE);
|
||||
|
||||
private ImageIcon settingsIconNot = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
|
||||
private OverlaySwingPanel swingPanel;
|
||||
|
||||
|
@ -13,6 +13,8 @@ import javax.swing.JRadioButton;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.TitledBorder;
|
||||
|
||||
import PamView.PamAWTUtils;
|
||||
import PamView.PamView;
|
||||
import PamView.dialog.PamDialogPanel;
|
||||
import PamView.dialog.PamGridBagContraints;
|
||||
|
||||
@ -130,7 +132,11 @@ public class DataSelectorDialogPanel implements PamDialogPanel {
|
||||
|
||||
public void enableComponent() {
|
||||
boolean enable = !disableButton.isSelected();
|
||||
innerPanel.getDialogComponent().setEnabled(enable);
|
||||
// System.out.println("Disable!!! " + enable);
|
||||
PamAWTUtils.setPanelEnabled(innerPanel.getDialogComponent(), enable);
|
||||
|
||||
//disable in swing is not recursive
|
||||
// innerPanel.getDialogComponent().setEnabled(enable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,114 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="150mm"
|
||||
height="150mm"
|
||||
viewBox="0 0 150 150"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
sodipodi:docname="logo01.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview7"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.74564394"
|
||||
inkscape:cx="379.53772"
|
||||
inkscape:cy="512.97943"
|
||||
inkscape:window-width="1242"
|
||||
inkscape:window-height="1008"
|
||||
inkscape:window-x="649"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<inkscape:path-effect
|
||||
effect="bspline"
|
||||
id="path-effect3117"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
weight="33.333333"
|
||||
steps="2"
|
||||
helper_size="0"
|
||||
apply_no_weight="true"
|
||||
apply_with_weight="true"
|
||||
only_selected="false" />
|
||||
<inkscape:path-effect
|
||||
effect="bspline"
|
||||
id="path-effect3117-7"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
weight="33.333333"
|
||||
steps="2"
|
||||
helper_size="0"
|
||||
apply_no_weight="true"
|
||||
apply_with_weight="true"
|
||||
only_selected="false" />
|
||||
<inkscape:path-effect
|
||||
effect="bspline"
|
||||
id="path-effect3117-6"
|
||||
is_visible="true"
|
||||
lpeversion="1"
|
||||
weight="33.333333"
|
||||
steps="2"
|
||||
helper_size="0"
|
||||
apply_no_weight="true"
|
||||
apply_with_weight="true"
|
||||
only_selected="false" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:3.175px;fill:#000000;stroke-width:0.264583"
|
||||
x="11.709678"
|
||||
y="81.967743"
|
||||
id="text113"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan111"
|
||||
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:25.4px;font-family:Calibri;-inkscape-font-specification:'Calibri, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.264583"
|
||||
x="11.709678"
|
||||
y="81.967743"><tspan
|
||||
style="fill:#6f916f"
|
||||
id="tspan167">delphin</tspan><tspan
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:Calibri;-inkscape-font-specification:'Calibri, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#0b2817"
|
||||
id="tspan165">ID</tspan></tspan></text>
|
||||
<path
|
||||
style="fill:#6f916f;stroke-width:0.264583"
|
||||
d="m 27.322579,38.322579 6.741938,2.838712"
|
||||
id="path535" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.85;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 120.67435,61.080456 c 1.55411,1.367612 3.10801,2.735039 4.219,4.735608 1.11098,2.00057 1.77914,4.634082 1.8024,7.356282 0.0232,2.7222 -0.5983,5.53298 -1.65497,7.685367 -1.05667,2.152388 -2.5484,3.646416 -4.0401,5.140414"
|
||||
id="path3115"
|
||||
inkscape:path-effect="#path-effect3117"
|
||||
inkscape:original-d="m 120.67435,61.080456 c 1.55406,1.367671 3.10796,2.735101 4.66173,4.102301 0.66832,2.63386 1.33649,5.26737 2.00453,7.90072 -0.62143,2.81111 -1.24298,5.62189 -1.86469,8.43252 -1.49163,1.49428 -2.98336,2.98831 -4.47524,4.48213" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.85;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 115.99401,66.369877 c 0.93292,0.812059 1.86573,1.624027 2.53264,2.81193 0.66692,1.187903 1.06802,2.751664 1.08197,4.368074 0.014,1.61641 -0.35915,3.285393 -0.99347,4.563459 -0.63431,1.278066 -1.52976,2.165182 -2.42524,3.052317"
|
||||
id="path3115-4"
|
||||
inkscape:path-effect="#path-effect3117-6"
|
||||
inkscape:original-d="m 115.99401,66.369877 c 0.93289,0.81209 1.8657,1.62406 2.79841,2.43588 0.4012,1.56394 0.8023,3.1277 1.20331,4.69134 -0.37304,1.66922 -0.74616,3.3382 -1.11936,5.00712 -0.89543,0.88729 -1.79089,1.7744 -2.68646,2.66144" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.85;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 125.65039,55.168033 c 2.46165,2.066818 4.923,4.133391 6.68278,7.156798 1.75977,3.023407 2.81814,7.003389 2.85497,11.117374 0.0368,4.113986 -0.9477,8.361845 -2.62144,11.614689 -1.67374,3.252844 -4.03659,5.51072 -6.39943,7.768583"
|
||||
id="path3115-8"
|
||||
inkscape:path-effect="#path-effect3117-7"
|
||||
inkscape:original-d="m 125.65039,55.168033 c 2.46157,2.06691 4.92292,4.133487 7.38405,6.199707 1.05862,3.980467 2.11699,7.960447 3.17515,11.940157 -0.98434,4.24836 -1.96886,8.49622 -2.95363,12.74383 -2.36272,2.2583 -4.72558,4.51617 -7.08869,6.77375" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 5.2 KiB |
@ -137,7 +137,7 @@
|
||||
*/
|
||||
/** top-left, top-right, bottom-right, and bottom-left corners, in that order. */
|
||||
.close-button-right{
|
||||
-fx-background-color: -fx-darkbackground-trans;
|
||||
-fx-background-color: -fx-darkbackground;
|
||||
-fx-background-radius: 0 10 10 0;
|
||||
-fx-border-color: transparent;
|
||||
-fx-border-radius: 0 10 10 0;
|
||||
@ -145,7 +145,7 @@
|
||||
|
||||
|
||||
.close-button-left{
|
||||
-fx-background-color: -fx-darkbackground-trans;
|
||||
-fx-background-color: -fx-darkbackground;
|
||||
-fx-background-radius: 10 0 0 10;
|
||||
-fx-border-color: transparent;
|
||||
-fx-border-radius: 10 0 0 10;
|
||||
@ -153,7 +153,7 @@
|
||||
|
||||
|
||||
.close-button-top{
|
||||
-fx-background-color: -fx-darkbackground-trans;
|
||||
-fx-background-color: -fx-darkbackground;
|
||||
-fx-background-radius: 10 10 0 0;
|
||||
-fx-border-color: transparent;
|
||||
-fx-border-radius: 10 10 0 0;
|
||||
@ -161,7 +161,7 @@
|
||||
|
||||
|
||||
.close-button-bottom{
|
||||
-fx-background-color: -fx-darkbackground-trans;
|
||||
-fx-background-color: -fx-darkbackground;
|
||||
-fx-background-radius: 0 0 10 10;
|
||||
-fx-border-color: transparent;
|
||||
-fx-border-radius: 0 0 10 10;
|
||||
|
@ -22,6 +22,9 @@ import javax.swing.JRadioButton;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignP;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import soundPlayback.PlaybackControl;
|
||||
import clickDetector.BTDisplayParameters;
|
||||
import clickDetector.ClickBTDisplay;
|
||||
@ -29,6 +32,7 @@ import clickDetector.ClickControl;
|
||||
import clickDetector.ClickDisplay;
|
||||
import clickDetector.ClickClassifiers.ClickIdentifier;
|
||||
import PamView.PamToolBar;
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
import PamView.dialog.PamCheckBox;
|
||||
import PamView.dialog.PamLabel;
|
||||
import PamView.dialog.PamRadioButton;
|
||||
@ -75,14 +79,16 @@ public class OfflineToolbar {
|
||||
toolBar = new PamToolBar("Offline Click Analysis");
|
||||
|
||||
if (isViewer) {
|
||||
playClicks = new JButton(new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/clickPlayStart.png")));
|
||||
|
||||
// private static final FontIcon settings = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.SMALL_SIZE, Color.WHITE);
|
||||
|
||||
playClicks = new JButton(FontIcon.of(MaterialDesignP.PLAY_CIRCLE_OUTLINE, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY));
|
||||
playClicks.addActionListener(new PlayClicks());
|
||||
playClicks.setToolTipText("Play clicks (pack empty space with 0's)");
|
||||
PlaybackControl.registerPlayButton(playClicks);
|
||||
|
||||
reAnalyseClicks = new JButton(new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/reanalyseClicks.png")));
|
||||
.getSystemResource("Resources/reanalyseClicks.png")));
|
||||
reAnalyseClicks.addActionListener(new ReanalyseClicks());
|
||||
reAnalyseClicks.setToolTipText("Re-analyse clicks");
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class CTMSettingsPanel extends TMSettingsPanel {
|
||||
*/
|
||||
private void setPanelEnabled(boolean enable) {
|
||||
PamAWTUtils.setPanelEnabled(getFilterPanel(), enable);
|
||||
PamAWTUtils.setPanelEnabled(getLocPanel(), enable);
|
||||
PamAWTUtils.setPanelEnabled(getLocPanel(), enable);
|
||||
}
|
||||
|
||||
|
||||
|
@ -649,6 +649,8 @@ public class ModuleConnectionNode extends StandardConnectionNode implements PAMC
|
||||
|
||||
}
|
||||
|
||||
System.out.println("Add module: " + pamControlledUnit.getUnitName() + " " + pamControlledUnit.getPamModuleInfo());
|
||||
|
||||
if (pamControlledUnit.getPamModuleInfo()!=null) {
|
||||
Node icon = ModuleIconFactory.getInstance().
|
||||
getModuleNode(pamControlledUnit.getPamModuleInfo().getClassName());
|
||||
|
@ -132,6 +132,7 @@ public class ModuleIconFactory {
|
||||
break;
|
||||
case TETHYS:
|
||||
iconNode = PamGlyphDude.createModuleIcon("file-codemeta");
|
||||
System.out.println("Get module Tethys " + iconNode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -215,7 +216,6 @@ public class ModuleIconFactory {
|
||||
* @return the module icon enum
|
||||
*/
|
||||
public ModuleIcon getModuleIcon(String className) {
|
||||
// System.out.println("Get module icon: " + className);
|
||||
ModuleIcon icon = null;
|
||||
switch (className) {
|
||||
case "Acquisition.AcquisitionControl":
|
||||
@ -270,10 +270,12 @@ public class ModuleIconFactory {
|
||||
case "cpod.CPODControl2":
|
||||
icon=ModuleIcon.CPOD;
|
||||
break;
|
||||
case "MetaDataControl":
|
||||
case "Meta Data":
|
||||
icon = ModuleIcon.TETHYS;
|
||||
break;
|
||||
}
|
||||
System.out.println("Get module icon: " + className + " icon " + icon);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,10 @@ import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
import PamView.dialog.PamButtonAlpha;
|
||||
import PamView.dialog.PamDialog;
|
||||
import PamView.hidingpanel.TabbedHidingPane;
|
||||
@ -25,8 +29,11 @@ public class CompoundHidingTabPane extends TabbedHidingPane{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final ImageIcon settingsImage=new ImageIcon(ClassLoader
|
||||
.getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
// public static final ImageIcon settingsImage=new ImageIcon(ClassLoader
|
||||
// .getSystemResource("Resources/SettingsButtonSmallWhite.png"));
|
||||
|
||||
public static final FontIcon settingsImage = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.SMALL_SIZE, Color.WHITE);
|
||||
|
||||
|
||||
|
||||
public CompoundHidingTabPane() {
|
||||
|
@ -114,9 +114,11 @@ public class TDControlFX extends TDControl implements UserDisplayNodeFX {
|
||||
ArrayList<PamDataBlock> dataBlocks=new ArrayList<PamDataBlock>();
|
||||
PamDataBlock dataBlock=this.tdDisplayController.getUserDisplayProcess().getParentDataBlock();
|
||||
if (TDDataProviderRegisterFX.getInstance().findDataProvider(dataBlock)!=null) dataBlocks.add(dataBlock);
|
||||
if (dataBlock!=null) System.out.println("TDControldFX: parent datablock "+dataBlock.getDataName());
|
||||
if (dataBlock!=null) {
|
||||
// System.out.println("TDControldFX: parent datablock "+dataBlock.getDataName());
|
||||
}
|
||||
else{
|
||||
System.out.println("TDControldFX: parent datablock null");
|
||||
// System.out.println("TDControldFX: parent datablock null");
|
||||
return dataBlocks;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ public abstract class GenericLinePlotInfo extends TDDataInfoFX {
|
||||
|
||||
double[][] detData = getDetData(pamDataUnit);
|
||||
|
||||
if (lastUnits[chan]==null && detData!=null) {
|
||||
if ((lastUnits[chan]==null || lastUnits[chan].length<1) && detData!=null) {
|
||||
//System.out.println("lastUnits: " + lastUnits);
|
||||
//create the array of last units.
|
||||
lastUnits[chan] = new Point2D[detData.length];
|
||||
|
@ -252,10 +252,11 @@ public class TDDisplayFX extends PamBorderPane {
|
||||
//create the button which shows the hiding panel. Although we get this button from the hiding pane, where to place
|
||||
//it and what colour it is etc has to be set for whatever pane it is to be located in.
|
||||
showButton=hidingControlPane.getShowButton();
|
||||
showButton.getStyleClass().add("transparent-button-square");
|
||||
showButton.setStyle("-fx-background-radius: 0 0 10 10;");
|
||||
hidingControlPane.setShowButtonOpacity(1.0);
|
||||
// showButton.getStyleClass().add("transparent-button-square");
|
||||
showButton.setStyle("-fx-background-radius: 0 0 10 0;");
|
||||
showButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-down", PamGuiManagerFX.iconSize));
|
||||
showButton.setPrefWidth(60);
|
||||
showButton.setPrefWidth(30);
|
||||
showButton.setMaxHeight(timeAxisSize-20);
|
||||
|
||||
//create the time axis for the display.
|
||||
@ -276,7 +277,7 @@ public class TDDisplayFX extends PamBorderPane {
|
||||
StackPane mainGraphPane=new StackPane();
|
||||
mainGraphPane.getChildren().add(splitPaneHolder);
|
||||
mainGraphPane.getChildren().add(showButton);
|
||||
StackPane.setAlignment(showButton, Pos.TOP_CENTER);
|
||||
StackPane.setAlignment(showButton, Pos.TOP_LEFT);
|
||||
|
||||
this.setCenter(mainGraphPane);
|
||||
|
||||
|
@ -58,7 +58,7 @@ public class MLExportOverlayMenu extends ExportOverlayMenu {
|
||||
buttonNode = createButton();
|
||||
|
||||
defaultPath=FileSystemView.getFileSystemView().getDefaultDirectory().getPath();
|
||||
defaultPath=defaultPath + "/Pamguard Manual Export";
|
||||
defaultPath=defaultPath + File.separator + "Pamguard Manual Export";
|
||||
|
||||
currentFolder=defaultPath;
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class RExportOverlayMenu extends ExportOverlayMenu {
|
||||
buttonNode = createButton();
|
||||
|
||||
defaultPath=FileSystemView.getFileSystemView().getDefaultDirectory().getPath();
|
||||
defaultPath=defaultPath + "/Pamguard Manual Export";
|
||||
defaultPath=defaultPath + File.separator + "Pamguard Manual Export";
|
||||
|
||||
currentFolder=defaultPath;
|
||||
|
||||
@ -113,8 +113,8 @@ public class RExportOverlayMenu extends ExportOverlayMenu {
|
||||
dataUnits.add(fnDataUnit);
|
||||
}
|
||||
|
||||
RData mlData=rExportManger.dataUnits2R(dataUnits);
|
||||
if (mlData==null ){
|
||||
RData rData=rExportManger.dataUnits2R(dataUnits);
|
||||
if (rData==null ){
|
||||
//do nothing
|
||||
System.out.println("rOverlayMenu: no data units were converted to structs");
|
||||
}
|
||||
@ -134,12 +134,12 @@ public class RExportOverlayMenu extends ExportOverlayMenu {
|
||||
long millisStart=foundDataUnits.getFirstTimeMillis();
|
||||
String currentPath = PamCalendar.formatFileDateTime(millisStart, false);
|
||||
//add data types to the filen,ae
|
||||
for (int i=0 ;i<mlData.rData.length(); i++ ){
|
||||
currentPath=currentPath + "_" + mlData.dataUnitTypes.get(i);
|
||||
for (int i=0 ;i<rData.dataUnitTypes.size(); i++ ){
|
||||
currentPath=currentPath + "_" + rData.dataUnitTypes.get(i);
|
||||
}
|
||||
//add correct file type.
|
||||
currentPath = currentPath + ".RData";
|
||||
currentPath = currentFolder+"/"+currentPath;
|
||||
currentPath = currentFolder+ File.separator+currentPath;
|
||||
|
||||
//now write the file
|
||||
try {
|
||||
@ -155,7 +155,7 @@ public class RExportOverlayMenu extends ExportOverlayMenu {
|
||||
FileOutputStream fos = new FileOutputStream(currentPath);
|
||||
GZIPOutputStream zos = new GZIPOutputStream(fos);
|
||||
RDataWriter writer = new RDataWriter(context, zos);
|
||||
writer.save(mlData.rData.build());
|
||||
writer.save(rData.rData.build());
|
||||
zos.close();
|
||||
writer.close();
|
||||
super.showConfirmOverlay(currentPath, "R");
|
||||
|
@ -184,6 +184,29 @@ public class WhistlePlotInfoFX extends TDDataInfoFX {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a whistle fragment.
|
||||
* @param pamDataUnit - the PAM data unit
|
||||
* @param g - the graphics handle
|
||||
* @param windowRect - window describing window pixel dimensions to draw on
|
||||
* @param orientation - orientation
|
||||
* @param tdprojector - projector which converts pixels to time, frequency and vice versa.
|
||||
* @param scrollStart - the scroll start
|
||||
* @param type - type flag for plotting
|
||||
* @param wmControl
|
||||
* @param fftLength - the FFT length in samples
|
||||
* @param fftHop - the FFT hop in samples
|
||||
* @param sampleRate - the sample rate in samples per second
|
||||
* @param fillCol - the fill colour
|
||||
* @param linCol - the line colour.
|
||||
* @param useKhz - true to pot with kHz instead of Hz
|
||||
* @return a 2D path in pixels of the fragment.
|
||||
*/
|
||||
public static Path2D drawWhistleFragement(PamDataUnit pamDataUnit, WhistleMoanControl wmControl, int fftLength, int fftHop, float sampleRate,
|
||||
GraphicsContext g, TimeProjectorFX tdprojector, double scrollStart, int type, Color fillCol, Color linCol, Orientation orientation) {
|
||||
return WhistlePlotInfoFX.drawWhistleFragement(pamDataUnit, wmControl, fftLength, fftHop, sampleRate, g, tdprojector, scrollStart, type, fillCol, linCol, false, orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a whistle fragment.
|
||||
@ -200,10 +223,11 @@ public class WhistlePlotInfoFX extends TDDataInfoFX {
|
||||
* @param sampleRate - the sample rate in samples per second
|
||||
* @param fillCol - the fill colour
|
||||
* @param linCol - the line colour.
|
||||
* @param useKhz - true to pot with kHz instead of Hz
|
||||
* @return a 2D path in pixels of the fragment.
|
||||
*/
|
||||
public static Path2D drawWhistleFragement(PamDataUnit pamDataUnit, WhistleMoanControl wmControl, int fftLength, int fftHop, float sampleRate,
|
||||
GraphicsContext g, TimeProjectorFX tdprojector, double scrollStart, int type, Color fillCol, Color linCol, Orientation orientation) {
|
||||
GraphicsContext g, TimeProjectorFX tdprojector, double scrollStart, int type, Color fillCol, Color linCol, boolean useKhz, Orientation orientation) {
|
||||
|
||||
//get position on time axis
|
||||
long timeMillis=pamDataUnit.getTimeMilliseconds();
|
||||
@ -275,7 +299,9 @@ public class WhistlePlotInfoFX extends TDDataInfoFX {
|
||||
sliceMillis += timeMillis;
|
||||
slicePeaks = sliceData.getnPeaks();
|
||||
|
||||
|
||||
tC=tdprojector.getTimePix((long) (sliceMillis-scrollStart));
|
||||
|
||||
if (tC < 0 || tC > tdprojector.getGraphTimePixels()) {
|
||||
return null;
|
||||
}
|
||||
@ -305,6 +331,7 @@ public class WhistlePlotInfoFX extends TDDataInfoFX {
|
||||
}
|
||||
lastPeak = prevSlice.getPeakInfo()[lastPeakNum];
|
||||
f2 = thisPeak[1] * sampleRate / fftLength;
|
||||
if (useKhz) f2=f2/1000.;
|
||||
|
||||
pt2 = new Point2D(tC, tdprojector.getCoord3d(0,f2,0).getCoordinate(1));
|
||||
|
||||
@ -315,9 +342,10 @@ public class WhistlePlotInfoFX extends TDDataInfoFX {
|
||||
awtPath.lineTo(pt2.getX(), pt2.getY());
|
||||
}
|
||||
pathCount++;
|
||||
// System.out.println("yAxis: "+ tdprojector.getCoord3d(0,f2,0).getCoordinate(1)+ " f2: " +f2 + " max val: "+yAxis.getMaxVal()+" "+frequencyInfo.getUnitDivisor());
|
||||
// System.out.println("yAxis: "+ tdprojector.getCoord3d(0,f2,0).getCoordinate(1)+ " f2: " +f2 ); //+yAxis.getMaxVal()+" "+frequencyInfo.getUnitDivisor());
|
||||
|
||||
f1=lastPeak[1] * sampleRate / fftLength;
|
||||
if (useKhz) f1=f1/1000.;
|
||||
|
||||
pt1 = new Point2D(prevtC,tdprojector.getCoord3d(0,f1,0).getCoordinate(1));
|
||||
|
||||
@ -332,9 +360,10 @@ public class WhistlePlotInfoFX extends TDDataInfoFX {
|
||||
pt2 = new Point2D(tC, tdprojector.getCoord3d(0,f2,0).getCoordinate(1));
|
||||
|
||||
f1=lastPeak[0] * sampleRate / fftLength;
|
||||
if (useKhz) f1=f1/1000.;
|
||||
|
||||
pt1 = new Point2D(prevtC, tdprojector.getCoord3d(0,f1,0).getCoordinate(1));
|
||||
|
||||
|
||||
drawWhistleSegment( g, orientation, prevSliceX, pt1.getY(), sliceX, pt2.getY());
|
||||
|
||||
minX = Math.min(minX, pt1.getX());
|
||||
@ -347,10 +376,13 @@ public class WhistlePlotInfoFX extends TDDataInfoFX {
|
||||
maxY = Math.max(maxY, pt2.getY());
|
||||
|
||||
f2=thisPeak[2] * sampleRate / fftLength;
|
||||
if (useKhz) f2=f2/1000.;
|
||||
|
||||
pt2 = new Point2D(tC, tdprojector.getCoord3d(0,f2,0).getCoordinate(1));
|
||||
|
||||
f1=lastPeak[2] * sampleRate / fftLength;
|
||||
if (useKhz) f1=f1/1000.;
|
||||
|
||||
pt1 = new Point2D(prevtC, tdprojector.getCoord3d(0,f1,0).getCoordinate(1));
|
||||
|
||||
drawWhistleSegment( g, orientation, prevSliceX, pt1.getY(), sliceX, pt2.getY());
|
||||
|
@ -18,20 +18,25 @@ import javafx.geometry.Pos;
|
||||
import javafx.geometry.Side;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.control.TabPane.TabClosingPolicy;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
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.PamStackPane;
|
||||
import pamViewFX.fxNodes.PamTabPane;
|
||||
import pamViewFX.fxNodes.hidingPane.HidingPane;
|
||||
import pamViewFX.fxNodes.utilityPanes.PamToggleSwitch;
|
||||
import pamViewFX.fxStyles.PamStylesManagerFX;
|
||||
|
||||
/**
|
||||
@ -113,8 +118,17 @@ public class DetectionGroupDisplay extends PamBorderPane {
|
||||
/**
|
||||
* Hiding pane for the plot settings.
|
||||
*/
|
||||
private HidingPane hidingPane;
|
||||
|
||||
private HidingPane hidingPane;
|
||||
|
||||
/**
|
||||
* Flag for how the deteciton plot is laid out.
|
||||
*/
|
||||
private int layoutType = DISPLAY_EXTENDED;
|
||||
|
||||
/**
|
||||
* Toggle switch for showing the scroll pane.
|
||||
*/
|
||||
private PamToggleSwitch showScrollSwitch;
|
||||
|
||||
/**
|
||||
* Constructor for the detection group display.
|
||||
@ -122,6 +136,7 @@ public class DetectionGroupDisplay extends PamBorderPane {
|
||||
public DetectionGroupDisplay() {
|
||||
//create hash map to map DDDataInfos to datablocks for quick access.
|
||||
dDataInfoHashMap = new HashMap<PamDataBlock, DDDataInfo>();
|
||||
this.layoutType = DISPLAY_EXTENDED;
|
||||
createDetectionDisplay(DISPLAY_EXTENDED);
|
||||
this.setCenter(detectionDisplayHolder);
|
||||
}
|
||||
@ -131,9 +146,11 @@ public class DetectionGroupDisplay extends PamBorderPane {
|
||||
* @param layoutType - the layout of the display - e.g. DetectionGroupDisplay.DISPLAY_COMPACT
|
||||
*/
|
||||
public DetectionGroupDisplay(int layoutType) {
|
||||
this.layoutType = layoutType;
|
||||
|
||||
//create hash map to map DDDataInfos to datablocks for quick access.
|
||||
dDataInfoHashMap = new HashMap<PamDataBlock, DDDataInfo>();
|
||||
createDetectionDisplay(DISPLAY_COMPACT);
|
||||
createDetectionDisplay(layoutType);
|
||||
this.setCenter(detectionDisplayHolder);
|
||||
}
|
||||
|
||||
@ -201,6 +218,7 @@ public class DetectionGroupDisplay extends PamBorderPane {
|
||||
|
||||
hidingPane.getShowButton().setGraphic(PamGlyphDude.createPamIcon("mdi2c-cog",
|
||||
PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
hidingPane.setShowButtonOpacity(1.0); //don't want show button to gray out if mouse not over it
|
||||
this.setRight(hidingPane); //bit of a hack but works.
|
||||
hidingPane.showHidePane(false);
|
||||
|
||||
@ -219,36 +237,68 @@ public class DetectionGroupDisplay extends PamBorderPane {
|
||||
detectionDisplayHolder = new PamStackPane();
|
||||
|
||||
PamTabPane settingsPane = new PamTabPane();
|
||||
settingsPane.setTabMinHeight(60);
|
||||
settingsPane.setMinHeight(60);
|
||||
// settingsPane.repackTabs();
|
||||
|
||||
//this has to be before removing the heading button
|
||||
settingsPane.setAddTabButton(false);
|
||||
settingsPane.setTabMinHeight(60);
|
||||
settingsPane.setMinHeight(100);
|
||||
|
||||
// settingsPane.getStyleClass().add(Styles.TABS_FLOATING);
|
||||
settingsPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
|
||||
//settingsPane.getStylesheets().addAll(PamStylesManagerFX.getPamStylesManagerFX().getCurStyle().getSlidingDialogCSS());
|
||||
|
||||
Tab dataTab = new Tab("Data",detectionDisplay.getDataTypePane());
|
||||
Tab settingsTab = new Tab("Settings -BLAH",detectionDisplay.getSettingsHolder());
|
||||
PamGridPane gridPane = new PamGridPane();
|
||||
gridPane.setHgap(5.);
|
||||
gridPane.setVgap(5.);
|
||||
gridPane.setPadding(new Insets(0,0,0,5));
|
||||
|
||||
gridPane.add(new Label("Plot type"), 0, 0);
|
||||
gridPane.add(detectionDisplay.getDataTypePane(), 1, 0);
|
||||
|
||||
showScrollSwitch = new PamToggleSwitch("Show scroll bar");
|
||||
showScrollSwitch.selectedProperty().addListener((obsVal, oldVal, newVal)->{
|
||||
//show or hide the scroll bar.
|
||||
this.setEnableScrollBar(newVal);
|
||||
});
|
||||
showScrollSwitch.setSelected(true);
|
||||
gridPane.add(showScrollSwitch, 0, 1);
|
||||
GridPane.setColumnSpan(showScrollSwitch, GridPane.REMAINING);
|
||||
|
||||
|
||||
Tab dataTab = new Tab("Plot",gridPane);
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane();
|
||||
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
|
||||
scrollPane.setContent(detectionDisplay.getSettingsHolder());
|
||||
Tab settingsTab = new Tab("Settings", scrollPane);
|
||||
|
||||
//here add the option to show the scroll bar or not.
|
||||
settingsPane.getTabs().add(dataTab);
|
||||
settingsPane.getTabs().add(settingsTab);
|
||||
|
||||
hidingPane = new HidingPane(Side.RIGHT, settingsPane, detectionDisplayHolder, layoutType==DISPLAY_COMPACT, 0);
|
||||
//set the hiding pane
|
||||
Node icon = PamGlyphDude.createPamIcon("mdi2c-cog", PamGuiManagerFX.iconSize);
|
||||
detectionDisplay.getPlotPane().setHidePane(new PamBorderPane(settingsPane), icon, Side.RIGHT);
|
||||
|
||||
//move the hiding pane button into the top of the tab pane - this makes best
|
||||
//use of space.
|
||||
hidingPane = detectionDisplay.getPlotPane().getHidePane(Side.RIGHT);
|
||||
|
||||
hidingPane.removeHideButton();
|
||||
hidingPane.getHideButton().setMinWidth(40);
|
||||
|
||||
settingsPane.setTabStartRegion(hidingPane.getHideButton());
|
||||
// hidingPane.getHideButton().getStyleClass().add("close-button-right-trans");
|
||||
// hidingPane.getHideButton().setStyle(" -fx-background-radius: 0 0 0 0;");
|
||||
hidingPane.setPadding(new Insets(0,0,0,0));
|
||||
|
||||
hidingPane.getHideButton().prefHeightProperty().bind(settingsPane.tabMinHeightProperty());
|
||||
|
||||
//set the show button to be slight larger
|
||||
hidingPane.getShowButton().setPrefHeight(60.);
|
||||
|
||||
//now everything to pane.
|
||||
detectionDisplayHolder.getChildren().add(detectionDisplay);
|
||||
StackPane.setAlignment(detectionDisplay, Pos.CENTER);
|
||||
|
||||
//settingsPane.setPadding(new Insets(35,0,0,0));
|
||||
|
||||
Node icon = PamGlyphDude.createPamIcon("mdi2c-cog", PamGuiManagerFX.iconSize);
|
||||
detectionDisplay.getPlotPane().setHidePane(new PamBorderPane(settingsPane), icon, Side.RIGHT);
|
||||
hidingPane.getShowButton().setPrefHeight(30);
|
||||
|
||||
}
|
||||
|
||||
//set styles
|
||||
@ -532,11 +582,23 @@ public class DetectionGroupDisplay extends PamBorderPane {
|
||||
|
||||
|
||||
/**
|
||||
* Show the scroll bar which allows the user to chnage time limits.
|
||||
* Show the scroll bar which allows the user to change time limits.
|
||||
* @param enableScrollBarPane - true to enable the time scroll bar.
|
||||
*/
|
||||
public void setEnableScrollBar(boolean enableScrollBarPane) {
|
||||
this.detectionDisplay.setEnableScrollBar(enableScrollBarPane);
|
||||
if (this.layoutType==DISPLAY_COMPACT) {
|
||||
showScrollSwitch.setSelected(enableScrollBarPane);
|
||||
}
|
||||
detectionDisplay.setEnableScrollBar(enableScrollBarPane);
|
||||
detectionDisplay.setupScrollBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the scroll bar is changing. The scroll bar allows the user to change time limits.
|
||||
* @return true if the scroll bar pane is showing.
|
||||
*/
|
||||
public boolean isEnableScrollBar() {
|
||||
return this.detectionDisplay.isEnableScrollBar();
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,8 +75,10 @@ public class DetectionGroupDisplayFX extends DetectionGroupDisplay implements U
|
||||
|
||||
@Override
|
||||
public void closeNode() {};
|
||||
|
||||
@Override
|
||||
public DetectionPlotParams getDisplayParams() {
|
||||
|
||||
return this.detectionPlotParams;
|
||||
}
|
||||
|
||||
@ -86,6 +88,8 @@ public class DetectionGroupDisplayFX extends DetectionGroupDisplay implements U
|
||||
}
|
||||
else detectionPlotParams.dataSource = null;
|
||||
|
||||
detectionPlotParams.showScrollBar = this.isEnableScrollBar();
|
||||
|
||||
if (this.internalFrame!=null) {
|
||||
//need to use the parent node because inside an internal pane.
|
||||
detectionPlotParams.positionX=internalFrame.getInternalRegion().getLayoutX();
|
||||
@ -189,6 +193,10 @@ public class DetectionGroupDisplayFX extends DetectionGroupDisplay implements U
|
||||
// System.out.println("LOAD DETECTION DISPLAY DATA SOURCE: " + settings.tabName);
|
||||
|
||||
this.detectionPlotParams = settings.clone();
|
||||
|
||||
|
||||
this.setEnableScrollBar(detectionPlotParams.showScrollBar);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -213,10 +221,9 @@ public class DetectionGroupDisplayFX extends DetectionGroupDisplay implements U
|
||||
/**
|
||||
* The extra stuff here is to make sure that the plot types for a specific detection are saved. So for example
|
||||
* if viewing click spectrum then the spectrum plot is selected whenever 1) PAMGuard is opened again or 2) switching from
|
||||
* one type of detection ot another e.g. whistle to click, then the click does nto revert to shwoing a waveform instead
|
||||
* one type of detection to another e.g. whistle to click, then the click does not revert to showing a waveform instead
|
||||
* of spectrum.
|
||||
*/
|
||||
|
||||
if (currentDetection!=null) {
|
||||
//save the current selected detection plot for the particular type of data unit.
|
||||
String detectionPlotName = this.getDetectionDisplay().getCurrentDataInfo().getCurrentDetectionPlot().getName();
|
||||
|
@ -26,8 +26,12 @@ public class DetectionPlotParams extends UserDisplayNodeParams implements Clonea
|
||||
* The data source for the detection plot.
|
||||
*/
|
||||
public String dataSource = null;
|
||||
|
||||
|
||||
/**
|
||||
* True to show the scroll bar.
|
||||
*/
|
||||
public boolean showScrollBar = true;
|
||||
|
||||
/**
|
||||
* Saves which data axis is used for which data block. The key is the data block long name and the
|
||||
* result is the name of the plot e.g. waveform. In this way users can set how they want the data plots to display
|
||||
|
@ -107,6 +107,7 @@ public class DDDataPane2 extends PamBorderPane {
|
||||
detectionPlotDisplay.setMinHidePaneHeight(ddDataInfo.getCurrentDetectionPlot().getSettingsPane().getMinHeight());
|
||||
|
||||
}
|
||||
|
||||
//don't want the hide button if there's no settings pane.
|
||||
//detectionPlotDisplay.setEnableSettingsButton(ddDataInfo.getCurrentDetectionPlot().getSettingsPane()!=null);
|
||||
|
||||
|
@ -355,16 +355,17 @@ public class DetectionPlotDisplay extends PamBorderPane {
|
||||
* the current data unit.
|
||||
*/
|
||||
public void setupScrollBar(PamDataUnit newDataUnit){
|
||||
|
||||
if (currentDataInfo!=null) {
|
||||
//important we put this here as it allows the plot to set up the scroll bar pane.
|
||||
this.currentDataInfo.setupAxis(detectionPlotProjector, newDataUnit);
|
||||
}
|
||||
|
||||
//setup the scroll bar (or not)
|
||||
if (enableScrollBar && this.detectionPlotProjector.enableScrollBar && newDataUnit!=null) {
|
||||
|
||||
this.setTop(scrollBarPane);
|
||||
|
||||
if (currentDataInfo!=null) {
|
||||
//important we put this here as it allows the plot to set up the scroll bar pane.
|
||||
this.currentDataInfo.setupAxis(detectionPlotProjector, newDataUnit);
|
||||
}
|
||||
|
||||
//System.out.println("Set min and max limits for scroll bar: " + detectionPlotProjector.getMinScrollLimit() + " " + detectionPlotProjector.getMaxScrollLimit());
|
||||
scrollBarPane.setMinVal(detectionPlotProjector.getMinScrollLimit());
|
||||
scrollBarPane.setMaxVal(detectionPlotProjector.getMaxScrollLimit());
|
||||
@ -384,6 +385,9 @@ public class DetectionPlotDisplay extends PamBorderPane {
|
||||
|
||||
}
|
||||
else {
|
||||
//need this to ensure the axis change when scroll bar is not longer displayed.
|
||||
detectionPlotProjector.setAxisMinMax(detectionPlotProjector.getMinScrollLimit(),
|
||||
detectionPlotProjector.getMaxScrollLimit(), detectionPlotProjector.getScrollAxis());
|
||||
this.setTop(null);
|
||||
}
|
||||
}
|
||||
@ -409,19 +413,25 @@ public class DetectionPlotDisplay extends PamBorderPane {
|
||||
private void drawDataUnit(PamDataUnit newDataUnit) {
|
||||
//Debug.out.println("DetectionPlotDisplay DrawDataUnit: " +newDataUnit);
|
||||
if (currentDataInfo!=null){
|
||||
|
||||
//sometimes the axis just need a little push to make sure the pane and axis object bindings have been updated
|
||||
for (int i=0; i<Side.values().length; i++) {
|
||||
dDPlotPane.getAxisPane(Side.values()[i]).layout();
|
||||
|
||||
}
|
||||
|
||||
// System.out.println("Axis Width: " + dDPlotPane.getAxisPane(Side.BOTTOM).getWidth() + " canvas width " + dDPlotPane.getPlotCanvas().getWidth());
|
||||
|
||||
|
||||
currentDataInfo.drawData(dDPlotPane.getPlotCanvas().getGraphicsContext2D(),
|
||||
new Rectangle(0,0,dDPlotPane.getPlotCanvas().getWidth(),dDPlotPane.getPlotCanvas().getHeight()),
|
||||
this.detectionPlotProjector, newDataUnit);
|
||||
}
|
||||
if (reDrawScroll) {
|
||||
setupScrollBar( newDataUnit);
|
||||
setupScrollBar(newDataUnit);
|
||||
reDrawScroll=false;
|
||||
}
|
||||
|
||||
//dDPlotPane.repaintAxis();
|
||||
}
|
||||
|
||||
@ -554,6 +564,7 @@ public class DetectionPlotDisplay extends PamBorderPane {
|
||||
*/
|
||||
public void setEnableScrollBar(boolean enableScrollBarPane) {
|
||||
enableScrollBar=enableScrollBarPane;
|
||||
this.detectionPlotProjector.enableScrollBar = enableScrollBarPane;
|
||||
setupScrollBar();
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import detectionPlotFX.plots.RawFFTPlot.FreqTimeProjector;
|
||||
import detectionPlotFX.projector.DetectionPlotProjector;
|
||||
import javafx.geometry.Side;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.control.TextFormatter.Change;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
@ -38,6 +39,12 @@ import javafx.scene.shape.Rectangle;
|
||||
*/
|
||||
public abstract class FFTPlot<D extends PamDataUnit> implements DetectionPlot<D> {
|
||||
|
||||
/**
|
||||
* Plot kHz instead of
|
||||
*/
|
||||
private static final double USE_KHZ_FREQ = 2000;
|
||||
|
||||
|
||||
/**
|
||||
* Reference to the detection plot display.
|
||||
*/
|
||||
@ -63,7 +70,7 @@ public abstract class FFTPlot<D extends PamDataUnit> implements DetectionPlot<D>
|
||||
/**
|
||||
* The FFT parameters.
|
||||
*/
|
||||
protected FFTPlotParams fftParams = new FFTPlotParams();
|
||||
protected FFTPlotParams fftParams = createPlotParams();
|
||||
|
||||
|
||||
private static DataTypeInfo dataTypeInfo = new DataTypeInfo(ParameterType.FREQUENCY, ParameterUnits.HZ);
|
||||
@ -79,6 +86,10 @@ public abstract class FFTPlot<D extends PamDataUnit> implements DetectionPlot<D>
|
||||
private FFTWriteableImage writableImage;
|
||||
|
||||
|
||||
/**
|
||||
* True if plotting as kHz instead of Hz - usually for higher frequency data greater than USE_KHZ_FREQ;
|
||||
*/
|
||||
private boolean useKHz = false;
|
||||
|
||||
public FFTPlot(DetectionPlotDisplay displayPlot, DetectionPlotProjector projector) {
|
||||
this.detectionPlotDisplay=displayPlot;
|
||||
@ -186,10 +197,11 @@ public abstract class FFTPlot<D extends PamDataUnit> implements DetectionPlot<D>
|
||||
* @param freqAxis
|
||||
*/
|
||||
public void setupFreqAxis(double minFreq, double maxFreq, DetectionPlotProjector projector) {
|
||||
if (maxFreq>2000) {
|
||||
if (maxFreq>USE_KHZ_FREQ) {
|
||||
//use kHz
|
||||
//projector.getAxis(Side.LEFT).setLabelScale(0.001);
|
||||
projector.setAxisMinMax(minFreq, maxFreq/ 1000, Side.LEFT, "Frequency (kHz)");
|
||||
this.useKHz = true;
|
||||
projector.setAxisMinMax(minFreq, maxFreq/1000., Side.LEFT, "Frequency (kHz)");
|
||||
}
|
||||
else {
|
||||
projector.setAxisMinMax(minFreq, maxFreq, Side.LEFT, "Frequency (Hz)");
|
||||
@ -407,7 +419,9 @@ public abstract class FFTPlot<D extends PamDataUnit> implements DetectionPlot<D>
|
||||
|
||||
//add settings listener to dynamic settings pane.
|
||||
setttingsPane.addSettingsListener(()->{
|
||||
settingsChanged(setttingsPane.getParams(new FFTPlotParams()));
|
||||
//this needs to be a new instance of the the FFTPlotParams or some settings don't
|
||||
//register a chnage
|
||||
settingsChanged(setttingsPane.getParams(createPlotParams() ));
|
||||
});
|
||||
|
||||
// /////////*****Test Pane*******///////////
|
||||
@ -431,6 +445,14 @@ public abstract class FFTPlot<D extends PamDataUnit> implements DetectionPlot<D>
|
||||
}
|
||||
return (Pane) setttingsPane.getContentNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create plot paramters for the FFT plot params
|
||||
* @return
|
||||
*/
|
||||
public FFTPlotParams createPlotParams() {
|
||||
return new FFTPlotParams();
|
||||
}
|
||||
|
||||
public class SimpleFFTDataUnit extends DataUnit2D<PamDataUnit,SuperDetection> {
|
||||
|
||||
@ -537,7 +559,6 @@ public abstract class FFTPlot<D extends PamDataUnit> implements DetectionPlot<D>
|
||||
* The PAM detection used for plotting
|
||||
*/
|
||||
private D pamDetection;
|
||||
|
||||
|
||||
|
||||
public FFTWriteableImage(int x, int y, FFTPlotParams fftParams, D pamDetection) {
|
||||
@ -546,9 +567,12 @@ public abstract class FFTPlot<D extends PamDataUnit> implements DetectionPlot<D>
|
||||
this.pamDetection=pamDetection;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public boolean isUseKHz() {
|
||||
return useKHz;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -349,12 +349,21 @@ public class FFTSettingsPane<D extends PamDataUnit> extends DynamicSettingsPane<
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the VBox holder. This is the main pane whihc holds the spectrogram colour settings.
|
||||
* This is the main pane which holds the spectrogram colour and FFT settings.
|
||||
* @return the VBox holder.
|
||||
*/
|
||||
public PamHBox getVBoxHolder() {
|
||||
public PamHBox getHolderPane() {
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Pane which holds the FFT Settings e.. length hop etc.
|
||||
* @return the pane with controls for FFT settings.
|
||||
*/
|
||||
public Pane getFFTPane() {
|
||||
return fftPane;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colour combo box which allows users to change the gradient colour
|
||||
|
@ -133,6 +133,7 @@ public abstract class RawFFTPlot<D extends PamDataUnit> extends FFTPlot<D> {
|
||||
reloadImage=true;
|
||||
}
|
||||
lastData=dataUnit;
|
||||
|
||||
//three threaded sequences. 1) Load the data
|
||||
//2) generate the image and 3), on the FX thread, paint the image,
|
||||
if (reloadRaw && detectionPlotDisplay.isViewer()){
|
||||
@ -142,19 +143,19 @@ public abstract class RawFFTPlot<D extends PamDataUnit> extends FFTPlot<D> {
|
||||
//Otherwise variables get cleared etc and it;s a mess
|
||||
spectrogram.checkConfig();
|
||||
|
||||
loadRawData(dataUnit, fftParams.detPadding, fftParams.plotChannel);
|
||||
loadRawData(dataUnit, fftParams.detPadding, fftParams.plotChannel);
|
||||
//rawDataOrder.startRawDataLoad(dataUnit, fftParams.detPadding, fftParams.plotChannel);
|
||||
//on a different thread which will call repaint again
|
||||
}
|
||||
else if (reloadImage && detectionPlotDisplay.isViewer()){
|
||||
// System.out.println("Load IMAGE data: seconds: " + this.rawDataOrder.getRawDataObserver().getRawData().length
|
||||
// + " for data unit: " + +dataUnit.getUID());
|
||||
System.out.println("Load IMAGE data: seconds: " + this.rawDataOrder.getRawDataObserver().getRawData().length
|
||||
+ " for data unit: " + +dataUnit.getUID());
|
||||
spectrogram.checkConfig();
|
||||
startImageLoad();
|
||||
}
|
||||
else {
|
||||
//repaint the image!!
|
||||
// System.out.println("PAINT the image for: " +dataUnit.getUID());
|
||||
System.out.println("PAINT the image for: " +dataUnit.getUID());
|
||||
if (detectionPlotDisplay.isViewer()) paintSpecImage(graphicsContext, rectangle, projector);
|
||||
paintDetections(dataUnit, graphicsContext, rectangle, projector) ;
|
||||
}
|
||||
@ -177,6 +178,8 @@ public abstract class RawFFTPlot<D extends PamDataUnit> extends FFTPlot<D> {
|
||||
// if (pamDetection != null) {
|
||||
// sR = pamDetection.getParentDataBlock().getSampleRate();
|
||||
// }
|
||||
|
||||
//TODO - need to get this working
|
||||
projector.setEnableScrollBar(false);
|
||||
|
||||
setupFreqAxis(0, sR/2, projector);
|
||||
@ -305,8 +308,8 @@ public abstract class RawFFTPlot<D extends PamDataUnit> extends FFTPlot<D> {
|
||||
*/
|
||||
protected synchronized void loadDataUnitImage(double[] rawData, float sR, int channel, long dataStart, Task task ){
|
||||
|
||||
System.out.println("RawFFTPlot: Raw data to process: " + rawData.length + " bins: FFTPlot: hop: " + fftParams.fftLength + " length: " + fftParams.fftHop
|
||||
+ " sampleRate: " + sR);
|
||||
// System.out.println("RawFFTPlot: Raw data to process: " + rawData.length + " bins: FFTPlot: hop: " + fftParams.fftLength + " length: " + fftParams.fftHop
|
||||
// + " sampleRate: " + sR);
|
||||
|
||||
this.simpleFFTBlock.setFftHop(fftParams.fftHop);
|
||||
this.simpleFFTBlock.setFftLength(fftParams.fftLength);
|
||||
@ -480,11 +483,11 @@ public abstract class RawFFTPlot<D extends PamDataUnit> extends FFTPlot<D> {
|
||||
fftPlotParams.windowFunction!=this.fftParams.windowFunction ||
|
||||
fftPlotParams.normalise!=this.fftParams.normalise) {
|
||||
|
||||
// Debug.out.println("CheckSettings: Image needs relaoded: FFTLength: "
|
||||
// + (fftPlotParams.fftLength!=this.fftParams.fftLength) + " FFTHop: "
|
||||
// + (fftPlotParams.fftHop!=this.fftParams.fftHop) + " WindowFunction: "
|
||||
// + (fftPlotParams.windowFunction!=this.fftParams.windowFunction) + " Normalise: "
|
||||
// + (fftPlotParams.normalise!=this.fftParams.normalise) + " ");
|
||||
System.out.println("CheckSettings: Image needs relaoded: FFTLength: "
|
||||
+ (fftPlotParams.fftLength!=this.fftParams.fftLength) + " FFTHop: "
|
||||
+ (fftPlotParams.fftHop!=this.fftParams.fftHop) + " WindowFunction: "
|
||||
+ (fftPlotParams.windowFunction!=this.fftParams.windowFunction) + " Normalise: "
|
||||
+ (fftPlotParams.normalise!=this.fftParams.normalise) + " ");
|
||||
|
||||
this.reloadImage=true;
|
||||
}
|
||||
@ -682,6 +685,8 @@ public abstract class RawFFTPlot<D extends PamDataUnit> extends FFTPlot<D> {
|
||||
|
||||
@Override
|
||||
public Coordinate3d getCoord3d(double d1, double d2, double d3) {
|
||||
// PamAxisFX axis = projector.getAxis(Side.LEFT);
|
||||
// System.out.println("d2 : " + d2 + " minmax: " + axis.getMinVal() + " " + axis.getMaxVal());
|
||||
return projector.getCoord3d(d1,d2,d3);
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ public class DetectionPlotProjector extends GeneralProjector<Coordinate3d> {
|
||||
/**
|
||||
* True to enable the scroll bar.
|
||||
*/
|
||||
public boolean enableScrollBar = false;
|
||||
public boolean enableScrollBar = true;
|
||||
|
||||
/**
|
||||
* Projector for the ddPlotPane.
|
||||
|
@ -1,22 +1,21 @@
|
||||
package detectionPlotFX.whistleDDPlot;
|
||||
|
||||
import PamguardMVC.debug.Debug;
|
||||
import dataPlotsFX.whistlePlotFX.WhistlePlotInfoFX;
|
||||
import detectionPlotFX.layout.DetectionPlotDisplay;
|
||||
import detectionPlotFX.plots.RawFFTPlot;
|
||||
import detectionPlotFX.plots.FFTPlotParams;
|
||||
import detectionPlotFX.plots.FFTSettingsPane;
|
||||
import detectionPlotFX.plots.RawFFTPlot;
|
||||
import detectionPlotFX.projector.DetectionPlotProjector;
|
||||
import javafx.geometry.Orientation;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import pamViewFX.fxNodes.pamAxis.PamAxisFX;
|
||||
import whistlesAndMoans.ConnectedRegionDataUnit;
|
||||
import whistlesAndMoans.WhistleMoanControl;
|
||||
|
||||
/**
|
||||
* Plots a whistle contour over.
|
||||
* Plots a whistle contour over a spectrgram if one is available.
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
@ -27,21 +26,6 @@ public class WhistleFFTPlot extends RawFFTPlot<ConnectedRegionDataUnit> {
|
||||
*/
|
||||
private WhistleMoanControl whistleMoanControl;
|
||||
|
||||
/**
|
||||
* Line colour
|
||||
*/
|
||||
private Color lineColor=Color.BLACK;
|
||||
|
||||
/**
|
||||
* The fill colour
|
||||
*/
|
||||
private Color fillColor=Color.BLACK;
|
||||
|
||||
/**
|
||||
* The whislte settings pane.
|
||||
*/
|
||||
private WhistleSettingsPane setttingsPane;
|
||||
|
||||
/**
|
||||
* The whistle FFT plot
|
||||
* @param displayPlot - the display plot.
|
||||
@ -56,7 +40,9 @@ public class WhistleFFTPlot extends RawFFTPlot<ConnectedRegionDataUnit> {
|
||||
public void paintDetections(ConnectedRegionDataUnit whistleDataUnit,
|
||||
GraphicsContext graphicsContext, Rectangle windowRect, DetectionPlotProjector projector) {
|
||||
|
||||
// Debug.out.println("Draw whistle fragment: " + whistleDataUnit + " sR: "+ whistleDataUnit.getParentDataBlock().getSampleRate() + " Scroll start: " + getScrollStart());
|
||||
|
||||
// System.out.println("Draw whistle fragment: " + whistleDataUnit + " sR: "+ whistleDataUnit.getParentDataBlock().getSampleRate() + " Scroll start: " + getScrollStart());
|
||||
|
||||
WhistlePlotInfoFX.drawWhistleFragement(whistleDataUnit,
|
||||
whistleMoanControl,
|
||||
//need to have fft which was used in making the detections
|
||||
@ -64,20 +50,23 @@ public class WhistleFFTPlot extends RawFFTPlot<ConnectedRegionDataUnit> {
|
||||
whistleMoanControl.getWhistleToneProcess().getOutputData().getFftHop(),
|
||||
whistleDataUnit.getParentDataBlock().getSampleRate(), //need to use this because FFT sample rate can be unreliable
|
||||
graphicsContext,
|
||||
super.getProjector(), getScrollStart(), 0, fillColor, lineColor, Orientation.HORIZONTAL);
|
||||
super.getProjector(), getScrollStart(), 0, getContourColor(), getContourColor(), this.isUseKHz(), Orientation.HORIZONTAL);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pane getSettingsPane() {
|
||||
return super.getSettingsPane();
|
||||
// if (setttingsPane==null){
|
||||
// setttingsPane= new WhistleSettingsPane(whistleMoanControl, this);
|
||||
// setttingsPane.setParams(super.getFFTParams()) ;
|
||||
// }
|
||||
// return (Pane) setttingsPane.getContentNode();
|
||||
private Color getContourColor() {
|
||||
return ((WhistlePlotParams) this.getFFTParams()).contourColor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FFTSettingsPane<?> createSettingsPane(){
|
||||
return new WhistleSettingsPane(null, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FFTPlotParams createPlotParams() {
|
||||
return new WhistlePlotParams();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
13
src/detectionPlotFX/whistleDDPlot/WhistlePlotParams.java
Normal file
13
src/detectionPlotFX/whistleDDPlot/WhistlePlotParams.java
Normal file
@ -0,0 +1,13 @@
|
||||
package detectionPlotFX.whistleDDPlot;
|
||||
|
||||
|
||||
import detectionPlotFX.plots.FFTPlotParams;
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
public class WhistlePlotParams extends FFTPlotParams {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
Color contourColor = Color.GRAY;
|
||||
|
||||
}
|
@ -1,21 +1,11 @@
|
||||
package detectionPlotFX.whistleDDPlot;
|
||||
|
||||
import detectionPlotFX.plots.RawFFTPlot;
|
||||
import detectionPlotFX.plots.FFTPlotParams;
|
||||
import detectionPlotFX.plots.FFTSettingsPane;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.ColorPicker;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.control.Spinner;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.Pane;
|
||||
import pamViewFX.PamGuiManagerFX;
|
||||
import pamViewFX.fxGlyphs.PamGlyphDude;
|
||||
import pamViewFX.fxNodes.PamButton;
|
||||
import pamViewFX.fxNodes.PamHBox;
|
||||
import pamViewFX.fxNodes.PamSpinner;
|
||||
import pamViewFX.fxNodes.PamVBox;
|
||||
import whistlesAndMoans.ConnectedRegionDataUnit;
|
||||
|
||||
@ -27,24 +17,18 @@ import whistlesAndMoans.ConnectedRegionDataUnit;
|
||||
*/
|
||||
public class WhistleSettingsPane extends FFTSettingsPane<ConnectedRegionDataUnit> {
|
||||
|
||||
//TODO - neeed to complete this class;
|
||||
//TODO - need to complete this class;
|
||||
|
||||
/**
|
||||
* Allows fragments colours.
|
||||
*/
|
||||
private ColorPicker colorPicker;
|
||||
|
||||
/**
|
||||
* The time buffer control. Controls the time shown before and after the whislte.
|
||||
*/
|
||||
private PamSpinner<Double> timeBuffer;
|
||||
|
||||
private PamSpinner<Integer> fftSpinnerLength;
|
||||
|
||||
|
||||
public WhistleSettingsPane(Object owner, RawFFTPlot<?> fftPlot) {
|
||||
super(owner, fftPlot);
|
||||
//add whistle fragment to bottom;
|
||||
//super.getVBoxHolder().getChildren().add(createWhistlePane());
|
||||
super.getFFTPane().getChildren().add(createWhistlePane());
|
||||
}
|
||||
|
||||
|
||||
@ -54,55 +38,79 @@ public class WhistleSettingsPane extends FFTSettingsPane<ConnectedRegionDataUnit
|
||||
*/
|
||||
private Pane createWhistlePane(){
|
||||
|
||||
//make the colour box smaller so we can fit more stuff in.
|
||||
super.getColorBox().setPrefWidth(50);
|
||||
super.getSpectroControlPane().setPrefWidth(75);
|
||||
// //make the colour box smaller so we can fit more stuff in.
|
||||
// super.getColorBox().setPrefWidth(50);
|
||||
// super.getSpectroControlPane().setPrefWidth(75);
|
||||
|
||||
//colour picker
|
||||
Label contourColourLabel = new Label("Contour Colour");
|
||||
colorPicker = new ColorPicker();
|
||||
|
||||
//buffer
|
||||
Label timeBufferLabel = new Label("Time Buffer");
|
||||
timeBuffer = new PamSpinner<Double>(0, 500, 1, 0.2);
|
||||
timeBuffer.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
|
||||
colorPicker.valueProperty().addListener((obsval, oldVal, newVal)->{
|
||||
newSettings();
|
||||
});
|
||||
|
||||
//slider for changing the FFT length.
|
||||
Label fftSpinnerLabel = new Label("FFT Length");
|
||||
ObservableList<Integer> stepSizeListLength=FXCollections.observableArrayList();
|
||||
for (int i=2; i<15; i++){
|
||||
stepSizeListLength.add((int) Math.pow(2,i));
|
||||
}
|
||||
fftSpinnerLength=new PamSpinner<Integer>(stepSizeListLength);
|
||||
fftSpinnerLength.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
|
||||
fftSpinnerLength.setEditable(true);
|
||||
|
||||
//Slider for changing hop size
|
||||
Label windowLengthLabel = new Label("Window Length");
|
||||
PamButton pamButton = new PamButton();
|
||||
// pamButton.setGraphic(PamGlyphDude.createPamGlyph(MaterialIcon.ADJUST, PamGuiManagerFX.iconSize));
|
||||
pamButton.setGraphic(PamGlyphDude.createPamIcon("mdi2a-adjust", PamGuiManagerFX.iconSize));
|
||||
pamButton.setTooltip(new Tooltip("Optimise the window length based on the average frequency slope of the signal"));
|
||||
|
||||
PamHBox windowLengthHBox= new PamHBox(windowLengthLabel, pamButton);
|
||||
windowLengthHBox.setAlignment(Pos.CENTER_LEFT);
|
||||
windowLengthHBox.setSpacing(5);
|
||||
|
||||
Slider windowSizeSlider= new Slider();
|
||||
windowSizeSlider.setMax(8192);
|
||||
windowSizeSlider.setMin(8);
|
||||
|
||||
windowSizeSlider.setShowTickLabels(true);
|
||||
windowSizeSlider.setShowTickMarks(true);
|
||||
windowSizeSlider.setMajorTickUnit(1024);
|
||||
windowSizeSlider.setMinorTickCount(0); //disable minor tick marks
|
||||
// //buffer
|
||||
// Label timeBufferLabel = new Label("Time Buffer");
|
||||
// timeBuffer = new PamSpinner<Double>(0, 500, 1, 0.2);
|
||||
// timeBuffer.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
|
||||
//
|
||||
// //slider for changing the FFT length.
|
||||
// Label fftSpinnerLabel = new Label("FFT Length");
|
||||
// ObservableList<Integer> stepSizeListLength=FXCollections.observableArrayList();
|
||||
// for (int i=2; i<15; i++){
|
||||
// stepSizeListLength.add((int) Math.pow(2,i));
|
||||
// }
|
||||
// fftSpinnerLength=new PamSpinner<Integer>(stepSizeListLength);
|
||||
// fftSpinnerLength.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
|
||||
// fftSpinnerLength.setEditable(true);
|
||||
//
|
||||
// //Slider for changing hop size
|
||||
// Label windowLengthLabel = new Label("Window Length");
|
||||
// PamButton pamButton = new PamButton();
|
||||
//// pamButton.setGraphic(PamGlyphDude.createPamGlyph(MaterialIcon.ADJUST, PamGuiManagerFX.iconSize));
|
||||
// pamButton.setGraphic(PamGlyphDude.createPamIcon("mdi2a-adjust", PamGuiManagerFX.iconSize));
|
||||
// pamButton.setTooltip(new Tooltip("Optimise the window length based on the average frequency slope of the signal"));
|
||||
//
|
||||
// PamHBox windowLengthHBox= new PamHBox(windowLengthLabel, pamButton);
|
||||
// windowLengthHBox.setAlignment(Pos.CENTER_LEFT);
|
||||
// windowLengthHBox.setSpacing(5);
|
||||
//
|
||||
// Slider windowSizeSlider= new Slider();
|
||||
// windowSizeSlider.setMax(8192);
|
||||
// windowSizeSlider.setMin(8);
|
||||
//
|
||||
// windowSizeSlider.setShowTickLabels(true);
|
||||
// windowSizeSlider.setShowTickMarks(true);
|
||||
// windowSizeSlider.setMajorTickUnit(1024);
|
||||
// windowSizeSlider.setMinorTickCount(0); //disable minor tick marks
|
||||
|
||||
|
||||
PamVBox pamVBox = new PamVBox(contourColourLabel, colorPicker, timeBufferLabel, timeBuffer,
|
||||
fftSpinnerLabel, fftSpinnerLength, windowLengthHBox, windowSizeSlider);
|
||||
PamVBox pamVBox = new PamVBox(contourColourLabel, colorPicker);
|
||||
pamVBox.setSpacing(7);
|
||||
|
||||
return pamVBox;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the params from the current settings of the controls.
|
||||
* @param wignerParams - the params to set.
|
||||
* @return the new FFT parameters
|
||||
*/
|
||||
@Override
|
||||
public FFTPlotParams getParams(FFTPlotParams fftPlotParams) {
|
||||
((WhistlePlotParams) fftPlotParams).contourColor = this.colorPicker.getValue();
|
||||
return super.getParams(fftPlotParams);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setParams(FFTPlotParams input) {
|
||||
this.colorPicker.setValue(((WhistlePlotParams) input).contourColor);
|
||||
super.setParams(input);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,44 @@
|
||||
package export.CSVExport;
|
||||
|
||||
public class CSVExportManager {
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import export.PamDataUnitExporter;
|
||||
|
||||
public class CSVExportManager implements PamDataUnitExporter{
|
||||
|
||||
@Override
|
||||
public boolean hasCompatibleUnits(Class dataUnitType) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exportData(File fileName, List<PamDataUnit> dataUnits, boolean append) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileExtension() {
|
||||
return "csv";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconString() {
|
||||
return "mdi2f-file-table-outline";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "CSV Export";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ public abstract class MLDataUnitExport<T extends PamDataUnit<?, ?>> {
|
||||
double datenumMT = PamCalendar.millistoDateNum(dataUnit.getTimeMilliseconds());
|
||||
Matrix date = Mat5.newScalar(datenumMT);
|
||||
|
||||
mlStruct.set("date", date);
|
||||
mlStruct.set("date", index, date);
|
||||
|
||||
//add detection specific data
|
||||
mlStruct= addDetectionSpecificFields(mlStruct, index, dataUnit);
|
||||
|
@ -2,13 +2,21 @@ package export.MLExport;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import PamUtils.PamArrayUtils;
|
||||
import PamUtils.PamCalendar;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import export.PamDataUnitExporter;
|
||||
import us.hebi.matlab.mat.format.Mat5;
|
||||
import us.hebi.matlab.mat.format.Mat5File;
|
||||
import us.hebi.matlab.mat.format.Mat5Writer;
|
||||
import us.hebi.matlab.mat.types.Matrix;
|
||||
import us.hebi.matlab.mat.types.Sink;
|
||||
import us.hebi.matlab.mat.types.Sinks;
|
||||
@ -22,14 +30,22 @@ import us.hebi.matlab.mat.util.Casts;
|
||||
*
|
||||
*/
|
||||
public class MLDetectionsManager implements PamDataUnitExporter {
|
||||
|
||||
|
||||
public static final String extension = "mat";
|
||||
|
||||
// Creating date format
|
||||
public static SimpleDateFormat dataFormat = new SimpleDateFormat(
|
||||
"yyyyMMdd_HHmmss_SSS");
|
||||
|
||||
/**
|
||||
*
|
||||
* All the possible MLDataUnitExport export classes.
|
||||
*/
|
||||
ArrayList<MLDataUnitExport> mlDataUnitsExport = new ArrayList<MLDataUnitExport>();
|
||||
ArrayList<MLDataUnitExport> mlDataUnitsExport = new ArrayList<MLDataUnitExport>();
|
||||
|
||||
private Sink sink;
|
||||
|
||||
private File currentFile;
|
||||
|
||||
|
||||
public MLDetectionsManager(){
|
||||
@ -37,7 +53,7 @@ public class MLDetectionsManager implements PamDataUnitExporter {
|
||||
mlDataUnitsExport.add(new MLWhistleMoanExport());
|
||||
mlDataUnitsExport.add(new MLRawExport());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasCompatibleUnits(Class dataUnitType) {
|
||||
for (int i=0; i<mlDataUnitsExport.size(); i++){
|
||||
@ -54,21 +70,65 @@ public class MLDetectionsManager implements PamDataUnitExporter {
|
||||
|
||||
@Override
|
||||
public boolean exportData(File fileName, List<PamDataUnit> dataUnits, boolean append) {
|
||||
|
||||
|
||||
try {
|
||||
Mat5File matFile = Mat5.newMatFile();
|
||||
Sink sink = Sinks.newMappedFile(fileName, Casts.sint32(1000000));
|
||||
|
||||
matFile.writeTo(sink);//Streams the data into a MAT file?
|
||||
|
||||
System.out.println("Export: " + dataUnits.size() + " data units " + append);
|
||||
|
||||
if (dataUnits==null || dataUnits.size()<1) {
|
||||
//nothing to write but no error.
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Struct dataUnitsStruct = dataUnits2MAT(dataUnits);
|
||||
|
||||
// then
|
||||
PamDataUnit minByTime = PamArrayUtils.getMinTimeMillis(dataUnits);
|
||||
|
||||
//matlab struct must start with a letter.
|
||||
Date date = new Date(minByTime.getTimeMilliseconds());
|
||||
String entryName = "det_" + dataFormat.format( date);
|
||||
|
||||
//is there an existing sink? Is that sink writing to the correct file?
|
||||
if (sink==null || !fileName.equals(currentFile)) {
|
||||
|
||||
System.out.println("Export: " + dataUnitsStruct.getNumDimensions() + entryName);
|
||||
|
||||
currentFile = fileName;
|
||||
|
||||
//create the sink for the next data so it can be appended to the file.
|
||||
sink = Sinks.newStreamingFile(fileName);
|
||||
|
||||
//create the Mat File - gets all the headers right etc.
|
||||
Mat5File matFile = Mat5.newMatFile();
|
||||
matFile.addArray(entryName, dataUnitsStruct);
|
||||
// matFile.addArray("two", Mat5.newScalar(2));
|
||||
|
||||
matFile.writeTo(sink);
|
||||
|
||||
matFile.close();
|
||||
|
||||
}
|
||||
else {
|
||||
//write to the mat file without loading all contents into memory.
|
||||
Mat5Writer writer = Mat5.newWriter(sink);
|
||||
|
||||
writer
|
||||
.writeArray(entryName, dataUnitsStruct)
|
||||
.setDeflateLevel(Deflater.NO_COMPRESSION);
|
||||
// .writeArray("three", Mat5.newScalar(2));
|
||||
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,7 +154,7 @@ public class MLDetectionsManager implements PamDataUnitExporter {
|
||||
//ArrayList<ArrayList<PamDataUnit>> struct = new ArrayList<ArrayList<PamDataUnit>>();
|
||||
//if there's a mixed bunch of data units then we want separate arrays of structures. So a structure of arrays of structures.
|
||||
//so, need to sort compatible data units.
|
||||
|
||||
|
||||
Struct list = Mat5.newStruct();
|
||||
|
||||
//keep a track of the data units that have been transcribed. This means data units that are multiple types
|
||||
@ -118,25 +178,25 @@ public class MLDetectionsManager implements PamDataUnitExporter {
|
||||
|
||||
//create a structure for each type of data unit.
|
||||
Struct mlStructure= Mat5.newStruct(new int[]{n, 1});
|
||||
|
||||
|
||||
float sampleRate = -1;
|
||||
|
||||
|
||||
|
||||
n=0;
|
||||
//allocate the class now.
|
||||
for (int j=0; j<dataUnits.size(); j++){
|
||||
//check whether the same.
|
||||
if (mlDataUnitsExport.get(i).getUnitClass().isAssignableFrom(dataUnits.get(j).getClass()) && !alreadyStruct[j]) {
|
||||
|
||||
|
||||
mlStructure=mlDataUnitsExport.get(i).detectionToStruct(mlStructure, dataUnits.get(j), n);
|
||||
|
||||
|
||||
sampleRate = dataUnits.get(j).getParentDataBlock().getSampleRate();
|
||||
n++;
|
||||
alreadyStruct[j] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (n>=1) {
|
||||
if (n>0) {
|
||||
list.set(mlDataUnitsExport.get(i).getName(),mlStructure);
|
||||
list.set(mlDataUnitsExport.get(i).getName()+"_sR", Mat5.newScalar(sampleRate));
|
||||
}
|
||||
@ -161,15 +221,15 @@ public class MLDetectionsManager implements PamDataUnitExporter {
|
||||
public String getName() {
|
||||
return "MATLAB";
|
||||
}
|
||||
|
||||
|
||||
public static void main(String args[]) {
|
||||
|
||||
|
||||
String fileName = "/Users/au671271/MATLAB-Drive/MATLAB/PAMGUARD/_test/export_test.mat";
|
||||
|
||||
|
||||
try {
|
||||
Mat5File matFile = Mat5.newMatFile();
|
||||
|
||||
|
||||
|
||||
|
||||
Struct mlStruct = Mat5.newStruct(3, 1);
|
||||
Matrix triggerMap = Mat5.newScalar(Math.random());
|
||||
|
||||
@ -181,21 +241,35 @@ public class MLDetectionsManager implements PamDataUnitExporter {
|
||||
|
||||
//basic method to write to a file
|
||||
Mat5.writeToFile(matFile, fileName);
|
||||
|
||||
|
||||
// Sink sink = Sinks.newMappedFile(new File(fileName), Casts.sint32(1000000));
|
||||
//
|
||||
// matFile.writeTo(sink);
|
||||
//
|
||||
// sink.close();
|
||||
|
||||
|
||||
// Sink sink = Sinks.newMappedFile(new File(fileName), Casts.sint32(1000000));
|
||||
//
|
||||
// matFile.writeTo(sink);
|
||||
//
|
||||
// sink.close();
|
||||
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
//handled in the mian funtion
|
||||
if (sink!=null) {
|
||||
try {
|
||||
sink.close();
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -39,9 +39,9 @@ public class MLRawExport extends MLDataUnitExport<PamDataUnit>{
|
||||
Matrix angleErrors;
|
||||
if (dataUnit.getLocalisation()!=null) {
|
||||
//bearing angles
|
||||
angles = DLMatFile.array2Matrix(dataUnit.getLocalisation().getAngles());
|
||||
angles = DLMatFile.array2Matrix(dataUnit.getLocalisation().getAngles() == null ? new double[] {0.} : dataUnit.getLocalisation().getAngles());
|
||||
//angle errors
|
||||
angleErrors = DLMatFile.array2Matrix(dataUnit.getLocalisation().getAngleErrors());
|
||||
angleErrors = DLMatFile.array2Matrix(dataUnit.getLocalisation().getAngleErrors() == null ? new double[] {0.} : dataUnit.getLocalisation().getAngleErrors());
|
||||
}
|
||||
else {
|
||||
//bearing angles
|
||||
|
@ -46,5 +46,10 @@ public interface PamDataUnitExporter {
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Clsoe the exporter
|
||||
*/
|
||||
public void close();
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
package export;
|
||||
|
||||
import java.io.File;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
import PamUtils.PamCalendar;
|
||||
import PamguardMVC.PamDataBlock;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import export.CSVExport.CSVExportManager;
|
||||
import export.MLExport.MLDetectionsManager;
|
||||
import export.RExport.RExportManager;
|
||||
import export.layoutFX.ExportParams;
|
||||
@ -18,9 +21,9 @@ import export.wavExport.WavFileExportManager;
|
||||
public class PamExporterManager {
|
||||
|
||||
/**
|
||||
* The number of data units to save before saving.
|
||||
* The number of data units to save before saving. This prevents too much being stored in memory
|
||||
*/
|
||||
private static int BUFFER_SIZE = 1000;
|
||||
private static int BUFFER_SIZE = 10000;
|
||||
|
||||
/**
|
||||
* Keep the file size to around 1GB per file
|
||||
@ -47,6 +50,10 @@ public class PamExporterManager {
|
||||
* Reference to the current export paramters.
|
||||
*/
|
||||
private ExportParams exportParams = new ExportParams();
|
||||
|
||||
// Creating date format
|
||||
public static SimpleDateFormat dataFormat = new SimpleDateFormat(
|
||||
"yyyy_MM_dd_HHmmss");
|
||||
|
||||
public PamExporterManager() {
|
||||
pamExporters = new ArrayList<PamDataUnitExporter>();
|
||||
@ -55,19 +62,35 @@ public class PamExporterManager {
|
||||
pamExporters.add(new MLDetectionsManager());
|
||||
pamExporters.add(new RExportManager());
|
||||
pamExporters.add(new WavFileExportManager());
|
||||
pamExporters.add(new CSVExportManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a data unit to the export list.
|
||||
* @param force - true to force saving of data e.g. at the end of processing.
|
||||
*/
|
||||
public boolean exportDataUnit(PamDataUnit<?, ?> dataUnit) {
|
||||
public boolean exportDataUnit(PamDataUnit<?, ?> dataUnit, boolean force) {
|
||||
boolean exportOK = true;
|
||||
//if the data unit is null then save everything to the buffer.
|
||||
|
||||
|
||||
if (dataUnit==null) {
|
||||
if (force) {
|
||||
System.out.println("Write data 1!!" + dataUnitBuffer.size() );
|
||||
//finish off saving any buffered data
|
||||
exportOK = pamExporters.get(exportParams.exportChoice).exportData(currentFile, dataUnitBuffer, true);
|
||||
dataUnitBuffer.clear();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//if file is null or too large create another a file for saving.
|
||||
if (currentFile == null || isFileSizeMax(currentFile)) {
|
||||
Date date = new Date(dataUnit.getTimeMilliseconds());
|
||||
|
||||
String newFileName = "PAM_" + dataFormat.format(date);
|
||||
|
||||
//create a new file - note each exporter is responsible for closing the file after writing
|
||||
//so previous files should already be closed
|
||||
String fileName = (exportParams.folder + File.separator + PamCalendar.formatDate2(dataUnit.getTimeMilliseconds(), false)
|
||||
String fileName = (exportParams.folder + File.separator + newFileName
|
||||
+ "." + pamExporters.get(exportParams.exportChoice).getFileExtension());
|
||||
|
||||
currentFile = new File(fileName);
|
||||
@ -75,7 +98,10 @@ public class PamExporterManager {
|
||||
|
||||
dataUnitBuffer.add(dataUnit);
|
||||
|
||||
if (BUFFER_SIZE>=BUFFER_SIZE) {
|
||||
System.out.println("Write data unit " + dataUnitBuffer.size() + " to: "+ currentFile);
|
||||
|
||||
if (dataUnitBuffer.size()>=BUFFER_SIZE || force) {
|
||||
System.out.println("Write data 2!!" + dataUnitBuffer.size());
|
||||
exportOK = pamExporters.get(exportParams.exportChoice).exportData(currentFile, dataUnitBuffer, true);
|
||||
dataUnitBuffer.clear();
|
||||
}
|
||||
@ -83,6 +109,11 @@ public class PamExporterManager {
|
||||
return exportOK;
|
||||
|
||||
}
|
||||
|
||||
public void close() {
|
||||
pamExporters.get(exportParams.exportChoice).close();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the current file is greater than the maximum allowed file size.
|
||||
@ -101,6 +132,8 @@ public class PamExporterManager {
|
||||
private static double getFileSizeMegaBytes(File file) {
|
||||
return (double) file.length() / (1024 * 1024);
|
||||
}
|
||||
|
||||
|
||||
public boolean canExportDataBlock(PamDataBlock dataBlock) {
|
||||
for (PamDataUnitExporter exporter:pamExporters) {
|
||||
if (exporter.hasCompatibleUnits(dataBlock.getUnitClass())) return true;
|
||||
@ -127,5 +160,21 @@ public class PamExporterManager {
|
||||
|
||||
}
|
||||
|
||||
public void setCurrentFile(File file) {
|
||||
this.currentFile=file;
|
||||
|
||||
}
|
||||
|
||||
public ExportParams getExportParams() {
|
||||
return exportParams;
|
||||
}
|
||||
|
||||
public void setExportParams(ExportParams currentParams) {
|
||||
exportParams=currentParams;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ public class RClickExport extends RRawExport{
|
||||
|
||||
ClickDetection clickDetection = (ClickDetection) dataUnit;
|
||||
|
||||
super.addDetectionSpecificFields(rData, null, index);
|
||||
super.addDetectionSpecificFields(rData, dataUnit, index);
|
||||
|
||||
//add some basic click measurements
|
||||
rData.add("triggerMap", new DoubleArrayVector(clickDetection.getTriggerList()));
|
||||
|
@ -1,14 +1,24 @@
|
||||
package export.RExport;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.renjin.eval.Context;
|
||||
import org.renjin.primitives.io.serialization.RDataWriter;
|
||||
import org.renjin.sexp.DoubleArrayVector;
|
||||
import org.renjin.sexp.ListVector;
|
||||
import org.renjin.sexp.PairList;
|
||||
import org.renjin.sexp.PairList.Builder;
|
||||
|
||||
import PamUtils.PamArrayUtils;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import export.PamDataUnitExporter;
|
||||
import export.MLExport.MLDetectionsManager;
|
||||
|
||||
/**
|
||||
* Handles exporting pam data units into an rdata.
|
||||
@ -22,14 +32,75 @@ public class RExportManager implements PamDataUnitExporter {
|
||||
*
|
||||
* All the possible RDataUnit export classes.
|
||||
*/
|
||||
ArrayList<RDataUnitExport> mlDataUnitsExport = new ArrayList<RDataUnitExport>();
|
||||
ArrayList<RDataUnitExport> rDataExport = new ArrayList<RDataUnitExport>();
|
||||
|
||||
private File currentFileName ;
|
||||
|
||||
|
||||
private Builder allData;
|
||||
|
||||
|
||||
public RExportManager(){
|
||||
/***Add more options here to export data units****/
|
||||
mlDataUnitsExport.add(new RClickExport());
|
||||
mlDataUnitsExport.add(new RWhistleExport());
|
||||
mlDataUnitsExport.add(new RRawExport()); //should be last in case raw data holders have specific exporters
|
||||
rDataExport.add(new RClickExport());
|
||||
rDataExport.add(new RWhistleExport());
|
||||
rDataExport.add(new RRawExport()); //should be last in case raw data holders have specific exporters
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean exportData(File fileName, List<PamDataUnit> dataUnits, boolean append) {
|
||||
|
||||
/**
|
||||
* Note - there is no way to save data units to R files wothout loading the file into memory.
|
||||
* So everything is stored in memory until saved.
|
||||
*/
|
||||
// then
|
||||
PamDataUnit minByTime = PamArrayUtils.getMinTimeMillis(dataUnits);
|
||||
|
||||
//matlab struct must start with a letter.
|
||||
Date date = new Date(minByTime.getTimeMilliseconds());
|
||||
String entryName = "det_" + MLDetectionsManager.dataFormat.format( date);
|
||||
|
||||
// System.out.println("Save R data! "+ dataUnits.size());
|
||||
|
||||
// System.out.println("Export R file!!" + dataUnits.size());
|
||||
|
||||
//is there an existing writer? Is that writer writing to the correct file?
|
||||
if (allData==null || !fileName.equals(currentFileName)) {
|
||||
|
||||
if (allData!=null) {
|
||||
writeRFile();
|
||||
}
|
||||
|
||||
allData = new PairList.Builder();
|
||||
currentFileName = fileName;
|
||||
}
|
||||
|
||||
//convert the data units to R and save to the PairList builder
|
||||
dataUnits2R(dataUnits, entryName, allData);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private void writeRFile() {
|
||||
Context context = Context.newTopLevelContext();
|
||||
try {
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(currentFileName);
|
||||
GZIPOutputStream zos = new GZIPOutputStream(fos);
|
||||
|
||||
RDataWriter writer = new RDataWriter(context, zos);
|
||||
|
||||
writer.save(allData.build());
|
||||
writer.close();
|
||||
zos.close();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,70 +115,98 @@ public class RExportManager implements PamDataUnitExporter {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasCompatibleUnits(Class dataUnitType) {
|
||||
for (int i=0; i<mlDataUnitsExport.size(); i++){
|
||||
for (int i=0; i<rDataExport.size(); i++){
|
||||
//check whether the same. ;
|
||||
//System.out.println(" dataUnits.get(j).getClass(): " + dataUnits.get(j).getClass());
|
||||
//System.out.println(" mlDataUnitsExport.get(i).getUnitClass(): " + mlDataUnitsExport.get(i).getUnitClass());
|
||||
if (mlDataUnitsExport.get(i).getUnitClass().isAssignableFrom(dataUnitType)) {
|
||||
if (rDataExport.get(i).getUnitClass().isAssignableFrom(dataUnitType)) {
|
||||
//System.out.println("FOUND THE DATA UNIT!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sort a list of data units into lists of the same type of units. Convert to a list of structures.
|
||||
* @param dataUnits - a list of data units to convert to matlab structures.
|
||||
* @return list of list of R strucutures ready for saving to .RData file.
|
||||
*/
|
||||
public RData dataUnits2R(ArrayList<PamDataUnit> dataUnits){
|
||||
|
||||
public RData dataUnits2R(List<PamDataUnit> dataUnits){
|
||||
PairList.Builder allData = new PairList.Builder();
|
||||
return dataUnits2R(dataUnits, null, allData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sort a list of data units into lists of the same type of units. Convert to a list of structures.
|
||||
* @param dataUnits - a list of data units to convert to matlab structures.
|
||||
* @param - a name for the structure.
|
||||
* @return list of list of R strucutures ready for saving to .RData file.
|
||||
*/
|
||||
public RData dataUnits2R(List<PamDataUnit> dataUnits, String name, PairList.Builder allData) {
|
||||
|
||||
//if there's a mixed bunch of data units then we want separate arrays of structures. So a structure of arrays of structures.
|
||||
//so, need to sort compatible data units.
|
||||
|
||||
PairList.Builder allData = new PairList.Builder();
|
||||
|
||||
ArrayList<String> dataUnitTypes = new ArrayList<String>();
|
||||
|
||||
|
||||
//keep a track of the data units that have been transcribed. This means data units that are multiple types
|
||||
//(e.g. a raw data holder and click) are not added to two different list of structures.
|
||||
boolean[] alreadyStruct = new boolean[dataUnits.size()];
|
||||
|
||||
//iterate through possible export functions.
|
||||
for (int i=0; i<mlDataUnitsExport.size(); i++){
|
||||
|
||||
for (int i=0; i<rDataExport.size(); i++){
|
||||
|
||||
//first need to figure out how many data units there are.
|
||||
int n=0;
|
||||
for (int j=0; j<dataUnits.size(); j++){
|
||||
//check whether the same.
|
||||
if (mlDataUnitsExport.get(i).getUnitClass().isAssignableFrom(dataUnits.get(j).getClass())) {
|
||||
if (rDataExport.get(i).getUnitClass().isAssignableFrom(dataUnits.get(j).getClass())) {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (n==0) continue; //no need to do anything else. There are no data units of this type.
|
||||
|
||||
|
||||
ListVector.NamedBuilder dataListArray = new ListVector.NamedBuilder();
|
||||
|
||||
ListVector.NamedBuilder dataList;
|
||||
|
||||
n=0;
|
||||
double sampleRate = 0.;
|
||||
//allocate the class now.
|
||||
for (int j=0; j<dataUnits.size(); j++){
|
||||
//check whether the same.
|
||||
if (mlDataUnitsExport.get(i).getUnitClass().isAssignableFrom(dataUnits.get(j).getClass())) {
|
||||
dataList=mlDataUnitsExport.get(i).detectionToStruct(dataUnits.get(j), n);
|
||||
dataListArray.add((mlDataUnitsExport.get(i).getName() + "_" + dataUnits.get(j).getUID()), dataList);
|
||||
if (rDataExport.get(i).getUnitClass().isAssignableFrom(dataUnits.get(j).getClass()) && !alreadyStruct[j]) {
|
||||
dataList=rDataExport.get(i).detectionToStruct(dataUnits.get(j), n);
|
||||
dataListArray.add((rDataExport.get(i).getName() + "_" + dataUnits.get(j).getUID()), dataList);
|
||||
|
||||
sampleRate = dataUnits.get(j).getParentDataBlock().getSampleRate();
|
||||
n++;
|
||||
alreadyStruct[j] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (n>1) {
|
||||
allData.add(mlDataUnitsExport.get(i).getName(), dataListArray.build());
|
||||
dataUnitTypes.add(mlDataUnitsExport.get(i).getName());
|
||||
|
||||
if (n>0) {
|
||||
|
||||
String dataName;
|
||||
if (name==null) {
|
||||
dataName = rDataExport.get(i).getName();
|
||||
}
|
||||
else dataName = name + "_" + rDataExport.get(i).getName();
|
||||
|
||||
allData.add(dataName, dataListArray.build());
|
||||
allData.add(rDataExport.get(i).getName()+"_sR", new DoubleArrayVector(sampleRate));
|
||||
|
||||
dataUnitTypes.add(rDataExport.get(i).getName());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
RData rData = new RData();
|
||||
rData.rData=allData;
|
||||
rData.dataUnitTypes=dataUnitTypes;
|
||||
@ -115,33 +214,27 @@ public class RExportManager implements PamDataUnitExporter {
|
||||
//now ready to save.
|
||||
return rData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple class to hold RData and list of the data unit names whihc were saved.
|
||||
* @author jamie
|
||||
*
|
||||
*/
|
||||
public class RData {
|
||||
|
||||
|
||||
/**
|
||||
* The RData raedy to save
|
||||
*/
|
||||
public PairList.Builder rData;
|
||||
|
||||
|
||||
/**
|
||||
* List of the names of the types of data units whihc were saved.
|
||||
* List of the names of the types of data units which were saved.
|
||||
*/
|
||||
public ArrayList<String> dataUnitTypes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean exportData(File fileName, List<PamDataUnit> dataUnits, boolean append) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFileExtension() {
|
||||
return "RData";
|
||||
@ -157,6 +250,14 @@ public class RExportManager implements PamDataUnitExporter {
|
||||
return "R data";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (allData!=null) {
|
||||
writeRFile();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ public class RRawExport extends RDataUnitExport<PamDataUnit> {
|
||||
//time delay stuff.
|
||||
if (dataUnit.getLocalisation()!=null) {
|
||||
//bearing angles
|
||||
rData.add("angles", new DoubleArrayVector(dataUnit.getLocalisation().getAngles()));
|
||||
rData.add("angles", dataUnit.getLocalisation().getAngles() == null ? new DoubleArrayVector(0.) : new DoubleArrayVector(dataUnit.getLocalisation().getAngles()));
|
||||
//angle errors
|
||||
rData.add("angleErrors", new DoubleArrayVector(dataUnit.getLocalisation().getAngleErrors()));
|
||||
rData.add("angleErrors", dataUnit.getLocalisation().getAngleErrors() == null? new DoubleArrayVector(0.) : new DoubleArrayVector(dataUnit.getLocalisation().getAngleErrors()));
|
||||
}
|
||||
else {
|
||||
//bearing angles
|
||||
@ -73,7 +73,7 @@ public class RRawExport extends RDataUnitExport<PamDataUnit> {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "pam_data_units";
|
||||
return "raw_data_units";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ public class ExportParams implements Serializable, Cloneable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
/**
|
||||
* The index of the export choice.
|
||||
@ -25,6 +25,11 @@ public class ExportParams implements Serializable, Cloneable {
|
||||
*/
|
||||
public String folder = System.getProperty("user.home");
|
||||
|
||||
/**
|
||||
* The maximum file size in Megabytes
|
||||
*/
|
||||
public Double maximumFileSize = 1000.0;
|
||||
|
||||
@Override
|
||||
public ExportParams clone() {
|
||||
try {
|
||||
|
@ -1,6 +1,5 @@
|
||||
package export.swing;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Frame;
|
||||
@ -11,14 +10,10 @@ import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JSpinner.DefaultEditor;
|
||||
import javax.swing.JTextField;
|
||||
@ -29,13 +24,13 @@ import javax.swing.border.TitledBorder;
|
||||
|
||||
import org.kordamp.ikonli.Ikon;
|
||||
import org.kordamp.ikonli.fileicons.FileIcons;
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignA;
|
||||
import org.kordamp.ikonli.materialdesign2.MaterialDesignF;
|
||||
import org.kordamp.ikonli.swing.FontIcon;
|
||||
|
||||
import PamController.PamController;
|
||||
import PamUtils.PamFileChooser;
|
||||
import PamView.dialog.PamButton;
|
||||
import PamView.dialog.PamDialog;
|
||||
import PamView.dialog.PamGridBagContraints;
|
||||
import PamView.panel.PamPanel;
|
||||
import PamguardMVC.PamDataBlock;
|
||||
@ -43,6 +38,7 @@ import export.PamExporterManager;
|
||||
import export.layoutFX.ExportParams;
|
||||
import offlineProcessing.OLProcessDialog;
|
||||
import offlineProcessing.OfflineTaskGroup;
|
||||
import offlineProcessing.TaskStatus;
|
||||
|
||||
/**
|
||||
* Handles an offline dialog for processing offline data and exporting to bespoke file types.
|
||||
@ -150,20 +146,26 @@ public class ExportProcessDialog {
|
||||
|
||||
public ExportOLDialog(Window parentFrame, OfflineTaskGroup taskGroup, String title) {
|
||||
super(parentFrame, taskGroup, title);
|
||||
// TODO Auto-generated constructor stub
|
||||
|
||||
//remove the notes panel - don't need this for export.
|
||||
super.removeNotePanel();
|
||||
//remove delete database entried - not used.
|
||||
super.getDeleteOldDataBox().setVisible(false);
|
||||
|
||||
//construc tthe panel.
|
||||
PamPanel mainPanel = new PamPanel();
|
||||
|
||||
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
|
||||
mainPanel.setBorder(new TitledBorder("Export Settings"));
|
||||
|
||||
buttonGroup = new ButtonGroup();
|
||||
|
||||
PamPanel buttonPanel = new PamPanel();
|
||||
|
||||
|
||||
ActionListener listener = actionEvent -> {
|
||||
System.out.println(actionEvent.getActionCommand() + " Selected");
|
||||
// System.out.println(actionEvent.getActionCommand() + " Selected");
|
||||
//TODO set the buttons to be disabled or enabled.
|
||||
|
||||
enableTasks(getExportSelection());
|
||||
};
|
||||
|
||||
exportButtons = new JToggleButton[exportManager.getNumExporters()];
|
||||
@ -178,7 +180,7 @@ public class ExportProcessDialog {
|
||||
b.setIcon(icon);
|
||||
|
||||
b.addActionListener(listener);
|
||||
|
||||
|
||||
exportButtons[i]=b;
|
||||
buttonGroup.add(b);
|
||||
buttonPanel.add(b);
|
||||
@ -192,8 +194,8 @@ public class ExportProcessDialog {
|
||||
c.gridy = 0;
|
||||
|
||||
addComponent(p, exportTo = new JTextField(), c);
|
||||
exportTo.setMinimumSize(new Dimension(170, 25));
|
||||
exportTo.setPreferredSize(new Dimension(170, 25));
|
||||
exportTo.setMinimumSize(new Dimension(180, 25));
|
||||
exportTo.setPreferredSize(new Dimension(180, 25));
|
||||
|
||||
c.gridx +=3;
|
||||
c.gridwidth = 1;
|
||||
@ -216,34 +218,51 @@ public class ExportProcessDialog {
|
||||
c.gridx = 1;
|
||||
c.gridy++;
|
||||
c.gridwidth = 2;
|
||||
|
||||
|
||||
JLabel label = new JLabel("Maximum file size", SwingConstants.RIGHT);
|
||||
addComponent(p, label, c);
|
||||
|
||||
c.gridwidth = 1;
|
||||
c.gridx +=2;
|
||||
|
||||
|
||||
SpinnerListModel list = new SpinnerListModel(new Double[] {10.,30., 60., 100., 200., 300., 600., 1000.});
|
||||
|
||||
|
||||
spinner = new JSpinner(list);
|
||||
//don't want the user to to able to set values
|
||||
((DefaultEditor) spinner.getEditor()).getTextField().setEditable(false);
|
||||
spinner.setBounds(50, 80, 70, 100);
|
||||
addComponent(p, spinner, c);
|
||||
|
||||
|
||||
c.gridx ++;
|
||||
addComponent(p, new JLabel("MB"), c);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
mainPanel.add(p);
|
||||
mainPanel.add(buttonPanel);
|
||||
|
||||
//add the main panel at a different index.
|
||||
getMainPanel().add(mainPanel, 1);
|
||||
|
||||
pack();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable which task are disables and enabled.
|
||||
* @param exportSelection
|
||||
*/
|
||||
private void enableTasks(int exportSelection) {
|
||||
this.currentParams = getExportParams();
|
||||
exportManager.setExportParams(currentParams);
|
||||
// ExportTask task;
|
||||
// for (int i=0; i<this.getTaskGroup().getNTasks(); i++) {
|
||||
// task = (ExportTask) this.getTaskGroup().getTask(i);
|
||||
// }
|
||||
enableControls();
|
||||
}
|
||||
|
||||
|
||||
private Ikon getIconFromString(String iconString) {
|
||||
|
||||
@ -262,20 +281,57 @@ public class ExportProcessDialog {
|
||||
case "mdi2f-file-music":
|
||||
icon=MaterialDesignF.FILE_MUSIC;
|
||||
break;
|
||||
case "mdi2f-file-table-outline":
|
||||
icon=MaterialDesignF.FILE_TABLE_OUTLINE;
|
||||
break;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
private int getExportSelection() {
|
||||
int sel=-1;
|
||||
for (int i=0; i<exportButtons.length; i++) {
|
||||
if (this.exportButtons[i].isSelected()) {
|
||||
sel=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
|
||||
|
||||
public ExportParams getExportParams() {
|
||||
currentParams.folder = null;
|
||||
|
||||
if (exportTo.getText().length()>0) {
|
||||
|
||||
File file = new File(exportTo.getText());
|
||||
|
||||
if (!(file.exists() && file.isDirectory())) {
|
||||
currentParams.folder = null;
|
||||
}
|
||||
else {
|
||||
currentParams.folder = file.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
currentParams.exportChoice = getExportSelection();
|
||||
currentParams.maximumFileSize = (Double) spinner.getValue();
|
||||
|
||||
|
||||
return currentParams;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getParams() {
|
||||
//make sure we update the current paramters before processing starts.
|
||||
this.currentParams = getExportParams();
|
||||
exportManager.setExportParams(currentParams);
|
||||
|
||||
if (this.currentParams.folder==null) {
|
||||
return PamDialog.showWarning(super.getOwner(), "No folder or file selected", "You must select an output folder");
|
||||
}
|
||||
|
||||
|
||||
return super.getParams();
|
||||
}
|
||||
|
||||
@ -286,8 +342,14 @@ public class ExportProcessDialog {
|
||||
|
||||
buttonGroup.clearSelection();
|
||||
exportButtons[params.exportChoice].setSelected(true);
|
||||
|
||||
exportTo.setText(currentParams.folder);
|
||||
|
||||
spinner.setValue(currentParams.maximumFileSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -304,6 +366,7 @@ public class ExportProcessDialog {
|
||||
return "Export Data";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -25,12 +25,15 @@ public class ExportTask extends OfflineTask<PamDataUnit<?,?>>{
|
||||
/**
|
||||
* The data selector for the data block
|
||||
*/
|
||||
private DataSelector dataSelector;
|
||||
private DataSelector dataSelector;
|
||||
|
||||
private boolean canExport;
|
||||
|
||||
public ExportTask(PamDataBlock<PamDataUnit<?, ?>> parentDataBlock, PamExporterManager exporter) {
|
||||
super(parentDataBlock);
|
||||
this.exporter = exporter;
|
||||
dataSelector=parentDataBlock.getDataSelectCreator().getDataSelector(this.getUnitName() +"_clicks", false, null);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -41,20 +44,27 @@ public class ExportTask extends OfflineTask<PamDataUnit<?,?>>{
|
||||
|
||||
@Override
|
||||
public boolean processDataUnit(PamDataUnit<?, ?> dataUnit) {
|
||||
exporter.exportDataUnit(dataUnit);
|
||||
return true;
|
||||
if (dataSelector==null) exporter.exportDataUnit(dataUnit, false);
|
||||
else if (dataSelector.scoreData(dataUnit)>0) {
|
||||
exporter.exportDataUnit(dataUnit, false);
|
||||
}
|
||||
return false; //we don't need to indicate that anything has changed - we are just exporting.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newDataLoad(long startTime, long endTime, OfflineDataMapPoint mapPoint) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
// System.out.println("EXPORTER: new data load");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadedDataComplete() {
|
||||
//force the exporter so save any remaning data units in the buffer
|
||||
exporter.exportDataUnit(null);
|
||||
System.out.println("EXPORTER: loaded data complete");
|
||||
|
||||
//force the exporter so save any renaming data units in the buffer
|
||||
exporter.exportDataUnit(null, true);
|
||||
exporter.close();
|
||||
exporter.setCurrentFile(null);
|
||||
|
||||
}
|
||||
/**
|
||||
@ -79,4 +89,25 @@ public class ExportTask extends OfflineTask<PamDataUnit<?,?>>{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the task can export based on the current selection
|
||||
* @param exportSelection - the index of the selected exporter
|
||||
*/
|
||||
public boolean canExport(int exportSelection) {
|
||||
return exporter.getExporter(exportSelection).hasCompatibleUnits(getDataBlock().getUnitClass());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canRun() {
|
||||
boolean can = getDataBlock() != null;
|
||||
|
||||
if (can) {
|
||||
//check whether we can export based on the export selection
|
||||
can = canExport(exporter.getExportParams().exportChoice);
|
||||
}
|
||||
|
||||
return can;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public class WavFileExportManager implements PamDataUnitExporter {
|
||||
|
||||
|
||||
defaultPath=FileSystemView.getFileSystemView().getDefaultDirectory().getPath();
|
||||
defaultPath=defaultPath + "/Pamguard Manual Export";
|
||||
defaultPath=defaultPath + File.separator + "Pamguard Manual Export";
|
||||
|
||||
currentFolder=defaultPath;
|
||||
}
|
||||
@ -146,7 +146,7 @@ public class WavFileExportManager implements PamDataUnitExporter {
|
||||
|
||||
//add correct file type.
|
||||
currentPath = currentPath + ".wav";
|
||||
currentPath = currentFolder + File.pathSeparator + currentPath;
|
||||
currentPath = currentFolder + File.separator + currentPath;
|
||||
|
||||
return currentPath;
|
||||
|
||||
@ -353,8 +353,6 @@ public class WavFileExportManager implements PamDataUnitExporter {
|
||||
*/
|
||||
private int saveDataUnitWav(DetectionGroupSummary foundDataUnits) {
|
||||
//TODO - need to pad the detections...with zeros.
|
||||
|
||||
|
||||
//System.out.println("Save data unit wav: " + foundDataUnits.getNumDataUnits());
|
||||
|
||||
int n=0;
|
||||
@ -459,6 +457,14 @@ public class WavFileExportManager implements PamDataUnitExporter {
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// hello(){
|
||||
|
@ -47,20 +47,20 @@ public class FormsTabPanel implements PamTabPanel {
|
||||
// keyManager=KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||
// keyManager.addKeyEventDispatcher(new LoggerKeyEventDispatcher());
|
||||
|
||||
/** Global (OS-level) hotkey manager:
|
||||
* jnativehook supported systems: Windows, X11, MacOS
|
||||
*
|
||||
*/
|
||||
try {
|
||||
LogManager.getLogManager().reset();
|
||||
GlobalScreen.setEventDispatcher(new SwingDispatchService());
|
||||
GlobalScreen.registerNativeHook();
|
||||
GlobalScreen.addNativeKeyListener(new GlobalKeyListenerExample());
|
||||
}
|
||||
catch (NativeHookException ex) {
|
||||
System.err.println("There was a problem registering the native hook.");
|
||||
System.err.println(ex.getMessage());
|
||||
}
|
||||
// /** Global (OS-level) hotkey manager:
|
||||
// * jnativehook supported systems: Windows, X11, MacOS
|
||||
// *
|
||||
// */
|
||||
// try {
|
||||
// LogManager.getLogManager().reset();
|
||||
// GlobalScreen.setEventDispatcher(new SwingDispatchService());
|
||||
// GlobalScreen.registerNativeHook();
|
||||
// GlobalScreen.addNativeKeyListener(new GlobalKeyListenerExample());
|
||||
// }
|
||||
// catch (NativeHookException ex) {
|
||||
// System.err.println("There was a problem registering the native hook.");
|
||||
// System.err.println(ex.getMessage());
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -7,11 +7,14 @@ import java.io.Serializable;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import Array.ArrayManager;
|
||||
import PamController.PamControlledUnit;
|
||||
import PamController.PamControlledUnitSettings;
|
||||
import PamController.PamController;
|
||||
import PamController.PamGUIManager;
|
||||
import PamController.PamSettingManager;
|
||||
import PamController.PamSettings;
|
||||
import PamModel.PamModuleInfo;
|
||||
import metadata.swing.MetaDataDialog;
|
||||
|
||||
/**
|
||||
@ -44,6 +47,7 @@ public class MetaDataContol extends PamControlledUnit implements PamSettings {
|
||||
public static MetaDataContol getMetaDataControl() {
|
||||
if (singleInstance == null) {
|
||||
singleInstance = new MetaDataContol(unitType);
|
||||
singleInstance.addModuleInfo(); //needed for FX
|
||||
// add this line to add it to the main modules list. Then it will get menu's, etc.
|
||||
PamController.getInstance().addControlledUnit(singleInstance);
|
||||
}
|
||||
@ -108,6 +112,17 @@ public class MetaDataContol extends PamControlledUnit implements PamSettings {
|
||||
// send around a notification ?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add module info to the array manager. Need to do this to add icon which is used in data model.
|
||||
*/
|
||||
private void addModuleInfo(){
|
||||
//need to add module info due to fact array manager is a special case
|
||||
PamModuleInfo metaModuleInfo=new PamModuleInfo(unitType, "Handles project metadata", MetaDataContol.class);
|
||||
metaModuleInfo.setCoreModule(true);
|
||||
metaModuleInfo.addGUICompatabilityFlag(PamGUIManager.FX);
|
||||
this.setPamModuleInfo(metaModuleInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -13,7 +13,6 @@ import java.awt.event.WindowEvent;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JComboBox;
|
||||
@ -32,6 +31,7 @@ import PamUtils.PamCalendar;
|
||||
import PamUtils.TxtFileUtils;
|
||||
import PamView.CancelObserver;
|
||||
import PamView.DBTextArea;
|
||||
import PamView.component.PamSettingsIconButton;
|
||||
import PamView.dialog.PamDialog;
|
||||
import PamView.dialog.PamFileBrowser;
|
||||
import PamView.dialog.PamGridBagContraints;
|
||||
@ -39,7 +39,6 @@ import PamView.panel.PamAlignmentPanel;
|
||||
import PamView.panel.PamPanel;
|
||||
import PamView.panel.PamProgressBar;
|
||||
import PamguardMVC.PamDataBlock;
|
||||
import export.layoutFX.ExportParams;
|
||||
import offlineProcessing.logging.OldTaskData;
|
||||
import offlineProcessing.logging.TaskLogging;
|
||||
import offlineProcessing.superdet.OfflineSuperDetFilter;
|
||||
@ -95,7 +94,7 @@ public class OLProcessDialog extends PamDialog {
|
||||
|
||||
|
||||
// public static ImageIcon settings = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
|
||||
public static FontIcon settings = FontIcon.of(MaterialDesignC.COG, 20, Color.DARK_GRAY);
|
||||
public static FontIcon settings = FontIcon.of(PamSettingsIconButton.SETTINGS_IKON, PamSettingsIconButton.NORMAL_SIZE, Color.DARK_GRAY);
|
||||
|
||||
|
||||
TaskStatus currentStatus = TaskStatus.IDLE;
|
||||
@ -105,6 +104,13 @@ public class OLProcessDialog extends PamDialog {
|
||||
*/
|
||||
private JPanel mainPanel;
|
||||
|
||||
private JPanel notePanel;
|
||||
|
||||
/**
|
||||
* True if a note is required for the
|
||||
*/
|
||||
private boolean isNeedaNote = true;
|
||||
|
||||
|
||||
public OLProcessDialog(Window parentFrame, OfflineTaskGroup taskGroup, String title) {
|
||||
super(parentFrame, title, false);
|
||||
@ -165,7 +171,7 @@ public class OLProcessDialog extends PamDialog {
|
||||
c.gridy++;
|
||||
}
|
||||
|
||||
JPanel notePanel = new JPanel(new BorderLayout());
|
||||
notePanel = new JPanel(new BorderLayout());
|
||||
notePanel.setBorder(new TitledBorder("Notes"));
|
||||
noteText = new DBTextArea(2, 40, TaskLogging.TASK_NOTE_LENGTH);
|
||||
noteText.getComponent().setToolTipText("Notes to add to database record of complete tasks");
|
||||
@ -185,11 +191,14 @@ public class OLProcessDialog extends PamDialog {
|
||||
c.gridwidth = 1;
|
||||
addComponent(progressPanel, new JLabel("File ", SwingConstants.RIGHT), c);
|
||||
c.gridx++;
|
||||
c.gridwidth = 2;
|
||||
addComponent(progressPanel, loadedProgress = new PamProgressBar(0, 100), c);
|
||||
c.gridx = 0;
|
||||
c.gridy++;
|
||||
c.gridwidth = 1;
|
||||
addComponent(progressPanel, new JLabel("All Data ", SwingConstants.RIGHT), c);
|
||||
c.gridx++;
|
||||
c.gridwidth = 2;
|
||||
addComponent(progressPanel, globalProgress = new PamProgressBar(00, 100), c);
|
||||
|
||||
mainPanel.add(dataSelectPanel);
|
||||
@ -220,6 +229,15 @@ public class OLProcessDialog extends PamDialog {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the notes panel.
|
||||
*/
|
||||
public void removeNotePanel() {
|
||||
isNeedaNote = false;
|
||||
mainPanel.remove(notePanel);
|
||||
pack();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the main panel. This can be used to add additional controls if needed.
|
||||
* @return the main panel.
|
||||
@ -310,7 +328,7 @@ public class OLProcessDialog extends PamDialog {
|
||||
taskCheckBox[i].setSelected(false);
|
||||
}
|
||||
if (settingsButton[i] != null) {
|
||||
settingsButton[i].setEnabled(nr);
|
||||
settingsButton[i].setEnabled(aTask.canRun() && nr);
|
||||
}
|
||||
if (taskCheckBox[i].isSelected()) {
|
||||
selectedTasks++;
|
||||
@ -368,7 +386,7 @@ public class OLProcessDialog extends PamDialog {
|
||||
}
|
||||
|
||||
String note = noteText.getText();
|
||||
if (note == null || note.length() == 0) {
|
||||
if ((note == null || note.length() == 0) && isNeedaNote) {
|
||||
return PamDialog.showWarning(super.getOwner(), "Task note", "you must enter a note about what you are doing");
|
||||
}
|
||||
taskGroupParams.taskNote = note;
|
||||
@ -376,6 +394,7 @@ public class OLProcessDialog extends PamDialog {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void setTaskToolTips() {
|
||||
int nTasks = taskGroup.getNTasks();
|
||||
|
||||
@ -842,6 +861,24 @@ public class OLProcessDialog extends PamDialog {
|
||||
public OfflineTaskGroup getTaskGroup() {
|
||||
return this.taskGroup;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a note is required.
|
||||
* @return true if a note is required.
|
||||
*/
|
||||
public boolean isNeedaNote() {
|
||||
return isNeedaNote;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether a note is required before processing
|
||||
* @param isNeedaNote - true to require user to input a note.
|
||||
*/
|
||||
public void setNeedaNote(boolean isNeedaNote) {
|
||||
this.isNeedaNote = isNeedaNote;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -166,6 +166,8 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
|
||||
sidePaneContent.setPadding(new Insets(25,5,5,5)); //give quite abit of spacing at the top so that there is room for close button
|
||||
sidePaneContent.setMinWidth(0);
|
||||
hidingSidePane=new HidingPane(Side.RIGHT, sidePaneContent, this, false);
|
||||
hidingSidePane.setShowButtonOpacity(1.0);
|
||||
|
||||
hidingSidePane.showHidePane(false);
|
||||
|
||||
//create the button which shows the hiding panel. Although we get this button from the hiding pane, where to place
|
||||
@ -242,6 +244,7 @@ public class PamGuiFX extends StackPane implements PamViewInterface {
|
||||
|
||||
mainTabPane.setTabEndRegion(showButtonRight);
|
||||
mainTabPane.setTabStartRegion(showButtonLeft);
|
||||
// mainTabPane.getStyleClass().add(Styles.TABS_FLOATING);
|
||||
|
||||
mainTabPane.getAddTabButton().setOnAction((value)->{
|
||||
addPamTab(new TabInfo("Display " + (this.getNumTabs()+1)), null ,true);
|
||||
|
@ -201,7 +201,7 @@ public class PamGuiTabFX extends PamTabFX {
|
||||
* @return the internal pane which has been added
|
||||
*/
|
||||
public PamGuiInternalPane addInternalPane(UserDisplayNodeFX userDisplayNodeFX){
|
||||
System.out.println("UserDisplayNodeFX: " + userDisplayNodeFX);
|
||||
// System.out.println("UserDisplayNodeFX: " + userDisplayNodeFX);
|
||||
if (userDisplayNodeFX==null || userDisplayNodeFX.getNode()==null) return null;
|
||||
|
||||
for (PamGuiInternalPane internalPane: this.internalPanes) {
|
||||
|
@ -57,14 +57,14 @@ public class TabSelectionPane extends SettingsPane<PamGuiTabFX> {
|
||||
tabChoice=new ComboBox<String>();
|
||||
tabChoice.setMinWidth(100);
|
||||
PamHBox.setHgrow(tabChoice, Priority.ALWAYS); //make sure choice nox is big enough
|
||||
tabChoice.setEditable(true);
|
||||
tabChoice.setEditable(false);
|
||||
|
||||
//listener for adding tabs
|
||||
addButton=new PamButton();
|
||||
// addButton.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.PLUS, Color.WHITE, PamGuiManagerFX.iconSize));
|
||||
addButton.setGraphic(PamGlyphDude.createPamIcon("mdi2p-plus", Color.WHITE, PamGuiManagerFX.iconSize));
|
||||
addButton.setOnAction((action)->{
|
||||
pamGuiFX.addPamTab(new TabInfo("New Display " +(pamGuiFX.getTabs().size()+1)), null, true);
|
||||
pamGuiFX.addPamTab(new TabInfo("Display " +(pamGuiFX.getTabs().size()+1)), null, true);
|
||||
populateChoiceBox();
|
||||
//select the tab which has just been added.
|
||||
tabChoice.getSelectionModel().selectLast();
|
||||
|
@ -103,7 +103,8 @@ public class PamTabPane extends TabPane {
|
||||
public void setAddTabButton(boolean addTabButton) {
|
||||
if (this.addTabButton==addTabButton) return;
|
||||
this.addTabButton = addTabButton;
|
||||
tabPaneSkin = new PamTabPaneSkin(this);
|
||||
// tabPaneSkin = new PamTabPaneSkin(this);
|
||||
tabPaneSkin.setAddTabButton(addTabButton);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,13 +39,13 @@ public class PamTabPaneSkin extends TabPaneSkin {
|
||||
* Button which allows a new tab to be added.
|
||||
*/
|
||||
private PamButton addTabButton;
|
||||
|
||||
|
||||
/**
|
||||
* How many pixels the tab button 'floats' in the header area.
|
||||
*/
|
||||
public double addButtonInsets=3;
|
||||
|
||||
|
||||
|
||||
|
||||
public PamTabPaneSkin(PamTabPane tabPane) {
|
||||
super(tabPane);
|
||||
this.pamTabPane=tabPane;
|
||||
@ -66,7 +66,7 @@ public class PamTabPaneSkin extends TabPaneSkin {
|
||||
|
||||
//add extra regions to header area
|
||||
headerArea.getChildren().add(addTabButton);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -82,7 +82,7 @@ public class PamTabPaneSkin extends TabPaneSkin {
|
||||
public void removeTabEndRegion(Region tabRegion){
|
||||
headerArea.getChildren().remove(tabRegion);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add the tab start region. This sits in the tab header area, either at the left if the tab pane is horizontal or top if the tab pane is vertical.
|
||||
*/
|
||||
@ -114,23 +114,23 @@ public class PamTabPaneSkin extends TabPaneSkin {
|
||||
* Set the add button in the correct position
|
||||
*/
|
||||
private void layoutAddButton(){
|
||||
|
||||
//need to careful here. The width and height of the tab pane don'tr swap on rotation i.e. width of pane remains the axis on which tabs are added.
|
||||
//Weird but guess the java people decided that would make programming easier.
|
||||
double insetx=0.;
|
||||
if (pamTabPane.getSide()==Side.TOP || pamTabPane.getSide()==Side.BOTTOM){
|
||||
addTabButton.layoutXProperty().setValue(tabContentArea.getWidth()+insetx+headerArea.getPadding().getLeft()+addButtonInsets);
|
||||
addTabButton.layoutYProperty().setValue(headerArea.getHeight()-tabContentArea.getHeight()+addButtonInsets);
|
||||
addTabButton.resize(tabContentArea.getHeight()-4, tabContentArea.getHeight()-addButtonInsets*2);
|
||||
}
|
||||
else{
|
||||
//yep, this makes no sense but works when tabs are vertical.
|
||||
addTabButton.layoutXProperty().setValue(headerArea.getWidth()-tabContentArea.getWidth()-tabContentArea.getHeight()-headerArea.getPadding().getTop());
|
||||
addTabButton.layoutYProperty().setValue(headerArea.getHeight()-tabContentArea.getHeight());
|
||||
addTabButton.resize(tabContentArea.getHeight(),tabContentArea.getHeight());
|
||||
}
|
||||
|
||||
// System.out.println("tab Content area width: " +tabContentArea.getWidth()+" tab Content area height: "+tabContentArea.getHeight()+ " addTabButton.layoutYProperty()" +addTabButton.layoutYProperty().getValue());
|
||||
|
||||
//need to careful here. The width and height of the tab pane don'tr swap on rotation i.e. width of pane remains the axis on which tabs are added.
|
||||
//Weird but guess the java people decided that would make programming easier.
|
||||
double insetx=0.;
|
||||
if (pamTabPane.getSide()==Side.TOP || pamTabPane.getSide()==Side.BOTTOM){
|
||||
addTabButton.layoutXProperty().setValue(tabContentArea.getWidth()+insetx+headerArea.getPadding().getLeft()+addButtonInsets);
|
||||
addTabButton.layoutYProperty().setValue(headerArea.getHeight()-tabContentArea.getHeight()+addButtonInsets);
|
||||
addTabButton.resize(tabContentArea.getHeight()-4, tabContentArea.getHeight()-addButtonInsets*2);
|
||||
}
|
||||
else{
|
||||
//yep, this makes no sense but works when tabs are vertical.
|
||||
addTabButton.layoutXProperty().setValue(headerArea.getWidth()-tabContentArea.getWidth()-tabContentArea.getHeight()-headerArea.getPadding().getTop());
|
||||
addTabButton.layoutYProperty().setValue(headerArea.getHeight()-tabContentArea.getHeight());
|
||||
addTabButton.resize(tabContentArea.getHeight(),tabContentArea.getHeight());
|
||||
}
|
||||
|
||||
// System.out.println("tab Content area width: " +tabContentArea.getWidth()+" tab Content area height: "+tabContentArea.getHeight()+ " addTabButton.layoutYProperty()" +addTabButton.layoutYProperty().getValue());
|
||||
|
||||
}
|
||||
|
||||
@ -153,24 +153,24 @@ public class PamTabPaneSkin extends TabPaneSkin {
|
||||
double startHeaderSize;
|
||||
double endHeadersize;
|
||||
if (pamTabPane.getSide()==Side.TOP || pamTabPane.getSide()==Side.BOTTOM){
|
||||
startHeaderSize = (pamTabPane.getTabStartRegion()==null) ? in.getLeft() : getRegionWidth(pamTabPane.getTabStartRegion());
|
||||
endHeadersize = (pamTabPane.getTabEndRegion()==null) ? in.getRight(): getRegionWidth(pamTabPane.getTabEndRegion());
|
||||
//set padding of tab header to make space for any added buttons
|
||||
headerArea.setPadding(new Insets(
|
||||
in.getTop(),
|
||||
endHeadersize,
|
||||
in.getBottom(),
|
||||
startHeaderSize));
|
||||
startHeaderSize = (pamTabPane.getTabStartRegion()==null) ? in.getLeft() : getRegionWidth(pamTabPane.getTabStartRegion());
|
||||
endHeadersize = (pamTabPane.getTabEndRegion()==null) ? in.getRight(): getRegionWidth(pamTabPane.getTabEndRegion());
|
||||
//set padding of tab header to make space for any added buttons
|
||||
headerArea.setPadding(new Insets(
|
||||
in.getTop(),
|
||||
endHeadersize,
|
||||
in.getBottom(),
|
||||
startHeaderSize));
|
||||
}
|
||||
else {
|
||||
startHeaderSize = (pamTabPane.getTabStartRegion()==null) ? in.getTop() : pamTabPane.getTabStartRegion().getHeight();
|
||||
endHeadersize = (pamTabPane.getTabEndRegion()==null) ? in.getBottom(): pamTabPane.getTabEndRegion().getHeight();
|
||||
//set padding of tab header to make space for any added buttons
|
||||
headerArea.setPadding(new Insets(
|
||||
startHeaderSize,
|
||||
in.getRight(),
|
||||
endHeadersize,
|
||||
in.getLeft()));
|
||||
startHeaderSize = (pamTabPane.getTabStartRegion()==null) ? in.getTop() : pamTabPane.getTabStartRegion().getHeight();
|
||||
endHeadersize = (pamTabPane.getTabEndRegion()==null) ? in.getBottom(): pamTabPane.getTabEndRegion().getHeight();
|
||||
//set padding of tab header to make space for any added buttons
|
||||
headerArea.setPadding(new Insets(
|
||||
startHeaderSize,
|
||||
in.getRight(),
|
||||
endHeadersize,
|
||||
in.getLeft()));
|
||||
}
|
||||
|
||||
//layout additional header regions for start
|
||||
@ -210,14 +210,14 @@ public class PamTabPaneSkin extends TabPaneSkin {
|
||||
//System.out.println("Hello "+hello.getWidth()+" "+headerArea.getWidth()+ " "+tabContentArea.getWidth());
|
||||
|
||||
}
|
||||
|
||||
|
||||
private double getRegionWidth(Region region){
|
||||
double regionWidth=50;
|
||||
if (region.getMinWidth()>0) regionWidth=region.getMinWidth();
|
||||
if (region.getPrefWidth()>0) regionWidth=region.getPrefWidth();
|
||||
return regionWidth;
|
||||
}
|
||||
|
||||
|
||||
private double getRegionHeight(Region region){
|
||||
double regionHeight=50;
|
||||
if (region.getMinHeight()>0) regionHeight=region.getMinHeight();
|
||||
@ -240,7 +240,7 @@ public class PamTabPaneSkin extends TabPaneSkin {
|
||||
public double getHeaderHeight() {
|
||||
return headerArea.getHeight();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the height property of the header.
|
||||
* @return the height property of the header.
|
||||
@ -248,6 +248,20 @@ public class PamTabPaneSkin extends TabPaneSkin {
|
||||
public ReadOnlyDoubleProperty getHeaderHeightProperty(){
|
||||
return headerArea.heightProperty();
|
||||
}
|
||||
|
||||
|
||||
public void setAddTabButton(boolean addTabButton2) {
|
||||
if (addTabButton2){
|
||||
if (!headerArea.getChildren().contains(addTabButton)) {
|
||||
headerArea.getChildren().remove(addTabButton);
|
||||
layoutAddButton();
|
||||
}
|
||||
}
|
||||
else {
|
||||
headerArea.getChildren().remove(addTabButton);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ public class PamFlipPane extends FlipPane {
|
||||
backButton.setStyle("-fx-background-radius: 0 5 5 0; -fx-border-radius: 0 5 5 0; -fx-background-color: -color-accent-6");
|
||||
|
||||
backButton.setOnAction((action)->{
|
||||
System.out.println("FLIP BACK TO FRONT");
|
||||
// System.out.println("FLIP BACK TO FRONT");
|
||||
this.backButtonResponse.setValue(OK_BACK_BUTTON);
|
||||
this.flipToFront();
|
||||
});
|
||||
|
@ -13,12 +13,14 @@ import javafx.util.Duration;
|
||||
import javafx.animation.KeyFrame;
|
||||
import javafx.animation.KeyValue;
|
||||
import javafx.animation.Timeline;
|
||||
import javafx.animation.Animation.Status;
|
||||
import javafx.beans.binding.DoubleBinding;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.DoubleProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.Insets;
|
||||
|
||||
/**
|
||||
* Hiding pane which can be added to any node.
|
||||
@ -32,6 +34,12 @@ import javafx.event.EventHandler;
|
||||
*/
|
||||
public class HidingPane extends StackPane {
|
||||
|
||||
/**
|
||||
* The opacity of the button when the mouse is outside the show button
|
||||
*/
|
||||
private double showButtonOpacity = 0.8;
|
||||
|
||||
|
||||
/**
|
||||
* Which side the pane is hiding on.
|
||||
*/
|
||||
@ -52,7 +60,7 @@ public class HidingPane extends StackPane {
|
||||
* width when shown and when aligned top.button it is the height shown.
|
||||
*/
|
||||
private double expandedSize=300;
|
||||
|
||||
|
||||
/**
|
||||
* Show/Hide animation time in milliseconds.
|
||||
*/
|
||||
@ -72,7 +80,7 @@ public class HidingPane extends StackPane {
|
||||
* Button which sits in the hiding pane. Pressed to hide pane.
|
||||
*/
|
||||
private PamButton hideButton;
|
||||
|
||||
|
||||
/**
|
||||
* The button which shows the pane. This button isn't actually on the pane.
|
||||
*/
|
||||
@ -93,22 +101,22 @@ public class HidingPane extends StackPane {
|
||||
* The translate property, depends on side and whether the hiding panel is overlaid or moves it's parent node.
|
||||
*/
|
||||
private DoubleProperty paneTanslateProperty;
|
||||
|
||||
|
||||
/**
|
||||
* The binding property for the show button. Only used when the panel is overlayed on another panel.
|
||||
*/
|
||||
private DoubleBinding buttonTranslateProperty;
|
||||
|
||||
|
||||
/**
|
||||
* Indicates whether the panel is showing or not;
|
||||
*/
|
||||
private BooleanProperty showing=new SimpleBooleanProperty(false);
|
||||
|
||||
|
||||
/**
|
||||
* If true then the pane only shows once the hide pane animation has finished
|
||||
*/
|
||||
private boolean visibleImmediatly=true;
|
||||
|
||||
|
||||
/**
|
||||
* The default size of the icons
|
||||
*/
|
||||
@ -119,7 +127,7 @@ public class HidingPane extends StackPane {
|
||||
*
|
||||
*/
|
||||
private double offset=0;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor top create a new hiding pane.
|
||||
* @param side - the side the hiding pane appears from.
|
||||
@ -134,14 +142,14 @@ public class HidingPane extends StackPane {
|
||||
this.holderPane=holderPane;
|
||||
this.overlay=overlay;
|
||||
this.offset=offset;
|
||||
|
||||
// //CSS styling
|
||||
// this.getStylesheets().add(getClass().getResource("pamSettingsCSS.css").toExternalForm());
|
||||
// this.getStyleClass().add("pane");
|
||||
|
||||
|
||||
// //CSS styling
|
||||
// this.getStylesheets().add(getClass().getResource("pamSettingsCSS.css").toExternalForm());
|
||||
// this.getStyleClass().add("pane");
|
||||
|
||||
//set the size the panel will expand to
|
||||
setDefaultExpandedSize(hidePane);
|
||||
|
||||
|
||||
//set the translate property and side index.
|
||||
setTranlsateProperty();
|
||||
|
||||
@ -150,36 +158,36 @@ public class HidingPane extends StackPane {
|
||||
styleHideButton(hideButton);
|
||||
hideButton.setOnAction(new HideButtonPressed());
|
||||
hideButton.setVisible(false);
|
||||
// hideButton.setStyle("close-button-right");
|
||||
// hideButton.setStyle("close-button-right");
|
||||
|
||||
//create a show button. The show button is not displayed on the hiding panel but caqn be used in other panels
|
||||
showButton=createShowButton(true);
|
||||
|
||||
|
||||
//if overlay true bind the show button to the side pane.
|
||||
if (overlay) showButton.translateXProperty().bind(buttonTranslateProperty);
|
||||
|
||||
|
||||
//set up the animation for panel showing/hiding
|
||||
setAnimation();
|
||||
|
||||
|
||||
holderPane.setMinHeight(5); //needed for hiding panes to appear outside holder pane.
|
||||
|
||||
|
||||
// this.setMinHeight(500);
|
||||
// holderPane.heightProperty().addListener((oldVall, newVal, obsVsal)->{
|
||||
// if (this.getHeight()<500){
|
||||
// this.setLayoutY(0);
|
||||
// this.setMinHeight(500);
|
||||
// holderPane.setStyle("-fx-background: red;");
|
||||
// }
|
||||
// System.out.println("HidingPane: LayoutY: "+this.getLayoutY() + " height "+this.getHeight());
|
||||
// });
|
||||
|
||||
// PamBorderPane mainPane=new PamBorderPane();
|
||||
// mainPane.setCenter(hidePane);
|
||||
|
||||
|
||||
|
||||
// this.setMinHeight(500);
|
||||
// holderPane.heightProperty().addListener((oldVall, newVal, obsVsal)->{
|
||||
// if (this.getHeight()<500){
|
||||
// this.setLayoutY(0);
|
||||
// this.setMinHeight(500);
|
||||
// holderPane.setStyle("-fx-background: red;");
|
||||
// }
|
||||
// System.out.println("HidingPane: LayoutY: "+this.getLayoutY() + " height "+this.getHeight());
|
||||
// });
|
||||
|
||||
// PamBorderPane mainPane=new PamBorderPane();
|
||||
// mainPane.setCenter(hidePane);
|
||||
|
||||
this.getChildren().add(hidePane);
|
||||
setHideButtonPos(side);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -193,36 +201,36 @@ public class HidingPane extends StackPane {
|
||||
public HidingPane(final Side side, Region hidePane, Pane holderPane, boolean overlay) {
|
||||
this(side, hidePane, holderPane, overlay, 0);
|
||||
}
|
||||
|
||||
|
||||
public void setShowButton(PamButton showButton) {
|
||||
this.showButton = showButton;
|
||||
}
|
||||
|
||||
|
||||
public boolean isHorizontal(){
|
||||
if (side==Side.TOP || side==Side.BOTTOM) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void resetHideAnimation(){
|
||||
//set the size the panel will expand to
|
||||
setDefaultExpandedSize(hidePane);
|
||||
|
||||
|
||||
//set the translate property and side index.
|
||||
setTranlsateProperty();
|
||||
//set up the animation for panel showing/hiding
|
||||
setAnimation();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Style the button to have an image of arrow.
|
||||
* @param button-button to style
|
||||
*/
|
||||
public void styleHideButton(PamButton button){
|
||||
styleHideButton(button, side);
|
||||
styleHideButton(button, side);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Style the button to have an image of arrow.
|
||||
* @param button-button to style
|
||||
@ -232,34 +240,34 @@ public class HidingPane extends StackPane {
|
||||
switch (side){
|
||||
case RIGHT:
|
||||
//button.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("/Resources/SidePanelShow2.png"))));
|
||||
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_RIGHT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_RIGHT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-right", PamGuiManagerFX.iconSize));
|
||||
button.getStyleClass().add("close-button-right");
|
||||
break;
|
||||
case LEFT:
|
||||
//button.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("/Resources/SidePanelHide2.png"))));
|
||||
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_LEFT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_LEFT, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-left", PamGuiManagerFX.iconSize));
|
||||
button.getStyleClass().add("close-button-left");
|
||||
break;
|
||||
case TOP:
|
||||
//button.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("/Resources/SidePanelUp2.png"))));
|
||||
|
||||
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_UP, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
|
||||
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_UP, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-up", PamGuiManagerFX.iconSize));
|
||||
button.setPrefWidth(60); //horizontal buttons are slightly wider
|
||||
button.getStyleClass().add("close-button-top");
|
||||
break;
|
||||
case BOTTOM:
|
||||
//utton.setGraphic(new ImageView(new Image(getClass().getResourceAsStream("/Resources/SidePanelDown2.png"))));
|
||||
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_DOWN, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
// button.setGraphic(PamGlyphDude.createPamGlyph(FontAwesomeIcon.CHEVRON_DOWN, PamGuiManagerFX.iconColor, PamGuiManagerFX.iconSize));
|
||||
button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-down", PamGuiManagerFX.iconSize));
|
||||
button.setPrefWidth(60); //horizontal buttons are slightly wider
|
||||
button.getStyleClass().add("close-button-bottom");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the default expanded size for the hiding panel. If the pane has a preferred size then uses this but if not then uses
|
||||
* the field expandedSize to set expanded Size;
|
||||
@ -267,11 +275,11 @@ public class HidingPane extends StackPane {
|
||||
*/
|
||||
private void setDefaultExpandedSize(Region hidePane){
|
||||
boolean isHorizontal=isHorizontal();
|
||||
|
||||
|
||||
//check if the panel has a preferred width or height depending on side position. If so set the expanded size to that;
|
||||
if (!isHorizontal && hidePane.getPrefWidth()>0) expandedSize=hidePane.getPrefWidth();
|
||||
else if (isHorizontal && hidePane.getPrefHeight()>0) expandedSize=hidePane.getPrefHeight();
|
||||
|
||||
|
||||
//now set the correct preferred width for the panel
|
||||
if (!isHorizontal){
|
||||
hidePane.setPrefWidth(expandedSize);
|
||||
@ -285,7 +293,7 @@ public class HidingPane extends StackPane {
|
||||
this.setMinWidth(0);
|
||||
this.setMinHeight(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the preferred size is set for the hiding pane then the expanded size, the animation, the show
|
||||
* button binding property and position of the pane must be reset.
|
||||
@ -313,9 +321,9 @@ public class HidingPane extends StackPane {
|
||||
//set the correct translation for the pane
|
||||
if (showing.get()) paneTanslateProperty.set(overlay ? 0 : expandedSize+offset);
|
||||
else paneTanslateProperty.set(overlay ? (expandedSize+offset)*sideIndex: 0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a blank button which contains all the functionality to open or close the hiding panel, including the ability
|
||||
@ -328,75 +336,95 @@ public class HidingPane extends StackPane {
|
||||
|
||||
|
||||
private PamButton createShowButton(final boolean show){
|
||||
|
||||
final PamButton pamButton=new PamButton();
|
||||
|
||||
pamButton.setOnMousePressed(new EventHandler<MouseEvent>() {
|
||||
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
// record a delta distance for the drag and drop operation.
|
||||
dragX =mouseEvent.getSceneX();
|
||||
dragY =mouseEvent.getSceneY();
|
||||
}
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
// record a delta distance for the drag and drop operation.
|
||||
dragX =mouseEvent.getSceneX();
|
||||
dragY =mouseEvent.getSceneY();
|
||||
}
|
||||
});
|
||||
|
||||
pamButton.setOnMouseReleased(new EventHandler<MouseEvent>() {
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
if (distance==0) return;
|
||||
distance=sideIndex*distance;
|
||||
// System.out.println("Mouse released: HidePanel distance: "+distance);
|
||||
if (!overlay) distance=Math.abs(distance);
|
||||
//need to see where the drag has ended-if greater than 50% then open but if less then close.
|
||||
if (!isHorizontal()){
|
||||
if (distance<expandedSize/2) showHidePane(overlay? true : false);
|
||||
if (distance>=expandedSize/2) showHidePane(overlay? false : true);
|
||||
}
|
||||
else{
|
||||
if (distance<expandedSize/2) showHidePane(overlay? true : false);
|
||||
if (distance>=expandedSize/2) showHidePane(overlay? false : true);
|
||||
}
|
||||
//reset the distance
|
||||
distance=0;
|
||||
}
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
if (distance==0) return;
|
||||
distance=sideIndex*distance;
|
||||
// System.out.println("Mouse released: HidePanel distance: "+distance);
|
||||
if (!overlay) distance=Math.abs(distance);
|
||||
//need to see where the drag has ended-if greater than 50% then open but if less then close.
|
||||
if (!isHorizontal()){
|
||||
if (distance<expandedSize/2) showHidePane(overlay? true : false);
|
||||
if (distance>=expandedSize/2) showHidePane(overlay? false : true);
|
||||
}
|
||||
else{
|
||||
if (distance<expandedSize/2) showHidePane(overlay? true : false);
|
||||
if (distance>=expandedSize/2) showHidePane(overlay? false : true);
|
||||
}
|
||||
//reset the distance
|
||||
distance=0;
|
||||
}
|
||||
});
|
||||
|
||||
pamButton.setOnMouseDragged(new EventHandler<MouseEvent>() {
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
if (visibleImmediatly) hidePane.setVisible(true);
|
||||
else hidePane.setVisible(false);
|
||||
// hideButton.setVisible(true);
|
||||
/**
|
||||
* Work out the distance the panel is to be dragged;
|
||||
*/
|
||||
if (!isHorizontal()){
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
if (visibleImmediatly) hidePane.setVisible(true);
|
||||
else hidePane.setVisible(false);
|
||||
// hideButton.setVisible(true);
|
||||
/**
|
||||
* Work out the distance the panel is to be dragged;
|
||||
*/
|
||||
if (!isHorizontal()){
|
||||
if (!show) distance=(mouseEvent.getSceneX()-dragX);
|
||||
else distance=(mouseEvent.getSceneX()-dragX)+sideIndex*expandedSize;
|
||||
if (!overlay) distance=expandedSize-sideIndex*distance;
|
||||
}
|
||||
else{
|
||||
}
|
||||
else{
|
||||
if (!show) distance=(mouseEvent.getSceneY()-dragY);
|
||||
else distance=(mouseEvent.getSceneY()-dragY)-sideIndex*expandedSize;
|
||||
if (!overlay) distance=expandedSize+sideIndex*distance;
|
||||
}
|
||||
// if (show && Math.abs(distance)>expandedSize) return;
|
||||
|
||||
translatePanel(distance);
|
||||
}
|
||||
});
|
||||
pamButton.setOnMouseEntered(new EventHandler<MouseEvent>() {
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
}
|
||||
});
|
||||
pamButton.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
//System.out.println("Mouse clicked");
|
||||
showHidePane(show);
|
||||
}
|
||||
});
|
||||
pamButton.addEventHandler(ActionEvent.ACTION,new EventHandler<ActionEvent>() {
|
||||
@Override
|
||||
public void handle(ActionEvent e) {
|
||||
//System.out.println("Button event");
|
||||
showHidePane(show);
|
||||
}
|
||||
}
|
||||
// if (show && Math.abs(distance)>expandedSize) return;
|
||||
|
||||
translatePanel(distance);
|
||||
}
|
||||
});
|
||||
|
||||
pamButton.setOnMouseEntered(new EventHandler<MouseEvent>() {
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
// System.out.println("HidingPane.showButton - mouse entered");
|
||||
pamButton.setOpacity(1.0);
|
||||
pamButton.setPadding(new Insets(2.,2.,2.,2.));
|
||||
}
|
||||
});
|
||||
|
||||
pamButton.setOnMouseExited(new EventHandler<MouseEvent>() {
|
||||
@Override public void handle(MouseEvent mouseEvent) {
|
||||
// System.out.println("HidingPane.showButton - mouse exited");
|
||||
if (show) pamButton.setOpacity(showButtonOpacity);
|
||||
pamButton.setPadding(new Insets(0.,0.,0.,0.));
|
||||
}
|
||||
});
|
||||
|
||||
// pamButton.setOnMouseClicked(new EventHandler<MouseEvent>() {
|
||||
// @Override public void handle(MouseEvent mouseEvent) {
|
||||
// System.out.println("HidingPane.showButton - mouse clicked");
|
||||
// showHidePane(show);
|
||||
// }
|
||||
// });
|
||||
|
||||
pamButton.addEventHandler(ActionEvent.ACTION,new EventHandler<ActionEvent>() {
|
||||
@Override
|
||||
public void handle(ActionEvent e) {
|
||||
System.out.println("HidingPane.showButton - action event clicked");
|
||||
showHidePane(show);
|
||||
}
|
||||
});
|
||||
|
||||
if (show) pamButton.setOpacity(showButtonOpacity);
|
||||
|
||||
return pamButton;
|
||||
}
|
||||
|
||||
@ -425,21 +453,21 @@ public class HidingPane extends StackPane {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the hide button from the hiding pane. For example, used if the pane is non user controllable.
|
||||
*/
|
||||
public void removeHideButton(){
|
||||
this.getChildren().remove(hideButton);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The hiding panel will have a different side Index and translateProperty depending on what the side and overlay value combination is.
|
||||
* This function sets the correct values for sideIndex and translateProperty which are used in opening/closing animations and dragging the panel to an open or c
|
||||
* closed position.
|
||||
*/
|
||||
private void setTranlsateProperty(){
|
||||
|
||||
|
||||
/**
|
||||
* Figure out the correct index and property. The sideIndex is used to tell the animation what direction to
|
||||
* move the animation in. The property tells the panel either to translate in the x or y direction or
|
||||
@ -481,7 +509,7 @@ public class HidingPane extends StackPane {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a time line to show or hide a pane.
|
||||
* @param paneTanslateProperty -the translate property e.g. whether to change the preferred height/width, max height/width etc.
|
||||
@ -494,18 +522,18 @@ public class HidingPane extends StackPane {
|
||||
// Animation for scroll SHOW.
|
||||
timeLine.setCycleCount(1); //defines the number of cycles for this animation
|
||||
final KeyValue kvDwn = new KeyValue(paneTanslateProperty, newSize);
|
||||
// final KeyValue kvDwn = new KeyValue(translateProperty, expandedSize);
|
||||
// final KeyValue kvDwn = new KeyValue(translateProperty, expandedSize);
|
||||
final KeyFrame kfDwn = new KeyFrame(Duration.millis(duration), kvDwn);
|
||||
timeLine.getKeyFrames().add(kfDwn);
|
||||
return timeLine;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set up the animation that moves the hiding panel to show and to hide. translate property and sideIndex must be set
|
||||
* before calling this function.
|
||||
*/
|
||||
private void setAnimation(){
|
||||
|
||||
|
||||
//Initially hiding the pane
|
||||
paneTanslateProperty.set((expandedSize)*sideIndex); //+for right
|
||||
|
||||
@ -514,23 +542,23 @@ public class HidingPane extends StackPane {
|
||||
timeLineShow = createAnimation(paneTanslateProperty, overlay ? 0-offset : expandedSize +offset , duration);
|
||||
// Animation for scroll HIDE
|
||||
timeLineHide = createAnimation(paneTanslateProperty, overlay ? (expandedSize +offset)*sideIndex: 0-offset , duration);
|
||||
|
||||
|
||||
timeLineShow.setOnFinished(new EventHandler<ActionEvent>(){
|
||||
@Override
|
||||
public void handle(ActionEvent arg0) {
|
||||
showFinished();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void handle(ActionEvent arg0) {
|
||||
showFinished();
|
||||
}
|
||||
});
|
||||
|
||||
timeLineHide.setOnFinished(new EventHandler<ActionEvent>(){
|
||||
@Override
|
||||
public void handle(ActionEvent arg0) {
|
||||
hideFinished();
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public void handle(ActionEvent arg0) {
|
||||
hideFinished();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called whenever the hid animation has finished.
|
||||
*/
|
||||
@ -540,12 +568,12 @@ public class HidingPane extends StackPane {
|
||||
hidePane.setVisible(false);
|
||||
hideButton.setVisible(false);
|
||||
showButton.toFront();
|
||||
// //TODO-delete
|
||||
// System.out.println("ShowButton Size:"+showButton.getLayoutX() +" tranlateX: "+showButton.getTranslateX() +
|
||||
// " tranlateY: "+showButton.getTranslateY()+" show button layoutX "+ showButton.getLayoutX()+ " "
|
||||
// +showButton.getLayoutY()+ "show button width: "+showButton.getWidth());
|
||||
// //TODO-delete
|
||||
// System.out.println("ShowButton Size:"+showButton.getLayoutX() +" tranlateX: "+showButton.getTranslateX() +
|
||||
// " tranlateY: "+showButton.getTranslateY()+" show button layoutX "+ showButton.getLayoutX()+ " "
|
||||
// +showButton.getLayoutY()+ "show button width: "+showButton.getWidth());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called whenever the show animation has finished.
|
||||
*/
|
||||
@ -554,7 +582,7 @@ public class HidingPane extends StackPane {
|
||||
hidePane.setVisible(true);
|
||||
hideButton.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Move the hiding panel to show or hide a certain distance.
|
||||
* @param distance. The distance in pixels to move the panel. Positive to open the panel and negative to move the panel towards closed.
|
||||
@ -562,12 +590,12 @@ public class HidingPane extends StackPane {
|
||||
public void translatePanel(double distance){
|
||||
paneTanslateProperty.set(distance);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show or hide the pane.
|
||||
* @param showing-
|
||||
*/
|
||||
public void showHidePane(boolean show){
|
||||
public synchronized void showHidePane(boolean show){
|
||||
if (show) {
|
||||
//the pref size may have been changed...hide pane shoulf follow this size.
|
||||
showing.setValue(true);
|
||||
@ -575,6 +603,11 @@ public class HidingPane extends StackPane {
|
||||
//hideButton.setVisible(true);
|
||||
//System.out.println("HidingPane: Open Hide Pane");
|
||||
//open the panel
|
||||
if (timeLineShow.getStatus()==Status.RUNNING) {
|
||||
//stops the issue with the hiding pane freezing.
|
||||
return;
|
||||
}
|
||||
|
||||
timeLineShow.play();
|
||||
}
|
||||
else{
|
||||
@ -585,7 +618,7 @@ public class HidingPane extends StackPane {
|
||||
timeLineHide.play();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show the hide pane
|
||||
* @param show - tru to opne the pane. False to close the pnae
|
||||
@ -604,7 +637,7 @@ public class HidingPane extends StackPane {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called whenever the pin button is pressed.
|
||||
* @author Jamie Macaulay
|
||||
@ -624,7 +657,7 @@ public class HidingPane extends StackPane {
|
||||
public PamButton getHideButton() {
|
||||
return hideButton;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the button which shows the hide pane. This is generally not on the pane itself but needs to be
|
||||
* added to another pane.
|
||||
@ -649,7 +682,7 @@ public class HidingPane extends StackPane {
|
||||
public void setDuration(long duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the pane which contains this hiding pane.
|
||||
* @return the pane the hiding pane is located in.
|
||||
@ -657,7 +690,7 @@ public class HidingPane extends StackPane {
|
||||
public Pane getHolderPane() {
|
||||
return holderPane;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the timeline which opens hiding tab pane.
|
||||
* @return TimelIne which opens the hiding pane.
|
||||
@ -673,7 +706,7 @@ public class HidingPane extends StackPane {
|
||||
public Timeline getTimeLineHide() {
|
||||
return timeLineHide;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the hide pane shows content at the start of the hide animation or end.
|
||||
@ -682,7 +715,7 @@ public class HidingPane extends StackPane {
|
||||
public boolean isVisibleImmediatly() {
|
||||
return visibleImmediatly;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether the hide pane shows content at the start of the hide animation or end.
|
||||
* @param true if shows the pane at the start of the animation.
|
||||
@ -690,7 +723,7 @@ public class HidingPane extends StackPane {
|
||||
public void setVisibleImmediatly(boolean visibleImmediatly) {
|
||||
this.visibleImmediatly = visibleImmediatly;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The showing property for the hiding pane.
|
||||
* @return the showing property
|
||||
@ -698,53 +731,71 @@ public class HidingPane extends StackPane {
|
||||
public BooleanProperty showingProperty(){
|
||||
return this.showing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the opacity of the show button when the mouse is outside the button.
|
||||
* @return the opacity of the show button.
|
||||
*/
|
||||
public double getShowButtonOpacity() {
|
||||
return showButtonOpacity;
|
||||
}
|
||||
|
||||
|
||||
// hideSidebar.onFinishedProperty().set(new EventHandler<ActionEvent>() {
|
||||
// @Override public void handle(ActionEvent actionEvent) {
|
||||
// setVisible(false);
|
||||
// controlButton.setText("Show");
|
||||
// controlButton.getStyleClass().remove("hide-left");
|
||||
// controlButton.getStyleClass().add("show-right");
|
||||
// }
|
||||
//});
|
||||
//
|
||||
//
|
||||
//showSidebar.onFinishedProperty().set(new EventHandler<ActionEvent>() {
|
||||
// @Override public void handle(ActionEvent actionEvent) {
|
||||
// controlButton.setText("Collapse");
|
||||
// controlButton.getStyleClass().add("hide-left");
|
||||
// controlButton.getStyleClass().remove("show-right");
|
||||
// }
|
||||
//});
|
||||
|
||||
// // create an animation to hide sidebar.
|
||||
// final Animation hideSidebar = new Transition() {
|
||||
// { setCycleDuration(Duration.millis(50)); }
|
||||
// protected void interpolate(double frac) {
|
||||
// final double curWidth = expandedWidth * (1.0 - frac);
|
||||
// setPrefWidth(curWidth);
|
||||
// setTranslateX(curWidth);
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // create an animation to show a sidebar.
|
||||
// final Animation showSidebar = new Transition() {
|
||||
// { setCycleDuration(Duration.millis(duration)); }
|
||||
// protected void interpolate(double frac) {
|
||||
// final double curWidth = expandedWidth * frac;
|
||||
// setPrefWidth(curWidth);
|
||||
// setTranslateX(expandedWidth-curWidth);
|
||||
// }
|
||||
// };
|
||||
|
||||
// if (showSidebar.statusProperty().get() == Animation.Status.STOPPED && hideSidebar.statusProperty().get() == Animation.Status.STOPPED) {
|
||||
// if (isVisible()) {
|
||||
// hideSidebar.play();
|
||||
// } else {
|
||||
// setVisible(true);
|
||||
// showSidebar.play();
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Set the opacity of the show button when the mouse is outside.
|
||||
* @return the opacity of the show button - set to 1.0 for no chnage when mouse outside the button.
|
||||
*/
|
||||
public void setShowButtonOpacity(double showButtonOpacity) {
|
||||
this.showButtonOpacity = showButtonOpacity;
|
||||
this.showButton.setOpacity(showButtonOpacity);
|
||||
}
|
||||
|
||||
|
||||
// hideSidebar.onFinishedProperty().set(new EventHandler<ActionEvent>() {
|
||||
// @Override public void handle(ActionEvent actionEvent) {
|
||||
// setVisible(false);
|
||||
// controlButton.setText("Show");
|
||||
// controlButton.getStyleClass().remove("hide-left");
|
||||
// controlButton.getStyleClass().add("show-right");
|
||||
// }
|
||||
//});
|
||||
//
|
||||
//
|
||||
//showSidebar.onFinishedProperty().set(new EventHandler<ActionEvent>() {
|
||||
// @Override public void handle(ActionEvent actionEvent) {
|
||||
// controlButton.setText("Collapse");
|
||||
// controlButton.getStyleClass().add("hide-left");
|
||||
// controlButton.getStyleClass().remove("show-right");
|
||||
// }
|
||||
//});
|
||||
|
||||
// // create an animation to hide sidebar.
|
||||
// final Animation hideSidebar = new Transition() {
|
||||
// { setCycleDuration(Duration.millis(50)); }
|
||||
// protected void interpolate(double frac) {
|
||||
// final double curWidth = expandedWidth * (1.0 - frac);
|
||||
// setPrefWidth(curWidth);
|
||||
// setTranslateX(curWidth);
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // create an animation to show a sidebar.
|
||||
// final Animation showSidebar = new Transition() {
|
||||
// { setCycleDuration(Duration.millis(duration)); }
|
||||
// protected void interpolate(double frac) {
|
||||
// final double curWidth = expandedWidth * frac;
|
||||
// setPrefWidth(curWidth);
|
||||
// setTranslateX(expandedWidth-curWidth);
|
||||
// }
|
||||
// };
|
||||
|
||||
// if (showSidebar.statusProperty().get() == Animation.Status.STOPPED && hideSidebar.statusProperty().get() == Animation.Status.STOPPED) {
|
||||
// if (isVisible()) {
|
||||
// hideSidebar.play();
|
||||
// } else {
|
||||
// setVisible(true);
|
||||
// showSidebar.play();
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
@ -213,9 +213,7 @@ public class PamHiddenSidePane extends PamStackPane {
|
||||
break;
|
||||
}
|
||||
|
||||
//make show button same height as hide button
|
||||
// showButton.prefHeightProperty().bind(hidingPane.getHideButton().heightProperty());
|
||||
//translate it so it sits slightly below the top of the pane.
|
||||
//set the location of the show button to be in the middle of the pane
|
||||
showButton.translateYProperty().bind(displayPane.heightProperty().divide(2).subtract(showButton.heightProperty().divide(2)));
|
||||
|
||||
hidingPane.getHideButton().translateYProperty().setValue(yPos);
|
||||
|
@ -21,22 +21,22 @@ import pamViewFX.fxNodes.pamAxis.PamAxisPane2;
|
||||
*
|
||||
*/
|
||||
public class PlotPane extends PamBorderPane {
|
||||
|
||||
|
||||
/**
|
||||
* The x axis which sits at the top of the plot
|
||||
*/
|
||||
private PamAxisFX xAxisTop;
|
||||
|
||||
|
||||
/**
|
||||
* The x axis which sits at the bottom of the plot
|
||||
*/
|
||||
private PamAxisFX xAxisBottom;
|
||||
|
||||
|
||||
/**
|
||||
* The y Axis which sits to the left of the plot
|
||||
*/
|
||||
private PamAxisFX yAxisLeft;
|
||||
|
||||
|
||||
/*
|
||||
*The y axis which sits to right of the plot
|
||||
*/
|
||||
@ -88,7 +88,7 @@ public class PlotPane extends PamBorderPane {
|
||||
* Convenience variable, an array with all axis in order, top, right, bottom, left.
|
||||
*/
|
||||
private PamAxisFX[] axisArray;
|
||||
|
||||
|
||||
/**
|
||||
* Convenience variable, an array with all axis in order, top, right, bottom, left.
|
||||
*/
|
||||
@ -98,7 +98,7 @@ public class PlotPane extends PamBorderPane {
|
||||
* The holder pane for stuff
|
||||
*/
|
||||
private PamBorderPane holderPane;
|
||||
|
||||
|
||||
/**
|
||||
* Overlaid pane on canvas which can be used to add hiding panes to the plot.
|
||||
*/
|
||||
@ -111,23 +111,33 @@ public class PlotPane extends PamBorderPane {
|
||||
private double bottomBorder;
|
||||
|
||||
private double leftBorder;
|
||||
//
|
||||
// public static final int BOTTOMAXIS = 0;
|
||||
// public static final int BOTTOMAXIS = 1;
|
||||
// public static final int BOTTOMAXIS = 2;
|
||||
// public static final int BOTTOMAXIS = 3;
|
||||
//
|
||||
|
||||
//
|
||||
// public static final int BOTTOMAXIS = 0;
|
||||
// public static final int BOTTOMAXIS = 1;
|
||||
// public static final int BOTTOMAXIS = 2;
|
||||
// public static final int BOTTOMAXIS = 3;
|
||||
//
|
||||
|
||||
/**
|
||||
* Constructs a default plot with an bottom x axis and left y axis.
|
||||
*/
|
||||
public PlotPane(){
|
||||
this.setCenter(createPlot(false));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private PamBorderPane createPlot(boolean sidePanes){
|
||||
|
||||
|
||||
//create the panes to hold the axis;
|
||||
//create the plot pane.
|
||||
canvasHolder=new PamBorderPane();
|
||||
canvasHolder.setMaxWidth(4000);
|
||||
canvasHolder.setMaxHeight(4000);
|
||||
|
||||
canvas = new Canvas(50, 50);
|
||||
canvas.heightProperty().bind(canvasHolder.heightProperty());
|
||||
canvas.widthProperty().bind(canvasHolder.widthProperty());
|
||||
|
||||
//create the x axis for the display.
|
||||
xAxisTop = new PamAxisFX(0, 1, 0, 1, 0, 10, PamAxisFX.ABOVE_LEFT, null, PamAxis.LABEL_NEAR_CENTRE, null);
|
||||
xAxisTop.setCrampLabels(true);
|
||||
@ -145,67 +155,53 @@ public class PlotPane extends PamBorderPane {
|
||||
yAxisLeftPane=new PamAxisPane2(yAxisLeft, Side.LEFT);
|
||||
//yAxisLeftPane.setOrientation(Orientation.VERTICAL);
|
||||
|
||||
|
||||
yAxisRight = new PamAxisFX(0, 1, 0, 1, 0, 10, PamAxisFX.BELOW_RIGHT, "Graph Y Units", PamAxisFX.LABEL_NEAR_CENTRE, "%4d");
|
||||
yAxisRight.setCrampLabels(true);
|
||||
yAxisRightPane=new PamAxisPane2(yAxisRight, Side.RIGHT);
|
||||
//yAxisRightPane.setOrientation(Orientation.VERTICAL);
|
||||
//yAxisRightPane.setOrientation(Orientation.VERTICAL)
|
||||
|
||||
|
||||
//create the panes to hold the axis;
|
||||
|
||||
//create the plot pane.
|
||||
canvasHolder=new PamBorderPane();
|
||||
canvasHolder.setMaxWidth(4000);
|
||||
canvasHolder.setMaxHeight(4000);
|
||||
//allow hiding panes to be added
|
||||
hiddenSidePane=new PamHiddenSidePane();
|
||||
hiddenSidePane.getChildren().add(canvas);
|
||||
hiddenSidePane.toFront();
|
||||
|
||||
canvas = new Canvas(50, 50);
|
||||
canvas.heightProperty().bind(canvasHolder.heightProperty());
|
||||
canvas.widthProperty().bind(canvasHolder.widthProperty());
|
||||
|
||||
|
||||
//allow hiding panes to be added
|
||||
hiddenSidePane=new PamHiddenSidePane();
|
||||
hiddenSidePane.getChildren().add(canvas);
|
||||
hiddenSidePane.toFront();
|
||||
|
||||
|
||||
canvasHolder.setCenter(hiddenSidePane);
|
||||
canvasHolder.setMinHeight(0);
|
||||
canvasHolder.setMinWidth(0);
|
||||
//canvasHolder.getStyleClass().add("pane-plot");
|
||||
|
||||
//now add all axis together
|
||||
holderPane=new PamBorderPane();
|
||||
|
||||
//now need to add some corner sections to the top and bottom axis as borderpane is being used
|
||||
topHolder=createHorzHolder(xAxisTopPane);
|
||||
bottomHolder=createHorzHolder(xAxisBottomPane);
|
||||
canvasHolder.setCenter(hiddenSidePane);
|
||||
canvasHolder.setMinHeight(10);
|
||||
canvasHolder.setMinWidth(10);
|
||||
//canvasHolder.getStyleClass().add("pane-plot");
|
||||
|
||||
setAxisVisible(true, true, true, true);
|
||||
//now add all axis together
|
||||
holderPane=new PamBorderPane();
|
||||
|
||||
|
||||
// topHolder.toFront();
|
||||
//yAxisRightPane.toFront();
|
||||
// yAxisLeftPane.toFront();
|
||||
// bottomHolder.toFront();
|
||||
|
||||
axisArray=new PamAxisFX[4];
|
||||
axisArray[0]=xAxisTop;
|
||||
axisArray[1]=yAxisRight;
|
||||
axisArray[2]=xAxisBottom;
|
||||
axisArray[3]=yAxisLeft;
|
||||
|
||||
axisPanes=new PamAxisPane2[4];
|
||||
axisPanes[0]=xAxisTopPane;
|
||||
axisPanes[1]=yAxisRightPane;
|
||||
axisPanes[2]=xAxisBottomPane;
|
||||
axisPanes[3]=yAxisLeftPane;
|
||||
|
||||
return holderPane;
|
||||
//now need to add some corner sections to the top and bottom axis as borderpane is being used
|
||||
topHolder=createHorzHolder(xAxisTopPane);
|
||||
bottomHolder=createHorzHolder(xAxisBottomPane);
|
||||
|
||||
setAxisVisible(true, true, true, true);
|
||||
|
||||
|
||||
// topHolder.toFront();
|
||||
//yAxisRightPane.toFront();
|
||||
// yAxisLeftPane.toFront();
|
||||
// bottomHolder.toFront();
|
||||
|
||||
axisArray=new PamAxisFX[4];
|
||||
axisArray[0]=xAxisTop;
|
||||
axisArray[1]=yAxisRight;
|
||||
axisArray[2]=xAxisBottom;
|
||||
axisArray[3]=yAxisLeft;
|
||||
|
||||
axisPanes=new PamAxisPane2[4];
|
||||
axisPanes[0]=xAxisTopPane;
|
||||
axisPanes[1]=yAxisRightPane;
|
||||
axisPanes[2]=xAxisBottomPane;
|
||||
axisPanes[3]=yAxisLeftPane;
|
||||
|
||||
return holderPane;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set a hiding pane within the plot area
|
||||
* @param pane - the pane whihc is hidden
|
||||
@ -231,7 +227,7 @@ public class PlotPane extends PamBorderPane {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get one of the hiding panes within the plot area
|
||||
* @param side - the location of the pna eon the plot (left or right)
|
||||
@ -258,7 +254,7 @@ public class PlotPane extends PamBorderPane {
|
||||
*/
|
||||
private PamHBox createHorzHolder(PamAxisPane2 axisPane){
|
||||
PamHBox horzHolder=new PamHBox();
|
||||
|
||||
|
||||
Pane leftPane=new Pane();
|
||||
//need both min and pref to make binding work properly;
|
||||
leftPane.prefWidthProperty().bind(yAxisLeftPane.widthProperty());
|
||||
@ -267,26 +263,26 @@ public class PlotPane extends PamBorderPane {
|
||||
Pane rightPane=new Pane();
|
||||
rightPane.prefWidthProperty().bind(yAxisRightPane.widthProperty());
|
||||
rightPane.minWidthProperty().bind(yAxisRightPane.widthProperty());
|
||||
|
||||
|
||||
horzHolder.getChildren().addAll(leftPane, axisPane, rightPane);
|
||||
//axisPane.toFront(); this changes the order of children in a PamHBox.
|
||||
HBox.setHgrow(axisPane, Priority.ALWAYS);
|
||||
|
||||
HBox.setHgrow(axisPane, Priority.ALWAYS);
|
||||
|
||||
//horzHolder.getStyleClass().add("pane");
|
||||
|
||||
return horzHolder;
|
||||
|
||||
return horzHolder;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// public void repaintAxis() {
|
||||
// xAxisTopPane.repaint();
|
||||
// xAxisBottomPane.repaint();
|
||||
// yAxisRightPane.repaint();
|
||||
// yAxisLeftPane.repaint();
|
||||
// }
|
||||
|
||||
|
||||
// public void repaintAxis() {
|
||||
// xAxisTopPane.repaint();
|
||||
// xAxisBottomPane.repaint();
|
||||
// yAxisRightPane.repaint();
|
||||
// yAxisLeftPane.repaint();
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* Get the canvas- this is where the plotting takes place.
|
||||
* @return the plot canvas.
|
||||
@ -294,8 +290,8 @@ public class PlotPane extends PamBorderPane {
|
||||
public Canvas getPlotCanvas() {
|
||||
return canvas;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get an axis of the plot pane.
|
||||
* @param side the axis to get.
|
||||
@ -314,10 +310,10 @@ public class PlotPane extends PamBorderPane {
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get an axis pane. The axis pane is the node which displays a PamAxisFX.
|
||||
* @param side the axis pane to get.
|
||||
@ -337,7 +333,7 @@ public class PlotPane extends PamBorderPane {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all the axis of the plot pane.
|
||||
* @return a list of axis in the order: TOP, RIGHT, BOTTOM, LEFT.
|
||||
@ -345,7 +341,7 @@ public class PlotPane extends PamBorderPane {
|
||||
public PamAxisFX[] getAllAxis() {
|
||||
return axisArray;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an axis pane
|
||||
* @param side the axis to get.
|
||||
@ -353,14 +349,14 @@ public class PlotPane extends PamBorderPane {
|
||||
public PamAxisPane2[] getAllAxisPanes() {
|
||||
return axisPanes;
|
||||
}
|
||||
|
||||
|
||||
public void setEmptyBorders(double top, double right, double bottom, double left) {
|
||||
this.topBorder = top;
|
||||
this.rightBorder = right;
|
||||
this.bottomBorder = bottom;
|
||||
this.leftBorder = left;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set which axis are visible.
|
||||
* @param top true to show the top axis
|
||||
@ -370,9 +366,9 @@ public class PlotPane extends PamBorderPane {
|
||||
*/
|
||||
public void setAxisVisible(boolean top, boolean right, boolean bottom,
|
||||
boolean left) {
|
||||
|
||||
|
||||
//holderPane.getChildren().clear();
|
||||
|
||||
|
||||
//HACK- 05/08/2016 have to do this because there is a bug in switching children postions in a border pane.
|
||||
//casues a duplicate childrne error.
|
||||
holderPane.setRight(null);
|
||||
@ -381,41 +377,41 @@ public class PlotPane extends PamBorderPane {
|
||||
holderPane.setBottom(null);
|
||||
holderPane.getChildren().clear();
|
||||
//end of HACK.
|
||||
|
||||
|
||||
|
||||
if (top) {
|
||||
holderPane.setTop(topHolder) ;
|
||||
}
|
||||
else if (topBorder > 0) {
|
||||
// holderPane.setTopSpace(topBorder);
|
||||
// holderPane.setTopSpace(topBorder);
|
||||
}
|
||||
if (bottom) {
|
||||
holderPane.setBottom(bottomHolder);
|
||||
}
|
||||
else if (bottomBorder > 0) {
|
||||
// holderPane.setBottomSpace(bottomBorder);
|
||||
// holderPane.setBottomSpace(bottomBorder);
|
||||
}
|
||||
if (right) {
|
||||
holderPane.setRight(yAxisRightPane) ;
|
||||
}
|
||||
else if (rightBorder > 0){
|
||||
// holderPane.setRightSpace(rightBorder);
|
||||
// holderPane.setRightSpace(rightBorder);
|
||||
}
|
||||
if (left) {
|
||||
holderPane.setLeft(yAxisLeftPane) ;
|
||||
}
|
||||
else if (leftBorder > 0) {
|
||||
// holderPane.setLeftSpace(leftBorder);
|
||||
// holderPane.setLeftSpace(leftBorder);
|
||||
}
|
||||
holderPane.setCenter(canvasHolder);
|
||||
//bottomHolder.toBack();
|
||||
|
||||
// this.xAxisTopPane.setVisible(top);
|
||||
// this.xAxisBottomPane.setVisible(bottom);
|
||||
// this.yAxisRightPane.setVisible(right);
|
||||
// this.yAxisLeftPane.setVisible(left);
|
||||
|
||||
// this.xAxisTopPane.setVisible(top);
|
||||
// this.xAxisBottomPane.setVisible(bottom);
|
||||
// this.yAxisRightPane.setVisible(right);
|
||||
// this.yAxisLeftPane.setVisible(left);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the minimium height of the right and left hide pane. Set -1 for there to be no minimum height.
|
||||
* If the hide pane goes below the minimum height it pops out of its holder.
|
||||
@ -456,12 +452,12 @@ public class PlotPane extends PamBorderPane {
|
||||
public PamAxisFX getyAxisRight() {
|
||||
return yAxisRight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
39
src/pamguard/PAMGuard_sqlite.java
Normal file
39
src/pamguard/PAMGuard_sqlite.java
Normal file
@ -0,0 +1,39 @@
|
||||
package pamguard;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.sqlite.SQLiteConfig;
|
||||
|
||||
import generalDatabase.sqlite.SqliteSQLTypes;
|
||||
|
||||
public class PAMGuard_sqlite {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
String dbName = "/Users/jdjm/Desktop/section2_cpod/hyskeir_pamguard.sqlite3";
|
||||
/*
|
||||
* Don't use the driver manager, but open from the built in command in
|
||||
* SQLiteConfig. This will then correctly set the dateformat of the database.
|
||||
*/
|
||||
SQLiteConfig config = new SQLiteConfig();
|
||||
config.setSharedCache(true);
|
||||
config.enableRecursiveTriggers(true);
|
||||
config.enableLoadExtension(true);
|
||||
config.setDateClass(SqliteSQLTypes.dateClass.getValue());
|
||||
config.setDateStringFormat(SQLiteConfig.DEFAULT_DATE_STRING_FORMAT);
|
||||
|
||||
Connection con = null;
|
||||
try {
|
||||
con = config.createConnection("jdbc:sqlite:" + dbName);
|
||||
con.setAutoCommit(false);
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println("Connection: " + con);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -228,15 +228,17 @@ public class DLControl extends PamControlledUnit implements PamSettings {
|
||||
|
||||
// classify the raw data segments.
|
||||
addPamProcess(dlClassifyProcess = new DLClassifyProcess(this, segmenterProcess.getSegmenterDataBlock()));
|
||||
dlClassifyProcess.addMultiPlexDataBlock(segmenterProcess.getSegmenteGrouprDataBlock());
|
||||
|
||||
//manages the names assigned to different output classes.
|
||||
dlClassNameManager = new DLClassNameManager(this);
|
||||
|
||||
//manages default models
|
||||
defaultModelManager = new DLDefaultModelManager(this);
|
||||
|
||||
|
||||
//manages downloading models
|
||||
modelDownloadManager = new DLDownloadManager();
|
||||
|
||||
|
||||
// add storage options etc.
|
||||
dlBinaryDataSource = new DLResultBinarySource(dlClassifyProcess);
|
||||
|
@ -101,6 +101,8 @@ public class DLPredictionPane extends PamBorderPane implements TDSettingsPane {
|
||||
if (dlPredictionPlotInfoFX.getDlControl().getDLModel()!=null) {
|
||||
//populate the prediction pane.
|
||||
DLClassName[] classNames = dlPredictionPlotInfoFX.getDlControl().getDLModel().getClassNames();
|
||||
|
||||
// System.out.println("MAKE MY CLASS NAMES: " + dlPredictionPlotInfoFX.getDlControl().getDLModel().getClassNames());
|
||||
|
||||
layoutColourPanes(classNames);
|
||||
}
|
||||
|
@ -105,8 +105,8 @@ public class DLPredictionPlotInfoFX extends GenericLinePlotInfo {
|
||||
dlPredParams.lineInfos[i] = new LineInfo(true, Color.rgb(0, 0, 255%(i*30 + 50)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
getGraphSettingsPane().setParams();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import rawDeepLearningClassifier.logging.DLAnnotation;
|
||||
import rawDeepLearningClassifier.logging.DLAnnotationType;
|
||||
import rawDeepLearningClassifier.segmenter.GroupedRawData;
|
||||
import rawDeepLearningClassifier.segmenter.SegmenterDataBlock;
|
||||
import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup;
|
||||
|
||||
/**
|
||||
* The deep learning classification process. This takes a segment of raw data from the segmenter.
|
||||
@ -35,7 +36,7 @@ import rawDeepLearningClassifier.segmenter.SegmenterDataBlock;
|
||||
*/
|
||||
public class DLClassifyProcess extends PamInstantProcess {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Holds all model results but no other information
|
||||
*/
|
||||
@ -64,15 +65,13 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
/**
|
||||
* The DL buffer
|
||||
*/
|
||||
private ArrayList<GroupedRawData> classificationBuffer;
|
||||
|
||||
private ArrayList<PamDataUnit> classificationBuffer;
|
||||
|
||||
/**
|
||||
* The DL annotation type.
|
||||
*/
|
||||
private DLAnnotationType dlAnnotationType;
|
||||
|
||||
|
||||
/**
|
||||
* The last parent data for grouped data. This is used to ensure that DLDetections
|
||||
* correspond to the raw chunk of data from a parent detection e.g. a click detection.
|
||||
@ -82,8 +81,8 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
|
||||
public DLClassifyProcess(DLControl dlControl, SegmenterDataBlock parentDataBlock) {
|
||||
super(dlControl);
|
||||
|
||||
|
||||
|
||||
|
||||
this.setParentDataBlock(parentDataBlock);
|
||||
|
||||
// this.setParentDataBlock(parentDataBlock);
|
||||
@ -117,7 +116,7 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
overlayGraphics.setDetectionData(true);
|
||||
dlDetectionDataBlock.setOverlayDraw(overlayGraphics);
|
||||
|
||||
classificationBuffer = new ArrayList<GroupedRawData>();
|
||||
classificationBuffer = new ArrayList<PamDataUnit>();
|
||||
|
||||
//the process name.
|
||||
setProcessName("Deep Learning Classifier");
|
||||
@ -140,7 +139,7 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
System.err.println("Raw Deep Learning Classifier: The grouped source parameters were null."
|
||||
+ " A new instance has been created: Possible de-serialization error.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//important for downstream processes such as the bearing localiser.
|
||||
dlModelResultDataBlock.setChannelMap(dlControl.getDLParams().groupedSourceParams.getChannelBitmap());
|
||||
@ -166,7 +165,7 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
public void prepareProcess() {
|
||||
setupClassifierProcess();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* called for every process once the system model has been created.
|
||||
@ -194,30 +193,66 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
*/
|
||||
@Override
|
||||
public void newData(PamObservable obs, PamDataUnit pamRawData) {
|
||||
// System.out.println("NEW SEGMENTER DATA");
|
||||
|
||||
//the raw data units should appear in sequential channel order
|
||||
GroupedRawData rawDataUnit = (GroupedRawData) pamRawData;
|
||||
|
||||
if (checkGroupData(rawDataUnit)) {
|
||||
//check whether the classification buffer is full. If it is then run
|
||||
if (isClassificationBufferFull(classificationBuffer, rawDataUnit)) {
|
||||
|
||||
//first call run model to clear out the classification buffer if needs be
|
||||
runModel();
|
||||
if (pamRawData instanceof SegmenterDetectionGroup) {
|
||||
if (classificationBuffer.size()>=1) {
|
||||
// System.out.println("RUN THE MODEL FOR WHISTLES: ");
|
||||
runDetectionGroupModel();
|
||||
classificationBuffer.clear();
|
||||
}
|
||||
|
||||
classificationBuffer.add(rawDataUnit);
|
||||
else {
|
||||
classificationBuffer.add(pamRawData);
|
||||
}
|
||||
}
|
||||
// System.out.println("New raw data in: chan: " + PamUtils.getSingleChannel(pamRawData.getChannelBitmap()) +
|
||||
// " Size: " + pamRawData.getSampleDuration() + " first sample: " + rawDataUnit.getRawData()[0][0]
|
||||
// + "Parent UID: " + rawDataUnit.getParentDataUnit().getUID());
|
||||
|
||||
if (pamRawData instanceof GroupedRawData) {
|
||||
//the raw data units should appear in sequential channel order
|
||||
GroupedRawData rawDataUnit = (GroupedRawData) pamRawData;
|
||||
|
||||
if (checkGroupData(rawDataUnit)) {
|
||||
//check whether the classification buffer is full. If it is then run
|
||||
if (isRawClassificationBufferFull(classificationBuffer, rawDataUnit)) {
|
||||
|
||||
//first call run model to clear out the classification buffer if needs be
|
||||
runRawModel();
|
||||
classificationBuffer.clear();
|
||||
}
|
||||
|
||||
classificationBuffer.add(rawDataUnit);
|
||||
|
||||
}
|
||||
}
|
||||
// System.out.println("New raw data in: chan: " + PamUtils.getSingleChannel(pamRawData.getChannelBitmap()) +
|
||||
// " Size: " + pamRawData.getSampleDuration() + " first sample: " + rawDataUnit.getRawData()[0][0]
|
||||
// + "Parent UID: " + rawDataUnit.getParentDataUnit().getUID());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Run a model for which the input is a detection group.
|
||||
*/
|
||||
private synchronized void runDetectionGroupModel() {
|
||||
if (classificationBuffer.size()<=0) return;
|
||||
ArrayList<PamDataUnit> classificationBufferTemp = (ArrayList<PamDataUnit>) classificationBuffer.clone();
|
||||
|
||||
ArrayList<? extends PredictionResult> modelResults = this.dlControl.getDLModel().runModel(classificationBufferTemp);
|
||||
|
||||
for (int i=0; i<classificationBufferTemp.size(); i++) {
|
||||
|
||||
if (modelResults!=null && modelResults.get(i)!=null) {
|
||||
DLDataUnit dlDataUnit = predictionToDataUnit(classificationBuffer.get(i), modelResults.get(i));
|
||||
this.dlModelResultDataBlock.addPamData(dlDataUnit); //here
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the model if the classification buffer is full.
|
||||
*/
|
||||
private void runModel() {
|
||||
private void runRawModel() {
|
||||
|
||||
if (classificationBuffer.size()<=0) return;
|
||||
|
||||
@ -235,18 +270,18 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
// System.out.println("Compare Times: " + PamCalendar.formatDBDateTime(modelResults.get(i).getTimeMillis(), true) +
|
||||
// " " + PamCalendar.formatDBDateTime(classificationBufferTemp.get(i).getTimeMilliseconds(), true) + " " +
|
||||
// modelResults.get(i).getPrediction()[1]);
|
||||
newModelResult(modelResults.get(i), classificationBufferTemp.get(i));
|
||||
newRawModelResult(modelResults.get(i), classificationBufferTemp.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the buffer is full and the results should be passed to the classification model.
|
||||
* Check whether the buffer is full and the results should be passed to the classification model if we are using GrpoupDataUnits
|
||||
* @param classificationBuffer2 - the classification buffer.
|
||||
* @param rawDataUnit - the next raw data unit to add to the buffer.
|
||||
* @return true if the buffer is full.
|
||||
*/
|
||||
private boolean isClassificationBufferFull(ArrayList<GroupedRawData> classificationBuffer2, GroupedRawData rawDataUnit) {
|
||||
private boolean isRawClassificationBufferFull(ArrayList<PamDataUnit> classificationBuffer2, GroupedRawData rawDataUnit) {
|
||||
|
||||
if (classificationBuffer2.size()==0) return false;
|
||||
|
||||
@ -254,16 +289,16 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
//1) It's over a max time
|
||||
//2) Contains different parent data units (if not from raw data).
|
||||
|
||||
GroupedRawData lastUnit = classificationBuffer2.get(classificationBuffer2.size()-1);
|
||||
GroupedRawData lastUnit = (GroupedRawData) classificationBuffer2.get(classificationBuffer2.size()-1);
|
||||
|
||||
if (!(lastUnit.getParentDataUnit() instanceof RawDataUnit) && lastUnit.getParentDataUnit()!=rawDataUnit.getParentDataUnit()) {
|
||||
//there is a new parent data unit.
|
||||
return true;
|
||||
}
|
||||
|
||||
//get the start time. Use min value instead of first data just in case units ar enot in order.
|
||||
//get the start time. Use min value instead of first data just in case units are not in order.
|
||||
long min = Long.MAX_VALUE;
|
||||
for (GroupedRawData groupedRawData: classificationBuffer2) {
|
||||
for (PamDataUnit groupedRawData: classificationBuffer2) {
|
||||
if (groupedRawData.getTimeMilliseconds()<min) {
|
||||
min=groupedRawData.getTimeMilliseconds();
|
||||
}
|
||||
@ -299,18 +334,7 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a data unit form a model result. This is called whenever data passes a prediction threshold.
|
||||
*
|
||||
* @param modelResult - the model result.
|
||||
* @param pamRawData - the raw data unit which the model result came from.
|
||||
*/
|
||||
public void newModelResult(PredictionResult modelResult, GroupedRawData pamRawData) {
|
||||
|
||||
//the model result may be null if the classifier uses a new thread.
|
||||
|
||||
//System.out.println("New segment: parent UID: " + pamRawData.getParentDataUnit().getUID() + " Prediciton: " + modelResult.getPrediction()[0]+ " " + getSourceParams().countChannelGroups());
|
||||
|
||||
private DLDataUnit predictionToDataUnit(PamDataUnit pamRawData, PredictionResult modelResult) {
|
||||
//create a new data unit - always add to the model result section.
|
||||
DLDataUnit dlDataUnit = new DLDataUnit(pamRawData.getTimeMilliseconds(), pamRawData.getChannelBitmap(),
|
||||
pamRawData.getStartSample(), pamRawData.getSampleDuration(), modelResult);
|
||||
@ -319,17 +343,35 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
dlDataUnit.setFrequency(new double[] {0, dlControl.getDLClassifyProcess().getSampleRate()/2});
|
||||
dlDataUnit.setDurationInMilliseconds(pamRawData.getDurationInMilliseconds());
|
||||
|
||||
return dlDataUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a data unit form a model result. This is called whenever data passes a prediction threshold.
|
||||
*
|
||||
* @param modelResult - the model result.
|
||||
* @param pamRawData - the raw data unit which the model result came from.
|
||||
*/
|
||||
public void newRawModelResult(PredictionResult modelResult, GroupedRawData pamRawData) {
|
||||
|
||||
//the model result may be null if the classifier uses a new thread.
|
||||
|
||||
//System.out.println("New segment: parent UID: " + pamRawData.getParentDataUnit().getUID() + " Prediciton: " + modelResult.getPrediction()[0]+ " " + getSourceParams().countChannelGroups());
|
||||
|
||||
//create a new data unit - always add to the model result section.
|
||||
DLDataUnit dlDataUnit = predictionToDataUnit(pamRawData, modelResult);
|
||||
|
||||
this.dlModelResultDataBlock.addPamData(dlDataUnit); //here
|
||||
|
||||
//need to implement multiple groups.
|
||||
for (int i=0; i<getSourceParams().countChannelGroups(); i++) {
|
||||
|
||||
// System.out.println("RawDataIn: chan: " + pamRawData.getChannelBitmap()+ " " +
|
||||
// PamUtils.hasChannel(getSourceParams().getGroupChannels(i), pamRawData.getChannelBitmap()) +
|
||||
// " grouped source: " +getSourceParams().getGroupChannels(i) + " Channels OK? "
|
||||
// +PamUtils.hasChannel(getSourceParams().getGroupChannels(i), PamUtils.getSingleChannel(pamRawData.getChannelBitmap()))
|
||||
// + " groupchan: " + getSourceParams().getGroupChannels(i) + " " + PamUtils.getLowestChannel(pamRawData.getChannelBitmap())
|
||||
// + " chan bitmap: " + pamRawData.getChannelBitmap());
|
||||
// System.out.println("RawDataIn: chan: " + pamRawData.getChannelBitmap()+ " " +
|
||||
// PamUtils.hasChannel(getSourceParams().getGroupChannels(i), pamRawData.getChannelBitmap()) +
|
||||
// " grouped source: " +getSourceParams().getGroupChannels(i) + " Channels OK? "
|
||||
// +PamUtils.hasChannel(getSourceParams().getGroupChannels(i), PamUtils.getSingleChannel(pamRawData.getChannelBitmap()))
|
||||
// + " groupchan: " + getSourceParams().getGroupChannels(i) + " " + PamUtils.getLowestChannel(pamRawData.getChannelBitmap())
|
||||
// + " chan bitmap: " + pamRawData.getChannelBitmap());
|
||||
|
||||
if (PamUtils.hasChannel(getSourceParams().getGroupChannels(i), PamUtils.getLowestChannel(pamRawData.getChannelBitmap()))) {
|
||||
|
||||
@ -375,7 +417,7 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
//Need to go by the parent data unit for merging data not the segments. Note that we may still add multiple
|
||||
//predicitions to a single data unit depending on how many segments it contains.
|
||||
|
||||
//System.out.println("New model data " + pamRawData.getParentDataUnit().getUID() + " " + groupDataBuffer[i].size() + " " + modelResultDataBuffer[i].size());
|
||||
//System.out.println("New model data " + pamRawData.getParentDataUnit().getUID() + " " + groupDataBuffer[i].size() + " " + modelResultDataBuffer[i].size());
|
||||
|
||||
if (pamRawData.getParentDataUnit()!=lastParentDataUnit[i]) {
|
||||
//save any data
|
||||
@ -422,25 +464,25 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
*
|
||||
*/
|
||||
public void forceRunClassifier(PamDataUnit dataUnit) {
|
||||
|
||||
|
||||
|
||||
|
||||
//first call run model to clear out the classification buffer if needs be
|
||||
runModel();
|
||||
runRawModel();
|
||||
classificationBuffer.clear();
|
||||
|
||||
|
||||
//need to implement multiple groups.
|
||||
for (int i=0; i<getSourceParams().countChannelGroups(); i++) {
|
||||
|
||||
|
||||
// System.out.println("Nummber segments " + groupDataBuffer[i].size() + " data unit len: " + dataUnit.getSampleDurationAsInt() + " samples UID: " + dataUnit.getUID());
|
||||
// System.out.println("RawDataIn: chan: " + dataUnit.getChannelBitmap()+ " " +
|
||||
// PamUtils.hasChannel(getSourceParams().getGroupChannels(i), dataUnit.getChannelBitmap()) +
|
||||
// " grouped source: " +getSourceParams().getGroupChannels(i));
|
||||
|
||||
|
||||
|
||||
|
||||
// System.out.println("Nummber segments " + groupDataBuffer[i].size() + " data unit len: " + dataUnit.getSampleDurationAsInt() + " samples UID: " + dataUnit.getUID());
|
||||
// System.out.println("RawDataIn: chan: " + dataUnit.getChannelBitmap()+ " " +
|
||||
// PamUtils.hasChannel(getSourceParams().getGroupChannels(i), dataUnit.getChannelBitmap()) +
|
||||
// " grouped source: " +getSourceParams().getGroupChannels(i));
|
||||
|
||||
|
||||
if (PamUtils.hasChannel(getSourceParams().getGroupChannels(i), PamUtils.getSingleChannel(dataUnit.getChannelBitmap()))) {
|
||||
if (groupDataBuffer[i].size()>0) {
|
||||
//System.out.println("Save click annotation to " + lastParentDataUnit[i].getUID());
|
||||
//System.out.println("Save click annotation to " + lastParentDataUnit[i].getUID());
|
||||
addDLAnnotation(dataUnit,groupDataBuffer[i],modelResultDataBuffer[i]);
|
||||
lastParentDataUnit[i]=null;
|
||||
clearBuffer(i);
|
||||
@ -565,15 +607,22 @@ public class DLClassifyProcess extends PamInstantProcess {
|
||||
|
||||
@Override
|
||||
public void pamStart() {
|
||||
// TODO Auto-generated method stub
|
||||
System.out.println("PREP MODEL:");
|
||||
// System.out.println("PREP MODEL:");
|
||||
this.dlControl.getDLModel().prepModel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pamStop() {
|
||||
runModel(); //make sure to run the last data in the buffer.
|
||||
|
||||
//make sure to run the last data in the buffer.
|
||||
if (this.classificationBuffer.size()>0) {
|
||||
if (classificationBuffer.get(0) instanceof GroupedRawData) {
|
||||
runRawModel(); //raw data or raw data units
|
||||
}
|
||||
if (classificationBuffer.get(0) instanceof SegmenterDetectionGroup) {
|
||||
runDetectionGroupModel(); //any other data units.
|
||||
}
|
||||
}
|
||||
|
||||
//21/11/2022 - it seems like this causes a memory leak when models are reopened and closed every file...
|
||||
//this.dlControl.getDLModel().closeModel();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package rawDeepLearningClassifier.dlClassification;
|
||||
|
||||
import PamguardMVC.DataUnitBaseData;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
|
||||
/**
|
||||
* A data unit created from classification results of DL model. this data unit holds one model results, i.e.
|
||||
@ -37,7 +37,7 @@ public class DLDataUnit extends PamDataUnit {
|
||||
public DLDataUnit(DataUnitBaseData baseData, float[] data) {
|
||||
super(baseData);
|
||||
//System.out.println("DLDataUnit: " + this.getChannelBitmap());
|
||||
this.modelResult = new GenericPrediction(data);
|
||||
this.modelResult = new StandardPrediction(data);
|
||||
}
|
||||
|
||||
public DLDataUnit(DataUnitBaseData baseData, PredictionResult modelResult) {
|
||||
|
@ -7,7 +7,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
import rawDeepLearningClassifier.segmenter.GroupedRawData;
|
||||
|
||||
/**
|
||||
@ -52,7 +52,7 @@ public abstract class DLTaskThread extends Thread {
|
||||
System.out.println("DL TASK THREAD: " + "The queue size is " + queue.size());
|
||||
ArrayList<? extends PamDataUnit> groupedRawData = queue.remove(0);
|
||||
|
||||
ArrayList<GenericPrediction> modelResult = dlModelWorker.runModel(groupedRawData,
|
||||
ArrayList<StandardPrediction> modelResult = dlModelWorker.runModel(groupedRawData,
|
||||
groupedRawData.get(0).getParentDataBlock().getSampleRate(), 0); //TODO channel?
|
||||
|
||||
for (int i =0; i<modelResult.size(); i++) {
|
||||
@ -79,7 +79,7 @@ public abstract class DLTaskThread extends Thread {
|
||||
* @param soundSpotResult - the new result.
|
||||
* @param groupedRawData - the grouped data unit.
|
||||
*/
|
||||
public abstract void newDLResult(GenericPrediction soundSpotResult, PamDataUnit groupedRawData);
|
||||
public abstract void newDLResult(StandardPrediction soundSpotResult, PamDataUnit groupedRawData);
|
||||
|
||||
/**
|
||||
* Get the grouped data queue
|
||||
|
@ -19,7 +19,7 @@ import rawDeepLearningClassifier.DLStatus;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericDLClassifier;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
import rawDeepLearningClassifier.layoutFX.DLSettingsPane;
|
||||
import rawDeepLearningClassifier.segmenter.GroupedRawData;
|
||||
import warnings.PamWarning;
|
||||
@ -73,7 +73,7 @@ public abstract class StandardClassifierModel implements DLClassiferModel, PamSe
|
||||
if ((PamCalendar.isSoundFile() && !forceQueue) || dlControl.isViewer()) {
|
||||
//run the model
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<GenericPrediction> modelResult = (ArrayList<GenericPrediction>) getDLWorker().runModel(groupedRawData,
|
||||
ArrayList<StandardPrediction> modelResult = (ArrayList<StandardPrediction>) getDLWorker().runModel(groupedRawData,
|
||||
groupedRawData.get(0).getParentDataBlock().getSampleRate(), 0);
|
||||
|
||||
if (modelResult==null) {
|
||||
@ -106,7 +106,7 @@ public abstract class StandardClassifierModel implements DLClassiferModel, PamSe
|
||||
|
||||
@Override
|
||||
public void prepModel() {
|
||||
// System.out.println("STANDARD CLASSIFIER MODEL PREP MODEL! !!!");
|
||||
System.out.println("STANDARD CLASSIFIER MODEL PREP MODEL! !!!: " + getDLParams().modelPath);
|
||||
// StandardModelParams oldParams = getDLParams().clone();
|
||||
|
||||
getDLWorker().prepModel(getDLParams(), dlControl);
|
||||
@ -115,6 +115,7 @@ public abstract class StandardClassifierModel implements DLClassiferModel, PamSe
|
||||
if (getDLWorker().isModelNull()) {
|
||||
dlClassifierWarning.setWarningMessage("There is no loaded " + getName() + " classifier model. " + getName() + " disabled.");
|
||||
WarningSystem.getWarningSystem().addWarning(dlClassifierWarning);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -187,7 +188,7 @@ public abstract class StandardClassifierModel implements DLClassiferModel, PamSe
|
||||
public DLStatus setModel(URI uri) {
|
||||
//will change the params if we do not clone.
|
||||
StandardModelParams.setModel(uri, this.getDLParams());
|
||||
this.prepModel();
|
||||
this.getDLWorker().prepModel(getDLParams(), dlControl);
|
||||
return getModelStatus();
|
||||
}
|
||||
|
||||
@ -205,14 +206,58 @@ public abstract class StandardClassifierModel implements DLClassiferModel, PamSe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newDLResult(GenericPrediction soundSpotResult, PamDataUnit groupedRawData) {
|
||||
soundSpotResult.setClassNameID(GenericDLClassifier.getClassNameIDs(getDLParams()));
|
||||
soundSpotResult.setBinaryClassification(GenericDLClassifier.isBinaryResult(soundSpotResult, getDLParams()));
|
||||
public void newDLResult(StandardPrediction soundSpotResult, PamDataUnit groupedRawData) {
|
||||
soundSpotResult.setClassNameID(getClassNameIDs(getDLParams()));
|
||||
soundSpotResult.setBinaryClassification(isDecision(soundSpotResult, getDLParams()));
|
||||
newResult(soundSpotResult, groupedRawData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a decision on whether a result passed a decision
|
||||
* @param modelResult - the model result.
|
||||
* @param modelParmas - the model parameters.
|
||||
* @return true if a threshold has been met.
|
||||
*/
|
||||
public boolean isDecision(StandardPrediction modelResult, StandardModelParams modelParmas) {
|
||||
return isBinaryResult(modelResult, modelParmas);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the class name IDs
|
||||
* @return an array of class name IDs
|
||||
*/
|
||||
public static short[] getClassNameIDs(StandardModelParams standardModelParams) {
|
||||
if (standardModelParams.classNames==null || standardModelParams.classNames.length<=0) return null;
|
||||
short[] nameIDs = new short[standardModelParams.classNames.length];
|
||||
for (int i = 0 ; i<standardModelParams.classNames.length; i++) {
|
||||
nameIDs[i] = standardModelParams.classNames[i].ID;
|
||||
}
|
||||
return nameIDs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a model passes a binary test...
|
||||
* @param modelResult - the model results
|
||||
* @return the model results.
|
||||
*/
|
||||
public static boolean isBinaryResult(StandardPrediction modelResult, StandardModelParams genericModelParams) {
|
||||
for (int i=0; i<modelResult.getPrediction().length; i++) {
|
||||
//System.out.println("Binary Classification: " + genericModelParams.binaryClassification.length);
|
||||
|
||||
if (modelResult.getPrediction()[i]>genericModelParams.threshold && genericModelParams.binaryClassification[i]) {
|
||||
// System.out.println("SoundSpotClassifier: prediciton: " + i + " passed threshold with val: " + modelResult.getPrediction()[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void closeModel() {
|
||||
@ -225,9 +270,9 @@ public abstract class StandardClassifierModel implements DLClassiferModel, PamSe
|
||||
* @param modelResult - the model result;
|
||||
* @param groupedRawData - the grouped raw data.
|
||||
*/
|
||||
protected void newResult(GenericPrediction modelResult, PamDataUnit groupedRawData) {
|
||||
protected void newResult(StandardPrediction modelResult, PamDataUnit groupedRawData) {
|
||||
if (groupedRawData instanceof GroupedRawData) {
|
||||
this.dlControl.getDLClassifyProcess().newModelResult(modelResult, (GroupedRawData) groupedRawData);
|
||||
this.dlControl.getDLClassifyProcess().newRawModelResult(modelResult, (GroupedRawData) groupedRawData);
|
||||
}
|
||||
}
|
||||
//
|
||||
|
@ -15,7 +15,7 @@ import rawDeepLearningClassifier.DLControl;
|
||||
import rawDeepLearningClassifier.dlClassification.DLClassiferModel;
|
||||
import rawDeepLearningClassifier.dlClassification.StandardClassifierModel;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
import rawDeepLearningClassifier.layoutFX.DLCLassiferModelUI;
|
||||
|
||||
/**
|
||||
@ -53,7 +53,7 @@ public class SoundSpotClassifier extends StandardClassifierModel {
|
||||
/**
|
||||
* The deep learning model worker.
|
||||
*/
|
||||
private DLModelWorker<GenericPrediction> soundSpotWorker;
|
||||
private DLModelWorker<StandardPrediction> soundSpotWorker;
|
||||
|
||||
|
||||
public SoundSpotClassifier(DLControl dlControl) {
|
||||
@ -171,7 +171,7 @@ public class SoundSpotClassifier extends StandardClassifierModel {
|
||||
|
||||
|
||||
@Override
|
||||
public DLModelWorker<GenericPrediction> getDLWorker() {
|
||||
public DLModelWorker<StandardPrediction> getDLWorker() {
|
||||
if (soundSpotWorker==null) {
|
||||
soundSpotWorker = new SoundSpotWorker();
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package rawDeepLearningClassifier.dlClassification.animalSpot;
|
||||
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
|
||||
/**
|
||||
* Result from the SoundSpotClassifier.
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class SoundSpotResult extends GenericPrediction {
|
||||
public class SoundSpotResult extends StandardPrediction {
|
||||
|
||||
public SoundSpotResult(float[] prob, boolean isBinary) {
|
||||
super(prob, isBinary);
|
||||
|
@ -7,7 +7,7 @@ import org.jamdev.jdl4pam.animalSpot.AnimalSpotParams;
|
||||
|
||||
import rawDeepLearningClassifier.DLControl;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
|
||||
|
||||
/**
|
||||
@ -19,7 +19,7 @@ import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class SoundSpotWorker extends DLModelWorker<GenericPrediction> {
|
||||
public class SoundSpotWorker extends DLModelWorker<StandardPrediction> {
|
||||
|
||||
|
||||
/**
|
||||
|
@ -32,6 +32,7 @@ import pamViewFX.fxNodes.PamSpinner;
|
||||
import pamViewFX.fxNodes.PamVBox;
|
||||
import pamViewFX.validator.PamValidator;
|
||||
import rawDeepLearningClassifier.dlClassification.DLClassiferModel;
|
||||
import rawDeepLearningClassifier.dlClassification.StandardClassifierModel;
|
||||
|
||||
/**
|
||||
* Settings pane for SoundSpot
|
||||
@ -163,7 +164,7 @@ public abstract class StandardModelPane extends SettingsPane<StandardModelParams
|
||||
defaultSegmentLenChanged();
|
||||
//only set the hop if the user physically changes the toggle switch. This is not included in defaultSegmentLenChanged
|
||||
//becuase defaultSegmentLenChanged can be called from elsewhere
|
||||
int defaultsamples = getDefaultSamples();
|
||||
int defaultsamples = getDefaultSamples(dlClassifierModel, paramsClone);
|
||||
dlClassifierModel.getDLControl().getSettingsPane().getHopLenSpinner().getValueFactory().setValue((int) defaultsamples/2);
|
||||
});
|
||||
usedefaultSeg.setPadding(new Insets(0,0,0,0));
|
||||
@ -269,7 +270,7 @@ public abstract class StandardModelPane extends SettingsPane<StandardModelParams
|
||||
|
||||
// float sR = dlClassifierModel.getDLControl().getSettingsPane().getSelectedParentDataBlock().getSampleRate();
|
||||
|
||||
int defaultsamples = getDefaultSamples();
|
||||
int defaultsamples = getDefaultSamples(dlClassifierModel, paramsClone);
|
||||
|
||||
//work out the window length in samples
|
||||
dlClassifierModel.getDLControl().getSettingsPane().getSegmentLenSpinner().getValueFactory().setValue(defaultsamples);
|
||||
@ -282,7 +283,7 @@ public abstract class StandardModelPane extends SettingsPane<StandardModelParams
|
||||
}
|
||||
}
|
||||
|
||||
private int getDefaultSamples() {
|
||||
public static int getDefaultSamples(DLClassiferModel dlClassifierModel, StandardModelParams paramsClone) {
|
||||
float sR = dlClassifierModel.getDLControl().getSettingsPane().getSelectedParentDataBlock().getSampleRate();
|
||||
int defaultsamples = (int) (paramsClone.defaultSegmentLen.doubleValue()*sR/1000.0);
|
||||
return defaultsamples;
|
||||
|
@ -14,7 +14,7 @@ import rawDeepLearningClassifier.dlClassification.DLClassiferModel;
|
||||
import rawDeepLearningClassifier.dlClassification.StandardClassifierModel;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.ketos.KetosDLParams;
|
||||
import rawDeepLearningClassifier.dlClassification.ketos.KetosUI;
|
||||
import rawDeepLearningClassifier.layoutFX.DLCLassiferModelUI;
|
||||
@ -81,7 +81,7 @@ public abstract class ArchiveModelClassifier extends StandardClassifierModel {
|
||||
|
||||
|
||||
@Override
|
||||
public DLModelWorker<GenericPrediction> getDLWorker() {
|
||||
public DLModelWorker<StandardPrediction> getDLWorker() {
|
||||
return getModelWorker();
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ import rawDeepLearningClassifier.DLControl;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -58,10 +58,11 @@ public class ArchiveModelWorker extends GenericModelWorker {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the model
|
||||
* Prepare the model.
|
||||
* Note it is important to put a synchonized here or the model loading can fail.
|
||||
*/
|
||||
@Override
|
||||
public void prepModel(StandardModelParams dlParams, DLControl dlControl) {
|
||||
public synchronized void prepModel(StandardModelParams dlParams, DLControl dlControl) {
|
||||
//ClassLoader origCL = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
|
||||
@ -128,6 +129,7 @@ public class ArchiveModelWorker extends GenericModelWorker {
|
||||
// }
|
||||
|
||||
//generate the transforms from the KetosParams objects.
|
||||
System.out.println(modelParams.dlTransforms);
|
||||
ArrayList<DLTransform> transforms = DLTransformsFactory.makeDLTransforms(modelParams.dlTransforms);
|
||||
|
||||
// ///HACK here for now to fix an issue with dB and Ketos transforms having zero length somehow...
|
||||
@ -197,6 +199,7 @@ public class ArchiveModelWorker extends GenericModelWorker {
|
||||
* @throws IOException
|
||||
*/
|
||||
public ArchiveModel loadModel(String currentPath2) throws MalformedModelException, IOException {
|
||||
|
||||
return new SimpleArchiveModel(new File(currentPath2));
|
||||
}
|
||||
|
||||
@ -228,8 +231,8 @@ public class ArchiveModelWorker extends GenericModelWorker {
|
||||
|
||||
|
||||
@Override
|
||||
public GenericPrediction makeModelResult(float[] prob, double time) {
|
||||
GenericPrediction prediction = new GenericPrediction(prob);
|
||||
public StandardPrediction makeModelResult(float[] prob, double time) {
|
||||
StandardPrediction prediction = new StandardPrediction(prob);
|
||||
prediction.setAnalysisTime(time);
|
||||
return prediction;
|
||||
}
|
||||
@ -251,6 +254,10 @@ public class ArchiveModelWorker extends GenericModelWorker {
|
||||
public ArchiveModel getModel() {
|
||||
return dlModel;
|
||||
}
|
||||
|
||||
protected void setModel(ArchiveModel dlModel) {
|
||||
this.dlModel = dlModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isModelNull() {
|
||||
|
@ -8,12 +8,13 @@ import org.jamdev.jdl4pam.transforms.DLTransformsFactory;
|
||||
import org.jamdev.jdl4pam.transforms.DLTransfromParams;
|
||||
|
||||
import PamController.PamControlledUnitSettings;
|
||||
import PamController.PamSettingManager;
|
||||
import rawDeepLearningClassifier.DLControl;
|
||||
import rawDeepLearningClassifier.dlClassification.DLClassiferModel;
|
||||
import rawDeepLearningClassifier.dlClassification.StandardClassifierModel;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
import rawDeepLearningClassifier.layoutFX.DLCLassiferModelUI;
|
||||
|
||||
/**
|
||||
@ -37,6 +38,9 @@ public class DelphinIDClassifier extends StandardClassifierModel {
|
||||
|
||||
public DelphinIDClassifier(DLControl dlControl) {
|
||||
super(dlControl);
|
||||
|
||||
//load the previous settings
|
||||
PamSettingManager.getInstance().registerSettings(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,6 +90,15 @@ public class DelphinIDClassifier extends StandardClassifierModel {
|
||||
return delphinIDParams;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isDecision(StandardPrediction modelResult, StandardModelParams modelParmas) {
|
||||
//TODO
|
||||
//DelphinID uses a different decision making process to most of the standard classifiers which just pass a binary threshold.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
@ -96,10 +109,11 @@ public class DelphinIDClassifier extends StandardClassifierModel {
|
||||
|
||||
@Override
|
||||
public boolean restoreSettings(PamControlledUnitSettings pamControlledUnitSettings) {
|
||||
|
||||
DelphinIDParams newParameters = (DelphinIDParams) pamControlledUnitSettings.getSettings();
|
||||
if (newParameters!=null) {
|
||||
delphinIDParams = (DelphinIDParams) newParameters.clone();
|
||||
//System.out.println("SoundSpot have been restored. : " + soundSpotParmas.classNames);
|
||||
// System.out.println("DELPHINID have been restored. : " + delphinIDParams.modelPath);
|
||||
if (delphinIDParams.dlTransfromParams!=null) {
|
||||
delphinIDParams.dlTransfroms = DLTransformsFactory.makeDLTransforms((ArrayList<DLTransfromParams>) delphinIDParams.dlTransfromParams);
|
||||
}
|
||||
@ -111,7 +125,7 @@ public class DelphinIDClassifier extends StandardClassifierModel {
|
||||
|
||||
|
||||
@Override
|
||||
public DLModelWorker<GenericPrediction> getDLWorker() {
|
||||
public DLModelWorker<StandardPrediction> getDLWorker() {
|
||||
if (delphinIDWorker==null) {
|
||||
delphinIDWorker = new DelphinIDWorker();
|
||||
}
|
||||
|
@ -1,13 +1,26 @@
|
||||
package rawDeepLearningClassifier.dlClassification.delphinID;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import PamController.SettingsPane;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.control.Spinner;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import pamViewFX.PamGuiManagerFX;
|
||||
import pamViewFX.fxGlyphs.PamGlyphDude;
|
||||
import pamViewFX.fxNodes.PamHBox;
|
||||
import pamViewFX.fxNodes.PamSpinner;
|
||||
import pamViewFX.fxNodes.PamVBox;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelPane;
|
||||
|
||||
/**
|
||||
* Settings pane for delphin ID.
|
||||
@ -15,60 +28,141 @@ import pamViewFX.fxNodes.PamVBox;
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class DelphinIDPane extends SettingsPane<DelphinIDParams> {
|
||||
|
||||
public class DelphinIDPane extends SettingsPane<DelphinIDParams> {
|
||||
|
||||
/**
|
||||
* The main pane.
|
||||
*/
|
||||
private Pane mainPane;
|
||||
|
||||
|
||||
/**
|
||||
* Reference to the delphinID classifier
|
||||
*/
|
||||
private DelphinIDClassifier delphinUIClassifier;
|
||||
|
||||
private PamSpinner<Double> detectionDensitySpinner;
|
||||
|
||||
private Slider decisionSlider;
|
||||
|
||||
private DelphinIDParams currentParams;
|
||||
|
||||
private File currentSelectedFile;
|
||||
|
||||
public DelphinIDPane(DelphinIDClassifier delphinUIClassifier) {
|
||||
super(null);
|
||||
this.delphinUIClassifier = delphinUIClassifier;
|
||||
mainPane = createPane();
|
||||
}
|
||||
|
||||
|
||||
private Pane createPane() {
|
||||
|
||||
|
||||
//font to use for title labels.
|
||||
Font font= Font.font(null, FontWeight.BOLD, 11);
|
||||
|
||||
Node classifierIcon;
|
||||
classifierIcon = delphinUIClassifier.getModelUI().getIcon();
|
||||
|
||||
|
||||
Label classifierIcon;
|
||||
classifierIcon = new Label("DelphinID");
|
||||
PamGuiManagerFX.titleFont2style(classifierIcon);
|
||||
//todo - will need to figure out colour of icon using CSS.
|
||||
Node icon = PamGlyphDude.createPamIcon("mdi2r-rss", Color.BLACK, PamGuiManagerFX.iconSize);
|
||||
icon.getStyleClass().add(getName());
|
||||
icon.setRotate(45);
|
||||
classifierIcon.setGraphic(icon);
|
||||
classifierIcon.setContentDisplay(ContentDisplay.RIGHT);
|
||||
|
||||
|
||||
// String settings = currentParams.toString();
|
||||
// classifierIcon.setTooltip(new Tooltip(settings));
|
||||
|
||||
PamVBox vBox = new PamVBox();
|
||||
vBox.setSpacing(5.);
|
||||
|
||||
|
||||
/**Classification thresholds etc to set.**/
|
||||
Label detectionDensity = new Label("Detection Density");
|
||||
detectionDensity.setFont(font);
|
||||
String tooltip = "Set the minimum detection density to attempt to classify.";
|
||||
detectionDensity.setTooltip(new Tooltip(tooltip));
|
||||
detectionDensitySpinner = new PamSpinner<Double>(0.0, 1.0, 0.3, 0.1);
|
||||
detectionDensitySpinner.setPrefWidth(70);
|
||||
detectionDensitySpinner.setEditable(true);
|
||||
detectionDensitySpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
|
||||
|
||||
PamHBox minDensityHolder = new PamHBox();
|
||||
minDensityHolder.setAlignment(Pos.CENTER_RIGHT);
|
||||
minDensityHolder.setSpacing(5);
|
||||
Label minDensity = new Label("Min. density");
|
||||
minDensityHolder.getChildren().addAll(minDensity, detectionDensitySpinner);
|
||||
|
||||
/**Classification thresholds etc to set.**/
|
||||
Label classiferInfoLabel2 = new Label("Decision Threshold");
|
||||
classiferInfoLabel2.setTooltip(new Tooltip("Set the minimum prediciton value for selected classes. If a prediction exceeds this value "
|
||||
+ "a detection will be saved."));
|
||||
classiferInfoLabel2.setFont(font);
|
||||
|
||||
|
||||
vBox.getChildren().addAll(classifierIcon, classiferInfoLabel2);
|
||||
|
||||
|
||||
decisionSlider = new Slider();
|
||||
decisionSlider.setMin(0);
|
||||
decisionSlider.setMax(1);
|
||||
decisionSlider.setMajorTickUnit(0.2);
|
||||
decisionSlider.setMinorTickCount(10);
|
||||
decisionSlider.valueProperty().addListener((obsVal, oldVal, newVal)->{
|
||||
classiferInfoLabel2.setText(String.format("Decision Threshold %.2f", newVal));
|
||||
});
|
||||
decisionSlider.setShowTickMarks(true);
|
||||
decisionSlider.setShowTickLabels(true);
|
||||
|
||||
vBox.getChildren().addAll(classifierIcon, detectionDensity, minDensityHolder, classiferInfoLabel2, decisionSlider);
|
||||
|
||||
return vBox;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DelphinIDParams getParams(DelphinIDParams currParams) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
currParams.threshold = decisionSlider.getValue();
|
||||
currParams.minDetectionDensity = detectionDensitySpinner.getValue();
|
||||
return currParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParams(DelphinIDParams input) {
|
||||
// TODO Auto-generated method stub
|
||||
this.currentParams = input;
|
||||
decisionSlider.setValue(input.threshold);
|
||||
detectionDensitySpinner.getValueFactory().setValue(input.minDetectionDensity);
|
||||
|
||||
if (input.modelPath!=null) {
|
||||
//this might
|
||||
currentSelectedFile = new File(currentParams.modelPath);
|
||||
|
||||
//this might change the paramsClone values if the model contains pamguard compatible metadata
|
||||
newModelSelected(currentSelectedFile);
|
||||
}
|
||||
}
|
||||
|
||||
private void newModelSelected(File currentSelectedFile2) {
|
||||
if (currentParams!=null && currentParams.defaultSegmentLen != null) {
|
||||
|
||||
//System.out.println("Defualt segment length: " + paramsClone.defaultSegmentLen);
|
||||
|
||||
//cannot use because, if the parent datablock has changed, samplerate will be out of date.
|
||||
// int defaultsamples = (int) this.soundSpotClassifier.millis2Samples(paramsClone.defaultSegmentLen);
|
||||
|
||||
|
||||
// float sR = dlClassifierModel.getDLControl().getSettingsPane().getSelectedParentDataBlock().getSampleRate();
|
||||
|
||||
int defaultsamples = StandardModelPane.getDefaultSamples(delphinUIClassifier, currentParams);
|
||||
|
||||
//work out the window length in samples
|
||||
delphinUIClassifier.getDLControl().getSettingsPane().getSegmentLenSpinner().getValueFactory().setValue(defaultsamples);
|
||||
// dlClassifierModel.getDLControl().getSettingsPane().getHopLenSpinner().getValueFactory().setValue((int) defaultsamples/2);
|
||||
|
||||
delphinUIClassifier.getDLControl().getSettingsPane().getSegmentLenSpinner().setDisable(true);
|
||||
}
|
||||
else {
|
||||
delphinUIClassifier.getDLControl().getSettingsPane().getSegmentLenSpinner().setDisable(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "delphinIDParams";
|
||||
@ -82,7 +176,7 @@ public class DelphinIDPane extends SettingsPane<DelphinIDParams> {
|
||||
@Override
|
||||
public void paneInitialized() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,5 +8,11 @@ public class DelphinIDParams extends StandardModelParams {
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The minimum detection density.
|
||||
*/
|
||||
public double minDetectionDensity = 0.3;
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package rawDeepLearningClassifier.dlClassification.delphinID;
|
||||
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
|
||||
public class DelphinIDPrediction extends GenericPrediction{
|
||||
public class DelphinIDPrediction extends StandardPrediction{
|
||||
|
||||
public DelphinIDPrediction(float[] prob) {
|
||||
super(prob);
|
||||
|
@ -0,0 +1,138 @@
|
||||
package rawDeepLearningClassifier.dlClassification.delphinID;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.jamdev.jdl4pam.utils.DLMatFile;
|
||||
|
||||
import PamUtils.PamArrayUtils;
|
||||
import PamguardMVC.DataUnitBaseData;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup;
|
||||
import us.hebi.matlab.mat.format.Mat5;
|
||||
import us.hebi.matlab.mat.format.Mat5File;
|
||||
import us.hebi.matlab.mat.types.MatFile;
|
||||
import us.hebi.matlab.mat.types.Matrix;
|
||||
import us.hebi.matlab.mat.types.Struct;
|
||||
import whistlesAndMoans.AbstractWhistleDataUnit;
|
||||
|
||||
|
||||
/**
|
||||
* A delphinID test suite.
|
||||
*
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class DelphinIDTest {
|
||||
|
||||
|
||||
public static class DelphinIDWorkerTest extends DelphinIDWorker {
|
||||
|
||||
private float[][][] lastModelInput;
|
||||
|
||||
|
||||
public float[][][] dataUnits2ModelInput(ArrayList<? extends PamDataUnit> dataUnits, float sampleRate, int iChan){
|
||||
|
||||
float[][][] data = super.dataUnits2ModelInput(dataUnits, sampleRate, iChan);
|
||||
|
||||
this.lastModelInput = data;
|
||||
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public float[][][] getLastModelInput() {
|
||||
return lastModelInput;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Main class for running the test.
|
||||
* @param args - the arguments
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
|
||||
double segLen = 4000.;
|
||||
double segHop = 1000.0;
|
||||
float sampleRate =96000;
|
||||
//unix time from sound file
|
||||
long dataStartMillis = 1340212413000L;
|
||||
|
||||
//path to the .mat containing whistle contours.
|
||||
String whistleContourPath = "D:/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/testencounter415/whistle_contours.mat";
|
||||
|
||||
//the path to the model
|
||||
// String modelPath = "D:/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/testencounter415/whistle_model_2/whistle_4s_415.zip";
|
||||
String modelPath = "D:/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/testencounter415/whistle_model_3/whistle_4s_415_f5.zip";
|
||||
|
||||
|
||||
//the path to the model
|
||||
String matImageSave = "C:/Users/Jamie Macaulay/MATLAB Drive/MATLAB/PAMGUARD/deep_learning/delphinID/whistleimages.mat";
|
||||
|
||||
//create MatFile for saving the image data to.
|
||||
MatFile matFile = Mat5.newMatFile();
|
||||
|
||||
//get the whislte contours form a .mat file.
|
||||
ArrayList<AbstractWhistleDataUnit> whistleContours = DelphinIDUtils.getWhistleContoursMAT(whistleContourPath);
|
||||
|
||||
//segment the whistle detections
|
||||
ArrayList<SegmenterDetectionGroup> segments = DelphinIDUtils.segmentWhsitleData(whistleContours, (long) (dataStartMillis+(9.565*1000.)),
|
||||
segLen, segHop);
|
||||
|
||||
for (int i=0; i<segments.size(); i++) {
|
||||
System.out.println("Segment " + i + " contains " + segments.get(i).getSubDetectionsCount() + " whistles");
|
||||
}
|
||||
|
||||
//prepare the model - this loads the zip file and loads the correct transforms.
|
||||
DelphinIDWorkerTest model = DelphinIDUtils.prepDelphinIDModel(modelPath);
|
||||
model.setEnableSoftMax(false);
|
||||
|
||||
|
||||
//initialise strcuture for image data
|
||||
Struct imageStruct = Mat5.newStruct(segments.size(), 1);
|
||||
|
||||
for (int i=0; i<segments.size(); i++) {
|
||||
|
||||
//remember that the input is a stack of detections to be run by thge model at once - Here we want to do each one individually.
|
||||
ArrayList<SegmenterDetectionGroup> aSegment = new ArrayList<SegmenterDetectionGroup>();
|
||||
aSegment.add(segments.get(i));
|
||||
|
||||
//the prediciton.
|
||||
ArrayList<StandardPrediction> predicition = model.runModel(aSegment, sampleRate, 1);
|
||||
|
||||
float[] output = predicition.get(0).getPrediction();
|
||||
|
||||
System.out.println();
|
||||
System.out.print("Segment: " + i + " " + (aSegment.get(0).getSegmentStartMillis()-dataStartMillis)/1000. + "s ");
|
||||
for (int j=0; j<output.length; j++) {
|
||||
System.out.print(" " + output[j]);
|
||||
}
|
||||
|
||||
Matrix image = DLMatFile.array2Matrix(PamArrayUtils.float2Double(model.getLastModelInput()[0]));
|
||||
imageStruct.set("image", i, image);
|
||||
imageStruct.set("startmillis", i, Mat5.newScalar(aSegment.get(0).getSegmentStartMillis()));
|
||||
imageStruct.set("startseconds", i, Mat5.newScalar((aSegment.get(0).getSegmentStartMillis()-dataStartMillis)/1000.));
|
||||
imageStruct.set("prediction", i, DLMatFile.array2Matrix(PamArrayUtils.float2Double(output)));
|
||||
|
||||
}
|
||||
|
||||
matFile.addArray("whistle_images", imageStruct);
|
||||
// Serialize to disk using default configurations
|
||||
try {
|
||||
Mat5.writeToFile(matFile,matImageSave);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// for (int i=0; i<whistleContours.size(); i++) {
|
||||
// System.out.println("Whislte: " + i);
|
||||
// PamArrayUtils.printArray(whistleContours.get(i).getFreqsHz());
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package rawDeepLearningClassifier.dlClassification.delphinID;
|
||||
|
||||
|
@ -0,0 +1,394 @@
|
||||
package rawDeepLearningClassifier.dlClassification.delphinID;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import PamUtils.FileList;
|
||||
import PamUtils.PamArrayUtils;
|
||||
import PamUtils.TxtFileUtils;
|
||||
import PamguardMVC.DataUnitBaseData;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.delphinID.DelphinIDTest.DelphinIDWorkerTest;
|
||||
import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup;
|
||||
import us.hebi.matlab.mat.format.Mat5;
|
||||
import us.hebi.matlab.mat.format.Mat5File;
|
||||
import us.hebi.matlab.mat.types.Matrix;
|
||||
import us.hebi.matlab.mat.types.Struct;
|
||||
import whistlesAndMoans.AbstractWhistleDataUnit;
|
||||
|
||||
/**
|
||||
* A bunch of utility functions that a re useful for testing and running
|
||||
* DelphinID models
|
||||
*/
|
||||
public class DelphinIDUtils {
|
||||
|
||||
public static DelphinIDWorkerTest prepDelphinIDModel(String modelPath) {
|
||||
|
||||
//create the delphinID worker.
|
||||
DelphinIDWorkerTest delphinIDWorker = new DelphinIDWorkerTest();
|
||||
|
||||
StandardModelParams params = new StandardModelParams();
|
||||
params.modelPath = modelPath;
|
||||
|
||||
//prepare the model
|
||||
delphinIDWorker.prepModel(params, null);
|
||||
|
||||
return delphinIDWorker;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load whistle contours from a MAT file. ()
|
||||
*
|
||||
* @param filePath - the file path.
|
||||
*
|
||||
* @return a list of whistle contour objects from the mat file.
|
||||
*/
|
||||
public static ArrayList<AbstractWhistleDataUnit> getWhistleContoursMAT(String filePath){
|
||||
|
||||
ArrayList<AbstractWhistleDataUnit> contours = new ArrayList<AbstractWhistleDataUnit>();
|
||||
|
||||
// SegmenterDetectionGroup segmenterDetectionGroup = new SegmenterDetectionGroup(0, 0, 0, 0);
|
||||
|
||||
// Read scalar from nested struct
|
||||
try {
|
||||
Mat5File matFile = Mat5.readFromFile(filePath);
|
||||
|
||||
Struct whistlesStruct = matFile.getStruct("whistles");
|
||||
|
||||
double fftLen = matFile.getMatrix("fftlen").getDouble(0);
|
||||
double fftHop = matFile.getMatrix("ffthop").getDouble(0);
|
||||
double sampleRate = matFile.getMatrix("samplerate").getDouble(0);
|
||||
|
||||
return getWhistleContoursMAT(whistlesStruct, fftLen, fftHop, sampleRate);
|
||||
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return contours;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load whistle contours from a MATLAB struct
|
||||
|
||||
* @param whistlesStruct - a struct containing a list of whistle contours
|
||||
* @param fftLen- the fft length in samples
|
||||
* @param fftHop - the fft hop in samples.
|
||||
* @param sampleRate - the sample rate in samples per second.
|
||||
* @return a list of whistle contour objects from the struct.
|
||||
*/
|
||||
public static ArrayList<AbstractWhistleDataUnit> getWhistleContoursMAT(Struct whistlesStruct, double fftLen, double fftHop, double sampleRate){
|
||||
|
||||
ArrayList<AbstractWhistleDataUnit> contours = new ArrayList<AbstractWhistleDataUnit>();
|
||||
|
||||
|
||||
for (int i=0; i< whistlesStruct.getNumElements(); i++) {
|
||||
DataUnitBaseData basicData = new DataUnitBaseData();
|
||||
|
||||
long timeMillis = ((Matrix)whistlesStruct.get("millis", i)).getLong(0);
|
||||
basicData.setTimeMilliseconds(timeMillis);
|
||||
|
||||
long sampleDuration = ((Matrix)whistlesStruct.get("sampleDuration", i)).getLong(0);
|
||||
basicData.setSampleDuration(sampleDuration);
|
||||
|
||||
basicData.setMillisecondDuration(1000.*(sampleDuration/sampleRate));
|
||||
|
||||
int channelMap = ((Matrix)whistlesStruct.get("channelMap", i)).getInt(0);
|
||||
basicData.setChannelBitmap(channelMap);
|
||||
|
||||
long uid = ((Matrix)whistlesStruct.get("UID", i)).getLong(0);
|
||||
basicData.setUID(uid);
|
||||
|
||||
long startSample = ((Matrix)whistlesStruct.get("startSample", i)).getLong(0);
|
||||
basicData.setStartSample(startSample);
|
||||
|
||||
int nSlices = ((Matrix)whistlesStruct.get("nSlices", i)).getInt(0);
|
||||
|
||||
double[] freq = new double[nSlices];
|
||||
double[] times = new double[nSlices];
|
||||
|
||||
Matrix contourStruct = whistlesStruct.getMatrix("contour", i);
|
||||
for (int j=0; j<nSlices; j++) {
|
||||
freq[j] = contourStruct.getDouble(j)*sampleRate/fftLen;
|
||||
times[j] = j * fftHop /sampleRate;
|
||||
}
|
||||
|
||||
contours.add(new WhistleContourMAT(basicData, freq, times));
|
||||
}
|
||||
|
||||
return contours;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Segment the detections into groups. Note that segments are overlaps so each whistle may belong to multiple segments.
|
||||
* @param whistles - a list of whistles - not necessarily sorted by time.
|
||||
* @param dataStartMillis - the start time of the data in millis i.e. where the first segment starts.
|
||||
* @param segLen - the segment size in milliseconds.
|
||||
* @param segHop - the segment hop in milliseconds.
|
||||
* @return groups of data units within each segment.
|
||||
*/
|
||||
public static ArrayList<SegmenterDetectionGroup> segmentWhsitleData(ArrayList<AbstractWhistleDataUnit> whistles, long dataStartMillis,
|
||||
double segLen, double segHop){
|
||||
|
||||
ArrayList<SegmenterDetectionGroup> group = new ArrayList<SegmenterDetectionGroup>();
|
||||
|
||||
//find the maximum whistle time
|
||||
long maxTime = Long.MIN_VALUE;
|
||||
long endTime = 0;
|
||||
for (AbstractWhistleDataUnit whislte: whistles) {
|
||||
endTime = (long) (whislte.getTimeMilliseconds()+whislte.getDurationInMilliseconds());
|
||||
if (endTime>maxTime) maxTime=endTime;
|
||||
}
|
||||
|
||||
long segStart = dataStartMillis;
|
||||
long segEnd = (long) (segStart+segLen);
|
||||
|
||||
long whistleStart;
|
||||
long whistleEnd;
|
||||
SegmenterDetectionGroup whistleGroup;
|
||||
while (segStart<endTime){
|
||||
|
||||
whistleGroup = new SegmenterDetectionGroup(segStart, 1, segEnd, segLen);
|
||||
|
||||
for (AbstractWhistleDataUnit whislte: whistles) {
|
||||
whistleStart = whislte.getTimeMilliseconds();
|
||||
whistleEnd = (long) (whislte.getTimeMilliseconds() + whislte.getDurationInMilliseconds());
|
||||
|
||||
if ((whistleStart>=segStart && whistleStart<segEnd) || ((whistleEnd>=segStart && whistleEnd<segEnd))){
|
||||
//some part of the whistle is in the segment.
|
||||
whistleGroup.addSubDetection(whislte);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
group.add(whistleGroup);
|
||||
|
||||
// System.out.println("SegStart: " + (segStart - dataStartMillis));
|
||||
|
||||
segStart = (long) (segStart+segHop);
|
||||
segEnd = (long) (segStart+segLen);
|
||||
}
|
||||
|
||||
return group;
|
||||
|
||||
}
|
||||
|
||||
public static class WhistleContourMAT extends AbstractWhistleDataUnit {
|
||||
|
||||
private double[] freq;
|
||||
private double[] times;
|
||||
|
||||
public WhistleContourMAT(DataUnitBaseData basicData, double[] freq, double[] times) {
|
||||
super(basicData);
|
||||
this.freq=freq;
|
||||
this.times=times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSliceCount() {
|
||||
return freq.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[] getTimesInSeconds() {
|
||||
return times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[] getFreqsHz() {
|
||||
return freq;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static void generateImages(Struct whistlesStruct, String outName, DelphinIDWorker worker, double fftLen, double fftHop, double sampleRate) {
|
||||
|
||||
double segLen = 4000.;
|
||||
double segHop = 1000.0;
|
||||
|
||||
// ArrayList<ArrayList<Double>> contourData = TxtFileUtils.importCSVData(csvFile);
|
||||
ArrayList<AbstractWhistleDataUnit> whistles = getWhistleContoursMAT(whistlesStruct, fftLen, fftHop, sampleRate);
|
||||
|
||||
//segment the whistle detections
|
||||
ArrayList<SegmenterDetectionGroup> segments = DelphinIDUtils.segmentWhsitleData(whistles, whistles.get(0).getTimeMilliseconds(), segLen, segHop);
|
||||
|
||||
float[][][] images = worker.dataUnits2ModelInput(segments, (float) sampleRate, 0);
|
||||
|
||||
float[][] image;
|
||||
BufferedImage bfImage;
|
||||
double density;
|
||||
for (int k=0; k<images.length; k++) {
|
||||
|
||||
if (segments.get(k).getSubDetectionsCount()<1) {
|
||||
continue;
|
||||
}
|
||||
image = images[k];
|
||||
|
||||
bfImage = new BufferedImage(image[0].length, image.length, BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
// System.out.println("Max of image: " + PamArrayUtils.minmax(image)[1]);
|
||||
|
||||
for(int i = 0; i < image.length; i++) {
|
||||
for(int j = 0; j < image[0].length; j++) {
|
||||
Color myRGB = new Color(image[i][j], image[i][j], image[i][j]);
|
||||
int rgb = myRGB.getRGB();
|
||||
bfImage.setRGB(j,i, rgb);
|
||||
}
|
||||
}
|
||||
|
||||
density = getDensity(segments.get(k));
|
||||
//now save the image
|
||||
String outputPath = String.format("%s_d%.2f_%d.png", outName, density, k);
|
||||
|
||||
File outputfile = new File(outputPath);
|
||||
|
||||
try {
|
||||
ImageIO.write(bfImage, "png", outputfile);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the density of whistles for a segmenter group in the absence of a known fft length and hop.
|
||||
* @param group - the group
|
||||
* @return
|
||||
*/
|
||||
private static double getDensity(SegmenterDetectionGroup group) {
|
||||
//number of whistle bins/number of time bins
|
||||
ArrayList<double[][]> contour = Whistles2Image.whistContours2Points(group);
|
||||
|
||||
//time bin length from the first contour
|
||||
double[] times = new double[contour.get(0).length-1];
|
||||
for (int i=0; i<times.length; i++) {
|
||||
times[i]=1000.*(contour.get(0)[i+1][0] - contour.get(0)[i][0]);
|
||||
}
|
||||
|
||||
double timebinMillis = PamArrayUtils.mean(times);
|
||||
|
||||
double nBins = group.getSegmentDuration()/timebinMillis;
|
||||
|
||||
double nwhistleBins = 0;
|
||||
for (int i=0; i<contour.size(); i++) {
|
||||
nwhistleBins+=contour.get(i).length;
|
||||
}
|
||||
|
||||
// System.out.println("nwhistleBins: " +nwhistleBins + "nBins: " + nBins + " timebinMillis: " + timebinMillis);
|
||||
|
||||
return nwhistleBins/nBins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate training images for DelphinID
|
||||
* @param modelPath
|
||||
* @param whistlefolder
|
||||
* @param imageFolder
|
||||
* @param lineWidth - the line width in pixels to use
|
||||
*/
|
||||
private static void generateTrainingData(String modelPath, String whistlefolder, String imageFolder, double lineWidth) {
|
||||
DelphinIDWorkerTest model = DelphinIDUtils.prepDelphinIDModel(modelPath);
|
||||
model.setEnableSoftMax(false);
|
||||
|
||||
model.getWhistleImageParams().lineWidth=lineWidth;
|
||||
|
||||
FileList filelist = new FileList();
|
||||
|
||||
File folder = new File(whistlefolder);
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
if(listOfFiles != null) {
|
||||
for (int i = 0; i < listOfFiles.length; i++) {
|
||||
if (listOfFiles[i].isDirectory()) {
|
||||
//get a list of csv files
|
||||
// ArrayList<File> csvFiles = filelist.getFileList(listOfFiles[i].getAbsolutePath(), ".mat" , true);
|
||||
|
||||
System.out.println("Directory " + listOfFiles[i].getName());
|
||||
|
||||
|
||||
|
||||
try {
|
||||
|
||||
File file = new File(listOfFiles[i].getPath() + File.separator + "whistles.mat");
|
||||
|
||||
if (!file.exists()) {
|
||||
System.out.println("No whistles.mat for " + listOfFiles[i].getName());
|
||||
continue;
|
||||
}
|
||||
|
||||
Mat5File matFile = Mat5.readFromFile(file);
|
||||
|
||||
Struct whistlesStruct = matFile.getStruct("whistles");
|
||||
|
||||
double fftLen = matFile.getMatrix("fftlen").getDouble(0);
|
||||
double fftHop = matFile.getMatrix("ffthop").getDouble(0);
|
||||
double sampleRate = matFile.getMatrix("samplerate").getDouble(0);
|
||||
|
||||
List<String> fieldNames = whistlesStruct.getFieldNames();
|
||||
|
||||
File outFolder = new File(imageFolder + File.separator + listOfFiles[i].getName());
|
||||
outFolder.mkdir();//make the out folder directory
|
||||
|
||||
Struct whistecontours;
|
||||
for (String name: fieldNames) {
|
||||
System.out.println("Generating images for recording " + name + " from " + listOfFiles[i].getName() + " " + lineWidth);
|
||||
if (!name.equals("fftlen") && !name.equals("ffthop") && !name.equals("samplerate")) {
|
||||
whistecontours = whistlesStruct.get(name);
|
||||
|
||||
generateImages( whistecontours, (outFolder + File.separator + name) , model, fftLen, fftHop, sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
// double[] density = new double[] {0.15 - 1.5};
|
||||
|
||||
//number of whistle bins/number of time bins; either 16 or 21
|
||||
//the e contours as csv files.
|
||||
// String whistlefolder = "/Users/au671271/Library/CloudStorage/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/training/WMD";
|
||||
// String whistlefolder = "D:/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/training/WMD_examples/contours";
|
||||
String whistlefolder = "D:/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/training/WMD/contours";
|
||||
|
||||
//the image folder to save to.
|
||||
// String imageFolder = "/Users/au671271/Library/CloudStorage/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/training/WMD_Images";
|
||||
// String imageFolder = "D:/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/training/WMD_examples/images";
|
||||
String imageFolder = "C:/Users/Jamie Macaulay/Desktop/Tristan_training_images/contour_images";
|
||||
|
||||
//the path to the model
|
||||
// String modelPath = "/Users/au671271/Library/CloudStorage/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/testencounter415/whistle_model_2/whistle_4s_415.zip";
|
||||
String modelPath = "D:/Dropbox/PAMGuard_dev/Deep_Learning/delphinID/testencounter415/whistle_model_2/whistle_4s_415.zip";
|
||||
|
||||
double[] lineWidths = new double[] {6, 7, 10, 15, 20};
|
||||
|
||||
for (double lineWidth:lineWidths) {
|
||||
String imageFolderWidth = (imageFolder + "_"+ String.format("%d",(int)lineWidth));
|
||||
new File(imageFolderWidth).mkdir();
|
||||
generateTrainingData( modelPath, whistlefolder, imageFolderWidth, lineWidth);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,74 +1,209 @@
|
||||
package rawDeepLearningClassifier.dlClassification.delphinID;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.jamdev.jdl4pam.transforms.DLTransform;
|
||||
import org.jamdev.jdl4pam.transforms.DLTransfromParams;
|
||||
import org.jamdev.jdl4pam.transforms.FreqTransform;
|
||||
import org.jamdev.jdl4pam.transforms.DLTransform.DLTransformType;
|
||||
import org.jamdev.jdl4pam.transforms.jsonfile.DLTransformsParser;
|
||||
import org.jamdev.jdl4pam.utils.DLMatFile;
|
||||
import org.jamdev.jdl4pam.utils.DLUtils;
|
||||
import org.jamdev.jpamutils.JamArr;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import PamUtils.PamArrayUtils;
|
||||
import PamguardMVC.PamDataUnit;
|
||||
import ai.djl.Model;
|
||||
import rawDeepLearningClassifier.DLControl;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.archiveModel.ArchiveModelWorker;
|
||||
import rawDeepLearningClassifier.segmenter.GroupedRawData;
|
||||
|
||||
import rawDeepLearningClassifier.dlClassification.delphinID.Whistles2Image.Whistle2ImageParams;
|
||||
import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup;
|
||||
import us.hebi.matlab.mat.format.Mat5;
|
||||
import us.hebi.matlab.mat.types.MatFile;
|
||||
import us.hebi.matlab.mat.types.Matrix;
|
||||
import us.hebi.matlab.mat.types.Struct;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class DelphinIDWorker extends ArchiveModelWorker {
|
||||
|
||||
/**
|
||||
* Parameters for the whistle to image transform.
|
||||
*/
|
||||
private Whistle2ImageParams whistleImageParams;
|
||||
|
||||
/**
|
||||
* Get the whislte to image parameters.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Whistle2ImageParams getWhistleImageParams() {
|
||||
return whistleImageParams;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void prepModel(StandardModelParams dlParams, DLControl dlControl) {
|
||||
//most of the model prep is done in the perent class.
|
||||
super.prepModel(dlParams, dlControl);
|
||||
|
||||
//now have to read the whsitle2image transform to get correct parameters for that.
|
||||
String jsonString = DLTransformsParser.readJSONString(new File(this.getModel().getAudioReprFile()));
|
||||
whistleImageParams = readWhistleImageTransform(new JSONObject(jsonString)) ;
|
||||
if (whistleImageParams==null) {
|
||||
System.err.println("Error: could not find whistle2image transform in DelphinID JSON file. Model will not work.");
|
||||
this.setModel(null); // set model to null to make sure nothing works and errors are thrown
|
||||
}
|
||||
|
||||
dlParams.binaryClassification = new boolean[dlParams.numClasses];
|
||||
for (int i=0; i<dlParams.numClasses; i++) {
|
||||
dlParams.binaryClassification[i]=true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the whistle transform settings- this is not included in the JPAM library because it directly
|
||||
* reference PAMGuard specific detections.
|
||||
*/
|
||||
private Whistle2ImageParams readWhistleImageTransform(JSONObject mainObject) {
|
||||
//first parse the transforms.
|
||||
JSONArray jsonArray = mainObject.getJSONArray("transforms");
|
||||
|
||||
JSONObject jsonObjectParams;
|
||||
for (int i=0; i<jsonArray.length(); i++) {
|
||||
|
||||
String transformName = (String) jsonArray.getJSONObject(i).get("name");
|
||||
|
||||
if (transformName.trim().equals("whistles2image")) {
|
||||
|
||||
jsonObjectParams = (JSONObject) jsonArray.getJSONObject(i).get("params");
|
||||
|
||||
double[] freqLimits = new double[2];
|
||||
double[] size = new double[2];
|
||||
freqLimits[0] = jsonObjectParams.getFloat("minfreq");
|
||||
freqLimits[1] = jsonObjectParams.getFloat("maxfreq");
|
||||
size[0] = jsonObjectParams.getInt("widthpix");
|
||||
size[1] = jsonObjectParams.getInt("heightpix");
|
||||
double lineWidth = jsonObjectParams.getDouble("linewidthpix");
|
||||
|
||||
Whistle2ImageParams whistle2ImageParmas = new Whistle2ImageParams();
|
||||
whistle2ImageParmas.freqLimits = freqLimits;
|
||||
whistle2ImageParmas.size = size;
|
||||
whistle2ImageParmas.lineWidth = lineWidth;
|
||||
|
||||
return whistle2ImageParmas;
|
||||
}
|
||||
}
|
||||
|
||||
//something has gone wrong if we get here.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Struct imageStruct;
|
||||
int count = 0;
|
||||
/**
|
||||
* Tets by exporting results to a .mat file.
|
||||
* @param data
|
||||
* @param aSegment
|
||||
*/
|
||||
private void addIMage2MatFile(double[][] data, SegmenterDetectionGroup aSegment) {
|
||||
long dataStartMillis = 1340212413000L;
|
||||
|
||||
if (imageStruct==null) {
|
||||
imageStruct = Mat5.newStruct(100,1);
|
||||
}
|
||||
Matrix image = DLMatFile.array2Matrix(data);
|
||||
imageStruct.set("image", count, image);
|
||||
imageStruct.set("startmillis", count, Mat5.newScalar(aSegment.getSegmentStartMillis()));
|
||||
imageStruct.set("startseconds", count, Mat5.newScalar((aSegment.getSegmentStartMillis()-dataStartMillis)/1000.));
|
||||
|
||||
count++;
|
||||
|
||||
System.out.println("SAVED " +count + " TO MAT FILE");
|
||||
|
||||
if (count==10) {
|
||||
//create MatFile for saving the image data to.
|
||||
MatFile matFile = Mat5.newMatFile();
|
||||
matFile.addArray("whistle_images", imageStruct);
|
||||
//the path to the model
|
||||
String matImageSave = "C:/Users/Jamie Macaulay/MATLAB Drive/MATLAB/PAMGUARD/deep_learning/delphinID/whistleimages_pg.mat";
|
||||
try {
|
||||
Mat5.writeToFile(matFile,matImageSave);
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public float[][][] dataUnits2ModelInput(ArrayList<? extends PamDataUnit> dataUnits, float sampleRate, int iChan){
|
||||
|
||||
//Get a list of of the model transforms.
|
||||
ArrayList<DLTransform> modelTransforms = getModelTransforms();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<GroupedRawData> whistleGroups = (ArrayList<GroupedRawData>) dataUnits;
|
||||
|
||||
ArrayList<SegmenterDetectionGroup> whistleGroups = (ArrayList<SegmenterDetectionGroup>) dataUnits;
|
||||
|
||||
//the number of chunks.
|
||||
int numChunks = whistleGroups.size();
|
||||
|
||||
//data input into the model - a stack of spectrogram images.
|
||||
float[][][] transformedDataStack = new float[numChunks][][];
|
||||
//
|
||||
// //generate the spectrogram stack.
|
||||
// AudioData soundData;
|
||||
// double[][] transformedData2; //spec data
|
||||
// double[] transformedData1; //waveform data
|
||||
// for (int j=0; j<numChunks; j++) {
|
||||
//
|
||||
// soundData = new AudioData(rawDataUnits.get(j).getRawData()[iChan], sampleRate);
|
||||
//
|
||||
// // for (int i=0; i<modelTransforms.size(); i++) {
|
||||
// // System.out.println("Transfrom type: " + modelTransforms.get(i).getDLTransformType());
|
||||
// // }
|
||||
// //set the sound in the first transform.
|
||||
// ((WaveTransform) modelTransforms.get(0)).setWaveData(soundData);
|
||||
//
|
||||
//// System.out.println("Model transforms:no. " + modelTransforms.size()+ " input sounds len: " + soundData.getLengthInSeconds()
|
||||
//// + " Decimate Params: " + ((WaveTransform) modelTransforms.get(0)).getParams()[0] + "max amplitude sound: " + PamArrayUtils.max(soundData.samples));
|
||||
//
|
||||
// DLTransform transform = modelTransforms.get(0);
|
||||
// for (int i =0; i<modelTransforms.size(); i++) {
|
||||
// transform = modelTransforms.get(i).transformData(transform);
|
||||
//// //TEMP
|
||||
//// if (transform instanceof FreqTransform) {
|
||||
//// transformedData = ((FreqTransform) transform).getSpecTransfrom().getTransformedData();
|
||||
//// System.out.println("DLModelWorker: transform : " + modelTransforms.get(i).getDLTransformType() + " "+ i + transformedData.length + " " + transformedData[0].length + " minmax: " + PamArrayUtils.minmax(transformedData)[0] + " " + PamArrayUtils.minmax(transformedData)[1]);
|
||||
//// }
|
||||
// }
|
||||
//
|
||||
// if (transform instanceof FreqTransform) {
|
||||
// //add a spectrogram to the stacl
|
||||
// transformedData2 = ((FreqTransform) transform).getSpecTransfrom().getTransformedData();
|
||||
// transformedDataStack[j] = DLUtils.toFloatArray(transformedData2);
|
||||
// }
|
||||
// else {
|
||||
// //add wavefrom to the stack = we make the 2nd dimesnion 1.
|
||||
// transformedData1 = ((WaveTransform) transform).getWaveData().getScaledSampleAmplitudes();
|
||||
// transformedDataStack[j] = new float[1][transformedData1.length];
|
||||
// transformedDataStack[j][0] = DLUtils.toFloatArray(transformedData1);
|
||||
// }
|
||||
// }
|
||||
|
||||
double[][] transformedData2; //spectrogram data
|
||||
|
||||
|
||||
for (int j=0; j<numChunks; j++) {
|
||||
|
||||
// System.out.println("Number of whistle to process: " + whistleGroups.get(j).getStartSecond() + "s " + whistleGroups.get(j).getSubDetectionsCount() + " " + whistleGroups.get(j).getSegmentStartMillis());
|
||||
//create the first transform and set then whistle data. Note that the absolute time limits are
|
||||
//contained within the SegmenterDetectionGroup unit.
|
||||
Whistles2Image whistles2Image = new Whistles2Image(whistleGroups.get(j), whistleImageParams);
|
||||
|
||||
//set the spec transform
|
||||
((FreqTransform) modelTransforms.get(0)).setSpecTransfrom(whistles2Image.getSpecTransfrom());
|
||||
|
||||
//process all the transforms.
|
||||
DLTransform transform = modelTransforms.get(0);
|
||||
for (int i =0; i<modelTransforms.size(); i++) {
|
||||
transform = modelTransforms.get(i).transformData(transform);
|
||||
}
|
||||
|
||||
transformedData2 = ((FreqTransform) transform).getSpecTransfrom().getTransformedData();
|
||||
|
||||
//a bit ugly but works.
|
||||
transformedData2 = JamArr.transposeMatrix(transformedData2);
|
||||
|
||||
// System.out.println("DelphinID input image: " + transformedData2.length + " x " + transformedData2[0].length );
|
||||
transformedDataStack[j] = DLUtils.toFloatArray(transformedData2);
|
||||
|
||||
// //TEMP
|
||||
// try {
|
||||
// addIMage2MatFile(transformedData2, whistleGroups.get(j));
|
||||
// }
|
||||
// catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
return transformedDataStack;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package rawDeepLearningClassifier.dlClassification.delphinID;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -10,7 +8,6 @@ import javax.swing.JPanel;
|
||||
import PamController.SettingsPane;
|
||||
import javafx.scene.Node;
|
||||
import javafx.stage.FileChooser.ExtensionFilter;
|
||||
import pamViewFX.fxGlyphs.PamSVGIcon;
|
||||
import rawDeepLearningClassifier.layoutFX.DLCLassiferModelUI;
|
||||
|
||||
/**
|
||||
@ -83,24 +80,25 @@ public class DelphinUI implements DLCLassiferModelUI {
|
||||
|
||||
@Override
|
||||
public Node getIcon() {
|
||||
if (icon==null) {
|
||||
PamSVGIcon iconMaker= new PamSVGIcon();
|
||||
PamSVGIcon svgsprite;
|
||||
try {
|
||||
svgsprite = iconMaker.create(getClass().getResource("/Resources/delphinid_logo01.svg").toURI().toURL());
|
||||
icon = svgsprite.getSpriteNode();
|
||||
} catch (MalformedURLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (URISyntaxException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
// if (icon==null) {
|
||||
// PamSVGIcon iconMaker= new PamSVGIcon();
|
||||
// PamSVGIcon svgsprite;
|
||||
// try {
|
||||
// svgsprite = iconMaker.create(getClass().getResource("/Resources/delphinid_logo01.svg").toURI().toURL());
|
||||
// icon = svgsprite.getSpriteNode();
|
||||
// } catch (MalformedURLException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// } catch (URISyntaxException e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// } catch (Exception e) {
|
||||
// // TODO Auto-generated catch block
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// return icon;
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,18 @@
|
||||
package rawDeepLearningClassifier.dlClassification.delphinID;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.jamdev.jdl4pam.transforms.FreqTransform;
|
||||
import org.jamdev.jpamutils.spectrogram.SpecTransform;
|
||||
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.image.WritableImage;
|
||||
import javafx.scene.paint.Color;
|
||||
import PamUtils.PamArrayUtils;
|
||||
import rawDeepLearningClassifier.segmenter.SegmenterDetectionGroup;
|
||||
import whistlesAndMoans.AbstractWhistleDataUnit;
|
||||
|
||||
/**
|
||||
* Transform whistles to an image.
|
||||
@ -22,19 +28,19 @@ public class Whistles2Image extends FreqTransform {
|
||||
|
||||
/**
|
||||
* Create an image transform from a whistleGroup.
|
||||
* @param whistleGroup
|
||||
* @param params
|
||||
* @param whistleGroup - the whistle group
|
||||
* @param params - the paramters for whsilte image - min. freq., max. freq., width in pixels and height in pixels.
|
||||
*/
|
||||
public Whistles2Image(SegmenterDetectionGroup whistleGroup, Number[] params) {
|
||||
super(null, params);
|
||||
double[] freqLimits = new double[] {params[0].doubleValue(), params[1].doubleValue()};
|
||||
double[] size = new double[] {params[2].doubleValue(), params[3].doubleValue()};
|
||||
|
||||
SpecTransform specTransform = whistleGroupToImage( whistleGroup, freqLimits, size);
|
||||
|
||||
public Whistles2Image(SegmenterDetectionGroup whistleGroup, Whistle2ImageParams params) {
|
||||
super(null, null);
|
||||
// double[] freqLimits = new double[] {params[0].doubleValue(), params[1].doubleValue()};
|
||||
// double[] size = new double[] {params[2].doubleValue(), params[3].doubleValue()};
|
||||
|
||||
SpecTransform specTransform = whistleGroupToImage( whistleGroup, params.freqLimits, params.size, params.lineWidth);
|
||||
|
||||
this.setSpecTransfrom(specTransform);
|
||||
this.setFreqlims(freqLimits);
|
||||
|
||||
this.setFreqlims(params.freqLimits);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +50,7 @@ public class Whistles2Image extends FreqTransform {
|
||||
* @param freqLimits - the frequency limits
|
||||
* @return the spectrogram transform.
|
||||
*/
|
||||
private SpecTransform whistleGroupToImage(SegmenterDetectionGroup whistleGroup, double[] freqLimits, double[] size) {
|
||||
private SpecTransform whistleGroupToImage(SegmenterDetectionGroup whistleGroup, double[] freqLimits, double[] size, double lineWidth) {
|
||||
|
||||
SpecTransform specTransform = new SpecTransform();
|
||||
|
||||
@ -56,22 +62,25 @@ public class Whistles2Image extends FreqTransform {
|
||||
* 4.8 inches as default, axes removed before saving using plt.axes(‘off’))
|
||||
**/
|
||||
|
||||
double[][] points = whistContours2Points(whistleGroup);
|
||||
ArrayList<double[][]> points = whistContours2Points(whistleGroup);
|
||||
|
||||
Canvas canvas = makeScatterImage(points, size, new double[]{0, whistleGroup.getDurationInMilliseconds()}, freqLimits, 5.);
|
||||
|
||||
WritableImage image = canvas.getGraphicsContext2D().getCanvas().snapshot(null, null);
|
||||
//does not work becaue it has to be on the AWT thread.
|
||||
BufferedImage canvas = makeScatterImage(points, size, new double[]{0, whistleGroup.getSegmentDuration()/1000.}, freqLimits, lineWidth);
|
||||
|
||||
double[][] imaged = new double[(int) size[0]][(int) size[1]];
|
||||
|
||||
Color color;
|
||||
float[] color = new float[3];
|
||||
Raster raster = canvas.getData();
|
||||
for (int i=0; i<imaged.length; i++) {
|
||||
for (int j=0; j<imaged[0].length; j++) {
|
||||
color = image.getPixelReader().getColor(i, j);
|
||||
imaged[i][j] = color.getRed();
|
||||
color = raster.getPixel(i, j, color);
|
||||
imaged[i][j] = (255-color[0])/255.; //normalize
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// System.out.println("Original image: ");
|
||||
// PamArrayUtils.printArray(imaged);
|
||||
|
||||
specTransform.setSpecData(imaged);
|
||||
specTransform.setSampleRate((float) (freqLimits[1]*2));
|
||||
|
||||
@ -81,40 +90,137 @@ public class Whistles2Image extends FreqTransform {
|
||||
/**
|
||||
* Convert a list of whistle contours to a list of time and frequency points.
|
||||
* @param whistleGroup - list of whistle contours within a detection group.
|
||||
* @return an array with time (milliseconds from start of group) and frequency (Hz)
|
||||
* @return an array with time (seconds from start of group) and frequency (Hz)
|
||||
*/
|
||||
private double[][] whistContours2Points(SegmenterDetectionGroup whistleGroup) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
public static ArrayList<double[][]> whistContours2Points(SegmenterDetectionGroup whistleGroup) {
|
||||
|
||||
ArrayList<double[][]> contours = new ArrayList<double[][]>();
|
||||
|
||||
AbstractWhistleDataUnit whistleContour;
|
||||
|
||||
long segStart = whistleGroup.getSegmentStartMillis();
|
||||
long segEnd = (long) (whistleGroup.getSegmentStartMillis() + whistleGroup.getSegmentDuration());
|
||||
|
||||
|
||||
// for (int i=0; i<whistleGroup.getSubDetectionsCount(); i++) {
|
||||
// whistleContour = (AbstractWhistleDataUnit) whistleGroup.getSubDetection(i);
|
||||
//
|
||||
// long whistleStart = whistleContour.getTimeMilliseconds();
|
||||
// long whistleEnd = (long) (whistleContour.getTimeMilliseconds() + whistleContour.getDurationInMilliseconds());
|
||||
//
|
||||
// if ((whistleStart>=segStart && whistleStart<segEnd) || ((whistleEnd>=segStart && whistleEnd<segEnd))){
|
||||
// //some part of the whistle is in the segment.
|
||||
// System.out.println("Whistle in group? true");
|
||||
//
|
||||
// }
|
||||
// else {
|
||||
// System.out.println("Whistle in group? false!!!");
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// System.out.println("Whistle group: " + segStart);
|
||||
|
||||
for (int i=0; i<whistleGroup.getSubDetectionsCount(); i++) {
|
||||
|
||||
whistleContour = (AbstractWhistleDataUnit) whistleGroup.getSubDetection(i);
|
||||
|
||||
// System.out.println("Whistle start time: " + (whistleContour.getTimeMilliseconds()-segStart)/1000. + " end: " +
|
||||
// (whistleContour.getTimeMilliseconds() - (segStart + whistleContour.getDurationInMilliseconds()))/1000.
|
||||
// + " millis: " + whistleContour.getTimeMilliseconds() + " first slice: " + whistleContour.getTimesInSeconds()[0]);
|
||||
|
||||
double[][] contourD = new double[whistleContour.getSliceCount()][2];
|
||||
for (int j=0; j<whistleContour.getSliceCount(); j++) {
|
||||
contourD[j][0] = (whistleContour.getTimeMilliseconds()-segStart)/1000. + (whistleContour.getTimesInSeconds()[j]-whistleContour.getTimesInSeconds()[0]);
|
||||
contourD[j][1] = whistleContour.getFreqsHz()[j];
|
||||
}
|
||||
contours.add(contourD);
|
||||
}
|
||||
|
||||
return contours;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Create a scatter image from points
|
||||
// * @param points - list of time frequency points - the points are time (milliseconds from 0) and frequency
|
||||
// * @param size - the width and height of the image in pixels
|
||||
// * @param xlims - the minimum and maximum time in milliseconds from 0;
|
||||
// * @param ylims - the minimum and maximum frequency in Hz
|
||||
// * @param markerSize - the marker size in pixels
|
||||
// * @return an image with y axis as frequency and x axis as time.
|
||||
// */
|
||||
// private Canvas makeScatterImage(ArrayList<double[][]> points, double[] size, double[] xlims, double[] ylims, double markerSize) {
|
||||
//
|
||||
// Canvas canvas = new Canvas(size[0], size[1]);
|
||||
//
|
||||
// double x, y;
|
||||
// for (int j=0; j<points.size(); j++) {
|
||||
//
|
||||
// for (int i=0; i<points.get(j).length; i++) {
|
||||
// canvas.getGraphicsContext2D().setFill(Color.BLACK);
|
||||
//
|
||||
// //Calculate x and y in pixels.
|
||||
// x = ((points.get(j)[i][0]-xlims[0])/(xlims[1]-xlims[0]))*size[0];
|
||||
// y = ((points.get(j)[i][0]-xlims[0])/(xlims[1]-xlims[0]))*size[0];
|
||||
//
|
||||
// canvas.getGraphicsContext2D().fillOval(x+markerSize/2, y-markerSize/2, markerSize/2, markerSize/2);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return canvas;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Create a scatter image from points
|
||||
* @param points - the points are time (milliseconds from 0) and frequency
|
||||
* @param points - list of time frequency points - the points are time (milliseconds from 0) and frequency
|
||||
* @param size - the width and height of the image in pixels
|
||||
* @param xlims - the minimum and maximum time in milliseconds from 0;
|
||||
* @param ylims - the minimum and maximum frequency in Hz
|
||||
* @param markerSize - the marker size in pixels
|
||||
* @return an image with y axis as frequency and x axis as time.
|
||||
*/
|
||||
private Canvas makeScatterImage(double[][] points, double[] size, double[] xlims, double[] ylims, double markerSize) {
|
||||
public static BufferedImage makeScatterImage(ArrayList<double[][]> points, double[] size, double[] xlims, double[] ylims, double markerSize) {
|
||||
|
||||
Canvas canvas = new Canvas(size[0], size[1]);
|
||||
BufferedImage canvas = new BufferedImage((int) size[0], (int) size[1], BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
double x, y;
|
||||
for (int i=0; i<points.length; i++) {
|
||||
canvas.getGraphicsContext2D().setFill(Color.BLACK);
|
||||
for (int j=0; j<points.size(); j++) {
|
||||
|
||||
//Calculate x and y in pixels.
|
||||
x = ((points[i][0]-xlims[0])/(xlims[1]-xlims[0]))*size[0];
|
||||
y = ((points[i][0]-xlims[0])/(xlims[1]-xlims[0]))*size[0];
|
||||
for (int i=0; i<points.get(j).length; i++) {
|
||||
canvas.getGraphics().setColor(Color.BLACK);
|
||||
|
||||
canvas.getGraphicsContext2D().fillOval(x+markerSize/2, y-markerSize/2, markerSize/2, markerSize/2);
|
||||
//Calculate x and y in pixels.
|
||||
x = ((points.get(j)[i][0]-xlims[0])/(xlims[1]-xlims[0]))*size[0];
|
||||
y = ((points.get(j)[i][1]-ylims[0])/(ylims[1]-ylims[0]))*size[1];
|
||||
|
||||
// System.out.println("Fill oval: x " + x + " y: " + y + " time: " + points.get(j)[i][0]);
|
||||
|
||||
Graphics2D g2 = (Graphics2D) canvas.getGraphics();
|
||||
|
||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
|
||||
g2.fillOval((int) (x+markerSize/2),(int) (y-markerSize/2), (int) markerSize,(int) markerSize);
|
||||
}
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
public static class Whistle2ImageParams {
|
||||
|
||||
/**
|
||||
* The frequency limitis in
|
||||
*/
|
||||
public double[] freqLimits;
|
||||
|
||||
public double[] size;
|
||||
|
||||
/**
|
||||
* The line width to draw in pixels
|
||||
*/
|
||||
public double lineWidth = 10;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -184,43 +184,12 @@ public class GenericDLClassifier extends StandardClassifierModel {
|
||||
* @param modelResult - the model result;
|
||||
* @param groupedRawData - the grouped raw data.
|
||||
*/
|
||||
protected void newResult(GenericPrediction modelResult, GroupedRawData groupedRawData) {
|
||||
this.dlControl.getDLClassifyProcess().newModelResult(modelResult, groupedRawData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class name IDs
|
||||
* @return an array of class name IDs
|
||||
*/
|
||||
public static short[] getClassNameIDs(StandardModelParams standardModelParams) {
|
||||
if (standardModelParams.classNames==null || standardModelParams.classNames.length<=0) return null;
|
||||
short[] nameIDs = new short[standardModelParams.classNames.length];
|
||||
for (int i = 0 ; i<standardModelParams.classNames.length; i++) {
|
||||
nameIDs[i] = standardModelParams.classNames[i].ID;
|
||||
}
|
||||
return nameIDs;
|
||||
protected void newResult(StandardPrediction modelResult, GroupedRawData groupedRawData) {
|
||||
this.dlControl.getDLClassifyProcess().newRawModelResult(modelResult, groupedRawData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check whether a model passes a binary test...
|
||||
* @param modelResult - the model results
|
||||
* @return the model results.
|
||||
*/
|
||||
public static boolean isBinaryResult(GenericPrediction modelResult, StandardModelParams genericModelParams) {
|
||||
for (int i=0; i<modelResult.getPrediction().length; i++) {
|
||||
//System.out.println("Binary Classification: " + genericModelParams.binaryClassification.length);
|
||||
|
||||
if (modelResult.getPrediction()[i]>genericModelParams.threshold && genericModelParams.binaryClassification[i]) {
|
||||
// System.out.println("SoundSpotClassifier: prediciton: " + i + " passed threshold with val: " + modelResult.getPrediction()[i]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public ArrayList<PamWarning> checkSettingsOK() {
|
||||
// return checkSettingsOK(genericModelParams, dlControl);
|
||||
@ -234,7 +203,7 @@ public class GenericDLClassifier extends StandardClassifierModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DLModelWorker<GenericPrediction> getDLWorker() {
|
||||
public DLModelWorker<StandardPrediction> getDLWorker() {
|
||||
return this.genericModelWorker;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import org.jamdev.jdl4pam.transforms.FreqTransform;
|
||||
|
||||
import PamModel.PamModel;
|
||||
import PamModel.PamModel.PluginClassloader;
|
||||
import PamUtils.PamArrayUtils;
|
||||
import rawDeepLearningClassifier.DLControl;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
|
||||
@ -18,7 +19,7 @@ import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class GenericModelWorker extends DLModelWorker<GenericPrediction> {
|
||||
public class GenericModelWorker extends DLModelWorker<StandardPrediction> {
|
||||
|
||||
/**
|
||||
* The generic model
|
||||
@ -32,7 +33,7 @@ public class GenericModelWorker extends DLModelWorker<GenericPrediction> {
|
||||
|
||||
@Override
|
||||
public float[] runModel(float[][][] transformedDataStack) {
|
||||
//System.out.println("RUN GENERIC MODEL: " + transformedDataStack.length + " " + transformedDataStack[0].length + " " + transformedDataStack[0][0].length);
|
||||
// System.out.println("RUN GENERIC MODEL: " + transformedDataStack.length + " " + transformedDataStack[0].length + " " + transformedDataStack[0][0].length);
|
||||
// System.out.println("RUN GENERIC MODEL: " + transformedDataStack[0][0][0]);
|
||||
float[] results;
|
||||
if (freqTransform)
|
||||
@ -47,13 +48,14 @@ public class GenericModelWorker extends DLModelWorker<GenericPrediction> {
|
||||
//System.out.println("RUN GENERIC MODEL WAVE: " + waveStack.length + " " + waveStack[0].length + " " + waveStack[0][0]);
|
||||
results = getModel().runModel(waveStack);
|
||||
}
|
||||
//System.out.println("GENERIC MODEL RESULTS: " + results== null ? null : results.length);
|
||||
// System.out.println("GENERIC MODEL RESULTS: " + (results== null ? null : results.length));
|
||||
// PamArrayUtils.printArray(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericPrediction makeModelResult(float[] prob, double time) {
|
||||
GenericPrediction model = new GenericPrediction(prob);
|
||||
public StandardPrediction makeModelResult(float[] prob, double time) {
|
||||
StandardPrediction model = new StandardPrediction(prob);
|
||||
model.setAnalysisTime(time);
|
||||
return model;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import rawDeepLearningClassifier.dlClassification.PredictionResult;
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class GenericPrediction implements PredictionResult {
|
||||
public class StandardPrediction implements PredictionResult {
|
||||
|
||||
|
||||
/**
|
||||
@ -45,14 +45,14 @@ public class GenericPrediction implements PredictionResult {
|
||||
* @param classNameID - the ID's of the class names.
|
||||
* @param isBinary - true if the model result passed a binary test (usually one species above a threshold)
|
||||
*/
|
||||
public GenericPrediction(float[] prob, short[] classNameID, boolean isBinary) {
|
||||
public StandardPrediction(float[] prob, short[] classNameID, boolean isBinary) {
|
||||
this.prob=prob;
|
||||
this.classNameID = classNameID;
|
||||
this.binaryPass= isBinary;
|
||||
}
|
||||
|
||||
|
||||
public GenericPrediction(float[] prob, boolean isBinary) {
|
||||
public StandardPrediction(float[] prob, boolean isBinary) {
|
||||
this(prob, null, isBinary);
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ public class GenericPrediction implements PredictionResult {
|
||||
* Create a result for the Sound Spot classifier.
|
||||
* @param prob - the probability of each class.
|
||||
*/
|
||||
public GenericPrediction(float[] prob) {
|
||||
public StandardPrediction(float[] prob) {
|
||||
this(prob, null, false);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import rawDeepLearningClassifier.dlClassification.DLClassiferModel;
|
||||
import rawDeepLearningClassifier.dlClassification.StandardClassifierModel;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
import rawDeepLearningClassifier.layoutFX.DLCLassiferModelUI;
|
||||
|
||||
/**
|
||||
@ -77,7 +77,7 @@ public class KetosClassifier extends StandardClassifierModel {
|
||||
|
||||
|
||||
@Override
|
||||
public DLModelWorker<GenericPrediction> getDLWorker() {
|
||||
public DLModelWorker<StandardPrediction> getDLWorker() {
|
||||
return getKetosWorker();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package rawDeepLearningClassifier.dlClassification.ketos;
|
||||
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
|
||||
|
||||
/**
|
||||
@ -8,7 +8,7 @@ import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class KetosResult extends GenericPrediction {
|
||||
public class KetosResult extends StandardPrediction {
|
||||
|
||||
|
||||
public KetosResult(float[] prob) {
|
||||
|
@ -15,7 +15,7 @@ import PamView.dialog.warn.WarnOnce;
|
||||
import rawDeepLearningClassifier.DLControl;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -25,7 +25,7 @@ import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction
|
||||
* @author Jamie Macaulay
|
||||
*
|
||||
*/
|
||||
public class KetosWorker extends DLModelWorker<GenericPrediction> {
|
||||
public class KetosWorker extends DLModelWorker<StandardPrediction> {
|
||||
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ import rawDeepLearningClassifier.DLControl;
|
||||
import rawDeepLearningClassifier.dlClassification.archiveModel.ArchiveModelClassifier;
|
||||
import rawDeepLearningClassifier.dlClassification.archiveModel.ArchiveModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.DLModelWorker;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
|
||||
/**
|
||||
* Classifier which uses deep learning models from Koogus' framework.
|
||||
|
@ -35,6 +35,9 @@ import rawDeepLearningClassifier.defaultModels.DLModel;
|
||||
*/
|
||||
public class DefaultModelPane extends PamBorderPane{
|
||||
|
||||
private static final double PREF_WIDTH = 200;
|
||||
|
||||
|
||||
/**
|
||||
* Reference to the deafult model manager that contains the default models.
|
||||
*/
|
||||
@ -74,7 +77,7 @@ public class DefaultModelPane extends PamBorderPane{
|
||||
// vBox.setPrefWidth(120);
|
||||
|
||||
hidingPaneContent= new PamBorderPane();
|
||||
hidingPaneContent.setPrefWidth(150);
|
||||
hidingPaneContent.setPrefWidth(PREF_WIDTH);
|
||||
hidingPane = new HidingPane(Side.RIGHT, hidingPaneContent, vBox, true, 0);
|
||||
|
||||
PamButton button;
|
||||
@ -101,12 +104,15 @@ public class DefaultModelPane extends PamBorderPane{
|
||||
}
|
||||
|
||||
hidingPane.setStyle("-fx-background-color: -fx-base");
|
||||
hidingPane.setPrefWidth(PREF_WIDTH);
|
||||
// this.setStyle("-fx-background-color: -fx-base");
|
||||
|
||||
PamStackPane mainHolder = new PamStackPane();
|
||||
mainHolder.getChildren().addAll(vBox, hidingPane);
|
||||
StackPane.setAlignment(hidingPane, Pos.TOP_RIGHT);
|
||||
|
||||
mainHolder.setPrefWidth(PREF_WIDTH);
|
||||
|
||||
return mainHolder;
|
||||
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import PamUtils.PamArrayUtils;
|
||||
import rawDeepLearningClassifier.dlClassification.PredictionResult;
|
||||
import rawDeepLearningClassifier.dlClassification.animalSpot.SoundSpotResult;
|
||||
import rawDeepLearningClassifier.dlClassification.dummyClassifier.DummyModelResult;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction;
|
||||
import rawDeepLearningClassifier.dlClassification.ketos.KetosResult;
|
||||
|
||||
/**
|
||||
@ -146,7 +146,7 @@ public class ModelResultBinaryFactory {
|
||||
break;
|
||||
default:
|
||||
//ideally should never be used.
|
||||
result = new GenericPrediction(data, isBinary);
|
||||
result = new StandardPrediction(data, isBinary);
|
||||
break;
|
||||
}
|
||||
//System.out.println("New model result: "+ type);
|
||||
@ -173,7 +173,7 @@ public class ModelResultBinaryFactory {
|
||||
return KETOS;
|
||||
}
|
||||
//must be last because this is often sub classed
|
||||
if (modelResult instanceof GenericPrediction) {
|
||||
if (modelResult instanceof StandardPrediction) {
|
||||
return GENERIC;
|
||||
}
|
||||
if (modelResult instanceof DummyModelResult) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user