working natural earth mapconverter

This commit is contained in:
nathan 2020-06-18 19:29:45 -07:00
parent a580fbbba1
commit 5afa90b2dc
4 changed files with 106 additions and 141 deletions

30
Map.cpp
View file

@ -4,14 +4,14 @@
bool Map::QTInsert(QuadTree *tree, Line *line, int depth) {
if(depth > 25) {
// printf("fail [%f %f] -> [%f %f]\n",line->start.lon,line->start.lat,line->end.lon,line->end.lat);
// if(depth > 25) {
// // printf("fail [%f %f] -> [%f %f]\n",line->start.lon,line->start.lat,line->end.lon,line->end.lat);
// printf("bounds %f %f %f %f\n",tree->lon_min, tree->lon_max, tree->lat_min, tree->lat_max);
// fflush(stdout);
tree->lines.push_back(&(*line));
return true;
}
// // printf("bounds %f %f %f %f\n",tree->lon_min, tree->lon_max, tree->lat_min, tree->lat_max);
// // fflush(stdout);
// tree->lines.push_back(&(*line));
// return true;
// }
bool startInside = line->start.lat >= tree->lat_min &&
@ -24,17 +24,17 @@ bool Map::QTInsert(QuadTree *tree, Line *line, int depth) {
line->end.lon >= tree->lon_min &&
line->end.lon <= tree->lon_max;
if (!startInside || !endInside) {
return false;
}
// if (!startInside && !endInside) {
// if (!startInside || !endInside) {
// return false;
// }
if (!startInside && !endInside) {
return false;
}
// if (startInside != endInside) {
// tree->lines.push_back(&(*line));
// return true;
// }
if (startInside != endInside) {
tree->lines.push_back(&(*line));
return true;
}
if (tree->nw == NULL) {
tree->nw = new QuadTree;

View file

@ -1,12 +1,20 @@
# viz1090
**This is work in progress**
There are a lot of missing pieces in this implementation so far:
* A proper map system yet. Eventually map data should be pulled from Mapbox or similar.
* In-application menus or configuration yet.
There are some major fixes and cleanup that need to happen before a relase:
* Everything is a grab bag of C and C++, need to more consistently modernize
* A full refactor, especially View.cpp, necessary for many of the new features below.
* A working Android build, as this is the best way to run this on portable hardware.
There are also a lot of missing features:
* Map improvements
* Labels, different colors/line weights for features
* Tile prerenderer for improved performance
* In-application menus for view options and configuration
* Theming/colormaps (important as this is primarily intended to be eye candy!)
* Integration with handheld features like GPS, battery monitors, buttons/dials, etc.
* Android build is currently broken
### BUILDING
@ -34,30 +42,21 @@ make clean; make
```
3. Download and process map data
Until more comprehensive map source (e.g., Mapbox) is integrated, viz1090 uses the lat/lon SVG files from https://www.mccurley.org
Grab a shapefile with your desired level of detail from https://www.naturalearthdata.com/downloads
The getmap.sh pulls the large SVG file for the contiguous 48 US states and produces a binary file for viz1090 to read.
[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 lxml numpy tqdm
./getmap.sh
pip3 install geopandas tqdm
python3 mapconverter.py ne_10m_admin_1_states_provinces.shp
```
There is also a world map avaiable from McCurley (https://mccurley.org/svg/data/World.svgz), which is much lower resolution and thus better for lower power hardware.
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.
The mapconverter script called by getmap.sh downsamples the file to render resonably quickly on a Raspberri Pi 4. If you are on a slower device (e.g, a Raspberry Pi 3), you may want to try something like:
```
python3 mapconverter.py --resolution 64 all.svg
```
On the other hand, if you are on a modern desktop or laptop, you can use something higher (but you probably don't need the full 6 digit precision of the McCurley SVG file):
```
python3 mapconverter.py --resolution 8192 all.svg
```
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)

View file

@ -292,7 +292,7 @@ void View::font_init() {
// todo separate style stuff
//
SDL_Color bgcolor = {0,0,0,255};
SDL_Color bgcolor = {0,0,20,255};
SDL_Color greenblue = {236,192,68,255};
SDL_Color lightblue = {211,208,203,255};
SDL_Color mediumblue ={110,136,152,255};
@ -667,26 +667,33 @@ void View::drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen
lineRGBA(renderer, x1, y1, x2, y2, style.mapInnerColor.r, style.mapInnerColor.g, style.mapInnerColor.b, 255);
}
//Debug quadtree
int tl_x,tl_y,tr_x,tr_y,bl_x,bl_y,br_x,br_y;
float dx,dy;
// //Debug quadtree
// int tl_x,tl_y,tr_x,tr_y,bl_x,bl_y,br_x,br_y;
// float dx,dy;
pxFromLonLat(&dx, &dy, tree->lat_min, tree->lon_min);
screenCoords(&tl_x, &tl_y, dx, dy);
// pxFromLonLat(&dx, &dy, tree->lon_min, tree->lat_min);
// screenCoords(&tl_x, &tl_y, dx, dy);
pxFromLonLat(&dx, &dy, tree->lat_max, tree->lon_min);
screenCoords(&tr_x, &tr_y, dx, dy);
// pxFromLonLat(&dx, &dy, tree->lon_max, tree->lat_min);
// screenCoords(&tr_x, &tr_y, dx, dy);
pxFromLonLat(&dx, &dy, tree->lat_min, tree->lon_max);
screenCoords(&bl_x, &bl_y, dx, dy);
// pxFromLonLat(&dx, &dy, tree->lon_min, tree->lat_max);
// screenCoords(&bl_x, &bl_y, dx, dy);
pxFromLonLat(&dx, &dy, tree->lat_max, tree->lon_max);
screenCoords(&br_x, &br_y, dx, dy);
// pxFromLonLat(&dx, &dy, tree->lon_max, tree->lat_max);
// screenCoords(&br_x, &br_y, dx, dy);
lineRGBA(renderer, tl_x, tl_y, tr_x, tr_y, 255, 0, 0, 255);
lineRGBA(renderer, tr_x, tr_y, br_x, br_y, 255, 0, 0, 255);
lineRGBA(renderer, bl_x, bl_y, br_x, br_y, 255, 0, 0, 255);
lineRGBA(renderer, tl_x, tl_y, bl_x, bl_y, 255, 0, 0, 255);
// lineRGBA(renderer, tl_x, tl_y, tr_x, tr_y, 50, 50, 50, 255);
// lineRGBA(renderer, tr_x, tr_y, br_x, br_y, 50, 50, 50, 255);
// lineRGBA(renderer, bl_x, bl_y, br_x, br_y, 50, 50, 50, 255);
// lineRGBA(renderer, tl_x, tl_y, bl_x, bl_y, 50, 50, 50, 255);
// // pixelRGBA(renderer,tl_x, tl_y,255,0,0,255);
// pixelRGBA(renderer,tr_x, tr_y,0,255,0,255);
// pixelRGBA(renderer,bl_x, bl_y,0,0,255,255);
// pixelRGBA(renderer,br_x, br_y,255,255,0,255);
}

View file

@ -1,103 +1,62 @@
import geopandas
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
outlist = []
tolerance = .05
coast = geopandas.read_file("ne_10m_coastline.shp")
coast_simple = coast['geometry'].simplify(tolerance, preserve_topology=False)
for i in tqdm(range(len(coast_simple))):
pointx = coast_simple[i].coords.xy[0]
pointy = coast_simple[i].coords.xy[1]
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 = []
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]))
elif(simplified[i].geom_type == "MultiPolygon" or simplified[i].geom_type == "Polygon"):
if(simplified[i].boundary.geom_type == "MultiLineString"):
for boundary in simplified[i].boundary:
outlist.extend(convertLinestring(boundary))
else:
outlist.extend(convertLinestring(simplified[i].boundary))
else:
print("Unsupported type: " + simplified[i].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 = geopandas.read_file(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))
# import json
# import numpy as np
# import sys
# from tqdm import tqdm
# import argparse
# parser = argparse.ArgumentParser(description='viz1090 SVG Map Converter')
# parser.add_argument("--resolution", default=250, type=int, help="downsample resolution")
# parser.add_argument("file", nargs="+", help="filename")
# args = parser.parse_args()
# if(len(args.file) == 0):
# print("No input filename given")
# exit()
# bin_file = open("mapdata.bin", "wb")
# outlist = []
# resolution = args.resolution
# for file in args.file:
# with open(file, "r") as read_file:
# data = json.load(read_file)
# print("Reading points")
# for i in tqdm(range(len(data['features']))):
# if(data['features'][i]['geometry']['type'] == 'LineString'):
# prevx = 0
# prevy = 0
# temp = []
# for currentPoint in data['features'][i]['geometry']['coordinates']:
# currentx = float(int(resolution * float(currentPoint[0]))) / resolution
# currenty = float(int(resolution * float(currentPoint[1]))) / resolution
# if(currentx != prevx or currenty != prevy):
# temp.extend([currentx,currenty])
# prevx = currentx
# prevy = currenty
# temp.extend(["0","0"])
# else:
# prevx = 0
# prevy = 0
# temp = []
# for currentLine in data['features'][i]['geometry']['coordinates']:
# for currentPoint in currentLine:
# currentx = float(int(resolution * float(currentPoint[0]))) / resolution
# currenty = float(int(resolution * float(currentPoint[1]))) / resolution
# if(currentx != prevx or currenty != prevy):
# temp.extend([currentx,currenty])
# prevx = currentx
# prevy = currenty
# temp.extend(["0","0"])
# outlist.extend(temp)
# np.asarray(outlist).astype(np.single).tofile(bin_file)
# bin_file.close()
# print("Wrote %d points" % (len(outlist) / 2))
print("Wrote %d points" % (len(outlist) / 2))