So... many... maps...

I decided to spruce up my input SVG generation code, and got very carried away. I moved some of the bigger or more specific files into an Advanced folder in input, and then I got the horrible idea to make a super detailed computer-generated map from Natural Earth data with labels for everything and fancy borders, and then I had to do it. It took a very long time. But it is complete. Check out Advanced\Supermap if you have a powerful enough computer.
I also reorganised my code a bit and took better advantage of shapefiles.
This commit is contained in:
Justin Kunimune 2018-02-04 23:12:52 -10:00
parent 5e01e339b9
commit b50e63d19d
25 changed files with 14306 additions and 7019 deletions

View File

@ -43,8 +43,8 @@ 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 [Clouds.jpg](http://www.shadedrelief.com/natural3/pages/textures.html), [Rivers.png](http://www.shadedrelief.com/natural3/pages/extra.html), and [Political.svg](https://commons.wikimedia.org/wiki/File:BlankMap-Equirectangular.svg),
* **Natural Earth** for [Pastel.png](http://www.naturalearthdata.com/downloads/50m-raster-data/50m-natural-earth-2/) and their [vector coastline data](http://www.naturalearthdata.com/downloads/50m-physical-vectors/),
* **Tom Patterson** for [Clouds.jpg](http://www.shadedrelief.com/natural3/pages/textures.html), [Rivers.png](http://www.shadedrelief.com/natural3/pages/extra.html),
* **Natural Earth** for [Pastel.png](http://www.naturalearthdata.com/downloads/50m-raster-data/50m-natural-earth-2/) and their [detailed vector data](http://www.naturalearthdata.com/downloads/),
* **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 documentation of his map projection](http://www.genekeyes.com/CKOG-OOo/7-CKOG-illus-&-coastline.html),

6319
input/Advanced/Supermap.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.8 MiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 544 KiB

After

Width:  |  Height:  |  Size: 544 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 164 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 164 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@ -15,10 +15,10 @@
<rdf:Description
about="https://github.com/jkunimune15/Map-Projections/"
dc:title="Equirectangular map - 5 degree graticule"
dc:description="An Equirectangular graticule, showing all landmasses with 5 degree graticule."
dc:description="An Equirectangular graticule, showing all landmasses with 5 degree graticule, including the Polar Circles and the Tropics."
dc:creator="Justin Kunimune"
dc:source="http://www.naturalearthdata.com/"
dc:date="2018-01-15"
dc:date="2018-02-04"
dc:format="image/svg+xml"
dc:language="en" >
</rdf:Description>
@ -35,7 +35,7 @@
</metadata>
<title>Equirectangular map &#8211; 5&#0176; graticule</title>
<desc>
An Equirectangular graticule, showing all landmasses with 5&#0176; graticule, including the Arctic Circle, the Antarctic Circle, and the Tropics.
An Equirectangular graticule, showing all landmasses with 5&#0176; graticule, including the Polar Circles and the Tropics.
</desc>
<style>
.graticule {
@ -53,11 +53,11 @@
}
.tropics {
stroke:#bf0000;
stroke-dasharray:2;
stroke-dasharray:1;
}
.circles {
stroke:#0000bf;
stroke-dasharray:2;
stroke-dasharray:1;
}
</style>
<g transform="matrix(1,0,0,-1,180,90)">
@ -168,7 +168,6 @@
<path d="M-180,85h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1" />
<path class="prime-m" d="M-180,-90v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1" />
<path class="prime-m" d="M0,-90v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1" />
<path class="prime-m" d="M180,-90v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1v1" />
<path class="equator" d="M-180,0h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1" />
<path class="tropics" d="M-180,-23.43694h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1" />
<path class="tropics" d="M-180,23.43694h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1h1" />

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -18,7 +18,7 @@
dc:description="A mesh of great circles that intersect with 10-fold symmetry at 12 principal nodes and 6-fold symmetry at 20 minor nodes. Aligns with the edges of an icosohedron and its dual dodecahedron."
dc:creator="Justin Kunimune"
dc:source="http://www.naturalearthdata.com/"
dc:date="2018-01-15"
dc:date="2018-02-04"
dc:format="image/svg+xml"
dc:language="en" >
</rdf:Description>
@ -33,17 +33,18 @@
</cc:License>
</rdf:RDF>
</metadata>
<title>Icosohedral orthodromic mesh - Equirectangular projection</title>
<title>Icosohedral orthodromic mesh &#8211; Equirectangular projection</title>
<desc>
A mesh of great circles that intersect with 10-fold symmetry at 12 principal nodes and 6-fold symmetry at 20 minor nodes. Aligns with the edges of an icosohedron and its dual dodecahedron.
</desc>
<style>
path {
.lines {
stroke:#000000;
fill:none;
}
</style>
<g transform="matrix(1,0,0,-1,180,90)">
<g class="lines">
<path d="M-180,-90 L-180,-89 L-180,-88 L-180,-87 L-180,-86 L-180,-85 L-180,-84 L-180,-83 L-180,-82 L-180,-81 L-180,-80 L-180,-79 L-180,-78 L-180,-77 L-180,-76 L-180,-75 L-180,-74 L-180,-73 L-180,-72 L-180,-71 L-180,-70 L-180,-69 L-180,-68 L-180,-67 L-180,-66 L-180,-65 L-180,-64 L-180,-63 L-180,-62 L-180,-61 L-180,-60 L-180,-59 L-180,-58 L-180,-57 L-180,-56 L-180,-55 L-180,-54 L-180,-53 L-180,-52 L-180,-51 L-180,-50 L-180,-49 L-180,-48 L-180,-47 L-180,-46 L-180,-45 L-180,-44 L-180,-43 L-180,-42 L-180,-41 L-180,-40 L-180,-39 L-180,-38 L-180,-37 L-180,-36 L-180,-35 L-180,-34 L-180,-33 L-180,-32 L-180,-31 L-180,-30 L-180,-29 L-180,-28 L-180,-27 L-180,-26 L-180,-25 L-180,-24 L-180,-23 L-180,-22 L-180,-21 L-180,-20 L-180,-19 L-180,-18 L-180,-17 L-180,-16 L-180,-15 L-180,-14 L-180,-13 L-180,-12 L-180,-11 L-180,-10 L-180,-9 L-180,-8 L-180,-7 L-180,-6 L-180,-5 L-180,-4 L-180,-3 L-180,-2 L-180,-1 L-180,0 L-180,1 L-180,2 L-180,3 L-180,4 L-180,5 L-180,6 L-180,7 L-180,8 L-180,9 L-180,10 L-180,11 L-180,12 L-180,13 L-180,14 L-180,15 L-180,16 L-180,17 L-180,18 L-180,19 L-180,20 L-180,21 L-180,22 L-180,23 L-180,24 L-180,25 L-180,26 L-180,27 L-180,28 L-180,29 L-180,30 L-180,31 L-180,32 L-180,33 L-180,34 L-180,35 L-180,36 L-180,37 L-180,38 L-180,39 L-180,40 L-180,41 L-180,42 L-180,43 L-180,44 L-180,45 L-180,46 L-180,47 L-180,48 L-180,49 L-180,50 L-180,51 L-180,52 L-180,53 L-180,54 L-180,55 L-180,56 L-180,57 L-180,58 L-180,59 L-180,60 L-180,61 L-180,62 L-180,63 L-180,64 L-180,65 L-180,66 L-180,67 L-180,68 L-180,69 L-180,70 L-180,71 L-180,72 L-180,73 L-180,74 L-180,75 L-180,76 L-180,77 L-180,78 L-180,79 L-180,80 L-180,81 L-180,82 L-180,83 L-180,84 L-180,85 L-180,86 L-180,87 L-180,88 L-180,89 L-180,90 " />
<path d="M-144,-90 L-144,-89 L-144,-88 L-144,-87 L-144,-86 L-144,-85 L-144,-84 L-144,-83 L-144,-82 L-144,-81 L-144,-80 L-144,-79 L-144,-78 L-144,-77 L-144,-76 L-144,-75 L-144,-74 L-144,-73 L-144,-72 L-144,-71 L-144,-70 L-144,-69 L-144,-68 L-144,-67 L-144,-66 L-144,-65 L-144,-64 L-144,-63 L-144,-62 L-144,-61 L-144,-60 L-144,-59 L-144,-58 L-144,-57 L-144,-56 L-144,-55 L-144,-54 L-144,-53 L-144,-52 L-144,-51 L-144,-50 L-144,-49 L-144,-48 L-144,-47 L-144,-46 L-144,-45 L-144,-44 L-144,-43 L-144,-42 L-144,-41 L-144,-40 L-144,-39 L-144,-38 L-144,-37 L-144,-36 L-144,-35 L-144,-34 L-144,-33 L-144,-32 L-144,-31 L-144,-30 L-144,-29 L-144,-28 L-144,-27 L-144,-26 L-144,-25 L-144,-24 L-144,-23 L-144,-22 L-144,-21 L-144,-20 L-144,-19 L-144,-18 L-144,-17 L-144,-16 L-144,-15 L-144,-14 L-144,-13 L-144,-12 L-144,-11 L-144,-10 L-144,-9 L-144,-8 L-144,-7 L-144,-6 L-144,-5 L-144,-4 L-144,-3 L-144,-2 L-144,-1 L-144,0 L-144,1 L-144,2 L-144,3 L-144,4 L-144,5 L-144,6 L-144,7 L-144,8 L-144,9 L-144,10 L-144,11 L-144,12 L-144,13 L-144,14 L-144,15 L-144,16 L-144,17 L-144,18 L-144,19 L-144,20 L-144,21 L-144,22 L-144,23 L-144,24 L-144,25 L-144,26 L-144,27 L-144,28 L-144,29 L-144,30 L-144,31 L-144,32 L-144,33 L-144,34 L-144,35 L-144,36 L-144,37 L-144,38 L-144,39 L-144,40 L-144,41 L-144,42 L-144,43 L-144,44 L-144,45 L-144,46 L-144,47 L-144,48 L-144,49 L-144,50 L-144,51 L-144,52 L-144,53 L-144,54 L-144,55 L-144,56 L-144,57 L-144,58 L-144,59 L-144,60 L-144,61 L-144,62 L-144,63 L-144,64 L-144,65 L-144,66 L-144,67 L-144,68 L-144,69 L-144,70 L-144,71 L-144,72 L-144,73 L-144,74 L-144,75 L-144,76 L-144,77 L-144,78 L-144,79 L-144,80 L-144,81 L-144,82 L-144,83 L-144,84 L-144,85 L-144,86 L-144,87 L-144,88 L-144,89 L-144,90 " />
<path d="M-108,-90 L-108,-89 L-108,-88 L-108,-87 L-108,-86 L-108,-85 L-108,-84 L-108,-83 L-108,-82 L-108,-81 L-108,-80 L-108,-79 L-108,-78 L-108,-77 L-108,-76 L-108,-75 L-108,-74 L-108,-73 L-108,-72 L-108,-71 L-108,-70 L-108,-69 L-108,-68 L-108,-67 L-108,-66 L-108,-65 L-108,-64 L-108,-63 L-108,-62 L-108,-61 L-108,-60 L-108,-59 L-108,-58 L-108,-57 L-108,-56 L-108,-55 L-108,-54 L-108,-53 L-108,-52 L-108,-51 L-108,-50 L-108,-49 L-108,-48 L-108,-47 L-108,-46 L-108,-45 L-108,-44 L-108,-43 L-108,-42 L-108,-41 L-108,-40 L-108,-39 L-108,-38 L-108,-37 L-108,-36 L-108,-35 L-108,-34 L-108,-33 L-108,-32 L-108,-31 L-108,-30 L-108,-29 L-108,-28 L-108,-27 L-108,-26 L-108,-25 L-108,-24 L-108,-23 L-108,-22 L-108,-21 L-108,-20 L-108,-19 L-108,-18 L-108,-17 L-108,-16 L-108,-15 L-108,-14 L-108,-13 L-108,-12 L-108,-11 L-108,-10 L-108,-9 L-108,-8 L-108,-7 L-108,-6 L-108,-5 L-108,-4 L-108,-3 L-108,-2 L-108,-1 L-108,0 L-108,1 L-108,2 L-108,3 L-108,4 L-108,5 L-108,6 L-108,7 L-108,8 L-108,9 L-108,10 L-108,11 L-108,12 L-108,13 L-108,14 L-108,15 L-108,16 L-108,17 L-108,18 L-108,19 L-108,20 L-108,21 L-108,22 L-108,23 L-108,24 L-108,25 L-108,26 L-108,27 L-108,28 L-108,29 L-108,30 L-108,31 L-108,32 L-108,33 L-108,34 L-108,35 L-108,36 L-108,37 L-108,38 L-108,39 L-108,40 L-108,41 L-108,42 L-108,43 L-108,44 L-108,45 L-108,46 L-108,47 L-108,48 L-108,49 L-108,50 L-108,51 L-108,52 L-108,53 L-108,54 L-108,55 L-108,56 L-108,57 L-108,58 L-108,59 L-108,60 L-108,61 L-108,62 L-108,63 L-108,64 L-108,65 L-108,66 L-108,67 L-108,68 L-108,69 L-108,70 L-108,71 L-108,72 L-108,73 L-108,74 L-108,75 L-108,76 L-108,77 L-108,78 L-108,79 L-108,80 L-108,81 L-108,82 L-108,83 L-108,84 L-108,85 L-108,86 L-108,87 L-108,88 L-108,89 L-108,90 " />
@ -75,4 +76,5 @@
<path d="M108,-26.565 L108.653,-25.755 L109.296,-24.941 L109.932,-24.125 L110.559,-23.306 L111.178,-22.485 L111.791,-21.662 L112.396,-20.836 L112.994,-20.008 L113.587,-19.178 L114.173,-18.347 L114.754,-17.513 L115.329,-16.678 L115.900,-15.841 L116.466,-15.003 L117.027,-14.164 L117.584,-13.323 L118.138,-12.481 L118.687,-11.637 L119.234,-10.793 L119.777,-9.948 L120.318,-9.102 L120.856,-8.255 L121.391,-7.408 L121.925,-6.559 L122.457,-5.711 L122.987,-4.861 L123.516,-4.012 L124.044,-3.162 L124.571,-2.311 L125.097,-1.461 L125.623,-0.610 L126.149,0.240 L126.674,1.091 L127.200,1.941 L127.727,2.792 L128.254,3.642 L128.783,4.492 L129.313,5.341 L129.844,6.190 L130.376,7.039 L130.911,7.887 L131.448,8.734 L131.988,9.580 L132.530,10.426 L133.075,11.270 L133.623,12.114 L134.175,12.957 L134.730,13.798 L135.290,14.638 L135.853,15.477 L136.422,16.314 L136.995,17.150 L137.574,17.984 L138.157,18.817 L138.747,19.648 L139.343,20.476 L139.945,21.303 L140.555,22.127 L141.171,22.950 L141.795,23.769 L142.426,24.587 L143.066,25.401 L143.715,26.213 L144.373,27.022 L145.040,27.827 L145.717,28.630 L146.405,29.429 L147.104,30.224 L147.814,31.016 L148.535,31.804 L149.270,32.587 L150.017,33.367 L150.777,34.141 L151.552,34.911 L152.341,35.676 L153.145,36.436 L153.966,37.190 L154.802,37.938 L155.656,38.681 L156.528,39.417 L157.418,40.146 L158.328,40.868 L159.257,41.584 L160.207,42.291 L161.179,42.990 L162.173,43.681 L163.190,44.364 L164.230,45.037 L165.296,45.700 L166.386,46.353 L167.503,46.996 L168.647,47.627 L169.818,48.247 L171.018,48.854 L172.247,49.449 L173.506,50.031 L174.795,50.598 L176.116,51.151 L177.468,51.689 L178.852,52.211 L-179.732,52.716 L-178.283,53.204 L-176.801,53.674 L-175.286,54.126 L-173.739,54.558 L-172.160,54.969 L-170.548,55.360 L-168.905,55.729 L-167.232,56.076 L-165.530,56.400 L-163.799,56.701 L-162.042,56.976 L-160.260,57.227 L-158.454,57.453 L-156.628,57.652 L-154.782,57.824 L-152.921,57.970 L-151.045,58.088 L-149.159,58.178 L-147.264,58.241 L-145.365,58.275 L-143.463,58.281 L-141.562,58.259 L-139.664,58.209 L-137.774,58.131 L-135.893,58.025 L-134.025,57.891 L-132.173,57.730 L-130.338,57.542 L-128.523,57.328 L-126.730,57.089 L-124.962,56.824 L-123.219,56.534 L-121.505,56.220 L-119.819,55.883 L-118.163,55.523 L-116.537,55.142 L-114.944,54.739 L-113.383,54.316 L-111.854,53.873 L-110.358,53.411 L-108.895,52.931 L-107.464,52.433 L-106.066,51.918 L-104.700,51.387 L-103.366,50.841 L-102.063,50.279 L-100.791,49.704 L-99.549,49.115 L-98.336,48.513 L-97.153,47.898 L-95.997,47.272 L-94.869,46.634 L-93.767,45.985 L-92.691,45.326 L-91.639,44.658 L-90.612,43.979 L-89.608,43.292 L-88.627,42.596 L-87.668,41.892 L-86.730,41.180 L-85.812,40.461 L-84.913,39.735 L-84.033,39.002 L-83.172,38.262 L-82.328,37.516 L-81.500,36.765 L-80.689,36.007 L-79.893,35.245 L-79.112,34.477 L-78.346,33.704 L-77.593,32.927 L-76.853,32.145 L-76.126,31.359 L-75.411,30.569 L-74.708,29.775 L-74.015,28.978 L-73.333,28.177 L-72.662,27.373 L-72,26.565 " />
<path d="M108,-26.565 L109.060,-26.252 L110.115,-25.931 L111.164,-25.603 L112.207,-25.267 L113.244,-24.924 L114.276,-24.574 L115.301,-24.217 L116.321,-23.853 L117.335,-23.483 L118.344,-23.105 L119.346,-22.722 L120.343,-22.332 L121.335,-21.936 L122.321,-21.535 L123.301,-21.127 L124.276,-20.714 L125.246,-20.296 L126.210,-19.872 L127.169,-19.443 L128.123,-19.009 L129.072,-18.570 L130.017,-18.126 L130.956,-17.678 L131.891,-17.225 L132.821,-16.768 L133.747,-16.307 L134.668,-15.842 L135.585,-15.373 L136.498,-14.901 L137.407,-14.424 L138.312,-13.945 L139.213,-13.462 L140.111,-12.975 L141.005,-12.486 L141.895,-11.994 L142.783,-11.499 L143.667,-11.001 L144.548,-10.501 L145.427,-9.998 L146.303,-9.493 L147.176,-8.986 L148.047,-8.476 L148.915,-7.965 L149.781,-7.452 L150.645,-6.938 L151.508,-6.421 L152.368,-5.904 L153.227,-5.385 L154.085,-4.865 L154.941,-4.343 L155.796,-3.821 L156.650,-3.298 L157.503,-2.774 L158.355,-2.250 L159.207,-1.725 L160.058,-1.200 L160.909,-0.674 L161.760,-0.149 L162.610,0.377 L163.461,0.903 L164.312,1.428 L165.163,1.953 L166.015,2.478 L166.868,3.002 L167.721,3.526 L168.576,4.048 L169.431,4.570 L170.288,5.091 L171.146,5.611 L172.006,6.129 L172.867,6.646 L173.730,7.162 L174.595,7.676 L175.463,8.188 L176.332,8.698 L177.204,9.206 L178.078,9.713 L178.955,10.217 L179.835,10.718 L-179.283,11.218 L-178.397,11.714 L-177.508,12.208 L-176.616,12.699 L-175.721,13.187 L-174.821,13.672 L-173.919,14.154 L-173.012,14.632 L-172.101,15.107 L-171.187,15.578 L-170.268,16.045 L-169.345,16.508 L-168.417,16.968 L-167.485,17.423 L-166.548,17.873 L-165.607,18.320 L-164.660,18.761 L-163.709,19.198 L-162.753,19.630 L-161.791,20.057 L-160.824,20.478 L-159.853,20.894 L-158.875,21.305 L-157.892,21.710 L-156.904,22.109 L-155.910,22.502 L-154.911,22.889 L-153.906,23.270 L-152.895,23.645 L-151.878,24.012 L-150.856,24.373 L-149.828,24.727 L-148.794,25.075 L-147.754,25.414 L-146.708,25.747 L-145.657,26.072 L-144.600,26.389 L-143.537,26.699 L-142.468,27 L-141.394,27.294 L-140.314,27.579 L-139.229,27.856 L-138.138,28.124 L-137.041,28.384 L-135.940,28.634 L-134.833,28.876 L-133.721,29.109 L-132.604,29.333 L-131.482,29.547 L-130.356,29.751 L-129.225,29.947 L-128.090,30.132 L-126.951,30.308 L-125.808,30.474 L-124.661,30.629 L-123.510,30.775 L-122.356,30.910 L-121.199,31.036 L-120.039,31.150 L-118.876,31.255 L-117.711,31.349 L-116.544,31.432 L-115.374,31.505 L-114.203,31.567 L-113.031,31.619 L-111.857,31.659 L-110.683,31.689 L-109.508,31.709 L-108.332,31.717 L-107.157,31.715 L-105.981,31.702 L-104.806,31.678 L-103.632,31.643 L-102.459,31.598 L-101.287,31.541 L-100.117,31.475 L-98.948,31.397 L-97.782,31.309 L-96.618,31.211 L-95.456,31.102 L-94.297,30.982 L-93.142,30.853 L-91.989,30.713 L-90.840,30.563 L-89.695,30.403 L-88.553,30.233 L-87.415,30.053 L-86.282,29.863 L-85.153,29.664 L-84.029,29.455 L-82.910,29.236 L-81.795,29.009 L-80.685,28.772 L-79.581,28.526 L-78.481,28.272 L-77.387,28.008 L-76.299,27.736 L-75.216,27.456 L-74.138,27.167 L-73.066,26.870 L-72,26.565 " />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.3 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

@ -0,0 +1,143 @@
#compose_maps.py
#make ALL the maps
import math
from generate_borders import generate_borders
from generate_graticule import generate_graticule
from generate_indicatrices import generate_indicatrices
from generate_orthodromes import generate_orthodromes
from generate_shape import generate_administrivia, generate_disputes, generate_fine_borders, generate_land, generate_rivers, generate_lakes
from generate_labels import generate_topographical_labels, generate_political_labels, generate_urban_labels
def compose_landmasses():
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="land">')
generate_land('ne_50m', trim_antarctica=True)
print('\t\t</g>')
print('\t\t<g class="water">')
generate_lakes('ne_50m', max_rank=4)
print('\t\t</g>')
print('\t</g>')
def compose_graticule():
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="graticule">')
generate_graticule(5, 1, include_tropics=True, adjust_poles=True)
print('\t\t</g>')
print('\t</g>')
def compose_graticule2():
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="graticule">')
generate_graticule(15, .25, include_tropics=True, adjust_poles=True, double_dateline=True)
print('\t\t</g>')
print('\t</g>')
def compose_compound():
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="land">')
generate_land('ne_50m', trim_antarctica=True)
print('\t\t</g>')
print('\t\t<g class="river">')
generate_rivers('ne_50m', max_rank=4)
print('\t\t</g>')
print('\t\t<g class="lakes">')
generate_lakes('ne_50m', max_rank=4)
print('\t\t</g>')
print('\t\t<g class="graticule">')
generate_graticule(15, 1, include_tropics=True, adjust_poles=True)
print('\t\t</g>')
print('\t</g>')
def compose_indicatrices():
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="land">')
generate_land('ne_50m', trim_antarctica=True)
print('\t\t</g>')
print('\t\t<g class="lakes">')
generate_lakes('ne_50m', max_rank=4)
print('\t\t</g>')
print('\t\t<g class="tissot">')
generate_indicatrices(15, math.radians(3.75), adjust_poles=True)
print('\t\t</g>')
print('\t</g>')
def compose_indicatrices2(ctr_meridian):
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="land">')
generate_land('ne_110m')
print('\t\t</g>')
print('\t\t<g class="lakes">')
generate_lakes('ne_110m')
print('\t\t</g>')
print('\t\t<g class="graticule">')
generate_graticule(10, 1, double_dateline=True)
print('\t\t</g>')
print('\t\t<g class="tissot">')
generate_indicatrices(30, 600/6371, ctr_meridian=ctr_meridian, adjust_poles=True)
print('\t\t</g>')
print('\t</g>')
def compose_political():
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="country">')
generate_borders('ne_50m', trim_antarctica=True)
print('\t\t</g>')
print('\t\t<g class="lakes">')
generate_lakes('ne_50m', max_rank=4)
print('\t\t</g>')
print('\t</g>')
def compose_orthodromes():
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="lines">')
generate_orthodromes()
print('\t\t</g>')
print('\t</g>')
def compose_everything():
print('\t<g transform="matrix(1,0,0,-1,180,90)">')
print('\t\t<g class="country">')
generate_borders('ne_50m', trim_antarctica=True, borders_only=False)
print('\t\t</g>')
print('\t\t<g class="sovereign">')
generate_fine_borders('ne_50m')
print('\t\t</g>')
print('\t\t<g class="dispute">')
generate_disputes('ne_50m')
print('\t\t</g>')
print('\t\t<g class="adminis">')
generate_administrivia('ne_50m')
print('\t\t</g>')
print('\t\t<g class="land">')
generate_land('ne_50m', trim_antarctica=True)
print('\t\t</g>')
print('\t\t<g class="river">')
generate_rivers('ne_50m')
print('\t\t</g>')
print('\t\t<g class="lakes">')
generate_lakes('ne_50m')
print('\t\t</g>')
print('\t\t<g class="border">')
generate_borders('ne_50m', trim_antarctica=True, borders_only=True)
print('\t\t</g>')
print('\t\t<g class="graticule">')
generate_graticule(5, 1, include_tropics=True, adjust_poles=True)
print('\t\t</g>')
print('\t</g>')
generate_topographical_labels('ne_50m')
generate_political_labels('ne_50m')
generate_urban_labels('ne_50m')
if __name__ == '__main__':
# compose_landmasses()
# compose_graticule()
# compose_compound()
# compose_indicatrices()
# compose_indicatrices2(-20)
# compose_political()
# compose_orthodromes()
compose_everything()

View File

@ -0,0 +1,50 @@
import shapefile
from helpers import plot, trim_edges
SIZE_CLASSES = ['lg', 'md', 'sm', None, None, None]
def generate_borders(source, borders_only=False, labels=False, self_clip=False, trim_antarctica=False):
"""data from http://www.naturalearthdata.com/"""
sf = shapefile.Reader("data/{}_admin_0_countries".format(source))
sovereigns = {} #key is 3-char code, value is list of (record,shape)
for record, shape in zip(sf.records(), sf.shapes()):
if trim_antarctica:
if record[4] == 'ATA': #if it is Antarctica
shape.points = trim_edges(shape.points)
sovereigns[record[4]] = sovereigns.get(record[4], []) + [(record, shape)]
for code in sorted(sovereigns.keys()):
for record, shape in sovereigns[code]:
if record[3] == record[8]:
country_code = record[12]
# metropole = (record, shape)
# sovereigns[code].remove(metropole) #move the metropole to the front
# sovereigns[code] = [metropole] + sovereigns[code]
# break
print('\t\t\t<g id="{}">'.format(country_code))
for record, shape in sovereigns[code]:
x1, y1, x2, y2 = shape.bbox
x = (x1+x2)/2
y = (y1+y2)/2
region_code = record[12]
if country_code == region_code: #metropole
# name = record[3]
text_size = SIZE_CLASSES[int(record[2]-2)]
else: #dependency
# name = '{} ({})'.format(record[8], record[3])
text_size = SIZE_CLASSES[int(record[2]-1)]
# if labels:
# if text_size is not None:
# print('\t\t\t\t<text class="label-{}" x="{:.3f}" y="{:.3f}">{}</text>'.format(text_size, x, y, name))
if borders_only:
print('\t\t\t\t<clipPath id="{0}-clipPath">'.format(region_code))
print('\t\t\t\t\t<use href="#{0}-shape" />'.format(region_code))
print('\t\t\t\t</clipPath>')
print('\t\t\t\t<use href="#{0}-shape" style="fill:none; clip-path:url(#{0}-clipPath);" />'.format(region_code))
else:
plot(shape.points, midx=shape.parts, close=False, fourmat='xd', tabs=4, ident="{0}-shape".format(region_code))
print('\t\t\t</g>')

View File

@ -6,72 +6,17 @@ from helpers import plot, is_widdershins
SOURCE = 'ne_50m'
SKIP = 1
EXPAND_ANTARCTICA = True
MAX_RANK = 2
TRIM_ANTARCTICA = False
MAX_RANK = float('inf')
"""data from http://www.naturalearthdata.com/"""
sf = shapefile.Reader("data/{}_coastline".format(SOURCE))
pending_coasts = {} #key is last endpoint, value is list of points; every point should appear exactly twice, in each direction
split_points = {} #key is first endpoint of master curve, value is list of indices where the curve must be split
final_coasts = []
sf = shapefile.Reader("data/{}_land".format(SOURCE))
for record, shape in zip(sf.records(), sf.shapes()):
curve = shape.points[0:len(shape.points):SKIP]
if curve[-1] != shape.points[-1]: curve.append(shape.points[-1])
if len(curve) < 4: continue
if float(record[2]) > MAX_RANK: continue
if curve[0] == curve[-1]: #this curve is complete; we're done here
final_coasts.append(curve)
else:
if curve[0] in pending_coasts: #if this is an extension of another path
curve = pending_coasts.pop(curve[0]) + curve[1:] #replace that
elif curve[-1] in pending_coasts: #if this reversed is an extension of another path
curve = pending_coasts.pop(curve[-1]) + list(reversed(curve[:-1])) #replace that
pending_coasts[curve[-1]] = curve
pending_coasts[curve[0]] = list(reversed(curve))
# for key in pending_coasts:
# assert pending_coasts[key][-1] == key, "The curve from {} to {} is keyed by {}".format(val[0], val[-1], key)
# assert pending_coasts[key][0] in pending_coasts, "{} keys to a curve from {} to {}, but there is no key {}".format(key, val[0], val[-1], val[0])
for key, coast in pending_coasts.items():
if pending_coasts[coast[0]] is not None: #if the mirror is not checked
final_coasts.append(coast if is_widdershins(coast) else pending_coasts[coast[0]])
pending_coasts[key] = None #mark this as checked
final_coasts = sorted(sorted(sorted(final_coasts, key=lambda c:c[0][0]), key=lambda c:c[0][1]), key=len, reverse=True)
if SOURCE == 'ne_10m':
afroeurasia = final_coasts[1]
split_points[afroeurasia[0]] = [len(afroeurasia)]
final_coasts[1] += final_coasts.pop(12) #manually attach the Caspian to Afroeurasia
else:
afroeurasia = final_coasts[0]
for i in range(1,len(afroeurasia)):
if math.hypot(afroeurasia[i][0]-afroeurasia[i-1][0], afroeurasia[i][1]-afroeurasia[i-1][1]) > 10:
split_points[afroeurasia[0]] = [i] #manually detach the Caspian from Afroeurasia
break
if EXPAND_ANTARCTICA:
antarctica = final_coasts[2]
final_coasts[2] = [(antarctica[0][0], y) for y in range(-90, math.ceil(antarctica[0][1]))] +\
antarctica + [(antarctica[-1][0], y) for y in range(math.floor(antarctica[-1][1]), -91, -1)]
sf = shapefile.Reader("data/{}_lakes".format(SOURCE))
for record, lake in zip(sf.records(), sf.shapes()):
if float(record[-2]) > MAX_RANK: #if this lake isn't important enough
continue #skip it
x1l, y1l, x2l, y2l = lake.bbox
for i, continent in enumerate(final_coasts):
xc, yc = zip(*continent)
x1c, y1c, x2c, y2c = min(xc), min(yc), max(xc), max(yc)
if x1c < x1l and y1c < y1l and x2c > x2l and y2c > y2l: #if this continent contains this lake
curve = lake.points[0:len(lake.points):SKIP]
if curve[-1] != lake.points[-1]: curve.append(lake.points[-1])
split_points[continent[0]] = split_points.get(continent[0], []) + [len(continent)+p for p in lake.parts] #mark the movetos
final_coasts[i] = continent + curve #add it
break
for coast in final_coasts:
midx = [0] + split_points.get(coast[0], [])
plot(coast, midx=midx, fourmat='xd', close=False)
if TRIM_ANTARCTICA:
if shape.points[0][0] == -180 and shape.points[0][1] < -80: #if it is Antarctica
coast = shape.points
shape.points = [(coast[0][0],y) for y in range(-90,int(coast[0][1]))] + coast + [(coast[-1][0],y) for y in range(int(coast[-1][1]),-91,-1)]
plot(shape.points, midx=shape.parts, close=False, fourmat='xd')

View File

@ -1,34 +1,30 @@
import math
GRATICULE = 15
INCLUDE_TROPICS = True
ADJUST_POLES = True #set to True to reduce the number of meridians as you approach the pole
GRANULARITY = .25
AXIAL_TILT = 23.43694
ANTI_TILT = 66.56306
ANTI_TILT = 66.56306 #I have both of these because it's the easiest way to deal with roundoff
def plot_meridian(lamd, cut=0, clazz=None):
def plot_meridian(lamd, granularity, cut=0, clazz=None):
class_attr = 'class="{}" '.format(clazz) if clazz is not None else ''
tag = '\t\t\t<path {}d="M{},{}'.format(class_attr, lamd, cut-90) + 'v{}'.format(GRANULARITY)*round((180-2*cut)/GRANULARITY) + '" />'
tag = '\t\t\t<path {}d="M{},{}'.format(class_attr, lamd, cut-90) + 'v{}'.format(granularity)*round((180-2*cut)/granularity) + '" />'
print(tag)
def plot_parallel(phid, cut=0, clazz=None):
def plot_parallel(phid, granularity, cut=0, clazz=None):
class_attr = 'class="{}" '.format(clazz) if clazz is not None else ''
tag = '\t\t\t<path {}d="M{},{}'.format(class_attr, cut-180, phid) + 'h{}'.format(GRANULARITY)*round((360-2*cut)/GRANULARITY) + '" />'
tag = '\t\t\t<path {}d="M{},{}'.format(class_attr, cut-180, phid) + 'h{}'.format(granularity)*round((360-2*cut)/granularity) + '" />'
print(tag)
if __name__ == '__main__':
NUM_BASE = 90//GRATICULE
def generate_graticule(spacing, granularity, include_tropics=False, adjust_poles=False, double_dateline=False):
"""Generate a mesh of latitude and longitude lines"""
NUM_BASE = 90//spacing
cuts = [0]*(4*NUM_BASE)
if ADJUST_POLES:
if adjust_poles: #if this is True, reduce the number of meridians as you approach the pole
old_num = 1
for p in range(0, 90, GRATICULE):
new_num = old_num*int(1/math.cos(math.radians(p+GRATICULE/2))/old_num)
for p in range(0, 90, spacing):
new_num = old_num*int(1/math.cos(math.radians(p+spacing/2))/old_num)
while NUM_BASE%new_num != 0: new_num -= 1
if new_num >= 2*old_num:
for i in range(len(cuts)):
@ -36,17 +32,17 @@ if __name__ == '__main__':
cuts[i] = 90-p
old_num = new_num
for x in range(GRATICULE, 180, GRATICULE):
plot_meridian(-x, cut=cuts[x//GRATICULE%len(cuts)])
plot_meridian(x, cut=cuts[x//GRATICULE%len(cuts)])
for y in range(GRATICULE, 90, GRATICULE):
plot_parallel(-y)
plot_parallel(y)
for x in [-180, 0, 180]:
plot_meridian(x, clazz="prime-m")
plot_parallel(0, clazz="equator")
if INCLUDE_TROPICS:
plot_parallel(-AXIAL_TILT, clazz="tropics")
plot_parallel(AXIAL_TILT, clazz="tropics")
plot_parallel(-ANTI_TILT, clazz="circles")
plot_parallel(ANTI_TILT, clazz="circles")
for x in range(spacing, 180, spacing):
plot_meridian(-x, granularity, cut=cuts[x//spacing%len(cuts)])
plot_meridian(x, granularity, cut=cuts[x//spacing%len(cuts)])
for y in range(spacing, 90, spacing):
plot_parallel(-y, granularity)
plot_parallel(y, granularity)
for x in [-180, 0, 180] if double_dateline else [-180, 0]:
plot_meridian(x, granularity, clazz="prime-m")
plot_parallel(0, granularity, clazz="equator")
if include_tropics:
plot_parallel(-AXIAL_TILT, granularity, clazz="tropics")
plot_parallel(AXIAL_TILT, granularity, clazz="tropics")
plot_parallel(-ANTI_TILT, granularity, clazz="circles")
plot_parallel(ANTI_TILT, granularity, clazz="circles")

View File

@ -3,55 +3,53 @@ import math
from helpers import obliquify, plot
IND_NUM = 360
# IND_RAD = math.radians(3.75)
IND_RAD = 750/6371
SPACING = 30
ADJUST_SPACING = True
# IND_RAD = 750/6371
def plot_indicatrix(phi0, lam0, r):
def plot_indicatrix(phi0, lam0, r, res):
points = []
for l in range(0, 360, 360//IND_NUM):
for l in range(0, 360, 360//res):
points.append(obliquify(math.pi/2-r, math.radians(l), phi0, lam0))
plot(points)
def plot_side_indicatrix(phi0, r):
def plot_side_indicatrix(phi0, r, res):
points = []
midx = [0]
for l in range(0, 181, 360//IND_NUM):
points.append(obliquify(math.pi/2-r, math.radians(l), phi0, -math.pi))
for l in range(0, 181, 360//res):
pr, lr = obliquify(math.pi/2-r, math.radians(l), phi0, 0)
points.append((pr, lr - math.pi))
midx.append(len(points))
for l in range(180, 361, 360//IND_NUM):
pr, lr = obliquify(math.pi/2-r, math.radians(l), phi0, -math.pi)
points.append((pr, lr+2*math.pi))
for l in range(180, 361, 360//res):
pr, lr = obliquify(math.pi/2-r, math.radians(l), phi0, 0)
points.append((pr, lr + math.pi))
plot(points, midx=midx, close=False)
def plot_pole_indicatrix(north, r):
def plot_pole_indicatrix(north, r, res):
if north:
pp, pr = math.pi/2, math.pi/2-r
else:
pp, pr = -math.pi/2, -math.pi/2+r
points = [(pp, -math.pi)]
for x in range(-180, 181, 360//IND_NUM):
for x in range(-180, 181, 360//res):
points.append((pr, math.radians(x)))
points.append((pp, math.pi))
plot(points)
if __name__ == '__main__':
plot_pole_indicatrix(True, IND_RAD)
for y in range(-90+SPACING, 90, SPACING):
if ADJUST_SPACING:
step = SPACING * round(1/math.cos(math.radians(y)))
def generate_indicatrices(spacing, radius, adjust_poles=False, resolution=60, ctr_meridian=0):
plot_pole_indicatrix(True, radius, resolution)
for y in range(-90+spacing, 90, spacing):
if adjust_poles:
step = spacing * round(1/math.cos(math.radians(y)))
else:
step = SPACING
step = spacing
for x in range(-180, 180, step):
if abs(x) == 180:
plot_side_indicatrix(math.radians(y), math.pi/36)
if abs(x+ctr_meridian) == 180:
plot_side_indicatrix(math.radians(y), radius, resolution)
else:
plot_indicatrix(math.radians(y), math.radians(x), IND_RAD)
plot_pole_indicatrix(False, IND_RAD)
plot_indicatrix(math.radians(y), math.radians(x+ctr_meridian), radius, resolution)
plot_pole_indicatrix(False, radius, resolution)

View File

@ -0,0 +1,58 @@
#read data from a shapefile into SVG format
import shapefile
import math
from helpers import line_break, get_centroid
def plot_texts(data, label_class, source, max_rank, regulate_case=False, secondary_attr=None, force_points=False):
"""data from http://www.naturalearthdata.com/"""
sf = shapefile.Reader("data/{}_{}".format(source, data))
lat_idx = None
for i, field in enumerate(sf.fields):
if field[0] in ['scalerank', 'LABELRANK']:
rank_idx = i-1
if field[0] in ['name', 'NAME']:
name_idx = i-1
if field[0] == 'featurecla':
type_idx = i-1
if field[0] == secondary_attr:
secd_idx = i-1
if field[0] == 'lat_y':
lat_idx = i-1
if field[0] == 'long_x':
lon_idx = i-1
for record, shape in zip(sf.records(), sf.shapes()):
rank = record[rank_idx]
if rank <= max_rank:
if lat_idx is not None:
x, y = record[lon_idx], record[lat_idx]
else:
x, y = get_centroid(shape.points, shape.parts)
label = record[name_idx]
if not label:
continue #we can't waste our time worrying about features with no names
if label == 'EUROPE':
rank += 1 #You're not a continent! Get over it!
if regulate_case:
label = label.upper()
if secondary_attr is not None and record[7] == 'Dependency':
label = "{} ({})".format(label, record[secd_idx]) #indicate dependencies
text_size = ['sm', 'md', 'lg', 'xl'][min(3, int(max_rank-rank))] #lower ranks get bigger text
print('\t<text class="label-{} label-{}" x="{:.03f}" y="{:.03f}">{}</text>'.format(
label_class, text_size, 180+x, 90-y, label))
if force_points or record[type_idx] in ['mountain', 'depression', 'pole', 'waterfall']: #add circles to the ones that need markers
print('\t<circle cx="{:.03f}" cy="{:.03f}" r="{:.03f}" />'.format(180+x, 90-y, math.sqrt(max_rank-rank+1)*0.15))
def generate_political_labels(source, max_rank=4):
plot_texts('admin_0_countries', 'pol', source, max_rank, secondary_attr='NOTE_ADM0')
def generate_topographical_labels(source, max_rank=2):
plot_texts('geography_regions_points', 'geo', source, max_rank)
plot_texts('geography_regions_polys', 'geo', source, max_rank, regulate_case=True)
plot_texts('geography_regions_elevation_points', 'geo', source, max_rank)
plot_texts('geography_marine_polys', 'sea', source, max_rank)
def generate_urban_labels(source, max_rank=1):
plot_texts('populated_places', 'pol', source, max_rank, force_points=True)

View File

@ -0,0 +1,29 @@
import math
import numpy as np
import shapefile
from helpers import plot
SOURCE = 'ne_50m'
SKIP = 1
MAX_RANK = 2
INCLUDE_LAKES = False
"""data from http://www.naturalearthdata.com/"""
sf = shapefile.Reader("data/{}_lakes".format(SOURCE))
for record, lake in zip(sf.records(), sf.shapes()):
if float(record[-2]) > MAX_RANK: #if this lake isn't important enough
continue #skip it
x1l, y1l, x2l, y2l = lake.bbox
for i, continent in enumerate(final_coasts):
xc, yc = zip(*continent)
x1c, y1c, x2c, y2c = min(xc), min(yc), max(xc), max(yc)
if x1c < x1l and y1c < y1l and x2c > x2l and y2c > y2l: #if this continent contains this lake
curve = lake.points[0:len(lake.points):SKIP]
if curve[-1] != lake.points[-1]: curve.append(lake.points[-1])
split_points[continent[0]] = split_points.get(continent[0], []) + [len(continent)+p for p in lake.parts] #mark the movetos
final_coasts[i] = continent + curve #add it
break

View File

@ -14,7 +14,8 @@ def plot_orthodrome(phi0, lam0, tht0):
plot(points, close=False)
if __name__ == '__main__':
def generate_orthodromes():
"""generate an icosohedral orthodromic mesh, like the Brilliant logo (#notsponsored)"""
for l in range(-180, 180, 36):
plot_orthodrome(math.pi/2, 0, math.radians(l))
for l in range(0, 360, 72):

View File

@ -0,0 +1,38 @@
#read data from a shapefile into SVG format
import shapefile
from helpers import plot, trim_edges
def plot_shape(data, source, max_rank, trim_antarctica=False):
"""data from http://www.naturalearthdata.com/"""
sf = shapefile.Reader("data/{}_{}".format(source, data))
for i, field in enumerate(sf.fields):
if 'rank' in field[0]:
rank_idx = i-1
for record, shape in zip(sf.records(), sf.shapes()):
if record[rank_idx] <= max_rank:
if trim_antarctica:
if shape.points[0][1] < -60: #if it is Antarctica (this will have a few false positives, but that's fine)
shape.points = trim_edges(shape.points)
plot(shape.points, midx=shape.parts, close=False, fourmat='xd')
def generate_fine_borders(source, max_rank=float('inf')):
plot_shape('admin_0_map_units', source, max_rank)
def generate_disputes(source, max_rank=float('inf')):
plot_shape('admin_0_boundary_lines_disputed_areas', source, max_rank)
def generate_administrivia(source, max_rank=float('inf')):
plot_shape('admin_1_states_provinces_lines', source, max_rank)
def generate_land(source, max_rank=float('inf'), trim_antarctica=False):
plot_shape('land', source, max_rank, trim_antarctica=trim_antarctica)
def generate_rivers(source, max_rank=float('inf')):
plot_shape('rivers_lake_centerlines', source, max_rank)
def generate_lakes(source, max_rank=float('inf')):
plot_shape('lakes', source, max_rank)

View File

@ -1,4 +1,5 @@
import math
import random as rng
def obliquify(lat1, lon1, lat0, lon0):
@ -21,14 +22,20 @@ def obliquify(lat1, lon1, lat0, lon0):
while lonf > math.pi:
lonf -= 2*math.pi
while lonf < -math.pi:
lonf += 2*math.pi
return latf, lonf
def plot(coords, midx=[0], close=True, fourmat='pr'):
tag = '\t\t\t<path d="'
def plot(coords, midx=[0], close=True, fourmat='pr', clazz=None, ident=None, tabs=3):
class_attr = 'class="{}" '.format(clazz) if clazz is not None else ''
ident_attr = 'id="{}" '.format(ident) if ident is not None else ''
tag = '\t'*tabs+'<path {}{}d="'.format(class_attr, ident_attr)
last_move = None
for i, coord in enumerate(coords):
if i > 0 and coords[i-1] == coords[i]:
continue #no point repeating commands, though that sometimes happens
if coord == last_move:
tag += 'Z'
continue #save space by removing unnecessary repetitions
@ -51,9 +58,76 @@ def plot(coords, midx=[0], close=True, fourmat='pr'):
print(tag.replace('.000',''))
def is_widdershins(coords): #this method is not exact, but it should work well enough for my purposes.
x1, y1 = coords[0]
x2, y2 = coords[len(coords)//4]
x3, y3 = coords[len(coords)*3//4]
def trim_edges(coast):
"""remove the extra points placed along the edges of the Plate Carree map"""
for i in range(len(coast)-1, -1, -1):
x0, y0 = coast[i-1] if i > 0 else coast[i]
x1, y1 = coast[i]
x2, y2 = coast[i+1] if i < len(coast)-1 else coast[i]
if (abs(x0) > 179.99 or abs(y0) > 89.99) and (abs(x1) > 179.99 or abs(y1) > 89.99) and (abs(x2) > 179.99 or abs(y2) > 89.99):
coast.pop(i)
return coast
return (x2-x1)*(y3-y1) - (x3-x1)*(y2-y1) > 0
def line_break(line):
"""replace some space with a newline; whichever space is closest to the center"""
total_length = len(line)
words = line.split(' ')
best_length = float('inf')
left_length = 0
for i in range(len(words)-1):
left_length += len(words[i])+1
if max(left_length, total_length-left_length) < best_length:
best_length = max(left_length, total_length-left_length)
best_idx = left_length
return line[:best_idx-1] + '\n' + line[best_idx:]
def get_centroid(points, parts=None):
"""Compute the centroid of the spherical shape"""
minL = min([p[0] for p in points])
minP = min([p[1] for p in points])
maxL = max([p[0] for p in points])
maxP = max([p[1] for p in points])
if maxL-minL < 90:
return ((maxL+minL)/2, (maxP+minP)/2)
elif parts: #if there are multiple parts, try guessing the centroid of just one; the biggest one by bounding box
parts.append(len(points))
max_area = 0
for i in range(1, len(parts)):
part = points[parts[i-1]:parts[i]]
minL = min([p[0] for p in part])
minP = min([p[1] for p in part])
maxL = max([p[0] for p in part])
maxP = max([p[1] for p in part])
if (maxL-minL)*(maxP-minP) > max_area:
max_area = (maxL-minL)*(maxP-minP)
best_part = (parts[i-1], parts[i])
return get_centroid(points[best_part[0]:best_part[1]])
lines = []
for i in range(1, len(points)):
lines += [(*points[i-1], *points[i])]
xc, yc, zc = 0, 0, 0
j = 0
num_in = 0
while j < 4000 or num_in < 10:
j += 1
latr = math.asin(rng.random()*2-1)
lonr = rng.random()*2*math.pi - math.pi
latd, lond = math.degrees(latr), math.degrees(lonr)
num_crosses = 0
for l1, p1, l2, p2 in lines: #count the lines a northward ray crosses
if ((l1 <= lond and l2 > lond) or (l2 <= lond and l1 > lond)) and (p1*(l2-lond)/(l2-l1) + p2*(l1-lond)/(l1-l2) > latd):
num_crosses += 1
if num_crosses%2 == 1: #if odd,
num_in += 1
xc += math.cos(latr)*math.cos(lonr) #this point is in.
yc += math.cos(latr)*math.sin(lonr) #update the centroid
zc += math.sin(latr)
loncr = math.atan2(yc, xc)
latcr = math.atan2(zc, math.hypot(xc, yc))
return (math.degrees(loncr), math.degrees(latcr))