Bug fixes to Match Template classifier

1) When a large template was imported only 1: fftLength of the mathc waveform was used and so clicks would be correlated with noise. The peak of the template is now used when the peak search function is selected.
2) The plus button in the tab pane had disappeared.
3) Seems like the decimators were the wrong round. So the waveforms were using an up sample function when they should have been using a decimator function. and vice versa...major bug when using different sample rates!
This commit is contained in:
Jamie Mac 2023-12-14 12:06:51 +00:00
parent 25691563bf
commit 60b76fb711
21 changed files with 372 additions and 107 deletions

View File

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

View File

@ -23,7 +23,7 @@ public class InterpChoicePane extends InterpSettingsPane {
interpChoiceBox = new ChoiceBox<Integer>();
interpChoiceBox.getItems().addAll(interpChoice);
interpChoiceBox.setMaxWidth(Double.MAX_VALUE);
interpChoiceBox.setConverter(new StringConverter<>() {
@Override

View File

@ -490,14 +490,14 @@ public class StreamerSettingsPane extends SettingsPane<Streamer> {
defaultStreamer.setDz(Double.valueOf(zPosErr.getText()));
}
catch (NumberFormatException e) {
System.err.println("There is a problem with one of the position parameters in the streamer panel");
System.err.println("Streamer getParams: There is a problem with one of the position parameters in the streamer panel");
return null;
}
defaultStreamer.setStreamerName(currParams.getStreamerName());
int im = interpPane.getSelection();
if (im < 0) {
System.err.println("There is a problem with the interpolation selection streamer panel");
System.err.println("Streamer getParams: There is an index problem with the interpolation selection streamer panel: index = " + im);
}
currentArray.setOriginInterpolation(im);
// try {
@ -516,7 +516,7 @@ public class StreamerSettingsPane extends SettingsPane<Streamer> {
// }
// masterLocator.setHydrophoneLocator(streamerIndex, locator);
if (currentOriginMethod == null) {
System.err.println("No hydrophoneorigin method selected in streamer panel");
System.err.println("Streamer getParams: No hydrophoneorigin method selected in streamer panel");
}
OriginDialogComponent mthDialogComponent = currentOriginMethod.getDialogComponent();
if (mthDialogComponent != null) {
@ -532,13 +532,13 @@ public class StreamerSettingsPane extends SettingsPane<Streamer> {
defaultStreamer.setRoll(getDoubleValue(roll));
// }
if (!heading.isDisable() && defaultStreamer.getHeading() == null) {
System.err.println("You must enter a fixed value for the streamer heading");
System.err.println("Streamer getParams: You must enter a fixed value for the streamer heading");
}
if (!pitch.isDisable() && defaultStreamer.getPitch() == null) {
System.err.println("You must enter a fixed value for the streamer pitch");
System.err.println("Streamer getParams: You must enter a fixed value for the streamer pitch");
}
if (!roll.isDisable() && defaultStreamer.getRoll() == null) {
System.err.println("You must enter a fixed value for the streamer roll");
System.err.println("Streamer getParams: You must enter a fixed value for the streamer roll");
}
@ -563,13 +563,13 @@ public class StreamerSettingsPane extends SettingsPane<Streamer> {
}
}
return currParams;
return defaultStreamer;
}
@Override
public void setParams(Streamer input) {
if (input==null) {
System.out.print("The input streamer is null");
System.out.print("Streamer setParams: The input streamer is null");
}
this.defaultStreamer=input;
// origin methods
@ -616,21 +616,24 @@ public class StreamerSettingsPane extends SettingsPane<Streamer> {
OriginDialogComponent mthDialogComponent = mth.getDialogComponent();
if (mthDialogComponent != null) {
System.out.println("Streamer setParams: Set origin component: ");
mthDialogComponent.setParams();
}
System.out.println("Set orientation: " + defaultStreamer.getHeading() + " " + defaultStreamer.getPitch() + " " + defaultStreamer.getRoll());
System.out.println("Streamer setParams: Set orientation: " + defaultStreamer.getHeading() + " " + defaultStreamer.getPitch() + " " + defaultStreamer.getRoll());
heading .setText(orientation2Text(defaultStreamer.getHeading()));
pitch .setText(orientation2Text(defaultStreamer.getPitch()));
roll .setText(orientation2Text(defaultStreamer.getRoll()));
System.out.println("Origin interpolator: " + currentArray.getOriginInterpolation());
System.out.println("Streamer setParams: Origin interpolator: " + currentArray.getOriginInterpolation());
if (currentArray.getOriginInterpolation()<0) {
interpPane.setSelection(0);
}
else interpPane.setSelection(currentArray.getOriginInterpolation());
else {
interpPane.setSelection(currentArray.getOriginInterpolation());
}
ArraySensorFieldType[] sensorFields = ArraySensorFieldType.values();
for (int i = 0; i < sensorFields.length; i++) {

View File

@ -55,7 +55,7 @@ public class StreamersPane extends PamBorderPane {
this.setCenter(tableArrayPane);
pamFlipePane = new PamFlipPane();
pamFlipePane.getAdvLabel().setText("Hydrophone Settings");
pamFlipePane.getAdvLabel().setText("Streamer");
((Pane) streamerPane.getContentNode()).setPadding(new Insets(5,5,5,15));

View File

@ -449,12 +449,13 @@ public class PamArrayUtils {
return new int[] {min, max};
}
/**
* Calculate the maximum value in an array
* @param arr - the array to find the maximum value of.
* @return the maximum value in the array
*/
public static double max(double[] arr) {
public static double max(float[] arr) {
double max = Double.NEGATIVE_INFINITY;
for(double cur: arr)
@ -468,7 +469,7 @@ public class PamArrayUtils {
* @param arr - the array to find the maximum value of.
* @return the maximum value in the array
*/
public static double max(float[] arr) {
public static double max(double[] arr) {
double max = Double.NEGATIVE_INFINITY;
for(double cur: arr)
@ -491,6 +492,50 @@ public class PamArrayUtils {
return max;
}
/**
* Get the index of the maximum value in an array
* @param arr - the array to find the position of the maximum value.
* m value of.
* @return the index of the maximum value
*/
public static int maxPos(double[] arr) {
double max = Double.NEGATIVE_INFINITY;
int index = -1;
int count = 0;
for(double cur: arr) {
if (cur>max) {
index = count;
max=cur;
}
count++;
}
return index;
}
/**
* Get the minimum index of an array
* @param arr - the array to find the position of the maximum value.
* m value of.
* @return the index of the minimum value
*/
public static int minPos(double[] arr) {
double max = Double.POSITIVE_INFINITY;
int index = -1;
int count = 0;
for(double cur: arr) {
if (cur<max) {
index = count;
max=cur;
}
count++;
}
return index;
}
/**
* Get the minimum value in an array
* @param arr - the array to find the minimu
@ -506,6 +551,8 @@ public class PamArrayUtils {
return min;
}
/**
* Get the minimum value in an array
* @param arr - the array to find the minimum value of.
@ -1020,5 +1067,8 @@ public class PamArrayUtils {
}

View File

@ -6,6 +6,7 @@ import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
@ -89,10 +90,20 @@ public class TxtFileUtils {
//5/08/2022 - there was a bug here where there is some sort of invisible character that does not appear on the
//print screen - the only way you can tell is the char array is greater than the number of digits - removed all non numeric
//characters.
// if (recordsOnLine[i].contains("e") || recordsOnLine[i].contains("E")) {
// //need to check whether scientific notation might be used here
//// dat = new BigDecimal(recordsOnLine[i]).doubleValue();
// dat = Double.valueOf(recordsOnLine[i]);
// }
// else {
//note that this gets rid of numbers like 3.84e+05
// updated again on 15/11/23 to include - signs, or you end up with the abs(of every number!)
String number = new String(recordsOnLine[i].strip().replaceAll("[^\\d.-]", ""));
//also added E and e to neglected characters to ensure scientific notation can be used,
String number = new String(recordsOnLine[i].strip().replaceAll("[^Ee\\d.-]", ""));
dat = Double.valueOf(number);
//dat = DecimalFormat.getNumberInstance().parse(new String(recordsOnLine[i].strip().toCharArray())).doubleValue();
// }
}
catch (Exception e){
e.printStackTrace();

View File

@ -395,7 +395,7 @@ public class ClickBTDisplay extends ClickDisplay implements PamObserver, PamSett
int subDetInd = superDet.findSubdetectionInfo(clickDetection);
for (int i = subDetInd-1; i >= 0; i--) {
PamDataUnit subDet = superDet.getSubDetection(i);
if (subDet.getChannelBitmap() == clickDetection.getChannelBitmap()) {
if (subDet!=null && subDet.getChannelBitmap() == clickDetection.getChannelBitmap()) {
double ici = (double) (clickDetection.getTimeMilliseconds() - subDet.getTimeMilliseconds())/1000.;
clickDetection.setTempICI(ici);
break;

View File

@ -6,6 +6,7 @@ import pamViewFX.fxNodes.flipPane.PamFlipPane;
import pamViewFX.fxNodes.table.TableSettingsPane;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
@ -108,6 +109,7 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
protected Node createSettingsPane(){
mainHolderPane=new PamBorderPane();
mainHolderPane.setPadding(new Insets(5,5,5,5));
mainHolderPane.setCenter(clickTypesTable=new ClickClassifierTable(clickClassifiers));
clickTypeHolder=new PamBorderPane();

View File

@ -110,7 +110,7 @@ public class ClickClassifyPaneFX extends PamStackPane {
//create the main pane.
PamVBox holderPane=new PamVBox();
// holderPane.setPadding(new Insets(5,5,5,5));
holderPane.setPadding(new Insets(5,5,5,5));
holderPane.setSpacing(5);
//create label

View File

@ -8,7 +8,9 @@ import clickDetector.ClickClassifiers.basicSweep.SweepClassifierParameters;
import clickDetector.ClickClassifiers.basicSweep.SweepClassifierSet;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import javafx.scene.layout.Region;
import javafx.scene.text.Font;
import javafx.geometry.Insets;
/**
* Slightly different pane for the sweep classifier.
@ -43,13 +45,15 @@ public class SweepClassifierPaneFX extends BasicIdentifierPaneFX {
public void setClassifierPane(ClickTypeProperty clickTypeProperty){
SweepClassifierSetPaneFX sweepPane=new SweepClassifierSetPaneFX(sweepClickClassifier);
//set padding - want the flip pane not to have padding so back button reaches edge of node.
((Region) sweepPane.getContentNode()).setPadding(new Insets(5,5,5,5));
//make it so the title of the pane is the same as the name as the classifier
getFlipPane().getAdvLabel().textProperty().unbind();
getFlipPane().getAdvLabel().textProperty().bind(sweepPane.getNameTextProperty());
getFlipPane().getPreAdvLabel().graphicProperty().bind(sweepPane.getNameGraphicProperty());
sweepPane.classifierItemRow = sweepClickClassifier.getSweepClassifierParams().getSetRow((SweepClassifierSet) clickTypeProperty.getClickType());
sweepPane.setParams(clickTypeProperty);

View File

@ -2,7 +2,9 @@ package matchedTemplateClassifer
;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import PamUtils.PamArrayUtils;
import PamUtils.TxtFileUtils;
@ -44,16 +46,21 @@ public class ImportTemplateCSV implements TemplateImport {
//System.out.println("i: " + i + " : " + data.get(0).get(i));
waveform[i]=data.get(0).get(i);
}
// System.out.println("String sR = " + data.get(1).get(0));
float sR=data.get(1).get(0).floatValue();
//used big decimal here because String.,floatValue did not handle numbers like 3.85e05
float sR = new BigDecimal(data.get(1).get(0)).floatValue();
// float sR=data.get(1).get(0).floatValue();
//System.out.println("imported waveform");
//PamArrayUtils.printArrayRaw(waveform);
//now create waveform
// System.out.println("Create a waveform with " + waveform.length + " samples with a sample rate of "
// + sR + " Hz");
System.out.println("Import a waveform with " + waveform.length + " samples with a sample rate of "
+ sR + " Hz ");
MatchTemplate matchedTemplate = new MatchTemplate(filePath.getName(), waveform, sR);
//TODO
return matchedTemplate;

View File

@ -129,7 +129,7 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
if (fft==null) fft=new FastFFT();
//System.out.println("interpWaveform: " + waveformMatch.waveform.length + " sR " + waveformMatch.sR);
// System.out.println("interpWaveform: " + waveformMatch.waveform.length + " sR " + waveformMatch.sR);
//re-sample the waveform if the sample rate is different
this.interpWaveformMatch=interpWaveform(this.waveformMatch, sR);
@ -145,7 +145,12 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// System.out.println("MatchNorm: MATCH");
// MTClassifierTest.normalizeTest(interpWaveformMatch);
waveformMatchFFT = fft.rfft(interpWaveformMatch, length);
/**
* There is an issue here because, if we have a long template waveform, then it
* will become truncated and the actual waveform may be missed. This means we
* have to use the peak of the template
*/
waveformMatchFFT = calcTemplateFFT(interpWaveformMatch, length);
//need to calculate the complex conjugate - note that originally I was flipping the array but this means
//the max value does not equal one with identical waveforms...doh.
@ -158,6 +163,42 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
}
/**
* Calculate the FFT of an interpolate match template.
* @param interpTemplateWaveform - the waveform interpolated to the correct sample rate.
* @param length - the length of the FFT.
* @return the FFT of the waveform as a complex array.
*/
private ComplexArray calcTemplateFFT(double[] interpTemplateWaveform, int length) {
ComplexArray fftTemplate;
/**
* There is an issue here because, if we have a long template waveform, then it
* will become truncated and the actual waveform may be missed. This means we
* have to use the peak of the template
*/
if (interpTemplateWaveform.length>length) {
//If the template is long then need to find the peak, otherwise we will end up cross correlating with noise at the
//start of the template.
//because this is a template and not a random click we don't need to be so clever with how we find peaks. Find
//the maximum and use around that.
int pos = PamArrayUtils.maxPos(interpTemplateWaveform);
int startind = Math.max(0, pos-length/2);
int endind = startind+length-1;
double[] peakTemplate = ArrayUtils.subarray(interpTemplateWaveform, startind, endind);
fftTemplate = fft.rfft(peakTemplate, length);
}
else {
//template waveform is padded by fft function
fftTemplate = fft.rfft(interpTemplateWaveform, length);
}
return fftTemplate;
}
/**
* Get the match waveform for the sample rate
@ -181,13 +222,17 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// this.inteprWaveformReject=PamArrayUtils.divide(inteprWaveformReject, PamArrayUtils.max(inteprWaveformReject));
this.inteprWaveformReject = normaliseWaveform(inteprWaveformReject, this.normalisation);
// System.out.println("MatchNorm: REJECT ");
// MTClassifierTest.normalizeTest(inteprWaveformReject);
// MTClassifierTest.printWaveform(inteprWaveformReject);
//System.out.println("waveformReject: " +inteprWaveformReject.length + " fftLength: " + getFFTLength(sR));
waveformRejectFFT = fft.rfft(inteprWaveformReject, length);
/**
* There is an issue here because, if we have a long template waveform, then it
* will become truncated and the actual waveform may be missed. This means we
* have to use the peak of the template
*/
waveformRejectFFT = calcTemplateFFT(inteprWaveformReject, length);
//need to calculate the complex conjugate - note that originally I was flipping the array but this means
//the max value does not equal one with identical waveforms...doh.
@ -293,7 +338,7 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
ComplexArray matchTemplate = getWaveformMatchFFT(sR, matchResult.length());
//System.out.println("Match template length: " + matchTemplate.length() + "Click : " + click.length());
// System.out.println("Match template length: " + matchTemplate.length() + "Click : " + click.length());
for (int i=0; i<matchTemplate.length(); i++) {
matchResult.set(i, click.get(i).times(matchTemplate.get(i)));
@ -376,7 +421,7 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
//set the stored sR
currentSr=sR;
//System.out.println("Waveform click: len: " + click.length());
System.out.println("Waveform click: len: " + click.length());
//System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject)+ " len " + interpWaveformMatch.length);
@ -396,9 +441,11 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
ComplexArray matchResult= new ComplexArray(fftLength);
ComplexArray matchTemplate = getWaveformMatchFFT(sR,fftLength); //remember this is the complex conjugate
//System.out.println("matchTemplate interp: len: " + interpWaveformMatch.length+ " max: " + PamArrayUtils.max(interpWaveformMatch));
//System.out.println("matchTemplate: len: " + waveformMatch.waveform.length+ " max: " + PamArrayUtils.max(waveformMatch.waveform));
// System.out.println("matchTemplate interp: len: " + interpWaveformMatch.length+ " max: " + PamArrayUtils.max(interpWaveformMatch));
// System.out.println("matchTemplate: len: " + waveformMatch.waveform.length+ " max: " + PamArrayUtils.max(waveformMatch.waveform));
// System.out.println("matchTemplate interp: len: " + interpWaveformMatch.length+ " max: " + PamArrayUtils.max(interpWaveformMatch));
System.out.println("matchTemplate len: " + matchTemplate.length() + " click.length(): " +click.length());
for (int i=0; i<Math.min(matchTemplate.length(), click.length()); i++) {
matchResult.set(i, click.get(i).times(matchTemplate.get(i)));
}
@ -409,14 +456,11 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
rejectResult.set(i, click.get(i).times(rejectTemplate.get(i)));
}
// System.out.println("Waveform Match max: " + PamArrayUtils.max(this.interpWaveformMatch));
// System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject));
System.out.println("Waveform Match max: " + PamArrayUtils.max(this.interpWaveformMatch));
System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject));
//System.out.println("Click input: " + click.length() + " click template: " + matchTemplate.length());
//must use scaling to get the same result as MATLAB
if (fft==null) fft= new FastFFT();
fft.ifft(matchResult, fftLength, true);
@ -453,17 +497,18 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// //TEST
//if set to "none" then reject template will return a NaN - TODO bit messy and inefficient.
//if the reject template is set to "none" then reject template will return a NaN
//TODO bit messy and inefficient.
double result;
double maxReject = PamArrayUtils.max(rejectReal);
if (Double.isNaN(maxReject)) {
// double maxReject = PamArrayUtils.max(rejectReal);
if (Double.isNaN(maxreject)) {
result = PamArrayUtils.max(matchReal);
}
else {
result = PamArrayUtils.max(matchReal)-maxReject;
result = PamArrayUtils.max(matchReal)-maxreject;
}
//System.out.println("Match corr " + maxmatch + " Reject Corr: " + maxreject);
System.out.println("Match corr " + maxmatch + " Reject Corr: " + maxreject);
MatchedTemplateResult matchTmpResult = new MatchedTemplateResult();
matchTmpResult.threshold=result;
@ -476,17 +521,19 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
/**
* Get the match waveform for the sample rate
* @param sR - the sample rate in samples per second
* @param waveformMatch - the template to interpolate or decimate.
* @param sR - the target sample rate in samples per second
*/
private double[] interpWaveform(MatchTemplate waveformMatch, double sR) {
//System.out.println("Interp waveform: " + " old: " + waveformMatch.sR + " new: " + sR);
// System.out.println("Interp waveform: " + " old: " + waveformMatch.sR + " new: " + sR);
if ( waveformMatch.sR>sR) {
if (waveformMatch.sR<sR) {
//up sample
double[] interpWaveformMatch=reSampleWaveform(waveformMatch.waveform, waveformMatch.sR, sR);
return interpWaveformMatch;
}
else if (waveformMatch.sR<sR){
else if (waveformMatch.sR>sR){
//decimate
// //TODO - make a better decimator?
// double[] interpWaveformMatch=reSampleWaveform(waveformMatch.waveform, waveformMatch.sR, sR);
// return interpWaveformMatch;
@ -494,11 +541,9 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
return wavInterpolator.decimate(waveformMatch.waveform, waveformMatch.sR, (float) sR);
}
else {
//nothing needed/
//nothing needed
return waveformMatch.waveform;
}
}
@ -529,7 +574,8 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// // TODO Auto-generated method stub
// return PamInterp.interpLinear(x, waveform, xi);
return PamInterp.interpWaveform(waveform, 1/binSize);
// System.out.println("Interp waveform: " + binSize);
return PamInterp.interpWaveform(waveform, 1./binSize);
}

View File

@ -5,6 +5,7 @@ import java.util.Arrays;
import PamController.PamController;
import PamDetection.RawDataUnit;
import PamUtils.PamArrayUtils;
import PamUtils.complex.ComplexArray;
import PamView.symbol.PamSymbolManager;
import PamguardMVC.PamDataBlock;
@ -288,6 +289,7 @@ public class MTProcess extends PamInstantProcess {
@SuppressWarnings("unused")
private double[] getWaveData(RawDataHolder clickDetection, int i) {
double[] waveform;
if (this.getMTParams().peakSearch) {
waveform = createRestrictedLenghtWave(clickDetection, i, lengthData[i],
this.getMTParams().restrictedBins);
@ -377,7 +379,14 @@ public class MTProcess extends PamInstantProcess {
*/
private double[] createRestrictedLenghtWave(RawDataHolder click, int chan, int[] lengthPoints,
int restrictedBins) {
return createRestrictedLenghtWave(click, chan, lengthPoints, restrictedBins, getWindow(restrictedBins));
// System.out.println("Create restricted length wave: " + lengthPoints[0] + " to " + lengthPoints[1]);
// System.out.println("Max before restrict: " + PamArrayUtils.max(click.getWaveData()[chan]));
double[] wave = createRestrictedLenghtWave(click, chan, lengthPoints, restrictedBins, getWindow(restrictedBins));
// System.out.println("Max after restrict: " + PamArrayUtils.max(click.getWaveData()[chan]));
return wave;
}
@ -412,7 +421,7 @@ public class MTProcess extends PamInstantProcess {
ArrayList<MatchedTemplateResult> results = new ArrayList<MatchedTemplateResult>();
//System.out.println("Click waveform max: " + PamArrayUtils.max(clickWaveform) + " sample rate: " + sR);
System.out.println("Click waveform max: " + PamArrayUtils.max(clickWaveform) + " sample rate: " + sR);
//normalisation and picking peak has already been performed

View File

@ -40,19 +40,31 @@ public class MTClassifierOfflineTask extends OfflineTask<PamDataUnit<?,?>> {
@Override
public boolean processDataUnit(PamDataUnit dataUnit) {
try {
// System.out.println("MT new data unit: " + dataUnit);
count++;
mtClassifierControl.getMTProcess().newClickData(dataUnit);
//since an annotation has been added might need to do this so that the data unit is actually saved.
DataUnitFileInformation fileInfo = dataUnit.getDataUnitFileInformation();
//System.out.println("file info: " + fileInfo);
// System.out.println("file info: " + fileInfo);
if (fileInfo != null) {
fileInfo.setNeedsUpdate(true);
}
dataUnit.updateDataUnit(System.currentTimeMillis());
return true;
}
catch (Exception e) {
e.printStackTrace();
}
return false;
}

View File

@ -96,10 +96,12 @@ public class PamTabPane extends TabPane {
}
/**
* TODO - the button is removed and then added again it does not seem to appear....
* Set whether a button shows to add tabs to the TabPane
* @param addTabButton - true to show a button next to the last tab which allows new tabs to be added.
*/
public void setAddTabButton(boolean addTabButton) {
if (this.addTabButton==addTabButton) return;
this.addTabButton = addTabButton;
tabPaneSkin = new PamTabPaneSkin(this);
}

View File

@ -1,5 +1,8 @@
package pamViewFX.fxNodes.flipPane;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
@ -8,12 +11,16 @@ import javafx.scene.control.Labeled;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxGlyphs.PamGlyphDude;
import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamButton;
import pamViewFX.fxNodes.PamHBox;
import pamViewFX.fxNodes.utilsFX.TextUtilsFX;
/**
* Flip pane which has is supposed to be used for advanced settings. The front
@ -146,22 +153,48 @@ public class PamFlipPane extends FlipPane {
titleHolder.getChildren().addAll(preLabel = new Label(), advLabel = new TextField("Adv. "), postLabel = new Label("Settings"));
preLabel.setId("label-title2");
postLabel.setId("label-title2");
titleHolder.setAlignment(Pos.CENTER);
postLabel.setTextAlignment(TextAlignment.LEFT);
postLabel.setAlignment(Pos.CENTER_LEFT);
advLabel.setAlignment(Pos.CENTER);
// advLabel.prefColumnCountProperty().bind(advLabel.textProperty().length().subtract(3));
// Set Max and Min Width to PREF_SIZE so that the TextField is always PREF
advLabel.setMinWidth(Region.USE_PREF_SIZE);
advLabel.setMaxWidth(Region.USE_PREF_SIZE);
//pretty complicated to make sure the text field is the same size as the text that is being typed.
advLabel.textProperty().addListener((ov, prevText, currText) -> {
// Do this in a Platform.runLater because of Textfield has no padding at first time and so on
Platform.runLater(() -> {
Text text = new Text(currText);
text.setFont(advLabel.getFont()); // Set the same font, so the size is the same
double width = text.getLayoutBounds().getWidth() // This big is the Text in the TextField
+ advLabel.getPadding().getLeft() + advLabel.getPadding().getRight() // Add the padding of the TextField
+ 2d; // Add some spacing
advLabel.setPrefWidth(width); // Set the width
advLabel.positionCaret(advLabel.getCaretPosition()); // If you remove this line, it flashes a little bit
});
});
advLabel.setId("label-title2");
advLabel.setStyle("-fx-background-color: transparent");
titleHolder.setMaxWidth(Double.MAX_VALUE); //need to make sure label is in center.
//holds the back button and the title pane.
PamHBox buttonHolder = new PamHBox();
buttonHolder.setBackground(null);
//buttonHolder.setStyle("-fx-background-color: red;");
buttonHolder.setAlignment(Pos.CENTER_LEFT);
buttonHolder.getChildren().addAll(backButton, advLabel = new TextField("Adv. Settings"));
buttonHolder.getChildren().addAll(backButton, titleHolder);
advLabel.setAlignment(Pos.CENTER);
advLabel.setMaxWidth(Double.MAX_VALUE); //need to make sure label is in center.
// PamGuiManagerFX.titleFont2style(advLabel);
advLabel.setId("label-title2");
advLabel.setStyle("-fx-background-color: transparent");
advLabel.setAlignment(Pos.CENTER);
HBox.setHgrow(advLabel, Priority.ALWAYS);
HBox.setHgrow(titleHolder, Priority.ALWAYS);
advPane.setTop(buttonHolder);

View File

@ -143,7 +143,7 @@ public class FilterPaneFX extends SettingsPane<FilterParams> {
}
else {
mainPane.setTop(createFilterPane());
mainPane.setBottom(createBodeGraph());
mainPane.setCenter(createBodeGraph());
}
}

View File

@ -8,6 +8,7 @@ import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.text.TextAlignment;
import pamViewFX.PamGuiManagerFX;
@ -47,6 +48,11 @@ public class LatLongPane extends SettingsPane<LatLong>{
private ToggleButton decimal;
/**
* Segmented button that also selection of the latitude and longitude format type.
*/
private SegmentedButton segmentedButton;
public LatLongPane(String title) {
super(null);
@ -71,7 +77,7 @@ public class LatLongPane extends SettingsPane<LatLong>{
minutesSeconds = new ToggleButton("Degrees, Minutes, Seconds");
decimal = new ToggleButton("Decimal");
SegmentedButton segmentedButton = new SegmentedButton();
segmentedButton = new SegmentedButton();
segmentedButton.getButtons().addAll(decimalMinutes, minutesSeconds, decimal);
PamHBox top = new PamHBox();
@ -109,6 +115,7 @@ public class LatLongPane extends SettingsPane<LatLong>{
mainPane.getChildren().add(cent);
decimal.setSelected(true);
}
@ -144,18 +151,20 @@ public class LatLongPane extends SettingsPane<LatLong>{
longStrip.showControls(LatLong.FORMAT_DECIMAL);
}
}
private void showLatLong() {
decimalMinutes.setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_DECIMALMINUTES);
minutesSeconds.setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_MINUTESSECONDS);
latStrip.showControls(LatLong.getFormatStyle() );
longStrip.showControls(LatLong.getFormatStyle() );
latStrip.setValue(latLong.getLatitude());
longStrip.setValue(latLong.getLongitude());
decimalMinutes .setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_DECIMALMINUTES);
minutesSeconds .setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_MINUTESSECONDS);
decimal .setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_DECIMAL);
latStrip .showControls(LatLong.getFormatStyle() );
longStrip .showControls(LatLong.getFormatStyle() );
latStrip .setValue(latLong.getLatitude());
longStrip .setValue(latLong.getLongitude());
}
@ -165,6 +174,21 @@ public class LatLongPane extends SettingsPane<LatLong>{
*/
@Override
public LatLong getParams(LatLong currentParams) {
Toggle selectedButton = this.segmentedButton.getToggleGroup().getSelectedToggle();
if (selectedButton == decimalMinutes) {
LatLong.setFormatStyle(LatLong.FORMAT_DECIMALMINUTES);
}
else if (selectedButton == minutesSeconds){
LatLong.setFormatStyle(LatLong.FORMAT_MINUTESSECONDS);
}
else if (selectedButton == decimal){
LatLong.setFormatStyle(LatLong.FORMAT_DECIMAL);
}
latLong = new LatLong(latStrip.getValue(), longStrip.getValue());
if (Double.isNaN(latLong.getLatitude()) || Double.isNaN(latLong.getLongitude())) {
return null;

View File

@ -75,17 +75,22 @@ public class LatLongStrip extends PamBorderPane {
// title.setFont(PamGuiManagerFX.titleFontSize2);
degrees = new TextField();
degrees.setEditable(true);
degrees.setPrefColumnCount(4);
minutes = new TextField();
minutes.setPrefColumnCount(3);
minutes.setEditable(true);
seconds = new TextField();
seconds.setPrefColumnCount(6);
seconds.setEditable(true);
decminutes = new TextField();
decminutes.setPrefColumnCount(6);
decminutes.setEditable(true);
decimal=new TextField();
decimal.setPrefColumnCount(9);
decimal.setEditable(true);
nsew = new ComboBox<String>();
nsew.setOnAction((action)->{
@ -152,13 +157,15 @@ public class LatLongStrip extends PamBorderPane {
private void newTypedValues(KeyEvent e) {
double v = getValue();
// now need to put that into the fields that
// are not currently shown so that they are
// ready if needed.
if (e != null) {
setValue(v, true);
}
// // now need to put that into the fields that
// // are not currently shown so that they are
// // ready if needed.
//
// if (e != null) {
// setValue(v, true);
// }
// and say the formated version
sayFormattedValue(v);
@ -166,11 +173,19 @@ public class LatLongStrip extends PamBorderPane {
public void showControls(int formatStyle) {
if (formatType==formatStyle) {
return;
}
//important this comes before setting format style.
double currentValue = getValue();
this.formatType = formatStyle;
degHBox.getChildren().clear();
System.out.println("FORMATSTYLE: " + formatStyle);
System.out.println("FORMATSTYLE: " + formatStyle + " val " + currentValue);
switch (formatType) {
case LatLong.FORMAT_DECIMALMINUTES:
degHBox.getChildren().add(dl);
@ -193,6 +208,8 @@ public class LatLongStrip extends PamBorderPane {
}
setValue(currentValue);
sayFormattedValue(getValue());
}
@ -205,6 +222,8 @@ public class LatLongStrip extends PamBorderPane {
}
public void setValue(double value, boolean hiddenOnly) {
System.out.println("Set value: " + value);
if (value >= 0) {
nsew.getSelectionModel().select(0);
}
@ -249,18 +268,20 @@ public class LatLongStrip extends PamBorderPane {
}
/**
* Get the value for the latitude and longitude
* @return the value.
* Get the value for the latitude or longitude in decimal
* @return the value - the value in decimal
*/
public double getValue() {
double deg = 0;
double min = 0;
double sec = 0;
double sin = 1.;
if (nsew.getSelectionModel().getSelectedIndex() == 1) sin = -1.;
if (LatLong.getFormatStyle() == LatLong.FORMAT_DECIMAL){
if (formatType == LatLong.FORMAT_DECIMAL){
try {
deg = Double.valueOf(decimal.getText());
return deg;
@ -278,7 +299,7 @@ public class LatLongStrip extends PamBorderPane {
}
if (LatLong.getFormatStyle() == LatLong.FORMAT_DECIMALMINUTES){
if (formatType == LatLong.FORMAT_DECIMALMINUTES){
try {
min = Double.valueOf(decminutes.getText());
}
@ -355,4 +376,6 @@ public class LatLongStrip extends PamBorderPane {
public Label getTitleLabel() {
return titleLabel;
}
}

View File

@ -0,0 +1,40 @@
package pamViewFX.fxNodes.utilsFX;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextBoundsType;
public class TextUtilsFX {
static final Text helper;
static final double DEFAULT_WRAPPING_WIDTH;
static final double DEFAULT_LINE_SPACING;
static final String DEFAULT_TEXT;
static final TextBoundsType DEFAULT_BOUNDS_TYPE;
static {
helper = new Text();
DEFAULT_WRAPPING_WIDTH = helper.getWrappingWidth();
DEFAULT_LINE_SPACING = helper.getLineSpacing();
DEFAULT_TEXT = helper.getText();
DEFAULT_BOUNDS_TYPE = helper.getBoundsType();
}
public static double computeTextWidth(Font font, String text, double help0) {
// Toolkit.getToolkit().getFontLoader().computeStringWidth(field.getText(),
// field.getFont());
helper.setText(text);
helper.setFont(font);
helper.setWrappingWidth(0.0D);
helper.setLineSpacing(0.0D);
double d = Math.min(helper.prefWidth(-1.0D), help0);
helper.setWrappingWidth((int) Math.ceil(d));
d = Math.ceil(helper.getLayoutBounds().getWidth());
helper.setWrappingWidth(DEFAULT_WRAPPING_WIDTH);
helper.setLineSpacing(DEFAULT_LINE_SPACING);
helper.setText(DEFAULT_TEXT);
return d;
}
}