Compare commits

..

63 commits

Author SHA1 Message Date
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
nathan cd1ce278c1 changed map representation to lines instead of polys. tried some speedups by drawing around edges of previous map texture, but need to move to tiles
Former-commit-id: 48a929dea6e2eb94785fa4e38afb1aba357c372f
2020-06-12 20:32:42 -07:00
nathan b8dd741165 fixed mapconvert issue that eliminated horizontal and vertical lines
Former-commit-id: 88370ea8c775bc7b7cc03aae6193776df6783061
2020-06-11 22:55:59 -07:00
nathan def7ee20e1 map convert precision change. fixed map load issue. changed time functions to std::chrono
Former-commit-id: a774a5bdbcf9e1c643e56277dbeedcedacb54905
2020-06-11 21:55:04 -07:00
nathan bc88c0ba5d std::list -> vector for performance. Working on mapconverter precision to merge points. Broken with lower precision levels, something wrong with QTInsert
Former-commit-id: c40d67cd1346a723dd8a3440b7eb845575c05f0b
2020-06-11 00:11:52 -07:00
nathan c45c788cae readme table formatting
Former-commit-id: 6180e9e508a5212d3792b8729466f92e33c8c41c
2020-06-10 11:30:27 -07:00
nathan ca8610758f Merge branch 'master' of https://github.com/nmatsuda/viz1090
Former-commit-id: 37e64373825a5ee30b2dd66a805bae641607b477
2020-06-10 11:29:10 -07:00
nathan 2f8ce3447d misc cleanup
Former-commit-id: 747cd4fac34c15f1c7d404abb90a37ccdda8d208
2020-06-10 11:28:52 -07:00
nathan 5234e9aa12 misc comment and readme cleanup
Former-commit-id: 8a1bced26e178b09faeaaed2555d5ac5af558f28
2020-06-10 11:27:51 -07:00
nathan 01bf0bc396 rename map1090.cpp
Former-commit-id: 3c9b73e78c36033a45da363ad93fb21cdd90a50c
2020-06-09 20:36:10 -07:00
nathan dba4babbd2 more Readme edits and file cleanup
Former-commit-id: 6953975a19bc00dd58b4ec8881df6f8788a374d4
Former-commit-id: 81667ba89b5356b649b7e74b07636fe49b19814e
2020-06-08 15:57:11 -07:00
nathan bf3e7d42d7 updating readme for WSL support
Former-commit-id: 42ae8363f4c8d96f4facb2a3db12dffff69b0644
Former-commit-id: a187a458b7a86cbd972fd4de2ffbf7a27cbdb5d3
2020-06-08 11:49:58 -07:00
2025 changed files with 2790 additions and 76437 deletions

BIN
.DS_Store vendored

Binary file not shown.

26
.gitignore vendored
View file

