moved new fiona-based mapconverter for airports and names into mapconverter.py. updated readme

This commit is contained in:
nathan 2020-06-22 23:10:09 -07:00
parent 9c46dcbd58
commit 85ded9d60c
7 changed files with 131 additions and 278 deletions

View file

@ -1,5 +1,8 @@
# viz1090
![demo gif](https://media.giphy.com/media/VGh0nJHerUFFNxeAZo/giphy.gif)
**This is work in progress**
@ -42,21 +45,17 @@ make clean; make
```
3. Download and process map data
Grab a shapefile with your desired level of detail from https://www.naturalearthdata.com/downloads
[This](https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip) is a good place to start.
Unzip and copy the .shp and .shx files.
```
sudo apt install python3 python3-pip
pip3 install geopandas tqdm
python3 mapconverter.py ne_10m_admin_1_states_provinces.shp
pip3 install fiona tqdm
./getmap.sh
```
This will produce a file mapdata.bin that viz1090 reads. If the file doesn't exist then visualizer will show planes and trails without any geography.
This will produce files for map and airport geometry, with labels, that viz1090 reads. If any of these files don't exist then visualizer will show planes and trails without any geography.
The default parameters for mapconverter should render resonably quickly on a Raspberri Pi 4. See the mapconverter section below for other options and more information about map sources.
The default parameters for mapconverter should render resonably quickly on a Raspberri Pi 4. See the mapconverter section below for other options.
3. (Windows only)
@ -99,6 +98,31 @@ viz1090 will open an SDL window set to the resolution of your screen.
| --uiscale [scale] | Scale up UI elements by integer amounts for high resolution screen |
| --fullscreen | Render fullscreen rather than in a window |
### MAPS
The best map data source I've found so far is https://www.naturalearthdata.com. This has a lot of useful GIS data, but not airport runways, which you can get from the FAA Aeronautical Data Delivery Service (https://adds-faa.opendata.arcgis.com/)
I've been using these files:
* [Map geometry](https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip)
* [Place names](https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_populated_places.zip)
* [Airport IATA codes](https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_airports.zip)
* [Airport runway geometry](https://opendata.arcgis.com/datasets/4d8fa46181aa470d809776c57a8ab1f6_0.zip)
The bash script getmap.sh will download (so long as the links don't break) and convert these. Alternatiely, you can pass shapefiles and other arguments to mapconverter.py directly
### MAPCONVERTER.PY RUNTIME OPTIONS
| Argument | Description |
| ----------------------------- | ----------- |
| --mapfile | shapefile for main map |
| --mapnames | shapefile for map place names |
| --airportfile | shapefile for airport runway outlines |
| --airportnames | shapefile for airport IATA names |
| --minpop | minimum population to show place names for (defaults to 100000) |
| --tolerance" | map simplification tolerance (defaults to 0.001, which works well on a Raspberry Pi 4 - smaller values will produce more detail but slow down the map refresh rate) |
### HARDWARE NOTES
This software was originally intended for Raspberry Pi devices, and it is currently optimized for the Raspberry Pi 4 with the following configuration:

View file

@ -1,5 +1,12 @@
#!/bin/bash
wget https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
unzip ne_10m_admin_1_states_provinces.zip
python3 mapconverter.py ne_10m_admin_1_states_provinces.shp
wget https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_populated_places.zip
wget https://www.naturalearthdata.com/http//www.naturalearthdata.com/download/10m/cultural/ne_10m_airports.zip
#this may not be up to date
wget https://opendata.arcgis.com/datasets/4d8fa46181aa470d809776c57a8ab1f6_0.zip
unzip '*.zip'
python3 mapconverter.py --mapfile ne_10m_admin_1_states_provinces.shp --mapnames ne_10m_populated_places.shp --airportfile Runways.shp --airportnames ne_10m_airports.shp

View file

@ -1,64 +0,0 @@
import cartopy.io.shapereader as shpreader
import numpy as np
from tqdm import tqdm
import zipfile
from io import BytesIO
#from urllib.request import urlopen
import requests
import argparse
import os
def convertLinestring(linestring):
outlist = []
pointx = linestring.coords.xy[0]
pointy = linestring.coords.xy[1]
for j in range(len(pointx)):
outlist.extend([float(pointx[j]),float(pointy[j])])
outlist.extend([0,0])
return outlist
def extractLines(shapefile, tolerance):
print("Extracting map lines")
outlist = []
for i in tqdm(range(len(shapefile))):
simplified = shapefile[i].geometry.simplify(tolerance, preserve_topology=False)
if(simplified.geom_type == "LineString"):
outlist.extend(convertLinestring(simplified))
elif(simplified.geom_type == "MultiPolygon" or simplified.geom_type == "Polygon"):
if(simplified.boundary.geom_type == "MultiLineString"):
for boundary in simplified.boundary:
outlist.extend(convertLinestring(boundary))
else:
outlist.extend(convertLinestring(simplified.boundary))
else:
print("Unsupported type: " + simplified.geom_type)
return outlist
parser = argparse.ArgumentParser(description='viz1090 Natural Earth Data Map Converter')
parser.add_argument("--tolerance", default=0.001, type=float, help="map simplification tolerance")
parser.add_argument("--scale", default="10m", choices=["10m","50m","110m"], type=str, help="map file scale")
parser.add_argument("mapfile", type=str, help="shapefile to load (e.g., from https://www.naturalearthdata.com/downloads/")
args = parser.parse_args()
shapefile = list(shpreader.Reader(args.mapfile).records())
outlist = extractLines(shapefile, args.tolerance)
bin_file = open("mapdata.bin", "wb")
np.asarray(outlist).astype(np.single).tofile(bin_file)
bin_file.close()
print("Wrote %d points" % (len(outlist) / 2))

View file

@ -1,85 +0,0 @@
import fiona
from shapely.geometry import shape
import numpy as np
from tqdm import tqdm
import zipfile
from io import BytesIO
#from urllib.request import urlopen
import requests
import argparse
import os
def convertLinestring(linestring):
outlist = []
pointx = linestring.coords.xy[0]
pointy = linestring.coords.xy[1]
for j in range(len(pointx)):
outlist.extend([float(pointx[j]),float(pointy[j])])
outlist.extend([0,0])
return outlist
def extractLines(shapefile, tolerance):
print("Extracting map lines")
outlist = []
for i in tqdm(range(len(shapefile))):
simplified = shape(shapefile[i]['geometry'])#.simplify(tolerance, preserve_topology=False)
if(simplified.geom_type == "LineString"):
outlist.extend(convertLinestring(simplified))
elif(simplified.geom_type == "MultiPolygon" or simplified.geom_type == "Polygon"):
if(simplified.boundary.geom_type == "MultiLineString"):
for boundary in simplified.boundary:
outlist.extend(convertLinestring(boundary))
else:
outlist.extend(convertLinestring(simplified.boundary))
else:
print("Unsupported type: " + simplified.geom_type)
return outlist
parser = argparse.ArgumentParser(description='viz1090 Natural Earth Data Map Converter')
parser.add_argument("--tolerance", default=0.001, type=float, help="map simplification tolerance")
parser.add_argument("--scale", default="10m", choices=["10m","50m","110m"], type=str, help="map file scale")
parser.add_argument("mapfile", type=str, help="shapefile to load (e.g., from https://www.naturalearthdata.com/downloads/")
args = parser.parse_args()
shapefile = fiona.open(args.mapfile)
outlist = extractLines(shapefile, args.tolerance)
bin_file = open("airportdata.bin", "wb")
np.asarray(outlist).astype(np.single).tofile(bin_file)
bin_file.close()
print("Wrote %d points" % (len(outlist) / 2))
bin_file = open("airportnames", "w")
shapefile = fiona.open("ne_10m_airports.shp")
count = 0
for i in tqdm(range(len(shapefile))):
xcoord = shapefile[i]['geometry']['coordinates'][0]
ycoord = shapefile[i]['geometry']['coordinates'][1]
name = shapefile[i]['properties']['iata_code']
outstring = "{0} {1} {2}\n".format(xcoord, ycoord, name)
bin_file.write(outstring)
count = count + 1
bin_file.close()
print("Wrote %d airport names" % count)

View file

@ -1,35 +0,0 @@
import fiona
from tqdm import tqdm
import argparse
import os
bin_file = open("mapnames", "w")
parser = argparse.ArgumentParser(description='viz1090 Natural Earth Data Map Converter')
parser.add_argument("--minpop", default=100000, type=int, help="map simplification tolerance")
parser.add_argument("--scale", default="10m", choices=["10m","50m","110m"], type=str, help="map file scale")
parser.add_argument("mapfile", type=str, help="shapefile to load (e.g., from https://www.naturalearthdata.com/downloads/")
args = parser.parse_args()
shapefile = fiona.open(args.mapfile)
count = 0
for i in tqdm(range(len(shapefile))):
xcoord = shapefile[i]['geometry']['coordinates'][0]
ycoord = shapefile[i]['geometry']['coordinates'][1]
pop = shapefile[i]['properties']['POP_MIN']
name = shapefile[i]['properties']['NAME']
if pop > args.minpop:
outstring = "{0} {1} {2}\n".format(xcoord, ycoord, name)
bin_file.write(outstring)
count = count + 1
bin_file.close()
print("Wrote %d place names" % count)

View file

@ -1,65 +0,0 @@
import fiona
from shapely.geometry import shape
import numpy as np
from tqdm import tqdm
import zipfile
from io import BytesIO
#from urllib.request import urlopen
import requests
import argparse
import os
def convertLinestring(linestring):
outlist = []
pointx = linestring.coords.xy[0]
pointy = linestring.coords.xy[1]
for j in range(len(pointx)):
outlist.extend([float(pointx[j]),float(pointy[j])])
outlist.extend([0,0])
return outlist
def extractLines(shapefile, tolerance):
print("Extracting map lines")
outlist = []
for i in tqdm(range(len(shapefile))):
simplified = shape(shapefile[i]['geometry']).simplify(tolerance, preserve_topology=False)
if(simplified.geom_type == "LineString"):
outlist.extend(convertLinestring(simplified))
elif(simplified.geom_type == "MultiPolygon" or simplified.geom_type == "Polygon"):
if(simplified.boundary.geom_type == "MultiLineString"):
for boundary in simplified.boundary:
outlist.extend(convertLinestring(boundary))
else:
outlist.extend(convertLinestring(simplified.boundary))
else:
print("Unsupported type: " + simplified.geom_type)
return outlist
parser = argparse.ArgumentParser(description='viz1090 Natural Earth Data Map Converter')
parser.add_argument("--tolerance", default=0.001, type=float, help="map simplification tolerance")
parser.add_argument("--scale", default="10m", choices=["10m","50m","110m"], type=str, help="map file scale")
parser.add_argument("mapfile", type=str, help="shapefile to load (e.g., from https://www.naturalearthdata.com/downloads/")
args = parser.parse_args()
shapefile = fiona.open(args.mapfile)
outlist = extractLines(shapefile, args.tolerance)
bin_file = open("mapdata.bin", "wb")
np.asarray(outlist).astype(np.single).tofile(bin_file)
bin_file.close()
print("Wrote %d points" % (len(outlist) / 2))

View file

@ -1,4 +1,5 @@
import geopandas
import fiona
from shapely.geometry import shape
import numpy as np
from tqdm import tqdm
import zipfile
@ -23,40 +24,110 @@ def convertLinestring(linestring):
def extractLines(shapefile, tolerance):
print("Extracting map lines")
outlist = []
simplified = shapefile['geometry'].simplify(tolerance, preserve_topology=False)
for i in tqdm(range(len(simplified))):
if(simplified[i].geom_type == "LineString"):
outlist.extend(convertLinestring(simplified[i]))
for i in tqdm(range(len(shapefile))):
if(tolerance > 0):
simplified = shape(shapefile[i]['geometry']).simplify(tolerance, preserve_topology=False)
else:
simplified =shape(shapefile[i]['geometry'])
if(simplified.geom_type == "LineString"):
outlist.extend(convertLinestring(simplified))
elif(simplified[i].geom_type == "MultiPolygon" or simplified[i].geom_type == "Polygon"):
elif(simplified.geom_type == "MultiPolygon" or simplified.geom_type == "Polygon"):
if(simplified[i].boundary.geom_type == "MultiLineString"):
for boundary in simplified[i].boundary:
if(simplified.boundary.geom_type == "MultiLineString"):
for boundary in simplified.boundary:
outlist.extend(convertLinestring(boundary))
else:
outlist.extend(convertLinestring(simplified[i].boundary))
outlist.extend(convertLinestring(simplified.boundary))
else:
print("Unsupported type: " + simplified[i].geom_type)
print("Unsupported type: " + simplified.geom_type)
return outlist
parser = argparse.ArgumentParser(description='viz1090 Natural Earth Data Map Converter')
parser.add_argument("--mapfile", type=str, help="shapefile for main map")
parser.add_argument("--mapnames", type=str, help="shapefile for map place names")
parser.add_argument("--airportfile", type=str, help="shapefile for airport runway outlines")
parser.add_argument("--airportnames", type=str, help="shapefile for airport IATA names")
parser.add_argument("--minpop", default=100000, type=int, help="map simplification tolerance")
parser.add_argument("--tolerance", default=0.001, type=float, help="map simplification tolerance")
parser.add_argument("--scale", default="10m", choices=["10m","50m","110m"], type=str, help="map file scale")
parser.add_argument("mapfile", type=str, help="shapefile to load (e.g., from https://www.naturalearthdata.com/downloads/")
args = parser.parse_args()
shapefile = geopandas.read_file(args.mapfile)
# mapfile
if args.mapfile is not None:
shapefile = fiona.open(args.mapfile)
outlist = extractLines(shapefile, args.tolerance)
outlist = extractLines(shapefile, args.tolerance)
bin_file = open("mapdata.bin", "wb")
np.asarray(outlist).astype(np.single).tofile(bin_file)
bin_file.close()
bin_file = open("mapdata.bin", "wb")
np.asarray(outlist).astype(np.single).tofile(bin_file)
bin_file.close()
print("Wrote %d points" % (len(outlist) / 2))
# mapnames
bin_file = open("mapnames", "w")
if args.mapnames is not None:
shapefile = fiona.open(args.mapnames)
count = 0
for i in tqdm(range(len(shapefile))):
xcoord = shapefile[i]['geometry']['coordinates'][0]
ycoord = shapefile[i]['geometry']['coordinates'][1]
pop = shapefile[i]['properties']['POP_MIN']
name = shapefile[i]['properties']['NAME']
if pop > args.minpop:
outstring = "{0} {1} {2}\n".format(xcoord, ycoord, name)
bin_file.write(outstring)
count = count + 1
bin_file.close()
print("Wrote %d place names" % count)
#airportfile
if args.airportfile is not None:
shapefile = fiona.open(args.airportfile)
outlist = extractLines(shapefile, 0)
bin_file = open("airportdata.bin", "wb")
np.asarray(outlist).astype(np.single).tofile(bin_file)
bin_file.close()
print("Wrote %d points" % (len(outlist) / 2))
#airportnames
if args.airportnames is not None:
bin_file = open("airportnames", "w")
shapefile = fiona.open(args.airportnames)
count = 0
for i in tqdm(range(len(shapefile))):
xcoord = shapefile[i]['geometry']['coordinates'][0]
ycoord = shapefile[i]['geometry']['coordinates'][1]
name = shapefile[i]['properties']['iata_code']
outstring = "{0} {1} {2}\n".format(xcoord, ycoord, name)
bin_file.write(outstring)
count = count + 1
bin_file.close()
print("Wrote %d airport names" % count)
print("Wrote %d points" % (len(outlist) / 2))