I got the equations perfect. The Dymaxion projection is complete. And by far my slowest projection.
This commit is contained in:
Justin Kunimune 2018-01-20 17:40:32 -10:00
parent 2687fea6a4
commit 9dfc72f4b8
2 changed files with 32 additions and 11 deletions

View File

@ -107,7 +107,7 @@ public abstract class MapApplication extends Application {
private static final KeyCombination CTRL_ENTER = new KeyCodeCombination(KeyCode.ENTER, KeyCodeCombination.CONTROL_DOWN); private static final KeyCombination CTRL_ENTER = new KeyCodeCombination(KeyCode.ENTER, KeyCodeCombination.CONTROL_DOWN);
public static final Projection[] FEATURED_PROJECTIONS = { Polyhedral.DYMAXION, Cylindrical.MERCATOR, public static final Projection[] FEATURED_PROJECTIONS = { Cylindrical.MERCATOR,
Cylindrical.EQUIRECTANGULAR, Cylindrical.EQUAL_AREA, Cylindrical.GALL_STEREOGRAPHIC, Cylindrical.EQUIRECTANGULAR, Cylindrical.EQUAL_AREA, Cylindrical.GALL_STEREOGRAPHIC,
Azimuthal.STEREOGRAPHIC, Azimuthal.POLAR, Azimuthal.EQUAL_AREA, Azimuthal.GNOMONIC, Azimuthal.STEREOGRAPHIC, Azimuthal.POLAR, Azimuthal.EQUAL_AREA, Azimuthal.GNOMONIC,
Azimuthal.PERSPECTIVE, Conic.LAMBERT, Conic.EQUIDISTANT, Conic.ALBERS, Azimuthal.PERSPECTIVE, Conic.LAMBERT, Conic.EQUIDISTANT, Conic.ALBERS,
@ -126,8 +126,9 @@ public abstract class MapApplication extends Application {
{ Azimuthal.EQUAL_AREA, Azimuthal.POLAR, Azimuthal.GNOMONIC, Azimuthal.ORTHOGRAPHIC, { Azimuthal.EQUAL_AREA, Azimuthal.POLAR, Azimuthal.GNOMONIC, Azimuthal.ORTHOGRAPHIC,
Azimuthal.PERSPECTIVE, Azimuthal.STEREOGRAPHIC }, Azimuthal.PERSPECTIVE, Azimuthal.STEREOGRAPHIC },
{ Conic.ALBERS, Conic.LAMBERT, Conic.EQUIDISTANT }, { Conic.ALBERS, Conic.LAMBERT, Conic.EQUIDISTANT },
{ Polyhedral.AUTHAGRAPH, CahillKeyes.M_MAP, Polyhedral.LEE_TETRAHEDRAL_RECTANGULAR, { Polyhedral.AUTHAGRAPH, CahillKeyes.M_MAP, Polyhedral.DYMAXION,
Polyhedral.LEE_TETRAHEDRAL_TRIANGULAR, Waterman.BUTTERFLY }, Polyhedral.LEE_TETRAHEDRAL_RECTANGULAR, Polyhedral.LEE_TETRAHEDRAL_TRIANGULAR,
Waterman.BUTTERFLY },
{ Pseudocylindrical.ECKERT_IV, Pseudocylindrical.KAVRAYSKIY_VII, { Pseudocylindrical.ECKERT_IV, Pseudocylindrical.KAVRAYSKIY_VII,
Pseudocylindrical.MOLLWEIDE, Arbitrary.NATURAL_EARTH, Arbitrary.ROBINSON, Pseudocylindrical.MOLLWEIDE, Arbitrary.NATURAL_EARTH, Arbitrary.ROBINSON,
Pseudocylindrical.SINUSOIDAL, Tobler.TOBLER }, Pseudocylindrical.SINUSOIDAL, Tobler.TOBLER },

View File

@ -233,13 +233,16 @@ public class Polyhedral {
public static final Projection DYMAXION = public static final Projection DYMAXION =
new PolyhedralProjection( new PolyhedralProjection(
"Dymaxion", "A polyhedral projection that slices up the oceans as much as possible without slicing up any continents.", "Dymaxion", "A polyhedral projection that slices up the oceans as much as possible without slicing up any landmasses.",
0b1110, Configuration.DYMAXION, Property.COMPROMISE) { 0b1110, Configuration.DYMAXION, Property.COMPROMISE) {
private final double[] POLE = {0.040158, -0.091549,-2.015269}; //I derived these numbers from [Robert Gray](http://www.rwgrayprojects.com/rbfnotes/maps/graymap4.html) private final double[] POLE = {0.040158, -0.091549,-2.015269}; //I derived these numbers from [Robert Gray](http://www.rwgrayprojects.com/rbfnotes/maps/graymap4.html)
private final double X_0 = 0.75; private final double X_0 = 0.75;
private final double Y_0 = -Math.sqrt(3)/4; private final double Y_0 = -Math.sqrt(3)/4;
private final double sin36 = Math.sqrt(10-2*Math.sqrt(5))/4;
private final double cos36 = (1+Math.sqrt(5))/4;
@Override @Override
public double[] project(double lat, double lon) { //apply a pole shift and Cartesian shift to Dymaxion public double[] project(double lat, double lon) { //apply a pole shift and Cartesian shift to Dymaxion
double[] coords = obliquifySphc(lat, lon, POLE); double[] coords = obliquifySphc(lat, lon, POLE);
@ -255,12 +258,26 @@ public class Polyhedral {
} }
public double[] faceProject(double lat, double lon) { public double[] faceProject(double lat, double lon) {
return new double[] {(Math.PI/2-lat)/1.1, lon*5/6}; if (Math.abs(lon) > Math.PI/5) throw new IllegalArgumentException("That's not possible!");
double xG = Math.cos(lon)/Math.tan(lat)/cos36; //normalised gnomonic coordinates
double yG = Math.sin(lon)/Math.tan(lat)/sin36;
double a = Math.asin((xG+yG)/(2*Math.sqrt(1+xG*xG))) + Math.atan(xG); //angular distance up each side of the triangle
double b = Math.asin((xG-yG)/(2*Math.sqrt(1+xG*xG))) + Math.atan(xG);
double x = (a + b)/(2*Math.sqrt(3)); //final cartesian coordinates in radians
double y = (a - b)/2;
return new double[] {Math.hypot(x,y)/Math.atan(2), Math.atan2(y,x)}; //scale to fit to layout, where side length is 1
} }
public double[] faceInverse(double r, double th) { public double[] faceInverse(double r, double th) {
if (r > Math.sqrt(1/3.)) return null; if (Math.abs(th) > Math.PI/6) throw new IllegalArgumentException("Wait, what?");
return new double[] {Math.PI/2-r*1.1, th*6/5}; double x = r*Math.cos(th)*Math.atan(2); //cartesian coordinates in radians
double y = r*Math.sin(th)*Math.atan(2);
double a = Math.sqrt(3)*x + y; //angular distance up each side of the triangle
double b = Math.sqrt(3)*x - y;
double xG = cos36*(Math.sin(a) + Math.sin(b))/(1 + Math.cos(a) + Math.cos(b)); //unnormalised gnomonic coordinates
double yG = sin36*
(Math.sin(a) - Math.sin(b) + 2*Math.sin(a-b))/(1 + Math.cos(a) + Math.cos(b));
return new double[] {Math.atan(1/Math.hypot(xG, yG)), Math.atan2(yG, xG)}; //inverse gnomonic projection
} }
}; };
@ -311,10 +328,13 @@ public class Polyhedral {
double[] centrum = null; double[] centrum = null;
for (double[] testCentrum: configuration.centrumSet) { //iterate through the centrums to see which goes here for (double[] testCentrum: configuration.centrumSet) { //iterate through the centrums to see which goes here
final double[] relCoords = obliquifySphc(lat, lon, testCentrum); final double[] relCoords = obliquifySphc(lat, lon, testCentrum);
if (testCentrum.length > 6) //if the centrum is long, then it contains longitude bounds if (testCentrum.length > 6) { //if the centrum is long, then it contains longitude bounds
if (relCoords[1] < testCentrum[6]*Math.PI/numSym || double minL = testCentrum[6]*Math.PI/numSym;
relCoords[1] > testCentrum[7]*Math.PI/numSym) double maxL = testCentrum[7]*Math.PI/numSym;
relCoords[1] = Math2.floorMod(relCoords[1]-minL, 2*Math.PI) + minL;
if (relCoords[1] < minL || relCoords[1] > maxL)
continue; //ignore any longitudes not in the bounds described in [6:7] continue; //ignore any longitudes not in the bounds described in [6:7]
}
if (relCoords[0] > latR) { //pick the centrum that maxes out latitude if (relCoords[0] > latR) { //pick the centrum that maxes out latitude
latR = relCoords[0]; latR = relCoords[0];
@ -444,7 +464,7 @@ public class Polyhedral {
{ ATAN_ONE_HLF, 0.0, 0.0, -Math.PI/2, 0.0, Math.sqrt(3)/2,-3,5 }, //Caribbean { ATAN_ONE_HLF, 0.0, 0.0, -Math.PI/2, 0.0, Math.sqrt(3)/2,-3,5 }, //Caribbean
{ ATAN_ONE_HLF, 0.0, -4*Math.PI/5,-5*Math.PI/6,-0.5, Math.sqrt(3), -1,1 }, //North Atlantic O. { ATAN_ONE_HLF, 0.0, -4*Math.PI/5,-5*Math.PI/6,-0.5, Math.sqrt(3), -1,1 }, //North Atlantic O.
{ ATAN_ONE_HLF, 2*Math.PI/5, 0.0, -Math.PI/2, 1.0, Math.sqrt(3)/2,-5,5 }, //Patagonia { ATAN_ONE_HLF, 2*Math.PI/5, 0.0, -Math.PI/2, 1.0, Math.sqrt(3)/2,-5,5 }, //Patagonia
{ ATAN_ONE_HLF, 4*Math.PI/5, 0.0, -Math.PI/2, 2.0, Math.sqrt(3)/2,-5,0 }, //East Antarctica { ATAN_ONE_HLF, 4*Math.PI/5,-2*Math.PI/5,-5*Math.PI/6, 2.0, Math.sqrt(3)/2,-3,2 }, //East Antarctica
{ ATAN_ONE_HLF, 4*Math.PI/5, 0.0, -Math.PI/6, -3.5, 0.0, 0,1 }, //South Indian O. { ATAN_ONE_HLF, 4*Math.PI/5, 0.0, -Math.PI/6, -3.5, 0.0, 0,1 }, //South Indian O.
{ ATAN_ONE_HLF, 4*Math.PI/5, 2*Math.PI/5,-Math.PI/6, -3.0, Math.sqrt(3)/2,-1,1 }, //North Indian O. { ATAN_ONE_HLF, 4*Math.PI/5, 2*Math.PI/5,-Math.PI/6, -3.0, Math.sqrt(3)/2,-1,1 }, //North Indian O.
{ ATAN_ONE_HLF, 4*Math.PI/5, 4*Math.PI/5,-Math.PI/6, -2.5, Math.sqrt(3), -1,1 }, //South Africa { ATAN_ONE_HLF, 4*Math.PI/5, 4*Math.PI/5,-Math.PI/6, -2.5, Math.sqrt(3), -1,1 }, //South Africa