Compare commits

..

55 commits
tiles ... main

Author SHA1 Message Date
Tasia Iso 1e2b0dda2f
Merge branch 'tasiaiso-nix' 2025-02-23 22:37:26 +01:00
Tasia Iso 6743e1adf7
docs: add instructions for nix 2025-02-23 22:35:48 +01:00
Tasia Iso 7ceb1e69ab
build(nix): create nix flake and derivation 2025-02-23 22:35:25 +01:00
Tasia Iso 26a610c1a3
build(nix): add a patch to make viz1090 use the packaged mapdata 2025-02-23 19:10:00 +01:00
Tasia Iso 1922324b40
builld(nix): add nix flake and derivations 2025-02-23 00:41:37 +01:00
nmatsuda d1f53019b2
Merge pull request #13 from kalehmann/fix/getmap
Download links in the `getmap` script and cleanup the map data
2024-04-10 10:34:38 -07:00
Karsten Lehmann 36a398814e
fix: Download links in the getmap script and cleanup 2024-04-10 16:53:57 +02:00
nmatsuda ec055e1220
fixed uninitialized metric flag 2024-01-19 09:56:27 -08:00
nmatsuda 94930dde48
fixed shapely MultiLineString version issue
see https://gis.stackexchange.com/questions/456266/error-of-multilinestring-object-is-not-iterable
2023-08-23 17:00:00 -07:00
nmatsuda 43d4edebee
reverted test colors 2021-06-14 12:26:41 -07:00
nathan 69081b84c6 removed commented sections 2021-06-10 21:54:11 -07:00
nathan efe2687c10 fixed label surfaces not being freed before changes. added elapsed time check before label level change 2021-04-19 22:02:49 -07:00
nathan 319d910e8d labelLevel hysteresis now looks at target labelLevel size 2021-03-20 11:43:48 -07:00
nathan 721b9a4a17 fixed missing labels 2021-03-20 10:01:36 -07:00
nathan 383081d0de separate label and aircraft label classes [in progress] 2021-03-19 21:13:43 -07:00
nathan 2c484dc5fd trying label appear/disappear animations 2020-12-11 22:05:14 -08:00
nathan 74b1ae1c36 fixing label collision, still some issues with jumping 2020-12-11 21:21:28 -08:00
nathan c3bfbe4ff0 tweaking label hysteresis approach 2020-12-10 23:03:28 -08:00
nathan 6dbdaca8d0 added label display level hysteresis, other label motion adjustments 2020-12-09 20:58:27 -08:00
nathan f50cfc3c6e simplified resolveLabelConflicts. cleanup of label drawing in progress 2020-12-08 23:15:01 -08:00
nathan 56a4f252d6 added flag for fps display 2020-12-07 21:19:53 -08:00
nathan e9372475c9 fixed an issue prevent label positions from updating properly 2020-12-07 16:30:49 -08:00
nmatsuda d29a1e04e4
Added link to 3D printable case, still trying to make the GIF play more smoothly 2020-11-18 21:39:56 -08:00
nathan e3563f49e7 trying to fix readme bullet indentation 2020-08-31 10:45:18 -07:00
nathan 532d174362 trying to fix readme bullet indentation 2020-08-31 10:44:22 -07:00
nathan 4b976a273b readme depencies and WSL 2 options from @hhrhhr 2020-08-31 10:43:08 -07:00
nathan ddb9019194 removing accidentally commited binary files 2020-06-26 20:44:04 -07:00
nathan 3762585202 removed all thick and filled sdl_gfx operations to speed things up a little 2020-06-26 20:40:03 -07:00
nathan 831f4f672a spellcheck 2020-06-22 23:28:14 -07:00
nathan dc4c63aeff turned off fps debugging (may add as flag late) 2020-06-22 23:23:16 -07:00
nmatsuda 3fdc00b49d
another try at fixing gif 2020-06-22 23:21:13 -07:00
nathan cdb10b3d00 trying to embed gif in readme 2020-06-22 23:12:45 -07:00
nathan 85ded9d60c moved new fiona-based mapconverter for airports and names into mapconverter.py. updated readme 2020-06-22 23:10:09 -07:00
nathan 9c46dcbd58 fixed some drawTrail double line issues, cleaning up color assignments 2020-06-22 22:21:47 -07:00
nathan 80e776d470 working runway drawing and airport names with conversion 2020-06-20 21:44:30 -07:00
nathan ab1dce1d15 testing loading with fiona instead of geopandas (eliminates dependencies not available for raspberry pi) and tested loading place names 2020-06-19 22:04:57 -07:00
nathan 9c284a8460 carried over license from dump1090 per license terms 2020-06-18 20:03:38 -07:00
nathan f953b46f8e Merge branch 'natural_earth_maps' into main 2020-06-18 19:49:55 -07:00
nathan 1115280ba4 changed getmap.sh to new natural earth data source 2020-06-18 19:49:18 -07:00
nathan 352a06c80c testing cartopy instead of geopandas 2020-06-18 19:35:49 -07:00
nathan 5afa90b2dc working natural earth mapconverter 2020-06-18 19:29:45 -07:00
nathan a580fbbba1 working on shapefile conversion. now using geopandas to do it entirely in python. something is still wrong with the quadtree loader, need to debug 2020-06-17 23:42:39 -07:00
nathan ac5e777d78 removing shp and geojson files
Former-commit-id: ade3e41af34923766613364cc193d2dc95e0184a
2020-06-17 22:23:33 -07:00
nathan 5d6aa0e398 removed profiling files and changed gitignore for shp and geojson files
Former-commit-id: 80e12805b0dc79841b0996f11f28b53e50a590f7
Former-commit-id: 21a1e822e1596cecb779edbb0b788732c1d5131a
2020-06-17 22:12:23 -07:00
nathan 40f8edca66 removing profiling files
Former-commit-id: cef240e6ac16d1f361a6a6ef922d4ab6b0b979cc
2020-06-17 22:09:53 -07:00
nathan 6b219b43e7 load geojson files from ogr2ogr convert of shapefile
Former-commit-id: ad655164cf995c553ba491eb340c0ac75d92c9fe
2020-06-17 22:04:16 -07:00
nathan 14f0e15c76 moved drawtrails into map redraw logic for faster refresh when trails are long
Former-commit-id: 526374dcda6c078f3b58720b48c62edc16824903
2020-06-17 22:01:18 -07:00
nathan e8cf66ebb9 added resolution argument to mapconverter
Former-commit-id: 0f330b65175f27f4662c8eb56ff7eef105f97ac0
2020-06-16 21:50:58 -07:00
nathan eaf6bc70a8 fixed more warnings and Makefile issues. Should compile on mac now
Former-commit-id: cc10ac99b35ae34ba128642da32f0c9a223cfe31
2020-06-16 21:50:41 -07:00
nathan 83f2d6aa30 fixing c++ string literal and narrowing warnings
Former-commit-id: e92f153b516ab0fce55a9695ba91a2398f5ff719
2020-06-16 21:50:30 -07:00
nathan e198fffbd3 reenabled map texture shift reuse for improved speed. Added logic to redraw during big animated zooms or shifts
Former-commit-id: e135b9e4f4a0537a2de90c81a0f7ec8c6896f8fa
2020-06-16 21:49:53 -07:00
nathan 626a8fafbd plane animation tweaks
Former-commit-id: f102c7fb2e61b5b26d4d6ed78df7ac4d568b84fc
2020-06-16 21:46:51 -07:00
nathan 92d4bf928e fixed std:chrono issues
Former-commit-id: 2461384e0f6e6c638c2fadd8eb0263fc6d8d5dac
2020-06-14 15:26:26 -07:00
nathan df2ea21cde fixed ms clock issue using steady_clock -> high_resolution_clock. Changed line drawing to recursive instead of building line list in Map.cpp, seems to be a lot faster.
Former-commit-id: 81ff8167845869b8cf4fdc4ff3158aac84b24ce9
2020-06-13 22:15:47 -07:00
nathan 6caca48666 testing hard coded multipliers for latlon conversion and different quadtree filling logic
Former-commit-id: eee50502c57870a95890f85711286f3138da7ec7
2020-06-13 20:54:21 -07:00
43 changed files with 2716 additions and 1723 deletions

BIN
.DS_Store vendored

Binary file not shown.

22
.gitignore vendored
View file

@ -6,4 +6,24 @@
.~ .~
thumbs.db thumbs.db
viz1090 *.shp
*.shp*
*.shx*
*.shx
*.geojson
*.cpg
*.dbf
*.zip*
*.prj
*.xml
*.html
*.txt
airportnames
mapnames
viz1090
result

View file

@ -1,21 +1,47 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "Aircraft.h" #include "Aircraft.h"
#include "AircraftLabel.h"
Aircraft::Aircraft(uint32_t addr) { Aircraft::Aircraft(uint32_t addr) {
this->addr = addr; this->addr = addr;
created = 0;
prev_seen = 0; prev_seen = 0;
x = 0; lon = 0;
y = 0; lat = 0;
cx = 0;
cy = 0;
ox = 0; label = NULL;
oy = 0;
dox = 0; next = NULL;
doy = 0;
ddox = 0;
ddoy = 0;
} }

View file

