diff --git a/output/graph - plotter.png b/output/graph - plotter.png index 28e6167..3d569c7 100644 Binary files a/output/graph - plotter.png and b/output/graph - plotter.png differ diff --git a/src/apps/MapAnalyzer.java b/src/apps/MapAnalyzer.java index 47056ec..2b42cdf 100644 --- a/src/apps/MapAnalyzer.java +++ b/src/apps/MapAnalyzer.java @@ -24,7 +24,8 @@ package apps; import java.io.File; import java.io.IOException; -import java.util.function.DoubleFunction; +import java.util.function.DoubleUnaryOperator; + import javax.imageio.ImageIO; import dialogs.ProgressBarDialog; @@ -145,14 +146,14 @@ public class MapAnalyzer extends MapApplication { private Region buildTextDisplay() { - this.avgSizeDistort = new Text(". . ."); - this.avgShapeDistort = new Text(". . ."); + this.avgSizeDistort = new Text("..."); + this.avgShapeDistort = new Text("..."); final Text txt = new Text("Blue areas are dilated, red areas are compressed, and black areas are stretched."); txt.setWrappingWidth(GUI_WIDTH); VBox box = new VBox(3, - new HBox(new Label("Average area distortion: "), avgSizeDistort), - new HBox(new Label("Average angle distortion: "), avgShapeDistort), + new HBox(new Label("Average size distortion: "),avgSizeDistort), + new HBox(new Label("Average shape distortion: "),avgShapeDistort), txt); box.setAlignment(Pos.CENTER_LEFT); return box; @@ -172,7 +173,7 @@ public class MapAnalyzer extends MapApplication { this.shapeChart = new BarChart(new CategoryAxis(), new NumberAxis()); this.shapeChart.setPrefWidth(CHART_WIDTH); this.shapeChart.setPrefHeight(IMG_WIDTH/2); - this.shapeChart.getXAxis().setLabel("Angle displacement"); + this.shapeChart.getXAxis().setLabel("Stretch factor"); this.shapeChart.setBarGap(0); this.shapeChart.setCategoryGap(0); this.shapeChart.setAnimated(false); @@ -189,8 +190,8 @@ public class MapAnalyzer extends MapApplication { sizeChart.getData().clear(); shapeChart.getData().clear(); - avgSizeDistort.setText("\u2026"); - avgShapeDistort.setText("\u2026"); + avgSizeDistort.setText("..."); + avgShapeDistort.setText("..."); }); loadParameters(); @@ -204,13 +205,13 @@ public class MapAnalyzer extends MapApplication { final double[][][] distortionG = proj.calculateDistortion(Projection.globe(GLOBE_RES)); Platform.runLater(() -> { - sizeChart.getData().add(histogram(distortionG[0], -LN_10, LN_10, 20, - (x) -> Double.toString(Math.round(100*Math.exp(x))/100.))); - shapeChart.getData().add(histogram(distortionG[1], 0.0, Math.PI/2, 18, - (x) -> Integer.toString((int) Math.toDegrees(x))+"\u00B0")); + sizeChart.getData().add(histogram(distortionG[0], + -LN_10, LN_10, 20, Math::exp)); + shapeChart.getData().add(histogram(distortionG[1], + 0.0, LN_10, 20, Math::exp)); - avgSizeDistort.setText(format(Math2.toDecibels(Math2.stdDev(distortionG[0])))+"dB"); - avgShapeDistort.setText(format(Math.toDegrees(Math2.mean(distortionG[1])))+"\u00B0"); + avgSizeDistort.setText(format(Math2.stdDev(distortionG[0])/LN_10*10)); + avgShapeDistort.setText(format(Math2.mean(distortionG[1])/LN_10*10)); enable(ButtonType.UPDATE_MAP, ButtonType.SAVE_GRAPH); }); @@ -270,7 +271,7 @@ public class MapAnalyzer extends MapApplication { for (int x = 0; x < distortion[0][y].length; x ++) { final double sizeDistort = distortion[0][y][x], shapeDistort = distortion[1][y][x]; final double sizeContour = Math.round(sizeDistort/(LN_10/10))*LN_10/10; //contour the size by decibels - final double shapeContour = Math.round(shapeDistort/(Math.PI/36))*Math.PI/36; //contour the size by semidecibels + final double shapeContour = Math.round(shapeDistort/(LN_10/20))*LN_10/20; //contour the size by semidecibels if (Double.isNaN(sizeDistort) || Double.isNaN(shapeDistort)) { writer.setArgb(x, y, 0); continue; @@ -278,14 +279,14 @@ public class MapAnalyzer extends MapApplication { final int r, g, b; if (sizeDistort < 0) { //if compressing - r = (int)(255.9*(1-shapeContour/(Math.PI/2))); - g = (int)(255.9*(1-shapeContour/(Math.PI/2))*Math.exp(sizeContour*.6)); + r = (int)(255.9*Math.exp(-shapeContour*.6)); + g = (int)(255.9*Math.exp(-shapeContour*.6)*Math.exp(sizeContour*.6)); b = g; } else { //if dilating - r = (int)(255.9*(1-shapeContour/(Math.PI/2))*Math.exp(-sizeContour*.6)); + r = (int)(255.9*Math.exp(-shapeContour*.6)*Math.exp(-sizeContour*.6)); g = r; //I find .6 to be a rather visually pleasing sensitivity - b = (int)(255.9*(1-shapeContour/(Math.PI/2))); + b = (int)(255.9*Math.exp(-shapeContour*.6)); } final int argb = ((((((0xFF)<<8)+r)<<8)+g)<<8)+b; @@ -297,7 +298,7 @@ public class MapAnalyzer extends MapApplication { private static final Series histogram(double[][] values, - double min, double max, int num, DoubleFunction converter) { + double min, double max, int num, DoubleUnaryOperator converter) { int[] hist = new int[num+1]; //this array is the histogram values for min, min+dx, ..., max-dx, max int tot = 0; for (double[] row: values) { @@ -312,8 +313,9 @@ public class MapAnalyzer extends MapApplication { } Series output = new Series(); for (int i = 0; i <= num; i ++) { + double x = converter.applyAsDouble(i*(max-min)/num+min); output.getData().add(new Data( - converter.apply(i*(max-min)/num+min), + Double.toString(Math.round(100*x)/100.), (double)hist[i]/tot*100)); } return output; diff --git a/src/apps/MapApplication.java b/src/apps/MapApplication.java index 3b105e0..f12c7ce 100644 --- a/src/apps/MapApplication.java +++ b/src/apps/MapApplication.java @@ -42,6 +42,7 @@ import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Pos; +import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Button; @@ -68,7 +69,6 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; -import javafx.scene.paint.Color; import javafx.scene.text.Text; import javafx.stage.FileChooser; import javafx.stage.Stage; @@ -183,7 +183,7 @@ public abstract class MapApplication extends Application { public void start(Stage root) { this.root = root; this.root.setTitle(this.name); - this.root.setScene(new Scene(new StackPane(makeWidgets()), Color.ANTIQUEWHITE)); //Why can't I set this color? + this.root.setScene(new Scene(new StackPane(makeWidgets()))); this.root.show(); this.suppressListeners.set(); @@ -192,7 +192,7 @@ public abstract class MapApplication extends Application { } - protected abstract Region makeWidgets(); + protected abstract Node makeWidgets(); /** diff --git a/src/apps/MapPlotter.java b/src/apps/MapPlotter.java index 91edc8c..55a4bfb 100644 --- a/src/apps/MapPlotter.java +++ b/src/apps/MapPlotter.java @@ -47,18 +47,19 @@ import javafx.scene.control.Label; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.StackPane; import javafx.stage.Stage; -import maps.Arbitrary; import maps.Azimuthal; import maps.CahillKeyes; import maps.Cylindrical; import maps.Lenticular; import maps.Misc; -import maps.Polyhedral; +import maps.MyProjections; import maps.Projection; import maps.Pseudocylindrical; +import maps.Arbitrary; +import maps.Polyhedral; import maps.Tobler; +import maps.Waterman; import maps.WinkelTripel; -import utils.Math2; /** * A simple script that creates an annotated ScatterPlot of map projections @@ -66,6 +67,8 @@ import utils.Math2; * @author jkunimune */ public class MapPlotter extends Application { + + private static final double DECIBEL = Math.log(10)/10; private static final double GLOBE_RES = .005; @@ -98,7 +101,7 @@ public class MapPlotter extends Application { final ScatterChart plot = new ScatterChart( new NumberAxis("Size distortion", 0, 4, .5), - new NumberAxis("Shape distortion", 0, 20, 5)); + new NumberAxis("Shape distortion", 0, 3, .5)); plot.setLegendSide(Side.RIGHT); final AnchorPane overlay = new AnchorPane(); stack = new StackPane(plot, overlay); @@ -149,7 +152,7 @@ public class MapPlotter extends Application { final double[] params = projection.getDefaultParameters(); final double distortion[] = projection.avgDistortion(points, params); final Data datum = new Data( - Math2.toDecibels(distortion[0]), Math.toDegrees(distortion[1])); + distortion[0]/DECIBEL, distortion[1]/DECIBEL); series.getData().add(datum); final Label lbl = new Label(projection.getName()); overlay.getChildren().add(lbl); diff --git a/src/maps/Azimuthal.java b/src/maps/Azimuthal.java index c558097..5142a82 100644 --- a/src/maps/Azimuthal.java +++ b/src/maps/Azimuthal.java @@ -90,7 +90,7 @@ public class Azimuthal { 4, 4, 0b0111, Type.AZIMUTHAL, Property.GNOMONIC, 2) { public double[] project(double lat, double lon) { - if (lat < 0.01) lat = 0.01; + if (lat < 0.2) lat = 0.2; final double r = Math.tan(Math.PI/2 - lat); return new double[] { r*Math.sin(lon), -r*Math.cos(lon)}; } diff --git a/src/maps/Projection.java b/src/maps/Projection.java index 63aca46..b3b17ee 100644 --- a/src/maps/Projection.java +++ b/src/maps/Projection.java @@ -367,9 +367,8 @@ public abstract class Projection { final double s1ps2 = Math.hypot((pE[0]-pC[0])+(pN[1]-pC[1]), (pE[1]-pC[1])-(pN[0]-pC[0])); final double s1ms2 = Math.hypot((pE[0]-pC[0])-(pN[1]-pC[1]), (pE[1]-pC[1])+(pN[0]-pC[0])); - final double sig = Math.abs((s1ps2+s1ms2)/(s1ps2-s1ms2)); - output[1] = Math.atan((sig - 1)/Math.sqrt(sig)/2); //the first output is the shape (angle) distortion - if (sig > 1e10) + output[1] = Math.abs(Math.log(Math.abs((s1ps2-s1ms2)/(s1ps2+s1ms2)))); //the first output is the shape (angle) distortion + if (Math.abs(output[1]) > 25) output[1] = Double.NaN; //discard outliers return output; diff --git a/src/utils/Math2.java b/src/utils/Math2.java index d2d6757..36a51f9 100644 --- a/src/utils/Math2.java +++ b/src/utils/Math2.java @@ -171,11 +171,6 @@ public class Math2 { } - public static double toDecibels(double ratio) { - return ratio/Math.log(10)*10; - } - - public static double sind(double angdeg) { return Math.sin(Math.toRadians(angdeg)); }