mirror of
https://github.com/csharpee/Map-Projections.git
synced 2025-12-18 00:00:20 -05:00
Revert "Angles vs factors"
This reverts commit ed297dbd079f3cc1ce93cd3aeb2cd98a60be7351.
This commit is contained in:
parent
ed297dbd07
commit
00a3f2a25e
Binary file not shown.
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 46 KiB |
@ -24,7 +24,8 @@
|
|||||||
package apps;
|
package apps;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.function.DoubleFunction;
|
import java.util.function.DoubleUnaryOperator;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
import dialogs.ProgressBarDialog;
|
import dialogs.ProgressBarDialog;
|
||||||
@ -145,14 +146,14 @@ public class MapAnalyzer extends MapApplication {
|
|||||||
|
|
||||||
|
|
||||||
private Region buildTextDisplay() {
|
private Region buildTextDisplay() {
|
||||||
this.avgSizeDistort = new Text(". . .");
|
this.avgSizeDistort = new Text("...");
|
||||||
this.avgShapeDistort = new Text(". . .");
|
this.avgShapeDistort = new Text("...");
|
||||||
final Text txt = new Text("Blue areas are dilated, red areas are compressed, and black areas are stretched.");
|
final Text txt = new Text("Blue areas are dilated, red areas are compressed, and black areas are stretched.");
|
||||||
txt.setWrappingWidth(GUI_WIDTH);
|
txt.setWrappingWidth(GUI_WIDTH);
|
||||||
|
|
||||||
VBox box = new VBox(3,
|
VBox box = new VBox(3,
|
||||||
new HBox(new Label("Average area distortion: "), avgSizeDistort),
|
new HBox(new Label("Average size distortion: "),avgSizeDistort),
|
||||||
new HBox(new Label("Average angle distortion: "), avgShapeDistort),
|
new HBox(new Label("Average shape distortion: "),avgShapeDistort),
|
||||||
txt);
|
txt);
|
||||||
box.setAlignment(Pos.CENTER_LEFT);
|
box.setAlignment(Pos.CENTER_LEFT);
|
||||||
return box;
|
return box;
|
||||||
@ -172,7 +173,7 @@ public class MapAnalyzer extends MapApplication {
|
|||||||
this.shapeChart = new BarChart<String, Number>(new CategoryAxis(), new NumberAxis());
|
this.shapeChart = new BarChart<String, Number>(new CategoryAxis(), new NumberAxis());
|
||||||
this.shapeChart.setPrefWidth(CHART_WIDTH);
|
this.shapeChart.setPrefWidth(CHART_WIDTH);
|
||||||
this.shapeChart.setPrefHeight(IMG_WIDTH/2);
|
this.shapeChart.setPrefHeight(IMG_WIDTH/2);
|
||||||
this.shapeChart.getXAxis().setLabel("Angle displacement");
|
this.shapeChart.getXAxis().setLabel("Stretch factor");
|
||||||
this.shapeChart.setBarGap(0);
|
this.shapeChart.setBarGap(0);
|
||||||
this.shapeChart.setCategoryGap(0);
|
this.shapeChart.setCategoryGap(0);
|
||||||
this.shapeChart.setAnimated(false);
|
this.shapeChart.setAnimated(false);
|
||||||
@ -189,8 +190,8 @@ public class MapAnalyzer extends MapApplication {
|
|||||||
sizeChart.getData().clear();
|
sizeChart.getData().clear();
|
||||||
shapeChart.getData().clear();
|
shapeChart.getData().clear();
|
||||||
|
|
||||||
avgSizeDistort.setText("\u2026");
|
avgSizeDistort.setText("...");
|
||||||
avgShapeDistort.setText("\u2026");
|
avgShapeDistort.setText("...");
|
||||||
});
|
});
|
||||||
|
|
||||||
loadParameters();
|
loadParameters();
|
||||||
@ -204,13 +205,13 @@ public class MapAnalyzer extends MapApplication {
|
|||||||
final double[][][] distortionG = proj.calculateDistortion(Projection.globe(GLOBE_RES));
|
final double[][][] distortionG = proj.calculateDistortion(Projection.globe(GLOBE_RES));
|
||||||
|
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
sizeChart.getData().add(histogram(distortionG[0], -LN_10, LN_10, 20,
|
sizeChart.getData().add(histogram(distortionG[0],
|
||||||
(x) -> Double.toString(Math.round(100*Math.exp(x))/100.)));
|
-LN_10, LN_10, 20, Math::exp));
|
||||||
shapeChart.getData().add(histogram(distortionG[1], 0.0, Math.PI/2, 18,
|
shapeChart.getData().add(histogram(distortionG[1],
|
||||||
(x) -> Integer.toString((int) Math.toDegrees(x))+"\u00B0"));
|
0.0, LN_10, 20, Math::exp));
|
||||||
|
|
||||||
avgSizeDistort.setText(format(Math2.toDecibels(Math2.stdDev(distortionG[0])))+"dB");
|
avgSizeDistort.setText(format(Math2.stdDev(distortionG[0])/LN_10*10));
|
||||||
avgShapeDistort.setText(format(Math.toDegrees(Math2.mean(distortionG[1])))+"\u00B0");
|
avgShapeDistort.setText(format(Math2.mean(distortionG[1])/LN_10*10));
|
||||||
|
|
||||||
enable(ButtonType.UPDATE_MAP, ButtonType.SAVE_GRAPH);
|
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 ++) {
|
for (int x = 0; x < distortion[0][y].length; x ++) {
|
||||||
final double sizeDistort = distortion[0][y][x], shapeDistort = distortion[1][y][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 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)) {
|
if (Double.isNaN(sizeDistort) || Double.isNaN(shapeDistort)) {
|
||||||
writer.setArgb(x, y, 0);
|
writer.setArgb(x, y, 0);
|
||||||
continue;
|
continue;
|
||||||
@ -278,14 +279,14 @@ public class MapAnalyzer extends MapApplication {
|
|||||||
|
|
||||||
final int r, g, b;
|
final int r, g, b;
|
||||||
if (sizeDistort < 0) { //if compressing
|
if (sizeDistort < 0) { //if compressing
|
||||||
r = (int)(255.9*(1-shapeContour/(Math.PI/2)));
|
r = (int)(255.9*Math.exp(-shapeContour*.6));
|
||||||
g = (int)(255.9*(1-shapeContour/(Math.PI/2))*Math.exp(sizeContour*.6));
|
g = (int)(255.9*Math.exp(-shapeContour*.6)*Math.exp(sizeContour*.6));
|
||||||
b = g;
|
b = g;
|
||||||
}
|
}
|
||||||
else { //if dilating
|
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
|
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;
|
final int argb = ((((((0xFF)<<8)+r)<<8)+g)<<8)+b;
|
||||||
@ -297,7 +298,7 @@ public class MapAnalyzer extends MapApplication {
|
|||||||
|
|
||||||
|
|
||||||
private static final Series<String, Number> histogram(double[][] values,
|
private static final Series<String, Number> histogram(double[][] values,
|
||||||
double min, double max, int num, DoubleFunction<String> 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[] hist = new int[num+1]; //this array is the histogram values for min, min+dx, ..., max-dx, max
|
||||||
int tot = 0;
|
int tot = 0;
|
||||||
for (double[] row: values) {
|
for (double[] row: values) {
|
||||||
@ -312,8 +313,9 @@ public class MapAnalyzer extends MapApplication {
|
|||||||
}
|
}
|
||||||
Series<String, Number> output = new Series<String, Number>();
|
Series<String, Number> output = new Series<String, Number>();
|
||||||
for (int i = 0; i <= num; i ++) {
|
for (int i = 0; i <= num; i ++) {
|
||||||
|
double x = converter.applyAsDouble(i*(max-min)/num+min);
|
||||||
output.getData().add(new Data<String, Number>(
|
output.getData().add(new Data<String, Number>(
|
||||||
converter.apply(i*(max-min)/num+min),
|
Double.toString(Math.round(100*x)/100.),
|
||||||
(double)hist[i]/tot*100));
|
(double)hist[i]/tot*100));
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@ -42,6 +42,7 @@ import javafx.application.Platform;
|
|||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Node;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
@ -68,7 +69,6 @@ import javafx.scene.layout.Priority;
|
|||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.paint.Color;
|
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
@ -183,7 +183,7 @@ public abstract class MapApplication extends Application {
|
|||||||
public void start(Stage root) {
|
public void start(Stage root) {
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.root.setTitle(this.name);
|
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.root.show();
|
||||||
|
|
||||||
this.suppressListeners.set();
|
this.suppressListeners.set();
|
||||||
@ -192,7 +192,7 @@ public abstract class MapApplication extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected abstract Region makeWidgets();
|
protected abstract Node makeWidgets();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -47,18 +47,19 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import maps.Arbitrary;
|
|
||||||
import maps.Azimuthal;
|
import maps.Azimuthal;
|
||||||
import maps.CahillKeyes;
|
import maps.CahillKeyes;
|
||||||
import maps.Cylindrical;
|
import maps.Cylindrical;
|
||||||
import maps.Lenticular;
|
import maps.Lenticular;
|
||||||
import maps.Misc;
|
import maps.Misc;
|
||||||
import maps.Polyhedral;
|
import maps.MyProjections;
|
||||||
import maps.Projection;
|
import maps.Projection;
|
||||||
import maps.Pseudocylindrical;
|
import maps.Pseudocylindrical;
|
||||||
|
import maps.Arbitrary;
|
||||||
|
import maps.Polyhedral;
|
||||||
import maps.Tobler;
|
import maps.Tobler;
|
||||||
|
import maps.Waterman;
|
||||||
import maps.WinkelTripel;
|
import maps.WinkelTripel;
|
||||||
import utils.Math2;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple script that creates an annotated ScatterPlot of map projections
|
* A simple script that creates an annotated ScatterPlot of map projections
|
||||||
@ -67,6 +68,8 @@ import utils.Math2;
|
|||||||
*/
|
*/
|
||||||
public class MapPlotter extends Application {
|
public class MapPlotter extends Application {
|
||||||
|
|
||||||
|
private static final double DECIBEL = Math.log(10)/10;
|
||||||
|
|
||||||
private static final double GLOBE_RES = .005;
|
private static final double GLOBE_RES = .005;
|
||||||
|
|
||||||
private static final Projection[] CYLINDRICAL = { Cylindrical.MERCATOR,
|
private static final Projection[] CYLINDRICAL = { Cylindrical.MERCATOR,
|
||||||
@ -98,7 +101,7 @@ public class MapPlotter extends Application {
|
|||||||
final ScatterChart<Number, Number> plot =
|
final ScatterChart<Number, Number> plot =
|
||||||
new ScatterChart<Number, Number>(
|
new ScatterChart<Number, Number>(
|
||||||
new NumberAxis("Size distortion", 0, 4, .5),
|
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);
|
plot.setLegendSide(Side.RIGHT);
|
||||||
final AnchorPane overlay = new AnchorPane();
|
final AnchorPane overlay = new AnchorPane();
|
||||||
stack = new StackPane(plot, overlay);
|
stack = new StackPane(plot, overlay);
|
||||||
@ -149,7 +152,7 @@ public class MapPlotter extends Application {
|
|||||||
final double[] params = projection.getDefaultParameters();
|
final double[] params = projection.getDefaultParameters();
|
||||||
final double distortion[] = projection.avgDistortion(points, params);
|
final double distortion[] = projection.avgDistortion(points, params);
|
||||||
final Data<Number, Number> datum = new Data<Number, Number>(
|
final Data<Number, Number> datum = new Data<Number, Number>(
|
||||||
Math2.toDecibels(distortion[0]), Math.toDegrees(distortion[1]));
|
distortion[0]/DECIBEL, distortion[1]/DECIBEL);
|
||||||
series.getData().add(datum);
|
series.getData().add(datum);
|
||||||
final Label lbl = new Label(projection.getName());
|
final Label lbl = new Label(projection.getName());
|
||||||
overlay.getChildren().add(lbl);
|
overlay.getChildren().add(lbl);
|
||||||
|
|||||||
@ -90,7 +90,7 @@ public class Azimuthal {
|
|||||||
4, 4, 0b0111, Type.AZIMUTHAL, Property.GNOMONIC, 2) {
|
4, 4, 0b0111, Type.AZIMUTHAL, Property.GNOMONIC, 2) {
|
||||||
|
|
||||||
public double[] project(double lat, double lon) {
|
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);
|
final double r = Math.tan(Math.PI/2 - lat);
|
||||||
return new double[] { r*Math.sin(lon), -r*Math.cos(lon)};
|
return new double[] { r*Math.sin(lon), -r*Math.cos(lon)};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 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 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.abs(Math.log(Math.abs((s1ps2-s1ms2)/(s1ps2+s1ms2)))); //the first output is the shape (angle) distortion
|
||||||
output[1] = Math.atan((sig - 1)/Math.sqrt(sig)/2); //the first output is the shape (angle) distortion
|
if (Math.abs(output[1]) > 25)
|
||||||
if (sig > 1e10)
|
|
||||||
output[1] = Double.NaN; //discard outliers
|
output[1] = Double.NaN; //discard outliers
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@ -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) {
|
public static double sind(double angdeg) {
|
||||||
return Math.sin(Math.toRadians(angdeg));
|
return Math.sin(Math.toRadians(angdeg));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user