The Complete Set

I made inverse solutions for all my invented projections, and even threw
in a new one, "Tetrachamfer", which kind of sucks, but I felt like I
should include it for completeness's sake.  I found a bug in
MapConfigurationDialog and squashed it, as well. And I added a couple
new maps to the output folder. Oh, I never explained what the problem
with Tobler was! There was an issue with the way Z was being generated,
so last commit, I cleaned that up and may have made it slightly slower,
but I don't really care given how well it works now and how much faster
it still is than Lee (seriously, what is the deal with that?). Did I do
anything else? Not really. Next step: conic projections!
This commit is contained in:
Justin Kunimune 2017-07-15 16:51:38 -04:00
parent 18d2d8266f
commit ab155f2c9e
14 changed files with 127 additions and 41 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 43 KiB

BIN
output/Compass Rose.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

View File

@ -1,13 +0,0 @@
We got the best Tobler projections using:
t0=0.25022057521781305; t1=4.49997342476493; (4.0724237830145623E-4, 0.5079777001726435)
t0=0.2505753087520266; t1=4.499956546953281; (4.064604422025349E-4, 0.5079765807787102)
t0=0.2508838353035556; t1=4.4999316499660384; (4.0573108482153483E-4, 0.5079755362982413)
t0=0.2508314520322239; t1=4.499728417979239; (4.0450171936633287E-4, 0.5079758925954643)
t0=0.2500693069768243; t1=4.499328429617362; (4.0750703627578564E-4, 0.5079785011865504)
t0=0.2600667982838587; t1=4.5008562930364775; (3.8249122842821693E-4, 0.5079640977617719)
t0=0.2558237748512546; t1=4.4998740643492035; (3.9365452439070936E-4, 0.5079694226751023)
t0=0.24889877394521065; t1=4.498227902031633; (4.100009439557956E-4, 0.507979411007307)
t0=0.259316034943474; t1=4.4995552660836395; (3.8333968917550053E-4, 0.5079662063081046)
t0=0.2759279673286983; t1=4.5009128718891915; (3.3514923608814645E-4, 0.5079628635806102)
t0=0.2554293245455028; t1=4.492372958335096; (3.945025957463458E-4, 0.5079708674912415)

View File

@ -90,7 +90,7 @@ public class MapAnalyzer extends MapApplication {
Projection.ALBERS, Projection.LEE, Projection.TETRAGRAPH, Projection.SINUSOIDAL, Projection.MOLLWEIDE, Projection.ALBERS, Projection.LEE, Projection.TETRAGRAPH, Projection.SINUSOIDAL, Projection.MOLLWEIDE,
Projection.HAMMER, Projection.TOBLER, Projection.AITOFF, Projection.VAN_DER_GRINTEN, Projection.ROBINSON, Projection.HAMMER, Projection.TOBLER, Projection.AITOFF, Projection.VAN_DER_GRINTEN, Projection.ROBINSON,
Projection.WINKEL_TRIPEL, Projection.PEIRCE_QUINCUNCIAL, Projection.GUYOU, Projection.MAGNIFIER, Projection.WINKEL_TRIPEL, Projection.PEIRCE_QUINCUNCIAL, Projection.GUYOU, Projection.MAGNIFIER,
Projection.EXPERIMENT, Projection.HYPERELLIPOWER, Projection.TETRAPOWER, Projection.TETRAFILLET }; Projection.EXPERIMENT, Projection.HYPERELLIPOWER, Projection.TETRAPOWER, Projection.TETRAFILLET, Projection.TETRACHAMFER };
private Button updateBtn; private Button updateBtn;

View File

