diff --git a/pom.xml b/pom.xml index ca91aa43..1f960c52 100644 --- a/pom.xml +++ b/pom.xml @@ -270,14 +270,12 @@ --> - - - false - - bedatadriven - bedatadriven_renjin - https://nexus.bedatadriven.com/content/groups/public/ - + + bedatadriven + bedatadriven public repo + https://nexus.bedatadriven.com/content/groups/public/ + + @@ -310,7 +308,7 @@ io.github.macster110 jdl4pam - 0.0.98 + 0.0.99 @@ -711,7 +709,7 @@ org.xerial sqlite-jdbc - 3.28.0 + 3.45.3.0 diff --git a/readme.md b/readme.md index a63ea137..721b10db 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,73 @@ -This is the main code repository for the PAMGuard software. +# PAMGuard +PAMGuard is a bioacoustics analysis program designed for use in real time research contexts and for the processing of large datasets. PAMGuard provides users access to a suite of state-of-the-art auotmated analysis algorithms alongside displays for visualisation data and a comprehensive data management systems. -This repository was created on 7 January 2022 from sourceforge SVN repository at https://sourceforge.net/p/pamguard/svn/HEAD/tree/ revision r6278. +# Why do we need PAMGuard? +PAMGuard fufills two main requirements within marine bioacoustics -If you are a PAMGuard developer, you should clone and branch this repository and share with any collaborators in your own workspace. When your work is ready, contact the PAMGuard team to have your changes merged back into this repo. +1) **Real time operation** - Almost all PAMGuard features and modules work in real time - this allows scientists and industry to detect, classify and loclaise animals in real time on a standard consumer laptop, enabling mitigations and research survey without expensive bespoke software solutions and the transparncy of open source software. + +2) **Processing and visuslisation of large datasets** - + + +## Installation +PAMGuard is available on Windows and can be downloaded from the [PAMGuard website](www.pamguard.org). Note that we are considering MacOS installers but they are not available at this time. + +## Tutorial +PAMGuard is a modular program with two modes; real-time and viewer. Typically a user will start with real-time model, either in the field collecting data or post processing sound files from a recorder. Once data are processed, users move on to viewer mode where data can be explored and further processed. + +Upon opening PAMGuard for the first time you are greeted with a blank screen. You must add a series of modules to create the desired acosutic workflow. For example if processing sound files then first add the Sound Acquisition module **_File->Add Modules->Sound Processing->Sound Acquisition_**. Then add the desired detection algorothms e.g. **_File->Add Modules->Detector->Click Detectors_**. Some modules (such as the click detector) have their own displays, others are added to more generalised displays. For example, the whislte and moan detector module shows detections on a spectrgram display. First add a new tab using **_File->Add Modules->Displays->User Display**. Click on the user display tab and then from the top menu select **_User display-> New Spectrgram_**. Right click on the added spectrgram and select whistle and moan contours to show whistle detections overlaid on the raw spectrgram. + +Make sure to add the database and binary file storage modules **_File->Add Modules->Utilities->..._**) to save data then press the run button (red button) and data will process. PAMGuard can handle huge datasets so runing might take hours or even days. Progress is shown on the bottom of the screen. + +## Features + +### Hardware integration +PAMGuard connects with hardware such as various GPS and AIS systems and a multitude of different sound cards (e.g. [National Instruments](www.ni.com) devices, [SAIL DAQ cards](www.smruconsulting.com/contact-us), almost all ASIO sound cards and standard computer sound cards) for real time data collection and processing. PAMGuard also works with some very bespoke hardware such as [DIFAR Sonobuoys](); + +### Real time operation +PAMGuard takes advanatge of multi-core processors to run multiple signal processing automatic analysis algorithms in real time to detect whales, dolphins, bats etc. Data are shown in different displayes, including interactive spectrograms and maps. You might be using PAMGuard for simply viewing a spectrgram and making recordings or running deep learning algorithms for multiple species and loclaising the results to view locations on a map. Whatever acosutic workflow a user creates, PAMGuard can run it in real time. + +### Support for compressed audio +PAMGuard supports processing audio data from standard files (e.g. wav, aif) and also compressed files (e.g. .flac and .sud). Notew that sud files are created on SoundTraps widely used marine recorders and can be read by PAMGuard without decompressing - PAMGuard will automtically import click detections if present in sud files. PAMGuard also supports importing detection data from CPODs and FPODs. + +### Comprehensive data management system +PAMGuard is designed to collect/process data from large acosutic datasets. PAMGuard stores data in an SQLite databases and "Binary" files. The database stores important metadata such as when data has been processed and some low volume data streams such as GPS. Binary files are not human readbale but efficient to access - PAMGuard stores detection data (e.g. clicks, whistles, noise, etc) in these files. this allows PAMGuard to rapidly access data from large datasets. Data from binary files can be viewed in PAMGuard viewer mode or can be exported to MATLAB using the PAMGuard-MATLAB library or the exported to R using the R PAMBinaries package. + +### Access to detection and classification algorithms +PAMGuard allows users to inegrate automated detection and classification algorithms directly into their acosutic workflow. There are a multitude of differwent algorothms to choose from, including a basic click detector, whislte and moan detector, GPL detector, click train detectors and many others. The idea behind PAMGuard is allow researchers to access open source state-of-the-art algorithms devleoped within the scientific community - if you want to contribute and get your algorithm into PAMGuard get in touch. + +###Localisation +PAMGuard has a mutltude of different options for acoustic loclaisation. There's a comprehesnive beam forming module for beam forming arrays, a large aperture localiser for 3D loclaisation and target motion analysis for towed hydrophone arrays. + +###Soundscape analysis +PAMGuard has a noise band (which supports third octave noise bands) and long term spectral average module for soundscape analysis. + +### GIS +Almsot all detection data can be visualised on a map. PAMGaurd also supports plotting GPS and AIS data. + +### Suite of data visualisation tools +An important aspect of PAMGuard is the ability for users to explore porcessed data. This is + +### Advanced manual annotation +The displays within PAMGuard support a variety of manual annottion tools. A simple spectrogram + +### Deep learning integration + +### Meatadata standard and Tethys compatibility + +## Feature roadmap +There's lots of features we would like to add to PAMGuard. If you want to add a feature you can either code it up yourself in Java and submit a pull request or get in touch with us to discuss how to it might be integrated. Some smaller features might be in our roadmap anyway but larger features usually require funding. Some features we are thinking about (but do not necassarily have time for yet) are; + +* Support for decidecade noise bands (base 10 filter bank) in noise band monitor to meet Euopean standards +* Capabaility to export data directly from PAMGaurd e.g. as MAT files. +* Automated test suite to make releases more stable. Note that unit and integration tests are also being slowly incorporated. + +## Development +This is the main code repository for the PAMGuard software and was created on 7 January 2022 from a [sourceforge SVN repository](https://sourceforge.net/p/pamguard/svn/HEAD/tree/) revision r6278. + +If you are a PAMGuard developer, you should clone and branch this repository and share with any collaborators in your own workspace. When your work is ready, contact the PAMGuard team to have your changes merged back into this repo. + +PAMGuard uses Maven as build tool. + +# Organisation and License +PAMGuard is open source under an MIT license. It is currently primarily managed by the Sea Mammal Research Unit within the [University of St Andrews](https://www.st-andrews.ac.uk/). Please get in touch if you have any questions. diff --git a/src/Acquisition/filedate/FileDateDialogStrip.java b/src/Acquisition/filedate/FileDateDialogStrip.java index fb97ab26..c695f6de 100644 --- a/src/Acquisition/filedate/FileDateDialogStrip.java +++ b/src/Acquisition/filedate/FileDateDialogStrip.java @@ -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; diff --git a/src/Map/MapDetectionsDialog.java b/src/Map/MapDetectionsDialog.java index 1a9b100b..ed79530d 100644 --- a/src/Map/MapDetectionsDialog.java +++ b/src/Map/MapDetectionsDialog.java @@ -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); diff --git a/src/Map/MapPanel.java b/src/Map/MapPanel.java index 225f01ef..cc00acd2 100644 --- a/src/Map/MapPanel.java +++ b/src/Map/MapPanel.java @@ -30,7 +30,6 @@ import java.awt.MouseInfo; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; -import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; @@ -39,17 +38,14 @@ import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.text.DecimalFormat; import java.util.ArrayList; -import java.util.ConcurrentModificationException; import java.util.List; import java.util.ListIterator; import java.util.Vector; -import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; -import pamScrollSystem.PamScrollSlider; import Array.ArrayManager; import Array.PamArray; import Array.SnapshotGeometry; @@ -61,7 +57,6 @@ import GPS.GpsData; import GPS.GpsDataUnit; import Map.gridbaselayer.GridbaseControl; import Map.gridbaselayer.MapRasterImage; -import PamController.PamControlledUnit; import PamController.PamController; import PamController.PamControllerInterface; import PamController.masterReference.MasterReferencePoint; @@ -83,7 +78,6 @@ import PamView.PamColors.PamColor; import PamView.panel.JPanelWithPamKey; import PamView.panel.KeyPanel; import PamView.paneloverlay.OverlayCheckboxMenuItem; -import PamView.paneloverlay.overlaymark.MarkDataMatcher; import PamView.paneloverlay.overlaymark.MarkDataSelector; import PamView.paneloverlay.overlaymark.MarkOverlayDraw; import PamView.symbol.PamSymbolChooser; @@ -1476,9 +1470,9 @@ public class MapPanel extends JPanelWithPamKey implements PamObserver, ColorMana plotDetectorMenu.add(menuItem); plotDetectorMenu.addSeparator(); - ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png")); - ImageIcon settingsIconNot = new ImageIcon( - ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png")); +// ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png")); +// ImageIcon settingsIconNot = new ImageIcon( +// ClassLoader.getSystemResource("Resources/SettingsButtonSmallWhite.png")); ArrayList mddList = simpleMapRef.mapDetectionsManager.getMapDetectionDatas(); for (int i = 0; i < mddList.size(); i++) { diff --git a/src/PamController/PamController.java b/src/PamController/PamController.java index 5da0239a..2fe26b3e 100644 --- a/src/PamController/PamController.java +++ b/src/PamController/PamController.java @@ -100,6 +100,7 @@ import PamguardMVC.uid.UIDManager; import PamguardMVC.uid.UIDOnlineManager; import PamguardMVC.uid.UIDViewerManager; import binaryFileStorage.BinaryStore; +import export.ExportOptions; import PamguardMVC.debug.Debug; /** @@ -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; } + + } diff --git a/src/PamUtils/PamArrayUtils.java b/src/PamUtils/PamArrayUtils.java index 60cb22b4..37909be0 100644 --- a/src/PamUtils/PamArrayUtils.java +++ b/src/PamUtils/PamArrayUtils.java @@ -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 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 componentAvailability = new WeakHashMap(); + + 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. diff --git a/src/PamView/PamGui.java b/src/PamView/PamGui.java index ac51f1bc..bdfae2ee 100644 --- a/src/PamView/PamGui.java +++ b/src/PamView/PamGui.java @@ -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()); diff --git a/src/PamView/TopToolBar.java b/src/PamView/TopToolBar.java index 2844aff9..d245c78c 100644 --- a/src/PamView/TopToolBar.java +++ b/src/PamView/TopToolBar.java @@ -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()); diff --git a/src/PamView/component/PamSettingsIconButton.java b/src/PamView/component/PamSettingsIconButton.java index 20e6feda..cfc25fd6 100644 --- a/src/PamView/component/PamSettingsIconButton.java +++ b/src/PamView/component/PamSettingsIconButton.java @@ -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. diff --git a/src/PamView/dialog/SettingsButton.java b/src/PamView/dialog/SettingsButton.java index 510a1711..e734b045 100644 --- a/src/PamView/dialog/SettingsButton.java +++ b/src/PamView/dialog/SettingsButton.java @@ -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")); } diff --git a/src/PamView/hidingpanel/HidingDialog.java b/src/PamView/hidingpanel/HidingDialog.java index 90b6d2d8..94c3b327 100644 --- a/src/PamView/hidingpanel/HidingDialog.java +++ b/src/PamView/hidingpanel/HidingDialog.java @@ -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) { diff --git a/src/PamView/paneloverlay/OverlayCheckboxMenuItem.java b/src/PamView/paneloverlay/OverlayCheckboxMenuItem.java index e76891c1..7c9d2904 100644 --- a/src/PamView/paneloverlay/OverlayCheckboxMenuItem.java +++ b/src/PamView/paneloverlay/OverlayCheckboxMenuItem.java @@ -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; diff --git a/src/PamView/paneloverlay/OverlayDataManager.java b/src/PamView/paneloverlay/OverlayDataManager.java index 0bdf69db..a8d52586 100644 --- a/src/PamView/paneloverlay/OverlayDataManager.java +++ b/src/PamView/paneloverlay/OverlayDataManager.java @@ -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 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; diff --git a/src/PamguardMVC/dataSelector/DataSelectorDialogPanel.java b/src/PamguardMVC/dataSelector/DataSelectorDialogPanel.java index 3154f807..76f7ecd2 100644 --- a/src/PamguardMVC/dataSelector/DataSelectorDialogPanel.java +++ b/src/PamguardMVC/dataSelector/DataSelectorDialogPanel.java @@ -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 diff --git a/src/Resources/css/delphinid_logo01.svg b/src/Resources/css/delphinid_logo01.svg deleted file mode 100644 index 744670bf..00000000 --- a/src/Resources/css/delphinid_logo01.svg +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - - - delphinID - - - - - - diff --git a/src/Resources/css/primer-pamguard.css b/src/Resources/css/primer-pamguard.css index ece247b6..1a2a7415 100644 --- a/src/Resources/css/primer-pamguard.css +++ b/src/Resources/css/primer-pamguard.css @@ -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; diff --git a/src/clickDetector/offlineFuncs/OfflineToolbar.java b/src/clickDetector/offlineFuncs/OfflineToolbar.java index 86efaf3e..9ff5ba5f 100644 --- a/src/clickDetector/offlineFuncs/OfflineToolbar.java +++ b/src/clickDetector/offlineFuncs/OfflineToolbar.java @@ -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"); } diff --git a/src/clickTrainDetector/layout/localisation/CTMSettingsPanel.java b/src/clickTrainDetector/layout/localisation/CTMSettingsPanel.java index 8d74cc24..c068e418 100644 --- a/src/clickTrainDetector/layout/localisation/CTMSettingsPanel.java +++ b/src/clickTrainDetector/layout/localisation/CTMSettingsPanel.java @@ -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); } diff --git a/src/dataModelFX/connectionNodes/ModuleConnectionNode.java b/src/dataModelFX/connectionNodes/ModuleConnectionNode.java index 1e7996b3..a182c6ec 100644 --- a/src/dataModelFX/connectionNodes/ModuleConnectionNode.java +++ b/src/dataModelFX/connectionNodes/ModuleConnectionNode.java @@ -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()); diff --git a/src/dataModelFX/connectionNodes/ModuleIconFactory.java b/src/dataModelFX/connectionNodes/ModuleIconFactory.java index 86e170e4..4056f730 100644 --- a/src/dataModelFX/connectionNodes/ModuleIconFactory.java +++ b/src/dataModelFX/connectionNodes/ModuleIconFactory.java @@ -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; } diff --git a/src/dataPlots/layout/CompoundHidingTabPane.java b/src/dataPlots/layout/CompoundHidingTabPane.java index 8462d110..72a44e86 100644 --- a/src/dataPlots/layout/CompoundHidingTabPane.java +++ b/src/dataPlots/layout/CompoundHidingTabPane.java @@ -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() { diff --git a/src/dataPlotsFX/TDControlFX.java b/src/dataPlotsFX/TDControlFX.java index 3f162249..493b9fe0 100644 --- a/src/dataPlotsFX/TDControlFX.java +++ b/src/dataPlotsFX/TDControlFX.java @@ -114,9 +114,11 @@ public class TDControlFX extends TDControl implements UserDisplayNodeFX { ArrayList dataBlocks=new ArrayList(); 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; } diff --git a/src/dataPlotsFX/data/generic/GenericLinePlotInfo.java b/src/dataPlotsFX/data/generic/GenericLinePlotInfo.java index 92e19034..98b39929 100644 --- a/src/dataPlotsFX/data/generic/GenericLinePlotInfo.java +++ b/src/dataPlotsFX/data/generic/GenericLinePlotInfo.java @@ -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]; diff --git a/src/dataPlotsFX/layout/TDDisplayFX.java b/src/dataPlotsFX/layout/TDDisplayFX.java index afbcdb52..6cc2f259 100644 --- a/src/dataPlotsFX/layout/TDDisplayFX.java +++ b/src/dataPlotsFX/layout/TDDisplayFX.java @@ -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); diff --git a/src/dataPlotsFX/overlaymark/menuOptions/MLExportOverlayMenu.java b/src/dataPlotsFX/overlaymark/menuOptions/MLExportOverlayMenu.java index d0ace300..f0702f7f 100644 --- a/src/dataPlotsFX/overlaymark/menuOptions/MLExportOverlayMenu.java +++ b/src/dataPlotsFX/overlaymark/menuOptions/MLExportOverlayMenu.java @@ -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; diff --git a/src/dataPlotsFX/overlaymark/menuOptions/RExportOverlayMenu.java b/src/dataPlotsFX/overlaymark/menuOptions/RExportOverlayMenu.java index 60011a4f..fd6f6a0f 100644 --- a/src/dataPlotsFX/overlaymark/menuOptions/RExportOverlayMenu.java +++ b/src/dataPlotsFX/overlaymark/menuOptions/RExportOverlayMenu.java @@ -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 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()); diff --git a/src/detectionPlotFX/DetectionGroupDisplay.java b/src/detectionPlotFX/DetectionGroupDisplay.java index 28c416c3..69289edf 100644 --- a/src/detectionPlotFX/DetectionGroupDisplay.java +++ b/src/detectionPlotFX/DetectionGroupDisplay.java @@ -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(); + 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(); - 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(); } diff --git a/src/detectionPlotFX/DetectionGroupDisplayFX.java b/src/detectionPlotFX/DetectionGroupDisplayFX.java index a06b520d..ea831e73 100644 --- a/src/detectionPlotFX/DetectionGroupDisplayFX.java +++ b/src/detectionPlotFX/DetectionGroupDisplayFX.java @@ -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(); diff --git a/src/detectionPlotFX/DetectionPlotParams.java b/src/detectionPlotFX/DetectionPlotParams.java index f951e1c6..80840b7d 100644 --- a/src/detectionPlotFX/DetectionPlotParams.java +++ b/src/detectionPlotFX/DetectionPlotParams.java @@ -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 diff --git a/src/detectionPlotFX/layout/DDDataPane2.java b/src/detectionPlotFX/layout/DDDataPane2.java index 240a54f3..f73e289c 100644 --- a/src/detectionPlotFX/layout/DDDataPane2.java +++ b/src/detectionPlotFX/layout/DDDataPane2.java @@ -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); diff --git a/src/detectionPlotFX/layout/DetectionPlotDisplay.java b/src/detectionPlotFX/layout/DetectionPlotDisplay.java index 439301e9..16120cee 100644 --- a/src/detectionPlotFX/layout/DetectionPlotDisplay.java +++ b/src/detectionPlotFX/layout/DetectionPlotDisplay.java @@ -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 implements DetectionPlot { + /** + * 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 implements DetectionPlot /** * 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 implements DetectionPlot 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 implements DetectionPlot * @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 implements DetectionPlot //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 implements DetectionPlot } return (Pane) setttingsPane.getContentNode(); } + + /** + * Create plot paramters for the FFT plot params + * @return + */ + public FFTPlotParams createPlotParams() { + return new FFTPlotParams(); + } public class SimpleFFTDataUnit extends DataUnit2D { @@ -537,7 +559,6 @@ public abstract class FFTPlot implements DetectionPlot * 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 implements DetectionPlot this.pamDetection=pamDetection; } - } + public boolean isUseKHz() { + return useKHz; + } + } \ No newline at end of file diff --git a/src/detectionPlotFX/plots/FFTSettingsPane.java b/src/detectionPlotFX/plots/FFTSettingsPane.java index b7038a1b..16459be0 100644 --- a/src/detectionPlotFX/plots/FFTSettingsPane.java +++ b/src/detectionPlotFX/plots/FFTSettingsPane.java @@ -349,12 +349,21 @@ public class FFTSettingsPane 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 diff --git a/src/detectionPlotFX/plots/RawFFTPlot.java b/src/detectionPlotFX/plots/RawFFTPlot.java index 210a789f..045e2410 100644 --- a/src/detectionPlotFX/plots/RawFFTPlot.java +++ b/src/detectionPlotFX/plots/RawFFTPlot.java @@ -133,6 +133,7 @@ public abstract class RawFFTPlot extends FFTPlot { 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 extends FFTPlot { //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 extends FFTPlot { // 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 extends FFTPlot { */ 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 extends FFTPlot { 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 extends FFTPlot { @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); } diff --git a/src/detectionPlotFX/projector/DetectionPlotProjector.java b/src/detectionPlotFX/projector/DetectionPlotProjector.java index 40a5c6ff..960f61d1 100644 --- a/src/detectionPlotFX/projector/DetectionPlotProjector.java +++ b/src/detectionPlotFX/projector/DetectionPlotProjector.java @@ -35,7 +35,7 @@ public class DetectionPlotProjector extends GeneralProjector { /** * True to enable the scroll bar. */ - public boolean enableScrollBar = false; + public boolean enableScrollBar = true; /** * Projector for the ddPlotPane. diff --git a/src/detectionPlotFX/whistleDDPlot/WhistleFFTPlot.java b/src/detectionPlotFX/whistleDDPlot/WhistleFFTPlot.java index c58c1de2..c7a1895f 100644 --- a/src/detectionPlotFX/whistleDDPlot/WhistleFFTPlot.java +++ b/src/detectionPlotFX/whistleDDPlot/WhistleFFTPlot.java @@ -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 { */ 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 { 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 { 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(); + } } diff --git a/src/detectionPlotFX/whistleDDPlot/WhistlePlotParams.java b/src/detectionPlotFX/whistleDDPlot/WhistlePlotParams.java new file mode 100644 index 00000000..a9593ee7 --- /dev/null +++ b/src/detectionPlotFX/whistleDDPlot/WhistlePlotParams.java @@ -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; + +} diff --git a/src/detectionPlotFX/whistleDDPlot/WhistleSettingsPane.java b/src/detectionPlotFX/whistleDDPlot/WhistleSettingsPane.java index bf8abd54..ebfca3d6 100644 --- a/src/detectionPlotFX/whistleDDPlot/WhistleSettingsPane.java +++ b/src/detectionPlotFX/whistleDDPlot/WhistleSettingsPane.java @@ -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 { - //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 timeBuffer; - - private PamSpinner 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(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 stepSizeListLength=FXCollections.observableArrayList(); - for (int i=2; i<15; i++){ - stepSizeListLength.add((int) Math.pow(2,i)); - } - fftSpinnerLength=new PamSpinner(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(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 stepSizeListLength=FXCollections.observableArrayList(); +// for (int i=2; i<15; i++){ +// stepSizeListLength.add((int) Math.pow(2,i)); +// } +// fftSpinnerLength=new PamSpinner(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); + + } } diff --git a/src/export/CSVExport/CSVExportManager.java b/src/export/CSVExport/CSVExportManager.java index a624ebdb..bf011e30 100644 --- a/src/export/CSVExport/CSVExportManager.java +++ b/src/export/CSVExport/CSVExportManager.java @@ -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 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 + + } } diff --git a/src/export/MLExport/MLDataUnitExport.java b/src/export/MLExport/MLDataUnitExport.java index b6f2825e..8c67bbaa 100644 --- a/src/export/MLExport/MLDataUnitExport.java +++ b/src/export/MLExport/MLDataUnitExport.java @@ -84,7 +84,7 @@ public abstract class MLDataUnitExport> { 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); diff --git a/src/export/MLExport/MLDetectionsManager.java b/src/export/MLExport/MLDetectionsManager.java index 37f20911..fe05cd39 100644 --- a/src/export/MLExport/MLDetectionsManager.java +++ b/src/export/MLExport/MLDetectionsManager.java @@ -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 mlDataUnitsExport = new ArrayList(); + ArrayList mlDataUnitsExport = new ArrayList(); + + 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 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> struct = new ArrayList>(); //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=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(); + } + } + + } + + } diff --git a/src/export/MLExport/MLRawExport.java b/src/export/MLExport/MLRawExport.java index eb01a350..9271ec9f 100644 --- a/src/export/MLExport/MLRawExport.java +++ b/src/export/MLExport/MLRawExport.java @@ -39,9 +39,9 @@ public class MLRawExport extends MLDataUnitExport{ 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 diff --git a/src/export/PamDataUnitExporter.java b/src/export/PamDataUnitExporter.java index 44c10599..8ab6fa56 100644 --- a/src/export/PamDataUnitExporter.java +++ b/src/export/PamDataUnitExporter.java @@ -46,5 +46,10 @@ public interface PamDataUnitExporter { */ public String getName(); + /** + * Clsoe the exporter + */ + public void close(); + } diff --git a/src/export/PamExporterManager.java b/src/export/PamExporterManager.java index f81a50f9..61631f1a 100644 --- a/src/export/PamExporterManager.java +++ b/src/export/PamExporterManager.java @@ -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(); @@ -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; + + } + + + } diff --git a/src/export/RExport/RClickExport.java b/src/export/RExport/RClickExport.java index 68293f54..8730c118 100644 --- a/src/export/RExport/RClickExport.java +++ b/src/export/RExport/RClickExport.java @@ -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())); diff --git a/src/export/RExport/RExportManager.java b/src/export/RExport/RExportManager.java index 5ba0381d..a6cf1add 100644 --- a/src/export/RExport/RExportManager.java +++ b/src/export/RExport/RExportManager.java @@ -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 mlDataUnitsExport = new ArrayList(); + ArrayList rDataExport = new ArrayList(); + + 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 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 dataUnits){ - + public RData dataUnits2R(List 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 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 dataUnitTypes = new ArrayList(); - + + //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; i1) { - 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 dataUnitTypes; } - @Override - public boolean exportData(File fileName, List 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(); + } + } + + } diff --git a/src/export/RExport/RRawExport.java b/src/export/RExport/RRawExport.java index 1a7e7858..24f5abaa 100644 --- a/src/export/RExport/RRawExport.java +++ b/src/export/RExport/RRawExport.java @@ -52,9 +52,9 @@ public class RRawExport extends RDataUnitExport { //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 { @Override public String getName() { - return "pam_data_units"; + return "raw_data_units"; } } diff --git a/src/export/layoutFX/ExportParams.java b/src/export/layoutFX/ExportParams.java index aa68d5fe..a4c5dbdc 100644 --- a/src/export/layoutFX/ExportParams.java +++ b/src/export/layoutFX/ExportParams.java @@ -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 { diff --git a/src/export/swing/ExportProcessDialog.java b/src/export/swing/ExportProcessDialog.java index c3721a23..fd62ec6e 100644 --- a/src/export/swing/ExportProcessDialog.java +++ b/src/export/swing/ExportProcessDialog.java @@ -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; i0) { + + 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"; } } + diff --git a/src/export/swing/ExportTask.java b/src/export/swing/ExportTask.java index a3582eb2..665d9ded 100644 --- a/src/export/swing/ExportTask.java +++ b/src/export/swing/ExportTask.java @@ -25,12 +25,15 @@ public class ExportTask extends OfflineTask>{ /** * The data selector for the data block */ - private DataSelector dataSelector; + private DataSelector dataSelector; + + private boolean canExport; public ExportTask(PamDataBlock> 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>{ @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>{ } + /** + * 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; + } + } diff --git a/src/export/wavExport/WavFileExportManager.java b/src/export/wavExport/WavFileExportManager.java index 407560a8..a765a0c7 100644 --- a/src/export/wavExport/WavFileExportManager.java +++ b/src/export/wavExport/WavFileExportManager.java @@ -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(){ diff --git a/src/loggerForms/FormsTabPanel.java b/src/loggerForms/FormsTabPanel.java index 1176afd2..93d2cca4 100644 --- a/src/loggerForms/FormsTabPanel.java +++ b/src/loggerForms/FormsTabPanel.java @@ -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 diff --git a/src/metadata/MetaDataContol.java b/src/metadata/MetaDataContol.java index 98093b08..8fc66ee5 100644 --- a/src/metadata/MetaDataContol.java +++ b/src/metadata/MetaDataContol.java @@ -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); + } diff --git a/src/offlineProcessing/OLProcessDialog.java b/src/offlineProcessing/OLProcessDialog.java index bc94e2e1..79601623 100644 --- a/src/offlineProcessing/OLProcessDialog.java +++ b/src/offlineProcessing/OLProcessDialog.java @@ -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; + } + } diff --git a/src/pamViewFX/PamGuiFX.java b/src/pamViewFX/PamGuiFX.java index 80ee6983..a9d4c678 100644 --- a/src/pamViewFX/PamGuiFX.java +++ b/src/pamViewFX/PamGuiFX.java @@ -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); diff --git a/src/pamViewFX/PamGuiTabFX.java b/src/pamViewFX/PamGuiTabFX.java index c458f21e..9e1f3fb2 100644 --- a/src/pamViewFX/PamGuiTabFX.java +++ b/src/pamViewFX/PamGuiTabFX.java @@ -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) { diff --git a/src/pamViewFX/TabSelectionPane.java b/src/pamViewFX/TabSelectionPane.java index 25f862e8..2abdcbbd 100644 --- a/src/pamViewFX/TabSelectionPane.java +++ b/src/pamViewFX/TabSelectionPane.java @@ -57,14 +57,14 @@ public class TabSelectionPane extends SettingsPane { tabChoice=new ComboBox(); 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(); diff --git a/src/pamViewFX/fxNodes/PamTabPane.java b/src/pamViewFX/fxNodes/PamTabPane.java index 14ab8ab0..654f91e4 100644 --- a/src/pamViewFX/fxNodes/PamTabPane.java +++ b/src/pamViewFX/fxNodes/PamTabPane.java @@ -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); } /** diff --git a/src/pamViewFX/fxNodes/PamTabPaneSkin.java b/src/pamViewFX/fxNodes/PamTabPaneSkin.java index 9b575dc1..c795ac25 100644 --- a/src/pamViewFX/fxNodes/PamTabPaneSkin.java +++ b/src/pamViewFX/fxNodes/PamTabPaneSkin.java @@ -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); + } + + + } + } diff --git a/src/pamViewFX/fxNodes/flipPane/PamFlipPane.java b/src/pamViewFX/fxNodes/flipPane/PamFlipPane.java index 691248ba..756748bd 100644 --- a/src/pamViewFX/fxNodes/flipPane/PamFlipPane.java +++ b/src/pamViewFX/fxNodes/flipPane/PamFlipPane.java @@ -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(); }); diff --git a/src/pamViewFX/fxNodes/hidingPane/HidingPane.java b/src/pamViewFX/fxNodes/hidingPane/HidingPane.java index b60a5429..9e2ef7d8 100644 --- a/src/pamViewFX/fxNodes/hidingPane/HidingPane.java +++ b/src/pamViewFX/fxNodes/hidingPane/HidingPane.java @@ -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() { - @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() { - @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? false : true); - } - else{ - 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? false : true); + } + else{ + if (distance=expandedSize/2) showHidePane(overlay? false : true); + } + //reset the distance + distance=0; + } }); + pamButton.setOnMouseDragged(new EventHandler() { - @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() { - @Override public void handle(MouseEvent mouseEvent) { - } - }); - pamButton.setOnMouseClicked(new EventHandler() { - @Override public void handle(MouseEvent mouseEvent) { - //System.out.println("Mouse clicked"); - showHidePane(show); - } - }); - pamButton.addEventHandler(ActionEvent.ACTION,new EventHandler() { - @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() { + @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() { + @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() { +// @Override public void handle(MouseEvent mouseEvent) { +// System.out.println("HidingPane.showButton - mouse clicked"); +// showHidePane(show); +// } +// }); + + pamButton.addEventHandler(ActionEvent.ACTION,new EventHandler() { + @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(){ - @Override - public void handle(ActionEvent arg0) { - showFinished(); - } - }); + @Override + public void handle(ActionEvent arg0) { + showFinished(); + } + }); timeLineHide.setOnFinished(new EventHandler(){ - @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() { -// @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() { -// @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() { + // @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() { + // @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(); + // } + // } + } \ No newline at end of file diff --git a/src/pamViewFX/fxPlotPanes/PamHiddenSidePane.java b/src/pamViewFX/fxPlotPanes/PamHiddenSidePane.java index bee30dfa..4aaf312e 100644 --- a/src/pamViewFX/fxPlotPanes/PamHiddenSidePane.java +++ b/src/pamViewFX/fxPlotPanes/PamHiddenSidePane.java @@ -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); diff --git a/src/pamViewFX/fxPlotPanes/PlotPane.java b/src/pamViewFX/fxPlotPanes/PlotPane.java index 6f62eb2f..f85fc79b 100644 --- a/src/pamViewFX/fxPlotPanes/PlotPane.java +++ b/src/pamViewFX/fxPlotPanes/PlotPane.java @@ -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; } - - - - - - - + + + + + + + } diff --git a/src/pamguard/PAMGuard_sqlite.java b/src/pamguard/PAMGuard_sqlite.java new file mode 100644 index 00000000..7c57b1a7 --- /dev/null +++ b/src/pamguard/PAMGuard_sqlite.java @@ -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); + + } + +} diff --git a/src/rawDeepLearningClassifier/DLControl.java b/src/rawDeepLearningClassifier/DLControl.java index d22a07b3..4b7d3713 100644 --- a/src/rawDeepLearningClassifier/DLControl.java +++ b/src/rawDeepLearningClassifier/DLControl.java @@ -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); diff --git a/src/rawDeepLearningClassifier/dataPlotFX/DLPredictionPane.java b/src/rawDeepLearningClassifier/dataPlotFX/DLPredictionPane.java index c603f08f..19147c81 100644 --- a/src/rawDeepLearningClassifier/dataPlotFX/DLPredictionPane.java +++ b/src/rawDeepLearningClassifier/dataPlotFX/DLPredictionPane.java @@ -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); } diff --git a/src/rawDeepLearningClassifier/dataPlotFX/DLPredictionPlotInfoFX.java b/src/rawDeepLearningClassifier/dataPlotFX/DLPredictionPlotInfoFX.java index 44fdca6f..d5ab0f7f 100644 --- a/src/rawDeepLearningClassifier/dataPlotFX/DLPredictionPlotInfoFX.java +++ b/src/rawDeepLearningClassifier/dataPlotFX/DLPredictionPlotInfoFX.java @@ -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(); } } diff --git a/src/rawDeepLearningClassifier/dlClassification/DLClassifyProcess.java b/src/rawDeepLearningClassifier/dlClassification/DLClassifyProcess.java index b52eb089..4f487b5c 100644 --- a/src/rawDeepLearningClassifier/dlClassification/DLClassifyProcess.java +++ b/src/rawDeepLearningClassifier/dlClassification/DLClassifyProcess.java @@ -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 classificationBuffer; - + private ArrayList 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(); + classificationBuffer = new ArrayList(); //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 classificationBufferTemp = (ArrayList) classificationBuffer.clone(); + + ArrayList modelResults = this.dlControl.getDLModel().runModel(classificationBufferTemp); + + for (int i=0; i classificationBuffer2, GroupedRawData rawDataUnit) { + private boolean isRawClassificationBufferFull(ArrayList 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()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(); } diff --git a/src/rawDeepLearningClassifier/dlClassification/DLDataUnit.java b/src/rawDeepLearningClassifier/dlClassification/DLDataUnit.java index 869f9894..4fa03e38 100644 --- a/src/rawDeepLearningClassifier/dlClassification/DLDataUnit.java +++ b/src/rawDeepLearningClassifier/dlClassification/DLDataUnit.java @@ -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) { diff --git a/src/rawDeepLearningClassifier/dlClassification/DLTaskThread.java b/src/rawDeepLearningClassifier/dlClassification/DLTaskThread.java index 51d6c6e7..c1d77c41 100644 --- a/src/rawDeepLearningClassifier/dlClassification/DLTaskThread.java +++ b/src/rawDeepLearningClassifier/dlClassification/DLTaskThread.java @@ -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 groupedRawData = queue.remove(0); - ArrayList modelResult = dlModelWorker.runModel(groupedRawData, + ArrayList modelResult = dlModelWorker.runModel(groupedRawData, groupedRawData.get(0).getParentDataBlock().getSampleRate(), 0); //TODO channel? for (int i =0; i modelResult = (ArrayList) getDLWorker().runModel(groupedRawData, + ArrayList modelResult = (ArrayList) 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 ; igenericModelParams.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); } } // diff --git a/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotClassifier.java b/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotClassifier.java index 214149a3..d9374432 100644 --- a/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotClassifier.java +++ b/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotClassifier.java @@ -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 soundSpotWorker; + private DLModelWorker soundSpotWorker; public SoundSpotClassifier(DLControl dlControl) { @@ -171,7 +171,7 @@ public class SoundSpotClassifier extends StandardClassifierModel { @Override - public DLModelWorker getDLWorker() { + public DLModelWorker getDLWorker() { if (soundSpotWorker==null) { soundSpotWorker = new SoundSpotWorker(); } diff --git a/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotResult.java b/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotResult.java index 88178ab1..e94a9c56 100644 --- a/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotResult.java +++ b/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotResult.java @@ -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); diff --git a/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotWorker.java b/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotWorker.java index b7115630..735db07c 100644 --- a/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotWorker.java +++ b/src/rawDeepLearningClassifier/dlClassification/animalSpot/SoundSpotWorker.java @@ -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 { +public class SoundSpotWorker extends DLModelWorker { /** diff --git a/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java b/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java index 231a6d3e..7dda72ad 100644 --- a/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java +++ b/src/rawDeepLearningClassifier/dlClassification/animalSpot/StandardModelPane.java @@ -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 getDLWorker() { + public DLModelWorker getDLWorker() { return getModelWorker(); } diff --git a/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelWorker.java b/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelWorker.java index ab78a47b..d83086d0 100644 --- a/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelWorker.java +++ b/src/rawDeepLearningClassifier/dlClassification/archiveModel/ArchiveModelWorker.java @@ -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 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() { diff --git a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDClassifier.java b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDClassifier.java index 375efb79..29b7f66b 100644 --- a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDClassifier.java +++ b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDClassifier.java @@ -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) delphinIDParams.dlTransfromParams); } @@ -111,7 +125,7 @@ public class DelphinIDClassifier extends StandardClassifierModel { @Override - public DLModelWorker getDLWorker() { + public DLModelWorker getDLWorker() { if (delphinIDWorker==null) { delphinIDWorker = new DelphinIDWorker(); } diff --git a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDPane.java b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDPane.java index 749f01db..7a74c94b 100644 --- a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDPane.java +++ b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDPane.java @@ -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 { - +public class DelphinIDPane extends SettingsPane { + /** * The main pane. */ private Pane mainPane; - + /** * Reference to the delphinID classifier */ private DelphinIDClassifier delphinUIClassifier; + private PamSpinner 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(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 { @Override public void paneInitialized() { // TODO Auto-generated method stub - + } } diff --git a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDParams.java b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDParams.java index 8cbe9398..e655270c 100644 --- a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDParams.java +++ b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDParams.java @@ -8,5 +8,11 @@ public class DelphinIDParams extends StandardModelParams { * */ private static final long serialVersionUID = 1L; + + /** + * The minimum detection density. + */ + public double minDetectionDensity = 0.3; + } diff --git a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDPrediction.java b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDPrediction.java index b5140ee4..158f013a 100644 --- a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDPrediction.java +++ b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDPrediction.java @@ -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); diff --git a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDTest.java b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDTest.java new file mode 100644 index 00000000..eb8e72d6 --- /dev/null +++ b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDTest.java @@ -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 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 whistleContours = DelphinIDUtils.getWhistleContoursMAT(whistleContourPath); + + //segment the whistle detections + ArrayList segments = DelphinIDUtils.segmentWhsitleData(whistleContours, (long) (dataStartMillis+(9.565*1000.)), + segLen, segHop); + + for (int i=0; i aSegment = new ArrayList(); + aSegment.add(segments.get(i)); + + //the prediciton. + ArrayList 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 getWhistleContoursMAT(String filePath){ + + ArrayList contours = new ArrayList(); + + // 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 getWhistleContoursMAT(Struct whistlesStruct, double fftLen, double fftHop, double sampleRate){ + + ArrayList contours = new ArrayList(); + + + 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 segmentWhsitleData(ArrayList whistles, long dataStartMillis, + double segLen, double segHop){ + + ArrayList group = new ArrayList(); + + //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=segStart && whistleStart=segStart && whistleEnd> contourData = TxtFileUtils.importCSVData(csvFile); + ArrayList whistles = getWhistleContoursMAT(whistlesStruct, fftLen, fftHop, sampleRate); + + //segment the whistle detections + ArrayList 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 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 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 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); + } + } + +} diff --git a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDWorker.java b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDWorker.java index e4f83bd5..bb3ef58a 100644 --- a/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDWorker.java +++ b/src/rawDeepLearningClassifier/dlClassification/delphinID/DelphinIDWorker.java @@ -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 dataUnits, float sampleRate, int iChan){ - + //Get a list of of the model transforms. ArrayList modelTransforms = getModelTransforms(); @SuppressWarnings("unchecked") - ArrayList whistleGroups = (ArrayList) dataUnits; - + ArrayList whistleGroups = (ArrayList) 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 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 whistContours2Points(SegmenterDetectionGroup whistleGroup) { + + ArrayList contours = new ArrayList(); + + AbstractWhistleDataUnit whistleContour; + + long segStart = whistleGroup.getSegmentStartMillis(); + long segEnd = (long) (whistleGroup.getSegmentStartMillis() + whistleGroup.getSegmentDuration()); + + +// for (int i=0; i=segStart && whistleStart=segStart && whistleEnd 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, 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; igenericModelParams.threshold && genericModelParams.binaryClassification[i]) { - // System.out.println("SoundSpotClassifier: prediciton: " + i + " passed threshold with val: " + modelResult.getPrediction()[i]); - return true; - } - } - return false; - } - - // @Override // public ArrayList checkSettingsOK() { // return checkSettingsOK(genericModelParams, dlControl); @@ -234,7 +203,7 @@ public class GenericDLClassifier extends StandardClassifierModel { } @Override - public DLModelWorker getDLWorker() { + public DLModelWorker getDLWorker() { return this.genericModelWorker; } diff --git a/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelWorker.java b/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelWorker.java index fa7ecdd7..45863142 100644 --- a/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelWorker.java +++ b/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericModelWorker.java @@ -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 { +public class GenericModelWorker extends DLModelWorker { /** * The generic model @@ -32,7 +33,7 @@ public class GenericModelWorker extends DLModelWorker { @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 { //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; } diff --git a/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericPrediction.java b/src/rawDeepLearningClassifier/dlClassification/genericModel/StandardPrediction.java similarity index 90% rename from src/rawDeepLearningClassifier/dlClassification/genericModel/GenericPrediction.java rename to src/rawDeepLearningClassifier/dlClassification/genericModel/StandardPrediction.java index 57e83218..b2f93dd7 100644 --- a/src/rawDeepLearningClassifier/dlClassification/genericModel/GenericPrediction.java +++ b/src/rawDeepLearningClassifier/dlClassification/genericModel/StandardPrediction.java @@ -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); } diff --git a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosClassifier.java b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosClassifier.java index 437f8250..d224a013 100644 --- a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosClassifier.java +++ b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosClassifier.java @@ -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 getDLWorker() { + public DLModelWorker getDLWorker() { return getKetosWorker(); } diff --git a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosResult.java b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosResult.java index 510c311d..ca4777ff 100644 --- a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosResult.java +++ b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosResult.java @@ -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) { diff --git a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker.java b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker.java index 3a937c1b..a42422db 100644 --- a/src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker.java +++ b/src/rawDeepLearningClassifier/dlClassification/ketos/KetosWorker.java @@ -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 { +public class KetosWorker extends DLModelWorker { /** diff --git a/src/rawDeepLearningClassifier/dlClassification/koogu/KooguClassifier.java b/src/rawDeepLearningClassifier/dlClassification/koogu/KooguClassifier.java index 411d6551..df7e049a 100644 --- a/src/rawDeepLearningClassifier/dlClassification/koogu/KooguClassifier.java +++ b/src/rawDeepLearningClassifier/dlClassification/koogu/KooguClassifier.java @@ -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. diff --git a/src/rawDeepLearningClassifier/layoutFX/defaultModels/DefaultModelPane.java b/src/rawDeepLearningClassifier/layoutFX/defaultModels/DefaultModelPane.java index 755bd5db..b6b2078d 100644 --- a/src/rawDeepLearningClassifier/layoutFX/defaultModels/DefaultModelPane.java +++ b/src/rawDeepLearningClassifier/layoutFX/defaultModels/DefaultModelPane.java @@ -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; } diff --git a/src/rawDeepLearningClassifier/logging/ModelResultBinaryFactory.java b/src/rawDeepLearningClassifier/logging/ModelResultBinaryFactory.java index 91b10536..84a56dee 100644 --- a/src/rawDeepLearningClassifier/logging/ModelResultBinaryFactory.java +++ b/src/rawDeepLearningClassifier/logging/ModelResultBinaryFactory.java @@ -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) { diff --git a/src/rawDeepLearningClassifier/segmenter/SegmenterDataBlock.java b/src/rawDeepLearningClassifier/segmenter/SegmenterDataBlock.java index 34f4fc86..5e2d6daa 100644 --- a/src/rawDeepLearningClassifier/segmenter/SegmenterDataBlock.java +++ b/src/rawDeepLearningClassifier/segmenter/SegmenterDataBlock.java @@ -21,5 +21,5 @@ public class SegmenterDataBlock extends PamDataBlock { //need this to notify classifier in viewer mode. return true; } - + } diff --git a/src/rawDeepLearningClassifier/segmenter/SegmenterDetectionGroup.java b/src/rawDeepLearningClassifier/segmenter/SegmenterDetectionGroup.java index 1a00c4a3..6c152634 100644 --- a/src/rawDeepLearningClassifier/segmenter/SegmenterDetectionGroup.java +++ b/src/rawDeepLearningClassifier/segmenter/SegmenterDetectionGroup.java @@ -10,6 +10,19 @@ import PamguardMVC.PamDataUnit; */ public class SegmenterDetectionGroup extends GroupDetection { + + /** + * The duration of the segment in millis. + */ + private double segDuration; + + /** + * The start time fo the segment in millis. + */ + private long segMillis; + + private double timeS; + /** * Constructor for a group of detections within a detection. Note that some * longer detections (e.g. whistles) may have sections outside the segment. @@ -17,11 +30,45 @@ public class SegmenterDetectionGroup extends GroupDetection { * @param timeMilliseconds - this is the start of the SEGMENT - Note that the * @param channelBitmap - channels of all detections * @param startSample - the stratSample of the SEGMENT. - * @param duration - the duration of the SEGMENT. + * @param duration - the duration of the SEGMENT in milliseconds. */ - public SegmenterDetectionGroup(long timeMilliseconds, int channelBitmap, long startSample, long duration) { - super(timeMilliseconds, channelBitmap, startSample, duration); - // TODO Auto-generated constructor stub + public SegmenterDetectionGroup(long timeMilliseconds, int channelBitmap, long startSample, double duration) { + super(timeMilliseconds, channelBitmap, startSample, (long) duration); + this.setDurationInMilliseconds(duration); + this.segMillis = timeMilliseconds; + this.segDuration = duration; + } + + @Override + public boolean isAllowSubdetectionSharing() { + //segmetns share sub detections + return true; + } + + + public long getSegmentStartMillis() { + return segMillis; + } + + /** + * Get the segment duration in milliseconds. + * @return the segment duration in millis. + */ + public double getSegmentDuration() { + return segDuration; } + public long getSegmentEndMillis() { + return (long) (segMillis+segDuration); + } + + public void setStartSecond(double timeS) { + this.timeS = timeS; + } + + public double getStartSecond() { + return timeS; + } + + } diff --git a/src/rawDeepLearningClassifier/segmenter/SegmenterGroupDataBlock.java b/src/rawDeepLearningClassifier/segmenter/SegmenterGroupDataBlock.java index cbd18e3a..3a69c23a 100644 --- a/src/rawDeepLearningClassifier/segmenter/SegmenterGroupDataBlock.java +++ b/src/rawDeepLearningClassifier/segmenter/SegmenterGroupDataBlock.java @@ -12,7 +12,9 @@ public class SegmenterGroupDataBlock extends PamDataBlock>(Arrays.asList(RawDataUnit.class, ClickDetection.class, ClipDataUnit.class)); + return new ArrayList>(Arrays.asList(RawDataUnit.class, ClickDetection.class, ClipDataUnit.class, ConnectedRegionDataUnit.class)); } @@ -149,6 +166,7 @@ public class SegmenterProcess extends PamProcess { if (chanGroups!=null) { currentRawChunks = new GroupedRawData[chanGroups.length]; nextRawChunks = new GroupedRawData[chanGroups.length][]; + segmenterDetectionGroup = new SegmenterDetectionGroup[chanGroups.length]; } @@ -177,6 +195,8 @@ public class SegmenterProcess extends PamProcess { if (rawDataBlock==null) return; setParentDataBlock(rawDataBlock); + + this.firstClockUpdate = -1; } @@ -203,9 +223,10 @@ public class SegmenterProcess extends PamProcess { */ public void newData(PamDataUnit pamRawData) { +// System.out.println("New data for segmenter: " + pamRawData); + if (!dlControl.getDLParams().useDataSelector || dlControl.getDataSelector().scoreData(pamRawData)>0) { - //System.out.println("New data for segmenter: " + pamRawData); if (pamRawData instanceof RawDataUnit) { newRawDataUnit(pamRawData); } @@ -224,18 +245,151 @@ public class SegmenterProcess extends PamProcess { /** - * A new whistle data unit. + * A new detection data unit i.e. this is only if we have detection data which is being grouped into segments. * @param dataUnit - the whistle data unit. */ - private void newWhistleData(PamDataUnit dataUnit) { + private synchronized void newWhistleData(PamDataUnit dataUnit) { + + ConnectedRegionDataUnit whistle = (ConnectedRegionDataUnit) dataUnit; //TODO //this contains no raw data so we are branching off on a completely different processing path here. - //Whislte data units are saved to a buffer and then fed to the deep learning algorohtm + //Whislte data units are saved to a buffer and then fed to the deep learning algorithms + int[] chanGroups = dlControl.getDLParams().groupedSourceParams.getChannelGroups(); + + int index = -1; + for (int i=0; i0) { + this.segmenterGroupDataBlock.addPamData(segmenterDetectionGroup[index]); + } + } + + segmenterDetectionGroup[index] = aSegment; +// System.out.println("NEW SEGMENT START!: " + (segmentStart-firstClockUpdate)/1000. + "s" + " " + segmenterDetectionGroup[index].getSegmentStartMillis()+ " " +segmenterDetectionGroup[index]); + + } + + private boolean detectionInSegment(PamDataUnit dataUnit, SegmenterDetectionGroup segmenterDetectionGroup2) { + return detectionInSegment(dataUnit, segmenterDetectionGroup2.getSegmentStartMillis(), + (long) (segmenterDetectionGroup2.getSegmentStartMillis()+segmenterDetectionGroup2.getSegmentDuration())); + } + + + private boolean detectionInSegment(PamDataUnit dataUnit, long segStart, long segEnd) { + //TODO - this is going to fail for very small segments. + long whistleStart = dataUnit.getTimeMilliseconds(); + long whistleEnd = whistleStart + dataUnit.getDurationInMilliseconds().longValue(); + + if ((whistleStart>=segStart && whistleStart=segStart && whistleEnd implements PamTabPanel // public 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); public TargetMotionMainPanel(TargetMotionLocaliser targetMotionLocaliser) { diff --git a/src/test/rawDeepLearningClassifier/DelphinIDTest.java b/src/test/rawDeepLearningClassifier/DelphinIDTest.java new file mode 100644 index 00000000..f0a9cbc4 --- /dev/null +++ b/src/test/rawDeepLearningClassifier/DelphinIDTest.java @@ -0,0 +1,262 @@ +package test.rawDeepLearningClassifier; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; + +import org.jamdev.jdl4pam.transforms.DLTransform; +import org.jamdev.jdl4pam.transforms.FreqTransform; +import org.jamdev.jdl4pam.transforms.DLTransform.DLTransformType; +import org.jamdev.jdl4pam.utils.DLMatFile; +import org.jamdev.jdl4pam.utils.DLUtils; +import org.jamdev.jpamutils.JamArr; +import org.jamdev.jpamutils.interpolation.Bicubic; +import org.jamdev.jpamutils.interpolation.Bilinear; +import org.jamdev.jpamutils.interpolation.NearestNeighbor; +import org.jamdev.jpamutils.spectrogram.SpecTransform; +import org.junit.jupiter.api.Test; + +import ai.djl.MalformedModelException; +import rawDeepLearningClassifier.dlClassification.archiveModel.SimpleArchiveModel; +import rawDeepLearningClassifier.dlClassification.delphinID.Whistles2Image; +import us.hebi.matlab.mat.format.Mat5; +import us.hebi.matlab.mat.types.MatFile; +import us.hebi.matlab.mat.types.Matrix; + +public class DelphinIDTest { + + + private static double[][] whistleScatter2Image(double[][] whistleValues) { + + //now perform the image transform in Java + double[] freqLimits = new double[] {2000., 20000.}; + double[] size = new double[] {680., 480.}; + + ArrayList whistleImageArr = new ArrayList(); + whistleImageArr.add(whistleValues); + + BufferedImage canvas = Whistles2Image.makeScatterImage(whistleImageArr, size, new double[]{50, 50. + 4.}, freqLimits, 6.); + + double[][] imaged = new double[(int) size[0]][(int) size[1]]; + + float[] color = new float[3]; + Raster raster = canvas.getData(); + for (int i=0; i modelTransforms = new ArrayList(); + modelTransforms.add(new FreqTransform(DLTransformType.SPECFLIP)); +// modelTransforms.add(new FreqTransform(DLTransformType.SPECNORMALISE_MINIMAX)); + modelTransforms.add(new FreqTransform(DLTransformType.SPECRESIZE, new Number[] {Integer.valueOf(60), Integer.valueOf(80), SpecTransform.RESIZE_BICUBIC})); + modelTransforms.add(new FreqTransform(DLTransformType.GAUSSIAN_FILTER, new Number[] {Double.valueOf(0.5)})); + + + SpecTransform specTransform = new SpecTransform(); + specTransform.setSpecData(imaged); + specTransform.setSampleRate((float) (freqLimits[1]*2)); + + + //set the spec transform + ((FreqTransform) modelTransforms.get(0)).setSpecTransfrom(specTransform); + + //process all the transforms. + DLTransform transform = modelTransforms.get(0); + for (int i =0; i whistleImageArr = new ArrayList(); + whistleImageArr.add(whistleValues); + + BufferedImage canvas = Whistles2Image.makeScatterImage(whistleImageArr, size, new double[]{50, 50. + 4.}, freqLimits, 10.); + + double[][] imaged = new double[(int) size[0]][(int) size[1]]; + + float[] color = new float[3]; + Raster raster = canvas.getData(); + for (int i=0; i modelTransforms = new ArrayList(); + modelTransforms.add(new FreqTransform(DLTransformType.SPECFLIP)); +// modelTransforms.add(new FreqTransform(DLTransformType.SPECNORMALISE_MINIMAX)); + modelTransforms.add(new FreqTransform(DLTransformType.SPECRESIZE, new Number[] {Integer.valueOf(60), Integer.valueOf(80), SpecTransform.RESIZE_BICUBIC})); + modelTransforms.add(new FreqTransform(DLTransformType.GAUSSIAN_FILTER, new Number[] {Double.valueOf(0.5)})); + + + SpecTransform specTransform = new SpecTransform(); + specTransform.setSpecData(imaged); + specTransform.setSampleRate((float) (freqLimits[1]*2)); + + + //set the spec transform + ((FreqTransform) modelTransforms.get(0)).setSpecTransfrom(specTransform); + + //process all the transforms. + DLTransform transform = modelTransforms.get(0); + for (int i =0; i gwenericPrediciton = genericModelWorker.runModel(groupedData, soundData.sampleRate, 0); + ArrayList gwenericPrediciton = genericModelWorker.runModel(groupedData, soundData.sampleRate, 0); float[] output = gwenericPrediciton.get(0).getPrediction(); @@ -165,7 +165,7 @@ public class GenericDLClassifierTest { groupedData.add(groupedRawData); - ArrayList genericPrediction = genericModelWorker.runModel(groupedData, soundData.sampleRate, 0); + ArrayList genericPrediction = genericModelWorker.runModel(groupedData, soundData.sampleRate, 0); float[] output = genericPrediction.get(0).getPrediction(); diff --git a/src/test/rawDeepLearningClassifier/KetosDLClassifierTest.java b/src/test/rawDeepLearningClassifier/KetosDLClassifierTest.java index b898810b..fc590764 100644 --- a/src/test/rawDeepLearningClassifier/KetosDLClassifierTest.java +++ b/src/test/rawDeepLearningClassifier/KetosDLClassifierTest.java @@ -13,7 +13,7 @@ import javax.sound.sampled.UnsupportedAudioFileException; import org.jamdev.jdl4pam.utils.DLUtils; import org.jamdev.jpamutils.wavFiles.AudioData; -import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction; +import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction; import rawDeepLearningClassifier.dlClassification.ketos.KetosDLParams; import rawDeepLearningClassifier.dlClassification.ketos.KetosWorker2; import rawDeepLearningClassifier.segmenter.GroupedRawData; @@ -140,7 +140,7 @@ public class KetosDLClassifierTest { ArrayList groupedData = new ArrayList(); groupedData.add(groupedRawData); - ArrayList genericPrediciton = ketosWorker2.runModel(groupedData, soundData.sampleRate, 0); + ArrayList genericPrediciton = ketosWorker2.runModel(groupedData, soundData.sampleRate, 0); float[] output = genericPrediciton.get(0).getPrediction(); boolean testPassed= output[1]> ketosPredicitons[i][2]-0.1 && output[1]< ketosPredicitons[i][2]+0.1; diff --git a/src/test/rawDeepLearningClassifier/KooguDLClassifierTest.java b/src/test/rawDeepLearningClassifier/KooguDLClassifierTest.java index 6a13ec46..e3ea9c5b 100644 --- a/src/test/rawDeepLearningClassifier/KooguDLClassifierTest.java +++ b/src/test/rawDeepLearningClassifier/KooguDLClassifierTest.java @@ -16,7 +16,7 @@ import org.jamdev.jpamutils.wavFiles.AudioData; import org.junit.jupiter.api.Test; import rawDeepLearningClassifier.dlClassification.animalSpot.StandardModelParams; -import rawDeepLearningClassifier.dlClassification.genericModel.GenericPrediction; +import rawDeepLearningClassifier.dlClassification.genericModel.StandardPrediction; import rawDeepLearningClassifier.dlClassification.koogu.KooguModelWorker; import rawDeepLearningClassifier.segmenter.GroupedRawData; import us.hebi.matlab.mat.format.Mat5; @@ -102,7 +102,7 @@ public class KooguDLClassifierTest { groupedData.add(groupedRawData); - ArrayList genericPrediciton = kooguWorker.runModel(groupedData, soundData.sampleRate, 0); + ArrayList genericPrediciton = kooguWorker.runModel(groupedData, soundData.sampleRate, 0); float[] output = genericPrediciton.get(0).getPrediction(); boolean testPassed= output[1]> kooguPredicitions[i][2]-0.1 && output[1]< kooguPredicitions[i][2]+0.1; diff --git a/src/test/resources/rawDeepLearningClassifier/DelphinID/whistle_image_example.mat b/src/test/resources/rawDeepLearningClassifier/DelphinID/whistle_image_example.mat new file mode 100644 index 00000000..4b430277 Binary files /dev/null and b/src/test/resources/rawDeepLearningClassifier/DelphinID/whistle_image_example.mat differ diff --git a/src/tethys/localization/LocalizationHandler.java b/src/tethys/localization/LocalizationHandler.java index 69105b5e..3751df93 100644 --- a/src/tethys/localization/LocalizationHandler.java +++ b/src/tethys/localization/LocalizationHandler.java @@ -1,17 +1,17 @@ package tethys.localization; -import nilus.CylindricalCoordinateType; -import nilus.LocalizationType; -import nilus.Localize.Effort.CoordinateReferenceSystem; +//import nilus.CylindricalCoordinateType; +//import nilus.LocalizationType; +//import nilus.Localize.Effort.CoordinateReferenceSystem; public class LocalizationHandler { - public LocalizationType getLoc() { - LocalizationType lt = new LocalizationType(); - CylindricalCoordinateType cct = new CylindricalCoordinateType(); -// cct.set - CoordinateReferenceSystem cr; - return null; - } +// public LocalizationType getLoc() { +// LocalizationType lt = new LocalizationType(); +// CylindricalCoordinateType cct = new CylindricalCoordinateType(); +//// cct.set +// CoordinateReferenceSystem cr; +// return null; +// } }