diff --git a/README.md b/README.md index 10f2e34..32b5b52 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,13 @@ For some examples, check out the `output` folder. For more information, go to [j ## Credits While I wrote all of the code in this repository myself, and I created several of the simpler images from scratch, other people did help. Here's a comprehensive list. -* **The NASA** for [Basic.png](https://visibleearth.nasa.gov/view.php?id=57730), [Satellite.jpg](https://visibleearth.nasa.gov/view.php?id=57752), and [Altitude.png](https://asterweb.jpl.nasa.gov/gdem.asp) -* **Tom Patterson** for [Pastel.jpg](http://www.shadedrelief.com/natural3/pages/textures.html) and [Rivers.png](http://www.shadedrelief.com/natural3/pages/extra.html) -* **RokerHRO** for [the indicatrix layer of Tissot.jpg](https://commons.wikimedia.org/wiki/File:Tissot_10deg.png) -* **Crates** for [Landmasses.svg and the landmass layer of Basic.svg](https://commons.wikimedia.org/wiki/File:World_map_blank_without_borders.svg) -* **The CIA** for [Political.svg and Political.png](https://commons.wikimedia.org/wiki/File:BlankMap-World6-Equirectangular.svg). -* **The Apache Commons** for their [complex mathematics code](https://commons.apache.org/proper/commons-math/) -* **Technische Universität Berlin** for their [complex mathematics code](http://www3.math.tu-berlin.de/jtem/ellipticFunctions/) -* **AuthaGraph Co., Ltd.** for their [vague information about their map projection](http://www.authagraph.com/projects/description/%E3%80%90%E4%BD%9C%E5%93%81%E8%A7%A3%E8%AA%AC%E3%80%91%E8%A8%98%E4%BA%8B01/?lang=en), which inspired several of my own. -* **Wikipedia** for their [impressive collection of map projection information and equations](https://en.wikipedia.org/wiki/List_of_map_projections) +* **The NASA** for [Basic.png](https://visibleearth.nasa.gov/view.php?id=57730), [Satellite.jpg](https://visibleearth.nasa.gov/view.php?id=57752), and [Altitude.png](https://asterweb.jpl.nasa.gov/gdem.asp), +* **Tom Patterson** for [Pastel.jpg](http://www.shadedrelief.com/natural3/pages/textures.html) and [Rivers.png](http://www.shadedrelief.com/natural3/pages/extra.html), +* **RokerHRO** for [the indicatrix layer of Tissot.jpg](https://commons.wikimedia.org/wiki/File:Tissot_10deg.png), +* **Crates** for [Landmasses.svg](https://commons.wikimedia.org/wiki/File:World_map_blank_without_borders.svg), which I adapted into Basic.svg and Tissot.svg, +* **The CIA** for [Political.svg and Political.png](https://commons.wikimedia.org/wiki/File:BlankMap-World6-Equirectangular.svg), +* **The Apache Commons** for their [complex mathematics code](https://commons.apache.org/proper/commons-math/), +* **Technische Universität Berlin** for their [complex mathematics code](http://www3.math.tu-berlin.de/jtem/ellipticFunctions/), +* **Gene Keyes** for his [impressively in-depth and open documentation of his map projection](http://www.genekeyes.com/CKOG-OOo/7-CKOG-illus-&-coastline.html), +* **AuthaGraph Co., Ltd.** for their [vague information about their map projection](http://www.authagraph.com/projects/description/%E3%80%90%E4%BD%9C%E5%93%81%E8%A7%A3%E8%AA%AC%E3%80%91%E8%A8%98%E4%BA%8B01/?lang=en), which inspired several of my own, and +* **Wikipedia** for their [substantial collection of map projection information and equations](https://en.wikipedia.org/wiki/List_of_map_projections). diff --git a/input/Landmasses.svg b/input/Landmasses.svg index b1e30cc..c535a61 100644 --- a/input/Landmasses.svg +++ b/input/Landmasses.svg @@ -68,1253 +68,1253 @@ } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/input/Orthodromes.svg b/input/Orthodromes.svg new file mode 100644 index 0000000..8430e63 --- /dev/null +++ b/input/Orthodromes.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/input/Tissot.svg b/input/Tissot.svg new file mode 100644 index 0000000..b73ec55 --- /dev/null +++ b/input/Tissot.svg @@ -0,0 +1,1310 @@ + + + + + + image/svg+xml + + + World Map -- WDB2 combined + 2007-07-31 + + + David Hall (gringer) + + + http://www.evl.uic.edu/pape/data/WDB/ + + + world map country outline equirectangular + + + An equirectangular projection of the world, showing land outlines (resolution ~0.5 degrees). + + + + + + + + + World Databank II 2 SVG converter + World Map Image derived from WDB, using David Hall (gringer)'s converter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/maps/Projection.java b/src/maps/Projection.java index fdcdfdc..0f099b7 100644 --- a/src/maps/Projection.java +++ b/src/maps/Projection.java @@ -433,19 +433,16 @@ public abstract class Projection { lonf = lon0; } else if (Math.sin(lon1) > 0) - lonf = lon0 + - Math.acos(innerFunc); + lonf = lon0 + Math.acos(innerFunc); else - lonf = lon0 - - Math.acos(innerFunc); + lonf = lon0 - Math.acos(innerFunc); if (Math.abs(lonf) > Math.PI) lonf = Math2.floorMod(lonf+Math.PI, 2*Math.PI) - Math.PI; double thtf = pole[2]; - double[] output = {latf, lonf, thtf}; - return output; + return new double[] {latf, lonf, thtf}; } diff --git a/src/utils/SVGMap.java b/src/utils/SVGMap.java index c746457..7b964e8 100644 --- a/src/utils/SVGMap.java +++ b/src/utils/SVGMap.java @@ -81,7 +81,7 @@ public class SVGMap implements Iterable { @Override public void startElement( - String uri, String localName, String qName, Attributes attributes) { + String uri, String localName, String qName, Attributes attributes) throws SAXException { currentFormatString += "<"+qName; if (attributes.getIndex("transform") >= 0) @@ -89,8 +89,13 @@ public class SVGMap implements Iterable { else parseTransform(); - if (qName.equals("path")) - parsePath(attributes.getValue("d")); + if (qName.equals("path")) { + try { + parsePath(attributes.getValue("d")); + } catch (Exception e) { + throw new SAXException(e.getLocalizedMessage(), null); + } + } if (qName.equals("svg")) { parseViewBox(attributes); @@ -181,7 +186,7 @@ public class SVGMap implements Iterable { transformStack.push(new double[] {xScale, yScale, xTrans, yTrans}); } - private void parsePath(String d) { + private void parsePath(String d) throws Exception { currentFormatString += " d=\""; format.add(currentFormatString); paths.add(new Path(d, transformStack.peek(), minX, minY, width, height)); @@ -259,12 +264,12 @@ public class SVGMap implements Iterable { super(); } - public Path(String d, double vbWidth, double vbHeight) { + public Path(String d, double vbWidth, double vbHeight) throws Exception { this(d, new double[] {1,1,0,0}, 0, 0, vbWidth, vbHeight); } public Path(String d, double[] transform, - double vbMinX, double vbMinY, double vbWidth, double vbHeight) { + double vbMinX, double vbMinY, double vbWidth, double vbHeight) throws Exception { //I don't know if this is bad coding practice, but I don't really want to find a way to gracefully catch all possible errors into some more specific Exception class super(); int i = 0; @@ -276,6 +281,7 @@ public class SVGMap implements Iterable { i ++; argString += d.charAt(i); } + argString = argString.replaceAll("([0-9\\.])-", "$1,-"); //this is necessary because some Adobe products leave out delimiters between negative numbers i ++; String[] argStrings; @@ -288,11 +294,11 @@ public class SVGMap implements Iterable { argStrings = new String[] {argStrings[3], argStrings[4]}; } if (type == 'h' || type == 'H' || type == 'v' || type == 'V') { //convert these to 'L' - final int chgIdx = (type%32 == 8) ? 0 : 1; + final int direcIdx = (type%32 == 8) ? 0 : 1; args = new double[] {last[0], last[1]}; - if (type <= 'Z') args[chgIdx] = Double.parseDouble(argStrings[0]); //uppercase (absolute) - else args[chgIdx] += Double.parseDouble(argStrings[0]); //lowercase (relative) - last[chgIdx] = args[chgIdx]; + if (type <= 'Z') args[direcIdx] = Double.parseDouble(argStrings[0]); //uppercase (absolute) + else args[direcIdx] += Double.parseDouble(argStrings[0]); //lowercase (relative) + last[direcIdx] = args[direcIdx]; type = 'L'; } else { diff --git a/src/zupplementary python/input_generator.py b/src/zupplementary python/input_generator.py new file mode 100644 index 0000000..f2e7c05 --- /dev/null +++ b/src/zupplementary python/input_generator.py @@ -0,0 +1,123 @@ +import math +import numpy as np + +PHI = (math.sqrt(5)+1)/2 +ATH = math.atan(1/2) + +IND_NUM = 120 +IND_RAD = 500/6371 + + +def obliquify(lat1, lon1, lat0, lon0): + """ go from relative to absolute coordinates """ + latf = math.asin(math.sin(lat0)*math.sin(lat1) - math.cos(lat0)*math.cos(lon1)*math.cos(lat1)) + innerFunc = math.sin(lat1)/math.cos(lat0)/math.cos(latf) - math.tan(lat0)*math.tan(latf) + if lat0 == math.pi/2: # accounts for special case when lat0 = pi/2 + lonf = lon1+lon0 + elif lat0 == -math.pi/2: # accounts for special case when lat0 = -pi/2 + lonf = -lon1+lon0 + math.pi + elif abs(innerFunc) > 1: # accounts for special case when cos(lat1) -> 0 + if (lon1 == 0 and lat1 < -lat0) or (lon1 != 0 and lat1 < lat0): + lonf = lon0 + math.pi + else: + lonf = lon0 + elif math.sin(lon1) > 0: + lonf = lon0 + math.acos(innerFunc) + else: + lonf = lon0 - math.acos(innerFunc) + + return latf, lonf + + +def plot(coords): + tag = ' ' + print(tag.replace('L', 'M', 1).replace('.000','')) + + +def plot_orthodrome(phi0, lam0, tht0): + tag = ' ' + print(tag.replace('L', 'M', 1)) + + +def plot_indicatrix(phi0, lam0, r): + tag = ' ' + print(tag.replace('L', 'M', 1).replace('.000','')) + + +def plot_side_indicatrix(phi0, r): + tag0 = ' ' + print(tag0.replace('L', 'M', 1).replace('.000','') + tag1.replace('L', 'M', 1).replace('.000','')) + + +def plot_pole_indicatrix(north, r): + if north: + yp, yr = 360, 360-2*math.degrees(r) + else: + yp, yr = 0, 2*math.degrees(r) + + tag = ' '.format(720, yp) + print(tag) + + +def plot_meridian(lamd): + tag = ' ' + print(tag.replace('L', 'M', 1)) + + +def plot_parallel(phid): + tag = ' ' + print(tag.replace('L', 'M', 1)) + + +if __name__ == '__main__': + # for l in range(0, 180, 36): + # plot_orthodrome(math.pi/2, 0, math.radians(l)) + # for l in range(0, 360, 72): + # plot_orthodrome(ATH, math.radians(l), math.pi*.4) + # plot_orthodrome(ATH, math.radians(l), math.pi*.8) + + plot_pole_indicatrix(False, IND_RAD) + for y in [60, 30, 0, -30, -60]: + for x in range(0, 360, 30): + # if x == 0: + # plot_side_indicatrix(math.radians(y), math.pi/36) + # else: + plot_indicatrix(math.radians(y), math.radians(x), IND_RAD) + plot_pole_indicatrix(True, IND_RAD) + + # for x in range(0, 361, 10): + # plot_meridian(x) + # for y in range(-80, 90, 10): + # plot_parallel(y)