diff --git a/README.md b/README.md
index 0bf2324..5c58df1 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,10 @@ Technically, to unfold the earth into an icosahedron, we must first consider sli
All images in `/docs` and on this page are created by running `python3 -m dymax.examples`.
+SVG files suitable for printing and folding into an icosahedron are in `/svg`. They reference images in `/docs`. Open the SVG file in a text editor and change the image reference to use a different map.
+
+
+
## To-Do List
1) Replace spherical coordinate conversion with Earth-Centered-Earth-Fixed for much better accuracy.
2) Get documentation working correctly.
@@ -49,6 +53,6 @@ xy_projection = dymax.lonlat2dymax(-118.0367, 34.8951)
*pydymax* code is [Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)](http://creativecommons.org/licenses/by-nc-sa/4.0/)
## References
-* [Mike Bostock's](https://github.com/mbostock) [javascript code](http://mbostock.github.io/protovis/ex/dymax.js) and [http://mbostock.github.io/protovis/ex/dymax.html](live demo)
+* [Mike Bostock's](https://github.com/mbostock) [javascript code](http://mbostock.github.io/protovis/ex/dymax.js) and [live demo](https://mbostock.github.io/protovis/ex/dymax.html)
* [general info on dymax/fuller projections](http://www.progonos.com/furuti/MapProj/Normal/ProjPoly/projPoly3.html)
* [The big wiki article on Dymaxion Maps](http://en.wikipedia.org/wiki/Dymaxion_map)
diff --git a/docs/dymax_net_bmng.png b/docs/dymax_net_bmng.png
new file mode 100644
index 0000000..bec6691
Binary files /dev/null and b/docs/dymax_net_bmng.png differ
diff --git a/docs/dymax_ocean_etopo1.png b/docs/dymax_ocean_etopo1.png
new file mode 100644
index 0000000..1eca7b2
Binary files /dev/null and b/docs/dymax_ocean_etopo1.png differ
diff --git a/dymax/constants.py b/dymax/constants.py
index 7ef84cd..283e2e3 100644
--- a/dymax/constants.py
+++ b/dymax/constants.py
@@ -3,10 +3,17 @@
'''Constants for Dymaxion Projection Module'''
import math
import numpy as np
+from enum import Enum
### Quick Vector Functions
magnitude = lambda vector: np.sqrt(np.dot(vector, vector))
+### Face arrangement
+class Unfolding(Enum):
+ LAND = 0
+ OCEAN = 1
+ NET = 2
+
### Icosahedron Time
facecount, vertexcount = 20, 12
@@ -61,20 +68,42 @@
[1.5, 4 * math.sqrt(3) / 3.0, 300],
[1.0, 5 / (2 * math.sqrt(3)), 300],
[1.5, 2 / math.sqrt(3), 0],
- [2.0, 1 / (2 * math.sqrt(3)), 0],
+ [1.5, 1 / math.sqrt(3), 300],
[2.5, 1 / math.sqrt(3), 60],
[3.5, 1 / math.sqrt(3), 60],
[3.5, 2 / math.sqrt(3), 120],
[4.0, 5 / (2 * math.sqrt(3)), 60],
[4.0, 7 / (2 * math.sqrt(3)), 0],
[5.0, 7 / (2 * math.sqrt(3)), 0],
- [5.5, 2 / math.sqrt(3), 0],
+ [0.5, 1 / math.sqrt(3), 60],
[1.0, 1 / (2 * math.sqrt(3)), 0],
[4.0, 1 / (2 * math.sqrt(3)), 120],
[4.5, 2 / math.sqrt(3), 0],
[5.0, 5 / (2 * math.sqrt(3)), 60]])
-dymax_translate08_special = np.array([1.5, 1 / math.sqrt(3), 300]) # if LCD < 4
-dymax_translate15_special = np.array([0.5, 1 / math.sqrt(3), 60]) # if LCD < 3
+dymax_translate08_special = np.array([2.0, 1 / (2 * math.sqrt(3)), 0]) # if LCD >= 4
+dymax_translate15_special = np.array([5.5, 2 / math.sqrt(3), 0]) # if LCD >= 3
+
+dymax_ocean_translate = np.array([ [5.0, 5 / (2 * math.sqrt(3)), 300],
+ [0.5, 4 / (2 * math.sqrt(3)), 0],
+ [1.0, 5 / (2 * math.sqrt(3)), 60],
+ [1.0, 7 / (2 * math.sqrt(3)), 120],
+ [4.5, 8 / (2 * math.sqrt(3)), 300],
+ [4.5, 4 / (2 * math.sqrt(3)), 0],
+ [4.0, 1 / (2 * math.sqrt(3)), 240],
+ [1.0, 1 / (2 * math.sqrt(3)), 120],
+ [1.5, 2 / (2 * math.sqrt(3)), 60],
+ [1.5, 4 / (2 * math.sqrt(3)), 120],
+ [2.0, 5 / (2 * math.sqrt(3)), 60],
+ [2.0, 7 / (2 * math.sqrt(3)), 120],
+ [3.0, 7 / (2 * math.sqrt(3)), 0],
+ [4.0, 7 / (2 * math.sqrt(3)), 240],
+ [4.0, 5 / (2 * math.sqrt(3)), 300],
+ [3.5, 2 / (2 * math.sqrt(3)), 300],
+ [2.5, 2 / (2 * math.sqrt(3)), 180],
+ [2.5, 4 / (2 * math.sqrt(3)), 120],
+ [3.0, 5 / (2 * math.sqrt(3)), 300],
+ [3.5, 4 / (2 * math.sqrt(3)), 0]])
+dymax_ocean_translate08_special = np.array([2.0, 1 / (2 * math.sqrt(3)), 120]) # if LCD == 2 or LCD == 3
### Optimizations
garc = 2 * math.asin(math.sqrt( (5 - math.sqrt(5)) / 10))
diff --git a/dymax/convert.py b/dymax/convert.py
index 2d9d1f7..0c99afe 100644
--- a/dymax/convert.py
+++ b/dymax/convert.py
@@ -27,7 +27,7 @@ def euclidean(vec_a, vec_b):
### Dymax Conversion Main Routine
@lru_cache(maxsize=2**12)
-def lonlat2dymax(lon, lat, getlcd=False):
+def lonlat2dymax(lon, lat, getlcd=False, unfolding=constants.Unfolding.LAND):
'''
Lon Lat 2 Dymax XY
@@ -71,7 +71,7 @@ def lonlat2dymax(lon, lat, getlcd=False):
tri, lcd = fuller_triangle(XYZ)
# Determine the corresponding Fuller map plane(x, y) point
- x_pos, y_pos = dymax_point(tri, lcd, XYZ)
+ x_pos, y_pos = dymax_point(tri, lcd, XYZ, unfolding)
if getlcd: return x_pos, y_pos, lcd
else: return x_pos, y_pos
@@ -102,7 +102,7 @@ def vert2dymax(vert, vertset, push=.9999):
x_pos, y_pos = dymax_point(tri, hlcd, XYZ)
return x_pos, y_pos
-def face2dymax(face_idx, push=.9999, atomic=False):
+def face2dymax(face_idx, push=.9999, atomic=False, unfolding=constants.Unfolding.LAND):
'''
Convert Icosahedron Face to (4) XY Vertices
@@ -141,13 +141,13 @@ def face2dymax(face_idx, push=.9999, atomic=False):
XYZ = np.mean([up, down], axis=0)
XYZ = XYZ * push + constants.XYZcenters[face_idx] * (1-push)
tri, hlcd = fuller_triangle(XYZ)
- points[jdx] = dymax_point(tri, hlcd, XYZ)
+ points[jdx] = dymax_point(tri, hlcd, XYZ, unfolding)
else:
points = np.zeros((3+1, 2))
for jdx in range(3):
XYZ = constants.vertices[constants.vert_indices[face_idx, jdx]] * push + constants.XYZcenters[face_idx] * (1-push)
tri, hlcd = fuller_triangle(XYZ)
- points[jdx] = dymax_point(tri, hlcd, XYZ)
+ points[jdx] = dymax_point(tri, hlcd, XYZ, unfolding)
points[-1] = points[0] # Loop Back to Start
return points
@@ -246,7 +246,7 @@ def fuller_triangle(XYZ):
elif h_dist3 <= h_dist2 <= h_dist1: h_lcd = 3
return h_tri, h_lcd
-def dymax_point(tri, lcd, XYZ):
+def dymax_point(tri, lcd, XYZ, unfolding=constants.Unfolding.LAND):
'''
In order to rotate the given point into the template spherical
triangle, we need the spherical polar coordinates of the center
@@ -261,6 +261,8 @@ def dymax_point(tri, lcd, XYZ):
Dymaxion sub-triangle where we want to be.
XYZ : tuple of floats
Pseudo-ECEF coordinate that will be projected to dymaxion.
+ unfolding: enum
+ Either LAND, OCEAN or NET.
Returns
-------
@@ -320,10 +322,18 @@ def dymax_point(tri, lcd, XYZ):
### Move and Rotate as Appropriate
# You can disable the special translations for uniform triangles
- if tri == 8 and lcd < 4:
- xtranslate, ytranslate, rotation = constants.dymax_translate08_special
- elif tri == 15 and lcd < 3:
- xtranslate, ytranslate, rotation = constants.dymax_translate15_special
+ if unfolding == constants.Unfolding.LAND:
+ if tri == 8 and lcd >= 4:
+ xtranslate, ytranslate, rotation = constants.dymax_translate08_special
+ elif tri == 15 and lcd >= 3:
+ xtranslate, ytranslate, rotation = constants.dymax_translate15_special
+ else:
+ xtranslate, ytranslate, rotation = constants.dymax_translate[tri]
+ elif unfolding == constants.Unfolding.OCEAN:
+ if tri == 8 and (lcd == 2 or lcd == 3):
+ xtranslate, ytranslate, rotation = constants.dymax_ocean_translate08_special
+ else:
+ xtranslate, ytranslate, rotation = constants.dymax_ocean_translate[tri]
else:
xtranslate, ytranslate, rotation = constants.dymax_translate[tri]
@@ -437,4 +447,4 @@ def benchmark(verbose=True):
dymax_centers = np.zeros((constants.facecount, 2))
for fdx in range(constants.facecount):
tri, hlcd = fuller_triangle(constants.XYZcenters[fdx])
- dymax_centers[fdx] = dymax_point(tri, hlcd, constants.XYZcenters[fdx])
+ dymax_centers[fdx] = dymax_point(tri, hlcd, constants.XYZcenters[fdx], constants.Unfolding.LAND)
diff --git a/dymax/examples.py b/dymax/examples.py
index 7e495a0..fa6f8dd 100644
--- a/dymax/examples.py
+++ b/dymax/examples.py
@@ -247,7 +247,7 @@ def plot_coastline_vectors(verbose=True, save=False, show=True, dpi=300, resolut
plt.show()
else: plt.close()
-def convert_rectimage_2_dymaximage(inFilename, outFilename, verbose=True, scale=300, speedup=1, save=False, show=True):
+def convert_rectimage_2_dymaximage(inFilename, outFilename, verbose=True, scale=300, speedup=1, unfolding=constants.Unfolding.LAND, save=False, show=True):
'''
Convert rectilinear image to dymax projection image.
@@ -282,7 +282,7 @@ def convert_rectimage_2_dymaximage(inFilename, outFilename, verbose=True, scale=
stdout.flush() # I would add flush=True to print, but thats only in python3.3+
for j, lat in enumerate(np.linspace(90, -90, ysize/speedup, endpoint=True)):
j *= speedup
- newx, newy = convert.lonlat2dymax(lon, lat)
+ newx, newy = convert.lonlat2dymax(lon, lat, unfolding=unfolding)
newx = int(newx*scale) - 1
newy = int(newy*scale)
try: dymaximg.putpixel((newx, newy), pix[i, j])
@@ -361,7 +361,7 @@ def plot_face_hq(resolution='i', save=False, show=True, verbose=True, dpi=300):
# Draw final figure bits
plt.axis('off')
plt.gca().set_aspect('equal')
- if save: plt.savefig('dymax_earthmeridianstriangles.png', bbox_inches='tight', dpi=dpi, transparent=True, pad_inches=0)
+ if save: plt.savefig('dymax_face.png', bbox_inches='tight', dpi=dpi, transparent=True, pad_inches=0)
if show:
plt.tight_layout()
plt.show()
@@ -381,7 +381,9 @@ def run_examples(resolution='c', save=False, show=True, verbose=True):
plot_coastline_vectors(resolution=resolution, save=save, show=show)
plot_face_hq(resolution=resolution, save=save, show=show)
convert_rectimage_2_dymaximage(io.PKG_DATA+'bmng.jpg', 'dymax_bmng.png', save=save, show=show)
+ convert_rectimage_2_dymaximage(io.PKG_DATA+'bmng.jpg', 'dymax_net_bmng.png', unfolding=constants.Unfolding.NET, save=save, show=show)
convert_rectimage_2_dymaximage(io.PKG_DATA+'etopo1.jpg', 'dymax_etopo1.png', save=save, show=show)
+ convert_rectimage_2_dymaximage(io.PKG_DATA+'etopo1.jpg', 'dymax_ocean_etopo1.png', unfolding=constants.Unfolding.OCEAN, save=save, show=show)
if __name__ == '__main__':
run_examples()
diff --git a/svg/a2_dymaxion_a.svg b/svg/a2_dymaxion_a.svg
new file mode 100644
index 0000000..507dce3
--- /dev/null
+++ b/svg/a2_dymaxion_a.svg
@@ -0,0 +1,728 @@
+
+
diff --git a/svg/a2_dymaxion_b.svg b/svg/a2_dymaxion_b.svg
new file mode 100644
index 0000000..ebb49ea
--- /dev/null
+++ b/svg/a2_dymaxion_b.svg
@@ -0,0 +1,785 @@
+
+
diff --git a/svg/a3_dymaxion.svg b/svg/a3_dymaxion.svg
new file mode 100644
index 0000000..d11d142
--- /dev/null
+++ b/svg/a3_dymaxion.svg
@@ -0,0 +1,899 @@
+
+
diff --git a/svg/a4_dymaxion.svg b/svg/a4_dymaxion.svg
new file mode 100644
index 0000000..eb27088
--- /dev/null
+++ b/svg/a4_dymaxion.svg
@@ -0,0 +1,900 @@
+
+