From 80e776d470abbe9a02cbd3990c9a8104a30a0d06 Mon Sep 17 00:00:00 2001 From: nathan Date: Sat, 20 Jun 2020 21:44:30 -0700 Subject: [PATCH] working runway drawing and airport names with conversion --- AppData.cpp | 26 ++-- AppData.h | 1 + Map.cpp | 220 ++++++++++++++++++++++++--------- Map.h | 6 + View.cpp | 44 +++++-- View.h | 2 +- mapconverter-fiona-airports.py | 85 +++++++++++++ viz1090.cpp | 4 +- 8 files changed, 308 insertions(+), 80 deletions(-) create mode 100644 mapconverter-fiona-airports.py diff --git a/AppData.cpp b/AppData.cpp index 8ed2b8c..ca61b85 100644 --- a/AppData.cpp +++ b/AppData.cpp @@ -62,16 +62,20 @@ void AppData::initialize() { void AppData::connect() { - c = (struct client *) malloc(sizeof(*c)); - while(1) { - if ((fd = setupConnection(c)) == ANET_ERR) { - fprintf(stderr, "Waiting on %s:%d\n", server, modes.net_input_beast_port); - sleep(1); - } else { - break; - } + + if(connected) { + return; } + c = (struct client *) malloc(sizeof(*c)); + + if ((fd = setupConnection(c)) == ANET_ERR) { + fprintf(stderr, "Waiting on %s:%d\n", server, modes.net_input_beast_port); + return; + } + + connected = true; + fprintf(stderr, "Connected to %s:%d\n", server, modes.net_input_beast_port); } @@ -82,6 +86,10 @@ void AppData::disconnect() { void AppData::update() { + if(!connected) { + return; + } + if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) { free(c); usleep(1000000); @@ -154,4 +162,6 @@ AppData::AppData(){ modes.interactive = 0; modes.quiet = 1; + + connected = false; } diff --git a/AppData.h b/AppData.h index 4900f8e..fc19fa5 100644 --- a/AppData.h +++ b/AppData.h @@ -45,6 +45,7 @@ class AppData { // struct client *c; + bool connected; int fd; char pk_buf[8]; diff --git a/Map.cpp b/Map.cpp index b63a44e..7a4c9ab 100644 --- a/Map.cpp +++ b/Map.cpp @@ -189,70 +189,135 @@ std::vector Map::getLines(float screen_lat_min, float screen_lat_max, flo Map::Map() { FILE *fileptr; - if(!(fileptr = fopen("mapdata.bin", "rb"))) { + if((fileptr = fopen("mapdata.bin", "rb"))) { + + + fseek(fileptr, 0, SEEK_END); + mapPoints_count = ftell(fileptr) / sizeof(float); + rewind(fileptr); + + mapPoints = (float *)malloc(mapPoints_count * sizeof(float)); + if(!fread(mapPoints, sizeof(float), mapPoints_count, fileptr)){ + printf("Map read error\n"); + exit(0); + } + + fclose(fileptr); + + printf("Read %d map points.\n",mapPoints_count / 2); + + // load quad tree + + for(int i = 0; i < mapPoints_count; i+=2) { + if(mapPoints[i] == 0) + continue; + + if(mapPoints[i] < root.lon_min) { + root.lon_min = mapPoints[i]; + } else if(mapPoints[i] > root.lon_max) { + root.lon_max = mapPoints[i]; + } + + if(mapPoints[i+1] < root.lat_min) { + root.lat_min = mapPoints[i+1]; + } else if(mapPoints[i+1] > root.lat_max) { + root.lat_max = mapPoints[i+1]; + } + } + + //printf("map bounds: %f %f %f %f\n",root.lon_min, root.lon_max, root.lat_min, root.lat_max); + + Point currentPoint; + Point nextPoint; + + for(int i = 0; i < mapPoints_count - 2; i+=2) { + if(mapPoints[i] == 0) + continue; + if(mapPoints[i + 1] == 0) + continue; + if(mapPoints[i + 2] == 0) + continue; + if(mapPoints[i + 3] == 0) + continue; + currentPoint.lon = mapPoints[i]; + currentPoint.lat = mapPoints[i + 1]; + + nextPoint.lon = mapPoints[i + 2]; + nextPoint.lat = mapPoints[i + 3]; + + // printf("inserting [%f %f] -> [%f %f]\n",currentPoint.lon,currentPoint.lat,nextPoint.lon,nextPoint.lat); + + QTInsert(&root, new Line(currentPoint, nextPoint), 0); + } + } else { printf("No map file found\n"); - return; - } - - fseek(fileptr, 0, SEEK_END); - mapPoints_count = ftell(fileptr) / sizeof(float); - rewind(fileptr); - - mapPoints = (float *)malloc(mapPoints_count * sizeof(float)); - if(!fread(mapPoints, sizeof(float), mapPoints_count, fileptr)){ - printf("Map read error\n"); - exit(0); - } - - fclose(fileptr); - - printf("Read %d map points.\n",mapPoints_count / 2); - - // load quad tree - - for(int i = 0; i < mapPoints_count; i+=2) { - if(mapPoints[i] == 0) - continue; - - if(mapPoints[i] < root.lon_min) { - root.lon_min = mapPoints[i]; - } else if(mapPoints[i] > root.lon_max) { - root.lon_max = mapPoints[i]; - } - - if(mapPoints[i+1] < root.lat_min) { - root.lat_min = mapPoints[i+1]; - } else if(mapPoints[i+1] > root.lat_max) { - root.lat_max = mapPoints[i+1]; - } - } - - //printf("map bounds: %f %f %f %f\n",root.lon_min, root.lon_max, root.lat_min, root.lat_max); - - Point currentPoint; - Point nextPoint; - - for(int i = 0; i < mapPoints_count - 2; i+=2) { - if(mapPoints[i] == 0) - continue; - if(mapPoints[i + 1] == 0) - continue; - if(mapPoints[i + 2] == 0) - continue; - if(mapPoints[i + 3] == 0) - continue; - currentPoint.lon = mapPoints[i]; - currentPoint.lat = mapPoints[i + 1]; - - nextPoint.lon = mapPoints[i + 2]; - nextPoint.lat = mapPoints[i + 3]; - - // printf("inserting [%f %f] -> [%f %f]\n",currentPoint.lon,currentPoint.lat,nextPoint.lon,nextPoint.lat); - - QTInsert(&root, new Line(currentPoint, nextPoint), 0); - } + } +// + if((fileptr = fopen("airportdata.bin", "rb"))) { + fseek(fileptr, 0, SEEK_END); + airportPoints_count = ftell(fileptr) / sizeof(float); + rewind(fileptr); + + airportPoints = (float *)malloc(airportPoints_count * sizeof(float)); + if(!fread(airportPoints, sizeof(float), airportPoints_count, fileptr)){ + printf("Map read error\n"); + exit(0); + } + + fclose(fileptr); + + printf("Read %d airport points.\n",airportPoints_count / 2); + + // load quad tree + + for(int i = 0; i < airportPoints_count; i+=2) { + if(airportPoints[i] == 0) + continue; + + if(airportPoints[i] < airport_root.lon_min) { + airport_root.lon_min = airportPoints[i]; + } else if(airportPoints[i] > airport_root.lon_max) { + airport_root.lon_max = airportPoints[i]; + } + + if(airportPoints[i+1] < airport_root.lat_min) { + airport_root.lat_min = airportPoints[i+1]; + } else if(airportPoints[i+1] > airport_root.lat_max) { + airport_root.lat_max = airportPoints[i+1]; + } + } + + //printf("map bounds: %f %f %f %f\n",root.lon_min, root.lon_max, root.lat_min, root.lat_max); + + Point currentPoint; + Point nextPoint; + + for(int i = 0; i < airportPoints_count - 2; i+=2) { + if(airportPoints[i] == 0) + continue; + if(airportPoints[i + 1] == 0) + continue; + if(airportPoints[i + 2] == 0) + continue; + if(airportPoints[i + 3] == 0) + continue; + currentPoint.lon = airportPoints[i]; + currentPoint.lat = airportPoints[i + 1]; + + nextPoint.lon = airportPoints[i + 2]; + nextPoint.lat = airportPoints[i + 3]; + + //printf("inserting [%f %f] -> [%f %f]\n",currentPoint.lon,currentPoint.lat,nextPoint.lon,nextPoint.lat); + + QTInsert(&airport_root, new Line(currentPoint, nextPoint), 0); + } + } else { + printf("No airport file found\n"); + } + +// std::string line; @@ -283,5 +348,38 @@ Map::Map() { std::cout << "Read " << mapnames.size() << " place names\n"; + infile.close(); + + infile.open("airportnames"); + + + 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); + airportnames.push_back(label); + } + + std::cout << "Read " << airportnames.size() << " airport names\n"; + + infile.close(); + + + printf("done\n"); } diff --git a/Map.h b/Map.h index 3b75246..cd4245b 100644 --- a/Map.h +++ b/Map.h @@ -119,16 +119,22 @@ class Map { public: QuadTree root; + QuadTree airport_root; bool QTInsert(QuadTree *tree, Line *line, int depth); 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; + std::vector airportnames; Map(); int mapPoints_count; float *mapPoints; + + int airportPoints_count; + float *airportPoints; + }; #endif \ No newline at end of file diff --git a/View.cpp b/View.cpp index cd2e845..23c48c8 100644 --- a/View.cpp +++ b/View.cpp @@ -647,12 +647,14 @@ void View::drawLines(int left, int top, int right, int bottom, int bailTime) { latLonFromScreenCoords(&screen_lat_min, &screen_lon_min, left, top); latLonFromScreenCoords(&screen_lat_max, &screen_lon_max, right, bottom); - drawLinesRecursive(&(map.root), screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max); + drawLinesRecursive(&(map.root), screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max, style.mapInnerColor); + + drawLinesRecursive(&(map.airport_root), screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max, orange); drawTrails(left, top, right, bottom); } -void View::drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max) { +void View::drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max, SDL_Color color) { if(tree == NULL) { return; } @@ -665,13 +667,13 @@ void View::drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen return; } - drawLinesRecursive(tree->nw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max); + drawLinesRecursive(tree->nw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max, color); - drawLinesRecursive(tree->sw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max); + drawLinesRecursive(tree->sw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max, color); - drawLinesRecursive(tree->ne, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max); + drawLinesRecursive(tree->ne, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max, color); - drawLinesRecursive(tree->se, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max); + drawLinesRecursive(tree->se, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max, color); std::vector::iterator currentLine; @@ -695,7 +697,7 @@ void View::drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen continue; } - lineRGBA(renderer, x1, y1, x2, y2, style.mapInnerColor.r, style.mapInnerColor.g, style.mapInnerColor.b, 255); + lineRGBA(renderer, x1, y1, x2, y2, color.r, color.g, color.b, 255); } // //Debug quadtree @@ -742,6 +744,20 @@ void View::drawPlaceNames() { drawString((*label)->text, x, y, mapFont, grey); } + + for(std::vector::iterator label = map.airportnames.begin(); label != map.airportnames.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, listFont, red); + } } void View::drawGeography() { @@ -1202,6 +1218,13 @@ void View::drawPlanes() { while(p) { if (p->lon && p->lat) { + + // if lon lat argments were not provided, start by snapping to the first plane we see + if(centerLon == 0 && centerLat == 0) { + mapTargetLon = p->lon; + mapTargetLat = p->lat; + } + int x, y; float dx, dy; @@ -1256,6 +1279,10 @@ void View::drawPlanes() { drawPlaneOffMap(x, y, &(p->cx), &(p->cy), planeColor); } else { drawPlaneIcon(usex, usey, p->track, planeColor); + + p->x += usex - p->cx; + p->y += usey - p->cy; + p->cx = usex; p->cy = usey; } @@ -1517,6 +1544,9 @@ View::View(AppData *appData){ fullscreen = 0; screen_index = 0; + centerLon = 0; + centerLat = 0; + maxDist = 25.0; mapMoved = 1; diff --git a/View.h b/View.h index c5ea051..5403b88 100644 --- a/View.h +++ b/View.h @@ -122,7 +122,7 @@ class View { void drawPlaneIcon(int x, int y, float heading, SDL_Color planeColor); void drawTrails(int left, int top, int right, int bottom); void drawScaleBars(); - void drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max); + void drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max, SDL_Color color); void drawLines(int left, int top, int right, int bottom, int bailTime); void drawPlaceNames(); void drawGeography(); diff --git a/mapconverter-fiona-airports.py b/mapconverter-fiona-airports.py new file mode 100644 index 0000000..0929813 --- /dev/null +++ b/mapconverter-fiona-airports.py @@ -0,0 +1,85 @@ +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) \ No newline at end of file diff --git a/viz1090.cpp b/viz1090.cpp index f1e0484..fe395a2 100644 --- a/viz1090.cpp +++ b/viz1090.cpp @@ -114,10 +114,7 @@ int main(int argc, char **argv) { } int go; - - appData.connect(); - view.SDL_init(); view.font_init(); @@ -125,6 +122,7 @@ int main(int argc, char **argv) { while (go == 1) { + appData.connect(); input.getInput(); appData.update(); view.draw();