From ab1dce1d1526a33afe4d27b200d833cf4872a2fe Mon Sep 17 00:00:00 2001 From: nathan Date: Fri, 19 Jun 2020 22:04:57 -0700 Subject: [PATCH] testing loading with fiona instead of geopandas (eliminates dependencies not available for raspberry pi) and tested loading place names --- Map.cpp | 43 ++++++++++++++++++++++--- Map.h | 16 +++++++++- View.cpp | 19 ++++++++++- View.h | 1 + mapconverter-fiona-name.py | 35 ++++++++++++++++++++ mapconverter-fiona.py | 65 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 mapconverter-fiona-name.py create mode 100644 mapconverter-fiona.py diff --git a/Map.cpp b/Map.cpp index 38f18e3..b63a44e 100644 --- a/Map.cpp +++ b/Map.cpp @@ -32,6 +32,10 @@ #include "Map.h" #include #include +#include +#include +#include +#include bool Map::QTInsert(QuadTree *tree, Line *line, int depth) { @@ -186,8 +190,8 @@ Map::Map() { FILE *fileptr; if(!(fileptr = fopen("mapdata.bin", "rb"))) { - printf("Couldn't read mapdata.bin\nDid you run getmap.sh?\n"); - exit(0); + printf("No map file found\n"); + return; } fseek(fileptr, 0, SEEK_END); @@ -196,7 +200,7 @@ Map::Map() { mapPoints = (float *)malloc(mapPoints_count * sizeof(float)); if(!fread(mapPoints, sizeof(float), mapPoints_count, fileptr)){ - printf("Read error\n"); + printf("Map read error\n"); exit(0); } @@ -223,7 +227,7 @@ Map::Map() { } } - printf("map bounds: %f %f %f %f\n",root.lon_min, root.lon_max, root.lat_min, root.lat_max); + //printf("map bounds: %f %f %f %f\n",root.lon_min, root.lon_max, root.lat_min, root.lat_max); Point currentPoint; Point nextPoint; @@ -248,5 +252,36 @@ Map::Map() { QTInsert(&root, new Line(currentPoint, nextPoint), 0); } + + + + std::string line; + std::ifstream infile("mapnames"); + + + while (std::getline(infile, line)) + { + float lon, lat; + + std::istringstream iss(line); + + iss >> lon; + iss >> lat; + + std::string assemble; + + iss >> assemble; + + for(std::string s; iss >> s; ) { + assemble = assemble + " " + s; + } + + // std::cout << "[" << x << "," << y << "] " << assemble << "\n"; + Label *label = new Label(lon,lat,assemble); + mapnames.push_back(label); + } + + std::cout << "Read " << mapnames.size() << " place names\n"; + printf("done\n"); } diff --git a/Map.h b/Map.h index 0a0c012..3b75246 100644 --- a/Map.h +++ b/Map.h @@ -33,12 +33,24 @@ #define MAP_H #include +#include typedef struct Point{ float lat; float lon; } Point; +typedef struct Label{ + Point location; + std::string text; + + Label(float lon, float lat, std::string text) { + this->location.lon = lon; + this->location.lat = lat; + this->text = text; + } +} Label; + typedef struct Line{ float lat_min; float lat_max; @@ -112,9 +124,11 @@ public: std::vector getLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max); std::vector getLines(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max); + std::vector mapnames; + Map(); int mapPoints_count; - float *mapPoints; + float *mapPoints; }; #endif \ No newline at end of file diff --git a/View.cpp b/View.cpp index f2ef80c..cd2e845 100644 --- a/View.cpp +++ b/View.cpp @@ -727,10 +727,26 @@ void View::drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen } +void View::drawPlaceNames() { + + for(std::vector::iterator label = map.mapnames.begin(); label != map.mapnames.end(); ++label) { + float dx, dy; + int x,y; + + pxFromLonLat(&dx, &dy, (*label)->location.lon, (*label)->location.lat); + screenCoords(&x, &y, dx, dy); + + if(outOfBounds(x,y)) { + continue; + } + + drawString((*label)->text, x, y, mapFont, grey); + } +} void View::drawGeography() { - if((mapRedraw && !mapMoved) || (mapAnimating && elapsed(lastRedraw) > 8 * FRAMETIME)) { + if((mapRedraw && !mapMoved) || (mapAnimating && elapsed(lastRedraw) > 8 * FRAMETIME) || elapsed(lastRedraw) > 2000) { SDL_SetRenderTarget(renderer, mapTexture); @@ -739,6 +755,7 @@ void View::drawGeography() { SDL_RenderClear(renderer); drawLines(0, 0, screen_width, screen_height, 0); + drawPlaceNames(); SDL_SetRenderTarget(renderer, NULL ); diff --git a/View.h b/View.h index f03e854..c5ea051 100644 --- a/View.h +++ b/View.h @@ -124,6 +124,7 @@ class View { void drawScaleBars(); void drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max); void drawLines(int left, int top, int right, int bottom, int bailTime); + void drawPlaceNames(); void drawGeography(); void drawSignalMarks(Aircraft *p, int x, int y); void drawPlaneText(Aircraft *p); diff --git a/mapconverter-fiona-name.py b/mapconverter-fiona-name.py new file mode 100644 index 0000000..317fab6 --- /dev/null +++ b/mapconverter-fiona-name.py @@ -0,0 +1,35 @@ +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) \ No newline at end of file diff --git a/mapconverter-fiona.py b/mapconverter-fiona.py new file mode 100644 index 0000000..6f07c29 --- /dev/null +++ b/mapconverter-fiona.py @@ -0,0 +1,65 @@ +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)) \ No newline at end of file