diff --git a/.vscode/settings.json b/.vscode/settings.json index ead524ee..a46e5391 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,6 @@ { "minify.minifyExistingOnSave": true, - "editor.snippetSuggestions": "top" + "editor.snippetSuggestions": "top", + "python.pythonPath": "C:\\Users\\hausss\\.pyenv\\pyenv-win\\versions\\3.8.2\\python.exe", + "python.formatting.provider": "black" } \ No newline at end of file diff --git a/media/attribution.js b/media/attribution.js index e9131927..32ecf2f9 100644 --- a/media/attribution.js +++ b/media/attribution.js @@ -12136,6 +12136,13 @@ const attributionData = { "cdc" ] }, + { + prefix: "./media/naturals/global-cities", + all: "https://openstreetmap.org", + authors: [ + "openstreetmap" + ] + }, { prefix: "./media/food/plants/", files: [ diff --git a/media/naturals/global-cities/Beijing.svg b/media/naturals/global-cities/Beijing.svg new file mode 100644 index 00000000..ce067b9d --- /dev/null +++ b/media/naturals/global-cities/Beijing.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Berlin.svg b/media/naturals/global-cities/Berlin.svg new file mode 100644 index 00000000..8011eddb --- /dev/null +++ b/media/naturals/global-cities/Berlin.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Hong Kong.svg b/media/naturals/global-cities/Hong Kong.svg new file mode 100644 index 00000000..3283b2ca --- /dev/null +++ b/media/naturals/global-cities/Hong Kong.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Houston.svg b/media/naturals/global-cities/Houston.svg new file mode 100644 index 00000000..e4424bd8 --- /dev/null +++ b/media/naturals/global-cities/Houston.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/London.svg b/media/naturals/global-cities/London.svg new file mode 100644 index 00000000..e337ebeb --- /dev/null +++ b/media/naturals/global-cities/London.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Madrid.svg b/media/naturals/global-cities/Madrid.svg new file mode 100644 index 00000000..f5c1498f --- /dev/null +++ b/media/naturals/global-cities/Madrid.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Melbourne.svg b/media/naturals/global-cities/Melbourne.svg new file mode 100644 index 00000000..58ecb0a3 --- /dev/null +++ b/media/naturals/global-cities/Melbourne.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Moscow.svg b/media/naturals/global-cities/Moscow.svg new file mode 100644 index 00000000..6b5d6067 --- /dev/null +++ b/media/naturals/global-cities/Moscow.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/New York City.svg b/media/naturals/global-cities/New York City.svg new file mode 100644 index 00000000..4d951ea5 --- /dev/null +++ b/media/naturals/global-cities/New York City.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Paris.svg b/media/naturals/global-cities/Paris.svg new file mode 100644 index 00000000..d5de2a87 --- /dev/null +++ b/media/naturals/global-cities/Paris.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Seoul.svg b/media/naturals/global-cities/Seoul.svg new file mode 100644 index 00000000..3232b7f8 --- /dev/null +++ b/media/naturals/global-cities/Seoul.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/media/naturals/global-cities/Sydney.svg b/media/naturals/global-cities/Sydney.svg new file mode 100644 index 00000000..1a59b925 --- /dev/null +++ b/media/naturals/global-cities/Sydney.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/presets/naturals.js b/presets/naturals.js index 6d7728d4..6b851fb2 100644 --- a/presets/naturals.js +++ b/presets/naturals.js @@ -881,6 +881,19 @@ const cityData = [["Perris, CA", 81964684.1824094, 17340.390703739322], ["Santa Barbara, CA", 50991347.46845491, 7484.009670940266], ["Rio Rancho, NM", 269136968.1901309, 23814.351777786604]]; +const globalCityData = [ + ["London", 1595951001.243258, 45078.7351319594], + ["Paris", 105295835.99015382, 9638.711635935364], + ["Melbourne", 37645388.45504674, 8374.051389167866], + ["Sydney", 4324012960.9402275, 89922.41773568685], + ["Berlin", 889606455.0316621, 37503.65910136853], + ["Moscow", 2556449120.0771136, 97614.50005992019], + ["Seoul", 607651322.3035502, 30365.92222630693], + ["Madrid", 605538730.8845485, 36915.51233779266], + ["Hong Kong", 152936581.1183557, 11981.32777728141], + ["Beijing", 16426832679.115694, 178940.11723688344], +] + function makePlanet(name, diameter, mass, image) { return { name: name, @@ -928,7 +941,7 @@ function makeMountains() { }; } -function makeGIS(data, category) { +function makeGIS(data, category, rename=true) { const baseLength = math.unit(1, "meters"); const baseArea = math.unit(1, "meters^2"); return { @@ -960,7 +973,7 @@ function makeGIS(data, category) { name: name, rename: true, image: { - source: "./media/naturals/" + category.toLowerCase().replace(/ /g, "-") + "/" + name.toLowerCase().replace(/ /g, "-") + ".svg" + source: "./media/naturals/" + category.toLowerCase().replace(/ /g, "-") + "/" + (rename ? name.toLowerCase().replace(/ /g, "-") + ".svg" : name + ".svg") } } }); @@ -1087,6 +1100,13 @@ function makeNaturals() { "Cities" )); + results.push(makeGIS( + globalCityData.sort((s1, s2) => { + return s1[0].localeCompare(s2[0]) + }), + "Global Cities", + false + )); results.push(makeSkylines( [ ["Los Angeles", math.unit(1018, "feet")], diff --git a/scripts/osm-bounds/.gitignore b/scripts/osm-bounds/.gitignore new file mode 100644 index 00000000..919463b9 --- /dev/null +++ b/scripts/osm-bounds/.gitignore @@ -0,0 +1,2 @@ +*.svg +*.json \ No newline at end of file diff --git a/scripts/osm-bounds/cities.txt b/scripts/osm-bounds/cities.txt new file mode 100644 index 00000000..358e04d5 --- /dev/null +++ b/scripts/osm-bounds/cities.txt @@ -0,0 +1,10 @@ +London +Paris +Melbourne +Sydney +Berlin +Moscow +Seoul +Madrid +Hong Kong +Beijing \ No newline at end of file diff --git a/scripts/osm-bounds/get-polygon.py b/scripts/osm-bounds/get-polygon.py new file mode 100644 index 00000000..b07a7ca7 --- /dev/null +++ b/scripts/osm-bounds/get-polygon.py @@ -0,0 +1,88 @@ +import requests +import sys +import urllib.parse +import json +import subprocess +import os + +def get_polygon(name): + if not os.path.isfile(name + ".json"): + url = "https://nominatim.openstreetmap.org/search.php?q={0}&polygon_geojson=1&format=jsonv2".format( + urllib.parse.quote(name) + ) + r = requests.get(url) + data = json.loads(r.text) + + if data is None: + raise ValueError("Bogus results") + + osm_id = None + for entry in data: + if "boundary" in entry["category"] and entry["osm_type"] == "relation": + osm_id = entry["osm_id"] + break + + if not osm_id: + raise ValueError("No id") + + url = "http://polygons.openstreetmap.fr/get_geojson.py?id={0}¶ms=0".format(osm_id) + + with open(name + ".json", "w") as file: + file.write(requests.get(url).text) + else: + data = json.load(open(name + ".json")) + + info = subprocess.check_output( + [ + "mapshaper", + "-i", + "{0}.json".format(name), + "-each", + "console.log(this.centroidX, this.centroidY, this.area)"], + shell=True, + stderr=subprocess.STDOUT, + ).decode("utf-8") + + lon, lat, area = list(map(float, info.split(" "))) + if area is not None: + info = subprocess.check_output( + [ + "mapshaper", + "-i", + "{0}.json".format(name), + "-proj", + "+proj=nsper", + "+h=100000", + "+lat_0={0}".format(lat), + "+lon_0={0}".format(lon), + "-simplify", + "resolution=500x500", + "-each", + "console.log(\"HEIGHT:\" + this.height)", + "-o", + "{0}.svg".format(name), + ], + shell=True, + stderr=subprocess.STDOUT, + ).decode("utf-8") + height = None + for line in info.split("\n"): + if "HEIGHT:" in line: + height = float(line.split(":")[1].strip()) + print("[\"{0}\", {1}, {2}],".format(name, area, height)) + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: {0} list-of-cities".format(sys.argv[0])) + else: + city = None + try: + for city in open(sys.argv[1]).readlines(): + try: + get_polygon(city.strip()) + except ValueError as e: + print(city + " failed") + print(e) + except Exception as e: + print(city + " failed") + print(e) \ No newline at end of file diff --git a/scripts/osm-bounds/process-shapefile.py b/scripts/osm-bounds/process-shapefile.py new file mode 100644 index 00000000..3473bf3c --- /dev/null +++ b/scripts/osm-bounds/process-shapefile.py @@ -0,0 +1,41 @@ +import subprocess +import sys +import json + +def get_centroids(file, field_name): + results = {} + for entry in subprocess.check_output( + [ + "mapshaper", + "-i", + file, + "-each", + "\"console.log(JSON.stringify({{name: {0}, lon: this.centroidX, lat: this.centroidY}}))\"".format(field_name) + ], + shell = True, + stderr = subprocess.STDOUT + ).decode("utf-8").split("\n"): + print(entry) + parts = json.loads(entry) + results[parts["name"]] = { + "lon": float(parts["lon"]), + "lat": float(parts["lat"]) + } + + return results + +def extract_shape(file, field_name, field_value): + lat, lon = subprocess.check_output( + [ + "mapshaper", + "-i", + file, + "-filter", + "\"{0} == {1}\"".format(field_name, field_value), + "-each", + "\"console.log(this.centroidX, this.centroidY)" + ] + ) + +if __name__ == "__main__": + print(get_centroids(sys.argv[1], sys.argv[2])) \ No newline at end of file