mirror of
https://github.com/csharpee/Map-Projections.git
synced 2025-12-20 00:00:31 -05:00
Angles vs factors
I changed my shape distortion metric to be max angle displacement instead of stretch factor in decibels, hoping it would weigh moderate distortion higher and severe distortion lower. It didn't really do anything. I think I'll just set it back to how it was, because I liked it that way.
This commit is contained in:
parent
3ff09d1ada
commit
ed297dbd07
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 48 KiB |
@ -24,8 +24,7 @@
|
||||
package apps;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.function.DoubleUnaryOperator;
|
||||
|
||||
import java.util.function.DoubleFunction;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import dialogs.ProgressBarDialog;
|
||||
@ -146,14 +145,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 size distortion: "),avgSizeDistort),
|
||||
new HBox(new Label("Average shape distortion: "),avgShapeDistort),
|
||||
new HBox(new Label("Average area distortion: "), avgSizeDistort),
|
||||
new HBox(new Label("Average angle distortion: "), avgShapeDistort),
|
||||
txt);
|
||||
box.setAlignment(Pos.CENTER_LEFT);
|
||||
return box;
|
||||
@ -173,7 +172,7 @@ public class MapAnalyzer extends MapApplication {
|
||||
this.shapeChart = new BarChart<String, Number>(new CategoryAxis(), new NumberAxis());
|
||||
this.shapeChart.setPrefWidth(CHART_WIDTH);
|
||||
this.shapeChart.setPrefHeight(IMG_WIDTH/2);
|
||||
this.shapeChart.getXAxis().setLabel("Stretch factor");
|
||||
this.shapeChart.getXAxis().setLabel("Angle displacement");
|
||||
this.shapeChart.setBarGap(0);
|
||||
this.shapeChart.setCategoryGap(0);
|
||||
this.shapeChart.setAnimated(false);
|
||||
@ -190,8 +189,8 @@ public class MapAnalyzer extends MapApplication {
|
||||
sizeChart.getData().clear();
|
||||
shapeChart.getData().clear();
|
||||
|
||||
avgSizeDistort.setText("...");
|
||||
avgShapeDistort.setText("...");
|
||||
avgSizeDistort.setText("\u2026");
|
||||
avgShapeDistort.setText("\u2026");
|
||||
});
|
||||
|
||||
loadParameters();
|
||||
@ -205,13 +204,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, Math::exp));
|
||||
shapeChart.getData().add(histogram(distortionG[1],
|
||||
0.0, LN_10, 20, Math::exp));
|
||||
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"));
|
||||
|
||||
avgSizeDistort.setText(format(Math2.stdDev(distortionG[0])/LN_10*10));
|
||||
avgShapeDistort.setText(format(Math2.mean(distortionG[1])/LN_10*10));
|
||||
avgSizeDistort.setText(format(Math2.toDecibels(Math2.stdDev(distortionG[0])))+"dB");
|
||||
avgShapeDistort.setText(format(Math.toDegrees(Math2.mean(distortionG[1])))+"\u00B0");
|
||||
|
||||
enable(ButtonType.UPDATE_MAP, ButtonType.SAVE_GRAPH);
|
||||
});
|
||||
@ -271,7 +270,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/(LN_10/20))*LN_10/20; //contour the size by semidecibels
|
||||
final double shapeContour = Math.round(shapeDistort/(Math.PI/36))*Math.PI/36; //contour the size by semidecibels
|
||||
if (Double.isNaN(sizeDistort) || Double.isNaN(shapeDistort)) {
|
||||
writer.setArgb(x, y, 0);
|
||||
continue;
|
||||
@ -279,14 +278,14 @@ public class MapAnalyzer extends MapApplication {
|
||||
|
||||
final int r, g, b;
|
||||
if (sizeDistort < 0) { //if compressing
|
||||
r = (int)(255.9*Math.exp(-shapeContour*.6));
|
||||
g = (int)(255.9*Math.exp(-shapeContour*.6)*Math.exp(sizeContour*.6));
|
||||
r = (int)(255.9*(1-shapeContour/(Math.PI/2)));
|
||||
g = (int)(255.9*(1-shapeContour/(Math.PI/2))*Math.exp(sizeContour*.6));
|
||||
b = g;
|
||||
}
|
||||
else { //if dilating
|
||||
r = (int)(255.9*Math.exp(-shapeContour*.6)*Math.exp(-sizeContour*.6));
|
||||
r = (int)(255.9*(1-shapeContour/(Math.PI/2))*Math.exp(-sizeContour*.6));
|
||||
g = r; //I find .6 to be a rather visually pleasing sensitivity
|
||||
b = (int)(255.9*Math.exp(-shapeContour*.6));
|
||||
b = (int)(255.9*(1-shapeContour/(Math.PI/2)));
|
||||
}
|
||||
|
||||
final int argb = ((((((0xFF)<<8)+r)<<8)+g)<<8)+b;
|
||||
@ -298,7 +297,7 @@ public class MapAnalyzer extends MapApplication {
|
||||
|
||||
|
||||
private static final Series<String, Number> histogram(double[][] values,
|
||||
double min, double max, int num, DoubleUnaryOperator converter) {
|
||||
double min, double max, int num, DoubleFunction<String> 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) {
|
||||
@ -313,9 +312,8 @@ public class MapAnalyzer extends MapApplication {
|
||||
}
|
||||
Series<String, Number> output = new Series<String, Number>();
|
||||
for (int i = 0; i <= num; i ++) {
|
||||
double x = converter.applyAsDouble(i*(max-min)/num+min);
|
||||
output.getData().add(new Data<String, Number>(
|
||||
Double.toString(Math.round(100*x)/100.),
|
||||
converter.apply(i*(max-min)/num+min),
|
||||
(double)hist[i]/tot*100));
|
||||
}
|
||||
return output;
|
||||
|
||||
@ -42,7 +42,6 @@ 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;
|
||||
@ -69,6 +68,7 @@ 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())));
|
||||
this.root.setScene(new Scene(new StackPane(makeWidgets()), Color.ANTIQUEWHITE)); //Why can't I set this color?
|
||||
this.root.show();
|
||||
|
||||
this.suppressListeners.set();
|
||||
@ -192,7 +192,7 @@ public abstract class MapApplication extends Application {
|
||||
}
|
||||
|
||||
|
||||
protected abstract Node makeWidgets();
|
||||
protected abstract Region makeWidgets();
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -47,19 +47,18 @@ 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.MyProjections;
|
||||
import maps.Polyhedral;
|
||||
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
|
||||
@ -67,8 +66,6 @@ import maps.WinkelTripel;
|
||||
* @author jkunimune
|
||||
*/
|
||||
public class MapPlotter extends Application {
|
||||
|
||||
private static final double DECIBEL = Math.log(10)/10;
|
||||
|
||||
private static final double GLOBE_RES = .005;
|
||||
|
||||
@ -101,7 +98,7 @@ public class MapPlotter extends Application {
|
||||
final ScatterChart<Number, Number> plot =
|
||||
new ScatterChart<Number, Number>(
|
||||
new NumberAxis("Size distortion", 0, 4, .5),
|
||||
new NumberAxis("Shape distortion", 0, 3, .5));
|
||||
new NumberAxis("Shape distortion", 0, 20, 5));
|
||||
plot.setLegendSide(Side.RIGHT);
|
||||
final AnchorPane overlay = new AnchorPane();
|
||||
stack = new StackPane(plot, overlay);
|
||||
@ -152,7 +149,7 @@ public class MapPlotter extends Application {
|
||||
final double[] params = projection.getDefaultParameters();
|
||||
final double distortion[] = projection.avgDistortion(points, params);
|
||||
final Data<Number, Number> datum = new Data<Number, Number>(
|
||||
distortion[0]/DECIBEL, distortion[1]/DECIBEL);
|
||||
Math2.toDecibels(distortion[0]), Math.toDegrees(distortion[1]));
|
||||
series.getData().add(datum);
|
||||
final Label lbl = new Label(projection.getName());
|
||||
overlay.getChildren().add(lbl);
|
||||
|
||||
@ -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.2) lat = 0.2;
|
||||
if (lat < 0.01) lat = 0.01;
|
||||
final double r = Math.tan(Math.PI/2 - lat);
|
||||
return new double[] { r*Math.sin(lon), -r*Math.cos(lon)};
|
||||
}
|
||||
|
||||
@ -367,8 +367,9 @@ 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]));
|
||||
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)
|
||||
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] = Double.NaN; //discard outliers
|
||||
|
||||
return output;
|
||||
|
||||
@ -171,6 +171,11 @@ 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));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user