@ -2,12 +2,28 @@
*.bin
*.svg
view1090
map1090
*.swp
.~
thumbs.db
external/
.gradle
*.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 "AircraftLabel.h"
Aircraft::Aircraft(uint32_t addr) {
this->addr = addr;
created = 0;
prev_seen = 0;
x = 0;
y = 0;
cx = 0;
cy = 0;
lon = 0;
lat = 0;
ox = 0;
oy = 0;
dox = 0;
doy = 0;
ddox = 0;
ddoy = 0;
label = NULL;
next = NULL;
}

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 <list>
#include <vector>
#include <chrono>
class AircraftLabel;
class Aircraft {
public:
uint32_t addr; // ICAO address
char flight[16]; // Flight number
unsigned char signalLevel[8]; // Last 8 Signal Amplitudes
double messageRate;
float messageRate;
int altitude; // Altitude
int speed; // Velocity
int track; // Angle of flight
@ -16,29 +50,36 @@ public:
time_t seen; // Time at which the last packet was received
time_t seenLatLon; // Time at which the last packet was received
time_t prev_seen;
double lat, lon; // Coordinated obtained from CPR encoded data
float lat, lon; // Coordinated obtained from CPR encoded data
//history
std::list <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 oldLat[TRAIL_LENGTH];
// float oldHeading[TRAIL_LENGTH];
// time_t oldSeen[TRAIL_LENGTH];
// uint8_t oldIdx;
uint64_t created;
uint64_t msSeen;
uint64_t msSeenLatLon;
std::chrono::high_resolution_clock::time_point created;
std::chrono::high_resolution_clock::time_point msSeen;
std::chrono::high_resolution_clock::time_point msSeenLatLon;
int live;
struct Aircraft *next; // Next aircraft in our linked list
//// label stuff -> should go to aircraft icon class
int x, y, cx, cy, w, h;
float ox, oy, dox, doy, ddox, ddoy;
float pressure;
// int x, y, cx, cy;
int x, y;
// float w, h, target_w, target_h;
// float ox, oy, dox, doy, ddox, ddoy;
// float labelLevel;
// float opacity, target_opacity;
/// 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,15 +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.
//
#include "AircraftList.h"
static uint64_t mstime(void) {
struct timeval tv;
uint64_t mst;
gettimeofday(&tv, nullptr);
mst = ((uint64_t)tv.tv_sec)*1000;
mst += tv.tv_usec/1000;
return mst;
static std::chrono::high_resolution_clock::time_point now() {
return std::chrono::high_resolution_clock::now();
}
Aircraft *AircraftList::find(uint32_t addr) {
Aircraft *p = head;
@ -27,15 +53,18 @@ void AircraftList::update(Modes *modes) {
Aircraft *p = head;
while(p) {
p->live = 0;
p->live = 0;
p = p->next;
}
//debug
//find(1)->live = 1;
while(a) {
p = find(a->addr);
if (!p) {
//p = createPlaneObj(a);
p = new Aircraft(a->addr);
p->next = head;
head = p;
@ -51,7 +80,7 @@ void AircraftList::update(Modes *modes) {
}
p->seen = a->seen;
p->msSeen = mstime();
p->msSeen = now();
if((p->seen - p->prev_seen) > 0) {
p->messageRate = 1.0 / (double)(p->seen - p->prev_seen);
@ -60,32 +89,39 @@ void AircraftList::update(Modes *modes) {
memcpy(p->flight, a->flight, sizeof(p->flight));
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->speed = a->speed;
p->track = a->track;
p->track = a->track;
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->lat = a->lat;
if(p->seenLatLon < a->seenLatLon) {
p->msSeenLatLon = mstime();
// p->oldIdx = (p->oldIdx+1) % 32;
// 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->lonHistory.push_back(p->lon);
p->latHistory.push_back(p->lat);
p->headingHistory.push_back(p->track);
p->timestampHistory.push_back(p->msSeenLatLon);
p->seenLatLon = a->seenLatLon;
a = a->next;
}
@ -112,6 +148,10 @@ void AircraftList::update(Modes *modes) {
AircraftList::AircraftList() {
head = nullptr;
// //debug aircraft attached to mouse
// head = new Aircraft(1);
// memcpy(head->flight, "mouse", sizeof("mouse"));
}
AircraftList::~AircraftList() {
@ -120,4 +160,4 @@ AircraftList::~AircraftList() {
head = head->next;
delete(temp);
}
}
}

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 "dump1090.h" //for Modes

View file

@ -1,27 +1,45 @@
// 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 "anet.h"
//
//carried over from view1090.c
//
int AppData::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(modes.aneterr, server, modes.net_input_beast_port)) != ANET_ERR) {
anetNonBlock(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 =
@ -32,39 +50,32 @@ int AppData::setupConnection(struct client *c) {
return fd;
}
//
// end view1090.c
//
void AppData::initialize() {
// Allocate the various buffers used by Modes
if ( NULL == (modes.icao_cache = (uint32_t *) malloc(sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2)))
{
fprintf(stderr, "Out of memory allocating data buffer.\n");
exit(1);
}
// Clear the buffers that have just been allocated, just in-case
memset(modes.icao_cache, 0, sizeof(uint32_t) * MODES_ICAO_CACHE_LEN * 2);
// Prepare error correction tables
modesInitErrorInfo(&(modes));
}
void AppData::connect() {
// 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", server, modes.net_input_beast_port);
sleep(1);
} else {
break;
}
if(connected) {
return;
}
c = (struct client *) malloc(sizeof(*c));
if ((fd = setupConnection(c)) == ANET_ERR) {
fprintf(stderr, "Waiting on %s:%d\n", server, modes.net_input_beast_port);
return;
}
connected = true;
fprintf(stderr, "Connected to %s:%d\n", server, modes.net_input_beast_port);
}
@ -75,6 +86,10 @@ void AppData::disconnect() {
void AppData::update() {
if(!connected) {
return;
}
if ((fd == ANET_ERR) || (recv(c->fd, pk_buf, sizeof(pk_buf), MSG_PEEK | MSG_DONTWAIT) == 0)) {
free(c);
usleep(1000000);
@ -82,7 +97,8 @@ void AppData::update() {
fd = setupConnection(c);
return;
}
modesReadFromClient(&modes, c,"",decodeBinMessage);
char empty;
modesReadFromClient(&modes, c, &empty,decodeBinMessage);
interactiveRemoveStaleAircrafts(&modes);
@ -104,39 +120,37 @@ void AppData::updateStatus() {
msgRateAccumulate = 0.0;
// PlaneObj *p = appData.planes;
Aircraft *p = aircraftList.head;
// while(p) {
// unsigned char * pSig = p->signalLevel;
// unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
// pSig[4] + pSig[5] + pSig[6] + pSig[7]);
while(p) {
unsigned char * pSig = p->signalLevel;
unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
pSig[4] + pSig[5] + pSig[6] + pSig[7]);
// sigAccumulate += signalAverage;
sigAccumulate += signalAverage;
// if (p->lon && p->lat) {
// numVisiblePlanes++;
// }
if (p->lon && p->lat) {
numVisiblePlanes++;
}
// totalCount++;
totalCount++;
// msgRateAccumulate += p->messageRate;
msgRateAccumulate += p->messageRate;
// p = p->next;
// }
p = p->next;
}
// Status.msgRate = msgRateAccumulate;
// Status.avgSig = sigAccumulate / (double) totalCount;
// Status.numPlanes = totalCount;
// Status.numVisiblePlanes = numVisiblePlanes;
// Status.maxDist = maxDist;
msgRate = msgRateAccumulate;
avgSig = sigAccumulate / (double) totalCount;
numPlanes = totalCount;
numVisiblePlanes = numVisiblePlanes;
maxDist = maxDist;
}
AppData::AppData(){
// Default everything to zero/NULL
memset(&modes, 0, sizeof(Modes));
// Now initialise things that should not be 0/NULL to their defaults
modes.check_crc = 1;
strcpy(server,VIEW1090_NET_OUTPUT_IP_ADDRESS);
modes.net_input_beast_port = MODES_NET_OUTPUT_BEAST_PORT;
@ -148,4 +162,6 @@ AppData::AppData(){
modes.interactive = 0;
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
#define APPDATA_H
@ -14,6 +45,7 @@ class AppData {
//
struct client *c;
bool connected;
int fd;
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"
static uint64_t mstime(void) {
struct timeval tv;
uint64_t mst;
static std::chrono::high_resolution_clock::time_point now() {
return std::chrono::high_resolution_clock::now();
}
gettimeofday(&tv, NULL);
mst = ((uint64_t)tv.tv_sec)*1000;
mst += tv.tv_usec/1000;
return mst;
// static uint64_t now() {
// 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) {
@ -54,31 +87,33 @@ void Input::getInput()
view->mapTargetMaxDist = 0;
view->mapMoved = 1;
if(mstime() - touchDownTime > 100) {
touchDownTime = 0;
if(elapsed(touchDownTime) > 100) {
//touchDownTime = 0;
}
break;
case SDL_FINGERMOTION:;
if(mstime() - touchDownTime > 150) {
if(elapsed(touchDownTime) > 150) {
tapCount = 0;
touchDownTime = 0;
//touchDownTime = 0;
}
view->moveCenterRelative( view->screen_width * event.tfinger.dx, view->screen_height * event.tfinger.dy);
break;
case SDL_FINGERDOWN:
if(mstime() - touchDownTime > 500) {
if(elapsed(touchDownTime) > 500) {
tapCount = 0;
}
if(SDL_GetNumTouchFingers(event.tfinger.touchId) == 0) {
touchDownTime = mstime();
//this finger number is always 1 for down and 0 for up an rpi+hyperpixel??
if(SDL_GetNumTouchFingers(event.tfinger.touchId) <= 1) {
touchDownTime = now();
}
break;
case SDL_FINGERUP:
if(mstime() - touchDownTime < 150 && SDL_GetNumTouchFingers(event.tfinger.touchId) == 0) {
if(elapsed(touchDownTime) < 150 && SDL_GetNumTouchFingers(event.tfinger.touchId) == 0) {
touchx = view->screen_width * event.tfinger.x;
touchy = view->screen_height * event.tfinger.y;
tapCount++;
@ -93,10 +128,10 @@ void Input::getInput()
case SDL_MOUSEBUTTONDOWN:
if(event.button.which != SDL_TOUCH_MOUSEID) {
if(mstime() - touchDownTime > 500) {
if(elapsed(touchDownTime) > 500) {
tapCount = 0;
}
touchDownTime = mstime();
touchDownTime = now();
}
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
#define INPUT_H
#include "AppData.h"
#include "View.h"
#include "View.h"
#include <chrono>
class Input {
public:
@ -14,7 +47,7 @@ public:
View *view;
AppData *appData;
uint64_t touchDownTime;
std::chrono::high_resolution_clock::time_point touchDownTime;
int touchx;
int touchy;
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
#
CPPFLAGS=-O2 -g -Wno-write-strings -I/usr/include/SDL2
LIBS=-lm -lSDL2 -lSDL2_ttf -lSDL2_gfx
CC=g++
CXXFLAGS=-O2 -std=c++11 -g
LIBS= -lm -lSDL2 -lSDL2_ttf -lSDL2_gfx -g
CXX=g++
all: map1090
all: viz1090
%.o: %.c %.cpp
$(CC) $(CFLAGS) $(EXTRACFLAGS) -c $<
$(CXX) $(CXXFLAGS) $(EXTRACFLAGS) -c $<
map1090: map1090.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
$(CC) -g -o map1090 map1090.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)
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
$(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:
rm -f *.o map1090
rm -f \
airportdata.bin \
airportnames \
mapdata/* \
mapdata.bin \
mapnames \
*.o \
viz1090

369
Map.cpp
View file

@ -1,19 +1,76 @@
// 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 <stdio.h>
#include <cstdlib>
#include <sstream>
#include <fstream>
#include <string>
#include <iostream>
bool Map::QTInsert(QuadTree *tree, Polygon *polygon) {
// printf("Inserting %d point poly\n", polygon->numPoints);
bool Map::QTInsert(QuadTree *tree, Line *line, int depth) {
if (!(polygon->lat_min >= tree->lat_min &&
polygon->lat_max <= tree->lat_max &&
polygon->lon_min >= tree->lon_min &&
polygon->lon_max <= tree->lon_max)) {
// printf("doesnt fit: %f > %f, %f < %f, %f < %f,%f > %f \n",polygon->lat_min, tree->lat_min, polygon->lat_max, tree->lat_max, polygon->lon_min, tree->lon_min, polygon->lon_max,tree->lon_max);
// if(depth > 25) {
// // printf("fail [%f %f] -> [%f %f]\n",line->start.lon,line->start.lat,line->end.lon,line->end.lat);
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;
// }
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) {
tree->nw = new QuadTree;
@ -23,7 +80,7 @@ bool Map::QTInsert(QuadTree *tree, Polygon *polygon) {
tree->nw->lon_max = tree->lon_min + 0.5 * (tree->lon_max - tree->lon_min);
}
if (QTInsert(tree->nw,polygon)){
if (QTInsert(tree->nw, line, depth++)){
return true;
}
@ -36,7 +93,7 @@ bool Map::QTInsert(QuadTree *tree, Polygon *polygon) {
tree->sw->lon_max = tree->lon_max;
}
if (QTInsert(tree->sw,polygon)){
if (QTInsert(tree->sw, line, depth++)){
return true;
}
@ -49,7 +106,7 @@ bool Map::QTInsert(QuadTree *tree, Polygon *polygon) {
tree->ne->lon_max = tree->lon_min + 0.5 * (tree->lon_max - tree->lon_min);
}
if (QTInsert(tree->ne,polygon)){
if (QTInsert(tree->ne, line, depth++)){
return true;
}
@ -62,123 +119,267 @@ bool Map::QTInsert(QuadTree *tree, Polygon *polygon) {
tree->se->lon_max = tree->lon_max;
}
if (QTInsert(tree->se,polygon)){
if (QTInsert(tree->se, line, depth++)){
return true;
}
tree->polygons.push_back(*polygon);
tree->lines.push_back(&(*line));
return true;
}
std::list<Polygon> Map::getPolysRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max) {
std::list<Polygon> retPolys;
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;
if(tree == NULL) {
return retPolys;
return retLines;
}
if (tree->lat_min > screen_lat_max || screen_lat_min > tree->lat_max) {
return retPolys;
return retLines;
}
if (tree->lon_min > screen_lon_max || screen_lon_min > tree->lon_max) {
return retPolys;
return retLines;
}
retPolys.splice(retPolys.end(),getPolysRecursive(tree->nw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max));
retPolys.splice(retPolys.end(),getPolysRecursive(tree->sw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max));
retPolys.splice(retPolys.end(),getPolysRecursive(tree->ne, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max));
retPolys.splice(retPolys.end(),getPolysRecursive(tree->se, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max));
std::vector<Line*> ret;
ret = getLinesRecursive(tree->nw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max);
retLines.insert(retLines.end(), ret.begin(), ret.end());
float dx, dy;
ret = getLinesRecursive(tree->sw, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max);
retLines.insert(retLines.end(), ret.begin(), ret.end());
std::list<Polygon>::iterator currentPolygon;
ret = getLinesRecursive(tree->ne, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max);
retLines.insert(retLines.end(), ret.begin(), ret.end());
for (currentPolygon = tree->polygons.begin(); currentPolygon != tree->polygons.end(); ++currentPolygon) {
if(currentPolygon->points.empty()) {
continue;
}
ret = getLinesRecursive(tree->se, screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max);
retLines.insert(retLines.end(), ret.begin(), ret.end());
retPolys.push_back(*currentPolygon);
}
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;
}
std::list<Polygon> Map::getPolys(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max) {
return getPolysRecursive(&root, screen_lat_min, screen_lat_max, screen_lon_min, 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);
};
Map::Map() {
FILE *fileptr;
if(!(fileptr = fopen("mapdata.bin", "rb"))) {
printf("Couldn't read mapdata.bin\nDid you run getmap.sh?\n");
exit(0);
}
if((fileptr = fopen("mapdata.bin", "rb"))) {
fseek(fileptr, 0, SEEK_END);
mapPoints_count = ftell(fileptr) / sizeof(float);
rewind(fileptr);
fseek(fileptr, 0, SEEK_END);
mapPoints_count = ftell(fileptr) / sizeof(float);
rewind(fileptr);
mapPoints = (float *)malloc(mapPoints_count * sizeof(float));
if(!fread(mapPoints, sizeof(float), mapPoints_count, fileptr)){
printf("Read error\n");
exit(0);
}
mapPoints = (float *)malloc(mapPoints_count * sizeof(float));
if(!fread(mapPoints, sizeof(float), mapPoints_count, fileptr)){
printf("Map read error\n");
exit(0);
}
fclose(fileptr);
fclose(fileptr);
printf("Read %d map points.\n",mapPoints_count);
printf("Read %d map points.\n",mapPoints_count / 2);
// load quad tree
// load quad tree
for(int i = 0; i < mapPoints_count; i+=2) {
if(mapPoints[i] == 0)
continue;
for(int i = 0; i < mapPoints_count; i+=2) {
if(mapPoints[i] == 0)
continue;
if(mapPoints[i] < root.lon_min) {
root.lon_min = mapPoints[i];
} else if(mapPoints[i] > root.lon_max) {
root.lon_max = mapPoints[i];
}
if(mapPoints[i] < root.lon_min) {
root.lon_min = mapPoints[i];
} else if(mapPoints[i] > root.lon_max) {
root.lon_max = mapPoints[i];
}
if(mapPoints[i+1] < root.lat_min) {
root.lat_min = mapPoints[i+1];
} else if(mapPoints[i+1] > root.lat_max) {
root.lat_max = mapPoints[i+1];
}
}
if(mapPoints[i+1] < root.lat_min) {
root.lat_min = mapPoints[i+1];
} else if(mapPoints[i+1] > root.lat_max) {
root.lat_max = mapPoints[i+1];
}
}
Polygon *currentPolygon = new Polygon;
//printf("map bounds: %f %f %f %f\n",root.lon_min, root.lon_max, root.lat_min, root.lat_max);
for(int i = 0; i < mapPoints_count; i+=2) {
Point currentPoint;
Point nextPoint;
if(mapPoints[i] == 0) {
QTInsert(&root, currentPolygon);
currentPolygon = new Polygon;
for(int i = 0; i < mapPoints_count - 2; i+=2) {
if(mapPoints[i] == 0)
continue;
if(mapPoints[i + 1] == 0)
continue;
if(mapPoints[i + 2] == 0)
continue;
if(mapPoints[i + 3] == 0)
continue;
currentPoint.lon = mapPoints[i];
currentPoint.lat = mapPoints[i + 1];
nextPoint.lon = mapPoints[i + 2];
nextPoint.lat = mapPoints[i + 3];
// printf("inserting [%f %f] -> [%f %f]\n",currentPoint.lon,currentPoint.lat,nextPoint.lon,nextPoint.lat);
QTInsert(&root, new Line(currentPoint, nextPoint), 0);
}
} else {
printf("No map file found\n");
}
//
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];
}
}
currentPolygon->numPoints++;
//printf("map bounds: %f %f %f %f\n",root.lon_min, root.lon_max, root.lat_min, root.lat_max);
Point *currentPoint = new Point;
Point currentPoint;
Point nextPoint;
if(mapPoints[i] < currentPolygon->lon_min) {
currentPolygon->lon_min = mapPoints[i];
} else if(mapPoints[i] > currentPolygon->lon_max) {
currentPolygon->lon_max = mapPoints[i];
}
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];
if(mapPoints[i+1] < currentPolygon->lat_min) {
currentPolygon->lat_min = mapPoints[i+1];
} else if(mapPoints[i+1] > currentPolygon->lat_max) {
currentPolygon->lat_max = mapPoints[i+1];
}
currentPoint->lon = mapPoints[i];
currentPoint->lat = mapPoints[i+1];
nextPoint.lon = airportPoints[i + 2];
nextPoint.lat = airportPoints[i + 3];
currentPolygon->points.push_back(*currentPoint);
}
//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");
}

85
Map.h
View file

@ -1,30 +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.
//
#ifndef MAP_H
#define MAP_H
#include <list>
#include <vector>
#include <string>
typedef struct Point{
float lat;
float lon;
} Point;
typedef struct Polygon{
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{
float lat_min;
float lat_max;
float lon_min;
float lon_max;
std::list<Point> points;
int numPoints;
Point start;
Point end;
Polygon() {
lat_min = 180.0f;
lon_min = 180.0f;
lat_max = -180.0f;
lon_max = -180.0f;
numPoints = 0;
Line(Point start, Point end) {
this->start = start;
this->end = end;
lat_min = std::min(start.lat,end.lat);
lat_max = std::max(start.lat,end.lat);
lon_min = std::min(start.lon,end.lon);
lon_max = std::max(start.lon,end.lon);
}
} Polygon;
} Line;
typedef struct QuadTree{
float lat_min;
@ -32,7 +77,7 @@ typedef struct QuadTree{
float lon_min;
float lon_max;
std::list<Polygon> polygons;
std::vector<Line*> lines;
struct QuadTree *nw;
struct QuadTree *sw;
@ -74,14 +119,22 @@ class Map {
public:
QuadTree root;
QuadTree airport_root;
bool QTInsert(QuadTree *tree, Polygon *polygon);
std::list<Polygon> getPolysRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max);
std::list<Polygon> getPolys(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max);
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*> 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();
int mapPoints_count;
float *mapPoints;
float *mapPoints;
int airportPoints_count;
float *airportPoints;
};
#endif

146
README.md
View file

@ -1,88 +1,156 @@
#map1090
# viz1090
![image](https://media.giphy.com/media/dJnFpEDGi1swmb3L05/giphy.gif)
###BUILDING
**This is a work in progress**
Tested and working on Ubuntu 18.04, Raspbian Stretch, Buster
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!)
* Integration with handheld features like GPS, battery monitors, buttons/dials, etc.
### BUILDING
Tested and working on Ubuntu 18.04, Raspbian Stretch / Buster, Windows Subsystem for Linux (with Ubuntu 18.04), and Mac
0. Install build essentials
1. Install SDL and RTL-SDR libararies
```
sudo apt-get install libsdl2-dev libsdl2-ttf-dev libsdl2-gfx-dev librtlsdr-dev
sudo apt-get install build-essential
```
Note: the sdl2-config output that would normally be passed to compiler flags points to the wrong directory on my distro. Instead I have manually linked to /usr/include/sdl2
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.
1. Install SDL and RTL-SDR libraries
```
sudo apt-get install libsdl2-dev libsdl2-ttf-dev libsdl2-gfx-dev librtlsdr-dev libgdal-dev
```
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 ~
git clone https://www.github.com/nmatsuda/spidr
cd spidr
git clone https://www.github.com/nmatsuda/viz1090
cd viz1090
make clean; make
```
3. Download and process map data
Until more comprehensive map source (e.g., Mapbox) is integrated, map1090 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 map1090 to read.
```
sudo apt install python3 python3-pip
pip3 install fiona tqdm shapely
./getmap.sh
```
## Android Notes [temp]
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.
to change Android version or Arm type
android/app/build.gradle -> set compileSdkVersion, targetSdkVersion, abiFilters
android/sdl2/build.gradle -> set compileSdkVersion, targetSdkVersion, abiFilters
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.
###RUNNING
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/
* run Xlaunch from the start menu
* Uncheck "Use Native openGL"
* Add parameter ```-ac``` (WSL 2 only)
* Open the Ubuntu WSL terminal
* Specify the X display to use (WSL 1)
```
export DISPLAY=:0
```
* or for (WSL 2)
```
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):0
```
* Start viz1090 as described below.
### RUNNING
1. Start dump1090 (http://www.github.com/MalcolmRobb/dump1090) locally in network mode:
```
dump1090 --net
```
2. Run map1090
2. Run viz1090
```
./view1090 --fullsceen
./viz1090 --fullsceen --lat [your latitude] --lon [your longitude]
```
map1090 will open an SDL window set to the resolution of your screen.
viz1090 will open an SDL window set to the resolution of your screen.
###RUNTIME OPTIONS
### RUNTIME OPTIONS
--server [domain name or ip] Specify a dump1090 server. Renamed from the view1090 "--net-bo-ip-addr" argument
--port [port number] Specify dump1090 server port. Renamed from the view1090 "--net-bo-port" argument
--metric Display metric units rather than imperial.
| Argument | Description |
| ----------------------------- | ----------- |
| --server [domain name or ip] | Specify a dump1090 server |
| --port [port number] | Specify dump1090 server port |
| --metric | Display metric units |
| --lat | Specify your latitude in degrees |
| --lon | Specify your longitude in degrees |
| --screensize [width] [height] | Specify a resolution, otherwise use resolution of display |
| --uiscale [scale] | Scale up UI elements by integer amounts for high resolution screen |
| --fullscreen | Render fullscreen rather than in a window |
--screensize [width] [height] Specify a specific resolution to pass to SDL_RenderSetLogicalSize, otherwise use resolution of display
--uiscale [scale] Scale up UI elements by integer amounts for high resolution screen
--fullscreen Render fullscreen rather than in a window
### MAPS
###HARDWARE NOTES
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/)
map1090 is designed to be portable and work on a variety of systems, however it is intended to be used on a handheld device.
The software was originally develped for Raspberry Pi devices, and it is currently optimized for the Raspberry Pi 4 with the following configuration:
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
This software was originally intended for Raspberry Pi devices, and it is currently optimized for the Raspberry Pi 4 with the following configuration:
* Raspberry Pi 4
* A display:
* [Pimoroni HyperPixel 4.0 Display] (https://shop.pimoroni.com/products/hyperpixel-4) \*best overall, but requires some rework to use battery monitoring features of the PiJuice mentioned below
* [Waveshare 5.5" AMOLED] (https://www.waveshare.com/5.5inch-hdmi-amoled.htm) \*this is very good screen but the Google Pixel 2 phone mentioned below has a very similar display for the same price (along with everything else you need in a nice package)
* [Waveshare 4.3" HDMI(B)] (https://www.waveshare.com/wiki/4.3inch_HDMI_LCD_(B))
* [Adafruit 2.8" Capacitive Touch] (https://www.adafruit.com/product/2423)
* [Pimoroni HyperPixel 4.0 Display](https://shop.pimoroni.com/products/hyperpixel-4) \*best overall, but requires some rework to use battery monitoring features of the PiJuice mentioned below
* [Waveshare 5.5" AMOLED](https://www.waveshare.com/5.5inch-hdmi-amoled.htm) \*this is very good screen but the Google Pixel 2 phone mentioned below has a very similar display for the same price (along with everything else you need in a nice package)
* [Waveshare 4.3" HDMI(B)](https://www.waveshare.com/wiki/4.3inch_HDMI_LCD_(B))
* [Adafruit 2.8" Capacitive Touch](https://www.adafruit.com/product/2423)
* A battery hat, such as:
* [PiJuice Battery Hat] (https://uk.pi-supply.com/products/pijuice-standard) \*I2C pins must be reworked to connect to the Hyperpixel nonstandard I2C breakout pins, unfortunately
* [MakerFocus UPS Hat] (https://www.amazon.com/Makerfocus-Raspberry-2500mAh-Lithium-Battery/dp/B01MQYX4UX)
* [PiJuice Battery Hat](https://uk.pi-supply.com/products/pijuice-standard) \*I2C pins must be reworked to connect to the Hyperpixel nonstandard I2C breakout pins, unfortunately
* [MakerFocus UPS Hat](https://www.amazon.com/Makerfocus-Raspberry-2500mAh-Lithium-Battery/dp/B01MQYX4UX)
* Any USB SDR receiver:
* [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
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.
map1090 has been tested on other boards such as the UP Core and UP Squared, but these boards have significantly poorer performance than the Raspberry Pi 4 with less software and peripheral support, so they are not recommended. With low resolution maps the software will run on these boards or even a Raspberry Pi Zero, so these remain options with some tradeoffs.
viz1090 has been tested on other boards such as the UP Core and UP Squared, but these boards have poor performance compared to a Raspberry Pi 4, along with worse software and peripheral support, so they are not recommended. viz1090 with a low resolution map will run on these boards or even a Raspberry Pi Zero, so these remain options with some tradeoffs.
Of course, a variety of other devices work well for this purpose - all of the development so far has been done on a touchscreen Dell XPS laptop.
### Credits
viz1090 is largely based on [dump1090](https://github.com/MalcolmRobb/dump1090) (Malcom Robb, Salvatore Sanfilippo)

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

37
TODO.md
View file

@ -1,37 +0,0 @@
todo
UI stuff
+tap on plane sets plane to active
+animated recenter to active
+toggle follow and orient (and other popup info?)
double tap to zoom
animated label show and hide
+draw map to texture and only redraw on move
color themes (requires settings load)
settings (button popups or panes, sliders, etc)
battery level (need separate linux/win/android)
Utility stuff
+map load (and write from python) --> start by reducing lat/lon precision to 4 or 5 decimal places and change storage to float instead of double
libconfig load settings
Platforms
migrate Android project into main repo
SDL_AndroidGetJNIEnv() to access parameters, system info, etc
windows
naming
viz1090
map1090
sdl1090

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

1298
View.cpp

File diff suppressed because it is too large Load diff

107
View.h
View file

@ -1,22 +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
#define VIEW_H
#include "AppData.h"
#include "Map.h"
//#include "SDL2/SDL.h"
//#include "SDL2/SDL_ttf.h"
#include <SDL.h>
#include "SDL_ttf.h"
#include "Style.h"
#include "SDL2/SDL.h"
#include "SDL2/SDL_ttf.h"
#include <chrono>
#include <string>
//defs - should all move to config file setup
#define ROUND_RADIUS 3 //radius of text box corners
#define CENTEROFFSET .375 //vertical offset for middle of screen
#define TRAIL_LENGTH 120
#define TRAIL_TTL 240.0
#define DISPLAY_ACTIVE 30
#define DISPLAY_ACTIVE 30.0
#define TRAIL_TTL_STEP 2
#define MIN_MAP_FEATURE 2
@ -25,25 +55,7 @@
#define PAD 5
//
// 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;
#define LATLONMULT 111.195 // 6371.0 * M_PI / 180.0
class View {
@ -52,19 +64,26 @@ class View {
AppData *appData;
//for cursor drawing
uint64_t mouseMovedTime;
std::chrono::high_resolution_clock::time_point mouseMovedTime;
bool mouseMoved;
int mousex;
int mousey;
uint64_t clickTime;
std::chrono::high_resolution_clock::time_point clickTime;
bool clicked;
int clickx;
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 drawString(char * 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);
void drawStatusBox(int *left, int *top, char *label, char *message, SDL_Color color);
SDL_Rect drawString(std::string text, int x, int y, TTF_Font *font, SDL_Color color);
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, std::string label, std::string message, SDL_Color color);
void drawStatus();
Aircraft *selectedAircraft;
@ -77,16 +96,18 @@ class View {
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 drawTrail(Aircraft *p);
void drawTrails(int left, int top, int right, int bottom);
void drawScaleBars();
void drawPolys(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max);
void drawLinesRecursive(QuadTree *tree, float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max, SDL_Color color);
void drawLines(int left, int top, int right, int bottom, int bailTime);
void drawPlaceNames();
void drawGeography();
void drawSignalMarks(Aircraft *p, int x, int y);
void drawPlaneText(Aircraft *p);
void drawSelectedAircraftText(Aircraft *p);
void resolveLabelConflicts();
float resolveLabelConflicts();
void drawPlanes();
void animateCenterAbsolute(float x, float y);
void moveCenterAbsolute(float x, float y);
@ -109,7 +130,10 @@ class View {
////////////////
bool metric;
bool fps;
float maxDist;
float currentMaxDist;
float centerLon;
float centerLat;
@ -119,7 +143,14 @@ class View {
float mapTargetLon;
int mapMoved;
uint64_t lastFrameTime;
int mapRedraw;
int mapAnimating;
float currentLon;
float currentLat;
std::chrono::high_resolution_clock::time_point lastFrameTime;
std::chrono::high_resolution_clock::time_point drawStartTime;
std::chrono::high_resolution_clock::time_point lastRedraw;
Map map;
@ -150,4 +181,4 @@ class View {
int messageFontHeight;
};
#endif
#endif

BIN
a.out

Binary file not shown.

3
android/.gitignore vendored
View file

@ -1,3 +0,0 @@
distribution/
.gradle/
.idea/

View file

@ -1,28 +0,0 @@
cmake_minimum_required(VERSION 3.4.1)
message(${CMAKE_SOURCE_DIR})
string(TOLOWER ${CMAKE_BUILD_TYPE} ANDROID_BUILD_DIR)
set(DISTRIBUTION_DIR ${CMAKE_SOURCE_DIR}/distribution/android/SDL2/intermediates/ndkBuild)
set(SOURCE_FILES ../map1090.cpp ../AppData.cpp ../AircraftList.cpp ../Aircraft.cpp ../anet.c ../interactive.c ../mode_ac.c ../mode_s.c ../net_io.c ../Input.cpp ../View.cpp ../Map.cpp ../parula.c ../monokai.c)
set(SDL_LOCATION ${CMAKE_SOURCE_DIR}/external/SDL2)
add_library( SDL2 SHARED IMPORTED )
add_library( SDL2_ttf SHARED IMPORTED )
add_library( SDL2_gfx SHARED IMPORTED )
set_target_properties(SDL2 PROPERTIES IMPORTED_LOCATION
${DISTRIBUTION_DIR}/${ANDROID_BUILD_DIR}/obj/local/${ANDROID_ABI}/libSDL2.so)
set_target_properties(SDL2_ttf PROPERTIES IMPORTED_LOCATION
${DISTRIBUTION_DIR}/${ANDROID_BUILD_DIR}/obj/local/${ANDROID_ABI}/libSDL2_ttf.so)
set_target_properties(SDL2_gfx PROPERTIES IMPORTED_LOCATION
${DISTRIBUTION_DIR}/${ANDROID_BUILD_DIR}/obj/local/${ANDROID_ABI}/libSDL2_gfx.so)
include_directories(${SDL_LOCATION}/SDL2/include)
include_directories(${SDL_LOCATION}/SDL2_ttf)
include_directories(${SDL_LOCATION}/SDL2_gfx)
add_library( main SHARED ${SDL_LOCATION}/SDL2/src/main/android/SDL_android_main.c ${SOURCE_FILES} )
target_link_libraries( main SDL2 SDL2_ttf SDL2_gfx log)

View file

@ -1 +0,0 @@
.externalNativeBuild/

View file

@ -1,38 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
abiFilters "arm64-v8a"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
ndkBuild {
path '../external/SDL2/Android.mk'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:28.0.0'
testCompile 'junit:junit:4.12'
}

View file

@ -1,25 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/luap/Logiciels/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -1,10 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pvallet.com.github.sdl2">
<application android:allowBackup="true" android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>

View file

@ -1,3 +0,0 @@
<resources>
<string name="app_name">SDL2</string>
</resources>

View file

@ -1 +0,0 @@
.externalNativeBuild/

View file

@ -1,45 +0,0 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "nmatsuda.com.github.spidr"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti -fexceptions -Wno-narrowing"
}
}
ndk {
abiFilters "arm64-v8a"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
path "../CMakeLists.txt"
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:28.0.0'
// Uncomment this line to build SDL2
// Uncomment a line in ../gradle.settings as well
compile project(':SDL2')
testCompile 'junit:junit:4.12'
}

View file

@ -1,25 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/luap/Logiciels/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="nmatsuda.com.github.spidr">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".spidr"
android:configChanges="keyboardHidden|orientation"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

View file

@ -1 +0,0 @@
a007071944f7c90020e798eea53b10065e2b45a5

View file

@ -1 +0,0 @@
5e04b16605e6f165afada700fa09ec2c744bd4ca

View file

@ -1 +0,0 @@
cf67fe0caf3e7853db2af48cdcd28a4522a15572

View file

@ -1 +0,0 @@
e8e4a6045fa8374ca37fd7f53dfa95c61142ae98

View file

@ -1 +0,0 @@
730c63d4b5435fc57d6551f5a71d64b7e7d60fbb

View file

@ -1 +0,0 @@
97a5b8f6ed4324088d095d616a147d05cfe8917a

View file

@ -1 +0,0 @@
a09e9faff2c39c9dc56f6a0101a300851922e78d

View file

@ -1 +0,0 @@
ec881731ace782f1f692c4d9afabe1710ef6ac25

View file

@ -1 +0,0 @@
091001c845fa041bb58677bdb97edc546a43b72d

View file

@ -1 +0,0 @@
248a001641f39a4ad8b75387b889698120fd4983

View file

@ -1 +0,0 @@
130bb4a9cecd7210769427502b3ee33cdb097341

View file

@ -1 +0,0 @@
2a1ec89b5722143dfbdee504bbddab3a48b7bdd6

View file

@ -1 +0,0 @@
672aac709f31f3596fe66420cbc409122c8cb706

View file

@ -1 +0,0 @@
f20e8486e0becccceddade23c1f89d5336aebc49

View file

@ -1 +0,0 @@
11cbae78cf937af2f5c0236b8f86cad443162a2f

View file

@ -1 +0,0 @@
e8aa21e61df3e92fb290abc35215afdfe9a6db0a

View file

@ -1 +0,0 @@
bca6a642079482aab1d8d68488c6302c9e0e284d

View file

@ -1 +0,0 @@
5aeb931af933ee4dd2557a465ecadf908dc53978

View file

@ -1 +0,0 @@
22983e3d94e5c6e9c3f85f2bb6aff805b31657d0

View file

@ -1 +0,0 @@
66c93d8a95903ec73a80ea4f49811d23525ed967

View file

@ -1 +0,0 @@
d07ca5d41b3a257274f42c5fe0b402a672ea612a

View file

@ -1 +0,0 @@
db3b7b20ab68a2010a29158ad5a86a1fff1f86e5

View file

@ -1 +0,0 @@
6963c72346edf4b03a76271242ca933ac9afb750

View file

@ -1 +0,0 @@
0368d2bbae0b02dfeeb66950db2f79109714756e

View file

@ -1 +0,0 @@
f159709859ade068ba25e93720a5c8abc2fd20ce

View file

@ -1 +0,0 @@
53c606887962f52031d77dd4fe9c1ce85ce0783e

View file

@ -1 +0,0 @@
e52ba0d0e32c0a8a9de183dc11352f59c754c764

View file

@ -1 +0,0 @@
f279c6703790767cc5efae5941913527c039cb0b

View file

@ -1 +0,0 @@
653a1008f0ee073bafcd84e21bddd930e03579b1

View file

@ -1 +0,0 @@
d206e1de86a19ab735257abba83e25bd1d296ebb

View file

@ -1 +0,0 @@
9fe3e4aecd84c498563c3af03fe7050924915f60

View file

@ -1 +0,0 @@
eafa3a6e408def39bcd002f60a6d9a9810d54234

View file

@ -1 +0,0 @@
9dc2aed0a76993fd7ba9c28e0f55fce873a8c790

View file

@ -1 +0,0 @@
b173da27417c00101dff72617f9b9a2b80ecc8f3

View file

@ -1 +0,0 @@
72a5a99ac0c781eb60dd8721ae93eedda298e07e

View file

@ -1 +0,0 @@
602a3ee4ab20743037eee6daa1b304fa680967b6

View file

@ -1 +0,0 @@
ed0f5bce879796461ebb93969d28a2bbb35efd0f

View file

@ -1 +0,0 @@
c6cec55fcd5d8e00347661eba8684f848065594e

View file

@ -1 +0,0 @@
ca9c03a4767153b6d2f64c1d8909525ba39bb8d7

View file

@ -1 +0,0 @@
e8d186c510a26f1b4319bbb797c3ee18cb104e26

View file

@ -1 +0,0 @@
d748728a20789bf5f95e524f3d508f54c67f9475

View file

@ -1 +0,0 @@
4f2d2bc7cb6ae34d90066e1b330dc18ae2386e38

View file

@ -1 +0,0 @@
7bd6665765768ae885e2868623e7e9c2fd0cfc8a

View file

@ -1 +0,0 @@
6c5b8ba023e41689a2e14dc3c88f978e3188a1de

View file

@ -1 +0,0 @@
fdd309d716629f4e5339d5e5508225ed857a3ede

View file

@ -1 +0,0 @@
18f81a29258d13e1d6f1ce98cdd167091ea9bd4a

View file

@ -1 +0,0 @@
8ee248f748192c6ab6b2f5a1c18979d5bb16e646

View file

@ -1,53 +0,0 @@
package nmatsuda.com.github.spidr;
import org.libsdl.app.SDLActivity;
import android.view.View;
import android.os.Bundle;
public class SPIDR extends SDLActivity
{
/**
* This method is called by SDL before loading the native shared libraries.
* It can be overridden to provide names of shared libraries to be loaded.
* The default implementation returns the defaults. It never returns null.
* An array returned by a new implementation must at least contain "SDL2".
* Also keep in mind that the order the libraries are loaded may matter.
*
* @return names of shared libraries to be loaded (e.g. "SDL2", "main").
*/
@Override
protected String[] getLibraries() {
return new String[]{
"SDL2",
"SDL2_ttf",
"SDL2_gfx",
"main"
};
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
hideSystemUI();
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
// When the window loses focus (e.g. the action overflow is shown),
// cancel any pending hide action. When the window gains focus,
// hide the system UI.
hideSystemUI();
}
private void hideSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_IMMERSIVE);
}
}

View file

@ -1,37 +0,0 @@
package org.libsdl.app;
import android.content.Context;
/**
SDL library initialization
*/
public class SDL {
// This function should be called first and sets up the native code
// so it can call into the Java classes
public static void setupJNI() {
SDLActivity.nativeSetupJNI();
SDLAudioManager.nativeSetupJNI();
SDLControllerManager.nativeSetupJNI();
}
// This function should be called each time the activity is started
public static void initialize() {
setContext(null);
SDLActivity.initialize();
SDLAudioManager.initialize();
SDLControllerManager.initialize();
}
// This function stores the current activity (SDL or not)
public static void setContext(Context context) {
mContext = context;
}
public static Context getContext() {
return mContext;
}
protected static Context mContext;
}

View file

@ -1 +0,0 @@
8c363ed5ba9ff45cd6324015f1ce04d428922e69

View file

@ -1,178 +0,0 @@
package org.libsdl.app;
import android.media.*;
import android.util.Log;
public class SDLAudioManager
{
protected static final String TAG = "SDLAudio";
protected static AudioTrack mAudioTrack;
protected static AudioRecord mAudioRecord;
public static void initialize() {
mAudioTrack = null;
mAudioRecord = null;
}
// Audio
/**
* This method is called by SDL using JNI.
*/
public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
Log.v(TAG, "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
if (mAudioTrack == null) {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
// Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
// Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
// Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
Log.e(TAG, "Failed during initialization of Audio Track");
mAudioTrack = null;
return -1;
}
mAudioTrack.play();
}
Log.v(TAG, "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
return 0;
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteShortBuffer(short[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length; ) {
int result = mAudioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(short)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteByteBuffer(byte[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length; ) {
int result = mAudioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(byte)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
if (mAudioRecord == null) {
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
channelConfig, audioFormat, desiredFrames * frameSize);
// see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.e(TAG, "Failed during initialization of AudioRecord");
mAudioRecord.release();
mAudioRecord = null;
return -1;
}
mAudioRecord.startRecording();
}
Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
return 0;
}
/** This method is called by SDL using JNI. */
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
return mAudioRecord.read(buffer, 0, buffer.length);
}
/** This method is called by SDL using JNI. */
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
// !!! FIXME: this is available in API Level 23. Until then, we always block. :(
//return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
return mAudioRecord.read(buffer, 0, buffer.length);
}
/** This method is called by SDL using JNI. */
public static void audioClose() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
/** This method is called by SDL using JNI. */
public static void captureClose() {
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
public static native int nativeSetupJNI();
}

View file

@ -1,435 +0,0 @@
package org.libsdl.app;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.content.Context;
import android.os.*;
import android.view.*;
import android.util.Log;
public class SDLControllerManager
{
public static native int nativeSetupJNI();
public static native int nativeAddJoystick(int device_id, String name, String desc,
int is_accelerometer, int nbuttons,
int naxes, int nhats, int nballs);
public static native int nativeRemoveJoystick(int device_id);
public static native int nativeAddHaptic(int device_id, String name);
public static native int nativeRemoveHaptic(int device_id);
public static native int onNativePadDown(int device_id, int keycode);
public static native int onNativePadUp(int device_id, int keycode);
public static native void onNativeJoy(int device_id, int axis,
float value);
public static native void onNativeHat(int device_id, int hat_id,
int x, int y);
protected static SDLJoystickHandler mJoystickHandler;
protected static SDLHapticHandler mHapticHandler;
private static final String TAG = "SDLControllerManager";
public static void initialize() {
mJoystickHandler = null;
mHapticHandler = null;
SDLControllerManager.setup();
}
public static void setup() {
if (Build.VERSION.SDK_INT >= 16) {
mJoystickHandler = new SDLJoystickHandler_API16();
} else if (Build.VERSION.SDK_INT >= 12) {
mJoystickHandler = new SDLJoystickHandler_API12();
} else {
mJoystickHandler = new SDLJoystickHandler();
}
mHapticHandler = new SDLHapticHandler();
}
// Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
public static boolean handleJoystickMotionEvent(MotionEvent event) {
return mJoystickHandler.handleMotionEvent(event);
}
/**
* This method is called by SDL using JNI.
*/
public static void pollInputDevices() {
mJoystickHandler.pollInputDevices();
}
/**
* This method is called by SDL using JNI.
*/
public static void pollHapticDevices() {
mHapticHandler.pollHapticDevices();
}
/**
* This method is called by SDL using JNI.
*/
public static void hapticRun(int device_id, int length) {
mHapticHandler.run(device_id, length);
}
// Check if a given device is considered a possible SDL joystick
public static boolean isDeviceSDLJoystick(int deviceId) {
InputDevice device = InputDevice.getDevice(deviceId);
// We cannot use InputDevice.isVirtual before API 16, so let's accept
// only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
if ((device == null) || (deviceId < 0)) {
return false;
}
int sources = device.getSources();
/* This is called for every button press, so let's not spam the logs */
/**
if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) {
Log.v(TAG, "Input device " + device.getName() + " is a joystick.");
}
if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) {
Log.v(TAG, "Input device " + device.getName() + " is a dpad.");
}
if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
Log.v(TAG, "Input device " + device.getName() + " is a gamepad.");
}
**/
return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
);
}
}
/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
class SDLJoystickHandler {
/**
* Handles given MotionEvent.
* @param event the event to be handled.
* @return if given event was processed.
*/
public boolean handleMotionEvent(MotionEvent event) {
return false;
}
/**
* Handles adding and removing of input devices.
*/
public void pollInputDevices() {
}
}
/* Actual joystick functionality available for API >= 12 devices */
class SDLJoystickHandler_API12 extends SDLJoystickHandler {
static class SDLJoystick {
public int device_id;
public String name;
public String desc;
public ArrayList<InputDevice.MotionRange> axes;
public ArrayList<InputDevice.MotionRange> hats;
}
static class RangeComparator implements Comparator<InputDevice.MotionRange> {
@Override
public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
return arg0.getAxis() - arg1.getAxis();
}
}
private ArrayList<SDLJoystick> mJoysticks;
public SDLJoystickHandler_API12() {
mJoysticks = new ArrayList<SDLJoystick>();
}
@Override
public void pollInputDevices() {
int[] deviceIds = InputDevice.getDeviceIds();
// It helps processing the device ids in reverse order
// For example, in the case of the XBox 360 wireless dongle,
// so the first controller seen by SDL matches what the receiver
// considers to be the first controller
for(int i=deviceIds.length-1; i>-1; i--) {
SDLJoystick joystick = getJoystick(deviceIds[i]);
if (joystick == null) {
joystick = new SDLJoystick();
InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) {
joystick.device_id = deviceIds[i];
joystick.name = joystickDevice.getName();
joystick.desc = getJoystickDescriptor(joystickDevice);
joystick.axes = new ArrayList<InputDevice.MotionRange>();
joystick.hats = new ArrayList<InputDevice.MotionRange>();
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
Collections.sort(ranges, new RangeComparator());
for (InputDevice.MotionRange range : ranges ) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
range.getAxis() == MotionEvent.AXIS_HAT_Y) {
joystick.hats.add(range);
}
else {
joystick.axes.add(range);
}
}
}
mJoysticks.add(joystick);
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, 0, -1,
joystick.axes.size(), joystick.hats.size()/2, 0);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
for(int i=0; i < mJoysticks.size(); i++) {
int device_id = mJoysticks.get(i).device_id;
int j;
for (j=0; j < deviceIds.length; j++) {
if (device_id == deviceIds[j]) break;
}
if (j == deviceIds.length) {
removedDevices.add(Integer.valueOf(device_id));
}
}
for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i).intValue();
SDLControllerManager.nativeRemoveJoystick(device_id);
for (int j=0; j < mJoysticks.size(); j++) {
if (mJoysticks.get(j).device_id == device_id) {
mJoysticks.remove(j);
break;
}
}
}
}
protected SDLJoystick getJoystick(int device_id) {
for(int i=0; i < mJoysticks.size(); i++) {
if (mJoysticks.get(i).device_id == device_id) {
return mJoysticks.get(i);
}
}
return null;
}
@Override
public boolean handleMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
int actionPointerIndex = event.getActionIndex();
int action = event.getActionMasked();
switch(action) {
case MotionEvent.ACTION_MOVE:
SDLJoystick joystick = getJoystick(event.getDeviceId());
if ( joystick != null ) {
for (int i = 0; i < joystick.axes.size(); i++) {
InputDevice.MotionRange range = joystick.axes.get(i);
/* Normalize the value to -1...1 */
float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
SDLControllerManager.onNativeJoy(joystick.device_id, i, value );
}
for (int i = 0; i < joystick.hats.size(); i+=2) {
int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY );
}
}
break;
default:
break;
}
}
return true;
}
public String getJoystickDescriptor(InputDevice joystickDevice) {
return joystickDevice.getName();
}
}
class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 {
@Override
public String getJoystickDescriptor(InputDevice joystickDevice) {
String desc = joystickDevice.getDescriptor();
if (desc != null && !desc.isEmpty()) {
return desc;
}
return super.getJoystickDescriptor(joystickDevice);
}
}
class SDLHapticHandler {
class SDLHaptic {
public int device_id;
public String name;
public Vibrator vib;
}
private ArrayList<SDLHaptic> mHaptics;
public SDLHapticHandler() {
mHaptics = new ArrayList<SDLHaptic>();
}
public void run(int device_id, int length) {
SDLHaptic haptic = getHaptic(device_id);
if (haptic != null) {
haptic.vib.vibrate (length);
}
}
public void pollHapticDevices() {
final int deviceId_VIBRATOR_SERVICE = 999999;
boolean hasVibratorService = false;
int[] deviceIds = InputDevice.getDeviceIds();
// It helps processing the device ids in reverse order
// For example, in the case of the XBox 360 wireless dongle,
// so the first controller seen by SDL matches what the receiver
// considers to be the first controller
if (Build.VERSION.SDK_INT >= 16)
{
for (int i = deviceIds.length - 1; i > -1; i--) {
SDLHaptic haptic = getHaptic(deviceIds[i]);
if (haptic == null) {
InputDevice device = InputDevice.getDevice(deviceIds[i]);
Vibrator vib = device.getVibrator();
if (vib.hasVibrator()) {
haptic = new SDLHaptic();
haptic.device_id = deviceIds[i];
haptic.name = device.getName();
haptic.vib = vib;
mHaptics.add(haptic);
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
}
}
}
}
/* Check VIBRATOR_SERVICE */
Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE);
if (vib != null) {
if (Build.VERSION.SDK_INT >= 11) {
hasVibratorService = vib.hasVibrator();
} else {
hasVibratorService = true;
}
if (hasVibratorService) {
SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE);
if (haptic == null) {
haptic = new SDLHaptic();
haptic.device_id = deviceId_VIBRATOR_SERVICE;
haptic.name = "VIBRATOR_SERVICE";
haptic.vib = vib;
mHaptics.add(haptic);
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
for(int i=0; i < mHaptics.size(); i++) {
int device_id = mHaptics.get(i).device_id;
int j;
for (j=0; j < deviceIds.length; j++) {
if (device_id == deviceIds[j]) break;
}
if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
// don't remove the vibrator if it is still present
} else if (j == deviceIds.length) {
removedDevices.add(device_id);
}
}
for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i);
SDLControllerManager.nativeRemoveHaptic(device_id);
for (int j=0; j < mHaptics.size(); j++) {
if (mHaptics.get(j).device_id == device_id) {
mHaptics.remove(j);
break;
}
}
}
}
protected SDLHaptic getHaptic(int device_id) {
for(int i=0; i < mHaptics.size(); i++) {
if (mHaptics.get(i).device_id == device_id) {
return mHaptics.get(i);
}
}
return null;
}
}
class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
// Generic Motion (mouse hover, joystick...) events go here
@Override
public boolean onGenericMotion(View v, MotionEvent event) {
float x, y;
int action;
switch ( event.getSource() ) {
case InputDevice.SOURCE_JOYSTICK:
case InputDevice.SOURCE_GAMEPAD:
case InputDevice.SOURCE_DPAD:
return SDLControllerManager.handleJoystickMotionEvent(event);
case InputDevice.SOURCE_MOUSE:
if (!SDLActivity.mSeparateMouseAndTouch) {
break;
}
action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
SDLActivity.onNativeMouse(0, action, x, y);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
SDLActivity.onNativeMouse(0, action, x, y);
return true;
default:
break;
}
break;
default:
break;
}
// Event was not managed
return false;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

View file

@ -1,3 +0,0 @@
<resources>
<string name="app_name">Hello-SDL2</string>
</resources>

View file

@ -1,11 +0,0 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

Some files were not shown because too many files have changed in this diff Show more