mirror of
https://github.com/csharpee/Map-Projections.git
synced 2025-10-20 00:00:13 -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;
|
package mapAnalyzer;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.BinaryOperator;
|
||||||
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.chart.NumberAxis;
|
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",
|
private static final String[] EXISTING_PROJECTIONS = { "Hobo-Dyer", "Winkel Tripel", "Robinson", "Van der Grinten",
|
||||||
"Mercator" };
|
"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;
|
private ScatterChart<Number, Number> chart;
|
||||||
|
|
||||||
|
|
||||||
@ -31,6 +35,8 @@ public class MapOptimizer extends Application {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws Exception {
|
public void start(Stage stage) throws Exception {
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
double[][][] globe = MapAnalyzer.globe(0.02);
|
double[][][] globe = MapAnalyzer.globe(0.02);
|
||||||
final Series<Number, Number> oldMaps = analyzeAll(globe, EXISTING_PROJECTIONS);
|
final Series<Number, Number> oldMaps = analyzeAll(globe, EXISTING_PROJECTIONS);
|
||||||
final Series<Number, Number> hyperMaps = optimizeHyperelliptical(globe);
|
final Series<Number, Number> hyperMaps = optimizeHyperelliptical(globe);
|
||||||
@ -42,6 +48,9 @@ public class MapOptimizer extends Application {
|
|||||||
chart.getData().add(hyperMaps);
|
chart.getData().add(hyperMaps);
|
||||||
chart.getData().add(roundMaps);
|
chart.getData().add(roundMaps);
|
||||||
|
|
||||||
|
System.out.println("Total time elapsed: "+
|
||||||
|
(System.currentTimeMillis()-startTime)/1000.);
|
||||||
|
|
||||||
stage.setTitle("Map Projections");
|
stage.setTitle("Map Projections");
|
||||||
stage.setScene(new Scene(chart));
|
stage.setScene(new Scene(chart));
|
||||||
stage.show();
|
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
|
private static Series<Number, Number> optimizeFamily(BinaryOperator<double[]> projectionFam, String name,
|
||||||
System.out.println("Hyperelliptical stuff. Aw yeah.");
|
double[][] bounds, double[][][] points) { // optimize and plot some maps of a given family maps
|
||||||
final double[] weights = {.22, .50, .86, 1, 1.3, 2, 3.0, 4.7, 8.0, 18.0 };
|
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
|
||||||
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 k = 0; k < WEIGHTS.length; k ++)
|
||||||
for (int i = 0; i < weights.length; i ++)
|
currentBest[k][0] = Integer.MAX_VALUE;
|
||||||
currentBest[i][0] = Integer.MAX_VALUE;
|
|
||||||
|
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));
|
||||||
|
|
||||||
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,
|
double[][][] dist = MapAnalyzer.calculateDistortion(points,
|
||||||
(coords) -> hyperelliptical(coords, k0, n0));
|
(coords) -> projectionFam.apply(coords, params));
|
||||||
final double avgSizeD = Stat.stdDev(dist[0]);
|
final double avgSizeD = Stat.stdDev(dist[0]);
|
||||||
final double avgShapeD = Stat.mean(dist[1]);
|
final double avgShapeD = Stat.mean(dist[1]);
|
||||||
for (int i = 0; i < weights.length; i ++) {
|
for (int k = 0; k < WEIGHTS.length; k ++) {
|
||||||
final double avgDist = avgSizeD + weights[i]*avgShapeD;
|
final double avgDist = avgSizeD + WEIGHTS[k]*avgShapeD;
|
||||||
if (avgDist < currentBest[i][0]) {
|
if (avgDist < currentBest[k][0]) {
|
||||||
currentBest[i][0] = avgDist;
|
currentBest[k][0] = avgDist;
|
||||||
currentBest[i][1] = avgSizeD;
|
currentBest[k][1] = avgSizeD;
|
||||||
currentBest[i][2] = avgShapeD;
|
currentBest[k][2] = avgShapeD;
|
||||||
currentBest[i][3] = k;
|
System.arraycopy(params,0, currentBest[k],3,params.length);
|
||||||
currentBest[i][4] = n;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Series<Number, Number> output = new Series<Number, Number>();
|
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) {
|
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]));
|
output.getData().add(new Data<Number, Number>(best[1], best[2]));
|
||||||
}
|
}
|
||||||
return output;
|
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
|
private static Series<Number, Number> optimizeElliptihypercosine(double[][][] points) { //optimize and plot some elliptical-hypebolic-cosine maps
|
||||||
return new Series<Number, Number>();
|
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 lat = coords[0], lon = coords[1];
|
||||||
|
final double k = params[0], n = params[1];
|
||||||
|
|
||||||
return new double[] {
|
return new double[] {
|
||||||
Math.pow(1 - Math.pow(Math.abs(lat/(Math.PI/2)), k),1/k)*lon,
|
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) {
|
private static double[] hyperelliptic(double lat, double lon) {
|
||||||
final double k = 3;
|
final double k = 3.5;
|
||||||
final double n = 1.5;
|
final double n = 1.3125;
|
||||||
return new double[] {
|
return new double[] {
|
||||||
Math.pow(1 - Math.pow(Math.abs(lat/(Math.PI/2)), k),1/k)*lon,
|
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};
|
(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