Merge remote-tracking branch 'origin/main' into Tethys

This commit is contained in:
Douglas Gillespie 2023-12-18 15:27:24 +00:00
commit 3cf0a4e1e6
17 changed files with 971 additions and 281 deletions

View File

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

View File

@ -22,19 +22,19 @@ public class PamArrayUtils {
/** /**
* Calculate the mean of one dimension within a list of points. <i>e.g.</i> the points might be a list of [x y z] co-ordinates in * Calculate the mean of one dimension within a list of points. <i>e.g.</i> the points might be a list of [x y z] co-ordinates in
* which case the dim=0 would return the mean of all x points. * which case the dim=0 would return the mean of all x points.
* @param array - a list of points * @param successJump - a list of points
* @param InitialtoIgnorePercentage: ignore the first percentage of results * @param InitialtoIgnorePercentage: ignore the first percentage of results
* @param dim - the dimension of the point to calculate the average for * @param dim - the dimension of the point to calculate the average for
* @return the mean of one dimension of the list of the points. * @return the mean of one dimension of the list of the points.
*/ */
public static double mean(ArrayList<double[]> array, double InitialtoIgnorePercentage, int dim){ public static double mean(ArrayList<double[]> successJump, double InitialtoIgnorePercentage, int dim){
double meanTotal=0; double meanTotal=0;
int n=0; int n=0;
int forStart=(int) Math.round((InitialtoIgnorePercentage)*array.size()); int forStart=(int) Math.round((InitialtoIgnorePercentage)*successJump.size());
for (int i=forStart; i<array.size();i++){ for (int i=forStart; i<successJump.size();i++){
meanTotal+= array.get(i)[dim]; meanTotal+= successJump.get(i)[dim];
n++; n++;
} }
@ -43,23 +43,24 @@ public class PamArrayUtils {
return mean; return mean;
} }
/** /**
* Calculate the standard deviation of an array of doubles, ignoring an 'initialtoIgnorePercentage' percentage of jumps * Calculate the standard deviation of an array of doubles, ignoring an 'initialtoIgnorePercentage' percentage of jumps
* @param array * @param successJump
* @param initialtoIgnorePercentage- percentage of initial values to ignore. * @param initialtoIgnorePercentage- percentage of initial values to ignore.
* @return standard deviation of array. * @return standard deviation of array.
*/ */
public static double std(ArrayList<double[]> array, double initialtoIgnorePercentage, int dim){ public static double std(ArrayList<double[]> successJump, double initialtoIgnorePercentage, int dim){
double std=0.0; double std=0.0;
int n=0; int n=0;
int forStart=(int) Math.round((initialtoIgnorePercentage)*array.size()); int forStart=(int) Math.round((initialtoIgnorePercentage)*successJump.size());
double meanTotal= mean(array, initialtoIgnorePercentage, dim); double meanTotal= mean(successJump, initialtoIgnorePercentage, dim);
//calculate standard deviation //calculate standard deviation
for (int k=forStart;k<array.size(); k++){ for (int k=forStart;k<successJump.size(); k++){
std+=Math.pow((array.get(k)[dim]-meanTotal),2); std+=Math.pow((successJump.get(k)[dim]-meanTotal),2);
} }
//standard deviation //standard deviation
@ -448,12 +449,13 @@ public class PamArrayUtils {
return new int[] {min, max}; return new int[] {min, max};
} }
/** /**
* Calculate the maximum value in an array * Calculate the maximum value in an array
* @param arr - the array to find the maximum value of. * @param arr - the array to find the maximum value of.
* @return the maximum value in the array * @return the maximum value in the array
*/ */
public static double max(double[] arr) { public static double max(float[] arr) {
double max = Double.NEGATIVE_INFINITY; double max = Double.NEGATIVE_INFINITY;
for(double cur: arr) for(double cur: arr)
@ -467,7 +469,7 @@ public class PamArrayUtils {
* @param arr - the array to find the maximum value of. * @param arr - the array to find the maximum value of.
* @return the maximum value in the array * @return the maximum value in the array
*/ */
public static double max(float[] arr) { public static double max(double[] arr) {
double max = Double.NEGATIVE_INFINITY; double max = Double.NEGATIVE_INFINITY;
for(double cur: arr) for(double cur: arr)
@ -490,6 +492,50 @@ public class PamArrayUtils {
return max; 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 * Get the minimum value in an array
* @param arr - the array to find the minimu * @param arr - the array to find the minimu
@ -505,6 +551,8 @@ public class PamArrayUtils {
return min; return min;
} }
/** /**
* Get the minimum value in an array * Get the minimum value in an array
* @param arr - the array to find the minimum value of. * @param arr - the array to find the minimum value of.
@ -579,6 +627,27 @@ public class PamArrayUtils {
return clone; return clone;
} }
/**
* Split an array based on start index and end index. A new array with index 0
* as start and the last index at end is created and data from the input array
* copied to it.
*
* @param arr - the array to split
* @param start - the start index
* @param end - the end index
* @return the split array.
*/
public static double[][] split(double[][] arr, int start, int end) {
double[][] newArr = new double[end - start][];
int n = 0;
for (int i = start; i < end; i++) {
newArr[n] = arr[i];
n++;
}
return newArr;
}
/** /**
* Sum the elements in an array * Sum the elements in an array
* @param array - the array to sum. * @param array - the array to sum.
@ -855,5 +924,152 @@ public class PamArrayUtils {
return arr; return arr;
} }
/**
* Convert a 2D float array to a 2D double array.
* @param arrf - the float array
* @return a double array containing the same numbers as arrf.
*/
public static double[][] float2Double(float[][] arrf) {
double[][] newArray = new double[arrf.length][];
for (int i=0; i<arrf.length; i++) {
newArray[i] = float2Double(arrf[i]);
} }
return newArray;
}
/**
* Convert a float array to a double array.
* @param arrd - the double array
* @return a double array containing the same numbers as arrf.
*/
public static float[] double2Float(double[] arrd) {
float[] arr = new float[arrd.length];
for (int i=0; i<arr.length; i++) {
arr[i] = (float) arrd[i];
}
return arr;
}
/**
* Convert a 2D float array to a 2D double array.
* @param arrd - the double array
* @return a double array containing the same numbers as arrf.
*/
public static float[][] double2Float(double[][] arrd) {
float[][] newArray = new float[arrd.length][];
for (int i=0; i<arrd.length; i++) {
newArray[i] = double2Float(arrd[i]);
}
return newArray;
}
/**
* Check if two int arrays contain the same elements
* @param arr1 - the array to compare to.
* @param arr2 - the array to be compared.
*/
public static boolean arrEquals(int[] arr1, int[] arr2) {
if (arr1.length!=arr2.length) return false;
for (int i =0 ;i<arr1.length; i++) {
if (arr1[i]!=arr2[i]) return false;
}
return true;
}
/**
* Check if two double arrays contain the same elements
* @param arr1 - the array to compare to.
* @param arr2 - the array to be compared.
*/
public static boolean arrEquals(double[] arr1, double[] arr2) {
if (arr1.length!=arr2.length) return false;
for (int i =0 ;i<arr1.length; i++) {
if (arr1[i]!=arr2[i]) return false;
}
return true;
}
/**
* Convert primitive long array to Long object array.
* @param arr - primitive long array
* @return a Long array
*/
public static Long[] primitive2Object(long[] arr) {
if (arr==null) return null;
Long[] arrL = new Long[arr.length];
for (int i=0; i<arr.length; i++) {
arrL[i]=arr[i];
}
return arrL;
}
/**
* Convert primitive double array to Double object array.
* @param arr - primitive double array
* @return a Double array
*/
public static Double[] primitive2Object(double[] arr) {
if (arr==null) return null;
Double[] arrL = new Double[arr.length];
for (int i=0; i<arr.length; i++) {
arrL[i]=arr[i];
}
return arrL;
}
/**
* Convert primitive int array to Integer object array.
* @param arr - primitive int array
* @return a Ineteger array
*/
public static Integer[] primitive2Object(int[] arr) {
if (arr==null) return null;
Integer[] arrL = new Integer[arr.length];
for (int i=0; i<arr.length; i++) {
arrL[i]=arr[i];
}
return arrL;
}
public static long[] object2Primitve(Long[] arr) {
if (arr==null) return null;
long[] arrL = new long[arr.length];
for (int i=0; i<arr.length; i++) {
arrL[i]=arr[i].longValue();
}
return arrL;
}
}

View File

@ -6,6 +6,7 @@ import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.ArrayList; 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 //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 //print screen - the only way you can tell is the char array is greater than the number of digits - removed all non numeric
//characters. //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!) // 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 = Double.valueOf(number);
//dat = DecimalFormat.getNumberInstance().parse(new String(recordsOnLine[i].strip().toCharArray())).doubleValue(); //dat = DecimalFormat.getNumberInstance().parse(new String(recordsOnLine[i].strip().toCharArray())).doubleValue();
// }
} }
catch (Exception e){ catch (Exception e){
e.printStackTrace(); e.printStackTrace();

View File

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

View File

@ -1,13 +1,18 @@
package clickDetector.layoutFX.clickClassifiers; package clickDetector.layoutFX.clickClassifiers;
import pamViewFX.fxNodes.PamBorderPane; import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamSymbolFX;
import pamViewFX.fxNodes.flipPane.PamFlipPane; import pamViewFX.fxNodes.flipPane.PamFlipPane;
import pamViewFX.fxNodes.table.TableSettingsPane; import pamViewFX.fxNodes.table.TableSettingsPane;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.Dialog; import javafx.scene.control.Dialog;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.cell.CheckBoxTableCell; import javafx.scene.control.cell.CheckBoxTableCell;
import clickDetector.BasicClickIdParameters; import clickDetector.BasicClickIdParameters;
@ -15,6 +20,7 @@ import clickDetector.ClickControl;
import clickDetector.ClickTypeParams; import clickDetector.ClickTypeParams;
import clickDetector.ClickClassifiers.ClickIdentifier; import clickDetector.ClickClassifiers.ClickIdentifier;
import clickDetector.ClickClassifiers.basic.BasicClickIdentifier; import clickDetector.ClickClassifiers.basic.BasicClickIdentifier;
import clickDetector.ClickClassifiers.basicSweep.*;
/** /**
* Pane for the basic click classifier. * Pane for the basic click classifier.
@ -37,7 +43,7 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
/** /**
* Pane which holds table data. * Pane which holds table data.
*/ */
private TableSettingsPane<ClickTypeProperty> settingsPane; protected TableSettingsPane<ClickTypeProperty> clickTypesTable;
// /** // /**
// * Hiding pane which slides out to allow users to change click type settings. // * Hiding pane which slides out to allow users to change click type settings.
@ -103,7 +109,8 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
protected Node createSettingsPane(){ protected Node createSettingsPane(){
mainHolderPane=new PamBorderPane(); mainHolderPane=new PamBorderPane();
mainHolderPane.setCenter(settingsPane=new ClickClassifierTable(clickClassifiers)); mainHolderPane.setPadding(new Insets(5,5,5,5));
mainHolderPane.setCenter(clickTypesTable=new ClickClassifierTable(clickClassifiers));
clickTypeHolder=new PamBorderPane(); clickTypeHolder=new PamBorderPane();
//clickTypeHolder.setPrefWidth(hidingPaneWidth); //clickTypeHolder.setPrefWidth(hidingPaneWidth);
@ -165,9 +172,19 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
super(data); super(data);
//need to set up all the rows. //need to set up all the rows.
TableColumn<ClickTypeProperty,String> name = new TableColumn<ClickTypeProperty,String>("Name"); TableColumn<ClickTypeProperty,String> icon = new TableColumn<ClickTypeProperty,String>("Name");
name.setCellValueFactory(cellData -> cellData.getValue().name); icon.setCellValueFactory(cellData -> cellData.getValue().name);
name.setEditable(true); icon.setEditable(false);
icon.setCellFactory((tableColumn) -> {
TableCell<ClickTypeProperty, String> tableCell = new ClickTypeNameCell();
return tableCell;
});
// TableColumn<ClickTypeProperty,String> name = new TableColumn<ClickTypeProperty,String>("Name");
// name.setCellValueFactory(cellData -> cellData.getValue().name);
// name.setEditable(true);
TableColumn<ClickTypeProperty,Number> code = new TableColumn<ClickTypeProperty,Number>("Species Code"); TableColumn<ClickTypeProperty,Number> code = new TableColumn<ClickTypeProperty,Number>("Species Code");
code.setCellValueFactory(cellData -> cellData.getValue().code); code.setCellValueFactory(cellData -> cellData.getValue().code);
@ -190,7 +207,7 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
getTableView().setEditable(true); getTableView().setEditable(true);
getTableView().getColumns().addAll(checkCol, name, code, discard); getTableView().getColumns().addAll(checkCol, icon, code, discard);
} }
@ -261,7 +278,6 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
*/ */
public void setClassifierPane(ClickTypeProperty clickTypeProperty){ public void setClassifierPane(ClickTypeProperty clickTypeProperty){
ClickTypePaneFX clickTypePane=new ClickTypePaneFX(); ClickTypePaneFX clickTypePane=new ClickTypePaneFX();
clickTypePane.setParams(clickTypeProperty); clickTypePane.setParams(clickTypeProperty);
@ -270,10 +286,12 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
//now need to make sure on closing the pane that settings are saved. Need to //now need to make sure on closing the pane that settings are saved. Need to
//remove the old click type from the list and add new one in the same position. //remove the old click type from the list and add new one in the same position.
getFlipPaneCloseButton().setOnAction((action)->{ getFlipPaneCloseButton().setOnAction((action)->{
//System.out.println("CLOSE FLIP PANE");
showFlipPane(false); showFlipPane(false);
//this should update the click type property in the observable list thus changing the table //this should update the click type property in the observable list thus changing the table
clickTypePane.getParams(clickTypeProperty); clickTypePane.getParams(clickTypeProperty);
//need to refresh table to show symbol.
clickTypesTable.getTableView().refresh();
}); });
} }
@ -309,7 +327,7 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
* @return table which holds a list of classifiers * @return table which holds a list of classifiers
*/ */
public TableSettingsPane<ClickTypeProperty> getTablePane() { public TableSettingsPane<ClickTypeProperty> getTablePane() {
return this.settingsPane; return this.clickTypesTable;
}; };
/** /**
@ -329,4 +347,48 @@ public class BasicIdentifierPaneFX implements ClassifyPaneFX {
return flipPane; return flipPane;
} }
/**
* Shows a name alongside a graphic showing the current symbol.
* @author Jamie Macaulay.
*
*/
private class ClickTypeNameCell extends TableCell<ClickTypeProperty, String> {
/**
* Symbol is drawn on the canvas
*/
Canvas canvas;
public static final double SYMBOL_SIZE = 20;
public ClickTypeNameCell() {
super();
canvas = new Canvas(SYMBOL_SIZE, SYMBOL_SIZE);
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
this.setText(item);
this.setGraphic(null);
if (this.getTableRow()!=null && this.getTableRow().getItem()!=null) {
SweepClassifierSet clickProperty = (SweepClassifierSet) this.getTableRow().getItem().getClickType();
if (clickProperty.symbol!=null) {
canvas.getGraphicsContext2D().clearRect(0, 0, SYMBOL_SIZE, SYMBOL_SIZE);
PamSymbolFX pamSymbolFX = new PamSymbolFX(clickProperty.symbol);
pamSymbolFX.draw(canvas.getGraphicsContext2D(), new Point2D(SYMBOL_SIZE/2,SYMBOL_SIZE/2), SYMBOL_SIZE, SYMBOL_SIZE);
this.setGraphic(canvas);
}
}
}
};
} }

View File

@ -1,10 +1,16 @@
package clickDetector.layoutFX.clickClassifiers; package clickDetector.layoutFX.clickClassifiers;
import clickDetector.ClickControl; import clickDetector.ClickControl;
import clickDetector.ClickClassifiers.basicSweep.SweepClassifier; import clickDetector.ClickClassifiers.basicSweep.SweepClassifier;
import clickDetector.ClickClassifiers.basicSweep.SweepClassifierParameters; import clickDetector.ClickClassifiers.basicSweep.SweepClassifierParameters;
import clickDetector.ClickClassifiers.basicSweep.SweepClassifierSet; 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. * Slightly different pane for the sweep classifier.
@ -39,10 +45,15 @@ public class SweepClassifierPaneFX extends BasicIdentifierPaneFX {
public void setClassifierPane(ClickTypeProperty clickTypeProperty){ public void setClassifierPane(ClickTypeProperty clickTypeProperty){
SweepClassifierSetPaneFX sweepPane=new SweepClassifierSetPaneFX(sweepClickClassifier); 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 //make it so the title of the pane is the same as the name as the classifier
getFlipPane().getAdvLabel().textProperty().unbind(); getFlipPane().getAdvLabel().textProperty().unbind();
getFlipPane().getAdvLabel().textProperty().bind(sweepPane.getNameTextProperty()); getFlipPane().getAdvLabel().textProperty().bind(sweepPane.getNameTextProperty());
// removed DG 2023 12 14 since not everything was in this merge that was required Needs to be put back.
// getFlipPane().getPreAdvLabel().graphicProperty().bind(sweepPane.getNameGraphicProperty());
sweepPane.classifierItemRow = sweepClickClassifier.getSweepClassifierParams().getSetRow((SweepClassifierSet) clickTypeProperty.getClickType()); sweepPane.classifierItemRow = sweepClickClassifier.getSweepClassifierParams().getSetRow((SweepClassifierSet) clickTypeProperty.getClickType());
@ -54,6 +65,8 @@ public class SweepClassifierPaneFX extends BasicIdentifierPaneFX {
getFlipPaneCloseButton().setOnAction((action)->{ getFlipPaneCloseButton().setOnAction((action)->{
showFlipPane(false); showFlipPane(false);
sweepPane.getParams(clickTypeProperty); sweepPane.getParams(clickTypeProperty);
//need to refresh table to show symbol.
clickTypesTable.getTableView().refresh();
}); });
} }

View File

@ -2,7 +2,9 @@ package matchedTemplateClassifer
; ;
import java.io.File; import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import PamUtils.PamArrayUtils; import PamUtils.PamArrayUtils;
import PamUtils.TxtFileUtils; import PamUtils.TxtFileUtils;
@ -44,16 +46,21 @@ public class ImportTemplateCSV implements TemplateImport {
//System.out.println("i: " + i + " : " + data.get(0).get(i)); //System.out.println("i: " + i + " : " + data.get(0).get(i));
waveform[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"); //System.out.println("imported waveform");
//PamArrayUtils.printArrayRaw(waveform); //PamArrayUtils.printArrayRaw(waveform);
//now create waveform //now create waveform
// System.out.println("Create a waveform with " + waveform.length + " samples with a sample rate of " System.out.println("Import a waveform with " + waveform.length + " samples with a sample rate of "
// + sR + " Hz"); + sR + " Hz ");
MatchTemplate matchedTemplate = new MatchTemplate(filePath.getName(), waveform, sR); MatchTemplate matchedTemplate = new MatchTemplate(filePath.getName(), waveform, sR);
//TODO //TODO
return matchedTemplate; return matchedTemplate;

View File

@ -146,7 +146,12 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// System.out.println("MatchNorm: MATCH"); // System.out.println("MatchNorm: MATCH");
// MTClassifierTest.normalizeTest(interpWaveformMatch); // 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 //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. //the max value does not equal one with identical waveforms...doh.
@ -159,6 +164,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 * Get the match waveform for the sample rate
@ -182,13 +223,17 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// this.inteprWaveformReject=PamArrayUtils.divide(inteprWaveformReject, PamArrayUtils.max(inteprWaveformReject)); // this.inteprWaveformReject=PamArrayUtils.divide(inteprWaveformReject, PamArrayUtils.max(inteprWaveformReject));
this.inteprWaveformReject = normaliseWaveform(inteprWaveformReject, this.normalisation); this.inteprWaveformReject = normaliseWaveform(inteprWaveformReject, this.normalisation);
// System.out.println("MatchNorm: REJECT "); // System.out.println("MatchNorm: REJECT ");
// MTClassifierTest.normalizeTest(inteprWaveformReject); // MTClassifierTest.normalizeTest(inteprWaveformReject);
// MTClassifierTest.printWaveform(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 //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. //the max value does not equal one with identical waveforms...doh.
@ -377,7 +422,7 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
//set the stored sR //set the stored sR
currentSr=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); //System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject)+ " len " + interpWaveformMatch.length);
@ -399,7 +444,9 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// System.out.println("matchTemplate interp: len: " + interpWaveformMatch.length+ " max: " + PamArrayUtils.max(interpWaveformMatch)); // 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: 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++) { for (int i=0; i<Math.min(matchTemplate.length(), click.length()); i++) {
matchResult.set(i, click.get(i).times(matchTemplate.get(i))); matchResult.set(i, click.get(i).times(matchTemplate.get(i)));
} }
@ -410,14 +457,11 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
rejectResult.set(i, click.get(i).times(rejectTemplate.get(i))); rejectResult.set(i, click.get(i).times(rejectTemplate.get(i)));
} }
// System.out.println("Waveform Match max: " + PamArrayUtils.max(this.interpWaveformMatch)); System.out.println("Waveform Match max: " + PamArrayUtils.max(this.interpWaveformMatch));
// System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject)); System.out.println("Waveform Reject max: " + PamArrayUtils.max(this.inteprWaveformReject));
//System.out.println("Click input: " + click.length() + " click template: " + matchTemplate.length()); //System.out.println("Click input: " + click.length() + " click template: " + matchTemplate.length());
//must use scaling to get the same result as MATLAB //must use scaling to get the same result as MATLAB
if (fft==null) fft= new FastFFT(); if (fft==null) fft= new FastFFT();
fft.ifft(matchResult, fftLength, true); fft.ifft(matchResult, fftLength, true);
@ -454,17 +498,18 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// //TEST // //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 result;
double maxReject = PamArrayUtils.max(rejectReal); // double maxReject = PamArrayUtils.max(rejectReal);
if (Double.isNaN(maxReject)) { if (Double.isNaN(maxreject)) {
result = PamArrayUtils.max(matchReal); result = PamArrayUtils.max(matchReal);
} }
else { 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(); MatchedTemplateResult matchTmpResult = new MatchedTemplateResult();
matchTmpResult.threshold=result; matchTmpResult.threshold=result;
@ -477,17 +522,19 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
/** /**
* Get the match waveform for the sample rate * 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) { 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 //up sample
double[] interpWaveformMatch=reSampleWaveform(waveformMatch.waveform, waveformMatch.sR, sR); double[] interpWaveformMatch=reSampleWaveform(waveformMatch.waveform, waveformMatch.sR, sR);
return interpWaveformMatch; return interpWaveformMatch;
} }
else if (waveformMatch.sR<sR){ else if (waveformMatch.sR>sR){
//decimate
// //TODO - make a better decimator? // //TODO - make a better decimator?
// double[] interpWaveformMatch=reSampleWaveform(waveformMatch.waveform, waveformMatch.sR, sR); // double[] interpWaveformMatch=reSampleWaveform(waveformMatch.waveform, waveformMatch.sR, sR);
// return interpWaveformMatch; // return interpWaveformMatch;
@ -495,11 +542,9 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
return wavInterpolator.decimate(waveformMatch.waveform, waveformMatch.sR, (float) sR); return wavInterpolator.decimate(waveformMatch.waveform, waveformMatch.sR, (float) sR);
} }
else { else {
//nothing needed/ //nothing needed
return waveformMatch.waveform; return waveformMatch.waveform;
} }
} }
@ -530,7 +575,8 @@ public class MTClassifier implements Serializable, Cloneable, ManagedParameters
// // TODO Auto-generated method stub // // TODO Auto-generated method stub
// return PamInterp.interpLinear(x, waveform, xi); // 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 PamController.PamController;
import PamDetection.RawDataUnit; import PamDetection.RawDataUnit;
import PamUtils.PamArrayUtils;
import PamUtils.complex.ComplexArray; import PamUtils.complex.ComplexArray;
import PamView.symbol.PamSymbolManager; import PamView.symbol.PamSymbolManager;
import PamguardMVC.PamDataBlock; import PamguardMVC.PamDataBlock;
@ -288,6 +289,7 @@ public class MTProcess extends PamInstantProcess {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private double[] getWaveData(RawDataHolder clickDetection, int i) { private double[] getWaveData(RawDataHolder clickDetection, int i) {
double[] waveform; double[] waveform;
if (this.getMTParams().peakSearch) { if (this.getMTParams().peakSearch) {
waveform = createRestrictedLenghtWave(clickDetection, i, lengthData[i], waveform = createRestrictedLenghtWave(clickDetection, i, lengthData[i],
this.getMTParams().restrictedBins); this.getMTParams().restrictedBins);
@ -377,7 +379,14 @@ public class MTProcess extends PamInstantProcess {
*/ */
private double[] createRestrictedLenghtWave(RawDataHolder click, int chan, int[] lengthPoints, private double[] createRestrictedLenghtWave(RawDataHolder click, int chan, int[] lengthPoints,
int restrictedBins) { 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>(); 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 //normalisation and picking peak has already been performed

View File

@ -40,6 +40,10 @@ public class MTClassifierOfflineTask extends OfflineTask<PamDataUnit<?,?>> {
@Override @Override
public boolean processDataUnit(PamDataUnit dataUnit) { public boolean processDataUnit(PamDataUnit dataUnit) {
try {
// System.out.println("MT new data unit: " + dataUnit);
count++; count++;
mtClassifierControl.getMTProcess().newClickData(dataUnit); mtClassifierControl.getMTProcess().newClickData(dataUnit);
@ -52,7 +56,15 @@ public class MTClassifierOfflineTask extends OfflineTask<PamDataUnit<?,?>> {
} }
dataUnit.updateDataUnit(System.currentTimeMillis()); dataUnit.updateDataUnit(System.currentTimeMillis());
return true; 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 * 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. * @param addTabButton - true to show a button next to the last tab which allows new tabs to be added.
*/ */
public void setAddTabButton(boolean addTabButton) { public void setAddTabButton(boolean addTabButton) {
if (this.addTabButton==addTabButton) return;
this.addTabButton = addTabButton; this.addTabButton = addTabButton;
} }

View File

@ -1,17 +1,26 @@
package pamViewFX.fxNodes.flipPane; package pamViewFX.fxNodes.flipPane;
import javafx.geometry.Insets; import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Orientation; import javafx.geometry.Orientation;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.Labeled;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import pamViewFX.PamGuiManagerFX; import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxGlyphs.PamGlyphDude; import pamViewFX.fxGlyphs.PamGlyphDude;
import pamViewFX.fxNodes.PamBorderPane; import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamButton; import pamViewFX.fxNodes.PamButton;
import pamViewFX.fxNodes.PamHBox; import pamViewFX.fxNodes.PamHBox;
import pamViewFX.fxNodes.utilsFX.TextUtilsFX;
/** /**
* Flip pane which has is supposed to be used for advanced settings. The front * Flip pane which has is supposed to be used for advanced settings. The front
@ -32,15 +41,34 @@ public class PamFlipPane extends FlipPane {
private PamBorderPane frontPane; private PamBorderPane frontPane;
private Label advLabel;
private PamButton backButton; private PamButton backButton;
/**
* Text field in the title of the advanced pane. This can be used to change settings.
*/
private TextField advLabel;
/**
* Label which sits before the text field in the advanced settings pane title
*/
private Label preLabel;
/**
* Label after the the text field in the advanced pane label - this can be set to say "settings" for example with the text field
* then editable to change the name of a parameter.
*/
private Label postLabel;
public PamFlipPane() { public PamFlipPane() {
super(); super();
this.advPane = createAdvSettingsPane(); this.advPane = createAdvSettingsPane();
this.getFront().getChildren().add(frontPane = new PamBorderPane()); this.getFront().getChildren().add(frontPane = new PamBorderPane());
// this.getFront().setStyle("-fx-background-color: grey;");
// this.getBack().setStyle("-fx-background-color: grey;");
this.getBack().getChildren().add(advPane); this.getBack().getChildren().add(advPane);
this.setFlipTime(FLIP_TIME); this.setFlipTime(FLIP_TIME);
@ -79,6 +107,23 @@ public class PamFlipPane extends FlipPane {
} }
/**
* Set the advanced pane content.
* @param - the content to set.
*/
public void setAdvPaneContent(Node content) {
advPane.setCenter(content);
}
/**
* Set the front pane content.
* @param - the content to set.
*/
public void setFrontContent(Node content) {
frontPane.setCenter(content);
}
/** /**
* Create the advanced settings pane which can be accessed by DAQ panes if needed. * Create the advanced settings pane which can be accessed by DAQ panes if needed.
*/ */
@ -86,29 +131,70 @@ public class PamFlipPane extends FlipPane {
backButton = new PamButton(); backButton = new PamButton();
backButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-left", Color.WHITE, PamGuiManagerFX.iconSize)); backButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chevron-left", Color.WHITE, PamGuiManagerFX.iconSize));
// backButton.setStyle("-fx-background-color: -color-base-6");
//backButton.setStyle("-fx-padding: 0,0,0,0");
backButton.setOnAction((action)->{ backButton.setOnAction((action)->{
// System.out.println("FLIP BACK TO FRONT"); // System.out.println("FLIP BACK TO FRONT");
this.flipToFront(); this.flipToFront();
}); });
//make the back button blue so users can easily see the button.
backButton.setStyle("-fx-background-radius: 0 5 5 0; -fx-border-radius: 0 5 5 0; -fx-background-color: -color-accent-6");
//backButton.setPrefWidth(150); //backButton.setPrefWidth(150);
PamBorderPane advPane = new PamBorderPane(); PamBorderPane advPane = new PamBorderPane();
advPane.setPadding(new Insets(5,5,5,5)); //advPane.setPadding(new Insets(5,5,5,5));
// holds the title of the advanced pane. This consists of a label for a graphic,
// an editable text field and a label after the editable settings field
PamHBox titleHolder = new PamHBox();
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(); PamHBox buttonHolder = new PamHBox();
buttonHolder.setBackground(null); buttonHolder.setBackground(null);
//buttonHolder.setStyle("-fx-background-color: red;"); //buttonHolder.setStyle("-fx-background-color: red;");
buttonHolder.setAlignment(Pos.CENTER_LEFT); buttonHolder.setAlignment(Pos.CENTER_LEFT);
buttonHolder.getChildren().addAll(backButton, advLabel = new Label("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.setAlignment(Pos.CENTER); advLabel.setAlignment(Pos.CENTER);
HBox.setHgrow(advLabel, Priority.ALWAYS); advLabel.setMaxWidth(Double.MAX_VALUE); //need to make sure label is in center.
// PamGuiManagerFX.titleFont2style(advLabel);
advLabel.setAlignment(Pos.CENTER);
HBox.setHgrow(titleHolder, Priority.ALWAYS);
advPane.setTop(buttonHolder); advPane.setTop(buttonHolder);
@ -117,16 +203,45 @@ public class PamFlipPane extends FlipPane {
} }
public Label getAdvLabel() { public TextField getAdvLabel() {
return advLabel; return advLabel;
} }
public void setAdvLabel(Label advLabel) { // public void setAdvLabel(Label advLabel) {
this.advLabel = advLabel; // this.advLabel = advLabel;
} // }
public PamButton getBackButton() { public PamButton getBackButton() {
return backButton; return backButton;
} }
/**
* Get the label located before the editable label in the title
* @return the label before the editable label
*/
public Label getPreAdvLabel() {
return preLabel;
}
/**
* Get the label located after the editable label in the title
* @return the label after the editable label
*/
public Label getPostAdvLabel() {
return postLabel;
}
/**
* True if the flip pane is showing the front.
*/
public boolean isShowingFront() {
return super.flipFrontProperty().get();
}
public void setAdvLabelEditable(boolean b) {
this.advLabel.setEditable(b);
}
} }

View File

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

View File

@ -1,19 +1,24 @@
package pamViewFX.fxNodes.utilityPanes; package pamViewFX.fxNodes.utilityPanes;
import org.controlsfx.control.SegmentedButton;
import PamController.SettingsPane; import PamController.SettingsPane;
import PamUtils.LatLong; import PamUtils.LatLong;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.RadioButton; import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup; import javafx.scene.control.ToggleButton;
import pamViewFX.fxNodes.PamBorderPane; import javafx.scene.text.TextAlignment;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxNodes.PamHBox; import pamViewFX.fxNodes.PamHBox;
import pamViewFX.fxNodes.PamVBox; import pamViewFX.fxNodes.PamVBox;
/** /**
* Pane with controls to to set the values for a Latitude and Longitude. The pane allows users to * Pane with controls to to set the values for a Latitude and Longitude. The pane allows users to
* change the Latitude and Longitude in both Degrees, Decimal minutes and Degrees, Minutes, Seconds * change the Latitude and Longitude in both Degrees, Decimal minutes and Degrees, Minutes, Seconds
*
* @author Jamie Macaulay * @author Jamie Macaulay
* *
*/ */
@ -27,37 +32,62 @@ public class LatLongPane extends SettingsPane<LatLong>{
/** /**
* The radio button to select decimal minutes * The radio button to select decimal minutes
*/ */
private RadioButton decimalMinutes; private ToggleButton decimalMinutes;
/** /**
* Radio button to input minutes and seconds. * Radio button to input minutes and seconds.
*/ */
private RadioButton minutesSeconds; private ToggleButton minutesSeconds;
/** /**
* Lat long strip * Lat long strip
*/ */
private LatLongStrip latStrip, longStrip; private LatLongStrip latStrip, longStrip;
private PamBorderPane mainPane; private PamVBox mainPane;
private ToggleButton decimal;
/**
* Segmented button that also selection of the latitude and longitude format type.
*/
private SegmentedButton segmentedButton;
public LatLongPane(String title) { public LatLongPane(String title) {
super(null); super(null);
mainPane = new PamVBox();
mainPane.setSpacing(5);
mainPane.setAlignment(Pos.CENTER);
Label titleLabel = new Label(title);
titleLabel.maxWidth(Double.MAX_VALUE);
titleLabel.setTextAlignment(TextAlignment.LEFT);
PamGuiManagerFX.titleFont2style(titleLabel);
mainPane.getChildren().add(titleLabel);
latLong= new LatLong(); latLong= new LatLong();
mainPane = new PamBorderPane();
decimalMinutes = new ToggleButton("Degrees, Decimal minutes");
minutesSeconds = new ToggleButton("Degrees, Minutes, Seconds");
decimal = new ToggleButton("Decimal");
segmentedButton = new SegmentedButton();
segmentedButton.getButtons().addAll(decimalMinutes, minutesSeconds, decimal);
PamHBox top = new PamHBox(); PamHBox top = new PamHBox();
top.setSpacing(5); top.setSpacing(5);
top.getChildren().add(new Label("Unit type :")); top.getChildren().add(segmentedButton);
top.getChildren().add(decimalMinutes = new RadioButton("Degrees, Decimal minutes"));
top.getChildren().add(minutesSeconds = new RadioButton("Degrees, Minutes, Seconds"));
ToggleGroup bg = new ToggleGroup(); // ToggleGroup bg = new ToggleGroup();
decimalMinutes.setToggleGroup(bg); // decimalMinutes.setToggleGroup(bg);
minutesSeconds.setToggleGroup(bg); // minutesSeconds.setToggleGroup(bg);
// decimal.setToggleGroup(bg);
decimalMinutes.setOnAction((action)->{ decimalMinutes.setOnAction((action)->{
actionPerformed(action); actionPerformed(action);
@ -66,7 +96,12 @@ public class LatLongPane extends SettingsPane<LatLong>{
minutesSeconds.setOnAction((action)->{ minutesSeconds.setOnAction((action)->{
actionPerformed(action); actionPerformed(action);
}); });
mainPane.setTop(top);
decimal.setOnAction((action)->{
actionPerformed(action);
});
mainPane.getChildren().add(top);
PamVBox cent = new PamVBox(); PamVBox cent = new PamVBox();
cent.setSpacing(5); cent.setSpacing(5);
@ -75,8 +110,12 @@ public class LatLongPane extends SettingsPane<LatLong>{
cent.getChildren().add(latStrip = new LatLongStrip(true)); cent.getChildren().add(latStrip = new LatLongStrip(true));
cent.getChildren().add(longStrip = new LatLongStrip(false)); cent.getChildren().add(longStrip = new LatLongStrip(false));
mainPane.setCenter(cent); //bit of a hack that makes sure controls are aligned for the latitude and longitude.
latStrip.getTitleLabel().prefWidthProperty().bind(longStrip.getTitleLabel().widthProperty());
mainPane.getChildren().add(cent);
decimal.setSelected(true);
} }
@ -85,6 +124,7 @@ public class LatLongPane extends SettingsPane<LatLong>{
*/ */
public void actionPerformed(javafx.event.ActionEvent action) { public void actionPerformed(javafx.event.ActionEvent action) {
if (action.getSource() == decimalMinutes) { if (action.getSource() == decimalMinutes) {
LatLong.setFormatStyle(LatLong.FORMAT_DECIMALMINUTES); LatLong.setFormatStyle(LatLong.FORMAT_DECIMALMINUTES);
// if (latStrip != null) { // if (latStrip != null) {
@ -105,19 +145,26 @@ public class LatLongPane extends SettingsPane<LatLong>{
latStrip.showControls(LatLong.FORMAT_MINUTESSECONDS); latStrip.showControls(LatLong.FORMAT_MINUTESSECONDS);
longStrip.showControls(LatLong.FORMAT_MINUTESSECONDS); longStrip.showControls(LatLong.FORMAT_MINUTESSECONDS);
} }
else if (action.getSource() == decimal){
LatLong.setFormatStyle(LatLong.FORMAT_DECIMAL);
latStrip.showControls(LatLong.FORMAT_DECIMAL);
longStrip.showControls(LatLong.FORMAT_DECIMAL);
}
} }
private void showLatLong() { private void showLatLong() {
decimalMinutes .setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_DECIMALMINUTES); decimalMinutes .setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_DECIMALMINUTES);
minutesSeconds .setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_MINUTESSECONDS); minutesSeconds .setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_MINUTESSECONDS);
decimal .setSelected(LatLong.getFormatStyle() == LatLong.FORMAT_DECIMAL);
latStrip .showControls(LatLong.getFormatStyle() ); latStrip .showControls(LatLong.getFormatStyle() );
longStrip .showControls(LatLong.getFormatStyle() ); longStrip .showControls(LatLong.getFormatStyle() );
latStrip.sayValue(latLong.getLatitude()); latStrip .setValue(latLong.getLatitude());
longStrip.sayValue(latLong.getLongitude()); longStrip .setValue(latLong.getLongitude());
} }
@ -127,6 +174,21 @@ public class LatLongPane extends SettingsPane<LatLong>{
*/ */
@Override @Override
public LatLong getParams(LatLong currentParams) { 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()); latLong = new LatLong(latStrip.getValue(), longStrip.getValue());
if (Double.isNaN(latLong.getLatitude()) || Double.isNaN(latLong.getLongitude())) { if (Double.isNaN(latLong.getLatitude()) || Double.isNaN(latLong.getLongitude())) {
return null; return null;

View File

@ -19,8 +19,8 @@ import pamViewFX.fxNodes.PamHBox;
public class LatLongStrip extends PamBorderPane { public class LatLongStrip extends PamBorderPane {
Label formattedText; Label formattedText;
TextField degrees, minutes, seconds, decminutes; TextField degrees, minutes, seconds, decminutes, decimal;
Label dl, ml, sl, dml; Label dl, ml, sl, dml, dec;
ComboBox<String> nsew; ComboBox<String> nsew;
boolean isLatitude; boolean isLatitude;
// boolean decimalMinutes = true; // boolean decimalMinutes = true;
@ -35,6 +35,12 @@ public class LatLongStrip extends PamBorderPane {
*/ */
private PamHBox decHBox; private PamHBox decHBox;
/**
* The format type e.g. LatLong.FORMAT_DECIMALMINUTES.
*/
private int formatType = LatLong.FORMAT_DECIMALMINUTES;
private Label titleLabel;
/** /**
* Construct a strip of controls to include in a larger dialog. * Construct a strip of controls to include in a larger dialog.
@ -62,23 +68,29 @@ public class LatLongStrip extends PamBorderPane {
private void createDialogStrip(boolean showBorder) { private void createDialogStrip(boolean showBorder) {
String borderTitle; String title;
if (isLatitude) borderTitle = "Latitude"; if (isLatitude) title = "Latitude";
else borderTitle = "Longitude"; else title = "Longitude";
Label title= new Label(borderTitle);
PamGuiManagerFX.titleFont2style(title);
// title.setFont(PamGuiManagerFX.titleFontSize2); // title.setFont(PamGuiManagerFX.titleFontSize2);
degrees = new TextField(); degrees = new TextField();
degrees.setEditable(true);
degrees.setPrefColumnCount(4); degrees.setPrefColumnCount(4);
minutes = new TextField(); minutes = new TextField();
minutes.setPrefColumnCount(3); minutes.setPrefColumnCount(3);
minutes.setEditable(true);
seconds = new TextField(); seconds = new TextField();
seconds.setPrefColumnCount(6); seconds.setPrefColumnCount(6);
seconds.setEditable(true);
decminutes = new TextField(); decminutes = new TextField();
decminutes.setPrefColumnCount(6); decminutes.setPrefColumnCount(6);
decminutes.setEditable(true);
decimal=new TextField();
decimal.setPrefColumnCount(9);
decimal.setEditable(true);
nsew = new ComboBox<String>(); nsew = new ComboBox<String>();
nsew.setOnAction((action)->{ nsew.setOnAction((action)->{
@ -91,6 +103,8 @@ public class LatLongStrip extends PamBorderPane {
ml = new Label("min."); ml = new Label("min.");
sl = new Label("sec."); sl = new Label("sec.");
dml = new Label("dec min."); dml = new Label("dec min.");
dec = new Label("decimal deg.");
formattedText = new Label("Position"); formattedText = new Label("Position");
if (isLatitude) { if (isLatitude) {
nsew.getItems().add("N"); nsew.getItems().add("N");
@ -117,6 +131,10 @@ public class LatLongStrip extends PamBorderPane {
newTypedValues(key); newTypedValues(key);
}); });
decimal.setOnKeyPressed((key)->{
newTypedValues(key);
});
nsew.setOnKeyPressed((key)->{ nsew.setOnKeyPressed((key)->{
newTypedValues(key); newTypedValues(key);
}); });
@ -126,50 +144,72 @@ public class LatLongStrip extends PamBorderPane {
degHBox.setSpacing(5); degHBox.setSpacing(5);
degHBox.setAlignment(Pos.CENTER_LEFT); degHBox.setAlignment(Pos.CENTER_LEFT);
this.setRight(nsew); PamHBox holder= new PamHBox();
this.setCenter(degHBox); holder.setAlignment(Pos.CENTER_LEFT);
holder.setSpacing(5);
holder.getChildren().addAll(titleLabel = new Label(title), degHBox, nsew);
this.setCenter(holder);
this.setBottom(formattedText); this.setBottom(formattedText);
showControls( LatLong.FORMAT_DECIMALMINUTES); showControls(formatType);
} }
private void newTypedValues(KeyEvent e) { private void newTypedValues(KeyEvent e) {
double v = getValue(); 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) {
sayValue(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 // and say the formated version
sayFormattedValue(v); sayFormattedValue(v);
} }
public void showControls(int formatStyle) { public void showControls(int formatStyle) {
boolean decimal = (formatStyle == LatLong.FORMAT_DECIMALMINUTES);
if (formatType==formatStyle) {
return;
}
//important this comes before setting format style.
double currentValue = getValue();
this.formatType = formatStyle;
degHBox.getChildren().clear(); degHBox.getChildren().clear();
if (decimal) {
System.out.println("FORMATSTYLE: " + formatStyle + " val " + currentValue);
switch (formatType) {
case LatLong.FORMAT_DECIMALMINUTES:
degHBox.getChildren().add(dl); degHBox.getChildren().add(dl);
degHBox.getChildren().add(degrees); degHBox.getChildren().add(degrees);
degHBox.getChildren().add(dml); degHBox.getChildren().add(dml);
degHBox.getChildren().add(decminutes); degHBox.getChildren().add(decminutes);
} break;
else { case LatLong.FORMAT_MINUTESSECONDS:
degHBox.getChildren().add(dl); degHBox.getChildren().add(dl);
degHBox.getChildren().add(degrees); degHBox.getChildren().add(degrees);
degHBox.getChildren().add(ml); degHBox.getChildren().add(ml);
degHBox.getChildren().add(minutes); degHBox.getChildren().add(minutes);
degHBox.getChildren().add(sl); degHBox.getChildren().add(sl);
degHBox.getChildren().add(seconds); degHBox.getChildren().add(seconds);
break;
case LatLong.FORMAT_DECIMAL:
degHBox.getChildren().add(dec);
degHBox.getChildren().add(decimal);
break;
} }
minutes.setVisible(decimal == false);
ml.setVisible(decimal == false); setValue(currentValue);
seconds.setVisible(decimal == false);
sl.setVisible(decimal == false);
decminutes.setVisible(decimal);
dml.setVisible(decimal);
sayFormattedValue(getValue()); sayFormattedValue(getValue());
} }
@ -177,11 +217,13 @@ public class LatLongStrip extends PamBorderPane {
* Set data in the lat long dialog strip * Set data in the lat long dialog strip
* @param value Lat or Long in decimal degrees. * @param value Lat or Long in decimal degrees.
*/ */
public void sayValue(double value) { public void setValue(double value) {
sayValue(value, false); setValue(value, false);
} }
public void sayValue(double value, boolean hiddenOnly) { public void setValue(double value, boolean hiddenOnly) {
System.out.println("Set value: " + value);
if (value >= 0) { if (value >= 0) {
nsew.getSelectionModel().select(0); nsew.getSelectionModel().select(0);
} }
@ -192,31 +234,72 @@ public class LatLongStrip extends PamBorderPane {
double deg = LatLong.getSignedDegrees(value); double deg = LatLong.getSignedDegrees(value);
// System.out.println("Deg: " + LatLong.getSignedDegrees(value) + " value: " +value); // System.out.println("Deg: " + LatLong.getSignedDegrees(value) + " value: " +value);
if (degrees.isVisible() == false || !hiddenOnly) degrees.setText(String.format("%d", (int)Math.abs(deg)));
if (minutes.isVisible() == false || !hiddenOnly) minutes.setText(String.format("%d", LatLong.getIntegerMinutes(value))); // if (degrees.isVisible() == false || !hiddenOnly) degrees.setText(String.format("%d", (int)Math.abs(deg)));
if (decminutes.isVisible() == false || !hiddenOnly) decminutes.setText(String.format("%3.5f", LatLong.getDecimalMinutes(value))); // if (minutes.isVisible() == false || !hiddenOnly) minutes.setText(String.format("%d", LatLong.getIntegerMinutes(value)));
if (seconds.isVisible() == false || !hiddenOnly) seconds.setText(String.format("%3.5f", LatLong.getSeconds(value))); // if (decminutes.isVisible() == false || !hiddenOnly) decminutes.setText(String.format("%3.5f", LatLong.getDecimalMinutes(value)));
if (nsew.isVisible() == false || !hiddenOnly) nsew.getSelectionModel().select(deg >= 0 ? 0 : 1); // if (seconds.isVisible() == false || !hiddenOnly) seconds.setText(String.format("%3.5f", LatLong.getSeconds(value)));
// if (nsew.isVisible() == false || !hiddenOnly) nsew.getSelectionModel().select(deg >= 0 ? 0 : 1);
// if (decimal.isVisible() == false || !hiddenOnly) decimal.setText(String.format("%.8f", value));
switch (formatType) {
case LatLong.FORMAT_DECIMALMINUTES:
degrees.setText(String.format("%d", (int)Math.abs(deg)));
decminutes.setText(String.format("%3.5f", LatLong.getDecimalMinutes(value)));
break;
case LatLong.FORMAT_MINUTESSECONDS:
degrees.setText(String.format("%d", (int)Math.abs(deg)));
minutes.setText(String.format("%d", LatLong.getIntegerMinutes(value)));
seconds.setText(String.format("%3.5f", LatLong.getSeconds(value)));
break;
case LatLong.FORMAT_DECIMAL:
decimal.setText(String.format("%.8f", value));
break;
}
sayFormattedValue(value); sayFormattedValue(value);
} }
/** /**
* Get the value for the latitude and longitude * Get the value for the latitude or longitude in decimal
* @return the value. * @return the value - the value in decimal
*/ */
public double getValue() { public double getValue() {
double deg = 0; double deg = 0;
double min = 0; double min = 0;
double sec = 0; double sec = 0;
double sin = 1.; double sin = 1.;
if (nsew.getSelectionModel().getSelectedIndex() == 1) sin = -1.; if (nsew.getSelectionModel().getSelectedIndex() == 1) sin = -1.;
if (formatType == LatLong.FORMAT_DECIMAL){
try {
deg = Double.valueOf(decimal.getText());
return deg;
}
catch (NumberFormatException ex) {
return Double.NaN;
}
}
try { try {
deg = Integer.valueOf(degrees.getText()); deg = Integer.valueOf(degrees.getText());
} }
catch (NumberFormatException Ex) { catch (NumberFormatException Ex) {
return Double.NaN; return Double.NaN;
} }
if (LatLong.getFormatStyle() == LatLong.FORMAT_DECIMALMINUTES){
if (formatType == LatLong.FORMAT_DECIMALMINUTES){
try { try {
min = Double.valueOf(decminutes.getText()); min = Double.valueOf(decminutes.getText());
} }
@ -237,6 +320,7 @@ public class LatLongStrip extends PamBorderPane {
catch (NumberFormatException ex) { catch (NumberFormatException ex) {
return Double.NaN; return Double.NaN;
} }
} }
deg += min/60 + sec/3600; deg += min/60 + sec/3600;
deg *= sin; deg *= sin;
@ -251,6 +335,7 @@ public class LatLongStrip extends PamBorderPane {
minutes.setText(""); minutes.setText("");
seconds.setText(""); seconds.setText("");
decminutes.setText(""); decminutes.setText("");
decimal.setText("");
} }
@ -281,5 +366,16 @@ public class LatLongStrip extends PamBorderPane {
seconds.setDisable(!enabled); seconds.setDisable(!enabled);
decminutes.setDisable(!enabled); decminutes.setDisable(!enabled);
nsew.setDisable(!enabled); nsew.setDisable(!enabled);
decimal.setDisable(!enabled);
} }
/**
* Get the title label.
* @return the title label.
*/
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;
}
}