mirror of
https://github.com/csharpee/Map-Projections.git
synced 2025-12-10 00:00:19 -05:00
add Solid Earth projection
there was also a bug where the Liquid Earth projection threw an error if you tried to use a map with points on the pole or antimeridian. but that's fixd now. I also fixed a minor issue where it said that the Equal Earth projection had a closed-form inverse when it in fact does not. I also renamed the liquid earth mesh files.
This commit is contained in:
parent
08ca187e7b
commit
4bd6f3c2c9
BIN
res/Solid_Earth_mesh_tris.npy
Normal file
BIN
res/Solid_Earth_mesh_tris.npy
Normal file
Binary file not shown.
BIN
res/Solid_Earth_mesh_verts_initial.npy
Normal file
BIN
res/Solid_Earth_mesh_verts_initial.npy
Normal file
Binary file not shown.
BIN
res/Solid_Earth_mesh_verts_transformed.npy
Normal file
BIN
res/Solid_Earth_mesh_verts_transformed.npy
Normal file
Binary file not shown.
@ -75,7 +75,7 @@ import maps.EqualEarth;
|
|||||||
import maps.Gyorffy;
|
import maps.Gyorffy;
|
||||||
import maps.HammerRetroazimuthal;
|
import maps.HammerRetroazimuthal;
|
||||||
import maps.Lenticular;
|
import maps.Lenticular;
|
||||||
import maps.Liquid;
|
import maps.Sargent;
|
||||||
import maps.Misc;
|
import maps.Misc;
|
||||||
import maps.Octahedral;
|
import maps.Octahedral;
|
||||||
import maps.Polyhedral;
|
import maps.Polyhedral;
|
||||||
@ -161,7 +161,7 @@ public abstract class MapApplication extends Application {
|
|||||||
Lenticular.HAMMER, Lenticular.LAGRANGE, Lenticular.STREBE_95,
|
Lenticular.HAMMER, Lenticular.LAGRANGE, Lenticular.STREBE_95,
|
||||||
Lenticular.VAN_DER_GRINTEN, Lenticular.WAGNER_VIII, WinkelTripel.WINKEL_TRIPEL },
|
Lenticular.VAN_DER_GRINTEN, Lenticular.WAGNER_VIII, WinkelTripel.WINKEL_TRIPEL },
|
||||||
{ Elastic.ELASTIC_I, Elastic.ELASTIC_II, Elastic.ELASTIC_III,
|
{ Elastic.ELASTIC_I, Elastic.ELASTIC_II, Elastic.ELASTIC_III,
|
||||||
Liquid.LIQUID_EARTH,
|
Sargent.LIQUID_EARTH, Sargent.SOLID_EARTH,
|
||||||
Danseiji.DANSEIJI_N, Danseiji.DANSEIJI_I, Danseiji.DANSEIJI_II, Danseiji.DANSEIJI_III,
|
Danseiji.DANSEIJI_N, Danseiji.DANSEIJI_I, Danseiji.DANSEIJI_II, Danseiji.DANSEIJI_III,
|
||||||
Danseiji.DANSEIJI_IV, Danseiji.DANSEIJI_V, Danseiji.DANSEIJI_VI },
|
Danseiji.DANSEIJI_IV, Danseiji.DANSEIJI_V, Danseiji.DANSEIJI_VI },
|
||||||
{ Misc.BONNE, Misc.CASSINI, Snyder.GS50, Misc.GUYOU, HammerRetroazimuthal.FULL,
|
{ Misc.BONNE, Misc.CASSINI, Snyder.GS50, Misc.GUYOU, HammerRetroazimuthal.FULL,
|
||||||
|
|||||||
@ -49,8 +49,8 @@ public class EqualEarth {
|
|||||||
|
|
||||||
|
|
||||||
public static final Projection EQUAL_EARTH = new Projection(
|
public static final Projection EQUAL_EARTH = new Projection(
|
||||||
"Equal Earth", "B. Savric, T. Patterson, and B. Jenny", "An equal-area pseudocylindrical projection specifically designed to woo Gall-Peters supporters away from that horrid thing",
|
"Equal Earth", "B. Savric, Tom Patterson, and B. Jenny", "An equal-area pseudocylindrical projection specifically designed to woo Gall-Peters supporters away from that horrid thing",
|
||||||
null, true, true, true, true, Type.PSEUDOCYLINDRICAL, Property.EQUAL_AREA, 3) {
|
null, true, true, true, false, Type.PSEUDOCYLINDRICAL, Property.EQUAL_AREA, 3) {
|
||||||
|
|
||||||
public double[] project(double lat, double lon) {
|
public double[] project(double lat, double lon) {
|
||||||
double th = asin(B*sin(lat));
|
double th = asin(B*sin(lat));
|
||||||
@ -69,6 +69,31 @@ public class EqualEarth {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public static final Projection SARGENT_EQUIVALENT_EARTH = new Projection(
|
||||||
|
"Equivalent Earth", "R. Sargent", "An equal-area pseudocylindrical projection based on the Equal Earth projection and the cylindrical equal area projection, used as the base of the Solid Earth projection",
|
||||||
|
null, true, true, true, false, Type.PSEUDOCYLINDRICAL, Property.EQUAL_AREA, 2) {
|
||||||
|
|
||||||
|
public double[] project(double lat, double lon) {
|
||||||
|
double th = asin(B*sin(lat));
|
||||||
|
return new double[] {
|
||||||
|
lon/(0.3*B*poly8(th)/cos(th) + 0.7*1.4),
|
||||||
|
0.3*poly9(th) + 0.7*1.4*sin(th)/B };
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[] inverse(double x, double y) {
|
||||||
|
double th = NumericalAnalysis.newtonRaphsonApproximation(
|
||||||
|
y, y/Y_SCALE,
|
||||||
|
(double th_) -> 0.3*poly9(th_) + 0.7*1.4*sin(th_)/B,
|
||||||
|
(double th_) -> 0.3*poly8(th_) + 0.7*1.4*cos(th_)/B, 1e-6);
|
||||||
|
return new double[] { asin(sin(th)/B), x*(0.3*B*poly8(th)/cos(th) + 0.7*1.4) };
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(double... params) throws IllegalArgumentException {
|
||||||
|
this.shape = Shape.meridianEnvelope(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static double poly9(double x) {
|
private static double poly9(double x) {
|
||||||
return A[3]*pow(x,9) + A[2]*pow(x,7) + A[1]*pow(x,3) + A[0]*x;
|
return A[3]*pow(x,9) + A[2]*pow(x,7) + A[1]*pow(x,3) + A[0]*x;
|
||||||
|
|||||||
@ -606,9 +606,6 @@ public class Misc {
|
|||||||
// for polar latitudes, switch to an azimuthal projection centered on the pole
|
// for polar latitudes, switch to an azimuthal projection centered on the pole
|
||||||
else {
|
else {
|
||||||
double sign = signum(φ0);
|
double sign = signum(φ0);
|
||||||
if (φ0 < -φMax) {
|
|
||||||
System.out.println(sign);
|
|
||||||
}
|
|
||||||
return new double[] {
|
return new double[] {
|
||||||
sign*(PI/2 - hypot(x - sign*xPole, y - sign*yPole)),
|
sign*(PI/2 - hypot(x - sign*xPole, y - sign*yPole)),
|
||||||
sign*coerceAngle(θPole - atan2(xPole - sign*x, yPole - sign*y)) };
|
sign*coerceAngle(θPole - atan2(xPole - sign*x, yPole - sign*y)) };
|
||||||
|
|||||||
@ -56,16 +56,19 @@ import static utils.Math2.coerceAngle;
|
|||||||
*
|
*
|
||||||
* @author Justin Kunimune
|
* @author Justin Kunimune
|
||||||
*/
|
*/
|
||||||
public class Liquid {
|
public class Sargent {
|
||||||
|
|
||||||
public static final LiquidProjection LIQUID_EARTH = new LiquidProjection(
|
public static final SargentProjection LIQUID_EARTH = new SargentProjection(
|
||||||
"Liquid Earth", "An equal-area map in the shape of the Equal Earth projection, optimized around the continents",
|
"Liquid Earth", "An equal-area map in the shape of the Equal Earth projection, optimized around the continents",
|
||||||
EqualEarth.EQUAL_EARTH, toRadians(11), true, "liquid");
|
EqualEarth.EQUAL_EARTH, toRadians(11), true);
|
||||||
|
|
||||||
|
public static final SargentProjection SOLID_EARTH = new SargentProjection(
|
||||||
|
"Solid Earth", "A map optimised to show off the continents by compressing the oceans",
|
||||||
|
EqualEarth.SARGENT_EQUIVALENT_EARTH, toRadians(11), true);
|
||||||
|
|
||||||
|
|
||||||
private static class LiquidProjection extends Projection {
|
private static class SargentProjection extends Projection {
|
||||||
|
|
||||||
private final String filename; // the data filename
|
|
||||||
private final Projection baseProjection;
|
private final Projection baseProjection;
|
||||||
private final double centralMeridian;
|
private final double centralMeridian;
|
||||||
private int[][] triangles;
|
private int[][] triangles;
|
||||||
@ -77,14 +80,13 @@ public class Liquid {
|
|||||||
private List<int[]>[][] lookupTableTransformed;
|
private List<int[]>[][] lookupTableTransformed;
|
||||||
|
|
||||||
|
|
||||||
public LiquidProjection(
|
public SargentProjection(
|
||||||
String title, String description, Projection baseProjection,
|
String title, String description, Projection baseProjection,
|
||||||
double centralMeridian, boolean based_on_land, String filename) {
|
double centralMeridian, boolean based_on_land) {
|
||||||
super(title, "Robert C. Sargent", description, null,
|
super(title, "Robert C. Sargent", description, null,
|
||||||
baseProjection.isContinuous(), baseProjection.isComprehensive(), true, true,
|
baseProjection.isContinuous(), baseProjection.isComprehensive(), true, true,
|
||||||
Type.OTHER, baseProjection.getProperty(), 4,
|
Type.OTHER, baseProjection.getProperty(), 4,
|
||||||
new String[0], new double[0][], !based_on_land);
|
new String[0], new double[0][], !based_on_land);
|
||||||
this.filename = filename;
|
|
||||||
this.baseProjection = baseProjection;
|
this.baseProjection = baseProjection;
|
||||||
this.centralMeridian = centralMeridian;
|
this.centralMeridian = centralMeridian;
|
||||||
}
|
}
|
||||||
@ -142,13 +144,17 @@ public class Liquid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find the triangle (represented as an array of three vertex indices) that contains the given point, using a
|
||||||
|
* table of cached triangle locations to do so efficiently.
|
||||||
|
*/
|
||||||
private static int[] findContainingTriangle(
|
private static int[] findContainingTriangle(
|
||||||
double[] фBins, double[] λBins, List<int[]>[][] lookupTable,
|
double[] фBins, double[] λBins, List<int[]>[][] lookupTable,
|
||||||
Vector[] vertices, double ф, double λ) {
|
Vector[] vertices, double ф, double λ) {
|
||||||
λ = coerceAngle(λ);
|
λ = coerceAngle(λ);
|
||||||
Vector point = new Vector(cos(ф)*cos(λ), cos(ф)*sin(λ), sin(ф));
|
Vector point = new Vector(cos(ф)*cos(λ), cos(ф)*sin(λ), sin(ф));
|
||||||
int i = (int) floor((ф - фBins[0])/(фBins[1] - фBins[0]));
|
int i = min((int) floor((ф - фBins[0])/(фBins[1] - фBins[0])), фBins.length - 2);
|
||||||
int j = (int) floor((λ - λBins[0])/(λBins[1] - λBins[0]));
|
int j = min((int) floor((λ - λBins[0])/(λBins[1] - λBins[0])), λBins.length - 2);
|
||||||
triangleLoop:
|
triangleLoop:
|
||||||
for (int[] triangle: lookupTable[i][j]) {
|
for (int[] triangle: lookupTable[i][j]) {
|
||||||
for (int k = 0; k < 3; k ++) {
|
for (int k = 0; k < 3; k ++) {
|
||||||
@ -216,14 +222,15 @@ public class Liquid {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// load the files
|
// load the files
|
||||||
|
String filename = "res/" + this.getName().replace(" ", "_") + "_mesh";
|
||||||
double[][] verticesInitial, verticesTransformed;
|
double[][] verticesInitial, verticesTransformed;
|
||||||
int[][] triangles;
|
int[][] triangles;
|
||||||
try {
|
try {
|
||||||
verticesInitial = readNumpyFloatArray("res/" + this.filename + "_vertices_initial.npy");
|
verticesInitial = readNumpyFloatArray(filename + "_verts_initial.npy");
|
||||||
verticesTransformed = readNumpyFloatArray("res/" + this.filename + "_vertices_transformed.npy");
|
verticesTransformed = readNumpyFloatArray(filename + "_verts_transformed.npy");
|
||||||
triangles = readNumpyIntArray("res/" + this.filename + "_triangles.npy");
|
triangles = readNumpyIntArray(filename + "_tris.npy");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalArgumentException("couldn't read the config file for this Liquid Projection: " + e);
|
throw new IllegalArgumentException("couldn't read the config file for this Sargent Projection: " + e);
|
||||||
}
|
}
|
||||||
if (verticesInitial.length != verticesTransformed.length)
|
if (verticesInitial.length != verticesTransformed.length)
|
||||||
throw new IllegalArgumentException("the initial vertices file and the transformed vertices files don't match.");
|
throw new IllegalArgumentException("the initial vertices file and the transformed vertices files don't match.");
|
||||||
@ -251,6 +258,15 @@ public class Liquid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* build a table that will allow us to efficiently determine which triangles might contain a given pixel.
|
||||||
|
* the output will be a table with фBins.length - 1 rows and λBins.length - 1 collums. each entry i,j will be
|
||||||
|
* a list of triangles that contact at least one point in the range
|
||||||
|
* фBins[i] <= ф <= фBins[i + 1] && λBins[j] <= λ <= λBins[j]
|
||||||
|
* thus, if you need to find the triangle that contains a given point, you can find a cell of the table that
|
||||||
|
* contains that point, and then you only need to check the contained triangles rather than every triangle in
|
||||||
|
* the mesh.
|
||||||
|
*/
|
||||||
private static List<int[]>[][] cacheTriangleLocations(
|
private static List<int[]>[][] cacheTriangleLocations(
|
||||||
int[][] triangles, Vector[] vertices, double[] фBins, double[] λBins) {
|
int[][] triangles, Vector[] vertices, double[] фBins, double[] λBins) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Loading…
x
Reference in New Issue
Block a user