+ * This is different from the JavAFX 3D system in which
+ *
+ * x points right
+ *
+ * y points down
+ *
+ * z points into the screen
+ *
+ * Thus the source code for this class is a little bit more complex. By convention the co-ordinate system is only changed for display purposes and remains
+ * in PAMGUARD format throughout the rest of code.
+ * @author Jamie Macaulay
+ *
+ */
+public class Array3DPane extends PamBorderPane {
+
+ public static final Color DEFAULT_HYDRO_COL = Color.RED;
+
+ // private static final Color DEFAULT_SENSOR_COL = Color.LIMEGREEN;
+
+ private double scaleFactor=20;
+
+ private double axisSize=10*scaleFactor;
+
+ //keep track of mouse positions
+ double mousePosX;
+ double mousePosY;
+ double mouseOldX;
+ double mouseOldY;
+ double mouseDeltaX;
+ double mouseDeltaY;
+
+ /**
+ * This is the group which rotates
+ */
+ Group root3D;
+
+ /**
+ * Group which holds array shapes.
+ */
+ Group arrayGroup;
+
+ /**
+ * Group which holds axis and other non changing bits.
+ */
+ Group axisGroup;
+
+ /**
+ * The camera transforms
+ */
+ private Rotate rotateY;
+ private Rotate rotateX;
+ private Translate translate;
+
+ /**
+ * The size of the hydrophone for the 3D display.
+ */
+ private double hydrophoneSize = 0.5;
+
+ /**
+ * Holds a list of hydrophone spheres
+ */
+ private ArrayList hydrophonesSpheres = new ArrayList();
+
+ /**
+ * Allow rotation
+ */
+ private boolean allowRotate = true;
+
+ private Text xText;
+
+ private Text yText;
+
+ private Text zText;
+
+ private Box yAxis;
+
+ private Shape3D ySphere;
+
+
+ public Array3DPane(){
+
+ // Create and position camera
+ PerspectiveCamera camera = new PerspectiveCamera(true);
+ camera.setFarClip(20000);
+ camera.setNearClip(0.1);
+// camera.setDepthTest(DepthTest.ENABLE);
+ camera.getTransforms().addAll (
+ rotateY=new Rotate(-45, Rotate.Y_AXIS),
+ rotateX=new Rotate(-45, Rotate.X_AXIS),
+ translate=new Translate(0, 0, -2000));
+
+ //create main 3D group
+ root3D=new Group();
+ axisGroup=buildAxes(axisSize); //create axis group
+ arrayGroup=new Group();
+
+ root3D.getChildren().add(arrayGroup);
+ root3D.getChildren().add(axisGroup);
+
+
+ AmbientLight light = new AmbientLight();
+ light.setColor(Color.WHITE);
+ Group lightGroup = new Group();
+ lightGroup.getChildren().add(light);
+ root3D.getChildren().add(lightGroup);
+
+ //Use a SubScene to mix 3D and 2D stuff.
+ //note- make sure depth buffer in sub scene is enabled.
+ SubScene subScene = new SubScene(root3D, 500,400, true, SceneAntialiasing.BALANCED);
+ subScene.widthProperty().bind(this.widthProperty());
+ subScene.heightProperty().bind(this.heightProperty());
+ subScene.setDepthTest(DepthTest.ENABLE);
+
+ subScene.setOnMouseClicked((MouseEvent me) -> {
+ mousePosX = me.getSceneX();
+ mousePosY = me.getSceneY();
+ PickResult pr = me.getPickResult();
+ // System.out.println("Picked something sphere: " + pr);
+
+ //clear selected radius
+ for (HydrophoneSphere sphere : hydrophonesSpheres) {
+ sphere.setRadius(hydrophoneSize*scaleFactor);
+ }
+
+ if(pr!=null && pr.getIntersectedNode() != null && pr.getIntersectedNode() instanceof Sphere){
+
+ //make the selected sphere slightly larger
+ HydrophoneSphere s = (HydrophoneSphere) pr.getIntersectedNode();
+ s.setRadius(hydrophoneSize*scaleFactor*1.2);
+
+ hydrophoneSelected(s.getHydrophone());
+
+ // System.out.println("Picked a sphere: " + pr);
+ // distance=pr.getIntersectedDistance();
+ // s = (Sphere) pr.getIntersectedNode();
+ // isPicking=true;
+ // vecIni = unProjectDirection(mousePosX, mousePosY, scene.getWidth(),scene.getHeight());
+ }
+ });
+
+ //note the fill is actually quite important because if you don't have it mouse rotations etc
+ //onyl work if you select a 3D shape
+ subScene.setFill(Color.TRANSPARENT);
+ subScene.setCamera(camera);
+
+ //handle mouse events for sub scene
+ handleMouse(subScene);
+
+ resetView();
+
+ //create new group to add sub scene to
+ Group group = new Group();
+ group.getChildren().add(subScene);
+
+ //add group to window.
+ this.setCenter(group);
+ this.setDepthTest(DepthTest.ENABLE);
+
+ }
+
+ /**
+ * Called whenever a hydrophone is selected.
+ * @param hydrophone - the selected hydrophone.
+ */
+ public void hydrophoneSelected(Hydrophone hydrophone) {
+ // TODO Auto-generated method stub
+ }
+
+ /**
+ * Create a 3D axis with default colours set.
+ * @param- size of the axis
+ */
+ public Group buildAxes(double axisSize) {
+ return buildAxes( axisSize,Color.RED, Color.RED,
+ Color.GREEN, Color.GREEN,
+ Color.BLUE, Color.BLUE,
+ Color.WHITE);
+ }
+
+
+ /**
+ * Create a 3D axis.
+ * @param- size of the axis
+ */
+ public Group buildAxes(double axisSize, Color xAxisDiffuse, Color xAxisSpectacular,
+ Color yAxisDiffuse, Color yAxisSpectacular,
+ Color zAxisDiffuse, Color zAxisSpectacular,
+ Color textColour) {
+
+ Group axisGroup=new Group();
+
+ double length = 2d*axisSize;
+ double width = axisSize/100d;
+ double radius = 2d*axisSize/100d;
+
+
+ final PhongMaterial redMaterial = new PhongMaterial();
+ redMaterial.setDiffuseColor(xAxisDiffuse);
+ redMaterial.setSpecularColor(xAxisSpectacular);
+ final PhongMaterial greenMaterial = new PhongMaterial();
+ greenMaterial.setDiffuseColor(yAxisDiffuse);
+ greenMaterial.setSpecularColor( yAxisSpectacular);
+ final PhongMaterial blueMaterial = new PhongMaterial();
+ blueMaterial.setDiffuseColor(zAxisDiffuse);
+ blueMaterial.setSpecularColor(zAxisSpectacular);
+
+ xText=new Text("x");
+ xText.setStyle("-fx-font: 20px Tahoma; -fx-fill: white;");
+ xText.setFill(textColour);
+ xText.setStroke(textColour);
+
+ yText=new Text("z");
+ yText.setStyle("-fx-font: 20px Tahoma; -fx-fill: white;");
+ yText.setFill(textColour);
+ yText.setStroke(textColour);
+
+ zText=new Text("y");
+ zText.setStyle("-fx-font: 20px Tahoma; -fx-fill: white;");
+ zText.setFill(textColour);
+ zText.setStroke(textColour);
+
+ xText.setTranslateX(axisSize+5);
+ xText.setTranslateZ(1); //dunno why but shifting a little in z is required to see colour
+
+ yText.setTranslateY(-(axisSize+5));
+ yText.setTranslateZ(1); //dunno why but shifting a little in z is required to see colour
+
+ zText.setTranslateZ(axisSize+5);
+
+ Sphere xSphere = new Sphere(radius);
+ ySphere = new Sphere(radius);
+ Sphere zSphere = new Sphere(radius);
+ xSphere.setMaterial(redMaterial);
+ ySphere.setMaterial(greenMaterial);
+ zSphere.setMaterial(blueMaterial);
+
+ xSphere.setTranslateX(axisSize);
+ ySphere.setTranslateY(-axisSize);
+ zSphere.setTranslateZ(axisSize);
+
+ Box xAxis = new Box(length, width, width);
+ yAxis = new Box(width, length, width);
+ Box zAxis = new Box(width, width, length);
+ xAxis.setMaterial(redMaterial);
+ yAxis.setMaterial(greenMaterial);
+ zAxis.setMaterial(blueMaterial);
+
+ axisGroup.getChildren().addAll(xAxis, yAxis, zAxis);
+ axisGroup.getChildren().addAll(xText, yText, zText);
+ axisGroup.getChildren().addAll(xSphere, ySphere, zSphere);
+
+
+ return axisGroup;
+ }
+
+
+ private void handleMouse(SubScene scene) {
+
+ scene.setOnMousePressed(new EventHandler() {
+
+ @Override public void handle(MouseEvent me) {
+ mousePosX = me.getSceneX();
+ mousePosY = me.getSceneY();
+ mouseOldX = me.getSceneX();
+ mouseOldY = me.getSceneY();
+ }
+ });
+
+ scene.setOnScroll(new EventHandler() {
+ @Override public void handle(ScrollEvent event) {
+ // System.out.println("Scroll Event: "+event.getDeltaX() + " "+event.getDeltaY());
+ translate.setZ(translate.getZ()+ event.getDeltaY() *0.001*translate.getZ()); // +
+ }
+ });
+
+
+ scene.setOnMouseDragged(new EventHandler() {
+
+
+ @Override
+ public void handle(MouseEvent me) {
+ mouseOldX = mousePosX;
+ mouseOldY = mousePosY;
+ mousePosX = me.getSceneX();
+ mousePosY = me.getSceneY();
+ mouseDeltaX = (mousePosX - mouseOldX);
+ mouseDeltaY = (mousePosY - mouseOldY);
+
+ double modifier = 1.0;
+ double modifierFactor = 0.1;
+
+ if (me.isControlDown()) {
+ modifier = 0.1;
+ }
+ if (me.isShiftDown()) {
+ modifier = 10.0;
+ }
+ if (me.isPrimaryButtonDown() && allowRotate) {
+ rotateY.setAngle(rotateY.getAngle() + mouseDeltaX * modifierFactor * modifier * 2.0); // +
+ rotateX.setAngle(rotateX.getAngle() - mouseDeltaY * modifierFactor * modifier * 2.0); // -
+
+// System.out.println("Rotation: x: " + rotateX.getAngle() + " y: " + rotateY.getAngle());
+ }
+ if (me.isSecondaryButtonDown()) {
+ translate.setX(translate.getX() -mouseDeltaX * modifierFactor * modifier * 5);
+ translate.setY(translate.getY() - mouseDeltaY * modifierFactor * modifier * 5); // +
+ }
+
+
+ }
+ });
+ }
+
+ /**
+ * Draw the hydrophone array.
+ * @param array - the hydrophone array to draw.
+ */
+ public void drawArray(PamArray array) {
+
+ // System.out.println("DRAW ARRAY: " + array);
+
+ //clear the array
+ arrayGroup.getChildren().removeAll(arrayGroup.getChildren());
+
+ ArrayList hydrophones = array.getHydrophoneArray();
+
+ //draw hydrophones
+ HydrophoneSphere sphere;
+ Streamer streamer;
+ hydrophonesSpheres.clear();
+ for (int i=0; i streamerPoints=new ArrayList();
+ //now plot a line from the streamer to the hydrophone
+ Point3D newPoint;
+
+ newPoint=new Point3D(x*scaleFactor, z*scaleFactor, y*scaleFactor);
+ streamerPoints.add(newPoint);
+
+ newPoint =new Point3D(streamer.getCoordinate(0)*scaleFactor, -streamer.getCoordinate(2)*scaleFactor, streamer.getCoordinate(1)*scaleFactor);
+ streamerPoints.add(newPoint);
+
+ //System.out.println("Streamer points: " + streamerPoints.size());
+
+ PolyLine3D polyLine3D=new PolyLine3D(streamerPoints, 4f, Color.DODGERBLUE);
+ arrayGroup.getChildren().add(polyLine3D);
+ }
+ }
+
+
+ private class HydrophoneSphere extends Sphere {
+
+ Hydrophone hydrophone;
+
+ public Hydrophone getHydrophone() {
+ return hydrophone;
+ }
+
+
+
+ public void setHydrophone(Hydrophone hydrophone) {
+ this.hydrophone = hydrophone;
+ }
+
+ public HydrophoneSphere() {
+ super();
+ }
+
+ public HydrophoneSphere(double radius) {
+ super(radius);
+ }
+
+ }
+
+ /**
+ * Sets the pane to show hydrophones in 2D or 3D.
+ * @param set3D - true to set to 3D
+ */
+ public void set3D(boolean set3D) {
+
+ double textRotation =0;
+
+ if (set3D) {
+ allowRotate=true;
+ xText.setRotate(0);
+ rotateY.setAngle(-45);
+ rotateX.setAngle(-45);
+ }
+ else {
+ allowRotate=false;
+ rotateY.setAngle(0);
+ rotateX.setAngle(270);
+ textRotation=-90;
+ }
+
+ //confusing because the yaxis is the z axis in JavaFX...
+ yText.setVisible(set3D);
+ yAxis.setVisible(set3D);
+ ySphere.setVisible(set3D);
+
+
+ xText.setRotate(textRotation);
+ xText.setRotationAxis(new javafx.geometry.Point3D(1,0,0));
+
+ yText.setRotationAxis(new javafx.geometry.Point3D(1,0,0));
+ yText.setRotate(textRotation);
+
+ zText.setRotationAxis(new javafx.geometry.Point3D(1,0,0));
+ zText.setRotate(textRotation);
+
+
+ }
+
+ /**
+ * Reset to the defulat view.
+ */
+ public void resetView() {
+
+ translate.setX(0);
+ translate.setY(0);
+ translate.setZ( -2000);
+
+ if (allowRotate) {
+ rotateY.setAngle(-45);
+ rotateX.setAngle(-45);
+ }
+ }
+
+ // /**
+ // * Draw the entire array
+ // * @param pos - hydrophone and streamer positions in the same co-ordinate frame as the reference frame.
+ // */
+ // public void drawArrays(ArrayList> pos){
+ //
+ // arrayGroup.getChildren().removeAll(arrayGroup.getChildren());
+ //
+ // if (pos==null){
+ // System.err.println("Array3DPane: Hydrophone positions are null");
+ // return;
+ // }
+ //
+ // for (int i=0; i< pos.size(); i++){
+ // for (int j=0; j streamerPoints;
+ //
+ // for (int i=0; i();
+ // for (int j=0; j
+ *
+ */
public class ArraySettingsPane extends SettingsPane{
+ /**
+ * Minimum size of the 3D pane.
+ */
+ private static final double MIN_3D_WIDTH = 450;
+
+ /**
+ * Minimum height of the 3D pane.
+ */
+ private static final double MIN_3D_HEIGHT = 600;
+
+ /**
+ * Pane for adding or removing streamers.
+ */
+ private StreamersPane streamerPane;
+
+ private PamBorderPane mainPane;
+
+ /**
+ * Pane for adding or removing hydrophones.
+ */
+ private HydrophonesPane hydrophonePane;
+
+ // private Pane holder;
+
+ private Label hydrophoneLabel;
+
+ /**
+ * Pane which shows a 3D representation of the hydrophone array.
+ */
+ private Array3DPane array3DPane;
+
+ private PropogationPane propogationPane;
+
+ private Label recivierDiagramLabel;
+
+ /**
+ * Pane with controls to change speed of sound.
+ */
+ private SettingsPane environmentalPane;
+
+ private FileChooser fileChooser;
+
+ //a copy of the current array
+ private PamArray currentArray;
+
public ArraySettingsPane() {
super(null);
- // TODO Auto-generated constructor stub
+
+ mainPane=new PamBorderPane();
+
+ mainPane.setCenter(createArrayPane());
+ // mainPane.setStyle("-fx-background-color: red;");
+ mainPane.setMaxWidth(Double.MAX_VALUE);
+ mainPane.setMinWidth(1100);
+ mainPane.setStyle("-fx-padding: 0,0,0,0");
+
+
+ recivierDiagramLabel = new Label("Hydrophone Diagram");
+ PamGuiManagerFX.titleFont1style(recivierDiagramLabel);
+ recivierDiagramLabel.setPadding(new Insets(5,5,5,5));
+
+ Label environmentLabel = new Label("Environment");
+ PamGuiManagerFX.titleFont1style(environmentLabel);
+ environmentLabel.setPadding(new Insets(0,0,5,0)); //little more space under this label
+
+ environmentalPane = createEnvironmentPane();
+
+ PamVBox rightPane = new PamVBox();
+ rightPane.setSpacing(5);
+
+ Pane hydrophone3DPane = create3DPane();
+ rightPane.getChildren().addAll(recivierDiagramLabel, hydrophone3DPane, environmentLabel, new PamBorderPane(environmentalPane.getContentNode()));
+ VBox.setVgrow(hydrophone3DPane, Priority.ALWAYS);
+
+ mainPane.setRight(rightPane);
+
+ // streamerPane.getStreamerTable().getItems().addListener((ListChangeListener super StreamerProperty>) c->{
+ // //the streamer table has changed and so the streamer needs changed
+ // System.out.println("Streamer Changed!!!");
+ // });
+
+ streamerPane.addStreamerListener((x,y)->{
+ PamArray array = getParams(new PamArray("temp_array: ", null)) ;
+ System.out.println("Streamer changed!");
+ array3DPane.drawArray(array);
+ });
+
+ hydrophonePane.addStreamerListener((x,y)->{
+ PamArray array = getParams(new PamArray("temp_array: ", null)) ;
+ System.out.println("Hydrophone changed!" + array.getHydrophoneCount());
+ array3DPane.drawArray(array);
+ });
+
+ // mainPane.setMinWidth(800);
+
+ // mainPane.setCenter(createArrayPane());
+ //
+ // mainPane.getAdvPane().setCenter(new Label("Advanced Settings"));
+
+
+ // //mainPane.getFront().setStyle("-fx-background-color: grey;");
+ // mainPane.setStyle("-fx-background-color: red;");
+ //
+ // FlipPane aflipPane = new FlipPane();
+ // aflipPane.setStyle("-fx-background-color: red;");
+ //
+ // PamHBox stackPane = new PamHBox();
+ // stackPane.setStyle("-fx-background-color: red;");
+ //
+ // Button button = new Button();
+ // button.setOnAction((action)->{
+ // System.out.println(" 1 " + stackPane.getPadding());
+ // System.out.println(" 2 " +PamBorderPane.getMargin(stackPane));
+ // System.out.println(" 3 " + holder.getPadding());
+ // });
+ //
+ // stackPane.getChildren().add(button);
+ //
+ //
+ // mainPane.setPadding(new Insets(0,0,0,0));
+
+
+ // holder = new StackPane();
+ // holder.getChildren().add(mainPane);
+ // holder.setStyle("-fx-padding: 0,0,0,0");
+
}
+ private Pane create3DPane() {
+
+ StackPane stackPane = new StackPane();
+ this.array3DPane = new HydrophoneArray3DPane();
+
+ //important because the 3D pane has not default size
+ stackPane.setMinWidth(MIN_3D_WIDTH);
+ stackPane.setMinHeight(MIN_3D_HEIGHT);
+
+ // stackPane.prefHeightProperty().bind(mainPane.heightProperty().subtract(100));
+
+ stackPane.getChildren().add(array3DPane);
+
+
+ //add buttons
+ ToggleButton b1 = new ToggleButton("2D");
+ ToggleButton b2 = new ToggleButton("3D");
+
+ b1.setOnAction((action)->{
+ array3DPane.set3D(false);
+ });
+
+ b2.setOnAction((action)->{
+ array3DPane.set3D(true);
+ });
+
+
+ SegmentedButton segmentedButton = new SegmentedButton();
+ segmentedButton.getButtons().addAll(b1, b2);
+ segmentedButton.setPadding(new Insets(5,5,5,5));
+ segmentedButton.setMinWidth(100);
+
+ StackPane.setAlignment(segmentedButton, Pos.TOP_RIGHT);
+ stackPane.getChildren().add(segmentedButton);
+
+
+ final ContextMenu contextMenu = new ContextMenu();
+ final MenuItem item1 = new MenuItem("Reset");
+ item1.setOnAction((action)->{
+ array3DPane.resetView();
+ });
+ contextMenu.getItems().add(item1);
+ segmentedButton.setContextMenu(contextMenu);
+
+// stackPane.setOnContextMenuRequested(e ->
+// contextMenu.show(stackPane, e.getScreenX(), e.getScreenY()));
+
+
+ b2.setSelected(true);
+
+ return stackPane;
+ }
+
+ /**
+ * Create the environment pane.
+ * @return the environment pane.
+ */
+ private SettingsPane createEnvironmentPane() {
+ this.propogationPane = new PropogationPane();
+ return propogationPane;
+ }
+
+ /**
+ * Create the main pane.
+ * @return the main array pane.
+ */
+ private Pane createArrayPane() {
+
+ Label arrayLabel = new Label("Array");
+ arrayLabel.setPadding(new Insets(5,5,5,5));
+ PamGuiManagerFX.titleFont1style(arrayLabel);
+
+ //holds the array label and also some button for import and export.
+ PamHBox arrayImportExportBox = new PamHBox();
+ arrayImportExportBox.setSpacing(5);
+ arrayImportExportBox.setAlignment(Pos.CENTER_LEFT);
+ arrayImportExportBox.setPadding(new Insets(5,0,0,0));
+
+ fileChooser = new FileChooser();
+ fileChooser.setTitle("Open Resource File");
+ fileChooser.getExtensionFilters().addAll(
+ new ExtensionFilter("PAMGuard Array Files", "*.paf"));
+
+ PamButton importButton = new PamButton("Import...");
+ importButton.setOnAction((action)->{
+ importArray();
+ });
+ importButton.setGraphic(PamGlyphDude.createPamIcon("mdi2f-file-import", PamGuiManagerFX.iconSize));
+ importButton.setTooltip(new Tooltip("Import array settings from a .pgaf file"));
+
+ PamButton exportButton = new PamButton("Export...");
+ exportButton.setOnAction((action)->{
+ exportArray();
+ });
+ exportButton.setGraphic(PamGlyphDude.createPamIcon("mdi2f-file-export", PamGuiManagerFX.iconSize));
+ exportButton.setTooltip(new Tooltip("Export array settings to a .pgaf file"));
+
+ //balnk region to make it look nicer
+ Region blank = new Region();
+ blank.setPrefWidth(70);
+
+ arrayImportExportBox.getChildren().addAll(importButton, exportButton, blank);
+
+ PamBorderPane titleHolder = new PamBorderPane();
+ titleHolder.setLeft(arrayLabel);
+ titleHolder.setRight(arrayImportExportBox);
+
+ //the streamer pane for changing streamer settings.
+ streamerPane = new StreamersPane();
+ streamerPane.setMaxWidth(Double.MAX_VALUE);
+
+ hydrophoneLabel = new Label("Hydrophones");
+ PamGuiManagerFX.titleFont1style(hydrophoneLabel);
+ hydrophoneLabel.setPadding(new Insets(5,5,5,5));
+
+ hydrophonePane = new HydrophonesPane();
+ hydrophonePane.setMaxWidth(Double.MAX_VALUE);
+
+ // PamButton advancedButton = new PamButton();
+ // advancedButton.setOnAction((action)->{
+ // mainPane.flipToBack();
+ // });
+ // advancedButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-cog"));
+
+ // PamHBox advancedPane = new PamHBox();
+ // advancedPane.setSpacing(5);
+ // advancedPane.setAlignment(Pos.CENTER_RIGHT);
+ // advancedPane.getChildren().addAll(new Label("Advanced"), advancedButton);
+
+ PamVBox vBox = new PamVBox();
+ vBox.setSpacing(5);
+ vBox.getChildren().addAll(titleHolder, streamerPane, hydrophoneLabel,
+ hydrophonePane);
+
+ return vBox;
+ }
+
+ /**
+ * Select a file to export array settings to.
+ */
+ private void exportArray() {
+ File file = fileChooser.showSaveDialog(getFXWindow());
+ if (file==null) return;
+ PamArray pamArray = getParams(new PamArray("saved_array: ", null));
+ boolean isSaved = ArrayManager.saveArrayToFile(pamArray);
+ if (isSaved==false) {
+ PamDialogFX.showError("Unable to save the array file to \n" + file.toString());
+ }
+ }
+
+ /**
+ * Select a file to import array settings
+ */
+ private void importArray() {
+ File file = fileChooser.showOpenDialog(getFXWindow());
+ if (file==null) return;
+ PamArray pamArray = ArrayManager.loadArrayFromFile(file.getPath());
+ this.setParams(pamArray);
+ }
+
+ /**
+ * Set correct text for the receiver in the current medium (e.g. air or water);
+ */
+ private void setReceieverLabels() {
+ hydrophonePane.setRecieverLabels();
+ streamerPane.setRecieverLabels();
+
+ hydrophoneLabel.setText(PamController.getInstance().getGlobalMediumManager().getRecieverString(true) + "s");
+ recivierDiagramLabel.setText(PamController.getInstance().getGlobalMediumManager().getRecieverString(true) + " diagram");
+ // if (singleInstance!=null) {
+ // singleInstance.setTitle("Pamguard "+ PamController.getInstance().getGlobalMediumManager().getRecieverString(false) +" array");
+ // }
+ }
+
+
@Override
- public PamArray getParams(PamArray currParams) {
- // TODO Auto-generated method stub
- return null;
+ public PamArray getParams(PamArray currParams) {
+
+ if (currParams==null) currParams = this.currentArray;
+
+ currParams = streamerPane.getParams(currParams);
+ currParams = hydrophonePane.getParams(currParams);
+ currParams.setHydrophoneInterpolation(hydrophonePane.getHydrophoneInterp());
+ currParams = environmentalPane.getParams(currParams);
+ // System.out.println("Array settings pane: No. streamers: " + currParams.getStreamerCount());
+ return currParams;
}
@Override
public void setParams(PamArray input) {
- // TODO Auto-generated method stub
-
+ this.currentArray = input.clone();
+ // System.out.println("Hydrophone array is: "+ input);
+ setReceieverLabels();
+ hydrophonePane.setParams(input);
+ streamerPane.setParams(input);
+ environmentalPane.setParams(input);
+
+ //draw the array
+ array3DPane.drawArray(input);
}
@Override
public String getName() {
- // TODO Auto-generated method stub
return "Array Parameters";
}
@Override
public Node getContentNode() {
- // TODO Auto-generated method stub
- return new Label("TODO: The Array Manager needs an FX GUI");
+
+ return mainPane;
}
@Override
public void paneInitialized() {
// TODO Auto-generated method stub
-
+
+ }
+
+ private class HydrophoneArray3DPane extends Array3DPane {
+
+ @Override
+ public void hydrophoneSelected(Hydrophone hydrophone) {
+ hydrophonePane.selectHydrophone(hydrophone);
+ }
+
}
}
diff --git a/src/Array/layoutFX/DefaultHydrophone.java b/src/Array/layoutFX/DefaultHydrophone.java
new file mode 100644
index 00000000..5d571775
--- /dev/null
+++ b/src/Array/layoutFX/DefaultHydrophone.java
@@ -0,0 +1,58 @@
+package Array.layoutFX;
+
+/**
+ * Default hydrophone parameters.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public enum DefaultHydrophone {
+
+ SoundTrap600HF("SoundTrap 600 HF", -176., 0), SoundTrap300HF("SoundTrap 300 HF", -176., 0), HydroMoth_1_0_0("HydroMoth 1.0.0", -180., 0);
+
+ /**
+ * The name of the hydrophones.
+ */
+ private String name;
+
+
+ /**
+ * The sensitivity of the hydrophone in dB re 1V/uPa.
+ */
+ private double sens;
+
+ /**
+ * The gain in dB.
+ */
+ private double gain;
+
+ /**
+ * The name of the hydrophone.
+ * @param name - the name of the hydrophone.
+ * @param sens - the sensitivity of the hydrophone.
+ * @param gain - the gain of the hydrophone.
+ */
+ DefaultHydrophone(String name, double sens, double gain) {
+ this.name = name;
+ this.sens = sens;
+ this.gain = gain;
+
+ }
+
+ /**
+ * The sensitivity of the hydrophone in dB re 1V/uPa.
+ */
+ public double getSens() {
+ return sens;
+ }
+
+
+ /**
+ * The gain in dB.
+ */
+ public double getGain() {
+ return gain;
+ }
+
+
+}
diff --git a/src/Array/layoutFX/HydrophoneProperty.java b/src/Array/layoutFX/HydrophoneProperty.java
new file mode 100644
index 00000000..72679010
--- /dev/null
+++ b/src/Array/layoutFX/HydrophoneProperty.java
@@ -0,0 +1,116 @@
+package Array.layoutFX;
+
+import Array.Hydrophone;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+
+
+/**
+ * Property class for a hydrophone object.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class HydrophoneProperty {
+
+ SimpleDoubleProperty x = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty y = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty z = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty xErr = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty yErr = new SimpleDoubleProperty();
+
+ SimpleDoubleProperty zErr = new SimpleDoubleProperty();
+
+ SimpleIntegerProperty id = new SimpleIntegerProperty();
+
+ private Hydrophone hydrophone;
+
+ public HydrophoneProperty(Hydrophone hydrophone) {
+ setHydrophone(hydrophone);
+ }
+
+ public void setHydrophone(Hydrophone hydrophone) {
+ this.hydrophone = hydrophone;
+
+
+ x .set(hydrophone.getX());
+ y .set(hydrophone.getY());
+ z .set(hydrophone.getZ());
+
+ xErr .set(hydrophone.getdX());
+ yErr .set(hydrophone.getdY());
+ zErr .set(hydrophone.getdZ());
+
+ id.set(hydrophone.getID());
+ }
+
+ /**
+ * The x-coordinate property.
+ * @return the x coordintae property.
+ */
+ public SimpleDoubleProperty getX() {
+ return x;
+ }
+
+ /**
+ * The y-coordinate property.
+ * @return the y coordintae property.
+ */
+ public SimpleDoubleProperty getY() {
+ return y;
+ }
+
+ /**
+ * The z-coordinate property.
+ * @return the z coordintae property.
+ */
+ public SimpleDoubleProperty getZ() {
+ return z;
+ }
+
+ public SimpleIntegerProperty getID() {
+ return id;
+ }
+
+ public Hydrophone getHydrophone() {
+ //incase table data changes.
+ this.hydrophone.setID(this.id.get());
+ this.hydrophone.setX(x.get());
+ this.hydrophone.setY(y.get());
+ this.hydrophone.setZ(z.get());
+ this.hydrophone.setdX(xErr.get());
+ this.hydrophone.setdY(yErr.get());
+ this.hydrophone.setdZ(xErr.get());
+
+ return hydrophone;
+ }
+
+ /**
+ * The x-coordinate property.
+ * @return the x coordintae property.
+ */
+ public SimpleDoubleProperty getXErr() {
+ return xErr;
+ }
+
+ /**
+ * The y-coordinate property.
+ * @return the y coordintae property.
+ */
+ public SimpleDoubleProperty getYErr() {
+ return yErr;
+ }
+
+ /**
+ * The z-coordinate property.
+ * @return the z coordintae property.
+ */
+ public SimpleDoubleProperty getZErr() {
+ return zErr;
+ }
+
+}
diff --git a/src/Array/layoutFX/HydrophoneSettingsPane.java b/src/Array/layoutFX/HydrophoneSettingsPane.java
new file mode 100644
index 00000000..0e8f4507
--- /dev/null
+++ b/src/Array/layoutFX/HydrophoneSettingsPane.java
@@ -0,0 +1,589 @@
+package Array.layoutFX;
+
+import Array.Hydrophone;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import Array.PamArray;
+import Array.Streamer;
+import PamController.PamController;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.scene.control.ChoiceBox;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Labeled;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.ColumnConstraints;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Region;
+import net.synedra.validatorfx.Validator;
+import pamViewFX.PamGuiManagerFX;
+import pamViewFX.fxNodes.PamVBox;
+import pamViewFX.fxSettingsPanes.DynamicSettingsPane;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.PamGridPane;
+import pamViewFX.fxNodes.PamHBox;
+import pamViewFX.fxNodes.PamSpinner;
+import pamViewFX.validator.PamValidator;
+
+/**
+ * The settings pane for a single hydrophones.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class HydrophoneSettingsPane extends DynamicSettingsPane {
+
+ private static final double COLUMN_0_WIDTH = 120;
+
+
+ private final static double MAX_TEXTFIELD_WIDTH = 80;
+
+ /**
+ *
+ * Check inputs in real time
+ */
+ PamValidator validator = new PamValidator();
+
+
+ @Override
+ public String getName() {
+ return "Hydrophone Settings";
+ }
+
+ @Override
+ public Node getContentNode() {
+ return mainPane;
+ }
+
+ @Override
+ public void paneInitialized() {
+ // TODO Auto-generated method stub
+
+ }
+
+ private TextField iD;
+
+ private TextField yPos;
+ private TextField xPos;
+ private TextField zPos;
+
+ private TextField yPosErr;
+ private TextField xPosErr;
+ private TextField zPosErr;
+
+ private PamSpinner hSens;
+ private PamSpinner preampGain;
+
+ private ComboBox streamers;
+ private ChoiceBox defaultArrays;
+ private TextField nameField;
+
+ private PamArray currentArray;
+
+ ///Labels which might change name if in air or water (i.e. hydrophone or microphone).
+
+ private Labeled depthLabel;
+
+ private Labeled depthLabel2;
+
+ private Label recieverIDLabel;
+
+ private Label recieverTypeLabel;
+
+ private Label recieverSensLabel;
+
+ private Label dBSensLabel;
+
+ private boolean ressetHydrophoneType = false;
+
+ /**
+ * The main holder pane.
+ */
+ private PamBorderPane mainPane;
+
+ private InterpChoicePane interpPane;
+
+ private ComboBox defaultHydro;
+
+ //create the dialog
+ public HydrophoneSettingsPane() {
+ super(null);
+
+ PamVBox holderPane = new PamVBox();
+ holderPane.setSpacing(5);
+
+
+ recieverIDLabel = new Label("General");
+ PamGuiManagerFX.titleFont2style(recieverIDLabel);
+
+ Label coOrdLabel = new Label("Coordinates");
+ PamGuiManagerFX.titleFont2style(coOrdLabel);
+
+ Label interpLabel = new Label("Interpolation");
+ PamGuiManagerFX.titleFont2style(interpLabel);
+
+ interpPane = new InterpChoicePane();
+
+ PamHBox interpHolder = new PamHBox();
+ interpHolder.setSpacing(5);
+ interpHolder.setAlignment(Pos.CENTER_LEFT);
+ interpHolder.getChildren().addAll(new Label("Method"), interpPane);
+
+ holderPane.getChildren().addAll(recieverIDLabel, createGeneralPane(), coOrdLabel, createPositionPane(), interpLabel, interpHolder);
+
+ mainPane = new PamBorderPane();
+ mainPane.setCenter(holderPane);
+ }
+
+ //
+ // public Boolean getParams(){
+ // array.nameProperty().setValue(nameField.getText());
+ // array.hArrayTypeProperty().setValue(arrayType.getValue());
+ // try {
+ // array.xPosProperty().setValue(Double.valueOf(xPos.getText()));
+ // array.yPosProperty().setValue(Double.valueOf(yPos.getText()));
+ // array.zPosProperty().setValue(Double.valueOf(zPos.getText()));
+ // }
+ // catch (Exception e){
+ // System.err.println("Invalid field in Array Dialog");
+ // return false;
+ // }
+ // return true;
+ // }
+ //
+ // public void setParams(Hydrophone hydrophone){
+ //
+ // iD.setText(String.format("%d", hydrophone.getID()));
+ // streamers.getItems().clear();
+ //
+ // //set thre text values for the recieevrs.
+ //// setRecieverLabelText();
+ // if (currentArray != null) {
+ // Streamer s;
+ // for (int i = 0; i < currentArray.getNumStreamers(); i++) {
+ // s = currentArray.getStreamer(i);
+ // streamers.getItems().add(String.format("Streamer %d, x=%3.1f", i, s.getX()));
+ // }
+ // }
+ // if (hydrophone.getStreamerId() < currentArray.getNumStreamers()) {
+ // streamers.getSelectionModel().select(hydrophone.getStreamerId());
+ // }
+ // hSens.setText(String.format("%.1f", hydrophone.getSensitivity()-PamController.getInstance().getGlobalMediumManager().getdBSensOffset()));
+ // preampGain.setText(String.format("%.1f", hydrophone.getPreampGain()));
+ // // bandwidth0.setText(String.format("%.1f", hydrophone.getBandwidth()[0]));
+ // // bandwidth1.setText(String.format("%.1f", hydrophone.getBandwidth()[1]));
+ //
+ //
+ //// this.array=array;
+ //// nameField.setText(hydrophone.getType());
+ // parentArrayComboBox.setValue(array.get);
+ //
+ // //attachmentComboBox.setItems(ArrayModelControl.getInstance().getArrays());
+ // parentArrayComboBox.setValue(array.parentHArrayProperty().getValue());
+ //
+ // xPos.setText(Double.toString(hydrophone.);
+ // yPos.setText(Double.toString(array.yPosProperty().get()));
+ // zPos.setText(Double.toString(array.zPosProperty().get()));
+ //
+ // createArrayPane(array);
+ //
+ // }
+
+
+ /**
+ * Set the receiver labels depending on whether air or water is being used.
+ */
+ private void setGeneralInfoLabelText() {
+ String recieverString = PamController.getInstance().getGlobalMediumManager().getRecieverString();
+ String dbSens = PamController.getInstance().getGlobalMediumManager().getdBSensString();
+
+ recieverIDLabel.setText(recieverString+ " ID Info");
+ recieverTypeLabel.setText(recieverString + " type ");
+ recieverSensLabel.setText(recieverString + " sens ");
+ dBSensLabel.setText(dbSens);
+ }
+
+
+ /**
+ * Set the receiver labels depending on whether air or water is being used.
+ */
+ private void setCoordsText() {
+ String recieverDepthString = PamController.getInstance().getGlobalMediumManager().getZString();
+
+ depthLabel.setText(recieverDepthString + " ");
+
+ switch (PamController.getInstance().getGlobalMediumManager().getCurrentMedium()) {
+ case Air:
+ depthLabel2.setText(" m (height above streamer)");
+ break;
+ case Water:
+ depthLabel2.setText(" m (depth below streamer)");
+ break;
+ }
+
+ }
+
+
+
+
+ /**
+ * Create the pane to allow users to change the position of hydrophones
+ */
+ private Pane createGeneralPane() {
+
+ PamGridPane mainControls=new PamGridPane();
+ mainControls.setHgap(5);
+ mainControls.setVgap(5);
+
+
+ int gridy = 0;
+ Label parentArrayLabel = new Label("Parent Array");
+ parentArrayLabel.setAlignment(Pos.CENTER_LEFT);
+ mainControls.add(parentArrayLabel, 0, gridy);
+ streamers = new ComboBox();
+ mainControls.add(streamers, 1, gridy);
+
+ gridy++;
+ mainControls.add(recieverTypeLabel = new Label(""), 0, gridy);
+ recieverTypeLabel.setAlignment(Pos.CENTER_LEFT);
+ defaultHydro = new ComboBox();
+
+ for (int i=0; i{
+ //don't want to trigger this if we are programtically setting it back
+ if (defaultHydro.getSelectionModel().getSelectedIndex() <= 0 || ressetHydrophoneType) {
+ //do nothing.
+ return;
+ }
+ ressetHydrophoneType=true;
+ hSens.getValueFactory().setValue(Double.valueOf(DefaultHydrophone.values()[defaultHydro.getSelectionModel().getSelectedIndex()-1].getSens()));
+ preampGain.getValueFactory().setValue(Double.valueOf(DefaultHydrophone.values()[defaultHydro.getSelectionModel().getSelectedIndex()-1].getGain()));
+ ressetHydrophoneType=false;
+ });
+
+ mainControls.add(defaultHydro, 1, gridy);
+
+ gridy++;
+ mainControls.add(recieverSensLabel = new Label(""), 0, gridy);
+ recieverSensLabel.setAlignment(Pos.CENTER_LEFT);
+ hSens = new PamSpinner(-Double.MAX_VALUE, Double.MAX_VALUE, -200., 1.);
+ hSens.setEditable(true);
+
+ hSens.valueProperty().addListener((obs, oldval, newVal)->{
+ if (ressetHydrophoneType) return;
+ ressetHydrophoneType = true; //make sure we don't trigger anything when resetting the combo box
+ defaultHydro.getSelectionModel().select(0);
+ ressetHydrophoneType= false;
+ });
+
+ mainControls.add(hSens, 1, gridy);
+ mainControls.add(dBSensLabel = new Label(""), 2, gridy);
+
+
+ gridy++;
+ Label preAmpLabel = new Label("Preamplifier gain");
+ mainControls.add(preAmpLabel, 0, gridy);
+ preAmpLabel.setAlignment(Pos.CENTER_LEFT);
+ preampGain =new PamSpinner(-Double.MAX_VALUE, Double.MAX_VALUE, 0., 1.);
+ preampGain.valueProperty().addListener((obs, oldval, newVal)->{
+ if (ressetHydrophoneType) return;
+ ressetHydrophoneType = true;//make sure we don't trigger anything when resetting the combo box
+ defaultHydro.getSelectionModel().select(0);
+ ressetHydrophoneType= false;
+ });
+ preampGain.setEditable(true);
+
+
+ mainControls.add(preampGain, 1, gridy);
+ mainControls.add(new Label("dB"), 2, gridy);
+
+ ColumnConstraints col1 = new ColumnConstraints();
+ col1.setMinWidth(COLUMN_0_WIDTH);
+ col1.setMaxWidth(COLUMN_0_WIDTH);
+ mainControls.getColumnConstraints().addAll(col1);
+
+ setGeneralInfoLabelText();
+
+
+ return mainControls;
+ }
+
+ /**
+ * Create the pane to allow users to change the position of hydrophones
+ */
+ private Pane createPositionPane(){
+
+ double sectionPadding=15;
+
+
+ PamVBox mainControls=new PamVBox();
+ mainControls.setSpacing(5);
+
+ Insets h;
+
+ Label nameLabel=new Label("Array Name");
+ nameLabel.setPadding(new Insets(5,0,0,0));
+ nameField=new TextField();
+
+ //parent array.
+ Label parentArrayLabel=new Label("Parent Streamer");
+ parentArrayLabel.setPadding(new Insets(sectionPadding,0,0,0));
+
+ PamGridPane positionPane = new PamGridPane();
+ positionPane.setHgap(5);
+ positionPane.setVgap(5);
+
+ ColumnConstraints rc = new ColumnConstraints(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE, MAX_TEXTFIELD_WIDTH);
+ //this sets all text fields to the correct width - but of naff hack but what grid pane needs to work.
+ for (int i=1; i<5; i++) {
+ positionPane.getColumnConstraints().add(rc);
+ }
+
+ double maxWidth =10;
+
+ xPos=new TextField();
+ xPos.textProperty().addListener((obsVal, oldVal, newVal)->{
+ notifySettingsListeners();
+ });
+ xPos.setMaxWidth(maxWidth);
+ addTextValidator(xPos, "x position", validator);
+
+ yPos=new TextField();
+ yPos.setMaxWidth(maxWidth);
+ addTextValidator(yPos, "y position", validator);
+ yPos.textProperty().addListener((obsVal, oldVal, newVal)->{
+ notifySettingsListeners();
+ });
+
+ zPos=new TextField();
+ zPos.setMaxWidth(maxWidth);
+ zPos.textProperty().addListener((obsVal, oldVal, newVal)->{
+ notifySettingsListeners();
+ });
+
+ addTextValidator(zPos, "z position", validator);
+ depthLabel = new Label("Depth");
+ depthLabel.setAlignment(Pos.CENTER);
+
+ xPosErr=new TextField();
+ xPosErr.setMaxWidth(50);
+ addTextValidator(xPosErr, "x error",validator);
+ yPosErr=new TextField();
+ yPosErr.setMaxWidth(50);
+ addTextValidator(yPosErr, "y error",validator);
+ zPosErr=new TextField();
+ zPosErr.setMaxWidth(50);
+ depthLabel2 = new Label(""); //changes with air or water mode.
+ depthLabel2.setAlignment(Pos.CENTER);
+ addTextValidator(zPosErr, "z error", validator);
+
+ int col=0;
+ int row =0;
+
+ Label xLabel = new Label("x");
+ xLabel.setAlignment(Pos.CENTER);
+
+ Label yLabel = new Label("y");
+ yLabel.setAlignment(Pos.CENTER);
+
+ col=1;
+ positionPane.add(xLabel, col++, row);
+ positionPane.add(yLabel, col++, row);
+ positionPane.add(depthLabel, col++, row);
+
+ col=0;
+ row++;
+
+ Label positionLabel = new Label("Position");
+ positionPane.add(positionLabel, col++, row);
+ positionPane.add(xPos, col++, row);
+ positionPane.add(yPos, col++, row);
+ positionPane.add(zPos, col++, row);
+ positionPane.add(new Label("(m)"), col++, row);
+
+ col=0;
+ row++;
+
+ Label errLabel = new Label("Error");
+ positionPane.add(errLabel, col++, row);
+ positionPane.add(xPosErr, col++, row);
+ positionPane.add(yPosErr, col++, row);
+ positionPane.add(zPosErr, col++, row);
+ positionPane.add(new Label("(m)"), col++, row);
+
+// positionPane.add(new Label("\u00B1"), col, 2);
+// positionPane.add(xPosErr, col, 3);
+// positionPane.add(new Label("m (right of streamer)"), col, 5);
+
+ col++;
+
+// Label yLabel = new Label("y");
+// yLabel.setAlignment(Pos.CENTER);
+// positionPane.add(yLabel, col, 0);
+// positionPane.add(yPos, col, 1);
+// positionPane.add(new Label("\u00B1"), col, 2);
+// positionPane.add(yPosErr, col, 3);
+// positionPane.add(new Label("m (ahead of streamer)"), col, 4);
+// col++;
+//
+//
+// positionPane.add(depthLabel, col, 0);
+// positionPane.add(zPos, col, 1);
+// positionPane.add(new Label("\u00B1"), col, 2);
+// positionPane.add(zPosErr, col, 3);
+// positionPane.add(depthLabel2, col, 4);
+
+ // ColumnConstraints col1 = new ColumnConstraints();
+ // col1.setHgrow(Priority.ALWAYS);
+ // positionPane.getColumnConstraints().add(col1);
+
+ // Label positionLabel = new Label("Coordinates");
+ // PamGuiManagerFX.titleFont2style(positionLabel);
+
+ mainControls.getChildren().addAll(positionPane);
+
+ ColumnConstraints col1 = new ColumnConstraints();
+ col1.setMinWidth(COLUMN_0_WIDTH);
+ col1.setMaxWidth(COLUMN_0_WIDTH);
+ positionPane.getColumnConstraints().addAll(col1);
+
+
+ setCoordsText();
+
+ return mainControls;
+
+ }
+
+
+
+ /**
+ * Creates a text filed and adds a validator to check that the input is OK.
+ * @return
+ */
+ protected static void addTextValidator(TextField userTextField, String description, Validator validator) {
+ //userTextField.setPrefColumnCount(8);
+
+ validator.createCheck()
+ .dependsOn(description, userTextField.textProperty())
+ .withMethod(c -> {
+ String posVal = c.get(description);
+
+ /**
+ * Ok, this is weird. So if the c.error is called then somehow it messes up
+ * the sizing of the pane i.e. it does not resize..
+ */
+
+ try {
+ if (posVal.isEmpty() || Double.valueOf(posVal)==null) {
+ c.error("The input for " + description + " is invalid");
+ }
+ }
+ catch (Exception e) {
+ c.error("The input for " + description + " is invalid");
+ }
+ })
+ .decorates(userTextField).immediate();
+ }
+
+
+
+ @Override
+ public void setParams(Hydrophone hydrophone) {
+
+ //parent array stuff.
+
+ //iD.setText(String.format("%d", hydrophone.getID()));
+
+ streamers.getItems().clear();
+
+ //set thre text values for the recieevrs.
+ setGeneralInfoLabelText();
+ if (currentArray != null) {
+ Streamer s;
+ for (int i = 0; i < currentArray.getNumStreamers(); i++) {
+ s = currentArray.getStreamer(i);
+ streamers.getItems().add(String.format("Streamer %d, x=%3.1f", i, s.getX()));
+ }
+ }
+ if (hydrophone.getStreamerId() < currentArray.getNumStreamers()) {
+ streamers.getSelectionModel().select(hydrophone.getStreamerId());
+ }
+
+ //hydrophone stuff
+ hSens.getValueFactory().setValue(hydrophone.getSensitivity()-PamController.getInstance().getGlobalMediumManager().getdBSensOffset());
+ preampGain.getValueFactory().setValue(hydrophone.getPreampGain());
+
+ double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();
+ setCoordsText();
+
+ interpPane.setSelection(currentArray.getHydrophoneInterpolation());
+
+ xPos.setText(Double.toString(hydrophone.getX()));
+ yPos.setText(Double.toString(hydrophone.getY()));
+ zPos.setText(Double.toString(zCoeff*hydrophone.getZ()));
+ xPosErr.setText(Double.toString(hydrophone.getdX()));
+ yPosErr.setText(Double.toString(hydrophone.getdY()));
+ zPosErr.setText(Double.toString(hydrophone.getdZ()));
+
+ }
+
+
+ @Override
+ public Hydrophone getParams(Hydrophone hydrophone) {
+ double zCoeff = PamController.getInstance().getGlobalMediumManager().getZCoeff();
+
+ try {
+ //hydrophone.setID(Integer.valueOf(iD.getText()));
+ //hydrophone.setType(type.getText());
+ hydrophone.setStreamerId(streamers.getSelectionModel().getSelectedIndex());
+ hydrophone.setSensitivity(hSens.getValue()+PamController.getInstance().getGlobalMediumManager().getdBSensOffset());
+ hydrophone.setPreampGain(preampGain.getValue());
+// double[] bw = new double[2];
+ // bw[0] = Double.valueOf(bandwidth0.getText());
+ // bw[1] = Double.valueOf(bandwidth1.getText());
+ // hydrophone.setBandwidth(bw);
+
+ hydrophone.setX(Double.valueOf(xPos.getText()));
+ hydrophone.setY(Double.valueOf(yPos.getText()));
+ hydrophone.setZ(zCoeff*Double.valueOf(zPos.getText()));
+ hydrophone.setdX(Double.valueOf(xPosErr.getText()));
+ hydrophone.setdY(Double.valueOf(yPosErr.getText()));
+ hydrophone.setdZ(Double.valueOf(zPosErr.getText()));
+
+ int hi = interpPane.getSelection();
+ if (hi >= 0) {
+ this.currentArray.setHydrophoneInterpolation(interpPane.getSelectedInterpType());
+ }
+ }
+ catch (Exception Ex) {
+ System.err.println("There is a problem with one of the parameters in the hydrophone panel");
+ return null;
+ }
+ return hydrophone;
+ }
+
+ /**
+ * Set the current array associated with the hydrophone.
+ * @param currentArray - the current array.
+ */
+ public void setCurrentArray(PamArray currentArray) {
+ this.currentArray= currentArray;
+
+ }
+
+ public void setRecieverLabels() {
+ setGeneralInfoLabelText();
+
+ }
+
+
+
+
+
+
+}
diff --git a/src/Array/layoutFX/HydrophonesPane.java b/src/Array/layoutFX/HydrophonesPane.java
new file mode 100644
index 00000000..4d574fa4
--- /dev/null
+++ b/src/Array/layoutFX/HydrophonesPane.java
@@ -0,0 +1,412 @@
+package Array.layoutFX;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import Array.Hydrophone;
+import Array.PamArray;
+import PamController.PamController;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.geometry.Insets;
+import javafx.scene.control.Button;
+import javafx.scene.control.Dialog;
+import javafx.scene.control.TableCell;
+import javafx.scene.layout.Pane;
+import javafx.scene.paint.Color;
+import javafx.util.Callback;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.cell.TextFieldTableCell;
+import javafx.util.converter.IntegerStringConverter;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.PamColorsFX;
+import pamViewFX.fxNodes.flipPane.PamFlipPane;
+import pamViewFX.fxNodes.table.TableSettingsPane;
+
+/**
+ * Table which allows users to add and edit hydrophones.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class HydrophonesPane extends PamBorderPane {
+
+
+ static final double defaultx = 0.;
+ static final double defaulty = 0.;
+ static final double defaultz = 0.;
+ static final double defaultxErr = 0.;
+ static final double defaultyErr = 0.;
+ static final double defaultzErr = 0.;
+ static final String defaulttype = "Unknown";
+ static final double defaultsensitivity = -201;
+
+ /**
+ * Reference to the current array
+ */
+ protected PamArray currentArray;
+
+ /**
+ * The current hydrophone data.
+ */
+ private HydrophoneProperty currentHydrophoneData;
+
+
+ /**
+ * A list of all the current hydrophones.
+ */
+ ObservableList hydrophoneList = FXCollections.observableArrayList();
+
+
+ /**
+ * The hydrophone array table.
+ */
+ private HydrophoneTable tableArrayPane;
+
+ private PamFlipPane pamFlipePane;
+
+ /**
+ * Settings pane for a single hydrophone.
+ */
+ private HydrophoneSettingsPane hydrophonePane = new HydrophoneSettingsPane();
+
+ /**
+ * A list of listeners which are called whenever a hydrophone is added removed or changed.
+ */
+ public ArrayList hydrophoneChangeListeners = new ArrayList();
+
+ public HydrophonesPane() {
+
+ tableArrayPane = new HydrophoneTable(hydrophoneList);
+
+ tableArrayPane.setPadding(new Insets(5,5,5,5));
+
+ pamFlipePane = new PamFlipPane();
+ pamFlipePane.getAdvLabel().setText(PamController.getInstance().getGlobalMediumManager().getRecieverString());
+ // pamFlipePane.minWidthProperty().bind(this.widthProperty());
+ // pamFlipePane.setStyle("-fx-background-color: green;");
+
+
+ ((Pane) hydrophonePane.getContentNode()).setPadding(new Insets(5,5,5,15));
+
+ pamFlipePane.setAdvPaneContent(hydrophonePane.getContentNode());
+ pamFlipePane.setFrontContent(tableArrayPane);
+
+ pamFlipePane.getFront().setPadding(new Insets(5,5,5,10));
+
+ pamFlipePane.backButtonProperty().addListener((obsval, oldVal, newVal)->{
+
+ // System.out.println("Hello back button pressed: " + newVal.intValue());
+ //the flip pane
+ if (newVal.intValue()==PamFlipPane.OK_BACK_BUTTON) {
+
+ Hydrophone hydro = hydrophonePane.getParams(currentHydrophoneData.getHydrophone());
+
+ if (hydro==null) {
+ //the warning dialog is shown in the streamer settings pane
+ return;
+ }
+
+ // System.out.println("Hydro: " + currentHydrophoneData.getX().get()+ " " + currentHydrophoneData.getY().get() + " " + currentHydrophoneData.getZ().get() + " ID: " +hydro.getID());
+ // System.out.println("Hydro err: " + currentHydrophoneData.getXErr().get()+ " " + currentHydrophoneData.getYErr().get() + " " + currentHydrophoneData.getZErr().get());
+
+ currentHydrophoneData.setHydrophone(hydro);
+
+ notifyHydrophoneListeners(currentHydrophoneData);
+
+ //need to refresh table to show symbol.
+ tableArrayPane.getTableView().refresh();
+ //
+ // System.out.println("Table size: " + tableArrayPane.getTableView().getItems().size());
+ // for (int i=0; i {
+
+
+ /**
+ * The z table
+ */
+ private TableColumn z;
+
+ public HydrophoneTable(ObservableList hydrophoneData) {
+ super(hydrophoneData);
+
+ z = new TableColumn("depth");
+ z.setCellValueFactory(cellData -> cellData.getValue().getZ().multiply(PamController.getInstance().getGlobalMediumManager().getZCoeff()));
+ z.setEditable(true);
+
+ //need to set up all the rows.
+ TableColumn hydroID = new TableColumn("ID");
+ hydroID.setCellValueFactory(cellData -> cellData.getValue().getID().asObject());
+ hydroID.setEditable(false);
+
+ // Default cell factory provides text field for editing and converts text in text field to int.
+ Callback, TableCell> defaultCellFactory =
+ TextFieldTableCell.forTableColumn(new IntegerStringConverter());
+
+ // Cell factory implementation that uses default cell factory above, and augments the implementation
+ // by updating the value of the looked-up color cell-selection-color for the cell when the item changes:
+ Callback, TableCell> cellFactory = col -> {
+ TableCell cell = defaultCellFactory.call(col);
+ cell.itemProperty().addListener((obs, oldValue, newValue) -> {
+// System.out.println("Hello set colour: " + newValue);
+ if (newValue == null) {
+ cell.setStyle("cell-selection-color: -fx-selection-bar ;");
+ } else {
+ Color color = createColor(newValue.intValue());
+ String formattedColor = formatColor(color);
+// cell.setStyle("cell-selection-color: "+ formattedColor + " ;");
+ cell.setStyle("-fx-background: "+ formattedColor + " ;");
+ cell.setStyle("-fx-background-color: "+ formattedColor + " ;");
+// System.out.println("Hello set style: " + formattedColor);
+ }
+ });
+ return cell;
+ };
+
+ hydroID.setCellFactory(cellFactory);
+
+
+ TableColumn x = new TableColumn("x");
+ x.setCellValueFactory(cellData -> cellData.getValue().getX());
+ x.setEditable(true);
+
+ TableColumn y = new TableColumn("y");
+ y.setCellValueFactory(cellData -> cellData.getValue().getY());
+ y.setEditable(true);
+
+
+ TableColumn posColumn=new TableColumn("Position (m)");
+ posColumn.getColumns().addAll(x, y, z);
+
+ TableColumn xErr = new TableColumn("x");
+ xErr.setCellValueFactory(cellData -> cellData.getValue().getXErr());
+ xErr.setEditable(true);
+
+ TableColumn yErr = new TableColumn("y");
+ yErr.setCellValueFactory(cellData -> cellData.getValue().getYErr());
+ yErr.setEditable(true);
+
+ TableColumn zErr = new TableColumn("z");
+ zErr.setCellValueFactory(cellData -> cellData.getValue().getZErr());
+ zErr.setEditable(true);
+
+ TableColumn errorColumn=new TableColumn("Errors (m)");
+ errorColumn.getColumns().addAll(xErr, yErr, zErr);
+
+ getTableView().getColumns().addAll(hydroID, posColumn, errorColumn);
+
+ }
+
+
+ // Create color based on int value. Just use value as hue, full saturation and brightness:
+ private Color createColor(int i) {
+ //get channel colour and add a bit of transparancy to make less abnoxious
+ return PamColorsFX.getInstance().getChannelColor(i).deriveColor(1, 1, 1, 0.5);
+
+// return Color.hsb(x, 1.0, 1.0);
+ }
+
+ // Format color as string for CSS (#rrggbb format, values in hex).
+ private String formatColor(Color c) {
+ int r = (int) (255 * c.getRed());
+ int g = (int) (255 * c.getGreen());
+ int b = (int) (255 * c.getBlue());
+ return String.format("#%02x%02x%02x", r, g, b);
+ }
+
+ @Override
+ public void dialogClosed(HydrophoneProperty data) {
+ System.out.println("Get hydrophone paramters");
+ Hydrophone hydro = hydrophonePane.getParams(data.getHydrophone());
+ data.setHydrophone(hydro);
+ }
+
+ @Override
+ public Dialog createSettingsDialog(HydrophoneProperty data) {
+ //we do not use dialogs here- sliding pane instead.
+ // setClassifierPane(data);
+ pamFlipePane.flipToBack();
+ return null;
+ }
+
+ @Override
+ public void editData(HydrophoneProperty data){
+ // setClassifierPane(data);
+
+ pamFlipePane.getAdvLabel().setText("Hydrophone " + data.getID().get() + " Settings");
+
+ hydrophonePane.setCurrentArray(currentArray);
+ hydrophonePane.setParams(data.getHydrophone());
+
+ currentHydrophoneData = data;
+
+ pamFlipePane.flipToBack();
+ }
+
+
+ private PamArray getCurrentArray() {
+ return currentArray;
+ }
+
+ /**
+ * Get the button which closes the hiding pane.
+ * @return button which closes the hiding pane.
+ */
+ public Button getFlipPaneCloseButton() {
+ return pamFlipePane.getBackButton();
+ }
+
+ @Override
+ public void createNewData(){
+ HydrophoneProperty hydrophone = createDefaultHydrophoneProperty(hydrophoneList.size());
+ //create a new classifier.
+ hydrophoneList.add(hydrophone);
+ notifyHydrophoneListeners(hydrophone);
+ }
+
+
+ @Override
+ public void deleteData(HydrophoneProperty data){
+ super.deleteData(data);
+ //the ID number for hydrophone sis actually important for where they are in the list. Bit a legacy issue but no
+ //point in messes everything up to fix. So, when a hydrophone is deleted must update all the ID numbers.
+
+ updateIDNumbers();
+
+ notifyHydrophoneListeners(data);
+ }
+
+ /**
+ * Update the ID numbers.
+ */
+ private void updateIDNumbers() {
+ for (int i=0; i getZColumn() {
+ return z;
+ }
+
+ /**
+ * Get the current streamers.
+ * @return the current streamers.
+ */
+ public ObservableList getHydrophones() {
+ return getData();
+ }
+
+
+ }
+
+ public void setParams(PamArray currentArray) {
+ this.currentArray=currentArray;
+
+ tableArrayPane.getHydrophones().clear();
+
+ for (int i=0; i getHydrophoneList() {
+ return hydrophoneList;
+ }
+
+ public void setHydrophoneList(ObservableList hydrophoneList) {
+ this.hydrophoneList = hydrophoneList;
+ }
+
+ public void setRecieverLabels() {
+ tableArrayPane.getZColumn().setText(PamController.getInstance().getGlobalMediumManager().getZString());
+ hydrophonePane.setRecieverLabels();
+ }
+
+ /**
+ * Add a listener which is called whenever a hydrophone is added, removed or changed.
+ * @param e - the listener to add
+ */
+ public void addStreamerListener(ArrayChangeListener e) {
+ hydrophoneChangeListeners.add(e);
+
+ }
+
+ /**
+ * Select the current hydrophone in table.
+ */
+ public void selectHydrophone(Hydrophone hydrophone) {
+ //select the current hydrophone in the table
+ tableArrayPane.getTableView().getSelectionModel().select(hydrophone.getID());
+ }
+
+ public void setCurrentArray(PamArray currentArray) {
+ this.currentArray=currentArray;
+
+ }
+
+ /**
+ * Get the hydrophone interpolation. Note that this is stored in the
+ * currentArray because the interpolator must be the same for all hydrophones.
+ *
+ * @return the inteprolation selection.
+ */
+ public int getHydrophoneInterp() {
+ return currentArray.getHydrophoneInterpolation();
+ }
+
+}
diff --git a/src/Array/layoutFX/InterpChoicePane.java b/src/Array/layoutFX/InterpChoicePane.java
new file mode 100644
index 00000000..b5e7613b
--- /dev/null
+++ b/src/Array/layoutFX/InterpChoicePane.java
@@ -0,0 +1,104 @@
+package Array.layoutFX;
+
+import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
+import javafx.scene.control.ChoiceBox;
+import javafx.util.StringConverter;
+
+
+
+/**
+ * Choice box which allows selection of interpolation options.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class InterpChoicePane extends InterpSettingsPane {
+
+ /**
+ * Interp choice box.
+ */
+ private ChoiceBox interpChoiceBox;
+
+ public InterpChoicePane() {
+
+ interpChoiceBox = new ChoiceBox();
+ interpChoiceBox.getItems().addAll(interpChoice);
+ interpChoiceBox.setMaxWidth(Double.MAX_VALUE);
+
+ interpChoiceBox.setConverter(new StringConverter<>() {
+ @Override
+ public String toString(Integer item) {
+ if (item ==null) return "null";
+ return getInterpString(item);
+ }
+
+ @Override
+ public Integer fromString(String unused) {
+ throw new UnsupportedOperationException();
+ }
+ });
+
+ this.setCenter(interpChoiceBox);
+
+ }
+
+ public void setSelection(int option) {
+
+ System.out.println("Select interp option: " + option);
+
+ interpChoiceBox.getSelectionModel().select(Integer.valueOf(option));
+
+ // useLatest.setSelected(option == PamArray.ORIGIN_USE_LATEST);
+ // useInterpolate.setSelected(option == PamArray.ORIGIN_INTERPOLATE);
+ // usePrevious.setSelected(option == PamArray.ORIGIN_USE_PRECEEDING);
+ }
+
+ public int getSelection() {
+ int sel = getSelectedInterpType();
+ if (((1< {
+
+ Pane mainPane;
+
+ private TextField speedOfSound;
+
+ private TextField speedOfSoundError;
+
+ private PamValidator validator;
+
+
+ public PropogationPane() {
+ super(null);
+ validator= new PamValidator();
+ mainPane = createEnvironmentPane();
+ }
+
+ /**
+ * Create the pane for setting propogation conditions.
+ * @return the pane with controls to change environmental variables.
+ */
+ private Pane createEnvironmentPane() {
+ speedOfSound = new TextField();
+ speedOfSound.setPrefColumnCount(6);
+
+ validator.createCheck()
+ .dependsOn("speed_of_sound", speedOfSound.textProperty())
+ .withMethod(c -> {
+ try {
+ String posVal = c.get("speed_of_sound");
+ if (posVal.isEmpty() || Double.valueOf(posVal)==null) {
+ c.error("The input for speed of sound is invalid");
+ }
+ }
+ catch (Exception e) {
+ c.error("The input for speed of sound is invalid");
+ }
+ })
+ .decorates(speedOfSound).immediate();
+
+
+ speedOfSoundError = new TextField();
+ speedOfSoundError.setPrefColumnCount(4);
+
+ validator.createCheck()
+ .dependsOn("speed_of_sound_error", speedOfSoundError.textProperty())
+ .withMethod(c -> {
+ try {
+ String posVal = c.get("speed_of_sound_error");
+ if (posVal.isEmpty() || Double.valueOf(posVal)==null) {
+ c.error("The input for speed of sound error is invalid");
+ }
+ }
+ catch (Exception e) {
+ c.error("The input for speed of sound is invalid");
+ }
+ })
+ .decorates(speedOfSoundError).immediate();
+
+ PamHBox hBox = new PamHBox();
+ hBox.setSpacing(5);
+ hBox.setAlignment(Pos.CENTER);
+
+
+ hBox.getChildren().addAll(new Label("Speed of sound"), speedOfSound, new Label("\u00B1"), speedOfSoundError, new Label("m/s"));
+
+ return hBox;
+ }
+
+ @Override
+ public PamArray getParams(PamArray currParams) {
+ if (validator.containsErrors()) return null;
+
+ currParams.setSpeedOfSound(Double.valueOf(speedOfSound.getText()));
+ currParams.setSpeedOfSoundError(Double.valueOf(speedOfSoundError.getText()));
+ return currParams;
+ }
+
+ @Override
+ public void setParams(PamArray input) {
+ //set the current params.
+ speedOfSound.setText(String.valueOf(input.getSpeedOfSound()));
+ speedOfSoundError.setText(String.valueOf(input.getSpeedOfSoundError()));
+ }
+
+ @Override
+ public String getName() {
+ return "Propogation pane";
+ }
+
+ @Override
+ public Node getContentNode() {
+ return mainPane;
+ }
+
+ @Override
+ public void paneInitialized() {
+ // TODO Auto-generated method stub
+
+ }
+
+
+
+}
diff --git a/src/Array/layoutFX/SensorSourcePane.java b/src/Array/layoutFX/SensorSourcePane.java
new file mode 100644
index 00000000..9c6f61f0
--- /dev/null
+++ b/src/Array/layoutFX/SensorSourcePane.java
@@ -0,0 +1,162 @@
+package Array.layoutFX;
+
+import java.util.ArrayList;
+
+import Array.sensors.ArrayParameterType;
+import Array.sensors.ArraySensorDataBlock;
+import Array.sensors.ArraySensorDataUnit;
+import Array.sensors.ArraySensorFieldType;
+import PamController.PamController;
+import PamguardMVC.PamDataBlock;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.Node;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Tooltip;
+
+public class SensorSourcePane {
+
+ private ArraySensorFieldType sensorType;
+
+ private ComboBox sensorDropDown;
+
+ private ArrayList currentBlocks;
+
+ private boolean defaultOption;
+
+ private boolean fixedOption;
+
+ private int nSpecials;
+
+ private ArrayParameterType[] specialTypes = new ArrayParameterType[2];
+
+ public SensorSourcePane(ArraySensorFieldType sensorType, boolean fixedOption, boolean defaultOption) {
+ this.sensorType = sensorType;
+ this.fixedOption = fixedOption;
+ this.defaultOption = defaultOption;
+ sensorDropDown = new ComboBox<>();
+ fillDropDown();
+ sensorDropDown.setTooltip(new Tooltip("Sensor updates for " + sensorType.toString()));
+ }
+
+ /**
+ * Get the type of sensor.
+ * @return the type of sensor.
+ */
+ public ArraySensorFieldType getSensorType() {
+ return sensorType;
+ }
+
+ public void setOnAction(EventHandler e) {
+ sensorDropDown.setOnAction(e);
+ }
+
+ public void fillDropDown() {
+ currentBlocks = getDataBlocks();
+ sensorDropDown.getItems().clear();
+ nSpecials = 0;
+ if (fixedOption) {
+ sensorDropDown.getItems().add("Fixed Value");
+ specialTypes[nSpecials++] = ArrayParameterType.FIXED;
+ }
+ if (defaultOption) {
+ sensorDropDown.getItems().add("Default value");
+ specialTypes[nSpecials++] = ArrayParameterType.DEFAULT;
+ }
+ for (PamDataBlock aBlock : currentBlocks) {
+ sensorDropDown.getItems().add(aBlock.getDataName());
+ }
+ }
+
+ /**
+ * Set the type of parameter being used, fixed, default or sensor
+ * @param paramType
+ */
+ public void setParameterType(ArrayParameterType paramType) {
+ for (int i = 0; i < nSpecials; i++) {
+ if (paramType == specialTypes[i]) {
+ sensorDropDown.getSelectionModel().select(i);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Get the type of parameter being used, fixed, default or sensor
+ * @return
+ */
+ public ArrayParameterType getParameterType() {
+ int ind = sensorDropDown.getSelectionModel().getSelectedIndex();
+ if (ind < 0) {
+ return null;
+ }
+ if (ind < nSpecials) {
+ return specialTypes[ind];
+ }
+ return ArrayParameterType.SENSOR;
+ }
+
+ /**
+ * Set the selected datablock for sensor data. Before calling this, you should call
+ * fillDropDown to make sure list of blocks is up to date.
+ * @param aDataBlock datablock to select
+ * @return true if that block was selected OK, i.e. it was in the list.
+ */
+ public boolean setDataBlock(PamDataBlock aDataBlock) {
+ if (currentBlocks == null) {
+ return false;
+ }
+ int ind = currentBlocks.indexOf(aDataBlock);
+ if (ind < 0) {
+ return false;
+ }
+ sensorDropDown.getSelectionModel().select(ind+nSpecials); // offset by 1 to allow for null option.
+ return true;
+ }
+
+ /**
+ *
+ * @return Currently selected datablock for this sensor (can be null)
+ */
+ public PamDataBlock getDataBlock() {
+ int ind = sensorDropDown.getSelectionModel().getSelectedIndex();
+ if (ind <= 0 || currentBlocks == null) {
+ return null;
+ }
+ else {
+ return currentBlocks.get(ind-nSpecials);
+ }
+ }
+
+ /**
+ * Get the sensor pane.
+ * @return the sensor pane
+ */
+ public Node getPane() {
+ return sensorDropDown;
+ }
+
+ /**
+ * Get a list of datablocks that might be able to provide info on this
+ * sensor field type
+ * @return
+ */
+ private ArrayList getDataBlocks() {
+ ArrayList allDataBlocks = PamController.getInstance().getDataBlocks(ArraySensorDataUnit.class, true);
+ ArrayList sensBlocks = new ArrayList<>();
+ if (allDataBlocks == null) {
+ return sensBlocks;
+ }
+ // go through take out the ones that support this sensor.
+ for (PamDataBlock aBlock : allDataBlocks) {
+ if (aBlock instanceof ArraySensorDataBlock == false) {
+ continue;
+ }
+ ArraySensorDataBlock sensBlock = (ArraySensorDataBlock) aBlock;
+ if (sensBlock.hasSensorField(sensorType)) {
+ sensBlocks.add(aBlock);
+ }
+ }
+ return sensBlocks;
+ }
+}
diff --git a/src/Array/layoutFX/StreamerProperty.java b/src/Array/layoutFX/StreamerProperty.java
new file mode 100644
index 00000000..eb82adc5
--- /dev/null
+++ b/src/Array/layoutFX/StreamerProperty.java
@@ -0,0 +1,121 @@
+package Array.layoutFX;
+
+import Array.Streamer;
+import javafx.beans.property.SimpleDoubleProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.property.SimpleStringProperty;
+
+
+/**
+ * Property class for a Streamer. Create property bindings for certain Streamer values which allows
+ * for much easier integration into UI components in JavaFX.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class StreamerProperty {
+
+ /**
+ * The simple name property.
+ */
+ private SimpleStringProperty name = new SimpleStringProperty();
+
+ private SimpleStringProperty reference = new SimpleStringProperty();
+
+ private SimpleStringProperty origin = new SimpleStringProperty();
+
+ /**
+ * Get the x, y and z.
+ */
+ private SimpleDoubleProperty x = new SimpleDoubleProperty();
+
+ private SimpleDoubleProperty y = new SimpleDoubleProperty();
+
+ private SimpleDoubleProperty z = new SimpleDoubleProperty();
+
+
+ private Streamer streamer;
+
+ private SimpleIntegerProperty streamerIDProperty = new SimpleIntegerProperty();
+
+ public StreamerProperty(Streamer streamer) {
+ setStreamer( streamer);
+ }
+
+ public void setStreamer(Streamer streamer) {
+ this.streamer = streamer;
+ name.setValue(streamer.getStreamerName());
+ x.setValue(streamer.getX());
+ y.setValue(streamer.getY());
+ z.setValue(streamer.getZ());
+ streamerIDProperty.setValue(streamer.getStreamerIndex());
+ reference.setValue(streamer.getHydrophoneLocator() != null ? streamer.getHydrophoneLocator().getName() : "null");
+ origin.setValue(streamer.getHydrophoneOrigin() != null ? streamer.getHydrophoneOrigin().getName() : "null");
+
+ }
+
+ public SimpleStringProperty getName() {
+ return name;
+ }
+
+ public void setName(SimpleStringProperty name) {
+ this.name = name;
+ }
+
+ public SimpleDoubleProperty getX() {
+ return x;
+ }
+
+ public void setX(SimpleDoubleProperty x) {
+ this.x = x;
+ }
+
+ public SimpleDoubleProperty getY() {
+ return y;
+ }
+
+ public void setY(SimpleDoubleProperty y) {
+ this.y = y;
+ }
+
+ public SimpleDoubleProperty getZ() {
+ return z;
+ }
+
+ public void setZ(SimpleDoubleProperty z) {
+ this.z = z;
+ }
+
+
+ public Streamer getStreamer() {
+ return streamer;
+ }
+
+ /**
+ * Get the index property of the streamer.
+ * @return the streamer index.
+ */
+ public SimpleIntegerProperty getID() {
+ return streamerIDProperty;
+ }
+
+ /**
+ * Get the reference property.
+ * @return the reference property.
+ */
+ public SimpleStringProperty getHydrophineLocator() {
+ return reference;
+ }
+
+
+ /**
+ * Get the origin string property.
+ * @return the origin string property.
+ */
+ public SimpleStringProperty getHydrophoneOrigin() {
+ return origin;
+ }
+
+
+
+}
diff --git a/src/Array/layoutFX/StreamerSettingsPane.java b/src/Array/layoutFX/StreamerSettingsPane.java
new file mode 100644
index 00000000..f2880f52
--- /dev/null
+++ b/src/Array/layoutFX/StreamerSettingsPane.java
@@ -0,0 +1,752 @@
+package Array.layoutFX;
+
+import org.controlsfx.control.PopOver;
+
+import Array.HydrophoneLocator;
+import Array.HydrophoneLocators;
+import Array.PamArray;
+import Array.Streamer;
+import Array.sensors.ArrayParameterType;
+import Array.sensors.ArraySensorFieldType;
+import Array.streamerOrigin.HydrophoneOriginMethod;
+import Array.streamerOrigin.HydrophoneOriginMethods;
+import Array.streamerOrigin.HydrophoneOriginSystem;
+import Array.streamerOrigin.OriginDialogComponent;
+import Array.streamerOrigin.OriginSettings;
+import PamController.PamController;
+import PamController.SettingsPane;
+import PamUtils.LatLong;
+import PamguardMVC.PamDataBlock;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import pamViewFX.PamGuiManagerFX;
+import pamViewFX.fxGlyphs.PamGlyphDude;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.PamButton;
+import pamViewFX.fxNodes.PamGridPane;
+import pamViewFX.fxNodes.PamHBox;
+import pamViewFX.fxNodes.PamVBox;
+import pamViewFX.validator.PamValidator;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.ColumnConstraints;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.Region;
+import net.synedra.validatorfx.Validator;
+
+
+/**
+ * A JavaFX settings pane for a streamer.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class StreamerSettingsPane extends SettingsPane {
+
+ private final static double MAX_TEXTFIELD_WIDTH = 80;
+
+
+ public PamBorderPane mainPane;
+
+ /**
+ * Combo Box which shows which origin methods are available.
+ */
+ private ComboBox originMethod;
+
+ /**
+ * The origin pane;
+ */
+ private PamBorderPane originPane;
+
+ /**
+ * The default streamer
+ */
+ public Streamer defaultStreamer;
+
+
+ /**
+ * The current array
+ */
+ private PamArray currentArray;
+
+ /**
+ * The current origin methods
+ */
+ private HydrophoneOriginMethod currentOriginMethod;
+
+ /*
+ * The current origin method pane.
+ */
+ private Pane currentOriginComponent;
+
+ /**
+ * Interpolation panel
+ */
+ private InterpChoicePane interpPane;
+
+
+ private TextField xPos;
+
+
+ private Validator validator = new PamValidator();
+
+
+ private TextField yPos;
+
+
+ private TextField zPos;
+
+
+ private TextField zPosErr;
+
+
+ private TextField xPosErr;
+
+
+ private Label depthLabel;
+
+
+ private TextField yPosErr;
+
+
+ private Label depthLabel2;
+
+
+ private TextField heading;
+
+
+ private TextField roll;
+
+
+ private TextField pitch;
+
+
+ private ComboBox localiserMethod;
+
+
+ private SensorSourcePane[] sensorComponents;
+
+
+ private Label depthSensorLabel;
+
+
+ /**
+ * Button for extra origin parameters.
+ */
+ private PamButton originButton;
+
+
+
+ public StreamerSettingsPane() {
+ super(null);
+
+ mainPane = new PamBorderPane();
+ mainPane.setCenter(getStreamerPane());
+
+ }
+
+ /**
+ * Create the streamer pane
+ * @return get the pane.
+ */
+ private Pane getStreamerPane(){
+
+ String reciever = PamController.getInstance().getGlobalMediumManager().getRecieverString();
+
+ Label label = new Label("Geo-reference Position");
+ PamGuiManagerFX.titleFont2style(label);
+
+ //holds advanced setings for new origin methods.
+ originPane = new PamBorderPane();
+ PopOver popOver = new PopOver();
+ popOver.setContentNode(originPane);
+
+ originMethod = new ComboBox();
+ originButton = new PamButton();
+ originButton.setGraphic(PamGlyphDude.createPamIcon("mdi2c-crosshairs-gps"));
+ originButton.setOnAction((a)->{
+ popOver.show(originButton);
+ });
+ originMethod.setMaxWidth(Double.MAX_VALUE);
+
+ PamHBox originHolder = new PamHBox();
+ originHolder.setSpacing(5);
+ originHolder.setAlignment(Pos.CENTER_LEFT);
+ originHolder.getChildren().addAll(originMethod,originButton);
+ originHolder.setMaxWidth(Double.MAX_VALUE);
+ HBox.setHgrow(originMethod, Priority.ALWAYS);
+
+ int n = HydrophoneOriginMethods.getInstance().getCount();
+ for (int i = 0; i < n; i++) {
+ originMethod.getItems().add(HydrophoneOriginMethods.getInstance().getMethod(i));
+ }
+
+ Label hydroMovementLabel = new Label(reciever +" Movement Model");
+
+ //listener for when a new origin method is called.
+ originMethod.setOnAction((action)->{
+ newOriginMethod();
+ });
+
+ interpPane = new InterpChoicePane();
+ Label inteprlabel = new Label("Interpolation");
+ PamGuiManagerFX.titleFont2style(inteprlabel);
+
+ PamHBox interpBox = new PamHBox();
+ interpBox.setSpacing(5);
+ Label interpMethodLabel = new Label("Method");
+
+ Region spacer = new Region();
+ spacer.prefWidthProperty().bind(originButton.widthProperty());
+ interpBox.getChildren().addAll(interpMethodLabel, interpPane, spacer);
+ interpBox.setAlignment(Pos.CENTER_LEFT);
+ interpBox.setMaxWidth(Double.MAX_VALUE);
+ interpPane.setMaxWidth(Double.MAX_VALUE);
+ HBox.setHgrow(interpPane, Priority.ALWAYS);
+
+ //add all stuff to the holder
+ PamVBox holder = new PamVBox();
+ holder.getChildren().addAll(label, originHolder, hydroMovementLabel, createLocatorPane(), inteprlabel, interpBox);
+ holder.setSpacing(5);
+
+
+ return holder;
+
+ }
+
+ /**
+ * Create the locator pane.
+ * @return the pane containing controls.
+ */
+ public Pane createLocatorPane() {
+
+ localiserMethod = new ComboBox<>();
+ int n = HydrophoneLocators.getInstance().getCount();
+ for (int i = 0; i < n; i++) {
+ localiserMethod.getItems().add(HydrophoneLocators.getInstance().getSystem(i));
+ }
+ localiserMethod.setMaxWidth(Double.MAX_VALUE);
+
+ PamHBox loclaiserMethodHolder = new PamHBox();
+ loclaiserMethodHolder.setSpacing(5);
+ loclaiserMethodHolder.setAlignment(Pos.CENTER_LEFT);
+ Label spacer = new Label();
+ spacer.prefWidthProperty().bind(originButton.widthProperty());
+ loclaiserMethodHolder.getChildren().addAll(localiserMethod, spacer);
+ loclaiserMethodHolder.setMaxWidth(Double.MAX_VALUE);
+ HBox.setHgrow(localiserMethod, Priority.ALWAYS);
+
+ //hydrophone position and
+ PamGridPane positionPane = new PamGridPane();
+ positionPane.setHgap(5);
+ positionPane.setVgap(5);
+
+ ColumnConstraints rc = new ColumnConstraints(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE, MAX_TEXTFIELD_WIDTH);
+
+ //Orientation pane.
+ //create data sources for sensors.
+ ArraySensorFieldType[] sensorFields = ArraySensorFieldType.values();
+ sensorComponents = new SensorSourcePane[sensorFields.length];
+ //EnableOrientation eo = new EnableOrientation();
+ for (int i = 0; i < sensorFields.length; i++) {
+ sensorComponents[i] = new SensorSourcePane(sensorFields[i], true, sensorFields[i] != ArraySensorFieldType.HEIGHT);
+ sensorComponents[i].setOnAction((e)->{
+ enableOrientationPane();
+ });
+ }
+ PamButton button = new PamButton("Sensors");
+ button.setGraphic(PamGlyphDude.createPamIcon("mdi2c-compass-outline", PamGuiManagerFX.iconSize));
+
+ PopOver popOver = new PopOver(createSensorPane());
+ popOver.setDetachable(true);
+
+ button.setOnAction((a)->{
+ popOver.show(button);
+ });
+
+
+ //this sets all text fields to the correct width - but of naff hack but what grid pane needs to work.
+ for (int i=1; i<5; i++) {
+ positionPane.getColumnConstraints().add(rc);
+ }
+
+ xPos=new TextField();
+ xPos.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(xPos, "x position", validator);
+ yPos=new TextField();
+ yPos.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(yPos, "y position", validator);
+ zPos=new TextField();
+ zPos.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(zPos, "z position", validator);
+
+
+ depthLabel = new Label("Depth");
+ depthLabel.setAlignment(Pos.CENTER);
+
+ depthSensorLabel = new Label("Depth Sensor");
+ depthSensorLabel.setAlignment(Pos.CENTER);
+
+
+ xPosErr=new TextField();
+ xPosErr.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(xPosErr, "x error", validator);
+ yPosErr=new TextField();
+ yPosErr.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(yPosErr, "y error", validator);
+ zPosErr=new TextField();
+ zPosErr.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ depthLabel2 = new Label(""); //changes with air or water mode.
+ depthLabel2.setAlignment(Pos.CENTER);
+ HydrophoneSettingsPane.addTextValidator(zPosErr, "z error", validator);
+
+ int col=0;
+ int row=0;
+
+
+ Label xLabel = new Label("x");
+ xLabel.setAlignment(Pos.CENTER);
+
+ Label yLabel = new Label("y");
+ yLabel.setAlignment(Pos.CENTER);
+
+ //Orientations
+
+ String degsLab = LatLong.deg + " ";
+
+
+ col=1;
+ positionPane.add(xLabel, col++, row);
+ positionPane.add(yLabel, col++, row);
+ positionPane.add(depthLabel, col++, row);
+ col++;
+ positionPane.add(depthSensorLabel, col++, row);
+
+ col=0;
+ row++;
+
+ Label positionLabel = new Label("Position");
+ positionPane.add(positionLabel, col++, row);
+ positionPane.add(xPos, col++, row);
+ positionPane.add(yPos, col++, row);
+ positionPane.add(zPos, col++, row);
+ positionPane.add(new Label("(m)"), col++, row);
+ positionPane.add(sensorComponents[ArraySensorFieldType.HEIGHT.ordinal()].getPane(), col++, row);
+
+ col=0;
+ row++;
+
+ Label errLabel = new Label("Error");
+ positionPane.add(errLabel, col++, row);
+ positionPane.add(xPosErr, col++, row);
+ positionPane.add(yPosErr, col++, row);
+ positionPane.add(zPosErr, col++, row);
+ positionPane.add(new Label("(m)"), col++, row);
+
+ //Orientation
+ col=1;
+ row++;
+
+ Label headingLabel = new Label("Heading");
+ headingLabel.setAlignment(Pos.CENTER);
+
+ Label pitchLabel = new Label("Pitch");
+ pitchLabel.setAlignment(Pos.CENTER);
+
+ Label rolllabel = new Label("Roll");
+ rolllabel.setAlignment(Pos.CENTER);
+
+
+ positionPane.add(headingLabel, col++, row);
+ positionPane.add(pitchLabel, col++, row);
+ positionPane.add(rolllabel, col++, row);
+
+ row++;
+
+ heading = new TextField();
+ heading.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(heading, "heading", validator);
+
+ pitch = new TextField();
+ pitch.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(pitch, "pitch", validator);
+
+ roll = new TextField();
+ roll.setMaxWidth(MAX_TEXTFIELD_WIDTH);
+ HydrophoneSettingsPane.addTextValidator(roll, "roll", validator);
+
+ col=0;
+
+ Label orientation = new Label("Orientation");
+ positionPane.add(orientation, col++, row);
+ positionPane.add(heading, col++, row);
+ positionPane.add(pitch, col++, row);
+ positionPane.add(roll, col++, row);
+ positionPane.add(new Label(degsLab), col++, row);
+
+
+ positionPane.add(button, col++, row);
+
+ PamVBox holder= new PamVBox();
+ holder.setSpacing(5);
+ holder.getChildren().addAll(loclaiserMethodHolder, positionPane);
+
+ return holder;
+ }
+
+ /**
+ * Enables or disables controls in the orientation pane.
+ */
+ private void enableOrientationPane() {
+ for (int i=0; i=currentOriginMethod.getAllowedInterpolationMethods()) {
+ System.err.println("Streamer setParams: Origin interpolator value of " + currentArray.getOriginInterpolation() + " not allowed for origin method - setting to first allowed method:");
+ interpPane.setSelection(0);
+ }
+ else {
+ interpPane.setSelection(currentArray.getOriginInterpolation());
+ }
+
+ System.out.println("Streamer setParams: selected interp: " + interpPane.getSelectedInterpType());
+
+
+ ArraySensorFieldType[] sensorFields = ArraySensorFieldType.values();
+ for (int i = 0; i < sensorFields.length; i++) {
+ ArrayParameterType fieldType = defaultStreamer.getOrientationTypes(sensorFields[i]);
+ String fieldDataBlock = defaultStreamer.getSensorDataBlocks(sensorFields[i]);
+ sensorComponents[i].setParameterType(fieldType);
+ if (fieldType == ArrayParameterType.SENSOR && fieldDataBlock != null) {
+ sensorComponents[i].setDataBlock(PamController.getInstance().getDataBlockByLongName(fieldDataBlock));
+ }
+ }
+
+ setRecieverLabels() ;
+ enableControls();
+
+ }
+
+ private String orientation2Text(Double ang) {
+ if (ang == null) return String.valueOf(0.0);
+ else return String.format("%3.1f", ang);
+ }
+
+ @Override
+ public String getName() {
+ return "Streamer Pane";
+ }
+
+ @Override
+ public Node getContentNode() {
+ return mainPane;
+ }
+
+ @Override
+ public void paneInitialized() {
+
+ }
+
+ public void setRecieverLabels() {
+ String recieverDepthString = PamController.getInstance().getGlobalMediumManager().getZString();
+
+ depthLabel.setText(recieverDepthString );
+ depthSensorLabel.setText(recieverDepthString + " Sensor");
+
+ }
+
+ private Double getDoubleValue(TextField textField) {
+ String txt = textField.getText();
+ if (txt == null || txt.length() == 0) {
+ return null;
+ }
+ Double val;
+ try {
+ val = Double.valueOf(txt);
+ return val;
+ }
+ catch (NumberFormatException e) {
+ System.err.println("Invalid orientation information: " + txt);
+ return null;
+ }
+ }
+
+ public void setCurrentArray(PamArray currentArray2) {
+ this.currentArray=currentArray2;
+
+ }
+}
diff --git a/src/Array/layoutFX/StreamersPane.java b/src/Array/layoutFX/StreamersPane.java
new file mode 100644
index 00000000..b5adf047
--- /dev/null
+++ b/src/Array/layoutFX/StreamersPane.java
@@ -0,0 +1,315 @@
+package Array.layoutFX;
+
+import java.util.ArrayList;
+
+import Array.PamArray;
+import Array.Streamer;
+import PamController.PamController;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.scene.control.Dialog;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.flipPane.PamFlipPane;
+import pamViewFX.fxNodes.table.TableSettingsPane;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.layout.Pane;
+import javafx.geometry.Insets;
+
+/**
+ * A pane for setting up hydrophones. Note that this is entirely separate from PAMGuard so can be used in
+ * other projects.
+ *
+ * @author Jamie Macaulay
+ *
+ */
+public class StreamersPane extends PamBorderPane {
+
+ BasicArrayTable tableArrayPane;
+
+ ObservableList streamerData = FXCollections.observableArrayList();
+
+ /**
+ * The current hydrophone array
+ */
+ private PamArray currentArray;
+
+ /**
+ * The pam flip pane.
+ */
+ private PamFlipPane pamFlipePane;
+
+ /**
+ * The current streamer data.
+ */
+ private StreamerProperty currentStreamerData;
+
+ /**
+ * Settings pane for a single hydrophone.
+ */
+ private StreamerSettingsPane streamerPane = new StreamerSettingsPane();
+
+ /**
+ * A list of listeners which are called whenever a streamer is added removed or changed.
+ */
+ public ArrayList streamerChangeListeners = new ArrayList();
+
+
+ public StreamersPane() {
+
+ tableArrayPane = new BasicArrayTable(streamerData);
+
+ tableArrayPane.setPadding(new Insets(5,5,5,5));
+ this.setCenter(tableArrayPane);
+
+ pamFlipePane = new PamFlipPane();
+ pamFlipePane.getAdvLabel().setText("Streamer");
+ pamFlipePane.setMaxWidth(Double.MAX_VALUE);
+
+ ((Pane) streamerPane.getContentNode()).setPadding(new Insets(5,5,5,15));
+
+ pamFlipePane.setAdvPaneContent(streamerPane.getContentNode());
+ pamFlipePane.setFrontContent(tableArrayPane);
+
+ pamFlipePane.getFront().setPadding(new Insets(5,5,5,10));
+ pamFlipePane.setAdvLabelEditable(true);
+ pamFlipePane.getPostAdvLabel().setText("Settings");
+
+
+ pamFlipePane.backButtonProperty().addListener((obsval, oldVal, newVal)->{
+
+// System.out.println("Hello back button pressed: " + newVal.intValue());
+
+ //the flip pane
+ if (newVal.intValue()==PamFlipPane.OK_BACK_BUTTON) {
+
+ Streamer streamer = streamerPane.getParams(currentStreamerData.getStreamer());
+
+ if (streamer==null) {
+ //the warning dialog is shown in the streamer settings pane
+ return;
+ }
+
+ streamer.setStreamerName(pamFlipePane.getAdvLabel().getText());
+
+ currentStreamerData.setStreamer(streamer);
+
+ notifyStreamerListeners(currentStreamerData);
+// System.out.println("Update streamer: " + tableArrayPane.getStreamers().indexOf(currentStreamerData) + " no. streamers: " + currentArray.getNumStreamers());
+
+ //need to refresh table to show symbol.
+ tableArrayPane.getTableView().refresh();
+
+ if (streamer != null) {
+ streamer.setupLocator(currentArray);
+ streamer.makeStreamerDataUnit();
+ //update the streamer in the current array
+ }
+ }
+ });
+
+ this.setCenter(pamFlipePane);
+
+ }
+
+ /**
+ * Notify the streamer listeners of a change
+ * @param streamer - the changed streamer
+ */
+ public void notifyStreamerListeners(StreamerProperty streamer) {
+ for (ArrayChangeListener listener: streamerChangeListeners) {
+ listener.arrayChanged(ArrayChangeListener.STREAMER_CHANGE, streamer);
+ }
+ }
+
+ /**
+ * Class which extends TableSettingsPane and creates a sliding pane instead of a dialog when an item is added.
+ * @author Jamie Macaulay
+ *
+ */
+ class BasicArrayTable extends TableSettingsPane {
+
+ private TableColumn z;
+
+
+ public BasicArrayTable(ObservableList data) {
+ super(data);
+ //need to set up all the rows.
+ TableColumn streamerID = new TableColumn("ID");
+ streamerID.setCellValueFactory(cellData -> cellData.getValue().getID());
+ streamerID.setEditable(false);
+
+ TableColumn name = new TableColumn("Name");
+ name.setCellValueFactory(cellData -> cellData.getValue().getName());
+ name.setEditable(true);
+
+
+ TableColumn x = new TableColumn("x");
+ x.setCellValueFactory(cellData -> cellData.getValue().getX());
+ x.setEditable(false);
+
+ TableColumn y = new TableColumn("y");
+ y.setCellValueFactory(cellData -> cellData.getValue().getY());
+ y.setEditable(false);
+
+ z = new TableColumn("depth");
+ z.setCellValueFactory(cellData -> cellData.getValue().getZ().multiply(PamController.getInstance().getGlobalMediumManager().getZCoeff()));
+ z.setEditable(false);
+
+ TableColumn posColumn=new TableColumn("Position (m)");
+ posColumn.getColumns().addAll(x, y, z);
+
+ TableColumn reference = new TableColumn("Reference");
+ reference.setCellValueFactory(cellData -> cellData.getValue().getHydrophoneOrigin());
+ reference.setEditable(true);
+
+ TableColumn locator = new TableColumn("Locator");
+ locator.setCellValueFactory(cellData -> cellData.getValue().getHydrophineLocator());
+ locator.setEditable(true);
+
+ TableColumn geoColumn=new TableColumn("Geo-reference");
+ geoColumn.getColumns().addAll(reference, locator);
+
+
+ getTableView().getColumns().addAll(streamerID, name, posColumn, geoColumn);
+
+ }
+
+ /**
+ * Get the current streamers.
+ * @return the current streamers.
+ */
+ public ObservableList getStreamers() {
+ return getData();
+ }
+
+ @Override
+ public void dialogClosed(StreamerProperty data) {
+ Streamer hydro = streamerPane.getParams(data.getStreamer());
+ data.setStreamer(hydro);
+ }
+
+ @Override
+ public Dialog createSettingsDialog(StreamerProperty data) {
+ //we do not use dialogs here- sliding pane instead.
+ // setClassifierPane(data);
+ // showFlipPane(true);
+ pamFlipePane.flipToBack();
+ return null;
+ }
+
+ @Override
+ public void editData(StreamerProperty data){
+ //edit streamer data.
+ if (data.getName() == null){
+ pamFlipePane.getAdvLabel().setText("Streamer " + data.getID().get());
+ }
+
+ streamerPane.setCurrentArray(currentArray);
+ streamerPane.setParams(data.getStreamer());
+
+ currentStreamerData = data;
+
+ pamFlipePane.flipToBack();
+ }
+
+ @Override
+ public void createNewData(){
+ StreamerProperty newStreamer = createDefaultStreamerProperty();
+ //create a new classifier.
+ streamerData.add(newStreamer);
+ //add to the current array.
+ currentArray.addStreamer(newStreamer.getStreamer());
+ System.out.println("Create new streamer: " + currentArray.getNumStreamers());
+
+ notifyStreamerListeners(newStreamer);
+
+ }
+
+ @Override
+ public void deleteData(StreamerProperty data){
+ super.deleteData(data);
+ notifyStreamerListeners(null);
+ }
+
+ private StreamerProperty createDefaultStreamerProperty() {
+ Streamer streamer = new Streamer(1, 0.,0.,0.,0.,0.,0.);
+ return new StreamerProperty(streamer);
+ }
+
+ public TableColumn getZColumn() {
+ return z;
+ }
+
+
+ }
+
+ /**
+ * Set the parameters for the streamer pane.
+ * @param currentArray - the current array.
+ */
+ public void setParams(PamArray currentArray) {
+
+ this.currentArray=currentArray.clone();
+
+ System.out.println("Set params streamer: " + currentArray.getNumStreamers());
+
+ tableArrayPane.getStreamers().clear();
+
+ for (int i=0; itableArrayPane.getStreamers().size()) {
+ currParams.removeStreamer(currParams.getStreamerCount()-1);
+ }
+
+// currentArray.updateStreamer(tableArrayPane.getStreamers().indexOf(currentStreamerData), streamer);
+
+ return currParams;
+ }
+
+ public void setRecieverLabels() {
+ tableArrayPane.getZColumn().setText(PamController.getInstance().getGlobalMediumManager().getZString());
+ streamerPane.setRecieverLabels();
+ }
+
+ public TableView getStreamerTable() {
+ return tableArrayPane.getTableView();
+ }
+
+ /**
+ * Add a listener which is called whenever a streamer is added, removed or changed.
+ * @param e - the listener to add
+ */
+ public void addStreamerListener(ArrayChangeListener e) {
+ this.streamerChangeListeners.add(e);
+ }
+
+ public void setCurrentArray(PamArray currentArray) {
+ this.currentArray=currentArray;
+
+ }
+
+
+}
diff --git a/src/Array/streamerOrigin/OriginDialogComponent.java b/src/Array/streamerOrigin/OriginDialogComponent.java
index f6ab058b..26dbcb79 100644
--- a/src/Array/streamerOrigin/OriginDialogComponent.java
+++ b/src/Array/streamerOrigin/OriginDialogComponent.java
@@ -1,7 +1,15 @@
package Array.streamerOrigin;
import PamView.dialog.DialogComponent;
+import javafx.scene.layout.Pane;
public abstract class OriginDialogComponent implements DialogComponent{
+ /**
+ * Get a JavaFX pane for the origin method.
+ * @return the JavaFX pane.
+ */
+ public abstract Pane getSettingsPane();
+
+
}
diff --git a/src/Array/streamerOrigin/StaticHydrophonePane.java b/src/Array/streamerOrigin/StaticHydrophonePane.java
new file mode 100644
index 00000000..fc85a583
--- /dev/null
+++ b/src/Array/streamerOrigin/StaticHydrophonePane.java
@@ -0,0 +1,97 @@
+package Array.streamerOrigin;
+
+import GPS.GpsData;
+import GPS.GpsDataUnit;
+import PamUtils.LatLong;
+import javafx.scene.control.Label;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.utilityPanes.LatLongPane;
+
+/**
+ * JavaFX settings pane for a static hydrophones.
+ */
+public class StaticHydrophonePane extends PamBorderPane {
+
+ /**
+ * Reference to static origin mwthod.
+ */
+ private StaticOriginMethod staticOriginMethod;
+
+ LatLongPane latLongPane;
+
+ public StaticHydrophonePane(StaticOriginMethod staticOriginMethod) {
+
+ this.staticOriginMethod=staticOriginMethod;
+
+ latLongPane = new LatLongPane("Static streamer position");
+ this.setCenter(latLongPane.getContentNode());
+
+ }
+
+
+ public void setParams() {
+ GpsDataUnit dataUnit = getStaticOriginSettings().getStaticPosition();
+ if (dataUnit == null) {
+ setLatLong(null);
+ }
+ else {
+ GpsData gpsData = dataUnit.getGpsData();
+ setLatLong(gpsData);
+ }
+
+// if (gpsData == null) {
+// return;
+// }
+// else {
+// setLatLong(gpsData);
+// }
+
+ }
+
+ private StaticOriginSettings getStaticOriginSettings() {
+ return ((StaticOriginSettings) staticOriginMethod.getOriginSettings());
+ }
+
+
+ public boolean getParams() {
+
+ LatLong latLong = latLongPane.getParams(null);
+
+ if (latLong==null) {
+ System.err.println("StaticHydrophonePane: latitude and longitude is null");
+ return false;
+ }
+
+ if (getStaticOriginSettings()==null) {
+ System.err.println("StaticHydrophonePane: static origin is null");
+ return false;
+ }
+
+ //set
+ getStaticOriginSettings().setStaticPosition(staticOriginMethod.getStreamer(), new GpsData(latLong));
+//
+// boolean ok = getStaticOriginSettings()!= null && getStaticOriginSettings() .getStaticPosition() != null;
+//
+// System.out.println("StaticHydrophonePane: Get params from static origin 1 : " + getStaticOriginSettings());
+//
+// System.out.println("StaticHydrophonePane: Get params from static origin 2: " + getStaticOriginSettings() .getStaticPosition());
+
+ return true;
+ }
+
+ /**
+ * Just set the lat long without resetting the heading.
+ * @param latLong
+ */
+ private void setLatLong(LatLong latLong) {
+ if (latLong==null) {
+ //create a default latitude and longitude - Rockall (why not).
+ LatLong latLongdefault = new LatLong();
+ latLongdefault.setLatitude(57.595833333333);
+ latLongdefault.setLongitude(-13.686944444444);
+ latLongPane.setParams(latLongdefault);
+ }
+ else latLongPane.setParams(latLong);
+ }
+
+}
diff --git a/src/Array/streamerOrigin/StaticOriginMethod.java b/src/Array/streamerOrigin/StaticOriginMethod.java
index 8c413c9c..4f42c922 100644
--- a/src/Array/streamerOrigin/StaticOriginMethod.java
+++ b/src/Array/streamerOrigin/StaticOriginMethod.java
@@ -29,10 +29,11 @@ import PamUtils.LatLongDialog;
import PamUtils.PamCalendar;
import PamView.dialog.PamDialog;
import PamView.dialog.PamGridBagContraints;
+import javafx.scene.layout.Pane;
public class StaticOriginMethod extends HydrophoneOriginMethod {
- private StaticHydrophoneDialogComponent staticHydrophoneDialogComponent;
+ private StaticHydrophoneComponent staticHydrophoneDialogComponent;
private StaticOriginSettings staticOriginSettings = new StaticOriginSettings();
@@ -48,12 +49,107 @@ public class StaticOriginMethod extends HydrophoneOriginMethod {
@Override
public OriginDialogComponent getDialogComponent() {
if (staticHydrophoneDialogComponent == null) {
- staticHydrophoneDialogComponent = new StaticHydrophoneDialogComponent();
+ staticHydrophoneDialogComponent = new StaticHydrophoneComponent();
}
return staticHydrophoneDialogComponent;
}
+ @Override
+ public OriginSettings getOriginSettings() {
+ return staticOriginSettings;
+ }
+
+ @Override
+ public void setOriginSettings(OriginSettings originSettings) {
+ staticOriginSettings = (StaticOriginSettings) originSettings;
+ }
+
+ @Override
+ public boolean prepare() {
+ return true;
+ }
+
+ @Override
+ public StreamerDataUnit getLastStreamerData() {
+ StreamerDataBlock streamerDataBlock = ArrayManager.getArrayManager().getStreamerDatabBlock();
+ StreamerDataUnit sdu = streamerDataBlock.getLastUnit(1< {
public String getToolTipText();
/**
- * The type of localisation information the localizer can accept. e.g. bearings, time delays etc. The types are
+ * The type of localisation information the localiser can accept. e.g. bearings, time delays etc. The types are
* defined in the AbstractLocalisation class.
* @return integer bitmap of the type of localisation information the localiser can use.
*/
@@ -35,20 +35,20 @@ public interface LocaliserModel {
/**
* Get the settings pane for the localiser. Allows users to change localiser settings.
- * @return the settings pane for the loclaiser.
+ * @return the settings pane for the localiser.
*/
- public LocaliserPane> getSettingsPane();
+ public LocaliserPane> getAlgorithmSettingsPane();
/**
- * True if the model has paramaters to set. If has the loclaiser has a settings pane it will have
+ * True if the model has parameters to set. If has the localiser has a settings pane it will have
* parameters. This generally puts an extra button onto a display panel.
*/
public boolean hasParams();
/**
* Run the localisation model. Once completed the results are added to the AbstractLoclaisation class of the input PamDataUnit.
- * Note that algorithms may run on a separate thread. Once processing has finished the notifyModelFinished function is called with
+ *Note that algorithms may run on a separate thread. Once processing has finished the notifyModelFinished function is called with
* a progress of 1;.
* @param pamDataUnit the pamDataUnit. This can be a super unit if multiple detections are required.
* @param addLoc automatically add the localisation result to the data unit, replacing it's current localisation info.
@@ -56,7 +56,7 @@ public interface LocaliserModel {
public AbstractLocalisation runModel(T pamDataUnit, DetectionGroupOptions detectionGroupOptions, boolean addLoc);
/**
- * This should be called whenever the localiser has finished processing and, if the loclaisation process is long, then updates progress.
+ * This should be called whenever the localiser has finished processing and, if the localisation process is long, then updates progress.
*/
public void notifyModelProgress(double progress);
diff --git a/src/Localiser/LocaliserPane.java b/src/Localiser/LocaliserPane.java
index 4ca335cf..e275a3f8 100644
--- a/src/Localiser/LocaliserPane.java
+++ b/src/Localiser/LocaliserPane.java
@@ -1,5 +1,17 @@
package Localiser;
-public interface LocaliserPane {
+import PamController.SettingsPane;
+
+public abstract class LocaliserPane extends SettingsPane {
+
+ public LocaliserPane() {
+ super(null);
+ // TODO Auto-generated constructor stub
+ }
+
+
+
+
+
}
diff --git a/src/Localiser/ModelControlPanel.java b/src/Localiser/ModelControlPanel.java
index 21172a14..2b63bfa6 100644
--- a/src/Localiser/ModelControlPanel.java
+++ b/src/Localiser/ModelControlPanel.java
@@ -152,8 +152,7 @@ public class ModelControlPanel {
@Override
//settings panel
public void actionPerformed(ActionEvent arg0) {
- model.getSettingsPane();
-
+ model.getAlgorithmSettingsPane();
//AWT implementation.
}
}
diff --git a/src/Localiser/algorithms/Correlations.java b/src/Localiser/algorithms/Correlations.java
index 7b726338..294ad138 100644
--- a/src/Localiser/algorithms/Correlations.java
+++ b/src/Localiser/algorithms/Correlations.java
@@ -258,6 +258,8 @@ public class Correlations {
correlationValue = newPeak[1];
return newPeak[0];
}
+
+
/**
* Measure the time delay between pulses on two channels. Inputs in this case are the
* spectrum data (most of the cross correlation is done in the frequency domain)
diff --git a/src/Localiser/algorithms/genericLocaliser/Chi2TimeDelays.java b/src/Localiser/algorithms/genericLocaliser/Chi2TimeDelays.java
index 093d8fd7..c757c009 100644
--- a/src/Localiser/algorithms/genericLocaliser/Chi2TimeDelays.java
+++ b/src/Localiser/algorithms/genericLocaliser/Chi2TimeDelays.java
@@ -185,7 +185,7 @@ public class Chi2TimeDelays implements MinimisationFunction {
}
/**
- * Set the time delays. Each row is a set fo delays from N synchronised hydrophones. Different rows
+ * Set the time delays. Each row is a set for delays from N synchronised hydrophones. Different rows
* can have different numbers of synchronised hydrophones.
* @param timeDelays - a set of time delays in seconds.
*/
diff --git a/src/Localiser/algorithms/genericLocaliser/MCMC/MCMC.java b/src/Localiser/algorithms/genericLocaliser/MCMC/MCMC.java
index a1ebc80b..1413e943 100644
--- a/src/Localiser/algorithms/genericLocaliser/MCMC/MCMC.java
+++ b/src/Localiser/algorithms/genericLocaliser/MCMC/MCMC.java
@@ -18,17 +18,19 @@ import PamUtils.CoordUtils;
import org.apache.commons.math3.ml.clustering.Cluster;
import org.apache.commons.math3.ml.clustering.DoublePoint;
import org.apache.commons.math3.ml.clustering.KMeansPlusPlusClusterer;
+
+
/**
* Markov chain Monte Carlo (MCMC) is a minimisation technique used widely in a variety of field, from finding exo planets,
* to solving complex intergals.
*
-* This is an advanced and highly computationally intensive localisation algorithm based on MCMC methods. For a good description see;
+* This is a highly computationally intensive localisation algorithm based on MCMC methods. For a good description see;
* The Transit Light Curve (TLC) Project.I. Four Consecutive Transits of the Exoplanet XO-1b Matthew J. Holman1
*
-* This is an abstract class and requires a chi2 function to operate.
+* A chi2 function is required to define the minimisation problem.
*
-* Multiple MCMC chains can and should be run. These are executed on different threads to take advantage of multi-core processing as much as possible.
-* Even so a large number of chains or large observation set can result in significant processing times.
+* Multiple MCMC chains can and should be run. These are executed on different threads to take advantage of multi-core processing if possible.
+* Even so, a large number of chains or large observation set can result in significant processing times.
*
* Results are analysed for convergence and final locations packed into an MCMCTDResults class.
*
@@ -117,7 +119,7 @@ public class MCMC implements MinimisationAlgorithm {
double newChi;
ArrayList successChi=new ArrayList(settings.numberOfJumps/5);
- ArrayList successJump=new ArrayList(settings.numberOfJumps/5);
+ ArrayList successJump=new ArrayList(settings.numberOfJumps/5);
// System.out.println("Start MCMC milliseconds: "+ System.currentTimeMillis());
@@ -143,7 +145,7 @@ public class MCMC implements MinimisationAlgorithm {
chainPos=potentialNewJump;
currentChi=newChi;
successChi.add(newChi);
- successJump.add(chainPos);
+ successJump.add(PamArrayUtils.double2Float(chainPos));
//System.out.println(ChainPos);
//System.out.println(NewChi);
//System.out.println(ObservedTimeDelays);
@@ -153,7 +155,7 @@ public class MCMC implements MinimisationAlgorithm {
chainPos=potentialNewJump;
currentChi=newChi;
successChi.add(newChi);
- successJump.add(chainPos);
+ successJump.add(PamArrayUtils.double2Float(chainPos));
//System.out.println(ChainPos);
//System.out.println(NewChi);
//System.out.println(ObservedTimeDelays);
@@ -164,7 +166,7 @@ public class MCMC implements MinimisationAlgorithm {
ChainResult chainResult=new ChainResult(successJump, successChi);
chainResult= analyseChain( chainResult);
- chainResult.nDim=this.chi2.getDim();
+ chainResult.nDim=chi2.getDim();
// System.out.println("Chain results is: " + chainResult.mean[0] + " " + chainResult.mean[1] + " " + chainResult.mean[2]);
// System.out.println("End MCMC millis: "+ System.currentTimeMillis());
@@ -184,7 +186,7 @@ public class MCMC implements MinimisationAlgorithm {
* @param successJump - list of successful jumps
* @param successChi - list of successful chi2 values.
*/
- public ChainResult(ArrayList successJump, ArrayList successChi) {
+ public ChainResult(ArrayList successJump, ArrayList successChi) {
this.successJump=successJump;
this.successChi=successChi;
}
@@ -197,7 +199,7 @@ public class MCMC implements MinimisationAlgorithm {
/**
* A list of points of the successful jumps.
*/
- public ArrayList successJump;
+ public ArrayList successJump;
/**
* The number of dimensions.
@@ -584,7 +586,7 @@ public class MCMC implements MinimisationAlgorithm {
//find min value
int minIndex = chainResult.successChi.indexOf(Collections.min(chainResult.successChi));
minChi2=chainResult.successChi.get(minIndex);
- minChi2Pos=chainResult.successJump.get(minIndex);
+ minChi2Pos=PamArrayUtils.float2Double(chainResult.successJump.get(minIndex));
break;
}
@@ -728,19 +730,19 @@ public class MCMC implements MinimisationAlgorithm {
*/
private EllipticalError getLocError(ArrayList data) {
- ArrayList successJumpAll = new ArrayList();
- List successJump;
+ ArrayList successJumpAll = new ArrayList();
+ List successJump;
for (int i=0; i> getJumps() {
ArrayList> jumps=new ArrayList>();
ArrayList chainJumps;
- double[] ajump;
+ float[] ajump;
for (int i=0; i();
for (int j=0; j0) return null;
+
+ if (errors2D==null) return null;
- //System.out.println("EllipseLocErrorDraw: draw ellipse:"+errors2D[0]+" "+errors2D[1]+" "+Math.toDegrees(errors2D[2]));
+
+ if (errors2D[0] > PamConstants.EARTH_RADIUS_METERS || errors2D[1] > PamConstants.EARTH_RADIUS_METERS) {
+ return null; //don't draw infintie stuff - causes nasty errors.
+ }
+// System.out.println("Draw ovals on map");
+// System.out.println("EllipseLocErrorDraw: draw ellipse:"+errors2D[0]+" "+errors2D[1]+" "+Math.toDegrees(errors2D[2]));
//System.out.println("Plot errors: perp: "+ perpError+ " horz: "+horzError+ " " + errorDirection);
Graphics2D g2d = (Graphics2D)g;
- if (errors2D==null) return null;
-
//draw oval
// //need to work out the size of the horizontal error.
// perpError=Math.max(perpError, 100);
@@ -140,7 +156,7 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
//draw the ellipse and rotate.
Ellipse2D oval=new Ellipse2D.Double(errorOriginXY.getX()-horzErrPix/2, errorOriginXY.getY()-perpErrPix/2, horzErrPix, perpErrPix);
- g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 5 * 0.1f));
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 5 * 0.05f));
g2d.setPaint(ellipseColor.brighter());
if (!Double.isNaN(errorDirection)) g2d.rotate(-paintAngle, errorOriginXY.getX(), errorOriginXY.getY());
@@ -158,4 +174,8 @@ public class EllipseLocErrorDraw implements LocErrorGraphics {
}
+ public int getDrawType() {
+ return drawType;
+ }
+
}
diff --git a/src/Localiser/algorithms/locErrors/EllipticalError.java b/src/Localiser/algorithms/locErrors/EllipticalError.java
index 501cbeb2..9fc25df5 100644
--- a/src/Localiser/algorithms/locErrors/EllipticalError.java
+++ b/src/Localiser/algorithms/locErrors/EllipticalError.java
@@ -51,6 +51,8 @@ public class EllipticalError implements LocaliserError {
errorEllipse = new ErrorEllipse(errors, angles);
}
+
+
@Override
public double getError(PamVector errorDirection) {
return errorEllipse.getErrorMagnitude(errorDirection.getUnitVector().getVector());
@@ -78,7 +80,7 @@ public class EllipticalError implements LocaliserError {
/**
* Get the 2D elliptical error.
- * @param planeXy - the plane on whihc to find the ellipse for.
+ * @param planeXy - the plane on which to find the ellipse for.
* @return the elliptical error.
*/
public double[] getErrorEllipse2D(int planeXy) {
@@ -111,6 +113,9 @@ public class EllipticalError implements LocaliserError {
@Override
public String getStringResult() {
String description="";
+ if (errorEllipse==null) {
+ return "Elliptical error is null";
+ }
if (!errorEllipse.is3D()){
description+=String.format("&ensp 2D Elliptical error: &ensp Radii: ");
for (int i=0; imax){
max=curvatureError;
ind=i; //record index of max value;
}
}
- double[] dim={max, getLLCurvature(chi2, point, PamVector.fromHeadAndSlant(Math.toDegrees(angleBin*ind)+90, 0)),-1 };
+ double[] dim={max, getLLCurvature(point, PamVector.fromHeadAndSlant(Math.toDegrees(angleBin*ind)+90, 0)),-1 };
double[] angles={angleBin*ind, 0,0};
for (int i=0; imax){
max=curvatureError;
@@ -171,7 +171,7 @@ public class LikilihoodError extends EllipticalError {
Vector3D location3D=plane.getPointAt(vector2D, 0);
// get the max error in this plane.
- curvatureError=getLLCurvature(chi2, point, new PamVector(location3D.toArray()));
+ curvatureError=getLLCurvature(point, new PamVector(location3D.toArray()));
if (curvatureError>maxPlane){
maxPlane=curvatureError;
indPlane=n; //record index of max value;
@@ -203,7 +203,7 @@ public class LikilihoodError extends EllipticalError {
ArrayList vectors=new ArrayList();
vectors.add(firstEigenvector.scalarMultiply(max)); //have already calculated error in previous steps.
vectors.add(secondVector.scalarMultiply(maxPlane)); //have already calculated error in previous steps.
- vectors.add(thirdVector.scalarMultiply(getLLCurvature( chi2, point, new PamVector(thirdVector.toArray()))));
+ vectors.add(thirdVector.scalarMultiply(getLLCurvature( point, new PamVector(thirdVector.toArray()))));
//create an error ellipse.
ErrorEllipse errorEllipse=new ErrorEllipse(vectors);
@@ -240,7 +240,7 @@ public class LikilihoodError extends EllipticalError {
* direction specified and in the opposite direction. Curvature is expressed as 1 standard deviation
* error
*/
- private double getLLCurvature(MinimisationFunction chi2, double[] point, PamVector errorVector) {
+ private double getLLCurvature(double[] point, PamVector errorVector) {
double dis = 10; //the jump along the chi2 surface.
double err = 0;
diff --git a/src/Localiser/algorithms/locErrors/SimpleError.java b/src/Localiser/algorithms/locErrors/SimpleError.java
index 02b64d88..2b00cb4a 100644
--- a/src/Localiser/algorithms/locErrors/SimpleError.java
+++ b/src/Localiser/algorithms/locErrors/SimpleError.java
@@ -42,10 +42,7 @@ public class SimpleError implements LocaliserError {
* @param xyzError - an array of the x/perpindicular y/parallel and z error in meters {x y z}
*/
public SimpleError(Double xyzError[]) {
- simpleErrorDraw=new SimpleLocErrorDraw(this);
- perpindiuclarError=xyzError[0];
- parallelError=xyzError[1];
- zError=xyzError[2];
+ this(xyzError, 0.);
}
/**
diff --git a/src/Localiser/algorithms/locErrors/SimpleErrorXMLData.java b/src/Localiser/algorithms/locErrors/SimpleErrorJSONData.java
similarity index 78%
rename from src/Localiser/algorithms/locErrors/SimpleErrorXMLData.java
rename to src/Localiser/algorithms/locErrors/SimpleErrorJSONData.java
index b2942829..afffd260 100644
--- a/src/Localiser/algorithms/locErrors/SimpleErrorXMLData.java
+++ b/src/Localiser/algorithms/locErrors/SimpleErrorJSONData.java
@@ -1,14 +1,13 @@
package Localiser.algorithms.locErrors;
-import java.text.DecimalFormat;
-public class SimpleErrorXMLData extends ErrorXMLData {
+public class SimpleErrorJSONData extends ErrorJSONData {
private String errorType;
private double[] errorData;
- public SimpleErrorXMLData(String errorType, double[] errorData) {
+ public SimpleErrorJSONData(String errorType, double[] errorData) {
this.errorType = errorType;
this.errorData = errorData;
}
diff --git a/src/Localiser/algorithms/locErrors/SimpleLocErrorDraw.java b/src/Localiser/algorithms/locErrors/SimpleLocErrorDraw.java
index 48c433be..148177ee 100644
--- a/src/Localiser/algorithms/locErrors/SimpleLocErrorDraw.java
+++ b/src/Localiser/algorithms/locErrors/SimpleLocErrorDraw.java
@@ -27,6 +27,7 @@ public class SimpleLocErrorDraw implements LocErrorGraphics {
@Override
public TransformShape drawOnMap(Graphics g, PamDataUnit pamDetection, LatLong errorOrigin,
GeneralProjector generalProjector, Color ellipseColor) {
+
g.setColor(ellipseColor);
if (simpleError == null) {
return null;
diff --git a/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/Hyperbolic.java b/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/Hyperbolic.java
index 6aa2eaf7..4875aefa 100644
--- a/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/Hyperbolic.java
+++ b/src/Localiser/algorithms/timeDelayLocalisers/hyperbolic/Hyperbolic.java
@@ -17,6 +17,7 @@ import PamUtils.PamUtils;
*
* The hyperbolic localiser also includes an error estimation by sampling time delays from a distribution of errors. As a localisation has to
* occur for each sample, this drastically increases the computational time for the hyperbolic localiser.
+ *
* @author Jamie Macaulay
*
*/
@@ -62,7 +63,7 @@ public class Hyperbolic implements TimeDelayLocaliserModel {
* @param timeDelays - time delay values in seconds. Each is a list of time delays using to indexM1 and indexM2 conventions and corresponding to hydrophones in hydrophoneArray list.
* @param timeDelayErrors - time delay error values in seconds. Each is a list of time delay errors using to indexM1 and indexM2 conventions and corresponding to hydrophones in hydrophoneArray list.
* @param speedOfSound - the speed of sound in m/s
- * @param hyperbolicParams - hyperbolic paramaters to use for this instance of the localiser.
+ * @param hyperbolicParams - hyperbolic parameters to use for this instance of the localiser.
*/
public Hyperbolic(ArrayList> hydrophoneArray ,ArrayList> timeDelays, ArrayList< ArrayList> timeDelayErrors, float speedOfSound, HyperbolicParams hyperbolicParams){
this.speedOfSound=speedOfSound;
diff --git a/src/Localiser/controls/MCMCPane.java b/src/Localiser/controls/MCMCPane.java
new file mode 100644
index 00000000..8674a419
--- /dev/null
+++ b/src/Localiser/controls/MCMCPane.java
@@ -0,0 +1,305 @@
+package Localiser.controls;
+
+import Localiser.algorithms.genericLocaliser.MCMC.MCMCParams2;
+import PamController.SettingsPane;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.control.Spinner;
+import javafx.scene.control.ComboBox;
+
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Pane;
+import javafx.scene.text.Font;
+import javafx.scene.text.FontWeight;
+import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxNodes.PamGridPane;
+import pamViewFX.fxNodes.PamHBox;
+import pamViewFX.fxNodes.PamSpinner;
+import pamViewFX.fxNodes.PamVBox;
+
+public class MCMCPane extends SettingsPane {
+
+ private PamBorderPane mainPane;
+
+ private double JUMP_SPINNER_WIDTH = 60;
+
+
+ //controls
+ private PamSpinner numJumps;
+
+
+ private PamSpinner jumpXSpinner;
+ private PamSpinner jumpYSpinner;
+ private PamSpinner jumpZSpinner;
+
+ private PamSpinner startDispersion;
+ private PamSpinner numChains;
+ private ComboBox clustering;
+ private PamSpinner numkMeans;
+ private PamSpinner maxClustDist;
+
+ public MCMCPane() {
+ super(null);
+ mainPane = new PamBorderPane();
+ mainPane.setTop(createMCMCPane());
+
+ }
+
+ private Pane createMCMCPane() {
+ PamVBox vBox = new PamVBox();
+
+ PamGridPane gridPane = new PamGridPane();
+ gridPane.setHgap(5);
+ gridPane.setVgap(5);
+
+ int row = 0;
+ int col = 0;
+
+ Label chainTitleLabel = new Label("Markov chain settings");
+// PamGuiManagerFX.titleFont2style(chainTitleLabel);
+ chainTitleLabel.setFont(Font.font(null,FontWeight.BOLD, 11));
+
+ gridPane.add(chainTitleLabel, col, row);
+ GridPane.setColumnSpan(chainTitleLabel, 7);
+ row++;
+
+
+ col=0;
+ PamHBox chainHolder = new PamHBox();
+ chainHolder.setSpacing(5);
+ chainHolder.setAlignment(Pos.CENTER_LEFT);
+
+ Label label3 = new Label("Start");
+ label3.setAlignment(Pos.CENTER_RIGHT);
+ gridPane.add(label3, col, row);
+ col++;
+
+ chainHolder.getChildren().add(numChains = new PamSpinner(1,Integer.MAX_VALUE, 20, 1));
+ numChains.setEditable(true);
+ numChains.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ numChains.setMaxWidth(JUMP_SPINNER_WIDTH);
+
+ chainHolder.getChildren().add(new Label("chains seperated by"));
+
+ chainHolder.getChildren().add(startDispersion = new PamSpinner(0.,Double.MAX_VALUE, 100., 1.));
+ startDispersion.setEditable(true);
+ startDispersion.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ startDispersion.setMaxWidth(JUMP_SPINNER_WIDTH+10);
+
+ chainHolder.getChildren().add(new Label("m"));
+
+ gridPane.add(chainHolder, col, row);
+ GridPane.setColumnSpan(chainHolder, 7);
+
+ row++;
+ col=0;
+
+
+ //chain propertires
+
+ Label label = new Label("No. jumps");
+ label.setAlignment(Pos.CENTER_RIGHT);
+
+ gridPane.add(label, col, row);
+ col++;
+ gridPane.add(numJumps = new PamSpinner(10,Integer.MAX_VALUE, 2500000, 10000), col, row);
+ numJumps.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ GridPane.setColumnSpan(numJumps, 3);
+ numJumps.setEditable(true);
+ //mcmJumpSpinner.setMaxWidth(JUMP_SPINNER_WIDTH*2);
+
+ col+=col+2;
+ Label chainLabel = new Label("per chain");
+ gridPane.add(chainLabel, col, row);
+ GridPane.setColumnSpan(chainLabel, 3);
+
+ row++;
+ col=0;
+ Label label2 = new Label("Jump size x");
+ label2.setAlignment(Pos.CENTER_RIGHT);
+
+ gridPane.add(label2, col, row);
+ col++;
+
+
+ gridPane.add(jumpXSpinner = new PamSpinner(0.,Double.MAX_VALUE, 1., 0.5), col, row);
+ jumpXSpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ jumpXSpinner.setMaxWidth(JUMP_SPINNER_WIDTH);
+ jumpXSpinner.setEditable(true);
+ col++;
+
+ gridPane.add(new Label("y"), col, row);
+ col++;
+
+ gridPane.add(jumpYSpinner = new PamSpinner(0.,Double.MAX_VALUE, 1., 0.5), col, row);
+ jumpYSpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ jumpYSpinner.setMaxWidth(JUMP_SPINNER_WIDTH);
+ jumpYSpinner.setEditable(true);
+ col++;
+
+ gridPane.add(new Label("z"), col, row);
+ col++;
+
+ gridPane.add(jumpZSpinner = new PamSpinner(0.,Double.MAX_VALUE, 1., 0.5), col, row);
+ jumpZSpinner.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ jumpZSpinner.setMaxWidth(JUMP_SPINNER_WIDTH);
+ jumpZSpinner.setEditable(true);
+ col++;
+
+ gridPane.add(new Label("m"), col, row);
+ row++;
+ col=0;
+
+
+
+ //chain clustering
+ Label clusterTitleLabel = new Label("Result clustering");
+ //PamGuiManagerFX.titleFont2style(clusterTitleLabel);
+ clusterTitleLabel.setFont(Font.font(null,FontWeight.BOLD, 11));
+
+ gridPane.add(clusterTitleLabel, col, row);
+ GridPane.setColumnSpan(clusterTitleLabel, 7);
+ row++;
+
+
+ row++;
+ col=0;
+ Label label5 = new Label("Clustering");
+ label5.setAlignment(Pos.CENTER_RIGHT);
+ gridPane.add(label5, col, row);
+ col++;
+ clustering = new ComboBox();
+ clustering.getItems().addAll("None", "kMeans");
+ clustering.getSelectionModel().select(1);
+ gridPane.add(clustering, col, row);
+
+ GridPane.setColumnSpan(clustering, 3);
+
+ clustering.setOnAction((action)->{
+ enableControls();
+ });
+
+
+ row++;
+ col=0;
+
+
+ //kmeans settings - TODO - would be better to have a custom pane for each clustering algorithm
+ //but not worth the effort until more clustering algorithms are implemented.
+ Label label6 = new Label("Start");
+ label6.setAlignment(Pos.CENTER_RIGHT);
+ gridPane.add(label6, col, row);
+ col++;
+
+
+ PamHBox kMeansHolder = new PamHBox();
+ kMeansHolder.setSpacing(5);
+ kMeansHolder.setAlignment(Pos.CENTER_LEFT);
+
+ kMeansHolder.getChildren().add(numkMeans = new PamSpinner(1,Integer.MAX_VALUE, 20, 1));
+ numkMeans.setEditable(true);
+ numkMeans.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ numkMeans.setMaxWidth(JUMP_SPINNER_WIDTH);
+
+
+ kMeansHolder.getChildren().add(new Label("k-means and merge at <"));
+ kMeansHolder.getChildren().add(maxClustDist = new PamSpinner(0.,Double.MAX_VALUE, 5., 1));
+ maxClustDist.setEditable(true);
+ maxClustDist.getStyleClass().add(Spinner.STYLE_CLASS_SPLIT_ARROWS_HORIZONTAL);
+ maxClustDist.setMaxWidth(JUMP_SPINNER_WIDTH);
+ kMeansHolder.getChildren().add(new Label("m"));
+
+ gridPane.add(kMeansHolder, col, row);
+ GridPane.setColumnSpan(kMeansHolder, 7);
+
+ vBox.getChildren().add(gridPane);
+
+ enableControls();
+
+ return vBox;
+ }
+
+ private void enableControls() {
+ //clustering
+ numkMeans.setDisable(true);
+ maxClustDist.setDisable(true);
+ switch (clustering.getSelectionModel().getSelectedIndex()) {
+ case MCMCParams2.K_MEANS:
+ numkMeans.setDisable(false);
+ maxClustDist.setDisable(false);
+ break;
+ case MCMCParams2.NONE:
+ break;
+ }
+ }
+
+ @Override
+ public MCMCParams2 getParams(MCMCParams2 currParams) {
+
+ //chain settings.
+ currParams.numberOfChains = numChains.getValue();
+ currParams.numberOfJumps = numJumps.getValue();
+
+ double[] jumpSize = new double[3];
+
+ jumpSize[0] = jumpXSpinner.getValue();
+ jumpSize[1] = jumpYSpinner.getValue();
+ jumpSize[2] = jumpZSpinner.getValue();
+
+ currParams.jumpSize = jumpSize;
+
+ //bit messy but works...
+ currParams.setChainDispersion(startDispersion.getValue(), 3);
+
+ //cluster settings
+ currParams.clusterAnalysis = clustering.getSelectionModel().getSelectedIndex();
+ currParams.kmeanAttempts = numkMeans.getValue();
+ currParams.maxClusterSize = maxClustDist.getValue();
+
+ return currParams;
+ }
+
+ @Override
+ public void setParams(MCMCParams2 currParams) {
+
+ //chain settings.
+ numJumps.getValueFactory().setValue(currParams.numberOfJumps);
+
+ jumpXSpinner.getValueFactory().setValue(currParams.jumpSize[0]);
+ jumpYSpinner.getValueFactory().setValue(currParams.jumpSize[1]);
+ jumpZSpinner.getValueFactory().setValue(currParams.jumpSize[2]);
+
+ numChains.getValueFactory().setValue(currParams.numberOfChains);
+
+ //bit messy but works...
+ startDispersion.getValueFactory().setValue(Math.abs(currParams.chainStartDispersion[0][0]));
+
+
+ //cluster settings
+ clustering.getSelectionModel().select(currParams.clusterAnalysis);
+ numkMeans.getValueFactory().setValue(currParams.kmeanAttempts);
+ maxClustDist.getValueFactory().setValue(currParams.maxClusterSize);
+
+ //enable the controls.
+ enableControls();
+ }
+
+ @Override
+ public String getName() {
+ return "MCMC Settings";
+ }
+
+ @Override
+ public Node getContentNode() {
+ return mainPane;
+ }
+
+ @Override
+ public void paneInitialized() {
+ // TODO Auto-generated method stub
+
+ }
+
+
+}
diff --git a/src/Localiser/detectionGroupLocaliser/DetectionGroupLocaliser2.java b/src/Localiser/detectionGroupLocaliser/DetectionGroupLocaliser2.java
index 1420233f..964d83ef 100644
--- a/src/Localiser/detectionGroupLocaliser/DetectionGroupLocaliser2.java
+++ b/src/Localiser/detectionGroupLocaliser/DetectionGroupLocaliser2.java
@@ -132,7 +132,7 @@ public class DetectionGroupLocaliser2 implements Local
}
@Override
- public LocaliserPane getSettingsPane() {
+ public LocaliserPane getAlgorithmSettingsPane() {
return locAlgorithm.getSettingsPane();
}
diff --git a/src/Localiser/detectionGroupLocaliser/GroupLocResult.java b/src/Localiser/detectionGroupLocaliser/GroupLocResult.java
index 2b6b1c24..4b361768 100644
--- a/src/Localiser/detectionGroupLocaliser/GroupLocResult.java
+++ b/src/Localiser/detectionGroupLocaliser/GroupLocResult.java
@@ -16,6 +16,7 @@ import targetMotionOld.TargetMotionModel;
*
* Result class for the a group localiser. Usually this will be a target motion localisation, however could also be a group of DIFAR buoys
* or other systems which uses a set of detections to localise animals.
+ *
* @author Doug Gillespie
*
*/
@@ -75,8 +76,6 @@ public class GroupLocResult implements Comparable, LocalisationC
*/
private int dim=3;
- private ArrayList> MCMCJumpResults;
-
/**
* @param latLong
* @param chi2
@@ -132,16 +131,7 @@ public class GroupLocResult implements Comparable, LocalisationC
return side;
}
- /**Not the correct place to store**/
- @Deprecated
- public void setMCMCJumps(ArrayList> MCMCResults){
- this.MCMCJumpResults=MCMCResults;
- }
- @Deprecated
- public ArrayList> getMCMCJumps(){
- return MCMCJumpResults;
- }
/**
diff --git a/src/Map/MapDetectionsDialog.java b/src/Map/MapDetectionsDialog.java
index bb85bdb9..1a9b100b 100644
--- a/src/Map/MapDetectionsDialog.java
+++ b/src/Map/MapDetectionsDialog.java
@@ -1,6 +1,7 @@
package Map;
import java.awt.BorderLayout;
+import java.awt.Color;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@@ -16,6 +17,9 @@ import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
+import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
+import org.kordamp.ikonli.swing.FontIcon;
+
import PamController.PamController;
import PamView.dialog.PamDialog;
import PamguardMVC.PamDataBlock;
@@ -85,7 +89,8 @@ public class MapDetectionsDialog extends PamDialog {
MapDetectionData md;
- ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+// ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+ FontIcon settingsIcon = FontIcon.of(MaterialDesignC.COG, 20, Color.DARK_GRAY);
for (int i = 0; i < n; i++) {
md = mapDetectionsParameters.mapDetectionDatas.get(i);
diff --git a/src/PamController/fileprocessing/ReprocessStoreChoice.java b/src/PamController/fileprocessing/ReprocessStoreChoice.java
index 6a6bd019..ec41f6b4 100644
--- a/src/PamController/fileprocessing/ReprocessStoreChoice.java
+++ b/src/PamController/fileprocessing/ReprocessStoreChoice.java
@@ -24,7 +24,7 @@ public enum ReprocessStoreChoice {
case DONTSSTART:
return "Don't start processing";
case OVERWRITEALL:
- return "Overwrite existing output data";
+ return "Overwrite all existing output data";
default:
break;
}
@@ -42,7 +42,7 @@ public enum ReprocessStoreChoice {
case DONTSSTART:
return "Processing will not start. Select alternative storage locations / databases and try again";
case OVERWRITEALL:
- return "Overwrite existing output data. Existing data will be deleted";
+ return "Overwrite existing output data. All existing data will be deleted";
default:
break;
}
diff --git a/src/PamController/soundMedium/GlobalMediumManager.java b/src/PamController/soundMedium/GlobalMediumManager.java
index f546caea..2fff40d5 100644
--- a/src/PamController/soundMedium/GlobalMediumManager.java
+++ b/src/PamController/soundMedium/GlobalMediumManager.java
@@ -27,7 +27,7 @@ public class GlobalMediumManager implements PamSettings {
private GlobalMediumParams globalMediumParams = new GlobalMediumParams();
- private String warning = " Changing to between air and water requires a PAMGuard restart\n"
+ public String warning = " Changing to between air and water requires a PAMGuard restart\n"
+ " for some display changes to take effect. Settings such as\n"
+ " sound speed, reciever sensitivity values and data unit amplitudes\n"
+ " will be recalculated or set to new default values.\n"
@@ -74,6 +74,7 @@ public class GlobalMediumManager implements PamSettings {
subMenu.add(rbMenuItem);
}
}
+
/**
diff --git a/src/PamModel/PamModel.java b/src/PamModel/PamModel.java
index d2bcb919..2ff3b92e 100644
--- a/src/PamModel/PamModel.java
+++ b/src/PamModel/PamModel.java
@@ -45,7 +45,6 @@ import whistlesAndMoans.AbstractWhistleDataUnit;
import fftManager.FFTDataUnit;
import fftManager.PamFFTControl;
import group3dlocaliser.Group3DLocaliserControl;
-import metadata.MetaDataContol;
import meygenturbine.MeygenTurbine;
import printscreen.PrintScreenControl;
import rockBlock.RockBlockControl;
@@ -472,6 +471,7 @@ final public class PamModel implements PamSettings {
mi.setToolTipText("Interface to Tethys Database");
mi.setModulesMenuGroup(utilitiesGroup);
mi.setMaxNumber(1);
+ //mi.addGUICompatabilityFlag(PamGUIManager.FX); //has FX enabled GUI.
mi.setHidden(SMRUEnable.isEnable() == false);
}
@@ -522,7 +522,8 @@ final public class PamModel implements PamSettings {
mi.setModulesMenuGroup(sensorsGroup);
mi.setToolTipText("Imports CPOD data");
mi.setHidden(SMRUEnable.isEnable() == false);
-
+ mi.addGUICompatabilityFlag(PamGUIManager.FX); //has FX enabled GUI.
+
/*
* ************* Start Displays Group *******************
*/
@@ -591,6 +592,7 @@ final public class PamModel implements PamSettings {
mi.addDependency(new PamDependency(RawDataUnit.class, "Acquisition.AcquisitionControl"));
mi.setToolTipText("Decimates (reduces the frequency of) audio data");
mi.setModulesMenuGroup(processingGroup);
+ mi.addGUICompatabilityFlag(PamGUIManager.FX); //has FX enabled GUI.
mi = PamModuleInfo.registerControlledUnit(CepstrumControl.class.getName(), CepstrumControl.unitType);
mi.addDependency(new PamDependency(FFTDataUnit.class, PamFFTControl.class.getName()));
@@ -875,7 +877,7 @@ final public class PamModel implements PamSettings {
mi.setModulesMenuGroup(displaysGroup);
mi.addGUICompatabilityFlag(PamGUIManager.FX);
- mi = PamModuleInfo.registerControlledUnit("detectionPlotFX.DetectionDisplayControl", "Detection Display" );
+ mi = PamModuleInfo.registerControlledUnit("detectionPlotFX.DetectionDisplayControl2", "Detection Display" );
mi.setToolTipText("Display detection data");
mi.setModulesMenuGroup(displaysGroup);
mi.addGUICompatabilityFlag(PamGUIManager.FX);
diff --git a/src/PamUtils/FileParts.java b/src/PamUtils/FileParts.java
index ff2c8aba..ef185556 100644
--- a/src/PamUtils/FileParts.java
+++ b/src/PamUtils/FileParts.java
@@ -6,6 +6,7 @@ import java.net.URI;
/**
* Class for breaking a file name down into it's constituent
* parts.
+ *
* @author Doug Gillespie
*
*/
diff --git a/src/PamUtils/PamArrayUtils.java b/src/PamUtils/PamArrayUtils.java
index e6467abd..997a7138 100644
--- a/src/PamUtils/PamArrayUtils.java
+++ b/src/PamUtils/PamArrayUtils.java
@@ -10,6 +10,8 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.math.linear.Array2DRowRealMatrix;
import org.apache.commons.math.linear.RealMatrix;
+import us.hebi.matlab.mat.types.Matrix;
+
/**
* Some math and utility functions for arrays and Lists.
*
@@ -22,19 +24,19 @@ public class PamArrayUtils {
/**
* Calculate the mean of one dimension within a list of points. e.g. 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.
- * @param successJump - a list of points
+ * @param array - a list of points
* @param InitialtoIgnorePercentage: ignore the first percentage of results
* @param dim - the dimension of the point to calculate the average for
* @return the mean of one dimension of the list of the points.
*/
- public static double mean(ArrayList successJump, double InitialtoIgnorePercentage, int dim){
+ public static double mean(ArrayList array, double InitialtoIgnorePercentage, int dim){
double meanTotal=0;
int n=0;
- int forStart=(int) Math.round((InitialtoIgnorePercentage)*successJump.size());
+ int forStart=(int) Math.round((InitialtoIgnorePercentage)*array.size());
- for (int i=forStart; i successJump, double initialtoIgnorePercentage, int dim){
+ public static double std(ArrayList array, double initialtoIgnorePercentage, int dim){
double std=0.0;
int n=0;
- int forStart=(int) Math.round((initialtoIgnorePercentage)*successJump.size());
+ int forStart=(int) Math.round((initialtoIgnorePercentage)*array.size());
- double meanTotal= mean(successJump, initialtoIgnorePercentage, dim);
+ double meanTotal= mean(array, initialtoIgnorePercentage, dim);
//calculate standard deviation
- for (int k=forStart;k {
private BackgroundWorker backgroundWorker;
+
private volatile boolean running = false;
/**
@@ -82,11 +83,11 @@ public class PamWorker {
*/
public boolean start() {
if (backgroundWorker.isCancelled() || backgroundWorker.isDone() || running) return false;
- backgroundWorker.execute();
+ backgroundWorker.execute();
return true;
}
- protected class BackgroundWorker extends SwingWorker {
+ public class BackgroundWorker extends SwingWorker {
@Override
protected T doInBackground() throws Exception {
@@ -139,6 +140,12 @@ public class PamWorker {
}
}
+
+
+ public BackgroundWorker getBackgroundWorker() {
+ return backgroundWorker;
+ }
+
diff --git a/src/PamView/PamDetectionOverlayGraphics.java b/src/PamView/PamDetectionOverlayGraphics.java
index 78917ecc..e4667b8b 100644
--- a/src/PamView/PamDetectionOverlayGraphics.java
+++ b/src/PamView/PamDetectionOverlayGraphics.java
@@ -1,5 +1,6 @@
package PamView;
+import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
@@ -9,6 +10,7 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.Window;
+import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
@@ -282,7 +284,6 @@ public class PamDetectionOverlayGraphics extends PanelOverlayDraw {
protected Rectangle drawOnMap(Graphics g, PamDataUnit pamDetection, GeneralProjector generalProjector) {
-
/*
*
* four possibilities here.
@@ -390,7 +391,12 @@ public class PamDetectionOverlayGraphics extends PanelOverlayDraw {
generalProjector.addHoverData(endPoint, pamDetection);
//plot localisation errors.
if (localisation.getLocError(i)!=null){
- TransformShape shape=localisation.getLocError(i).getErrorDraw().drawOnMap(g, pamDetection, endLatLong, generalProjector, symbol.getLineColor());
+
+ Color col =symbol.getLineColor();
+ if (drawingOptions != null) {
+ col = drawingOptions.createColor(symbol.getLineColor(), drawingOptions.getLineOpacity());
+ }
+ TransformShape shape=localisation.getLocError(i).getErrorDraw().drawOnMap(g, pamDetection, endLatLong, generalProjector, col);
generalProjector.addHoverData(shape, pamDetection);
}
else {
@@ -496,14 +502,14 @@ public class PamDetectionOverlayGraphics extends PanelOverlayDraw {
}
- /**
- * Draw a localisation symbol. This is just a circel with a specified radius.
- * @param g - graphics handle
- * @param pamDataUnit - the PAM data unit which holds the localisation that is being plotted/
- * @param originPoint - the origin of the localisation.
- * @param locPoint - the location of the localisation
- * @return a rectangle which is the bounds of the localisation symbol.
- */
+// /**
+// * Draw a localisation symbol. This is just a circel with a specified radius.
+// * @param g - graphics handle
+// * @param pamDataUnit - the PAM data unit which holds the localisation that is being plotted/
+// * @param originPoint - the origin of the localisation.
+// * @param locPoint - the location of the localisation
+// * @return a rectangle which is the bounds of the localisation symbol.
+// */
// protected Rectangle drawLocSymbol(Graphics g, PamDataUnit pamDataUnit, Point originPoint, Point locPoint, Color color){
//
// //need some better graphics options- cast to Graphics2D.
@@ -527,79 +533,79 @@ public class PamDetectionOverlayGraphics extends PanelOverlayDraw {
//
// return oval.getBounds();
// }
-
-
- // /**
- // * Plots errors as an ellipse.
- // * @param g - the graphics handle.
- // * @param errorOrigin - the error origin point.
- // * @param errorDirection. The direction of the perpendicular error. In RADIANS
- // * @param perpError - the error perpendicular to the track line or (if no track line this is simply the error in x)
- // * @param horzError - the error horizontal to the track line or (if no track line this is simply the error in x)
- // * @param color
- // * @return
- // */
- // private Rectangle drawErrors(Graphics g, PamDataUnit pamDataUnit, GeneralProjector generalProjector, LatLong errorOrigin, double errorDirection, double perpError, double horzError, Color color) {
- //
- // //System.out.println("Plot errors: perp: "+ perpError+ " horz: "+horzError+ " " + errorDirection);
- //
- // Graphics2D g2d = (Graphics2D)g;
- //
- // //draw oval
- //// //need to work out the size of the horizontal error.
- //// perpError=Math.max(perpError, 100);
- //// horzError=Math.max(horzError, 50);
- //
- // //must work out the horizontal and perpindicular error size in pixels using the projector
- // //this is a bit of round about way to do thinfs but best use of framework here.
- // LatLong llperp=errorOrigin.addDistanceMeters(0, perpError);
- // LatLong l2perp=errorOrigin.addDistanceMeters(horzError, 0);
- //
- // Point pointPerp = generalProjector.getCoord3d(llperp.getLatitude(), llperp.getLongitude(), 0).getXYPoint();
- // Point pointHorz = generalProjector.getCoord3d(l2perp.getLatitude(), l2perp.getLongitude(), 0).getXYPoint();
- // Point errorOriginXY=generalProjector.getCoord3d(errorOrigin.getLatitude(), errorOrigin.getLongitude(), 0).getXYPoint();
- //
- // double perpErrPix=errorOriginXY.distance(pointPerp);
- // double horzErrPix=errorOriginXY.distance(pointHorz);
- //
- // //draw the ellipse and rotate if possible.
- // Ellipse2D oval=new Ellipse2D.Double(errorOriginXY.getX()-horzErrPix/2, errorOriginXY.getY()-perpErrPix/2, horzErrPix, perpErrPix);
- // g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 5 * 0.1f));
- // g2d.setPaint(color.brighter());
- //
- // if (!Double.isNaN(errorDirection)) g2d.rotate(errorDirection,errorOriginXY.getX(), errorOriginXY.getY());
- // g2d.draw(oval);
- // g2d.fill(oval);
- //
- // //reset transparency.
- // g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1));
- // //need to reset the rotation
- // if (!Double.isNaN(errorDirection)) g2d.rotate(-errorDirection,errorOriginXY.getX(), errorOriginXY.getY());
- //
- //
- // return oval.getBounds();
- //
- //
- //// // refBEaring should be an angle in radians from the x axis (trig coordinates)
- //// // convert this to a compass heading and get the positions of the ends.
- //// g.setColor(col);
- //// double compassHeading = 90 - (refAngle * 180 / Math.PI);
- //// Coordinate3d centre = generalProjector.getCoord3d(refPoint.getLatitude(), refPoint.getLongitude(), 0);
- //// LatLong ll1 = refPoint.travelDistanceMeters(compassHeading, err1);
- //// LatLong ll2 = refPoint.travelDistanceMeters(compassHeading+90, err2);
- //// Coordinate3d p1 = generalProjector.getCoord3d(ll1.getLatitude(), ll1.getLongitude(), 0);
- //// Coordinate3d p2 = generalProjector.getCoord3d(ll2.getLatitude(), ll2.getLongitude(), 0);
- //// int cx = (int) centre.x;
- //// int cy = (int) centre.y;
- //// int dx = (int) (p1.x- centre.x);
- //// int dy = (int) (p1.y- centre.y);
- //// g.drawLine(cx + dx, cy - dy, cx - dx, cy + dy);
- //// dx = (int) (p2.x- centre.x);
- //// dy = (int) (p2.y- centre.y);
- //// g.drawLine(cx + dx, cy - dy, cx - dx, cy + dy);
- ////
- //// return null;
- // }
+//
+//
+// /**
+// * Plots errors as an ellipse.
+// * @param g - the graphics handle.
+// * @param errorOrigin - the error origin point.
+// * @param errorDirection. The direction of the perpendicular error. In RADIANS
+// * @param perpError - the error perpendicular to the track line or (if no track line this is simply the error in x)
+// * @param horzError - the error horizontal to the track line or (if no track line this is simply the error in x)
+// * @param color
+// * @return
+// */
+// private Rectangle drawErrors(Graphics g, PamDataUnit pamDataUnit, GeneralProjector generalProjector, LatLong errorOrigin, double errorDirection, double perpError, double horzError, Color color) {
+//
+// //System.out.println("Plot errors: perp: "+ perpError+ " horz: "+horzError+ " " + errorDirection);
+//
+// Graphics2D g2d = (Graphics2D)g;
+//
+// //draw oval
+// // //need to work out the size of the horizontal error.
+// // perpError=Math.max(perpError, 100);
+// // horzError=Math.max(horzError, 50);
+//
+// //must work out the horizontal and perpindicular error size in pixels using the projector
+// //this is a bit of round about way to do thinfs but best use of framework here.
+// LatLong llperp=errorOrigin.addDistanceMeters(0, perpError);
+// LatLong l2perp=errorOrigin.addDistanceMeters(horzError, 0);
+//
+// Point pointPerp = generalProjector.getCoord3d(llperp.getLatitude(), llperp.getLongitude(), 0).getXYPoint();
+// Point pointHorz = generalProjector.getCoord3d(l2perp.getLatitude(), l2perp.getLongitude(), 0).getXYPoint();
+// Point errorOriginXY=generalProjector.getCoord3d(errorOrigin.getLatitude(), errorOrigin.getLongitude(), 0).getXYPoint();
+//
+// double perpErrPix=errorOriginXY.distance(pointPerp);
+// double horzErrPix=errorOriginXY.distance(pointHorz);
+//
+// //draw the ellipse and rotate if possible.
+// Ellipse2D oval=new Ellipse2D.Double(errorOriginXY.getX()-horzErrPix/2, errorOriginXY.getY()-perpErrPix/2, horzErrPix, perpErrPix);
+// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 5 * 0.1f));
+// g2d.setPaint(color.brighter());
+//
+// if (!Double.isNaN(errorDirection)) g2d.rotate(errorDirection,errorOriginXY.getX(), errorOriginXY.getY());
+// g2d.draw(oval);
+// g2d.fill(oval);
+//
+// //reset transparency.
+// g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1));
+// //need to reset the rotation
+// if (!Double.isNaN(errorDirection)) g2d.rotate(-errorDirection,errorOriginXY.getX(), errorOriginXY.getY());
+//
+//
+// return oval.getBounds();
+//
+//
+// // // refBEaring should be an angle in radians from the x axis (trig coordinates)
+// // // convert this to a compass heading and get the positions of the ends.
+// // g.setColor(col);
+// // double compassHeading = 90 - (refAngle * 180 / Math.PI);
+// // Coordinate3d centre = generalProjector.getCoord3d(refPoint.getLatitude(), refPoint.getLongitude(), 0);
+// // LatLong ll1 = refPoint.travelDistanceMeters(compassHeading, err1);
+// // LatLong ll2 = refPoint.travelDistanceMeters(compassHeading+90, err2);
+// // Coordinate3d p1 = generalProjector.getCoord3d(ll1.getLatitude(), ll1.getLongitude(), 0);
+// // Coordinate3d p2 = generalProjector.getCoord3d(ll2.getLatitude(), ll2.getLongitude(), 0);
+// // int cx = (int) centre.x;
+// // int cy = (int) centre.y;
+// // int dx = (int) (p1.x- centre.x);
+// // int dy = (int) (p1.y- centre.y);
+// // g.drawLine(cx + dx, cy - dy, cx - dx, cy + dy);
+// // dx = (int) (p2.x- centre.x);
+// // dy = (int) (p2.y- centre.y);
+// // g.drawLine(cx + dx, cy - dy, cx - dx, cy + dy);
+// //
+// // return null;
+// }
protected Rectangle drawLineAndSymbol(Graphics g, PamDataUnit pamDataUnit, GeneralProjector generalProjector, LatLong LL1, LatLong LL2, PamSymbol symbol, ProjectorDrawingOptions drawingOptions) {
return drawLineAndSymbol(g, pamDataUnit, generalProjector.getCoord3d(LL1.getLatitude(), LL1.getLongitude(), 0).getXYPoint(),
diff --git a/src/PamView/component/PamSettingsIconButton.java b/src/PamView/component/PamSettingsIconButton.java
index 817903a5..20e6feda 100644
--- a/src/PamView/component/PamSettingsIconButton.java
+++ b/src/PamView/component/PamSettingsIconButton.java
@@ -1,8 +1,13 @@
package PamView.component;
+import java.awt.Color;
+
import javax.swing.ImageIcon;
import javax.swing.JButton;
+import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
+import org.kordamp.ikonli.swing.FontIcon;
+
public class PamSettingsIconButton extends JButton {
/**
@@ -10,8 +15,9 @@ public class PamSettingsIconButton extends JButton {
*/
private static final long serialVersionUID = 1L;
- private static final ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
-
+// private static final ImageIcon settingsIcon = new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+ private static final FontIcon settingsIcon = FontIcon.of(MaterialDesignC.COG, 20, Color.DARK_GRAY);
+
/**
* Create a simple square button using the given icon.
*/
diff --git a/src/PamView/dialog/SettingsButton.java b/src/PamView/dialog/SettingsButton.java
index d3b029f4..510a1711 100644
--- a/src/PamView/dialog/SettingsButton.java
+++ b/src/PamView/dialog/SettingsButton.java
@@ -1,9 +1,15 @@
package PamView.dialog;
+import java.awt.Color;
+
import javax.swing.Action;
+import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
+import org.kordamp.ikonli.materialdesign2.MaterialDesignC;
+import org.kordamp.ikonli.swing.FontIcon;
+
/**
* Standard settings button with the little cogwheel for use throughout Swing components.
* @author dg50
@@ -20,8 +26,9 @@ public class SettingsButton extends JButton {
super(makeIcon());
}
- private static ImageIcon makeIcon() {
- return new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
+ private static Icon makeIcon() {
+ return FontIcon.of(MaterialDesignC.COG, 20, Color.DARK_GRAY);
+// return new ImageIcon(ClassLoader.getSystemResource("Resources/SettingsButtonSmall2.png"));
}
/**
diff --git a/src/PamView/importData/DataImport.java b/src/PamView/importData/DataImport.java
index 2e881386..349c223f 100644
--- a/src/PamView/importData/DataImport.java
+++ b/src/PamView/importData/DataImport.java
@@ -5,66 +5,95 @@ import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
/**
- * This class is used to define what data to import and how to import it. It is used in conjunction with ImportDataSystem to create a generic system to load any type of data into a data block.
+ * This class is used to define what data to import and how to import it. It is
+ * used in conjunction with ImportDataSystem to create a generic system to load
+ * any type of data into a data block.
*
- * First getExtensionsStrings() defines which file types can be selected for import.
+ * First getExtensionsStrings() defines which file types can be selected for
+ * import.
*
- * Before loading in any data we need to perform pre-checks with the function performPreChecks(). This function is called before the load thread is called. Often this will remain blank but say you needed extra user imput then this function could be used
- * to create another dialog box before the data is loaded.
+ * Before loading in any data we need to perform pre-checks with the function
+ * performPreChecks(). This function is called before the load thread is called.
+ * Often this will remain blank but say you needed extra user imput then this
+ * function could be used to create another dialog box before the data is
+ * loaded.
*
- * To create a new importer first we need to load a file into memory using the loadDataIntermediate(String filePath) function. This will create an ArrayList were T is the type of data we're trying to save. So for example if you are loading in NMEA data then
- * you would use create loadDataIntermediate(String filePath) which imports the file (filepath) and converts into an ArrayList of strings io.e ArrayList such that T=String;
+ * To create a new importer first we need to load a file into memory using the
+ * loadDataIntermediate(String filePath) function. This will create an
+ * ArrayList were T is the type of data we're trying to save. So for example
+ * if you are loading in NMEA data then you would use create
+ * loadDataIntermediate(String filePath) which imports the file (filepath) and
+ * converts into an ArrayList of strings io.e ArrayList such that
+ * T=String;
*
- * Once the data has been loaded into memory it must be converted into a data unit and saved to a data block. The function createDataUnit(T dataLine) converts data into a PamDatUnit. This function would for example, convert an NMEA strings into a GPSDataUnit. The function
- * isDataFormatOK() needs to be used to check that each T is in the correct format.
+ * Once the data has been loaded into memory it must be converted into a data
+ * unit and saved to a data block. The function createDataUnit(T dataLine)
+ * converts data into a PamDatUnit. This function would for example, convert an
+ * NMEA strings into a GPSDataUnit. The function isDataFormatOK() needs to be
+ * used to check that each T is in the correct format.
*
*
* @author Jamie Macaulay
*
- * @param - the data type loaded from a file. This could be a String, ArrayList, ArrayList> etc.
+ * @param - the data type loaded from a file. This could be a String,
+ * ArrayList, ArrayList> etc.
*/
-public abstract class DataImport {
+public abstract class DataImport {
- public abstract ArrayList loadDataIntermediate(String filePath);
-
/**
- * Check that a row of imported data is in the correct format.
+ * Loads the file into memory - each element of the output array list is then processed.
+ * @param filePath - the filepath.
+ * @return a list of imported objects.
+ */
+ public abstract ArrayList loadDataIntermediate(String filePath);
+
+ /**
+ * Check that a row of imported data is in the correct format.
+ *
* @param dataLine-a row of data loaded from file
- * @return true if the format is OK.
+ * @return true if the format is OK.
*/
public abstract boolean isDataFormatOK(T dataLine);
-
+
/**
- * Use this function to perform any pre checks on data/ bring up extra dialog boxes before laoding data.
- * @return true iof pre checks are OK.
+ * Use this function to perform any pre checks on data/ bring up extra dialog
+ * boxes before loading data.
+ *
+ * @return true iof pre checks are OK.
*/
- public boolean performPreChecks(){ return true; }
-
+ public boolean performPreChecks() {
+ return true;
+ }
+
/**
- * Create a data unit from the data loaded from the imported file.
+ * Create a data unit from the data loaded from the imported file.
+ *
* @param dataLine-a row of data loaded from file
- * @return a data unit to be saved to the datablock.
+ * @return a data unit to be saved to the datablock.
*/
public abstract PamDataUnit createDataUnit(T dataLine);
/**
- * Get the data block to to save data to.
+ * Get the data block to to save data to.
+ *
* @return
*/
@SuppressWarnings("rawtypes")
public abstract PamDataBlock getDataBlock();
/**
- * Return the file extensions that can be loaded.
- * @return an array of file extensions that can be loaded.
+ * Return the file extensions that can be loaded.
+ *
+ * @return an array of file extensions that can be loaded.
*/
public abstract String[] getExtensionsStrings();
-
+
/**
- * The name of the data unit to appear on the dialog boxes.
- * @return name of the data unit to be imported.
+ * The name of the data unit to appear on the dialog boxes.
+ *
+ * @return name of the data unit to be imported.
*/
- public String getDataUnitName(){
+ public String getDataUnitName() {
return "Data Units";
}
diff --git a/src/PamView/importData/ImportDataSystem.java b/src/PamView/importData/ImportDataSystem.java
index 8f166883..820dbfa9 100644
--- a/src/PamView/importData/ImportDataSystem.java
+++ b/src/PamView/importData/ImportDataSystem.java
@@ -288,7 +288,7 @@ public class ImportDataSystem {
}
public void setSaveProgress(int prog){
- System.out.println("prog "+prog);
+ //System.out.println("prog "+prog);
setProgress(prog);
}
diff --git a/src/PamView/symbol/modifier/PeakFreqModifier.java b/src/PamView/symbol/modifier/PeakFreqModifier.java
index a989d419..1a8d504a 100644
--- a/src/PamView/symbol/modifier/PeakFreqModifier.java
+++ b/src/PamView/symbol/modifier/PeakFreqModifier.java
@@ -25,11 +25,11 @@ import pamViewFX.fxNodes.utilsFX.PamUtilsFX;
*
*/
public class PeakFreqModifier extends SymbolModifier {
-
+
public final static String PEAK_FREQ_MODIFIER_NAME = "Peak Frequency";
-
+
private SymbolData symbolData = new SymbolData(PamSymbolType.SYMBOL_CIRCLE, 5, 5, true, Color.BLACK, Color.BLACK);
-
+
/**
* The colour array for frequency
*/
@@ -49,23 +49,23 @@ public class PeakFreqModifier extends SymbolModifier {
public PeakFreqModifier(PamSymbolChooser symbolChooser) {
super(PEAK_FREQ_MODIFIER_NAME, symbolChooser, SymbolModType.FILLCOLOUR | SymbolModType.LINECOLOUR );
- checkColourArray();
- setToolTipText("Colour by the peak frequency of the sound");
+ checkColourArray();
+ setToolTipText("Colour by the peak frequency of the sound");
}
-
+
public SymbolData modifySymbol(SymbolData symbolData, GeneralProjector projector, PamDataUnit dataUnit) {
-// checkColourArray();
+ // checkColourArray();
return super.modifySymbol(symbolData, projector, dataUnit);
}
-
+
@Override
public SymbolData getSymbolData(GeneralProjector projector, PamDataUnit dataUnit) {
return colourByFreq(symbolData, projector, dataUnit);
}
-
-
+
+
/**
* Colour the symbol by frequency.
* @param symbolData - the symbol data.
@@ -74,9 +74,19 @@ public class PeakFreqModifier extends SymbolModifier {
* @return the symbol data
*/
private SymbolData colourByFreq(SymbolData symbolData, GeneralProjector projector, PamDataUnit dataUnit) {
-
+
double frequency = Double.NaN;
- if (dataUnit instanceof RawDataHolder) {
+
+ if (dataUnit instanceof CPODClick) {
+
+ //A bit of a HACK
+
+ frequency = ((CPODClick) dataUnit).getkHz()*1000;
+
+ // System.out.println("Frequency: " + frequency + " Upper freq: " + peakFreqSymbolOptions.freqLimts[1] " Lower freq: " + peakFreqSymbolOptions.freqLimts[0] );
+ }
+ else if (dataUnit instanceof RawDataHolder) {
+
RawDataHolder click = (RawDataHolder) dataUnit;
@@ -86,32 +96,25 @@ public class PeakFreqModifier extends SymbolModifier {
frequency= (maxIndex/(double) powerSpectrum.length)*dataUnit.getParentDataBlock().getSampleRate()/2;
-
}
- else if (dataUnit instanceof CPODClick) {
-
- frequency = ((CPODClick) dataUnit).getkHz()*1000;
-
-// System.out.println("Frequency: " + frequency + " Upper freq: " + peakFreqSymbolOptions.freqLimts[1] " Lower freq: " + peakFreqSymbolOptions.freqLimts[0] );
- }
else {
return null;
}
-
+
frequency=(frequency - peakFreqSymbolOptions.freqLimts[0])/(peakFreqSymbolOptions.freqLimts[1]-peakFreqSymbolOptions.freqLimts[0]);
checkColourArray();
Color freqCol = PamUtilsFX.fxToAWTColor(this.colourArray.getColour(frequency));
-
-// System.out.println("Freq colour: " + freqCol.getRed() + " " + freqCol.getGreen() + " " + freqCol.getBlue());
+
+ // System.out.println("Freq colour: " + freqCol.getRed() + " " + freqCol.getGreen() + " " + freqCol.getBlue());
symbolData.setFillColor(freqCol);
symbolData.setLineColor(freqCol);
return symbolData;
}
-
+
/**
@@ -123,7 +126,7 @@ public class PeakFreqModifier extends SymbolModifier {
this.colourArrayType=peakFreqSymbolOptions.freqColourArray;
}
}
-
+
@Override
public SymbolModifierPane getOptionsPane() {
//System.out.println("PEAK FREQ COLOUR ARRAY2: " + peakFreqSymbolOptions.freqColourArray);
@@ -133,7 +136,7 @@ public class PeakFreqModifier extends SymbolModifier {
}
return peakFreqOptions;
}
-
+
@Override
public SymbolModifierParams getSymbolModifierParams() {
//System.out.println("PEAK FREQ COLOUR ARRAY3: " + peakFreqSymbolOptions.freqColourArray);
@@ -154,7 +157,7 @@ public class PeakFreqModifier extends SymbolModifier {
//System.out.println("PEAK FREQ COLOUR ARRAY: " + peakFreqSymbolOptions.freqColourArray);
checkColourArray();
}
-
+
}
diff --git a/src/PamguardMVC/RawDataTransforms.java b/src/PamguardMVC/RawDataTransforms.java
index 98ffd01b..44690ed1 100644
--- a/src/PamguardMVC/RawDataTransforms.java
+++ b/src/PamguardMVC/RawDataTransforms.java
@@ -161,7 +161,9 @@ public class RawDataTransforms {
*/
public double[] getPowerSpectrum(int channel, int minBin, int maxBin, int fftLength) {
synchronized (synchObject) {
+
if (minBin==0 && maxBin>=this.getWaveData(0).length-1) {
+
return getPowerSpectrum(channel, fftLength);
}
if (fftLength == 0) {
@@ -169,8 +171,8 @@ public class RawDataTransforms {
}
double[] waveformTrim = new double[maxBin-minBin];
-
- //System.out.println("minBin: " + minBin + " maxBin: " + maxBin + " raw waveform: " + this.getWaveData(channel).length);
+
+// System.out.println("minBin: " +minBin + " maxBin: " + maxBin + " " + Math.min(this.getWaveData(channel).length, waveformTrim.length) + " " + this.getWaveData(channel).length + " " + this.getSampleDuration());
System.arraycopy(this.getWaveData(channel), minBin, waveformTrim, 0, Math.min(this.getWaveData(channel).length-minBin-1, waveformTrim.length));
@@ -305,7 +307,7 @@ public class RawDataTransforms {
* Get the spectrum length
* @return the spectrogram length.
*/
- private int getCurrentSpectrumLength() {
+ public int getCurrentSpectrumLength() {
if (currentSpecLen<=0) {
currentSpecLen = PamUtils.getMinFftLength(dataUnit.getSampleDuration());
}
@@ -573,14 +575,21 @@ public class RawDataTransforms {
*/
public FFTFilter getFFTFilter(FFTFilterParams fftFilterParams) {
if (fftFilter == null) {
- fftFilter = new FFTFilter(fftFilterParams, this.dataUnit.getParentDataBlock().getSampleRate());
+ fftFilter = new FFTFilter(fftFilterParams,getSampleRate());
}
else {
- fftFilter.setParams(fftFilterParams, this.dataUnit.getParentDataBlock().getSampleRate());
+ fftFilter.setParams(fftFilterParams, getSampleRate());
}
return fftFilter;
}
+ /**
+ * Get the sample rate to use for transforms.
+ * @return the sample rate.
+ */
+ public float getSampleRate() {
+ return this.dataUnit.getParentDataBlock().getSampleRate();
+ }
/**
* Get a correction based on the slope of the waveform which
diff --git a/src/PamguardMVC/toad/GenericTOADCalculator.java b/src/PamguardMVC/toad/GenericTOADCalculator.java
index 1a3e2644..3dbc5a13 100644
--- a/src/PamguardMVC/toad/GenericTOADCalculator.java
+++ b/src/PamguardMVC/toad/GenericTOADCalculator.java
@@ -134,6 +134,7 @@ public class GenericTOADCalculator implements TOADCalculator, PamSettings {
* to give better timing accuracy.
*/
FFTDataList fftData = fftDataOrganiser.createFFTDataList(dataUnit, sampleRate, dataUnit.getChannelBitmap() & channelMap);
+// System.out.println("fftData: " + fftData);
if (fftData == null || fftData.getMaxChannelCount() == 0) {
// debug stuff ...
System.out.println("No FFT Data for " + dataUnit.getSummaryString());
diff --git a/src/PamguardMVC/toad/TOADCalculator.java b/src/PamguardMVC/toad/TOADCalculator.java
index 92d0ae9c..818ed1f4 100644
--- a/src/PamguardMVC/toad/TOADCalculator.java
+++ b/src/PamguardMVC/toad/TOADCalculator.java
@@ -1,10 +1,10 @@
package PamguardMVC.toad;
import java.awt.Window;
+import java.io.Serializable;
import java.util.List;
import Array.SnapshotGeometry;
-import PamController.SettingsPane;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamDataUnit;
import group3dlocaliser.algorithm.toadbase.TOADInformation;
diff --git a/src/Resources/Ishmael_Energy_Sum.svg b/src/Resources/Ishmael_Energy_Sum.svg
new file mode 100644
index 00000000..91103d4c
--- /dev/null
+++ b/src/Resources/Ishmael_Energy_Sum.svg
@@ -0,0 +1,29 @@
+
+
+
+
diff --git a/src/Resources/css/delphinid_logo01.svg b/src/Resources/css/delphinid_logo01.svg
new file mode 100644
index 00000000..744670bf
--- /dev/null
+++ b/src/Resources/css/delphinid_logo01.svg
@@ -0,0 +1,114 @@
+
+
+
+
diff --git a/src/Resources/css/pamCSS.css b/src/Resources/css/pamCSS.css
index b2b2d58d..a951f86c 100644
--- a/src/Resources/css/pamCSS.css
+++ b/src/Resources/css/pamCSS.css
@@ -179,7 +179,7 @@
/*******************************************************************************
* *
- * Hiding Tab *
+ * Menu button *
* *
******************************************************************************/
diff --git a/src/Resources/css/pamSettingsCSS.css b/src/Resources/css/pamSettingsCSS.css
index 66d99081..af9f9cf9 100644
--- a/src/Resources/css/pamSettingsCSS.css
+++ b/src/Resources/css/pamSettingsCSS.css
@@ -163,7 +163,7 @@
*/
/** top-left, top-right, bottom-right, and bottom-left corners, in that order. */
.close-button-right{
- -fx-background-color: transparent;
+ -fx-background-color: -fx-darkbackground-trans;
-fx-background-radius: 0 10 10 0;
-fx-border-color: transparent;
-fx-border-radius: 0 10 10 0;
@@ -171,7 +171,7 @@
.close-button-left{
- -fx-background-color: transparent;
+ -fx-background-color: -fx-darkbackground-trans;
-fx-background-radius: 10 0 0 10;
-fx-border-color: transparent;
-fx-border-radius: 10 0 0 10;
@@ -179,17 +179,17 @@
.close-button-top{
- -fx-background-color: transparent;
+ -fx-background-color: -fx-darkbackground-trans;
-fx-background-radius: 10 10 0 0;
- -fx-border-color: transparent;
+ -fx-border-color: transparent;
-fx-border-radius: 10 10 0 0;
}
.close-button-bottom{
- -fx-background-color: transparent;
+ -fx-background-color: -fx-darkbackground-trans;
-fx-background-radius: 0 0 10 10;
- -fx-border-color: transparent;
+ -fx-border-color: transparent;
-fx-border-radius: 0 0 10 10;
}
diff --git a/src/Resources/css/primer-dark.css b/src/Resources/css/primer-dark.css
index 6c1e53ca..a5f0a267 100644
--- a/src/Resources/css/primer-dark.css
+++ b/src/Resources/css/primer-dark.css
@@ -3666,58 +3666,41 @@ Text {
}
-/********************************************
-* *
-* Spinner *
-* *
-*********************************************/
-.spinner {
- -fx-pref-width: 120px;
-}
-
-
-/********************************************
-* *
-* Chart *
-* *
-*********************************************/
-
-
-
-.thin-chart .chart-series-line {
- -fx-stroke-width: 1px;
-}
/*******************************************************************************
* *
- * Label *
+ * Pop over *
* *
******************************************************************************/
-
-#label-title1 {
- -fx-font: bold 14pt -fx-font-family;
+.popover {
+ -fx-background-color: -color-button-bg;
+ -fx-background-radius: 5;
+ -fx-border-radius: 5;
}
-#label-title2 {
- -fx-font: bold 13pt -fx-font-family;
- }
-
-/*******************************************************************************
- * *
- * Label *
- * *
- ******************************************************************************/
-
-
-.validatorfx-error {
- -fx-text-fill: rgb(164, 0, 0);
+.popover > .content {
+ -fx-background-color: -color-button-bg;
+ -fx-background-radius: 5;
+ -fx-border-radius: 5;
}
-.validatorfx-warning {
- -fx-text-fill: rgb(196, 160, 0);
+.popover > .arrow {
+ -fx-background-color: -color-button-bg;
+ -fx-background-radius: 5;
+ -fx-border-radius: 5;
}
+
+/*weird way to do it but need this to colour the arrow*/
+.popover > .border {
+ /*-fx-stroke: linear-gradient(to bottom, rgba(0,0,0, .3), rgba(0, 0, 0, .7)) ;*/
+ -fx-stroke-width: 0.5;
+ -fx-fill: -color-button-bg; /* instead -fx-background-color */
+ -fx-background-color: -color-button-bg;
+
}
+
+}
\ No newline at end of file
diff --git a/src/Resources/css/primer-pamguard-dark.css b/src/Resources/css/primer-pamguard-dark.css
new file mode 100644
index 00000000..ab1d4ecc
--- /dev/null
+++ b/src/Resources/css/primer-pamguard-dark.css
@@ -0,0 +1,320 @@
+{
+
+ -color-dark: #010409;
+ -color-light: #ffffff;
+ -color-base-0: #f0f6fc;
+ -color-base-1: #c9d1d9;
+ -color-base-2: #b1bac4;
+ -color-base-3: #8b949e;
+ -color-base-4: #6e7681;
+ -color-base-5: #484f58;
+ -color-base-6: #30363d;
+ -color-base-7: #21262d;
+ -color-base-8: #161b22;
+ -color-base-9: #0d1117;
+ -color-accent-0: #cae8ff;
+ -color-accent-1: #a5d6ff;
+ -color-accent-2: #79c0ff;
+ -color-accent-3: #58a6ff;
+ -color-accent-4: #388bfd;
+ -color-accent-5: #1f6feb;
+ -color-accent-6: #1158c7;
+ -color-accent-7: #0d419d;
+ -color-accent-8: #0c2d6b;
+ -color-accent-9: #051d4d;
+ -color-success-0: #aff5b4;
+ -color-success-1: #7ee787;
+ -color-success-2: #56d364;
+ -color-success-3: #3fb950;
+ -color-success-4: #2ea043;
+ -color-success-5: #238636;
+ -color-success-6: #196c2e;
+ -color-success-7: #0f5323;
+ -color-success-8: #033a16;
+ -color-success-9: #04260f;
+ -color-warning-0: #f8e3a1;
+ -color-warning-1: #f2cc60;
+ -color-warning-2: #e3b341;
+ -color-warning-3: #d29922;
+ -color-warning-4: #bb8009;
+ -color-warning-5: #9e6a03;
+ -color-warning-6: #845306;
+ -color-warning-7: #693e00;
+ -color-warning-8: #4b2900;
+ -color-warning-9: #341a00;
+ -color-danger-0: #ffdcd7;
+ -color-danger-1: #ffc1ba;
+ -color-danger-2: #ffa198;
+ -color-danger-3: #ff7b72;
+ -color-danger-4: #f85149;
+ -color-danger-5: #da3633;
+ -color-danger-6: #b62324;
+ -color-danger-7: #8e1519;
+ -color-danger-8: #67060c;
+ -color-danger-9: #490202;
+ -color-fg-default: #c9d1d9;
+ -color-fg-muted: #8b949e;
+ -color-fg-subtle: #6e7681;
+ -color-fg-emphasis: #ffffff;
+ -color-bg-default: #0d1117;
+ -color-bg-overlay: #0d1117;
+ -color-bg-subtle: #161b22;
+ -color-bg-inset: #010409;
+ -color-border-default: #30363d;
+ -color-border-muted: #21262d;
+ -color-border-subtle: rgba(240, 246, 252, 0.1);
+ -color-shadow-default: #010409;
+ -color-neutral-emphasis-plus: #6e7681;
+ -color-neutral-emphasis: #6e7681;
+ -color-neutral-muted: rgba(110, 118, 129, 0.4);
+ -color-neutral-subtle: rgba(110, 118, 129, 0.1);
+ -color-accent-fg: #58a6ff;
+ -color-accent-emphasis: #1f6feb;
+ -color-accent-muted: rgba(56, 139, 253, 0.4);
+ -color-accent-subtle: rgba(56, 139, 253, 0.15);
+ -color-warning-fg: #d29922;
+ -color-warning-emphasis: #9e6a03;
+ -color-warning-muted: rgba(187, 128, 9, 0.4);
+ -color-warning-subtle: rgba(187, 128, 9, 0.15);
+ -color-success-fg: #3fb950;
+ -color-success-emphasis: #238636;
+ -color-success-muted: rgba(46, 160, 67, 0.4);
+ -color-success-subtle: rgba(46, 160, 67, 0.15);
+ -color-danger-fg: #f85149;
+ -color-danger-emphasis: #da3633;
+ -color-danger-muted: rgba(248, 81, 73, 0.4);
+ -color-danger-subtle: rgba(248, 81, 73, 0.15);
+ -color-chart-1: #f3622d;
+ -color-chart-2: #fba71b;
+ -color-chart-3: #57b757;
+ -color-chart-4: #41a9c9;
+ -color-chart-5: #4258c9;
+ -color-chart-6: #9a42c8;
+ -color-chart-7: #c84164;
+ -color-chart-8: #888888;
+ -color-chart-1-alpha70: rgba(243, 98, 45, 0.7);
+ -color-chart-2-alpha70: rgba(251, 167, 27, 0.7);
+ -color-chart-3-alpha70: rgba(87, 183, 87, 0.7);
+ -color-chart-4-alpha70: rgba(65, 169, 201, 0.7);
+ -color-chart-5-alpha70: rgba(66, 88, 201, 0.7);
+ -color-chart-6-alpha70: rgba(154, 66, 200, 0.7);
+ -color-chart-7-alpha70: rgba(200, 65, 100, 0.7);
+ -color-chart-8-alpha70: rgba(136, 136, 136, 0.7);
+ -color-chart-1-alpha20: rgba(243, 98, 45, 0.2);
+ -color-chart-2-alpha20: rgba(251, 167, 27, 0.2);
+ -color-chart-3-alpha20: rgba(87, 183, 87, 0.2);
+ -color-chart-4-alpha20: rgba(65, 169, 201, 0.2);
+ -color-chart-5-alpha20: rgba(66, 88, 201, 0.2);
+ -color-chart-6-alpha20: rgba(154, 66, 200, 0.2);
+ -color-chart-7-alpha20: rgba(200, 65, 100, 0.2);
+ -color-chart-8-alpha20: rgba(136, 136, 136, 0.2);
+
+ -fx-pambackground: rgba(238,238,238);
+ -fx-darkbackground: -color-bg-default;
+ -fx-darkbackground-trans: rgba(13, 17, 23,0.90);
+ -fx-highlight: -color-base-6;
+ -fx-highlight_border: -color-button-fg;
+ -fx-text: -color-fg-default;
+ -fx-border_col: -color-border-default;
+ -fx-border_color: -color-border-default;
+ -fx-icon_col: -color-fg-default;
+}
+
+
+/*******************************************************************************
+ * *
+ * For some reason highlighting on hover goes all worng so need to fix this *
+ * *
+ ******************************************************************************/
+
+.button {
+ -color-button-border: -color-border-default;
+ -color-button-bg-hover: -color-base-6;
+ -color-button-fg-hover: -color-button-fg;
+ -color-button-border-hover: -color-button-border;
+}
+
+.menu-button,
+.split-menu-button {
+
+ -color-button-bg-hover: -color-base-6;
+ -color-button-fg-hover: -color-button-fg;
+ -color-button-border-hover: -color-button-border;
+ -color-button-bg-focused: -color-button-bg;
+ -color-button-fg-focused: -color-button-fg;
+ -color-button-border-focused: -color-accent-emphasis;
+ -color-button-bg-pressed: -color-bg-subtle;
+ -color-button-fg-pressed: -color-button-fg;
+}
+
+.menu-button.accent,
+.split-menu-button.accent {
+ -color-button-bg: -color-accent-emphasis;
+ -color-button-fg: -color-fg-emphasis;
+ -color-button-border: -color-accent-emphasis;
+ -color-button-bg-hover: -color-accent-emphasis;
+ -color-button-fg-hover: -color-fg-emphasis;
+ -color-button-border-hover: -color-accent-emphasis;
+ -color-button-bg-focused: -color-accent-6;
+ -color-button-fg-focused: -color-fg-emphasis;
+ -color-button-border-focused: -color-accent-emphasis;
+ -color-button-bg-pressed: -color-accent-emphasis;
+ -color-button-fg-pressed: -color-fg-emphasis;
+ -color-button-border-pressed: transparent;
+}
+.menu-button.accent.button-outlined,
+.split-menu-button.accent.button-outlined {
+ -color-button-bg: -color-bg-default;
+ -color-button-fg: -color-accent-fg;
+ -color-button-bg-hover: -color-accent-emphasis;
+ -color-button-fg-hover: -color-fg-emphasis;
+}
+.menu-button.accent.flat,
+.split-menu-button.accent.flat {
+ -color-button-fg: -color-accent-fg;
+ -color-button-bg-hover: -color-accent-subtle;
+}
+.menu-button.success,
+.split-menu-button.success {
+ -color-button-bg: -color-success-emphasis;
+ -color-button-fg: -color-fg-emphasis;
+ -color-button-border: -color-success-emphasis;
+ -color-button-bg-hover: -color-success-emphasis;
+ -color-button-fg-hover: -color-fg-emphasis;
+ -color-button-border-hover: -color-success-emphasis;
+ -color-button-bg-focused: -color-success-6;
+ -color-button-fg-focused: -color-fg-emphasis;
+ -color-button-border-focused: -color-success-emphasis;
+ -color-button-bg-pressed: -color-success-emphasis;
+ -color-button-fg-pressed: -color-fg-emphasis;
+ -color-button-border-pressed: transparent;
+}
+.menu-button.success.button-outlined,
+.split-menu-button.success.button-outlined {
+ -color-button-bg: -color-bg-default;
+ -color-button-fg: -color-success-fg;
+ -color-button-bg-hover: -color-success-emphasis;
+ -color-button-fg-hover: -color-fg-emphasis;
+}
+.menu-button.success.flat,
+.split-menu-button.success.flat {
+ -color-button-fg: -color-success-fg;
+ -color-button-bg-hover: -color-success-subtle;
+}
+.menu-button.danger,
+.split-menu-button.danger {
+ -color-button-bg: -color-danger-emphasis;
+ -color-button-fg: -color-fg-emphasis;
+ -color-button-border: -color-danger-emphasis;
+ -color-button-bg-hover: -color-danger-emphasis;
+ -color-button-fg-hover: -color-fg-emphasis;
+ -color-button-border-hover: -color-danger-emphasis;
+ -color-button-bg-focused: -color-danger-6;
+ -color-button-fg-focused: -color-fg-emphasis;
+ -color-button-border-focused: -color-danger-emphasis;
+ -color-button-bg-pressed: -color-danger-emphasis;
+ -color-button-fg-pressed: -color-fg-emphasis;
+ -color-button-border-pressed: transparent;
+}
+.menu-button.danger.button-outlined,
+.split-menu-button.danger.button-outlined {
+ -color-button-bg: -color-bg-default;
+ -color-button-fg: -color-danger-fg;
+ -color-button-bg-hover: -color-danger-emphasis;
+ -color-button-fg-hover: -color-fg-emphasis;
+}
+.menu-button.danger.flat,
+.split-menu-button.danger.flat {
+ -color-button-fg: -color-danger-fg;
+ -color-button-bg-hover: -color-danger-subtle;
+}
+.menu-button.flat,
+.split-menu-button.flat {
+ -color-button-bg: transparent;
+ -color-button-fg: -color-fg-default;
+ -color-button-border: transparent;
+ -color-button-bg-hover: -color-bg-subtle;
+ -color-button-fg-hover: -color-button-fg;
+ -color-button-border-hover: -color-bg-subtle;
+ -color-button-bg-focused: -color-button-bg;
+ -color-button-fg-focused: -color-button-fg;
+ -color-button-border-focused: -color-button-bg;
+ -color-button-bg-pressed: -color-button-bg;
+ -color-button-fg-pressed: -color-button-fg;
+ -color-button-border-pressed: transparent;
+}
+
+
+.toggle-button {
+ -color-button-bg: -color-bg-subtle;
+ -color-button-fg: -color-fg-default;
+ -color-button-border: -color-border-default;
+ -color-button-bg-hover: -color-base-6;
+ -color-button-fg-hover: -color-button-fg;
+ -color-button-border-hover: -color-button-border;
+ -color-button-bg-focused: -color-button-bg;
+ -color-button-fg-focused: -color-button-fg;
+ -color-button-border-focused: -color-accent-emphasis;
+ -color-button-bg-pressed: -color-bg-subtle;
+ -color-button-fg-pressed: -color-button-fg;
+ -color-button-border-pressed: transparent;
+}
+
+
+.list-view {
+ -color-cell-bg-selected: -color-base-6;
+ -color-cell-fg-selected: -color-fg-default;
+}
+
+.table-view {
+ -color-cell-bg-selected: -color-base-6;
+ -color-cell-fg-selected: -color-fg-default;
+}
+
+.titled-pane > .title > .text {
+ -fx-font-size: 1em;
+}
+
+.tree-view {
+ -color-cell-bg-selected: -color-base-6;
+ -color-cell-fg-selected: -color-fg-default;
+}
+
+.tree-table-view {
+
+ -color-cell-bg-selected: -color-base-6;
+ -color-cell-fg-selected: -color-fg-default;
+
+}
+
+.list-view:focused > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected,
+.tree-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-cell:filled:selected,
+.table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected,
+.tree-table-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-table-row-cell:filled:selected {
+ -color-cell-fg: -color-cell-fg-selected;
+ -fx-background-color: -color-cell-border, -color-cell-bg-selected;
+}
+
+/*******************************************************************************
+ * *
+ * For some reason the table background is white and so this needs fixed.
+ * *
+ ******************************************************************************/
+
+
+.table-view {
+ -color-cell-bg: -color-bg-default;
+ -color-cell-fg: -color-fg-default;
+ -color-cell-bg-selected: -color-base-6;
+ -color-cell-fg-selected: -color-fg-default;
+ -color-cell-bg-odd: -color-bg-subtle;
+ -color-cell-border: -color-border-default;
+ -fx-border-color: -color-cell-border;
+ -fx-control-inner-background: -color-bg-default;
+ -fx-border-width: 1px;
+ -fx-border-radius: 0;
+ -color-header-bg: -color-bg-subtle;
+ -color-header-fg: -color-fg-default;
+}
+
+
diff --git a/src/Resources/css/primer-pamguard.css b/src/Resources/css/primer-pamguard.css
index 1e28539e..ece247b6 100644
--- a/src/Resources/css/primer-pamguard.css
+++ b/src/Resources/css/primer-pamguard.css
@@ -1,114 +1,5 @@
-
{
- -color-dark: #010409;
- -color-light: #ffffff;
- -color-base-0: #f0f6fc;
- -color-base-1: #c9d1d9;
- -color-base-2: #b1bac4;
- -color-base-3: #8b949e;
- -color-base-4: #6e7681;
- -color-base-5: #484f58;
- -color-base-6: #30363d;
- -color-base-7: #21262d;
- -color-base-8: #161b22;
- -color-base-9: #0d1117;
- -color-accent-0: #cae8ff;
- -color-accent-1: #a5d6ff;
- -color-accent-2: #79c0ff;
- -color-accent-3: #58a6ff;
- -color-accent-4: #388bfd;
- -color-accent-5: #1f6feb;
- -color-accent-6: #1158c7;
- -color-accent-7: #0d419d;
- -color-accent-8: #0c2d6b;
- -color-accent-9: #051d4d;
- -color-success-0: #aff5b4;
- -color-success-1: #7ee787;
- -color-success-2: #56d364;
- -color-success-3: #3fb950;
- -color-success-4: #2ea043;
- -color-success-5: #238636;
- -color-success-6: #196c2e;
- -color-success-7: #0f5323;
- -color-success-8: #033a16;
- -color-success-9: #04260f;
- -color-warning-0: #f8e3a1;
- -color-warning-1: #f2cc60;
- -color-warning-2: #e3b341;
- -color-warning-3: #d29922;
- -color-warning-4: #bb8009;
- -color-warning-5: #9e6a03;
- -color-warning-6: #845306;
- -color-warning-7: #693e00;
- -color-warning-8: #4b2900;
- -color-warning-9: #341a00;
- -color-danger-0: #ffdcd7;
- -color-danger-1: #ffc1ba;
- -color-danger-2: #ffa198;
- -color-danger-3: #ff7b72;
- -color-danger-4: #f85149;
- -color-danger-5: #da3633;
- -color-danger-6: #b62324;
- -color-danger-7: #8e1519;
- -color-danger-8: #67060c;
- -color-danger-9: #490202;
- -color-fg-default: #c9d1d9;
- -color-fg-muted: #8b949e;
- -color-fg-subtle: #6e7681;
- -color-fg-emphasis: #ffffff;
- -color-bg-default: #0d1117;
- -color-bg-overlay: #0d1117;
- -color-bg-subtle: #161b22;
- -color-bg-inset: #010409;
- -color-border-default: #30363d;
- -color-border-muted: #21262d;
- -color-border-subtle: rgba(240, 246, 252, 0.1);
- -color-shadow-default: #010409;
- -color-neutral-emphasis-plus: #6e7681;
- -color-neutral-emphasis: #6e7681;
- -color-neutral-muted: rgba(110, 118, 129, 0.4);
- -color-neutral-subtle: rgba(110, 118, 129, 0.1);
- -color-accent-fg: #58a6ff;
- -color-accent-emphasis: #1f6feb;
- -color-accent-muted: rgba(56, 139, 253, 0.4);
- -color-accent-subtle: rgba(56, 139, 253, 0.15);
- -color-warning-fg: #d29922;
- -color-warning-emphasis: #9e6a03;
- -color-warning-muted: rgba(187, 128, 9, 0.4);
- -color-warning-subtle: rgba(187, 128, 9, 0.15);
- -color-success-fg: #3fb950;
- -color-success-emphasis: #238636;
- -color-success-muted: rgba(46, 160, 67, 0.4);
- -color-success-subtle: rgba(46, 160, 67, 0.15);
- -color-danger-fg: #f85149;
- -color-danger-emphasis: #da3633;
- -color-danger-muted: rgba(248, 81, 73, 0.4);
- -color-danger-subtle: rgba(248, 81, 73, 0.15);
- -color-chart-1: #f3622d;
- -color-chart-2: #fba71b;
- -color-chart-3: #57b757;
- -color-chart-4: #41a9c9;
- -color-chart-5: #4258c9;
- -color-chart-6: #9a42c8;
- -color-chart-7: #c84164;
- -color-chart-8: #888888;
- -color-chart-1-alpha70: rgba(243, 98, 45, 0.7);
- -color-chart-2-alpha70: rgba(251, 167, 27, 0.7);
- -color-chart-3-alpha70: rgba(87, 183, 87, 0.7);
- -color-chart-4-alpha70: rgba(65, 169, 201, 0.7);
- -color-chart-5-alpha70: rgba(66, 88, 201, 0.7);
- -color-chart-6-alpha70: rgba(154, 66, 200, 0.7);
- -color-chart-7-alpha70: rgba(200, 65, 100, 0.7);
- -color-chart-8-alpha70: rgba(136, 136, 136, 0.7);
- -color-chart-1-alpha20: rgba(243, 98, 45, 0.2);
- -color-chart-2-alpha20: rgba(251, 167, 27, 0.2);
- -color-chart-3-alpha20: rgba(87, 183, 87, 0.2);
- -color-chart-4-alpha20: rgba(65, 169, 201, 0.2);
- -color-chart-5-alpha20: rgba(66, 88, 201, 0.2);
- -color-chart-6-alpha20: rgba(154, 66, 200, 0.2);
- -color-chart-7-alpha20: rgba(200, 65, 100, 0.2);
- -color-chart-8-alpha20: rgba(136, 136, 136, 0.2);
-fx-pambackground: rgba(238,238,238);
-fx-darkbackground: -color-bg-default;
@@ -117,17 +8,19 @@
-fx-highlight_border: -color-button-fg;
-fx-text: -color-fg-default;
-fx-border_col: -color-border-default;
+ -fx-border_color: -color-border-default;
-fx-icon_col: -color-fg-default;
+ -fx-highlight_border_settings: rgba(0,204,204,1);
+ -fx-highlight_settings: rgba(0,204,204,1);
}
-.root {
- -fx-background-color:-fx-darkbackground;
- -fx-font-size: 12px;
- -fx-background-radius: inherit;
- -fx-background-insets: inherit;
- -fx-padding: 5px 5px 5px 5px;
+
+.root{
+ -fx-font-size: 10pt;
+ -fx-font-family: "Ubuntu";
}
+
/*******************************************************************************
* *
* Panes *
@@ -151,240 +44,6 @@
-fx-background-color: -fx-plotbackground;
}
-
-.button {
- -color-button-bg: -color-bg-subtle;
- -color-button-fg: -color-fg-default;
- -color-button-border: -color-border-default;
- -color-button-bg-hover: -color-base-6;
- -color-button-fg-hover: -color-button-fg;
- -color-button-border-hover: -color-button-border;
- -color-button-bg-focused: -color-button-bg;
- -color-button-fg-focused: -color-button-fg;
- -color-button-border-focused: -color-accent-emphasis;
- -color-button-bg-pressed: -color-bg-subtle;
- -color-button-fg-pressed: -color-button-fg;
- -color-button-border-pressed: transparent;
- -fx-background-color: -color-button-border, -color-button-bg;
- -fx-background-insets: 0, 1px;
- -fx-background-radius: 4px;
- -fx-graphic-text-gap: 6px;
- -fx-text-fill: -color-button-fg;
- -fx-alignment: CENTER;
- -fx-padding: 8px 12px 8px 12px;
-}
-
-.menu-button,
-.split-menu-button {
- -color-button-bg: -color-bg-subtle;
- -color-button-fg: -color-fg-default;
- -color-button-border: -color-border-default;
- -color-button-bg-hover: -color-base-6;
- -color-button-fg-hover: -color-button-fg;
- -color-button-border-hover: -color-button-border;
- -color-button-bg-focused: -color-button-bg;
- -color-button-fg-focused: -color-button-fg;
- -color-button-border-focused: -color-accent-emphasis;
- -color-button-bg-pressed: -color-bg-subtle;
- -color-button-fg-pressed: -color-button-fg;
- -color-button-border-pressed: transparent;
- -fx-background-color: -color-button-border, -color-button-bg;
- -fx-background-insets: 0, 1px;
- -fx-background-radius: 4px;
- -fx-graphic-text-gap: 6px;
- -fx-text-fill: -color-button-fg;
- -fx-alignment: CENTER;
- -fx-padding: 0;
- -fx-alignment: CENTER_LEFT;
-}
-
-.menu-button.accent,
-.split-menu-button.accent {
- -color-button-bg: -color-accent-emphasis;
- -color-button-fg: -color-fg-emphasis;
- -color-button-border: -color-accent-emphasis;
- -color-button-bg-hover: -color-accent-emphasis;
- -color-button-fg-hover: -color-fg-emphasis;
- -color-button-border-hover: -color-accent-emphasis;
- -color-button-bg-focused: -color-accent-6;
- -color-button-fg-focused: -color-fg-emphasis;
- -color-button-border-focused: -color-accent-emphasis;
- -color-button-bg-pressed: -color-accent-emphasis;
- -color-button-fg-pressed: -color-fg-emphasis;
- -color-button-border-pressed: transparent;
-}
-.menu-button.accent.button-outlined,
-.split-menu-button.accent.button-outlined {
- -color-button-bg: -color-bg-default;
- -color-button-fg: -color-accent-fg;
- -color-button-bg-hover: -color-accent-emphasis;
- -color-button-fg-hover: -color-fg-emphasis;
-}
-.menu-button.accent.flat,
-.split-menu-button.accent.flat {
- -color-button-fg: -color-accent-fg;
- -color-button-bg-hover: -color-accent-subtle;
-}
-.menu-button.success,
-.split-menu-button.success {
- -color-button-bg: -color-success-emphasis;
- -color-button-fg: -color-fg-emphasis;
- -color-button-border: -color-success-emphasis;
- -color-button-bg-hover: -color-success-emphasis;
- -color-button-fg-hover: -color-fg-emphasis;
- -color-button-border-hover: -color-success-emphasis;
- -color-button-bg-focused: -color-success-6;
- -color-button-fg-focused: -color-fg-emphasis;
- -color-button-border-focused: -color-success-emphasis;
- -color-button-bg-pressed: -color-success-emphasis;
- -color-button-fg-pressed: -color-fg-emphasis;
- -color-button-border-pressed: transparent;
-}
-.menu-button.success.button-outlined,
-.split-menu-button.success.button-outlined {
- -color-button-bg: -color-bg-default;
- -color-button-fg: -color-success-fg;
- -color-button-bg-hover: -color-success-emphasis;
- -color-button-fg-hover: -color-fg-emphasis;
-}
-.menu-button.success.flat,
-.split-menu-button.success.flat {
- -color-button-fg: -color-success-fg;
- -color-button-bg-hover: -color-success-subtle;
-}
-.menu-button.danger,
-.split-menu-button.danger {
- -color-button-bg: -color-danger-emphasis;
- -color-button-fg: -color-fg-emphasis;
- -color-button-border: -color-danger-emphasis;
- -color-button-bg-hover: -color-danger-emphasis;
- -color-button-fg-hover: -color-fg-emphasis;
- -color-button-border-hover: -color-danger-emphasis;
- -color-button-bg-focused: -color-danger-6;
- -color-button-fg-focused: -color-fg-emphasis;
- -color-button-border-focused: -color-danger-emphasis;
- -color-button-bg-pressed: -color-danger-emphasis;
- -color-button-fg-pressed: -color-fg-emphasis;
- -color-button-border-pressed: transparent;
-}
-.menu-button.danger.button-outlined,
-.split-menu-button.danger.button-outlined {
- -color-button-bg: -color-bg-default;
- -color-button-fg: -color-danger-fg;
- -color-button-bg-hover: -color-danger-emphasis;
- -color-button-fg-hover: -color-fg-emphasis;
-}
-.menu-button.danger.flat,
-.split-menu-button.danger.flat {
- -color-button-fg: -color-danger-fg;
- -color-button-bg-hover: -color-danger-subtle;
-}
-.menu-button.flat,
-.split-menu-button.flat {
- -color-button-bg: transparent;
- -color-button-fg: -color-fg-default;
- -color-button-border: transparent;
- -color-button-bg-hover: -color-bg-subtle;
- -color-button-fg-hover: -color-button-fg;
- -color-button-border-hover: -color-bg-subtle;
- -color-button-bg-focused: -color-button-bg;
- -color-button-fg-focused: -color-button-fg;
- -color-button-border-focused: -color-button-bg;
- -color-button-bg-pressed: -color-button-bg;
- -color-button-fg-pressed: -color-button-fg;
- -color-button-border-pressed: transparent;
-}
-
-
-.toggle-button {
- -color-button-bg: -color-bg-subtle;
- -color-button-fg: -color-fg-default;
- -color-button-border: -color-border-default;
- -color-button-bg-hover: -color-base-6;
- -color-button-fg-hover: -color-button-fg;
- -color-button-border-hover: -color-button-border;
- -color-button-bg-focused: -color-button-bg;
- -color-button-fg-focused: -color-button-fg;
- -color-button-border-focused: -color-accent-emphasis;
- -color-button-bg-pressed: -color-bg-subtle;
- -color-button-fg-pressed: -color-button-fg;
- -color-button-border-pressed: transparent;
- -fx-background-color: -color-button-border, -color-button-bg;
- -fx-background-insets: 0, 1px;
- -fx-background-radius: 4px;
- -fx-graphic-text-gap: 6px;
- -fx-text-fill: -color-button-fg;
- -fx-alignment: CENTER;
- -color-button-bg-selected: -color-accent-emphasis;
- -color-button-fg-selected: -color-fg-emphasis;
- -fx-padding: 8px 12px 8px 12px;
-}
-
-
-.list-view {
- -color-cell-bg: -color-bg-default;
- -color-cell-fg: -color-fg-default;
- -color-cell-bg-selected: -color-base-6;
- -color-cell-fg-selected: -color-fg-default;
- -color-cell-bg-odd: -color-bg-subtle;
- -color-cell-border: -color-border-default;
- -fx-border-color: -color-cell-border;
- -fx-border-width: 1px;
- -fx-border-radius: 0;
-}
-
-.table-view {
- -color-cell-bg: -color-bg-default;
- -color-cell-fg: -color-fg-default;
- -color-cell-bg-selected: -color-base-6;
- -color-cell-fg-selected: -color-fg-default;
- -color-cell-bg-odd: -color-bg-subtle;
- -color-cell-border: -color-border-default;
- -fx-border-color: -color-cell-border;
- -fx-border-width: 1px;
- -fx-border-radius: 0;
- -color-header-bg: -color-bg-subtle;
- -color-header-fg: -color-fg-default;
-}
-
-.titled-pane > .title > .text {
- -fx-font-size: 1em;
-}
-
-.tree-view {
- -color-cell-bg: -color-bg-default;
- -color-cell-fg: -color-fg-default;
- -color-cell-bg-selected: -color-base-6;
- -color-cell-fg-selected: -color-fg-default;
- -color-cell-bg-odd: -color-bg-subtle;
- -color-cell-border: -color-border-default;
- -fx-border-color: -color-cell-border;
- -fx-border-width: 1px;
- -fx-border-radius: 0;
-}
-
-.tree-table-view {
- -color-cell-bg: -color-bg-default;
- -color-cell-fg: -color-fg-default;
- -color-cell-bg-selected: -color-base-6;
- -color-cell-fg-selected: -color-fg-default;
- -color-cell-bg-odd: -color-bg-subtle;
- -color-cell-border: -color-border-default;
- -fx-border-color: -color-cell-border;
- -fx-border-width: 1px;
- -fx-border-radius: 0;
- -color-header-bg: -color-bg-subtle;
- -color-header-fg: -color-fg-default;
-}
-
-.list-view:focused > .virtual-flow > .clipped-container > .sheet > .list-cell:filled:selected,
-.tree-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-cell:filled:selected,
-.table-view:focused > .virtual-flow > .clipped-container > .sheet > .table-row-cell:filled:selected,
-.tree-table-view:focused > .virtual-flow > .clipped-container > .sheet > .tree-table-row-cell:filled:selected {
- -color-cell-fg: -color-cell-fg-selected;
- -fx-background-color: -color-cell-border, -color-cell-bg-selected;
-}
-
/*******************************************************************************
* *
* ikonli icons *
@@ -402,54 +61,50 @@
-fx-effect: none;
}
+/*******************************************************************************
+ * *
+ * Label *
+ * *
+ ******************************************************************************/
-/****************************************************************
-
- ScrollPane
-
-****************************************************************/
-.scroll-pane {
- -fx-background: #0d1117;
- -fx-background-color: transparent;
-}
-
-.scroll-pane > .viewport {
- -fx-background-color: transparent;
-}
-
-.scroll-pane-dark {
- -fx-background: -fx-darkbackground;
- -fx-background-color: -fx-darkbackground;
+
+#label-title1 {
+ -fx-font: bold 14pt -fx-font-family;
}
+#label-title2 {
+ -fx-font: bold 13pt -fx-font-family;
+ }
/*******************************************************************************
* *
- * Hiding Tab *
+ * Validator *
* *
******************************************************************************/
- #hide-tab {
- -fx-background-color: transparent;
- -fx-border-radius: 5 5 0 0;
- -fx-background-radius: 5 5 0 0;
- -fx-border-color: -fx-border_col;
+
+
+.validatorfx-error {
+ -fx-text-fill: rgb(164, 0, 0);
}
- #show-tab {
- -fx-background-color: transparent;
- -fx-border-radius: 5 5 0 0;
- -fx-background-radius: 5 5 0 0;
- -fx-border-color: -fx-border_col;
+.validatorfx-warning {
+ -fx-text-fill: rgb(196, 160, 0);
}
- #hide-tab-highlight {
- -fx-background-color: -fx-highlight;
- -fx-border-radius: 5 5 0 0;
- -fx-background-radius: 5 5 0 0;
- -fx-border-color: -fx-highlight_border;
-}
+/********************************************
+* *
+* Chart *
+* *
+*********************************************/
+
+
+
+.thin-chart .chart-series-line {
+ -fx-stroke-width: 1px;
+}
+
/*******************************************************************************
* *
@@ -475,13 +130,14 @@
-fx-border-color: -fx-highlight;
}
*/
+
/**
* Button for closing a hiding panel. Right indicates bottoms points towards the right, closing a hiding panel
* on the right hand side of the screen. These buttons have a transparent background and rounded corners.
*/
/** top-left, top-right, bottom-right, and bottom-left corners, in that order. */
.close-button-right{
- -fx-background-color: transparent;
+ -fx-background-color: -fx-darkbackground-trans;
-fx-background-radius: 0 10 10 0;
-fx-border-color: transparent;
-fx-border-radius: 0 10 10 0;
@@ -489,7 +145,7 @@
.close-button-left{
- -fx-background-color: transparent;
+ -fx-background-color: -fx-darkbackground-trans;
-fx-background-radius: 10 0 0 10;
-fx-border-color: transparent;
-fx-border-radius: 10 0 0 10;
@@ -497,21 +153,22 @@
.close-button-top{
- -fx-background-color: transparent;
+ -fx-background-color: -fx-darkbackground-trans;
-fx-background-radius: 10 10 0 0;
--fx-border-color: transparent;
+ -fx-border-color: transparent;
-fx-border-radius: 10 10 0 0;
}
.close-button-bottom{
- -fx-background-color: transparent;
+ -fx-background-color: -fx-darkbackground-trans;
-fx-background-radius: 0 0 10 10;
- -fx-border-color: transparent;
+ -fx-border-color: transparent;
-fx-border-radius: 0 0 10 10;
}
+
.close-button-bottom-trans{
-fx-border-color: transparent;
-fx-background-color: transparent;
@@ -577,7 +234,8 @@
.popover > .content {
-fx-background-color: -fx-darkbackground;
-fx-background-radius: 5;
- -fx-border-radius: 5;
+ -fx-border-radius: 5;
+ -fx-padding: 0 0 0 0;
}
.popover > .arrow {
@@ -636,8 +294,11 @@
}
-/**********/
-
+/*******************************************************************************
+ * *
+ * Menu Items *
+ * *
+ ******************************************************************************/
.menu-item {
-fx-background-color: -color-bg-default;
@@ -671,8 +332,6 @@
* Spinner *
* *
*********************************************/
-
-
.spinner {
-fx-pref-width: 120px;
}
@@ -682,98 +341,89 @@
}
+/****************************************************************
+
+ ScrollPane
+
+****************************************************************/
+.scroll-pane {
+ -fx-background: #0d1117;
+ -fx-background-color: transparent;
+}
+
+.scroll-pane > .viewport {
+ -fx-background-color: transparent;
+}
+
+.scroll-pane-dark {
+ -fx-background: -fx-darkbackground;
+ -fx-background-color: -fx-darkbackground;
+}
+
/*******************************************************************************
* *
- * Hiding Pane *
+ * Hiding Tab *
+ * *
+ ******************************************************************************/
+ #hide-tab {
+ -fx-background-color: transparent;
+ -fx-border-radius: 5 5 0 0;
+ -fx-background-radius: 5 5 0 0;
+ -fx-border-color: -fx-border_col;
+}
+
+ #show-tab {
+ -fx-background-color: transparent;
+ -fx-border-radius: 5 5 0 0;
+ -fx-background-radius: 5 5 0 0;
+ -fx-border-color: -fx-border_col;
+}
+
+ #hide-tab-highlight {
+ -fx-background-color: -fx-highlight;
+ -fx-border-radius: 5 5 0 0;
+ -fx-background-radius: 5 5 0 0;
+ -fx-border-color: -fx-highlight_border;
+}
+
+/*******************************************************************************
+ * *
+ * Pam Internal Pane *
+ * *
+ ******************************************************************************/
+
+.circle-internal {
+ -fx-fill: -fx-highlight_settings;
+ -fx-stroke: -fx-highlight_border_settings;
+ -fx-stroke-width: 2;
+}
+
+.line-internal {
+ -fx-fill: -fx-highlight_border_settings;
+ -fx-stroke: -fx-highlight_border_settings;
+ -fx-stroke-width: 3;
+ -fx-stroke-dash-array: 3.0 7.0 3.0 7.0;
+}
+
+.button-internal {
+ -fx-background-color: -fx-highlight_settings;
+ -fx-border-color: -fx-highlight_border_settings;
+ -fx-background-radius: 10;
+ -fx-border-radius: 10;
+}
+
+.button-internal:hover {
+ -fx-background-color: -fx-highlight_border_settings;
+}
+
+/*******************************************************************************
+ * *
+ * Dialog *
* *
******************************************************************************/
-/**
- * Button for closing a hiding panel. Right indicates bottoms points towards the right, closing a hiding panel
- * on the right hand side of the screen. These buttons have a transparent background and rounded corners.
- */
- /** top-left, top-right, bottom-right, and bottom-left corners, in that order. */
-.close-button-right{
- -fx-background-color: transparent;
- -fx-background-radius: 0 10 10 0;
- -fx-border-radius: 0 10 10 0;
-}
-
-.close-button-right:hover {
- -fx-background-color: -fx-highlight;
-}
-
-
-.close-button-left{
- -fx-background-color: transparent;
- -fx-background-radius: 10 0 0 10;
- -fx-border-radius: 10 0 0 10;
-}
-
-.close-button-left:hover {
- -fx-background-color: -fx-highlight;
-}
-
-
-.close-button-top{
- -fx-background-color: transparent;
- -fx-background-radius: 10 10 0 0;
- -fx-border-radius: 10 10 0 0;
-}
-
-
-.close-button-bottom {
- -fx-background-color: transparent;
- -fx-background-radius: 0 0 10 10;
- -fx-border-radius: 0 0 10 10;
-}
-
-.close-button-bottom:hover {
- -fx-background-color: -fx-highlight;
-}
-
-
-.close-button-bottom-grey{
--fx-border-color: transparent;
- -fx-background-radius: 0 0 10 10;
- -fx-border-radius: 0 0 10 10;
-}
-
-.close-button-left-trans{
- -fx-border-color: transparent;
- -fx-background-color: transparent;
- -fx-background-radius: 10 0 0 10;
- -fx-border-radius: 10 0 0 10;
-}
-
-.close-button-left-trans:focused {
- -fx-border-color: transparent;
- -fx-background-color: transparent;
- -fx-background-radius: 10 0 0 10;
- -fx-border-radius: 10 0 0 10;
-}
-
-.close-button-right-trans{
- -fx-border-color: transparent;
- -fx-background-color: transparent;
- -fx-background-radius: 0 10 10 0;
- -fx-border-radius: 0 10 10 0;
-}
-
-.close-button-right-trans:focused {
- -fx-border-color: transparent;
- -fx-background-color: transparent;
- -fx-background-radius: 0 10 10 0;
- -fx-border-radius: 0 10 10 0;
-}
-
-
-.menu-square-button {
--fx-border-color: -fx_border_col;
- -fx-background-color: transparent;
- -fx-background-radius: 0 0 0 0;
- -fx-border-radius: 0 0 0 0;
-}
-
+.dialog-pane > .content {
+ -fx-padding: 0,0,0,0;
+}
\ No newline at end of file
diff --git a/src/Resources/delphinid_logo01.svg b/src/Resources/delphinid_logo01.svg
new file mode 100644
index 00000000..744670bf
--- /dev/null
+++ b/src/Resources/delphinid_logo01.svg
@@ -0,0 +1,114 @@
+
+
+
+
diff --git a/src/Resources/exampleSounds/Blue_whale.wav b/src/Resources/exampleSounds/Blue_whale.wav
new file mode 100644
index 00000000..8bca2058
Binary files /dev/null and b/src/Resources/exampleSounds/Blue_whale.wav differ
diff --git a/src/Resources/modules/Array Icon2.svg b/src/Resources/modules/Array Icon2.svg
new file mode 100644
index 00000000..2ca3e501
--- /dev/null
+++ b/src/Resources/modules/Array Icon2.svg
@@ -0,0 +1,21 @@
+
+
+
+
diff --git a/src/Resources/modules/Click Detector Icon.svg b/src/Resources/modules/Click Detector Icon.svg
new file mode 100644
index 00000000..25f15d3e
--- /dev/null
+++ b/src/Resources/modules/Click Detector Icon.svg
@@ -0,0 +1,296 @@
+
+
+
+
diff --git a/src/Resources/modules/clicktrain.svg b/src/Resources/modules/clicktrain.svg
new file mode 100644
index 00000000..046aa6fe
--- /dev/null
+++ b/src/Resources/modules/clicktrain.svg
@@ -0,0 +1,393 @@
+
+
+
+
diff --git a/src/Resources/modules/decimator.svg b/src/Resources/modules/decimator.svg
new file mode 100644
index 00000000..79be1add
--- /dev/null
+++ b/src/Resources/modules/decimator.svg
@@ -0,0 +1,482 @@
+
+
+
+
diff --git a/src/Resources/modules/detectionDisplay.svg b/src/Resources/modules/detectionDisplay.svg
new file mode 100644
index 00000000..8ed70427
--- /dev/null
+++ b/src/Resources/modules/detectionDisplay.svg
@@ -0,0 +1,32 @@
+
+
+
+
diff --git a/src/Resources/modules/fft.svg b/src/Resources/modules/fft.svg
new file mode 100644
index 00000000..f65bbefc
--- /dev/null
+++ b/src/Resources/modules/fft.svg
@@ -0,0 +1,178 @@
+
+
+
+
diff --git a/src/Resources/modules/filters.svg b/src/Resources/modules/filters.svg
new file mode 100644
index 00000000..8997d124
--- /dev/null
+++ b/src/Resources/modules/filters.svg
@@ -0,0 +1,331 @@
+
+
+
+
diff --git a/src/Resources/modules/matched_click_classifier.svg b/src/Resources/modules/matched_click_classifier.svg
new file mode 100644
index 00000000..9ec8e0c8
--- /dev/null
+++ b/src/Resources/modules/matched_click_classifier.svg
@@ -0,0 +1,483 @@
+
+
+
+
diff --git a/src/binaryFileStorage/BinaryMapMakeProgress.java b/src/binaryFileStorage/BinaryMapMakeProgress.java
index 02e13578..3cb8a10e 100644
--- a/src/binaryFileStorage/BinaryMapMakeProgress.java
+++ b/src/binaryFileStorage/BinaryMapMakeProgress.java
@@ -87,42 +87,30 @@ public class BinaryMapMakeProgress extends PamTaskUpdate {
@Override
public double getProgress(){
- //System.out.println("BinaryProgress: " + currentStream + " tot: " + totalStreams);
+// System.out.println("BinaryProgress: " + currentStream + " of: " + totalStreams + " status: " + getStatus());
if (totalStreams==0) return 1.;
double progress = 0;
switch (getStatus()){
- case PamTaskUpdate.STATUS_ANALYSING_FILES:
- if (totalStreams==0) progress=0;
+ case STATUS_ANALYSING_FILES:
+ if (totalStreams==0) progress=-1;
else progress=((double) currentStream)/totalStreams;
break;
- case PamTaskUpdate.STATUS_COUNTING_FILES:
- progress=ProgressIndicator.INDETERMINATE_PROGRESS;
- break;
- case PamTaskUpdate.STATUS_DESERIALIZING:
- progress=ProgressIndicator.INDETERMINATE_PROGRESS;
- break;
- case PamTaskUpdate.STATUS_DONE:
- progress=ProgressIndicator.INDETERMINATE_PROGRESS;
- break;
- case PamTaskUpdate.STATUS_DONE_ERROR:
- progress=ProgressIndicator.INDETERMINATE_PROGRESS;
- break;
- case PamTaskUpdate.STATUS_IDLE:
- progress=ProgressIndicator.INDETERMINATE_PROGRESS;
- break;
- case PamTaskUpdate.STATUS_SERIALIZING:
- progress=ProgressIndicator.INDETERMINATE_PROGRESS;
- break;
- case PamTaskUpdate.STATUS_SORTING:
+ default:
progress=ProgressIndicator.INDETERMINATE_PROGRESS;
break;
}
return progress;
}
+
@Override
public String getName() {
return "Binary Data Map";
}
+
+ @Override
+ public String getProgressString() {
+ return this.streamName;
+ }
}
diff --git a/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierWorker.java b/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierWorker.java
index 6a52b01c..15af8d1d 100644
--- a/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierWorker.java
+++ b/src/clickDetector/ClickClassifiers/basicSweep/SweepClassifierWorker.java
@@ -629,7 +629,8 @@ public class SweepClassifierWorker {
* @return true if bearing limits are passed
*/
private boolean testBearings(ClickDetection click, SweepClassifierSet scs) {
-
+ if (click.getLocalisation()==null) return true;
+
if (click.getLocalisation().getAngles()==null) return true; //passes the test if there is no bearing info.
double bearing = click.getLocalisation().getAngles()[0];
diff --git a/src/clickDetector/ClickTemplate.java b/src/clickDetector/ClickTemplate.java
index 61a4b4ef..3d778229 100644
--- a/src/clickDetector/ClickTemplate.java
+++ b/src/clickDetector/ClickTemplate.java
@@ -1,7 +1,6 @@
package clickDetector;
import java.awt.Color;
-import java.awt.Paint;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
diff --git a/src/clickDetector/ClickTrainDetector.java b/src/clickDetector/ClickTrainDetector.java
index a0141e03..8bfe6bb3 100644
--- a/src/clickDetector/ClickTrainDetector.java
+++ b/src/clickDetector/ClickTrainDetector.java
@@ -58,7 +58,6 @@ public class ClickTrainDetector extends PamProcess implements PamSettings {
this.clickDataBlock = clickDataBlock;
-
PamSettingManager.getInstance().registerSettings(this);
clickDataBlock.addObserver(this);
diff --git a/src/clickDetector/layoutFX/ClickSettingsPane.java b/src/clickDetector/layoutFX/ClickSettingsPane.java
index a62f3be0..1f10f122 100644
--- a/src/clickDetector/layoutFX/ClickSettingsPane.java
+++ b/src/clickDetector/layoutFX/ClickSettingsPane.java
@@ -7,20 +7,18 @@ import clickDetector.ClickControl;
import clickDetector.ClickParameters;
import clickDetector.layoutFX.clickClassifiers.ClickClassifyPaneFX;
import javafx.geometry.HPos;
+import javafx.geometry.Insets;
import javafx.geometry.Orientation;
-import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;
import javafx.scene.control.Tab;
-import javafx.scene.control.TabPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
-import javafx.scene.paint.Color;
-import javafx.scene.shape.Line;
+import javafx.scene.layout.Region;
import javafx.util.StringConverter;
import net.synedra.validatorfx.Validator;
import PamController.PamController;
@@ -31,12 +29,12 @@ import PamguardMVC.PamConstants;
import PamguardMVC.PamDataBlock;
import PamguardMVC.PamRawDataBlock;
import pamViewFX.PamGuiManagerFX;
-import pamViewFX.fxNodes.PamBorderPane;
+import pamViewFX.fxGlyphs.PamGlyphDude;
import pamViewFX.fxNodes.PamGridPane;
import pamViewFX.fxNodes.PamHBox;
import pamViewFX.fxNodes.PamSpinner;
-import pamViewFX.fxNodes.PamTabPane;
import pamViewFX.fxNodes.PamVBox;
+import pamViewFX.fxNodes.navigationDrawer.NavigationDrawer;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import pamViewFX.fxNodes.utilityPanes.FilterPaneFX;
import pamViewFX.fxNodes.utilityPanes.GroupedSourcePaneFX;
@@ -68,7 +66,7 @@ public class ClickSettingsPane extends SettingsPane{
/**
* The main tab pane.
*/
- private PamTabPane pamTabbedPane;
+ private NavigationDrawer pamTabbedPane;
/**
* Pane for the pre-filter. The acoustic data detected click waveforms are extracted from but not
@@ -163,10 +161,6 @@ public class ClickSettingsPane extends SettingsPane{
*/
private Tab tdoaTab;
- /**
- * The main holder pane.
- */
- private PamBorderPane mainPane;
/**
* The default pane height.
@@ -176,7 +170,7 @@ public class ClickSettingsPane extends SettingsPane{
/**
* The default pane width
*/
- public static double PREF_PANE_WIDTH=560;
+ public static double PREF_PANE_WIDTH=750;
/**
@@ -188,14 +182,14 @@ public class ClickSettingsPane extends SettingsPane{
public ClickSettingsPane(ClickControl clickControl){
super(null);
- this.clickControl=clickControl;
- mainPane= new PamBorderPane();
+ this.clickControl=clickControl;
clickValidator = new PamValidator();
- pamTabbedPane=new PamTabPane();
- pamTabbedPane.setAddTabButton(false);
- pamTabbedPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
+ pamTabbedPane=new NavigationDrawer();
+// pamTabbedPane.setAddTabButton(false);
+// pamTabbedPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
+// pamTabbedPane.setStyle("-fx-background-color: blue;");
//create a combined detection and length pane
PamVBox detectionPane=new PamVBox();
@@ -211,9 +205,18 @@ public class ClickSettingsPane extends SettingsPane{
detectionPane.getChildren().add(createTriggerGraph());
//add everything to tabs.
- pamTabbedPane.getTabs().add(new Tab("Click Detection", detectionPane));
+ Tab clickDetectionTabe =new Tab("Click Detection", detectionPane);
+ clickDetectionTabe.setGraphic(PamGlyphDude.createPamIcon("mdi2w-waveform"));
+ detectionPane.setPadding(new Insets(5,5,5,5));
+ pamTabbedPane.getTabs().add(clickDetectionTabe);
+
+
clickDelayPane=createDelayPane();
- pamTabbedPane.getTabs().add(tdoaTab=new Tab("TDOA and Echoes", clickDelayPane.getContentNode()));
+ ((Region) clickDelayPane.getContentNode()).setPadding(new Insets(5,5,5,5));
+ tdoaTab=new Tab("TDOA and Echoes", clickDelayPane.getContentNode());
+ tdoaTab.setGraphic(PamGlyphDude.createPamIcon("mdi2a-av-timer"));
+ pamTabbedPane.getTabs().add(tdoaTab);
+
tdoaTab.setOnSelectionChanged((event)->{
if (pamTabbedPane.getSelectionModel().getSelectedItem()==tdoaTab){
//System.out.println("clickDelayPane: "+clickDelayPane);
@@ -225,11 +228,20 @@ public class ClickSettingsPane extends SettingsPane{
//pre filter pane.
preFilter=new FilterPaneFX(Orientation.VERTICAL);
- pamTabbedPane.getTabs().add(new Tab("Pre Filter", preFilter.getContentNode()));
+ ((Region) preFilter.getContentNode()).setPadding(new Insets(5,5,5,5));
+ Tab preFilterTab =new Tab("Pre Filter", preFilter.getContentNode());
+ preFilterTab.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chart-bell-curve-cumulative"));
+ pamTabbedPane.getTabs().add(preFilterTab);
//trigger pane
triggerFilter=new FilterPaneFX(Orientation.VERTICAL);
- pamTabbedPane.getTabs().add(new Tab("Trigger Filter", triggerFilter.getContentNode()));
+ ((Region) triggerFilter.getContentNode()).setPadding(new Insets(5,5,5,5));
+ Tab triggerFilterTab =new Tab("Trigger Filter", triggerFilter.getContentNode());
+ triggerFilterTab.setGraphic(PamGlyphDude.createPamIcon("mdi2c-chart-bell-curve"));
+ pamTabbedPane.getTabs().add(triggerFilterTab);
+
+
+
// //echo detection pane.
// echoDetection= new ClickEchoPane(clickControl);
@@ -238,15 +250,20 @@ public class ClickSettingsPane extends SettingsPane{
/***Note: FX does not implment click train detection in click detector****/
//classifiaction pane.
- pamTabbedPane.getTabs().add(new Tab("Classification", clickClassificationPane=new ClickClassifyPaneFX(clickControl)));
+ Tab classifierTab =new Tab("Classification", clickClassificationPane=new ClickClassifyPaneFX(clickControl));
+ classifierTab.setGraphic(PamGlyphDude.createPamIcon("mdi2g-graph"));
+ pamTabbedPane.getTabs().add(classifierTab);
- //want a slightly bigger pane as a lot going on in this dialog.
- //Note JavaFX 8u61 + has auto DPI scaling so this is really the size of a dialog on a standard HD monitor of
- //reasonable size, rather than actual pixels
- mainPane.setPrefSize(PREF_PANE_WIDTH, PREF_PANE_HEIGHT);
+// //want a slightly bigger pane as a lot going on in this dialog.
+// //Note JavaFX 8u61 + has auto DPI scaling so this is really the size of a dialog on a standard HD monitor of
+// //reasonable size, rather than actual pixels
+ pamTabbedPane.setMinSize(PREF_PANE_WIDTH, PREF_PANE_HEIGHT);
//addTabListeners();
- mainPane.setCenter(new PamBorderPane(pamTabbedPane));
+ pamTabbedPane.setPadding(new Insets(0,0,0,0));
+
+
+
}
// private void addTabListeners(){
@@ -890,7 +907,7 @@ public class ClickSettingsPane extends SettingsPane{
@Override
public Node getContentNode() {
- return mainPane;
+ return pamTabbedPane;
}
@Override
diff --git a/src/clickDetector/layoutFX/clickClassifiers/ClickTypeProperty.java b/src/clickDetector/layoutFX/clickClassifiers/ClickTypeProperty.java
index 23b41615..83370efd 100644
--- a/src/clickDetector/layoutFX/clickClassifiers/ClickTypeProperty.java
+++ b/src/clickDetector/layoutFX/clickClassifiers/ClickTypeProperty.java
@@ -11,6 +11,7 @@ import javafx.beans.property.StringProperty;
/**
* A property wrapper for a basic click with JavaFX properties. This is used so JavaFX controls
* automatically change.
+ *
* @author Jamie Macaulay
*
*/
@@ -23,11 +24,12 @@ public class ClickTypeProperty {
public ClickTypeProperty(ClickTypeCommonParams clickType){
- this.commonClickParams=clickType;
- name.setValue(clickType.getName());
- discardClassifier.setValue(clickType.getDiscard());
- code.setValue(clickType.getSpeciesCode());
-
+// this.commonClickParams=clickType;
+// name.setValue(clickType.getName());
+// discardClassifier.setValue(clickType.getDiscard());
+// code.setValue(clickType.getSpeciesCode());
+ setClickType( clickType);
+
}
public StringProperty name= new SimpleStringProperty("blank");
@@ -47,7 +49,7 @@ public class ClickTypeProperty {
this.commonClickParams = clickType;
//TODO-need to set properties;
name.setValue(clickType.getName());
- enableClassifier.setValue(clickType.enable);
+ enableClassifier.setValue(clickType.getEnable());
discardClassifier.setValue(clickType.getDiscard());
code.setValue(clickType.getSpeciesCode());
}
diff --git a/src/clickDetector/layoutFX/clickClassifiers/SweepClassifierPaneFX.java b/src/clickDetector/layoutFX/clickClassifiers/SweepClassifierPaneFX.java
index ba4fbf5e..a300684c 100644
--- a/src/clickDetector/layoutFX/clickClassifiers/SweepClassifierPaneFX.java
+++ b/src/clickDetector/layoutFX/clickClassifiers/SweepClassifierPaneFX.java
@@ -52,8 +52,7 @@ public class SweepClassifierPaneFX extends BasicIdentifierPaneFX {
getFlipPane().getAdvLabel().textProperty().unbind();
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());
+ getFlipPane().getPreAdvLabel().graphicProperty().bind(sweepPane.getNameGraphicProperty());
sweepPane.classifierItemRow = sweepClickClassifier.getSweepClassifierParams().getSetRow((SweepClassifierSet) clickTypeProperty.getClickType());
diff --git a/src/clickDetector/layoutFX/clickClassifiers/SweepClassifierSetPaneFX.java b/src/clickDetector/layoutFX/clickClassifiers/SweepClassifierSetPaneFX.java
index a86f27f5..b464813a 100644
--- a/src/clickDetector/layoutFX/clickClassifiers/SweepClassifierSetPaneFX.java
+++ b/src/clickDetector/layoutFX/clickClassifiers/SweepClassifierSetPaneFX.java
@@ -4,9 +4,12 @@ package clickDetector.layoutFX.clickClassifiers;
import fftFilter.FFTFilterParams;
import fftManager.FFTLengthModeled;
import javafx.beans.property.StringProperty;
+import javafx.beans.value.ObservableValue;
+import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
+import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
@@ -19,9 +22,11 @@ import javafx.scene.control.TabPane;
import javafx.scene.control.TabPane.TabClosingPolicy;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
+import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.scene.text.Font;
+import javafx.scene.canvas.Canvas;
import net.synedra.validatorfx.GraphicDecoration;
import net.synedra.validatorfx.ValidationMessage;
import net.synedra.validatorfx.Validator;
@@ -29,6 +34,7 @@ import pamViewFX.fxNodes.PamBorderPane;
import pamViewFX.fxNodes.PamGridPane;
import pamViewFX.fxNodes.PamHBox;
import pamViewFX.fxNodes.PamSpinner;
+import pamViewFX.fxNodes.PamSymbolFX;
import pamViewFX.fxNodes.PamVBox;
import pamViewFX.fxNodes.pamDialogFX.PamDialogFX;
import pamViewFX.fxNodes.picker.SymbolPicker;
@@ -39,19 +45,6 @@ import pamViewFX.fxNodes.utilsFX.PamUtilsFX;
import pamViewFX.PamGuiManagerFX;
import pamViewFX.fxGlyphs.PamGlyphDude;
-import java.awt.BorderLayout;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-
-import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.List;
@@ -60,7 +53,6 @@ import javax.swing.JPanel;
import PamController.SettingsPane;
import PamUtils.PamUtils;
import PamView.PamSymbol;
-import PamView.dialog.PamGridBagContraints;
import PamView.symbol.SymbolData;
import clickDetector.ClickControl;
import clickDetector.ClickClassifiers.basicSweep.CodeHost;
@@ -125,13 +117,17 @@ public class SweepClassifierSetPaneFX extends SettingsPane {
*/
private AmplitudeBlock amplitudeBlock;
-
/**
- * Changes the bearing paramters fro clicks.
+ * Changes the bearing parameters for clicks.
*/
private BearingBlock bearingBox;
+
+ /**
+ * Allows classification based on correlation scores.
+ */
+ private XCorrBlock xCorrBox;
-
+
private PamBorderPane mainPane = new PamBorderPane();
@@ -183,15 +179,17 @@ public class SweepClassifierSetPaneFX extends SettingsPane {
spectrumHolder.setPadding(new Insets(10,0,0,0));
spectrumTab.setContent(spectrumHolder);
- /*********Spectrum Tab****************/
+ /*********Bearing Tab****************/
Tab bearingTab=new Tab("Bearing");
- spectrumTab.setGraphic(PamGlyphDude.createPamIcon("mdi2c-compass-outline", PamGuiManagerFX.iconSize));
+ bearingTab.setGraphic(PamGlyphDude.createPamIcon("mdi2c-compass-outline", PamGuiManagerFX.iconSize));
+ bearingTab.setStyle("-fx-font-size: 14px; -fx-font-weight: bold;");
PamVBox bearingHolder=new PamVBox(5);
bearingBox=new BearingBlock();
-
- bearingHolder.getChildren().addAll(bearingBox);
+ xCorrBox=new XCorrBlock();
+
+ bearingHolder.getChildren().addAll(bearingBox, xCorrBox);
bearingHolder.setPadding(new Insets(10,0,0,0));
bearingTab.setContent(bearingHolder);
@@ -200,7 +198,7 @@ public class SweepClassifierSetPaneFX extends SettingsPane {
TabPane tabPane= new TabPane();
tabPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
- tabPane.getTabs().addAll(waveformTab, spectrumTab);
+ tabPane.getTabs().addAll(waveformTab, spectrumTab, bearingTab);
holder.getChildren().add(optionBox);
holder.getChildren().add(tabPane);
@@ -237,7 +235,7 @@ public class SweepClassifierSetPaneFX extends SettingsPane {
private Font disableFont;
private Label label;
-
+
SweepBox(String borderTitle, Boolean enableButton) {
@@ -279,6 +277,9 @@ public class SweepClassifierSetPaneFX extends SettingsPane {
}
this.setTop(hBox);
+ //little bit of space between the top and bottom button.m
+ BorderPane.setMargin(hBox, new Insets(0,0,5,0));
+
/**Don't like this in old swing version*/
//tP.setCenter( description = new Label("", JLabel.CENTER));
@@ -356,12 +357,19 @@ public class SweepClassifierSetPaneFX extends SettingsPane {
/**
- * General options for the sweep classifier set
+ * General options for the sweep classifier set. This inlcudes, name, symbol, and some basics on
+ * what part of the click to analyse.
+ *
* @author Jamie Macaulay
*
*/
private class OptionsBox extends SweepBox implements FFTLengthModeled, CodeHost {
+ /**
+ * The size of the preview symbol to show next to the title
+ */
+ private static final double TITLE_SYMBOL_SIZE = 20.;
+
/**
* Text field to set classifier name.
*/
@@ -396,6 +404,13 @@ public class SweepClassifierSetPaneFX extends SettingsPane {
* Shows lengths of extraction samples in millis.
*/
private Label lengthMS;
+
+ /**
+ * The property for the PAMSymbol
+ */
+ private SimpleObjectProperty