@ -113,7 +113,7 @@ public abstract class MapApplication extends Application {
final Label label = new Label("Current input:"); final Label label = new Label("Current input:");
final Text inputLabel = new Text("None"); final Text inputLabel = new Text("None");
final FileChooser inputChooser = new FileChooser(); final FileChooser inputChooser = new FileChooser(); //TODO: remember last directory
inputChooser.setInitialDirectory(new File("input")); inputChooser.setInitialDirectory(new File("input"));
inputChooser.setTitle("Choose an input map"); inputChooser.setTitle("Choose an input map");
inputChooser.getExtensionFilters().addAll(allowedExtensions); inputChooser.getExtensionFilters().addAll(allowedExtensions);
@ -376,7 +376,7 @@ public abstract class MapApplication extends Application {
Slider[] sliders, Spinner<Double>[] spinners) { Slider[] sliders, Spinner<Double>[] spinners) {
if (presetName.equals("Antipode")) { if (presetName.equals("Antipode")) {
sliders[0].setValue(-sliders[0].getValue()); sliders[0].setValue(-sliders[0].getValue());
sliders[1].setValue((sliders[1].getValue()+180)%360); sliders[1].setValue((sliders[1].getValue()+360)%360-180);
sliders[2].setValue(-sliders[2].getValue()); sliders[2].setValue(-sliders[2].getValue());
} }
else if (presetName.equals("Random")) { else if (presetName.equals("Random")) {

View File

@ -72,7 +72,7 @@ public class MapDesignerRaster extends MapApplication {
Projection.ALBERS, Projection.LEE, Projection.TETRAGRAPH, Projection.AUTHAGRAPH, Projection.SINUSOIDAL, Projection.ALBERS, Projection.LEE, Projection.TETRAGRAPH, Projection.AUTHAGRAPH, Projection.SINUSOIDAL,
Projection.MOLLWEIDE, Projection.TOBLER, Projection.AITOFF, Projection.VAN_DER_GRINTEN, Projection.ROBINSON, Projection.MOLLWEIDE, Projection.TOBLER, Projection.AITOFF, Projection.VAN_DER_GRINTEN, Projection.ROBINSON,
Projection.WINKEL_TRIPEL, Projection.PEIRCE_QUINCUNCIAL, Projection.GUYOU, Projection.LEMONS, Projection.WINKEL_TRIPEL, Projection.PEIRCE_QUINCUNCIAL, Projection.GUYOU, Projection.LEMONS,
Projection.MAGNIFIER, Projection.EXPERIMENT }; Projection.MAGNIFIER, Projection.EXPERIMENT, Projection.HYPERELLIPOWER, Projection.TETRAPOWER, Projection.TETRAFILLET, Projection.TETRACHAMFER };
private Button updateBtn, saveMapBtn; private Button updateBtn, saveMapBtn;

View File

@ -69,7 +69,7 @@ public class MapDesignerVector extends MapApplication {
Projection.ALBERS, Projection.LEE, Projection.TETRAGRAPH, Projection.SINUSOIDAL, Projection.MOLLWEIDE, Projection.ALBERS, Projection.LEE, Projection.TETRAGRAPH, Projection.SINUSOIDAL, Projection.MOLLWEIDE,
Projection.TOBLER, Projection.AITOFF, Projection.VAN_DER_GRINTEN, Projection.ROBINSON, Projection.TOBLER, Projection.AITOFF, Projection.VAN_DER_GRINTEN, Projection.ROBINSON,
Projection.WINKEL_TRIPEL, Projection.PEIRCE_QUINCUNCIAL, Projection.GUYOU, Projection.MAGNIFIER, Projection.WINKEL_TRIPEL, Projection.PEIRCE_QUINCUNCIAL, Projection.GUYOU, Projection.MAGNIFIER,
Projection.EXPERIMENT, Projection.HYPERELLIPOWER, Projection.TETRAPOWER, Projection.TETRAFILLET }; Projection.EXPERIMENT, Projection.HYPERELLIPOWER, Projection.TETRAPOWER, Projection.TETRAFILLET, Projection.TETRACHAMFER };
private static final int DEF_MAX_VTX = 5000; private static final int DEF_MAX_VTX = 5000;

View File

@ -73,10 +73,10 @@ public class MapOptimizer extends Application {
chart.getData().add(analyzeAll(globe, EXISTING_PROJECTIONS)); chart.getData().add(analyzeAll(globe, EXISTING_PROJECTIONS));
// chart.getData().add(optimizeFamily(Projection.WINKEL_TRIPEL, globe, log)); // chart.getData().add(optimizeFamily(Projection.WINKEL_TRIPEL, globe, log));
chart.getData().add(optimizeFamily(Projection.TOBLER, globe, log)); // chart.getData().add(optimizeFamily(Projection.TOBLER, globe, log));
// chart.getData().add(optimizeFamily(Projection.HYPERELLIPOWER, globe, log)); // chart.getData().add(optimizeFamily(Projection.HYPERELLIPOWER, globe, log));
// chart.getData().add(optimizeFamily(Projection.TETRAPOWER, globe, log)); // chart.getData().add(optimizeFamily(Projection.TETRAPOWER, globe, log));
// chart.getData().add(optimizeFamily(Projection.TETRAFILLET, globe, log)); chart.getData().add(optimizeFamily(Projection.TETRAFILLET, globe, log));
System.out.println("Total time elapsed: "+ System.out.println("Total time elapsed: "+
(System.currentTimeMillis()-startTime)/1000.+"s"); (System.currentTimeMillis()-startTime)/1000.+"s");

View File

@ -69,7 +69,7 @@ public class MapConfigurationDialog extends Dialog<Boolean> {
this.widthBox.valueProperty().addListener((observable, prev, now) -> { // link the Spinners this.widthBox.valueProperty().addListener((observable, prev, now) -> { // link the Spinners
if (realEdit && maintainRatio.isSelected()) { if (realEdit && maintainRatio.isSelected()) {
realEdit = false; realEdit = false;
int prefHeight = (int)Math.floor(widthBox.getValue()/defaultRatio); int prefHeight = (int)Math.round(widthBox.getValue()/defaultRatio);
heightBox.getValueFactory().setValue(prefHeight); heightBox.getValueFactory().setValue(prefHeight);
realEdit = true; realEdit = true;
} }
@ -77,7 +77,7 @@ public class MapConfigurationDialog extends Dialog<Boolean> {
this.heightBox.valueProperty().addListener((observable, prev, now) -> { this.heightBox.valueProperty().addListener((observable, prev, now) -> {
if (realEdit && maintainRatio.isSelected()) { if (realEdit && maintainRatio.isSelected()) {
realEdit = false; realEdit = false;
int prefWidth = (int)Math.ceil(heightBox.getValue()*defaultRatio); int prefWidth = (int)Math.round(heightBox.getValue()*defaultRatio);
widthBox.getValueFactory().setValue(prefWidth); widthBox.getValueFactory().setValue(prefWidth);
realEdit = true; realEdit = true;
} }
@ -87,7 +87,7 @@ public class MapConfigurationDialog extends Dialog<Boolean> {
if (!now) widthBox.increment(0); if (!now) widthBox.increment(0);
}); });
this.heightBox.focusedProperty().addListener((observable, prev,now) -> { //values when focus is lost this.heightBox.focusedProperty().addListener((observable, prev,now) -> { //values when focus is lost
if (!now) heightBox.increment(); if (!now) heightBox.increment(0);
}); });
ObservableList<String> items = FXCollections.observableArrayList( ObservableList<String> items = FXCollections.observableArrayList(

View File

@ -667,12 +667,21 @@ public enum Projection {
new double[][] {{1,5,3.7308},{.5,2.,1.2027},{.5,2.,1.1443}}) { new double[][] {{1,5,3.7308},{.5,2.,1.2027},{.5,2.,1.1443}}) {
public double[] project(double lat, double lon, double[] params) { public double[] project(double lat, double lon, double[] params) {
final double k = params[0], n = params[1], a = params[2]; final double k = params[0], n = params[1], a = params[2];
final double ynorm = (1-Math.pow(1-Math.abs(lat/(Math.PI/2)), n));
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(ynorm, k),1/k)*lon,
(1-Math.pow(1-Math.abs(lat/(Math.PI/2)), n))/Math.sqrt(n)*Math.signum(lat)*Math.PI/2*a}; ynorm*Math.PI/2/Math.sqrt(n)*a*Math.signum(lat)
};
} }
public double[] inverse(double x, double y, double[] params) { public double[] inverse(double x, double y, double[] params) {
return null; final double k = params[0], n = params[1];
return new double[] {
(1 - Math.pow(1-Math.abs(y), 1/n))*Math.PI/2*Math.signum(y),
x/Math.pow(1 - Math.pow(Math.abs(y),k),1/k)*Math.PI };
}
public double getAspectRatio(double[] params) {
final double n = params[1], a = params[2];
return 2*Math.sqrt(n)/a;
} }
}, },
@ -687,19 +696,34 @@ public enum Projection {
final double thtP = Math.PI/3*(1 - Math.pow(1-Math.abs(tht)/(Math.PI/2),k1))/(1 - 1/Math.pow(3,k1))*Math.signum(tht); final double thtP = Math.PI/3*(1 - Math.pow(1-Math.abs(tht)/(Math.PI/2),k1))/(1 - 1/Math.pow(3,k1))*Math.signum(tht);
final double kRad = k3*Math.abs(thtP)/(Math.PI/3) + k2*(1-Math.abs(thtP)/(Math.PI/3)); final double kRad = k3*Math.abs(thtP)/(Math.PI/3) + k2*(1-Math.abs(thtP)/(Math.PI/3));
final double rmax = .5/Math.cos(thtP); //the max normalized radius of this triangle (in the plane) final double rmax = .5/Math.cos(thtP); //the max normalized radius of this triangle (in the plane)
final double rtgf = Math.atan(1/Math.tan(coordR[0])*Math.cos(tht))/Math.atan(Math.sqrt(2))*rmax; //normalized tetragraph radius final double rtgf = Math.atan(1/Math.tan(coordR[0])*Math.cos(tht))/Math.atan(Math.sqrt(2))*rmax;
return new double[] { return new double[] {
(1 - Math.pow(1-rtgf,kRad))/(1 - Math.pow(1-rmax,kRad))*rmax*2*Math.PI/3, (1 - Math.pow(1-rtgf,kRad))/(1 - Math.pow(1-rmax,kRad))*rmax*2*Math.PI/3,
thtP + t0 }; thtP + t0 };
}); });
} }
public double[] inverse(double x, double y, double[] params) { public double[] inverse(double x, double y, double[] params) {
return null; final double k1 = params[0], k2 = params[1], k3 = params[2];
final double[] doubles = tetrahedralProjectionInverse(x,y);
final double[] faceCenter = { doubles[0], doubles[1], doubles[2] };
final double tht = doubles[3], xp = doubles[4], yp = doubles[5];
final double R = Math.hypot(xp, yp)*Math.sqrt(3)/2;
final double t = Math.atan2(yp, xp) + tht;
final double t0 = Math.floor((t+Math.PI/2)/(2*Math.PI/3)+0.5)*(2*Math.PI/3) - Math.PI/2;
final double thtP = t-t0;
final double lamS = (1-Math.pow(1-Math.abs(thtP)*(1-1/Math.pow(3,k1))/(Math.PI/3), 1/k1))*Math.PI/2*Math.signum(thtP);
final double kRad = k3*Math.abs(thtP)/(Math.PI/3) + k2*(1-Math.abs(thtP)/(Math.PI/3));
final double rmax = .5/Math.cos(thtP); //the max normalized radius of this triangle (in the plane)
final double rtgf = 1-Math.pow(1-R/rmax*(1-Math.pow(Math.abs(1-rmax), kRad)), 1/kRad); //normalized tetragraph radius
double[] triCoords = {
Math.atan(Math.cos(lamS)/Math.tan(rtgf/rmax*Math.atan(Math.sqrt(2)))),
Math.PI/2 + t0 + lamS };
return obliquifyPlnr(triCoords, faceCenter);
} }
}, },
TETRAFILLET("Tetrafillet", "A parametric projection that I'm still testing", TETRAFILLET("Tetrafillet", "A parametric projection that I'm still testing",
2., 0b1111, "other", "compromise", new String[] {"k1","k2","k3"}, Math.sqrt(3), 0b1111, "other", "compromise", new String[] {"k1","k2","k3"},
new double[][] {{.25,4.,1.1598},{.25,4.,.36295},{.25,4.,1.9553}}) { new double[][] {{.25,4.,1.1598},{.25,4.,.36295},{.25,4.,1.9553}}) {
public double[] project(double lat, double lon, double[] params) { public double[] project(double lat, double lon, double[] params) {
final double k1 = params[0], k2 = params[1], k3 = params[2]; final double k1 = params[0], k2 = params[1], k3 = params[2];
@ -708,7 +732,9 @@ public enum Projection {
final double tht = coordR[1] - t0; final double tht = coordR[1] - t0;
final double thtP = Math.PI/3*(1 - Math.pow(1-Math.abs(tht)/(Math.PI/2),k1))/(1 - 1/Math.pow(3,k1))*Math.signum(tht); final double thtP = Math.PI/3*(1 - Math.pow(1-Math.abs(tht)/(Math.PI/2),k1))/(1 - 1/Math.pow(3,k1))*Math.signum(tht);
final double kRad = k3*Math.abs(thtP)/(Math.PI/3) + k2*(1-Math.abs(thtP)/(Math.PI/3)); final double kRad = k3*Math.abs(thtP)/(Math.PI/3) + k2*(1-Math.abs(thtP)/(Math.PI/3));
final double rmax = 1/2. + 1/4.*Math.pow(thtP,2) + 5/48.*Math.pow(thtP,4) - .132621*Math.pow(thtP,6); //the max normalized radius of this triangle (in the plane) final double rmax; //the max normalized radius of this triangle (in the plane)
if (Math.abs(thtP) < .70123892) rmax = .5/Math.cos(thtP);
else rmax = .75 - 1.5972774*Math.pow(Math.PI/3-Math.abs(thtP),2)/2;
final double rtgf = Math.atan(1/Math.tan(coordR[0])*Math.cos(tht))/Math.atan(Math.sqrt(2))*rmax; //normalized tetragraph radius final double rtgf = Math.atan(1/Math.tan(coordR[0])*Math.cos(tht))/Math.atan(Math.sqrt(2))*rmax; //normalized tetragraph radius
return new double[] { return new double[] {
(1 - Math.pow(1-rtgf,kRad))/(1 - Math.pow(1-rmax,kRad))*rmax*2*Math.PI/3, (1 - Math.pow(1-rtgf,kRad))/(1 - Math.pow(1-rmax,kRad))*rmax*2*Math.PI/3,
@ -717,7 +743,64 @@ public enum Projection {
}); });
} }
public double[] inverse(double x, double y, double[] params) { public double[] inverse(double x, double y, double[] params) {
return null; final double k1 = params[0], k2 = params[1], k3 = params[2];
final double[] doubles = tetrahedralProjectionInverse(x,y);
final double[] faceCenter = { doubles[0], doubles[1], doubles[2] };
final double tht = doubles[3], xp = doubles[4], yp = doubles[5];
final double R = Math.hypot(xp, yp)*Math.sqrt(3)/2;
final double t = Math.atan2(yp, xp) + tht;
final double t0 = Math.floor((t+Math.PI/2)/(2*Math.PI/3)+0.5)*(2*Math.PI/3) - Math.PI/2;
final double thtP = t-t0;
final double lamS = (1-Math.pow(1-Math.abs(thtP)*(1-1/Math.pow(3,k1))/(Math.PI/3), 1/k1))*Math.PI/2*Math.signum(thtP);
final double kRad = k3*Math.abs(thtP)/(Math.PI/3) + k2*(1-Math.abs(thtP)/(Math.PI/3));
final double rmax; //the max normalized radius of this triangle (in the plane)
if (Math.abs(thtP) < .70123892) rmax = .5/Math.cos(thtP);
else rmax = .75 - 1.5972774*Math.pow(Math.PI/3-Math.abs(thtP),2)/2;
final double rtgf = 1-Math.pow(1-R/rmax*(1-Math.pow(Math.abs(1-rmax), kRad)), 1/kRad); //normalized tetragraph radius
if (R > rmax) return null;
double[] triCoords = {
Math.atan(Math.cos(lamS)/Math.tan(rtgf/rmax*Math.atan(Math.sqrt(2)))),
Math.PI/2 + t0 + lamS };
return obliquifyPlnr(triCoords, faceCenter);
}
},
TETRACHAMFER("Tetrachamfer", "A parametric projection that I'm still testing",
Math.sqrt(3), 0b1111, "other", "compromise", new String[] {"k1","k2","k3"},
new double[][] {{.25,4.,1.1598},{.25,4.,.36295},{.25,4.,1.9553}}) {
public double[] project(double lat, double lon, double[] params) {
final double k1 = params[0], k2 = params[1], k3 = params[2];
return tetrahedralProjectionForward(lat, lon, (coordR) -> {
final double t0 = Math.floor(coordR[1]/(2*Math.PI/3))*(2*Math.PI/3) + Math.PI/3;
final double tht = coordR[1] - t0;
final double thtP = Math.PI/3*(1 - Math.pow(1-Math.abs(tht)/(Math.PI/2),k1))/(1 - 1/Math.pow(3,k1))*Math.signum(tht);
final double kRad = k3*Math.abs(thtP)/(Math.PI/3) + k2*(1-Math.abs(thtP)/(Math.PI/3));
final double rmax = Math.min(.5/Math.cos(thtP), .75/Math.cos(Math.PI/3-Math.abs(thtP))); //the max normalized radius of this triangle (in the plane)
final double rtgf = Math.atan(1/Math.tan(coordR[0])*Math.cos(tht))/Math.atan(Math.sqrt(2))*rmax; //normalized tetragraph radius
return new double[] {
(1 - Math.pow(1-rtgf,kRad))/(1 - Math.pow(1-rmax,kRad))*rmax*2*Math.PI/3,
thtP + t0
};
});
}
public double[] inverse(double x, double y, double[] params) {
final double k1 = params[0], k2 = params[1], k3 = params[2];
final double[] doubles = tetrahedralProjectionInverse(x,y);
final double[] faceCenter = { doubles[0], doubles[1], doubles[2] };
final double tht = doubles[3], xp = doubles[4], yp = doubles[5];
final double R = Math.hypot(xp, yp)*Math.sqrt(3)/2;
final double t = Math.atan2(yp, xp) + tht;
final double t0 = Math.floor((t+Math.PI/2)/(2*Math.PI/3)+0.5)*(2*Math.PI/3) - Math.PI/2;
final double thtP = t-t0;
final double lamS = (1-Math.pow(1-Math.abs(thtP)*(1-1/Math.pow(3,k1))/(Math.PI/3), 1/k1))*Math.PI/2*Math.signum(thtP);
final double kRad = k3*Math.abs(thtP)/(Math.PI/3) + k2*(1-Math.abs(thtP)/(Math.PI/3));
final double rmax = Math.min(.5/Math.cos(thtP), .75/Math.cos(Math.PI/3-Math.abs(thtP))); //the max normalized radius of this triangle (in the plane)
final double rtgf = 1-Math.pow(1-R/rmax*(1-Math.pow(Math.abs(1-rmax), kRad)), 1/kRad); //normalized tetragraph radius
if (R > rmax) return null;
double[] triCoords = {
Math.atan(Math.cos(lamS)/Math.tan(rtgf/rmax*Math.atan(Math.sqrt(2)))),
Math.PI/2 + t0 + lamS };
return obliquifyPlnr(triCoords, faceCenter);
} }
}; };
@ -988,26 +1071,22 @@ public enum Projection {
private static double[] tetrahedralProjectionInverse(double x, double y) { // a function to help with tetrahedral projections private static double[] tetrahedralProjectionInverse(double x, double y) { // a function to help with tetrahedral projections
if (y < x-1) { if (y < x-1)
return new double[] { return new double[] {
-Math.PI/2, 0, 0, -Math.PI/2, 0, 0,
-Math.PI/2, Math.sqrt(3)*(x-2/3.), y+1 }; -Math.PI/2, Math.sqrt(3)*(x-2/3.), y+1 };
} else if (y < -x-1)
else if (y < -x-1) {
return new double[] { return new double[] {
-Math.PI/2, 0, 0, -Math.PI/2, 0, 0,
Math.PI/2, Math.sqrt(3)*(x+2/3.), y+1 }; Math.PI/2, Math.sqrt(3)*(x+2/3.), y+1 };
} else if (y > -x+1)
else if (y > -x+1) {
return new double[] { return new double[] {
Math.PI/2-Math.asin(Math.sqrt(8)/3), Math.PI, 0, Math.PI/2-Math.asin(Math.sqrt(8)/3), Math.PI, 0,
-Math.PI/2, Math.sqrt(3)*(x-2/3.), y-1 }; -Math.PI/2, Math.sqrt(3)*(x-2/3.), y-1 };
} else if (y > x+1)
else if (y > x+1) {
return new double[] { return new double[] {
Math.PI/2-Math.asin(Math.sqrt(8)/3), Math.PI, 0, Math.PI/2-Math.asin(Math.sqrt(8)/3), Math.PI, 0,
Math.PI/2, Math.sqrt(3)*(x+2/3.), y-1 }; Math.PI/2, Math.sqrt(3)*(x+2/3.), y-1 };
}
else if (x < 0) else if (x < 0)
return new double[] { return new double[] {
Math.PI/2-Math.asin(Math.sqrt(8)/3), -Math.PI/3, 0, Math.PI/2-Math.asin(Math.sqrt(8)/3), -Math.PI/3, 0,
@ -1078,8 +1157,7 @@ public enum Projection {
lonf = lon0 - lonf = lon0 -
Math.acos(innerFunc); Math.acos(innerFunc);
double thtf = 0; double thtf = pole[2];
thtf += pole[2];
double[] output = {latf, lonf, thtf}; double[] output = {latf, lonf, thtf};
return output; return output;
@ -1150,5 +1228,26 @@ public enum Projection {
public String getProperty() { public String getProperty() {
return this.property; return this.property;
} }
public static final void main(String[] args) {
double[] pole = {47, -173, 138};
System.out.println("The pole is at "+Arrays.toString(pole));
for (int i = 0; i < 3; i ++)
pole[i] = Math.toRadians(pole[i]);
for (double[] ref: new double[][] {{-Math.PI/2, 0, Math.PI/3},
{Math.asin(1/3.0), Math.PI, Math.PI/3},
{Math.asin(1/3.0), Math.PI/3, Math.PI/3},
{Math.asin(1/3.0), -Math.PI/3, -Math.PI/3}}) {
ref[0] *= -1;
ref[1] = (ref[1]+2*Math.PI)%(2*Math.PI)-Math.PI;
ref[2] *= -1;
System.out.println("The relative singularity is at "+Arrays.toString(ref));
final double[] coords = obliquifyPlnr(ref, pole);
for (int i = 0; i < 3; i ++)
coords[i] = Math.toDegrees(coords[i]);
System.out.println("That comes out to "+Arrays.toString(coords));
}
}
} }