@ -1,14 +1,48 @@
#include <stdint.h> // viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include <stdint.h>
#include <ctime> #include <ctime>
#include <vector> #include <vector>
#include <chrono>
class AircraftLabel;
class Aircraft { class Aircraft {
public: public:
uint32_t addr; // ICAO address uint32_t addr; // ICAO address
char flight[16]; // Flight number char flight[16]; // Flight number
unsigned char signalLevel[8]; // Last 8 Signal Amplitudes unsigned char signalLevel[8]; // Last 8 Signal Amplitudes
double messageRate; float messageRate;
int altitude; // Altitude int altitude; // Altitude
int speed; // Velocity int speed; // Velocity
int track; // Angle of flight int track; // Angle of flight
@ -16,29 +50,36 @@ public:
time_t seen; // Time at which the last packet was received time_t seen; // Time at which the last packet was received
time_t seenLatLon; // Time at which the last packet was received time_t seenLatLon; // Time at which the last packet was received
time_t prev_seen; time_t prev_seen;
double lat, lon; // Coordinated obtained from CPR encoded data float lat, lon; // Coordinated obtained from CPR encoded data
//history //history
std::vector <float> lonHistory, latHistory, headingHistory, timestampHistory; std::vector <float> lonHistory, latHistory, headingHistory;
std::vector <std::chrono::high_resolution_clock::time_point> timestampHistory;
AircraftLabel *label;
// float oldLon[TRAIL_LENGTH]; // float oldLon[TRAIL_LENGTH];
// float oldLat[TRAIL_LENGTH]; // float oldLat[TRAIL_LENGTH];
// float oldHeading[TRAIL_LENGTH]; // float oldHeading[TRAIL_LENGTH];
// time_t oldSeen[TRAIL_LENGTH]; // time_t oldSeen[TRAIL_LENGTH];
// uint8_t oldIdx; // uint8_t oldIdx;
uint64_t created; std::chrono::high_resolution_clock::time_point created;
uint64_t msSeen; std::chrono::high_resolution_clock::time_point msSeen;
uint64_t msSeenLatLon; std::chrono::high_resolution_clock::time_point msSeenLatLon;
int live; int live;
struct Aircraft *next; // Next aircraft in our linked list struct Aircraft *next; // Next aircraft in our linked list
//// label stuff -> should go to aircraft icon class //// label stuff -> should go to aircraft icon class
int x, y, cx, cy, w, h; // int x, y, cx, cy;
float ox, oy, dox, doy, ddox, ddoy; int x, y;
float pressure; // float w, h, target_w, target_h;
// float ox, oy, dox, doy, ddox, ddoy;
// float labelLevel;
// float opacity, target_opacity;
/// methods /// methods

538
AircraftLabel.cpp Normal file
View file

@ -0,0 +1,538 @@
#include "AircraftLabel.h"
#include "Aircraft.h"
#include <algorithm>
#include "SDL2/SDL2_gfxPrimitives.h"
using fmilliseconds = std::chrono::duration<float, std::milli>;
static std::chrono::high_resolution_clock::time_point now() {
return std::chrono::high_resolution_clock::now();
}
static float elapsed(std::chrono::high_resolution_clock::time_point ref) {
return (fmilliseconds {now() - ref}).count();
}
static float sign(float x) {
return (x > 0) - (x < 0);
}
SDL_Rect AircraftLabel::getFullRect(int labelLevel) {
SDL_Rect rect = {static_cast<int>(x),static_cast<int>(y),0,0};
SDL_Rect currentRect;
if(labelLevel < 2) {
currentRect = speedLabel.getRect();
rect.w = std::max(rect.w,currentRect.w);
rect.h += currentRect.h;
}
if(labelLevel < 1) {
currentRect = altitudeLabel.getRect();
rect.w = std::max(rect.w,currentRect.w);
rect.h += currentRect.h;
currentRect = speedLabel.getRect();
rect.w = std::max(rect.w,currentRect.w);
rect.h += currentRect.h;
}
return rect;
}
void AircraftLabel::update() {
char flight[17] = "";
snprintf(flight,17," %s", p->flight);
std::string flightString = flight;
flightString.erase(std::remove_if(flightString.begin(), flightString.end(), isspace), flightString.end());
flightLabel.setText(flightString);
char alt[10] = "";
if (metric) {
snprintf(alt,10," %dm", static_cast<int>(p->altitude / 3.2828));
} else {
snprintf(alt,10," %d'", p->altitude);
}
altitudeLabel.setText(alt);
char speed[10] = "";
if (metric) {
snprintf(speed,10," %dkm/h", static_cast<int>(p->speed * 1.852));
} else {
snprintf(speed,10," %dmph", p->speed);
}
speedLabel.setText(speed);
}
void AircraftLabel::clearAcceleration() {
ddx = 0;
ddy = 0;
}
float AircraftLabel::calculateDensity(Aircraft *check_p, int labelLevel) {
float density_max = 0;
while(check_p) {
if(check_p->addr == p->addr) {
check_p = check_p->next;
continue;
}
if(!check_p->label) {
check_p = check_p->next;
continue;
}
if(check_p->label->x + check_p->label->w < 0) {
check_p = check_p->next;
continue;
}
if(check_p->label->y + check_p->label->h < 0) {
check_p = check_p->next;
continue;
}
if(check_p->label->x > screen_width) {
check_p = check_p->next;
continue;
}
if(check_p->label->y > screen_height) {
check_p = check_p->next;
continue;
}
SDL_Rect currentRect = getFullRect(labelLevel);
float width_proportion = (currentRect.w + check_p->label->w) / fabs(x - check_p->label->x);
float height_proportion = (currentRect.h + check_p->label->h) / fabs(y - check_p->label->y);
float density = width_proportion * height_proportion;
if(density > density_max) {
density_max = density;
}
check_p = check_p -> next;
}
return density_max;
}
void AircraftLabel::calculateForces(Aircraft *check_p) {
if(w == 0 || h == 0) {
return;
}
Aircraft *head = check_p;
int p_left = x;
int p_right = x + w;
int p_top = y;
int p_bottom = y + h;
float boxmid_x = static_cast<float>(p_left + p_right) / 2.0f;
float boxmid_y = static_cast<float>(p_top + p_bottom) / 2.0f;
float offset_x = boxmid_x - p->x;
float offset_y = boxmid_y - p->y;
float target_length_x = attachment_dist + w / 2.0f;
float target_length_y = attachment_dist + h / 2.0f;
// stay icon_dist away from own icon
ddx -= sign(offset_x) * attachment_force * (fabs(offset_x) - target_length_x);
ddy -= sign(offset_y) * attachment_force * (fabs(offset_y) - target_length_y);
// screen edge
if(p_left < edge_margin) {
ddx += boundary_force * static_cast<float>(edge_margin - p_left);
}
if(p_right > screen_width - edge_margin) {
ddx += boundary_force * static_cast<float>(screen_width - edge_margin - p_right);
}
if(p_top < edge_margin) {
ddy += boundary_force * static_cast<float>(edge_margin - p_top);
}
if(p_bottom > screen_height - edge_margin) {
ddy += boundary_force * static_cast<float>(screen_height - edge_margin - p_bottom);
}
float all_x = 0;
float all_y = 0;
int count = 0;
//check against other labels
while(check_p) {
if(check_p->addr == p->addr) {
check_p = check_p->next;
continue;
}
if(!check_p->label) {
check_p = check_p->next;
continue;
}
int check_left = check_p->label->x;
int check_right = check_p->label->x + check_p->label->w;
int check_top = check_p->label->y;
int check_bottom = check_p->label->y + check_p->label->h;
float icon_x = static_cast<float>(check_p->x);
float icon_y = static_cast<float>(check_p->y);
float checkboxmid_x = static_cast<float>(check_left + check_right) / 2.0f;
float checkboxmid_y = static_cast<float>(check_top + check_bottom) / 2.0f;
float offset_x = boxmid_x - checkboxmid_x;
float offset_y = boxmid_y - checkboxmid_y;
float target_length_x = label_dist + static_cast<float>(check_p->label->w + w) / 2.0f;
float target_length_y = label_dist + static_cast<float>(check_p->label->h + h) / 2.0f;
float x_mag = std::max(0.0f,(target_length_x - fabs(offset_x)));
float y_mag = std::max(0.0f,(target_length_y - fabs(offset_y)));
// stay at least label_dist away from other icons
if(x_mag > 0 && y_mag > 0) {
ddx += sign(offset_x) * label_force * x_mag;
ddy += sign(offset_y) * label_force * y_mag;
}
// stay at least icon_dist away from other icons
offset_x = boxmid_x - check_p->x;
offset_y = boxmid_y - check_p->y;
target_length_x = icon_dist + static_cast<float>(check_p->label->w) / 2.0f;
target_length_y = icon_dist + static_cast<float>(check_p->label->h) / 2.0f;
x_mag = std::max(0.0f,(target_length_x - fabs(offset_x)));
y_mag = std::max(0.0f,(target_length_y - fabs(offset_y)));
if(x_mag > 0 && y_mag > 0) {
ddx += sign(offset_x) * icon_force * x_mag;
ddy += sign(offset_y) * icon_force * y_mag;
}
all_x += sign(boxmid_x - checkboxmid_x);
all_y += sign(boxmid_y - checkboxmid_y);
count++;
check_p = check_p -> next;
}
// move away from others
ddx += density_force * all_x / count;
ddy += density_force * all_y / count;
// char buff[100];
// snprintf(buff, sizeof(buff), "%2.2f", labelLevel);
// debugLabel.setText(buff);
float density_mult = 0.5f;
float level_rate = 0.25f;
if(elapsed(lastLevelChange) > 1000.0) {
if(labelLevel < 0.8f * density_mult * calculateDensity(head, labelLevel + 1)) {
if(labelLevel <= 2) {
labelLevel += level_rate;
lastLevelChange = now();
}
} else if (labelLevel > 1.2f * density_mult * calculateDensity(head, labelLevel - 1)) {
if(labelLevel >= 0) {
labelLevel -= level_rate;
lastLevelChange = now();
}
}
}
}
void AircraftLabel::applyForces() {
dx += ddx;
dy += ddy;
dx *= damping_force;
dy *= damping_force;
if(fabs(dx) > velocity_limit) {
dx = sign(dx) * velocity_limit;
}
if(fabs(dy) > velocity_limit) {
dy = sign(dy) * velocity_limit;
}
if(fabs(dx) < 0.01f) {
dx = 0;
}
if(fabs(dy) < 0.01f) {
dy = 0;
}
x += dx;
y += dy;
if(isnan(x)) {
x = 0;
}
if(isnan(y)) {
y = 0;
}
// x = p->cx + (int)round(p->ox);
// y = p->cy + (int)round(p->oy);
}
// SDL_Color signalToColor(int signal) {
// SDL_Color planeColor;
// if(signal > 127) {
// signal = 127;
// }
// if(signal < 0) {
// planeColor = setColor(96, 96, 96);
// } else {
// planeColor = setColor(parula[signal][0], parula[signal][1], parula[signal][2]);
// }
// return planeColor;
// }
// void View::drawSignalMarks(Aircraft *p, int x, int y) {
// unsigned char * pSig = p->signalLevel;
// unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
// pSig[4] + pSig[5] + pSig[6] + pSig[7] + 3) >> 3;
// SDL_Color barColor = signalToColor(signalAverage);
// Uint8 seenFade;
// if(elapsed(p->msSeen) < 1024) {
// seenFade = (Uint8) (255.0 - elapsed(p->msSeen) / 4.0);
// circleRGBA(renderer, x + mapFontWidth, y - 5, 2 * screen_uiscale, barColor.r, barColor.g, barColor.b, seenFade);
// }
// if(elapsed(p->msSeenLatLon) < 1024) {
// seenFade = (Uint8) (255.0 - elapsed(p->msSeenLatLon) / 4.0);
// hlineRGBA(renderer, x + mapFontWidth + 5 * screen_uiscale, x + mapFontWidth + 9 * screen_uiscale, y - 5, barColor.r, barColor.g, barColor.b, seenFade);
// vlineRGBA(renderer, x + mapFontWidth + 7 * screen_uiscale, y - 2 * screen_uiscale - 5, y + 2 * screen_uiscale - 5, barColor.r, barColor.g, barColor.b, seenFade);
// }
// }
void AircraftLabel::draw(SDL_Renderer *renderer, bool selected) {
if(x == 0 || y == 0) {
return;
}
// char buff[100];
// snprintf(buff, sizeof(buff), "%f %f", x, y);
// debugLabel.setText(buff);
int totalWidth = 0;
int totalHeight = 0;
// int margin = 4 * screen_uiscale;
int margin = 4;
SDL_Rect outRect;
if(opacity == 0 && labelLevel < 2) {
target_opacity = 1.0f;
}
if(opacity > 0 && labelLevel >= 2) {
target_opacity = 0.0f;
}
opacity += 0.25f * (target_opacity - opacity);
if(opacity < 0.05f) {
opacity = 0;
}
if(w != 0 && h != 0 && opacity > 0) {
SDL_Color drawColor = style.labelLineColor;
drawColor.a = static_cast<int>(255.0f * opacity);
if(selected) {
drawColor = style.selectedColor;
}
int tick = 4;
int anchor_x, anchor_y, exit_x, exit_y;
if(x + w / 2 > p->x) {
anchor_x = x;
} else {
anchor_x = x + w;
}
if(y + h / 2 > p->y) {
anchor_y = y - margin;
} else {
anchor_y = y + h + margin;
}
if(abs(anchor_x - p->x) > abs(anchor_y - p->y)) {
exit_x = (anchor_x + p->x) / 2;
exit_y = anchor_y;
} else {
exit_x = anchor_x;
exit_y = (anchor_y + p->y) / 2;
}
Sint16 vx[3] = {
static_cast<Sint16>(p->x),
static_cast<Sint16>(exit_x),
static_cast<Sint16>(anchor_x)};
Sint16 vy[3] = {
static_cast<Sint16>(p->y),
static_cast<Sint16>(exit_y),
static_cast<Sint16>(anchor_y)};
boxRGBA(renderer, x, y, x + w, y + h, style.labelBackground.r, style.labelBackground.g, style.labelBackground.b, drawColor.a);
// char buff[100];
// snprintf(buff, sizeof(buff), "%d", drawColor.a);
// debugLabel.setText(buff);
bezierRGBA(renderer, vx, vy, 3, 2, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
//lineRGBA(renderer, x,y - margin, x + tick, y - margin, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
lineRGBA(renderer, x,y - margin, x + w, y - margin, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
lineRGBA(renderer, x,y - margin, x, y - margin + tick, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
// lineRGBA(renderer, x + w, y - margin, x + w - tick, y - margin, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
lineRGBA(renderer, x + w, y - margin, x + w, y - margin + tick, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
//lineRGBA(renderer, x, y + h + margin, x + tick, y + h + margin, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
lineRGBA(renderer, x, y + h + margin, x + w, y + h + margin, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
lineRGBA(renderer, x, y + h + margin, x, y + h + margin - tick, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
// lineRGBA(renderer, x + w, y + h + margin,x + w - tick, y + h + margin, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
lineRGBA(renderer, x + w, y + h + margin,x + w, y + h + margin - tick, drawColor.r, drawColor.g, drawColor.b, drawColor.a);
}
if(labelLevel < 2 || selected) {
// drawSignalMarks(p, x, y);
SDL_Color drawColor = style.labelColor;
drawColor.a = static_cast<int>(255.0f * opacity);
flightLabel.setColor(drawColor);
flightLabel.setPosition(x,y);
flightLabel.draw(renderer);
// outRect = drawString(flight, x, y, mapBoldFont, drawColor);
outRect = flightLabel.getRect();
totalWidth = std::max(totalWidth,outRect.w);
totalHeight += outRect.h;
}
if(labelLevel < 1 || selected) {
SDL_Color drawColor = style.subLabelColor;
drawColor.a = static_cast<int>(255.0f * opacity);
altitudeLabel.setColor(drawColor);
altitudeLabel.setPosition(x,y + totalHeight);
altitudeLabel.draw(renderer);
outRect = altitudeLabel.getRect();
totalWidth = std::max(totalWidth,outRect.w);
totalHeight += outRect.h;
speedLabel.setColor(drawColor);
speedLabel.setPosition(x,y + totalHeight);
speedLabel.draw(renderer);
outRect = speedLabel.getRect();
totalWidth = std::max(totalWidth,outRect.w);
totalHeight += outRect.h;
}
debugLabel.setPosition(x,y + totalHeight);
debugLabel.draw(renderer);
target_w = totalWidth;
target_h = totalHeight;
w += 0.25f * (target_w - w);
h += 0.25f * (target_h - h);
if(w < 0.05f) {
w = 0;
}
if(h < 0.05f) {
h = 0;
}
}
AircraftLabel::AircraftLabel(Aircraft *p, bool metric, int screen_width, int screen_height, TTF_Font *font) {
this->p = p;
this->metric = metric;
x = p->x;
y = p->y + 20; //*screen_uiscale
w = 0;
h = 0;
target_w = 0;
target_h = 0;
opacity = 0;
target_opacity = 0;
dx = 0;
dy = 0;
ddx = 0;
ddy = 0;
this->screen_width = screen_width;
this->screen_height = screen_height;
labelLevel = 0;
flightLabel.setFont(font);
altitudeLabel.setFont(font);
speedLabel.setFont(font);
debugLabel.setFont(font);
lastLevelChange = now();
}

76
AircraftLabel.h Normal file
View file

@ -0,0 +1,76 @@
#include <string>
#include "SDL2/SDL_ttf.h"
#include <chrono>
#include "Label.h"
#include "Style.h"
class Aircraft;
class AircraftLabel {
public:
void update();
void clearAcceleration();
void calculateForces(Aircraft *check_p);
void applyForces();
void draw(SDL_Renderer *renderer, bool selected);
AircraftLabel(Aircraft *p, bool metric, int screen_width, int screen_height, TTF_Font *font);
private:
SDL_Rect getFullRect(int labelLevel);
float calculateDensity(Aircraft *check_p, int labelLevel);
Aircraft *p;
Label flightLabel;
Label altitudeLabel;
Label speedLabel;
Label debugLabel;
float labelLevel;
bool metric;
float x;
float y;
float w;
float h;
float target_w;
float target_h;
float dx;
float dy;
float ddx;
float ddy;
float opacity;
float target_opacity;
float pressure;
int screen_width;
int screen_height;
std::chrono::high_resolution_clock::time_point lastLevelChange;
///////////
float label_force = 0.001f;
float label_dist = 2.0f;
float density_force = 0.05f;
float attachment_force = 0.0015f;
float attachment_dist = 10.0f;
float icon_force = 0.001f;
float icon_dist = 15.0f;
float boundary_force = 0.01f;
float damping_force = 0.85f;
float velocity_limit = 2.0f;
float edge_margin = 15.0f;
Style style;
};

View file

@ -1,9 +1,38 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "AircraftList.h" #include "AircraftList.h"
#include <chrono> static std::chrono::high_resolution_clock::time_point now() {
return std::chrono::high_resolution_clock::now();
static uint64_t now() {
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
} }
@ -24,10 +53,14 @@ void AircraftList::update(Modes *modes) {
Aircraft *p = head; Aircraft *p = head;
while(p) { while(p) {
p->live = 0; p->live = 0;
p = p->next; p = p->next;
} }
//debug
//find(1)->live = 1;
while(a) { while(a) {
p = find(a->addr); p = find(a->addr);
@ -56,32 +89,39 @@ void AircraftList::update(Modes *modes) {
memcpy(p->flight, a->flight, sizeof(p->flight)); memcpy(p->flight, a->flight, sizeof(p->flight));
memcpy(p->signalLevel, a->signalLevel, sizeof(p->signalLevel)); memcpy(p->signalLevel, a->signalLevel, sizeof(p->signalLevel));
if(p->seenLatLon == a->seenLatLon) {
a = a->next;
continue;
}
p->msSeenLatLon = now();
p->seenLatLon = a->seenLatLon;
p->altitude = a->altitude; p->altitude = a->altitude;
p->speed = a->speed; p->speed = a->speed;
p->track = a->track; p->track = a->track;
p->vert_rate = a->vert_rate; p->vert_rate = a->vert_rate;
if(p->lon == 0) {
p->created = now();
}
if(p->lon == a->lon && p->lat == a->lat) {
a = a->next;
continue;
}
p->lon = a->lon; p->lon = a->lon;
p->lat = a->lat; p->lat = a->lat;
if(p->seenLatLon < a->seenLatLon) { p->lonHistory.push_back(p->lon);
p->msSeenLatLon = now(); p->latHistory.push_back(p->lat);
p->headingHistory.push_back(p->track);
// p->oldIdx = (p->oldIdx+1) % 32; p->timestampHistory.push_back(p->msSeenLatLon);
// p->oldLon[p->oldIdx] = p->lon;
// p->oldLat[p->oldIdx] = p->lat;
p->lonHistory.push_back(p->lon);
p->latHistory.push_back(p->lat);
p->headingHistory.push_back(p->track);
p->timestampHistory.push_back(p->seenLatLon);
// p->oldHeading[p->oldIdx] = p->track;
// p->oldSeen[p->oldIdx] = p->seenLatLon;
}
p->seenLatLon = a->seenLatLon;
a = a->next; a = a->next;
} }
@ -108,6 +148,10 @@ void AircraftList::update(Modes *modes) {
AircraftList::AircraftList() { AircraftList::AircraftList() {
head = nullptr; head = nullptr;
// //debug aircraft attached to mouse
// head = new Aircraft(1);
// memcpy(head->flight, "mouse", sizeof("mouse"));
} }
AircraftList::~AircraftList() { AircraftList::~AircraftList() {

View file

@ -1,3 +1,34 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "Aircraft.h" #include "Aircraft.h"
#include "dump1090.h" //for Modes #include "dump1090.h" //for Modes

View file

@ -1,10 +1,40 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "AppData.h" #include "AppData.h"
// //
//carried over from view1090.c //carried over from view1090.c
// //
int AppData::setupConnection(struct client *c) { int AppData::setupConnection(struct client *c) {
int fd; int fd;
@ -32,16 +62,20 @@ void AppData::initialize() {
void AppData::connect() { void AppData::connect() {
c = (struct client *) malloc(sizeof(*c));
while(1) { if(connected) {
if ((fd = setupConnection(c)) == ANET_ERR) { return;
fprintf(stderr, "Waiting on %s:%d\n", server, modes.net_input_beast_port);
sleep(1);
} else {
break;
}
} }
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);
} }
@ -52,6 +86,10 @@ void AppData::disconnect() {
void AppData::update() { void AppData::update() {
if(!connected) {
return;
}
if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) { if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) {
free(c); free(c);
usleep(1000000); usleep(1000000);
@ -59,7 +97,8 @@ void AppData::update() {
fd = setupConnection(c); fd = setupConnection(c);
return; return;
} }
modesReadFromClient(&modes, c,"",decodeBinMessage); char empty;
modesReadFromClient(&modes, c, &empty,decodeBinMessage);
interactiveRemoveStaleAircrafts(&modes); interactiveRemoveStaleAircrafts(&modes);
@ -123,4 +162,6 @@ AppData::AppData(){
modes.interactive = 0; modes.interactive = 0;
modes.quiet = 1; modes.quiet = 1;
connected = false;
} }

View file

@ -1,3 +1,34 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef APPDATA_H #ifndef APPDATA_H
#define APPDATA_H #define APPDATA_H
@ -14,6 +45,7 @@ class AppData {
// //
struct client *c; struct client *c;
bool connected;
int fd; int fd;
char pk_buf[8]; char pk_buf[8];

View file

@ -1,13 +1,46 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "Input.h" #include "Input.h"
#include <chrono> static std::chrono::high_resolution_clock::time_point now() {
return std::chrono::high_resolution_clock::now();
static uint64_t now() {
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
} }
static uint64_t elapsed(uint64_t ref) { // static uint64_t now() {
return now() - ref; // return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now().time_since_epoch).count();
// }
static uint64_t elapsed(std::chrono::high_resolution_clock::time_point ref) {
return std::chrono::duration_cast<std::chrono::milliseconds>(now() - ref).count();
} }
template <typename T> int sgn(T val) { template <typename T> int sgn(T val) {
@ -55,14 +88,14 @@ void Input::getInput()
view->mapMoved = 1; view->mapMoved = 1;
if(elapsed(touchDownTime) > 100) { if(elapsed(touchDownTime) > 100) {
touchDownTime = 0; //touchDownTime = 0;
} }
break; break;
case SDL_FINGERMOTION:; case SDL_FINGERMOTION:;
if(elapsed(touchDownTime) > 150) { if(elapsed(touchDownTime) > 150) {
tapCount = 0; tapCount = 0;
touchDownTime = 0; //touchDownTime = 0;
} }
view->moveCenterRelative( view->screen_width * event.tfinger.dx, view->screen_height * event.tfinger.dy); view->moveCenterRelative( view->screen_width * event.tfinger.dx, view->screen_height * event.tfinger.dy);
break; break;

37
Input.h
View file

@ -1,8 +1,41 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef INPUT_H #ifndef INPUT_H
#define INPUT_H #define INPUT_H
#include "AppData.h" #include "AppData.h"
#include "View.h" #include "View.h"
#include <chrono>
class Input { class Input {
public: public:
@ -14,7 +47,7 @@ public:
View *view; View *view;
AppData *appData; AppData *appData;
uint64_t touchDownTime; std::chrono::high_resolution_clock::time_point touchDownTime;
int touchx; int touchx;
int touchy; int touchy;
int tapCount; int tapCount;

70
Label.cpp Normal file
View file

@ -0,0 +1,70 @@
#include "Label.h"
#include <string>
void Label::draw(SDL_Renderer *renderer) {
SDL_Rect rect = getRect();
if(rect.h == 0 || rect.w == 0) {
return;
}
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderCopy(renderer, texture, NULL, &rect);
SDL_DestroyTexture(texture);
}
void Label::makeSurface() {
if(surface != NULL) {
SDL_FreeSurface(surface);
}
surface = TTF_RenderUTF8_Solid(font, text.c_str(), color);
}
SDL_Rect Label::getRect() {
SDL_Rect rect = {0,0,0,0};
if(!text.length()) {
return rect;
}
if(surface == NULL) {
return rect;
}
rect.x = x;
rect.y = y;
rect.w = surface->w;
rect.h = surface->h;
return rect;
}
void Label::setText(std::string text) {
this->text = text;
makeSurface();
}
void Label::setPosition(int x, int y) {
this->x = x;
this->y = y;
}
void Label::setFont(TTF_Font *font) {
this->font = font;
}
void Label::setColor(SDL_Color color) {
this->color = color;
}
//
Label::Label() {
this->color = {255,255,255,255};
surface = NULL;
}
Label::~Label() {
SDL_FreeSurface(surface);
}

29
Label.h Normal file
View file

@ -0,0 +1,29 @@
#include "SDL2/SDL.h"
#include "SDL2/SDL_ttf.h"
#include <string>
class Label {
public:
void draw(SDL_Renderer *renderer);
void setText(std::string text);
void setPosition(int x, int y);
void setFont(TTF_Font *font);
void setColor(SDL_Color color);
SDL_Rect getRect();
Label();
~Label();
private:
void makeSurface();
std::string text;
int x;
int y;
TTF_Font *font;
SDL_Color color;
SDL_Surface *surface;
};

View file

@ -3,17 +3,24 @@
# sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local # sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local
# #
CFLAGS=-O2 -Wno-write-strings CXXFLAGS=-O2 -std=c++11 -g
LIBS=-lm -lSDL2 -lSDL2_ttf -lSDL2_gfx LIBS= -lm -lSDL2 -lSDL2_ttf -lSDL2_gfx -g
CC=g++ CXX=g++
all: viz1090 all: viz1090
%.o: %.c %.cpp %.o: %.c %.cpp
$(CC) $(CFLAGS) $(EXTRACFLAGS) -c $< $(CXX) $(CXXFLAGS) $(EXTRACFLAGS) -c $<
viz1090: viz1090.o AppData.o AircraftList.o Aircraft.o anet.o interactive.o mode_ac.o mode_s.o net_io.o Input.o View.o Map.o parula.o monokai.o viz1090: viz1090.o AppData.o AircraftList.o Aircraft.o Label.o AircraftLabel.o anet.o interactive.o mode_ac.o mode_s.o net_io.o Input.o View.o Map.o parula.o monokai.o
$(CC) -g -o viz1090 viz1090.o AppData.o AircraftList.o Aircraft.o anet.o interactive.o mode_ac.o mode_s.o net_io.o Input.o View.o Map.o parula.o monokai.o $(LIBS) $(LDFLAGS) $(CXX) -o viz1090 viz1090.o AppData.o AircraftList.o Aircraft.o Label.o AircraftLabel.o anet.o interactive.o mode_ac.o mode_s.o net_io.o Input.o View.o Map.o parula.o monokai.o $(LIBS) $(LDFLAGS)
clean: clean:
rm -f *.o viz1090 rm -f \
airportdata.bin \
airportnames \
mapdata/* \
mapdata.bin \
mapnames \
*.o \
viz1090

335
Map.cpp
View file

@ -1,26 +1,75 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "Map.h" #include "Map.h"
#include <stdio.h> #include <stdio.h>
#include <cstdlib> #include <cstdlib>
#include <sstream>
#include <fstream>
#include <string>
#include <iostream>
bool Map::QTInsert(QuadTree *tree, Line *line, int depth) { bool Map::QTInsert(QuadTree *tree, Line *line, int depth) {
// printf("Inserting %d point poly\n", line->numPoints);
// if(depth > 25) {
if (!(line->lat_min >= tree->lat_min && // // printf("fail [%f %f] -> [%f %f]\n",line->start.lon,line->start.lat,line->end.lon,line->end.lat);
line->lat_max <= tree->lat_max &&
line->lon_min >= tree->lon_min &&
line->lon_max <= tree->lon_max)) {
// printf("doesnt fit: %f > %f, %f < %f, %f < %f,%f > %f \n",line->lat_min, tree->lat_min, line->lat_max, tree->lat_max, line->lon_min, tree->lon_min, line->lon_max,tree->lon_max);
return false; // // 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;
// //temp maxdepth for debugging
// if(depth > 20) {
// tree->lines.push_back(*line);
// return true;
// } // }
bool startInside = line->start.lat >= tree->lat_min &&
line->start.lat <= tree->lat_max &&
line->start.lon >= tree->lon_min &&
line->start.lon <= tree->lon_max;
bool endInside = line->end.lat >= tree->lat_min &&
line->end.lat <= tree->lat_max &&
line->end.lon >= tree->lon_min &&
line->end.lon <= tree->lon_max;
// if (!startInside || !endInside) {
// return false;
// }
if (!startInside && !endInside) {
return false;
}
if (startInside != endInside) {
tree->lines.push_back(&(*line));
return true;
}
if (tree->nw == NULL) { if (tree->nw == NULL) {
tree->nw = new QuadTree; tree->nw = new QuadTree;
@ -74,13 +123,14 @@ bool Map::QTInsert(QuadTree *tree, Line *line, int depth) {
return true; return true;
} }
tree->lines.push_back(*line); tree->lines.push_back(&(*line));
return true; return true;
} }
std::vector<Line> Map::getLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max) { std::vector<Line*> Map::getLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max) {
std::vector<Line> retLines; std::vector<Line*> retLines;
if(tree == NULL) { if(tree == NULL) {
return retLines; return retLines;
@ -94,7 +144,7 @@ std::vector<Line> Map::getLinesRecursive(QuadTree *tree, float screen_lat_min, f
return retLines; return retLines;
} }
std::vector<Line> ret; std::vector<Line*> ret;
ret = getLinesRecursive(tree->nw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max); ret = getLinesRecursive(tree->nw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max);
retLines.insert(retLines.end(), ret.begin(), ret.end()); retLines.insert(retLines.end(), ret.begin(), ret.end());
@ -109,70 +159,227 @@ std::vector<Line> Map::getLinesRecursive(QuadTree *tree, float screen_lat_min, f
retLines.insert(retLines.end(), tree->lines.begin(), tree->lines.end()); retLines.insert(retLines.end(), tree->lines.begin(), tree->lines.end());
// Debug quadtree
// Point TL, TR, BL, BR;
// TL.lat = tree->lat_min;
// TL.lon = tree->lon_min;
// TR.lat = tree->lat_max;
// TR.lon = tree->lon_min;
// BL.lat = tree->lat_min;
// BL.lon = tree->lon_max;
// BR.lat = tree->lat_max;
// BR.lon = tree->lon_max;
// retLines.push_back(new Line(TL,TR));
// retLines.push_back(new Line(TR,BR));
// retLines.push_back(new Line(BL,BR));
// retLines.push_back(new Line(TL,BL));
return retLines; return retLines;
} }
std::vector<Line> Map::getLines(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max) { std::vector<Line*> Map::getLines(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max) {
return getLinesRecursive(&root, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max); return getLinesRecursive(&root, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max);
}; };
Map::Map() { Map::Map() {
FILE *fileptr; FILE *fileptr;
if(!(fileptr = fopen("mapdata.bin", "rb"))) { if((fileptr = fopen("mapdata.bin", "rb"))) {
printf("Couldn't read mapdata.bin\nDid you run getmap.sh?\n");
exit(0);
}
fseek(fileptr, 0, SEEK_END); fseek(fileptr, 0, SEEK_END);
mapPoints_count = ftell(fileptr) / sizeof(float); mapPoints_count = ftell(fileptr) / sizeof(float);
rewind(fileptr); rewind(fileptr);
mapPoints = (float *)malloc(mapPoints_count * sizeof(float)); mapPoints = (float *)malloc(mapPoints_count * sizeof(float));
if(!fread(mapPoints, sizeof(float), mapPoints_count, fileptr)){ if(!fread(mapPoints, sizeof(float), mapPoints_count, fileptr)){
printf("Read error\n"); printf("Map read error\n");
exit(0); exit(0);
} }
fclose(fileptr); fclose(fileptr);
printf("Read %d map points.\n",mapPoints_count / 2); printf("Read %d map points.\n",mapPoints_count / 2);
// load quad tree // load quad tree
for(int i = 0; i < mapPoints_count; i+=2) { for(int i = 0; i < mapPoints_count; i+=2) {
if(mapPoints[i] == 0) if(mapPoints[i] == 0)
continue; continue;
if(mapPoints[i] < root.lon_min) { if(mapPoints[i] < root.lon_min) {
root.lon_min = mapPoints[i]; root.lon_min = mapPoints[i];
} else if(mapPoints[i] > root.lon_max) { } else if(mapPoints[i] > root.lon_max) {
root.lon_max = mapPoints[i]; root.lon_max = mapPoints[i];
} }
if(mapPoints[i+1] < root.lat_min) { if(mapPoints[i+1] < root.lat_min) {
root.lat_min = mapPoints[i+1]; root.lat_min = mapPoints[i+1];
} else if(mapPoints[i+1] > root.lat_max) { } else if(mapPoints[i+1] > root.lat_max) {
root.lat_max = mapPoints[i+1]; root.lat_max = mapPoints[i+1];
} }
} }
Point currentPoint; //printf("map bounds: %f %f %f %f\n",root.lon_min, root.lon_max, root.lat_min, root.lat_max);
Point nextPoint;
for(int i = 0; i < mapPoints_count - 2; i+=2) { Point currentPoint;
if(mapPoints[i] == 0) Point nextPoint;
continue;
currentPoint.lon = mapPoints[i];
currentPoint.lat = mapPoints[i + 1];
nextPoint.lon = mapPoints[i + 2]; for(int i = 0; i < mapPoints_count - 2; i+=2) {
nextPoint.lat = mapPoints[i + 3]; 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];
QTInsert(&root, new Line(currentPoint, nextPoint), 0); 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");
}
//
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;
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";
MapLabel *label = new MapLabel(lon,lat,assemble);
mapnames.push_back(label);
}
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";
MapLabel *label = new MapLabel(lon,lat,assemble);
airportnames.push_back(label);
}
std::cout << "Read " << airportnames.size() << " airport names\n";
infile.close();
printf("done\n");
} }
Map::~Map() {
delete mapPoints;
}

66
Map.h
View file

@ -1,13 +1,56 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef MAP_H #ifndef MAP_H
#define MAP_H #define MAP_H
#include <vector> #include <vector>
#include <string>
typedef struct Point{ typedef struct Point{
float lat; float lat;
float lon; float lon;
} Point; } Point;
typedef struct MapLabel{
Point location;
std::string text;
MapLabel(float lon, float lat, std::string text) {
this->location.lon = lon;
this->location.lat = lat;
this->text = text;
}
} MapLabel;
typedef struct Line{ typedef struct Line{
float lat_min; float lat_min;
float lat_max; float lat_max;
@ -34,7 +77,7 @@ typedef struct QuadTree{
float lon_min; float lon_min;
float lon_max; float lon_max;
std::vector<Line> lines; std::vector<Line*> lines;
struct QuadTree *nw; struct QuadTree *nw;
struct QuadTree *sw; struct QuadTree *sw;
@ -74,19 +117,24 @@ typedef struct QuadTree{
class Map { class Map {
private: public:
int mapPoints_count;
float *mapPoints;
QuadTree root; QuadTree root;
QuadTree airport_root;
bool QTInsert(QuadTree *tree, Line *line, int depth); bool QTInsert(QuadTree *tree, Line *line, int depth);
std::vector<Line> getLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max); std::vector<Line*> getLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max);
public: std::vector<Line*> getLines(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max);
std::vector<Line> getLines(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max); std::vector<MapLabel*> mapnames;
std::vector<MapLabel*> airportnames;
Map(); Map();
~Map();
int mapPoints_count;
float *mapPoints;
int airportPoints_count;
float *airportPoints;
}; };
#endif #endif

111
README.md
View file

@ -1,60 +1,89 @@
# viz1090 # viz1090
**This is work in progress** ![image](https://media.giphy.com/media/dJnFpEDGi1swmb3L05/giphy.gif)
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. **This is a work in progress**
* In-application menus or configuration yet.
There are some major fixes and cleanup that need to happen before a release:
* 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!) * Theming/colormaps (important as this is primarily intended to be eye candy!)
* Integration with handheld features like GPS, battery monitors, buttons/dials, etc. * Integration with handheld features like GPS, battery monitors, buttons/dials, etc.
* Android build is currently broken
### BUILDING ### BUILDING
Tested and working on Ubuntu 18.04, Raspbian Stretch / Buster, Windows Subsystem for Linux (with Ubuntu 18.04) Tested and working on Ubuntu 18.04, Raspbian Stretch / Buster, Windows Subsystem for Linux (with Ubuntu 18.04), and Mac
0. Install build essentials 0. Install build essentials
``` ```
sudo apt-get install build-essentials sudo apt-get install build-essential
``` ```
1. Install SDL and RTL-SDR libararies 1. Install SDL and RTL-SDR libraries
``` ```
sudo apt-get install libsdl2-dev libsdl2-ttf-dev libsdl2-gfx-dev librtlsdr-dev sudo apt-get install libsdl2-dev libsdl2-ttf-dev libsdl2-gfx-dev librtlsdr-dev libgdal-dev
``` ```
Note: On Raspbian the SDL2 package requires X to be running. See the Raspberry Pi section for notes on running from the terminal and other improvements.
2. Download and build spidr Note: On Raspbian the SDL2 package requires X to be running. See the Raspberry Pi section for notes on running from the terminal and other improvements.
2. Download and build viz1090
``` ```
cd ~ cd ~
git clone https://www.github.com/nmatsuda/spidr git clone https://www.github.com/nmatsuda/viz1090
cd spidr cd viz1090
make clean; make make clean; make
``` ```
3. Download and process map data 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
The getmap.sh pulls the svg file for the contiguous 48 US states and produces a binary file for viz1090 to read.
``` ```
sudo apt install python3 python3-pip sudo apt install python3 python3-pip
pip3 install lxml numpy tqdm pip3 install fiona tqdm shapely
./getmap.sh ./getmap.sh
``` ```
3. (optional for Windows) 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 reasonably quickly on a Raspberry Pi 4. See the mapconverter section below for other options and more information about map sources.
3. (Windows only)
As WSL does not have an X server built in, you will need to install a 3rd party X server, such as https://sourceforge.net/projects/vcxsrv/ As WSL does not have an X server built in, you will need to install a 3rd party X server, such as https://sourceforge.net/projects/vcxsrv/
* run Xlaunch from the start menu * run Xlaunch from the start menu
* Uncheck "Use Native openGL" * Uncheck "Use Native openGL"
* Open the Ubuntu WSL terminal * Add parameter ```-ac``` (WSL 2 only)
* Specify the X display to use * Open the Ubuntu WSL terminal
``` * Specify the X display to use (WSL 1)
export DISPLAY=:0 ```
``` export DISPLAY=:0
* Start viz1090 as described below. ```
* or for (WSL 2)
```
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
```
* Start viz1090 as described below.
#### Nix
Run without installing
```bash
nix shell git+https://git.vulpecula.zone/tasiaiso/viz1090
```
TODO docs
A shell is now open with viz1090 in the path
### RUNNING ### RUNNING
@ -78,11 +107,36 @@ viz1090 will open an SDL window set to the resolution of your screen.
| --port [port number] | Specify dump1090 server port | | --port [port number] | Specify dump1090 server port |
| --metric | Display metric units | | --metric | Display metric units |
| --lat | Specify your latitude in degrees | | --lat | Specify your latitude in degrees |
| --lon | Specify your longitiude in degrees | | --lon | Specify your longitude in degrees |
| --screensize [width] [height] | Specify a specific resolution to pass to SDL_RenderSetLogicalSize, otherwise use resolution of display | | --screensize [width] [height] | Specify a resolution, otherwise use resolution of display |
| --uiscale [scale] | Scale up UI elements by integer amounts for high resolution screen | | --uiscale [scale] | Scale up UI elements by integer amounts for high resolution screen |
| --fullscreen | Render fullscreen rather than in a window | | --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. Alternatively, 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 ### 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: This software was originally intended for Raspberry Pi devices, and it is currently optimized for the Raspberry Pi 4 with the following configuration:
@ -100,6 +154,7 @@ This software was originally intended for Raspberry Pi devices, and it is curren
* [Noelec Nano V3](https://www.nooelec.com/store/nesdr-nano-three.html) * [Noelec Nano V3](https://www.nooelec.com/store/nesdr-nano-three.html)
* Stratux V2 \*very low power but hard to find * Stratux V2 \*very low power but hard to find
If you want to print the case in the GIF shown above, you can [download it here](https://github.com/nmatsuda/viz1090_case).
If running as a front end only, with a separate dump1090 server, the best option is to use an Android phone, such as the Pixel 2, which significantly outperforms a Raspberry Pi 4. If running as a front end only, with a separate dump1090 server, the best option is to use an Android phone, such as the Pixel 2, which significantly outperforms a Raspberry Pi 4.

94
Style.h Normal file
View file

@ -0,0 +1,94 @@
#ifndef STYLE_H
#define STYLE_H
#include "SDL2/SDL.h"
//
// This should go to a full theming class
//
typedef struct Style {
SDL_Color backgroundColor;
SDL_Color selectedColor;
SDL_Color planeColor;
SDL_Color planeGoneColor;
SDL_Color trailColor;
SDL_Color geoColor;
SDL_Color airportColor;
SDL_Color labelColor;
SDL_Color labelLineColor;
SDL_Color subLabelColor;
SDL_Color labelBackground;
SDL_Color scaleBarColor;
SDL_Color buttonColor;
SDL_Color buttonBackground;
SDL_Color buttonOutline;
SDL_Color clickColor;
SDL_Color black;
SDL_Color white;
SDL_Color red;
SDL_Color green;
SDL_Color blue;
//
// todo separate style stuff
//
Style() {
SDL_Color pink = {249,38,114,255};
SDL_Color purple = {85, 0, 255,255};
SDL_Color purple_dark = {33, 0, 122,255};
SDL_Color blue = {102,217,239,255};
SDL_Color blue_dark = {102,217,239,255};
SDL_Color green = {0,255,234,255};
SDL_Color green_dark = {24,100,110,255};
SDL_Color yellow = {216,255,0,255};
SDL_Color yellow_dark = {90,133,50,255};
SDL_Color orange = {253,151,31,255};
SDL_Color grey_light = {196,196,196,255};
SDL_Color grey = {127,127,127,255};
SDL_Color grey_dark = {64,64,64,255};
black = {0,0,0,255};
white = {255,255,255,255};
red = {255,0,0,255};
green = {0,255,0,255};
blue = {0,0,255,255};
backgroundColor = black;
selectedColor = pink;
planeColor = yellow;
planeGoneColor = grey;
trailColor = yellow_dark;
geoColor = purple_dark;
airportColor = purple;
labelColor = white;
labelLineColor = grey_dark;
subLabelColor = grey;
labelBackground = black;
scaleBarColor = grey_light;
buttonColor = grey_light;
buttonBackground = black;
buttonOutline = grey_light;
clickColor = grey;
}
} Style;
#endif

73
Text.cpp Normal file
View file

@ -0,0 +1,73 @@
#include "SDL2/SDL2_gfxPrimitives.h"
#include "Text.h"
SDL_Rect Text::drawString(std::string text, int x, int y, TTF_Font *font, SDL_Color color)
{
SDL_Rect dest = {0,0,0,0};
if(!text.length()) {
return dest;
}
SDL_Surface *surface;
surface = TTF_RenderUTF8_Solid(font, text.c_str(), color);
if (surface == NULL)
{
printf("Couldn't create String %s: %s\n", text.c_str(), SDL_GetError());
return dest;
}
dest.x = x;
dest.y = y;
dest.w = surface->w;
dest.h = surface->h;
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderCopy(renderer, texture, NULL, &dest);
SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);
return dest;
}
SDL_Rect Text::drawStringBG(std::string text, int x, int y, TTF_Font *font, SDL_Color color, SDL_Color bgColor) {
SDL_Rect dest = {0,0,0,0};
if(!text.length()) {
return dest;
}
SDL_Surface *surface;
surface = TTF_RenderUTF8_Shaded(font, text.c_str(), color, bgColor);
if (surface == NULL)
{
printf("Couldn't create String %s: %s\n", text.c_str(), SDL_GetError());
return dest;
}
dest.x = x;
dest.y = y;
dest.w = surface->w;
dest.h = surface->h;
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderCopy(renderer, texture, NULL, &dest);
SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);
return dest;
}
// check if text has changed and surface exists
// redraw existing surface
// or make new surface
// for BG, draw bg size of surface
// draw surface

1355
View.cpp

File diff suppressed because it is too large Load diff

205
View.h
View file

@ -1,19 +1,52 @@
// viz1090, a vizualizer for dump1090 ADSB output
//
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef VIEW_H #ifndef VIEW_H
#define VIEW_H #define VIEW_H
#include "AppData.h" #include "AppData.h"
#include "Map.h" #include "Map.h"
#include "Style.h"
#include "SDL2/SDL.h" #include "SDL2/SDL.h"
#include "SDL2/SDL_ttf.h" #include "SDL2/SDL_ttf.h"
#include <chrono>
#include <string>
//defs - should all move to config file setup //defs - should all move to config file setup
#define ROUND_RADIUS 3 //radius of text box corners #define ROUND_RADIUS 3 //radius of text box corners
#define CENTEROFFSET .5 //vertical offset for middle of screen
#define TRAIL_LENGTH 120 #define TRAIL_LENGTH 120
#define TRAIL_TTL 240.0 #define TRAIL_TTL 240.0
#define DISPLAY_ACTIVE 30 #define DISPLAY_ACTIVE 30.0
#define TRAIL_TTL_STEP 2 #define TRAIL_TTL_STEP 2
#define MIN_MAP_FEATURE 2 #define MIN_MAP_FEATURE 2
@ -22,33 +55,7 @@
#define PAD 5 #define PAD 5
#define LATLONMULT 111.195 // 6371.0 * M_PI / 180.0
//
// This should go to a full theming class
//
typedef struct Style {
SDL_Color backgroundColor;
SDL_Color selectedColor;
SDL_Color planeColor;
SDL_Color planeGoneColor;
SDL_Color mapInnerColor;
SDL_Color mapOuterColor;
SDL_Color scaleBarColor;
SDL_Color buttonColor;
} Style;
typedef struct Tile {
float lat_min;
float lat_max;
float lon_min;
float lon_max;
SDL_Texture *texture;
} Tile;
class View { class View {
@ -57,39 +64,104 @@ class View {
AppData *appData; AppData *appData;
//for cursor drawing //for cursor drawing
uint64_t mouseMovedTime; std::chrono::high_resolution_clock::time_point mouseMovedTime;
bool mouseMoved;
int mousex; int mousex;
int mousey; int mousey;
uint64_t clickTime; std::chrono::high_resolution_clock::time_point clickTime;
bool clicked;
int clickx; int clickx;
int clicky; int clicky;
TTF_Font* loadFont(char *name, int size); int lineCount;
float dx_mult;
float dy_mult;
TTF_Font* loadFont(const char *name, int size);
void closeFont(TTF_Font *font); void closeFont(TTF_Font *font);
void drawString(char * text, int x, int y, TTF_Font *font, SDL_Color color); SDL_Rect drawString(std::string text, int x, int y, TTF_Font *font, SDL_Color color);
void drawStringBG(char * text, int x, int y, TTF_Font *font, SDL_Color color, SDL_Color bgColor); SDL_Rect drawStringBG(std::string text, int x, int y, TTF_Font *font, SDL_Color color, SDL_Color bgColor);
void drawStatusBox(int *left, int *top, char *label, char *message, SDL_Color color); void drawStatusBox(int *left, int *top, std::string label, std::string message, SDL_Color color);
void drawStatus(); void drawStatus();
Aircraft *selectedAircraft; Aircraft *selectedAircraft;
Style style; Style style;
public:
int screenDist(float d);
void pxFromLonLat(float *dx, float *dy, float lon, float lat);
void latLonFromScreenCoords(float *lat, float *lon, int x, int y);
void screenCoords(int *outX, int *outY, float dx, float dy);
int outOfBounds(int x, int y);
int outOfBounds(int x, int y, int left, int top, int right, int bottom);
void drawPlaneOffMap(int x, int y, int *returnx, int *returny, SDL_Color planeColor);
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, SDL_Color color);
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);
float resolveLabelConflicts();
void drawPlanes();
void animateCenterAbsolute(float x, float y);
void moveCenterAbsolute(float x, float y);
void moveCenterRelative(float dx, float dy);
void zoomMapToTarget();
void moveMapToTarget();
void drawMouse();
void drawClick();
void registerClick(int tapcount, int x, int y);
void registerMouseMove(int x, int y);
void draw();
void SDL_init();
void font_init();
View(AppData *appData);
~View();
////////////////
bool metric;
bool fps;
float maxDist;
float currentMaxDist; float currentMaxDist;
float centerLon;
float centerLat;
float mapTargetMaxDist;
float mapTargetLat; float mapTargetLat;
float mapTargetLon; float mapTargetLon;
int mapMoved;
int mapRedraw; int mapRedraw;
int mapAnimating;
float currentLon; float currentLon;
float currentLat; float currentLat;
uint64_t lastFrameTime; std::chrono::high_resolution_clock::time_point lastFrameTime;
uint64_t drawStartTime; std::chrono::high_resolution_clock::time_point drawStartTime;
std::chrono::high_resolution_clock::time_point lastRedraw;
Map map; Map map;
std::vector<Tile> tiles;
int screen_upscale;
int screen_uiscale;
int screen_width;
int screen_height;
int screen_depth;
int fullscreen;
int screen_index;
SDL_Window *window; SDL_Window *window;
SDL_Renderer *renderer; SDL_Renderer *renderer;
SDL_Texture *mapTexture; SDL_Texture *mapTexture;
@ -107,59 +179,6 @@ class View {
int labelFontHeight; int labelFontHeight;
int messageFontWidth; int messageFontWidth;
int messageFontHeight; int messageFontHeight;
int screenDist(float d);
void pxFromLonLat(float *dx, float *dy, float lon, float lat);
void lonLatFromScreenCoords(float *lon, float *lat, int x, int y);
void screenCoords(int *outX, int *outY, float dx, float dy);
int outOfBounds(int x, int y);
void drawPlaneOffMap(int x, int y, int *returnx, int *returny, SDL_Color planeColor);
void drawPlaneIcon(int x, int y, float heading, SDL_Color planeColor);
void drawTrail(Aircraft *p);
void drawScaleBars();
void drawLines(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max, int bailTime);
void drawGeography(int left, int top, int right, int bottom, int bailTime);
void drawSignalMarks(Aircraft *p, int x, int y);
void drawPlaneText(Aircraft *p);
void drawSelectedAircraftText(Aircraft *p);
void resolveLabelConflicts();
void drawPlanes();
void drawTiles();
void animateCenterAbsolute(float x, float y);
void moveCenterAbsolute(float x, float y);
void zoomMapToTarget();
void moveMapToTarget();
void drawMouse();
void drawClick();
public:
void registerClick(int tapcount, int x, int y);
void registerMouseMove(int x, int y);
void draw();
void SDL_init();
void font_init();
void moveCenterRelative(float dx, float dy);
View(AppData *appData);
~View();
bool metric;
float centerLon;
float centerLat;
float maxDist;
int mapMoved;
float mapTargetMaxDist;
int screen_upscale;
int screen_uiscale;
int screen_width;
int screen_height;
int screen_depth;
int fullscreen;
int screen_index;
}; };
#endif #endif

6
anet.c
View file

@ -122,7 +122,7 @@ int anetResolve(char *err, char *host, char *ipbuf)
struct sockaddr_in sa; struct sockaddr_in sa;
sa.sin_family = AF_INET; sa.sin_family = AF_INET;
if (inet_aton(host, (in_addr*)&sa.sin_addr) == 0) { if (inet_aton(host, &sa.sin_addr) == 0) {
struct hostent *he; struct hostent *he;
he = gethostbyname(host); he = gethostbyname(host);
@ -168,7 +168,7 @@ static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
memset(&sa,0,sizeof(sa)); memset(&sa,0,sizeof(sa));
sa.sin_family = AF_INET; sa.sin_family = AF_INET;
sa.sin_port = htons((uint16_t)port); sa.sin_port = htons((uint16_t)port);
if (inet_aton(addr, (in_addr*)&sa.sin_addr) == 0) { if (inet_aton(addr, &sa.sin_addr) == 0) {
struct hostent *he; struct hostent *he;
he = gethostbyname(addr); he = gethostbyname(addr);
@ -271,7 +271,7 @@ int anetTcpServer(char *err, int port, char *bindaddr)
sa.sin_family = AF_INET; sa.sin_family = AF_INET;
sa.sin_port = htons((uint16_t)port); sa.sin_port = htons((uint16_t)port);
sa.sin_addr.s_addr = htonl(INADDR_ANY); sa.sin_addr.s_addr = htonl(INADDR_ANY);
if (bindaddr && inet_aton(bindaddr, (in_addr*)&sa.sin_addr) == 0) { if (bindaddr && inet_aton(bindaddr, &sa.sin_addr) == 0) {
anetSetError(err, "invalid bind address"); anetSetError(err, "invalid bind address");
close(s); close(s);
return ANET_ERR; return ANET_ERR;

9
anet.h
View file

@ -39,6 +39,10 @@
#define AF_LOCAL AF_UNIX #define AF_LOCAL AF_UNIX
#endif #endif
#ifdef __cplusplus
extern "C" {
#endif
int anetTcpConnect(char *err, char *addr, int port); int anetTcpConnect(char *err, char *addr, int port);
int anetTcpNonBlockConnect(char *err, char *addr, int port); int anetTcpNonBlockConnect(char *err, char *addr, int port);
int anetUnixConnect(char *err, char *path); int anetUnixConnect(char *err, char *path);
@ -56,4 +60,9 @@ int anetTcpKeepAlive(char *err, int fd);
int anetPeerToString(int fd, char *ip, int *port); int anetPeerToString(int fd, char *ip, int *port);
int anetSetSendBuffer(char *err, int fd, int buffsize); int anetSetSendBuffer(char *err, int fd, int buffsize);
#ifdef __cplusplus
}
#endif
#endif #endif

View file

@ -1 +0,0 @@
85c850fc7f07d0cf30352d3385c7a2aeb57fecf3

View file

@ -428,7 +428,7 @@ extern "C" {
// Functions exported from mode_ac.c // Functions exported from mode_ac.c
// //
int detectModeA (uint16_t *m, struct modesMessage *mm); int detectModeA (uint16_t *m, struct modesMessage *mm);
void decodeModeAMessage(Modes *modes, struct modesMessage *mm, int ModeA); //void decodeModeAMessage(Modes *modes, struct modesMessage *mm, int ModeA);
int ModeAToModeC (unsigned int ModeA); int ModeAToModeC (unsigned int ModeA);
// //
@ -449,7 +449,7 @@ struct aircraft* interactiveReceiveData(Modes *modes, struct modesMessage *mm);
void interactiveShowData(void); void interactiveShowData(void);
void interactiveRemoveStaleAircrafts(Modes *modes); void interactiveRemoveStaleAircrafts(Modes *modes);
int decodeBinMessage (Modes *modes, struct client *c, char *p); int decodeBinMessage (Modes *modes, struct client *c, char *p);
struct aircraft *interactiveFindAircraft(uint32_t addr); // struct aircraft *interactiveFindAircraft(uint32_t addr);
struct stDF *interactiveFindDF (uint32_t addr); struct stDF *interactiveFindDF (uint32_t addr);
// //

61
flake.lock Normal file
View file

@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1739758141,
"narHash": "sha256-uq6A2L7o1/tR6VfmYhZWoVAwb3gTy7j4Jx30MIrH0rE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "c618e28f70257593de75a7044438efc1c1fc0791",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

50
flake.nix Normal file
View file

@ -0,0 +1,50 @@
{
# TODO desc
description = "viz1090";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = {
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {
inherit system;
};
in rec
{
# Nix formatter, run using `$ nix fmt`
formatter = pkgs.alejandra;
# Exports the package
# Build with `$ nix build`
packages.viz1090 = pkgs.callPackage ./nix/viz1090.nix {inherit self system;};
packages.viz1090-mapdata = pkgs.callPackage ./nix/viz1090-mapdata.nix {};
packages.default = packages.viz1090;
# Creates a shell with the necessary dependencies
# Enter using `$ nix develop`
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
rtl-sdr-librtlsdr
SDL2
SDL2_ttf
SDL2_gfx
gdal
python3
python312Packages.pip
python312Packages.shapely
python312Packages.fiona
python312Packages.tqdm
unzip
python312Packages.requests
git
];
};
});
}

BIN
font/TerminusTTF-4.46.0.ttf Normal file

Binary file not shown.

View file

@ -1 +0,0 @@
eafa3a6e408def39bcd002f60a6d9a9810d54234

Binary file not shown.

View file

@ -1 +0,0 @@
9dc2aed0a76993fd7ba9c28e0f55fce873a8c790

View file

@ -1,5 +1,24 @@
#!/bin/bash #!/bin/bash
wget -O all.svg.gz https://www.mccurley.org/svg/data/allzips.svgz mkdir -p mapdata
gunzip all.svg.gz pushd mapdata > /dev/null
python3 mapconverter.py all.svg
wget --no-verbose https://naciscdn.org/naturalearth/10m/cultural/ne_10m_admin_1_states_provinces.zip
wget --no-verbose https://naciscdn.org/naturalearth/10m/cultural/ne_10m_populated_places.zip
wget --no-verbose https://naciscdn.org/naturalearth/10m/cultural/ne_10m_airports.zip
#this may not be up to date
wget --no-verbose https://opendata.arcgis.com/datasets/4d8fa46181aa470d809776c57a8ab1f6_0.zip
for file in *.zip; do
unzip -o "${file}"
rm "${file}"
done
popd > /dev/null
python3 mapconverter.py \
--mapfile mapdata/ne_10m_admin_1_states_provinces.shp \
--mapnames mapdata/ne_10m_populated_places.shp \
--airportfile mapdata/Runways.shp \
--airportnames mapdata/ne_10m_airports.shp

View file

@ -1,6 +0,0 @@
curl "https://api.mapbox.com/v4/mapbox.mapbox-streets-v8/8/40/89.mvt?access_token=pk.eyJ1Ijoibm1hdHN1ZGEiLCJhIjoiY2swazhrdGNjMGZ3NzNvcmE0OGxoaGd2byJ9.PAYHqO3any_6vLdjQ44RGw"
mapbox://styles/nmatsuda/ck0k7rvvt3rkv1cq6l74wjda2
47.695,-123.489

View file

@ -1,58 +1,133 @@
from lxml import etree as ElementTree import fiona
from shapely.geometry import shape
import numpy as np import numpy as np
import sys
from tqdm import tqdm from tqdm import tqdm
import zipfile
from io import BytesIO
#from urllib.request import urlopen
import requests
import argparse
import os
filename = sys.argv[1] def convertLinestring(linestring):
outlist = []
if(len(filename) == 0): pointx = linestring.coords.xy[0]
print("No input filename given") pointy = linestring.coords.xy[1]
exit()
for j in range(len(pointx)):
outlist.extend([float(pointx[j]),float(pointy[j])])
parser = ElementTree.XMLParser(recover=True) outlist.extend([0,0])
tree = ElementTree.parse(filename, parser) return outlist
polys = tree.xpath('//polygon')
bin_file = open("mapdata.bin", "wb") def extractLines(shapefile, tolerance):
print("Extracting map lines")
outlist = []
outlist = [] 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.geom_type == "MultiPolygon" or simplified.geom_type == "Polygon"):
if(simplified.boundary.geom_type == "MultiLineString"):
for boundary in simplified.boundary.geoms:
outlist.extend(convertLinestring(boundary))
else:
outlist.extend(convertLinestring(simplified.boundary))
else:
print("Unsupported type: " + simplified.geom_type)
resolution = 250
print("Reading points")
for i in tqdm(range(len(polys))):
#for i in range(40):
p = polys[i]
currentPoints = (p.attrib['points']).replace(","," ").split()
if(len(currentPoints) == 14): #remove little circles in the McCurley maps return outlist
continue
prevx = 0 parser = argparse.ArgumentParser(description='viz1090 Natural Earth Data Map Converter')
prevy = 0 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")
temp = [] args = parser.parse_args()
for i in range(int(len(currentPoints)/2)): # mapfile
#currentPoints[2 * i + 0] = "%.*f" % (precision, float(currentPoints[2 * i + 0])) if args.mapfile is not None:
#currentPoints[2 * i + 1] = "%.*f" % (precision, float(currentPoints[2 * i + 1])) shapefile = fiona.open(args.mapfile)
currentPoints[2 * i + 0] = float(int(resolution * float(currentPoints[2 * i + 0]))) / resolution outlist = extractLines(shapefile, args.tolerance)
currentPoints[2 * i + 1] = float(int(resolution * float(currentPoints[2 * i + 1]))) / resolution
if(currentPoints[2 * i + 0] != prevx or currentPoints[2 * i + 1] != prevy): bin_file = open("mapdata.bin", "wb")
temp.extend([currentPoints[2 * i + 0],currentPoints[2 * i + 1]]) np.asarray(outlist).astype(np.single).tofile(bin_file)
bin_file.close()
prevx = currentPoints[2 * i + 0] print("Wrote %d points" % (len(outlist) / 2))
prevy = currentPoints[2 * i + 1]
if(len(currentPoints) > 6): #must be at least a triangle # mapnames
outlist.extend(temp) bin_file = open("mapnames", "w")
#outlist.extend([temp[0],temp[1]])
outlist.extend(["0","0"]) 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))
np.asarray(outlist).astype(np.single).tofile(bin_file) #airportnames
bin_file.close() 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))

View file

@ -210,7 +210,7 @@ int fixBitErrors(unsigned char *msg, int bits, int maxfix, char *fixedbits) {
int bitpos, offset, res, i; int bitpos, offset, res, i;
memset(&ei, 0, sizeof(struct errorinfo)); memset(&ei, 0, sizeof(struct errorinfo));
ei.syndrome = modesChecksum(msg, bits); ei.syndrome = modesChecksum(msg, bits);
pei = (errorinfo*)bsearch(&ei, bitErrorTable, NERRORINFO, pei = bsearch(&ei, bitErrorTable, NERRORINFO,
sizeof(struct errorinfo), cmpErrorInfo); sizeof(struct errorinfo), cmpErrorInfo);
if (pei == NULL) { if (pei == NULL) {
return 0; // No syndrome found return 0; // No syndrome found

70
nix/viz1090-mapdata.nix Normal file
View file

@ -0,0 +1,70 @@
{
lib,
pkgs,
stdenv,
fetchFromGitea,
}: let
runways = fetchTarball {
url = "https://opendata.arcgis.com/datasets/4d8fa46181aa470d809776c57a8ab1f6_0.zip";
sha256 = "sha256:1ivwx8glk8yk68nmqz467yzvlb3l66l1s3ibmd9p41wz737lmz88";
};
provinces = fetchTarball {
url = "https://naciscdn.org/naturalearth/10m/cultural/ne_10m_admin_1_states_provinces.zip";
sha256 = "sha256:06ai02b8rfsfzpa0gq4nsg29lxvwy4zvjw44099hc78vr7dkfsdp";
};
places = fetchTarball {
url = "https://naciscdn.org/naturalearth/10m/cultural/ne_10m_populated_places.zip";
sha256 = "sha256:1dhh569520f02yml1m5zp2znjv85cqbccl4nvpmigynxd37kid3j";
};
airports = fetchTarball {
url = "https://naciscdn.org/naturalearth/10m/cultural/ne_10m_airports.zip";
sha256 = "sha256:0893zg63ygr2l2d1wpyigls1syfkryjlygvnbbjikpqk5i5cwr56";
};
in
stdenv.mkDerivation rec {
pname = "viz1090-mapdata";
version = "0.1.0";
src = fetchFromGitea {
domain = "git.vulpecula.zone";
owner = "tasiaiso";
repo = pname;
rev = "d1f53019b22a9e605506bed90fcffcdc5f7e6186";
hash = "sha256-gtv0u7o+5fqVgA0CHDWdZr0h9A1Nbky1+okHvSv1cVU=";
};
nativeBuildInputs = with pkgs; [
python3
python312Packages.pip
python312Packages.shapely
python312Packages.fiona
python312Packages.tqdm
python312Packages.requests
];
buildPhase = ''
mkdir -p mapdata
cp ${runways}/* mapdata
cp ${provinces}/* mapdata
cp ${places}/* mapdata
cp ${airports}/* mapdata
python3 mapconverter.py \
--mapfile mapdata/ne_10m_admin_1_states_provinces.shp \
--mapnames mapdata/ne_10m_populated_places.shp \
--airportfile mapdata/Runways.shp \
--airportnames mapdata/ne_10m_airports.shp
'';
installPhase = ''
mkdir -p $out $out/font
cp airportdata.bin $out
cp airportnames $out
cp mapdata.bin $out
cp mapnames $out
cp font/* $out/font
'';
}

116
nix/viz1090.nix Normal file
View file

@ -0,0 +1,116 @@
{
lib,
pkgs,
stdenv,
fetchFromGitea,
self,
system,
}: let
viz1090-mapdata = self.packages.${system}.viz1090-mapdata;
in
stdenv.mkDerivation rec {
pname = "viz1090";
version = "0.1.0";
src = fetchFromGitea {
domain = "git.vulpecula.zone";
owner = "tasiaiso";
repo = pname;
rev = "1922324b40f84fd449cec3fbfdade8aa33597bf6";
hash = "sha256-bPVFKbGtPXOitzzHb3yJ6XW3fRh8PF/7kfP7EJkJX3c=";
};
nativeBuildInputs = with pkgs; [
rtl-sdr-librtlsdr
SDL2
SDL2_ttf
SDL2_gfx
gdal
git
];
buildInputs = [
viz1090-mapdata
];
buildPhase = ''
echo "diff --git a/Makefile b/Makefile
index 5e60779..d5b30ab 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
# sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local
#
-CXXFLAGS=-O2 -std=c++11 -g
+CXXFLAGS=-O2 -std=c++11 -g -I ${pkgs.SDL2.dev}/include/SDL2/
LIBS= -lm -lSDL2 -lSDL2_ttf -lSDL2_gfx -g
CXX=g++
diff --git a/Map.cpp b/Map.cpp
index cd798ec..c5736bd 100644
--- a/Map.cpp
+++ b/Map.cpp
@@ -189,7 +189,7 @@ std::vector<Line*> Map::getLines(float screen_lat_min, float screen_lat_max, flo
Map::Map() {
FILE *fileptr;
- if((fileptr = fopen(\"mapdata.bin\", \"rb\"))) {
+ if((fileptr = fopen(\"${viz1090-mapdata}/mapdata.bin\", \"rb\"))) {
fseek(fileptr, 0, SEEK_END);
@@ -255,7 +255,7 @@ Map::Map() {
//
- if((fileptr = fopen(\"airportdata.bin\", \"rb\"))) {
+ if((fileptr = fopen(\"${viz1090-mapdata}/airportdata.bin\", \"rb\"))) {
fseek(fileptr, 0, SEEK_END);
airportPoints_count = ftell(fileptr) / sizeof(float);
rewind(fileptr);
@@ -350,7 +350,7 @@ Map::Map() {
infile.close();
- infile.open(\"airportnames\");
+ infile.open(\"${viz1090-mapdata}/airportnames\");
while (std::getline(infile, line))
diff --git a/View.cpp b/View.cpp
index d5dace7..90f6165 100644
--- a/View.cpp
+++ b/View.cpp
@@ -174,13 +174,13 @@ void View::closeFont(TTF_Font *font)
void View::font_init() {
- mapFont = loadFont(\"font/TerminusTTF-4.46.0.ttf\", 12 * screen_uiscale);
- mapBoldFont = loadFont(\"font/TerminusTTF-Bold-4.46.0.ttf\", 12 * screen_uiscale);
+ mapFont = loadFont(\"${viz1090-mapdata}/font/TerminusTTF-4.46.0.ttf\", 12 * screen_uiscale);
+ mapBoldFont = loadFont(\"${viz1090-mapdata}/font/TerminusTTF-Bold-4.46.0.ttf\", 12 * screen_uiscale);
- listFont = loadFont(\"font/TerminusTTF-4.46.0.ttf\", 12 * screen_uiscale);
+ listFont = loadFont(\"${viz1090-mapdata}/font/TerminusTTF-4.46.0.ttf\", 12 * screen_uiscale);
- messageFont = loadFont(\"font/TerminusTTF-Bold-4.46.0.ttf\", 12 * screen_uiscale);
- labelFont = loadFont(\"font/TerminusTTF-Bold-4.46.0.ttf\", 12 * screen_uiscale);
+ messageFont = loadFont(\"${viz1090-mapdata}/font/TerminusTTF-Bold-4.46.0.ttf\", 12 * screen_uiscale);
+ labelFont = loadFont(\"${viz1090-mapdata}/font/TerminusTTF-Bold-4.46.0.ttf\", 12 * screen_uiscale);
mapFontWidth = 5 * screen_uiscale;
mapFontHeight = 12 * screen_uiscale;
" | git apply -
cat Map.cpp | grep mapdata
make -j $NIX_BUILD_CORES
'';
installPhase = ''
mkdir -p $out/bin
cp -v viz1090 $out/bin
'';
}

View file

@ -1 +0,0 @@
34c8403286643597ad193fa68d13266d3a5f07a6

View file

@ -1,234 +0,0 @@
// view1090, a Mode S messages viewer for dump1090 devices.
//
// Copyright (C) 2014 by Malcolm Robb <Support@ATTAvionics.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "view1090.h"
#include "structs.h"
#include "AircraftData.h"
int go = 1;
AppData appData;
Style style;
//
// ============================= Utility functions ==========================
//
void sigintHandler(int dummy) {
NOTUSED(dummy);
signal(SIGINT, SIG_DFL); // reset signal handler - bit extra safety
AircraftData.modes.exit = 1; // Signal to threads that we are done
}
//
//=========================================================================
//
// Set up data connection
int setupConnection(struct client *c) {
int fd;
// Try to connect to the selected ip address and port. We only support *ONE* input connection which we initiate.here.
if ((fd = anetTcpConnect(AircraftData.modes.aneterr, View1090.net_input_beast_ipaddr, AircraftData.modes.net_input_beast_port)) != ANET_ERR) {
anetNonBlock(AircraftData.modes.aneterr, fd);
//
// Setup a service callback client structure for a beast binary input (from dump1090)
// This is a bit dodgy under Windows. The fd parameter is a handle to the internet
// socket on which we are receiving data. Under Linux, these seem to start at 0 and
// count upwards. However, Windows uses "HANDLES" and these don't nececeriy start at 0.
// dump1090 limits fd to values less than 1024, and then uses the fd parameter to
// index into an array of clients. This is ok-ish if handles are allocated up from 0.
// However, there is no gaurantee that Windows will behave like this, and if Windows
// allocates a handle greater than 1024, then dump1090 won't like it. On my test machine,
// the first Windows handle is usually in the 0x54 (84 decimal) region.
c->next = NULL;
c->buflen = 0;
c->fd =
c->service =
AircraftData.modes.bis = fd;
AircraftData.modes.clients = c;
}
return fd;
}
//
// ================================ Main ====================================
//
void showHelp(void) {
printf(
"-----------------------------------------------------------------------------\n"
"| view1090 dump1090 Viewer Ver : "MODES_DUMP1090_VERSION " |\n"
"-----------------------------------------------------------------------------\n"
"--server <IPv4/hosname> TCP Beast output listen IPv4 (default: 127.0.0.1)\n"
"--port <port> TCP Beast output listen port (default: 30005)\n"
"--lat <latitude> Reference/receiver latitide for surface posn (opt)\n"
"--lon <longitude> Reference/receiver longitude for surface posn (opt)\n"
"--metric Use metric units (meters, km/h, ...)\n"
"--help Show this help\n"
"--uiscale <factor> UI global scaling (default: 1)\n"
"--screensize <width> <height> Set frame buffer resolution (default: screen resolution)\n"
"--fullscreen Start fullscreen\n"
);
}
#ifdef _WIN32
void showCopyright(void) {
uint64_t llTime = time(NULL) + 1;
printf(
"-----------------------------------------------------------------------------\n"
"| view1090 ModeS Viewer Ver : " MODES_DUMP1090_VERSION " |\n"
"-----------------------------------------------------------------------------\n"
"\n"
" Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>\n"
" Copyright (C) 2014 by Malcolm Robb <support@attavionics.com>\n"
" Copyright (C) 2020 by Nathan Matsuda <info@nathanmatsuda.com>\n"
"\n"
" All rights reserved.\n"
"\n"
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
" ""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n"
" For further details refer to <https://github.com/MalcolmRobb/dump1090>\n"
"\n"
);
// delay for 1 second to give the user a chance to read the copyright
while (llTime >= time(NULL)) {}
}
#endif
//
//=========================================================================
//
int main(int argc, char **argv) {
int j, fd;
struct client *c;
char pk_buf[8];
AircraftData aircraftData;
signal(SIGINT, sigintHandler); // Define Ctrl/C handler (exit program)
aircraftData.initialize();
// Parse the command line options
for (j = 1; j < argc; j++) {
int more = ((j + 1) < argc); // There are more arguments
if (!strcmp(argv[j],"--net-bo-port") && more) {
AircraftData.modes.net_input_beast_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--port") && more) {
AircraftData.modes.net_input_beast_port = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--net-bo-ipaddr") && more) {
strcpy(View1090.net_input_beast_ipaddr, argv[++j]);
} else if (!strcmp(argv[j],"--server") && more) {
strcpy(View1090.net_input_beast_ipaddr, argv[++j]);
} else if (!strcmp(argv[j],"--lat") && more) {
AircraftData.modes.fUserLat = atof(argv[++j]);
appData.centerLat = AircraftData.modes.fUserLat;
} else if (!strcmp(argv[j],"--lon") && more) {
AircraftData.modes.fUserLon = atof(argv[++j]);
appData.centerLon = AircraftData.modes.fUserLon;
} else if (!strcmp(argv[j],"--metric")) {
AircraftData.modes.metric = 1;
} else if (!strcmp(argv[j],"--fullscreen")) {
appData.fullscreen = 1;
} else if (!strcmp(argv[j],"--uiscale") && more) {
appData.screen_uiscale = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--screensize") && more) {
appData.screen_width = atoi(argv[++j]);
appData.screen_height = atoi(argv[++j]);
} else if (!strcmp(argv[j],"--help")) {
showHelp();
exit(0);
} else {
fprintf(stderr, "Unknown or not enough arguments for option '%s'.\n\n", argv[j]);
showHelp();
exit(1);
}
}
// Try to connect to the selected ip address and port. We only support *ONE* input connection which we initiate.here.
c = (struct client *) malloc(sizeof(*c));
while(1) {
if ((fd = setupConnection(c)) == ANET_ERR) {
fprintf(stderr, "Waiting on %s:%d\n", View1090.net_input_beast_ipaddr, AircraftData.modes.net_input_beast_port);
sleep(1);
} else {
break;
}
}
int go;
init("sdl1090");
atexit(cleanup);
go = 1;
while (go == 1)
{
getInput();
interactiveRemoveStaleAircrafts();
draw();
if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) {
free(c);
usleep(1000000);
c = (struct client *) malloc(sizeof(*c));
fd = setupConnection(c);
continue;
}
modesReadFromClient(c,"",decodeBinMessage);
//usleep(10000);
}
// The user has stopped us, so close any socket we opened
if (fd != ANET_ERR)
{close(fd);}
return (0);
}
//
//=========================================================================
//

View file

@ -1,149 +0,0 @@
# Microsoft Developer Studio Project File - Name="view1090" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=view1090 - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "view1090.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "view1090.mak" CFG="view1090 - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "view1090 - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "view1090 - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "view1090 - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /W3 /GX /O2 /I ".\pthreads\." /I ".\rtlsdr\." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /machine:I386
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "view1090 - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".\pthreads\." /I ".\rtlsdr\." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
# SUBTRACT CPP /YX /Yc /Yu
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "view1090 - Win32 Release"
# Name "view1090 - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\anet.c
# End Source File
# Begin Source File
SOURCE=.\interactive.c
# End Source File
# Begin Source File
SOURCE=.\mode_ac.c
# End Source File
# Begin Source File
SOURCE=.\mode_s.c
# End Source File
# Begin Source File
SOURCE=.\net_io.c
# End Source File
# Begin Source File
SOURCE=.\view1090.c
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\dump1090.h
# End Source File
# Begin Source File
SOURCE=.\view1090.h
# End Source File
# Begin Source File
SOURCE=.\winstubs.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# Begin Group "Library Files"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\pthreads\pthreadVC2.lib
# End Source File
# Begin Source File
SOURCE=.\rtlsdr\rtlsdr.lib
# End Source File
# End Group
# End Target
# End Project

View file

@ -1,8 +1,8 @@
// Adapted from: // viz1090, a vizualizer for dump1090 ADSB output
// view1090, a Mode S messages viewer for dump1090 devices.
//
// Copyright (C) 2014 by Malcolm Robb <Support@ATTAvionics.com>
// //
// Copyright (C) 2020, Nathan Matsuda <info@nathanmatsuda.com>
// Copyright (C) 2014, Malcolm Robb <Support@ATTAvionics.com>
// Copyright (C) 2012, Salvatore Sanfilippo <antirez at gmail dot com>
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -48,16 +48,17 @@ void showHelp(void) {
"-----------------------------------------------------------------------------\n" "-----------------------------------------------------------------------------\n"
"| viz1090 ADSB Viewer Ver : 0.1 |\n" "| viz1090 ADSB Viewer Ver : 0.1 |\n"
"-----------------------------------------------------------------------------\n" "-----------------------------------------------------------------------------\n"
"--server <IPv4/hosname> TCP Beast output listen IPv4 (default: 127.0.0.1)\n" "--fps Show current framerate\n"
"--port <port> TCP Beast output listen port (default: 30005)\n" "--fullscreen Start fullscreen\n"
"--lat <latitude> Latitide in degrees\n" "--help Show this help\n"
"--lon <longitude> Longitude in degrees\n" "--lat <latitude> Latitude in degrees\n"
"--metric Use metric units\n" "--lon <longitude> Longitude in degrees\n"
"--help Show this help\n" "--metric Use metric units\n"
"--uiscale <factor> UI global scaling (default: 1)\n" "--port <port> TCP Beast output listen port (default: 30005)\n"
"--screensize <width> <height> Set frame buffer resolution (default: screen resolution)\n" "--server <IPv4/hosname> TCP Beast output listen IPv4 (default: 127.0.0.1)\n"
"--screenindex <i> Set the index of the display to use (default: 0)\n" "--screensize <width> <height> Set frame buffer resolution (default: screen resolution)\n"
"--fullscreen Start fullscreen\n" "--screenindex <i> Set the index of the display to use (default: 0)\n"
"--uiscale <factor> UI global scaling (default: 1)\n"
); );
} }
@ -94,6 +95,8 @@ int main(int argc, char **argv) {
view.centerLon = appData.modes.fUserLon; view.centerLon = appData.modes.fUserLon;
} else if (!strcmp(argv[j],"--metric")) { } else if (!strcmp(argv[j],"--metric")) {
view.metric = 1; view.metric = 1;
} else if (!strcmp(argv[j],"--fps")) {
view.fps = 1;
} else if (!strcmp(argv[j],"--fullscreen")) { } else if (!strcmp(argv[j],"--fullscreen")) {
view.fullscreen = 1; view.fullscreen = 1;
} else if (!strcmp(argv[j],"--screenindex")) { } else if (!strcmp(argv[j],"--screenindex")) {
@ -114,10 +117,7 @@ int main(int argc, char **argv) {
} }
int go; int go;
appData.connect();
view.SDL_init(); view.SDL_init();
view.font_init(); view.font_init();
@ -125,6 +125,7 @@ int main(int argc, char **argv) {
while (go == 1) while (go == 1)
{ {
appData.connect();
input.getInput(); input.getInput();
appData.update(); appData.update();
view.draw(); view.draw();

View file

@ -1,111 +0,0 @@
// dump1090, a Mode S messages decoder for RTLSDR devices.
//
// Copyright (C) 2014 by Malcolm Robb <support@attavionics.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// This file provides basic Windows implementation of Linux specific functions
// used in the dump1090 project. This allows dump1090 to be compiled and debugged
// using Microsoft Visual C++ 6.0
//
// Note that not all functions actually provide equivalent functionality to their
// Linux equivalents. They are simply stubs to allow the project to compile.
//
#ifndef __WINSTUBS_H
#define __WINSTUBS_H
#include <winsock2.h>
#include <windows.h>
#include <basetsd.h>
typedef UCHAR uint8_t;
typedef USHORT uint16_t;
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;
typedef UINT32 mode_t;
typedef long ssize_t;
typedef int socklen_t;
#include <stdio.h>
#include <time.h>
#include <sys/timeb.h>
#include <sys/stat.h>
#include <signal.h>
#include <io.h>
#include <fcntl.h>
#define M_PI 3.14159265358979323846
#include <math.h>
#include <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
//Functions not included in the MSVC maths library. This will do for our use.
_inline double round(double d) {return floor(d + 0.5);}
_inline double trunc(double d) {return (d>0) ? floor(d):ceil(d) ;}
//usleep works in microseconds, and isn't supported in Windows. This will do for our use.
_inline void usleep(UINT32 ulSleep) {Sleep(ulSleep/1000);}
_inline uint64_t strtoll(const char *p, void *e, UINT32 base) {return _atoi64(p);}
_inline int inet_aton(const char * cp, DWORD * ulAddr) { *ulAddr = inet_addr(cp); return (INADDR_NONE != *ulAddr);}
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define realpath(N,R) _fullpath((R),(N),_MAX_PATH)
_inline void cls() {
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord = {0, 0};
DWORD count;
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hStdOut, &csbi);
FillConsoleOutputCharacter(hStdOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, coord, &count);
SetConsoleCursorPosition(hStdOut, coord);
}
_inline int gettimeofday(struct timeval *tv, struct timezone *tz) {
SYSTEMTIME stSystemTime;
GetLocalTime(&stSystemTime);
tv->tv_sec = stSystemTime.wSecond + (60 * (stSystemTime.wMinute + (60 * stSystemTime.wHour)));
tv->tv_usec = stSystemTime.wMilliseconds * 1000;
return 0;
}
#define STDIN_FILENO 0
#define EINPROGRESS WSAEINPROGRESS
#define EWOULDBLOCK WSAEWOULDBLOCK
#ifdef __cplusplus
}
#endif
#endif // __WINSTUBS_H