mirror of
https://github.com/csharpee/Map-Projections.git
synced 2025-10-16 00:00:11 -04:00
General hyperelliptic things
I generalized my formula to make it easier to add new map projection families.
This commit is contained in:
parent
2ffe290cb4
commit
2fcfa325e7
@ -1,5 +1,8 @@
|
||||
package mapAnalyzer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.BinaryOperator;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.chart.NumberAxis;
|
||||
@ -20,6 +23,7 @@ public class MapOptimizer extends Application {
|
||||
|
||||
private static final String[] EXISTING_PROJECTIONS = { "Hobo-Dyer", "Winkel Tripel", "Robinson", "Van der Grinten",
|
||||
"Mercator" };
|
||||
private static final double[] WEIGHTS = {.22, .50, .86, 1.3, 2.0, 2.67, 3.0, 4.7, 8.0, 18.0 };
|
||||
private ScatterChart<Number, Number> chart;
|
||||
|
||||
|
||||
@ -31,6 +35,8 @@ public class MapOptimizer extends Application {
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) throws Exception {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
|
||||
double[][][] globe = MapAnalyzer.globe(0.02);
|
||||
final Series<Number, Number> oldMaps = analyzeAll(globe, EXISTING_PROJECTIONS);
|
||||
final Series<Number, Number> hyperMaps = optimizeHyperelliptical(globe);
|
||||
@ -42,6 +48,9 @@ public class MapOptimizer extends Application {
|
||||
chart.getData().add(hyperMaps);
|
||||
chart.getData().add(roundMaps);
|
||||
|
||||
System.out.println("Total time elapsed: "+
|
||||
(System.currentTimeMillis()-startTime)/1000.);
|
||||
|
||||
stage.setTitle("Map Projections");
|
||||
stage.setScene(new Scene(chart));
|
||||
stage.show();
|
||||
@ -60,47 +69,63 @@ public class MapOptimizer extends Application {
|
||||
}
|
||||
|
||||
|
||||
private static Series<Number, Number> optimizeHyperelliptical(double[][][] points) { //optimize and plot some hyperelliptical maps
|
||||
System.out.println("Hyperelliptical stuff. Aw yeah.");
|
||||
final double[] weights = {.22, .50, .86, 1, 1.3, 2, 3.0, 4.7, 8.0, 18.0 };
|
||||
double[][] currentBest = new double[weights.length][5]; //the 0-3 cols are the min distortions for each weight, the other cols are the values of k and n that caused that
|
||||
for (int i = 0; i < weights.length; i ++)
|
||||
currentBest[i][0] = Integer.MAX_VALUE;
|
||||
private static Series<Number, Number> optimizeFamily(BinaryOperator<double[]> projectionFam, String name,
|
||||
double[][] bounds, double[][][] points) { // optimize and plot some maps of a given family maps
|
||||
final double[][] currentBest = new double[WEIGHTS.length][3+bounds.length]; //the 0-3 cols are the min distortions for each weight, the other cols are the values of k and n that caused that
|
||||
for (int k = 0; k < WEIGHTS.length; k ++)
|
||||
currentBest[k][0] = Integer.MAX_VALUE;
|
||||
|
||||
System.out.println("Iterating k and n:");
|
||||
for (double k = 2; k <= 5; k += .25) {
|
||||
for (double n = 1; n <= 2.75; n += .125) {
|
||||
System.out.println("("+k+","+n+")");
|
||||
final double k0 = k, n0 = n;
|
||||
double[][][] dist = MapAnalyzer.calculateDistortion(points,
|
||||
(coords) -> hyperelliptical(coords, k0, n0));
|
||||
final double avgSizeD = Stat.stdDev(dist[0]);
|
||||
final double avgShapeD = Stat.mean(dist[1]);
|
||||
for (int i = 0; i < weights.length; i ++) {
|
||||
final double avgDist = avgSizeD + weights[i]*avgShapeD;
|
||||
if (avgDist < currentBest[i][0]) {
|
||||
currentBest[i][0] = avgDist;
|
||||
currentBest[i][1] = avgSizeD;
|
||||
currentBest[i][2] = avgShapeD;
|
||||
currentBest[i][3] = k;
|
||||
currentBest[i][4] = n;
|
||||
}
|
||||
final double[] params = new double[bounds.length];
|
||||
for (int i = 0; i < params.length; i ++) params[i] = bounds[i][0]; //initialize params
|
||||
|
||||
while (true) {
|
||||
int i;
|
||||
for (i = 0; i < params.length; i ++) { //iterate the parameters
|
||||
if (params[i] < bounds[i][1]) {
|
||||
for (int j = 0; j < i; j ++)
|
||||
params[j] = bounds[j][0];
|
||||
params[i] += (bounds[i][1]-bounds[i][0])/8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == params.length) break; //if you made it through the for loop without breaking (finding a parameter to increment), you're done!
|
||||
System.out.println(Arrays.toString(params));
|
||||
|
||||
double[][][] dist = MapAnalyzer.calculateDistortion(points,
|
||||
(coords) -> projectionFam.apply(coords, params));
|
||||
final double avgSizeD = Stat.stdDev(dist[0]);
|
||||
final double avgShapeD = Stat.mean(dist[1]);
|
||||
for (int k = 0; k < WEIGHTS.length; k ++) {
|
||||
final double avgDist = avgSizeD + WEIGHTS[k]*avgShapeD;
|
||||
if (avgDist < currentBest[k][0]) {
|
||||
currentBest[k][0] = avgDist;
|
||||
currentBest[k][1] = avgSizeD;
|
||||
currentBest[k][2] = avgShapeD;
|
||||
System.arraycopy(params,0, currentBest[k],3,params.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final Series<Number, Number> output = new Series<Number, Number>();
|
||||
output.setName("Hyperelliptics");
|
||||
output.setName(name);
|
||||
|
||||
System.out.println("We got the best hyperelliptic projections using:");
|
||||
System.out.println("We got the best "+name+" projections using:");
|
||||
for (double[] best: currentBest) {
|
||||
System.out.println("\tk="+best[3]+"; n="+best[4]);
|
||||
System.out.print("\t");
|
||||
for (int i = 0; i < params.length; i ++)
|
||||
System.out.print("t"+i+"="+best[3+i]+"; ");
|
||||
System.out.println();
|
||||
output.getData().add(new Data<Number, Number>(best[1], best[2]));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
private static Series<Number, Number> optimizeHyperelliptical(double[][][] points) { //optimize and plot some hyperelliptical maps
|
||||
return optimizeFamily(MapOptimizer::hyperelliptical, "Hyperelliptic", new double[][] {{2,5}, {.75,1.75}}, points);
|
||||
}
|
||||
|
||||
|
||||
private static Series<Number, Number> optimizeElliptihypercosine(double[][][] points) { //optimize and plot some elliptical-hypebolic-cosine maps
|
||||
return new Series<Number, Number>();
|
||||
}
|
||||
@ -114,8 +139,9 @@ public class MapOptimizer extends Application {
|
||||
}
|
||||
|
||||
|
||||
private static double[] hyperelliptical(double[] coords, double k, double n) { //a hyperelliptic map projection with hyperellipse order k and lattitudinal spacind described by x^n/n
|
||||
private static final double[] hyperelliptical(double[] coords, double[] params) { //a hyperelliptic map projection with hyperellipse order k and lattitudinal spacind described by x^n/n
|
||||
final double lat = coords[0], lon = coords[1];
|
||||
final double k = params[0], n = params[1];
|
||||
|
||||
return new double[] {
|
||||
Math.pow(1 - Math.pow(Math.abs(lat/(Math.PI/2)), k),1/k)*lon,
|
||||
|
@ -833,8 +833,8 @@ public class MapProjections extends Application {
|
||||
|
||||
|
||||
private static double[] hyperelliptic(double lat, double lon) {
|
||||
final double k = 3;
|
||||
final double n = 1.5;
|
||||
final double k = 3.5;
|
||||
final double n = 1.3125;
|
||||
return new double[] {
|
||||
Math.pow(1 - Math.pow(Math.abs(lat/(Math.PI/2)), k),1/k)*lon,
|
||||
(1-Math.pow(1-Math.abs(lat/(Math.PI/2)), n))/Math.sqrt(n)*Math.signum(lat)*Math.PI/2};
|
||||
|
Loading…
x
Reference in New Issue
Block a user