2017-09-14 16:39:56 +02:00
|
|
|
#include "dump1090.h"
|
2017-10-05 16:58:23 +02:00
|
|
|
#include "structs.h"
|
2019-09-08 01:11:20 +02:00
|
|
|
#include "SDL2/SDL2_rotozoom.h"
|
2019-09-09 06:23:38 +02:00
|
|
|
#include "SDL2/SDL2_gfxPrimitives.h"
|
|
|
|
//color schemes
|
|
|
|
#include "parula.h"
|
|
|
|
#include "monokai.h"
|
2017-09-14 05:21:36 +02:00
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
#include "View.h"
|
|
|
|
|
2017-10-05 16:58:23 +02:00
|
|
|
static uint64_t mstime(void) {
|
|
|
|
struct timeval tv;
|
|
|
|
uint64_t mst;
|
2017-09-14 05:21:36 +02:00
|
|
|
|
2017-10-05 16:58:23 +02:00
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
mst = ((uint64_t)tv.tv_sec)*1000;
|
|
|
|
mst += tv.tv_usec/1000;
|
|
|
|
return mst;
|
2017-09-17 16:46:48 +02:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
static float sign(float x) {
|
2020-02-18 07:47:42 +01:00
|
|
|
return (x > 0) - (x < 0);
|
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
static float clamp(float in, float min, float max) {
|
2020-03-07 05:51:47 +01:00
|
|
|
float out = in;
|
|
|
|
|
|
|
|
if(in < min) {
|
|
|
|
out = min;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(in > max) {
|
|
|
|
out = max;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
static void CROSSVP(float *v, float *u, float *w)
|
2019-09-09 06:23:38 +02:00
|
|
|
{
|
|
|
|
v[0] = u[1]*w[2] - u[2]*(w)[1];
|
|
|
|
v[1] = u[2]*w[0] - u[0]*(w)[2];
|
|
|
|
v[2] = u[0]*w[1] - u[1]*(w)[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Color setColor(uint8_t r, uint8_t g, uint8_t b) {
|
|
|
|
SDL_Color out;
|
|
|
|
out.r = r;
|
|
|
|
out.g = g;
|
|
|
|
out.b = b;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-02-18 03:11:05 +01:00
|
|
|
SDL_Color lerpColor(SDL_Color aColor, SDL_Color bColor, float factor) {
|
|
|
|
if(factor > 1.0f) {
|
|
|
|
factor = 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(factor < 0.0f) {
|
|
|
|
factor = 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Color out;
|
|
|
|
out.r = (1.0f - factor) * aColor.r + factor * bColor.r;
|
|
|
|
out.g = (1.0f - factor) * aColor.g + factor * bColor.g;
|
|
|
|
out.b = (1.0f - factor) * aColor.b + factor * bColor.b;
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
SDL_Color hsv2SDLColor(float h, float s, float v)
|
2019-09-22 03:46:52 +02:00
|
|
|
{
|
2020-02-27 07:44:30 +01:00
|
|
|
float hh, p, q, t, ff;
|
2019-09-22 03:46:52 +02:00
|
|
|
long i;
|
|
|
|
SDL_Color out;
|
|
|
|
|
|
|
|
if(s <= 0.0) { // < is bogus, just shuts up warnings
|
|
|
|
out.r = (uint8_t)v;
|
|
|
|
out.g = (uint8_t)v;
|
|
|
|
out.b = (uint8_t)v;
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
hh = h;
|
|
|
|
if(hh >= 360.0) hh = 0.0;
|
|
|
|
hh /= 60.0;
|
|
|
|
i = (long)hh;
|
|
|
|
ff = hh - i;
|
|
|
|
p = v * (1.0 - s);
|
|
|
|
q = v * (1.0 - (s * ff));
|
|
|
|
t = v * (1.0 - (s * (1.0 - ff)));
|
|
|
|
|
|
|
|
switch(i) {
|
|
|
|
case 0:
|
|
|
|
out.r = (uint8_t)v;
|
|
|
|
out.g = (uint8_t)t;
|
|
|
|
out.b = (uint8_t)p;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
out.r = (uint8_t)q;
|
|
|
|
out.g = (uint8_t)v;
|
|
|
|
out.b = (uint8_t)p;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
out.r = (uint8_t)p;
|
|
|
|
out.g = (uint8_t)v;
|
|
|
|
out.b = (uint8_t)t;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
out.r = (uint8_t)p;
|
|
|
|
out.g = (uint8_t)q;
|
|
|
|
out.b = (uint8_t)v;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
out.r = (uint8_t)t;
|
|
|
|
out.g = (uint8_t)p;
|
|
|
|
out.b = (uint8_t)v;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
default:
|
|
|
|
out.r = (uint8_t)v;
|
|
|
|
out.g = (uint8_t)p;
|
|
|
|
out.b = (uint8_t)q;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
int View::screenDist(float d) {
|
2020-03-19 06:22:59 +01:00
|
|
|
float scale_factor = (screen_width > screen_height) ? screen_width : screen_height;
|
|
|
|
return round(0.95 * scale_factor * 0.5 * fabs(d) / maxDist);
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-03-08 05:28:55 +01:00
|
|
|
void View::pxFromLonLat(float *dx, float *dy, float lon, float lat) {
|
2019-09-09 06:23:38 +02:00
|
|
|
if(!lon || !lat) {
|
|
|
|
*dx = 0;
|
|
|
|
*dy = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
*dx = 6371.0 * (lon - centerLon) * M_PI / 180.0f * cos(((lat + centerLat)/2.0f) * M_PI / 180.0f);
|
|
|
|
*dy = 6371.0 * (lat - centerLat) * M_PI / 180.0f;
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::latLonFromScreenCoords(float *lat, float *lon, int x, int y) {
|
2020-03-19 06:22:59 +01:00
|
|
|
float scale_factor = (screen_width > screen_height) ? screen_width : screen_height;
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float dx = maxDist * (x - (screen_width>>1)) / (0.95 * scale_factor * 0.5 );
|
|
|
|
float dy = maxDist * (y - (screen_height * CENTEROFFSET)) / (0.95 * scale_factor * 0.5 );
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
*lat = 180.0f * dy / (6371.0 * M_PI) + centerLat;
|
|
|
|
*lon = 180.0 * dx / (cos(((*lat + centerLat)/2.0f) * M_PI / 180.0f) * 6371.0 * M_PI) + centerLon;
|
2020-01-20 07:22:58 +01:00
|
|
|
}
|
|
|
|
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::screenCoords(int *outX, int *outY, float dx, float dy) {
|
2020-03-19 06:22:59 +01:00
|
|
|
*outX = (screen_width>>1) + ((dx>0) ? 1 : -1) * screenDist(dx);
|
|
|
|
*outY = (screen_height * CENTEROFFSET) + ((dy>0) ? -1 : 1) * screenDist(dy);
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
int View::outOfBounds(int x, int y) {
|
2020-03-19 06:22:59 +01:00
|
|
|
if(x < 0 || x >= screen_width || y < 0 || y >= screen_height ) {
|
2019-09-09 06:23:38 +02:00
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
//
|
|
|
|
// Font stuff
|
|
|
|
//
|
|
|
|
|
|
|
|
TTF_Font* View::loadFont(char *name, int size)
|
|
|
|
{
|
|
|
|
TTF_Font *font = TTF_OpenFont(name, size);
|
|
|
|
|
|
|
|
if (font == NULL)
|
|
|
|
{
|
|
|
|
printf("Failed to open Font %s: %s\n", name, TTF_GetError());
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
|
|
|
void View::closeFont(TTF_Font *font)
|
|
|
|
{
|
|
|
|
if (font != NULL)
|
|
|
|
{
|
|
|
|
TTF_CloseFont(font);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// SDL Utils
|
|
|
|
//
|
|
|
|
|
|
|
|
void View::SDL_init() {
|
|
|
|
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
|
|
printf("Could not initialize SDL: %s\n", SDL_GetError());
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TTF_Init() < 0) {
|
|
|
|
printf("Couldn't initialize SDL TTF: %s\n", SDL_GetError());
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
|
|
|
|
Uint32 flags = 0;
|
|
|
|
|
|
|
|
if(fullscreen) {
|
|
|
|
flags = flags | SDL_WINDOW_FULLSCREEN_DESKTOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(screen_width == 0) {
|
|
|
|
SDL_DisplayMode DM;
|
|
|
|
SDL_GetCurrentDisplayMode(0, &DM);
|
|
|
|
screen_width = DM.w;
|
|
|
|
screen_height= DM.h;
|
|
|
|
}
|
|
|
|
|
|
|
|
window = SDL_CreateWindow("map1090", SDL_WINDOWPOS_CENTERED_DISPLAY(screen_index), SDL_WINDOWPOS_CENTERED_DISPLAY(screen_index), screen_width, screen_height, flags);
|
|
|
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
|
|
|
mapTexture = SDL_CreateTexture(renderer,
|
|
|
|
SDL_PIXELFORMAT_ARGB8888,
|
|
|
|
SDL_TEXTUREACCESS_TARGET,
|
|
|
|
screen_width, screen_height);
|
|
|
|
|
|
|
|
mapMoved = 1;
|
|
|
|
mapTargetLon = 0;
|
|
|
|
mapTargetLat = 0;
|
|
|
|
mapTargetMaxDist = 0;
|
|
|
|
|
|
|
|
if(fullscreen) {
|
|
|
|
//SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); // make the scaled rendering look smoother.
|
|
|
|
SDL_RenderSetLogicalSize(renderer, screen_width, screen_height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void View::font_init() {
|
|
|
|
mapFont = loadFont("font/TerminusTTF-4.46.0.ttf", 12 * screen_uiscale);
|
|
|
|
mapBoldFont = loadFont("font/TerminusTTF-Bold-4.46.0.ttf", 12 * screen_uiscale);
|
|
|
|
|
|
|
|
listFont = loadFont("font/TerminusTTF-4.46.0.ttf", 12 * screen_uiscale);
|
|
|
|
|
|
|
|
messageFont = loadFont("font/TerminusTTF-Bold-4.46.0.ttf", 12 * screen_uiscale);
|
|
|
|
labelFont = loadFont("font/TerminusTTF-Bold-4.46.0.ttf", 12 * screen_uiscale);
|
|
|
|
|
|
|
|
mapFontWidth = 5 * screen_uiscale;
|
|
|
|
mapFontHeight = 12 * screen_uiscale;
|
|
|
|
|
|
|
|
messageFontWidth = 6 * screen_uiscale;
|
|
|
|
messageFontHeight = 12 * screen_uiscale;
|
|
|
|
|
|
|
|
labelFontWidth = 6 * screen_uiscale;
|
|
|
|
labelFontHeight = 12 * screen_uiscale;
|
|
|
|
|
|
|
|
//
|
|
|
|
// todo separate style stuff
|
|
|
|
//
|
|
|
|
|
|
|
|
SDL_Color bgcolor = {10,20,30,255};
|
|
|
|
SDL_Color greenblue = {236,192,68,255};
|
|
|
|
SDL_Color lightblue = {211,208,203,255};
|
|
|
|
SDL_Color mediumblue ={110,136,152,255};
|
|
|
|
SDL_Color darkblue = {46,82,102,255};
|
|
|
|
|
|
|
|
style.backgroundColor = bgcolor;
|
|
|
|
style.selectedColor = pink;
|
|
|
|
style.planeColor = greenblue;
|
|
|
|
style.planeGoneColor = grey;
|
|
|
|
style.mapInnerColor = mediumblue;
|
|
|
|
style.mapOuterColor = darkblue;
|
|
|
|
style.scaleBarColor = lightGrey;
|
|
|
|
style.buttonColor = lightblue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void View::drawString(char * text, int x, int y, TTF_Font *font, SDL_Color color)
|
|
|
|
{
|
|
|
|
if(!strlen(text)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Surface *surface;
|
|
|
|
SDL_Rect dest;
|
|
|
|
|
|
|
|
surface = TTF_RenderUTF8_Solid(font, text, color);
|
|
|
|
|
|
|
|
if (surface == NULL)
|
|
|
|
{
|
|
|
|
printf("Couldn't create String %s: %s\n", text, SDL_GetError());
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void View::drawStringBG(char * text, int x, int y, TTF_Font *font, SDL_Color color, SDL_Color bgColor) {
|
|
|
|
if(!strlen(text)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_Surface *surface;
|
|
|
|
SDL_Rect dest;
|
|
|
|
|
|
|
|
surface = TTF_RenderUTF8_Shaded(font, text, color, bgColor);
|
|
|
|
|
|
|
|
if (surface == NULL)
|
|
|
|
{
|
|
|
|
printf("Couldn't create String %s: %s\n", text, SDL_GetError());
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Blit the entire surface to the screen */
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Status boxes
|
|
|
|
//
|
|
|
|
|
|
|
|
void View::drawStatusBox(int *left, int *top, char *label, char *message, SDL_Color color) {
|
|
|
|
int labelWidth = (strlen(label) + ((strlen(label) > 0 ) ? 1 : 0)) * labelFontWidth;
|
|
|
|
int messageWidth = (strlen(message) + ((strlen(message) > 0 ) ? 1 : 0)) * messageFontWidth;
|
|
|
|
|
|
|
|
if(*left + labelWidth + messageWidth + PAD > screen_width) {
|
|
|
|
*left = PAD;
|
|
|
|
*top = *top - messageFontHeight - PAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
// filled black background
|
|
|
|
if(messageWidth) {
|
|
|
|
roundedBoxRGBA(renderer, *left, *top, *left + labelWidth + messageWidth, *top + messageFontHeight, ROUND_RADIUS, black.r, black.g, black.b, SDL_ALPHA_OPAQUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// filled label box
|
|
|
|
if(labelWidth) {
|
|
|
|
roundedBoxRGBA(renderer, *left, *top, *left + labelWidth, *top + messageFontHeight, ROUND_RADIUS,color.r, color.g, color.b, SDL_ALPHA_OPAQUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// outline message box
|
|
|
|
if(messageWidth) {
|
|
|
|
roundedRectangleRGBA(renderer, *left, *top, *left + labelWidth + messageWidth, *top + messageFontHeight, ROUND_RADIUS,color.r, color.g, color.b, SDL_ALPHA_OPAQUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
drawString(label, *left + labelFontWidth/2, *top, labelFont, black);
|
|
|
|
|
|
|
|
//message
|
|
|
|
drawString(message, *left + labelWidth + messageFontWidth/2, *top, messageFont, color);
|
|
|
|
|
|
|
|
*left = *left + labelWidth + messageWidth + PAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
void View::drawStatus() {
|
|
|
|
|
|
|
|
int left = PAD;
|
|
|
|
int top = screen_height - messageFontHeight - PAD;
|
|
|
|
|
|
|
|
char strLoc[20] = " ";
|
|
|
|
snprintf(strLoc, 20, "%3.3fN %3.3f%c", centerLat, fabs(centerLon),(centerLon > 0) ? 'E' : 'W');
|
|
|
|
drawStatusBox(&left, &top, "loc", strLoc, style.buttonColor);
|
|
|
|
|
|
|
|
char strPlaneCount[10] = " ";
|
|
|
|
snprintf(strPlaneCount, 10,"%d/%d", Status.numVisiblePlanes, Status.numPlanes);
|
|
|
|
drawStatusBox(&left, &top, "disp", strPlaneCount, style.buttonColor);
|
|
|
|
|
|
|
|
char strMsgRate[18] = " ";
|
|
|
|
snprintf(strMsgRate, 18,"%.0f/s", Status.msgRate);
|
|
|
|
drawStatusBox(&left, &top, "rate", strMsgRate, style.buttonColor);
|
|
|
|
|
|
|
|
char strSig[18] = " ";
|
|
|
|
snprintf(strSig, 18, "%.0f%%", 100.0 * Status.avgSig / 1024.0);
|
|
|
|
drawStatusBox(&left, &top, "sAvg", strSig, style.buttonColor);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
//
|
|
|
|
// Main drawing
|
|
|
|
//
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawPlaneOffMap(int x, int y, int *returnx, int *returny, SDL_Color planeColor) {
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float arrowWidth = 6.0 * screen_uiscale;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float inx = x - (screen_width>>1);
|
|
|
|
float iny = y - screen_height * CENTEROFFSET;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
float outx, outy;
|
|
|
|
outx = inx;
|
|
|
|
outy = iny;
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(abs(inx) > abs(y - (screen_height>>1)) * (float)(screen_width>>1) / (float)(screen_height * CENTEROFFSET)) { //left / right quadrants
|
|
|
|
outx = (screen_width>>1) * ((inx > 0) ? 1.0 : -1.0);
|
2019-09-09 06:23:38 +02:00
|
|
|
outy = (outx) * iny / (inx);
|
|
|
|
} else { // up / down quadrants
|
2020-03-19 06:22:59 +01:00
|
|
|
outy = screen_height * ((iny > 0) ? 1.0-CENTEROFFSET : -CENTEROFFSET );
|
2019-09-09 06:23:38 +02:00
|
|
|
outx = (outy) * inx / (iny);
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
// circleRGBA (renderer,(screen_width>>1) + outx, screen_height * CENTEROFFSET + outy,50,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
|
|
// thickLineRGBA(renderer,screen_width>>1,screen_height * CENTEROFFSET, (screen_width>>1) + outx, screen_height * CENTEROFFSET + outy,arrowWidth,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float inmag = sqrt(inx *inx + iny*iny);
|
|
|
|
float vec[3];
|
2019-09-09 06:23:38 +02:00
|
|
|
vec[0] = inx / inmag;
|
|
|
|
vec[1] = iny /inmag;
|
|
|
|
vec[2] = 0;
|
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float up[] = {0,0,1};
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float out[3];
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
CROSSVP(out,vec,up);
|
|
|
|
|
|
|
|
int x1, x2, x3, y1, y2, y3;
|
|
|
|
|
|
|
|
// arrow 1
|
2020-03-19 06:22:59 +01:00
|
|
|
x1 = (screen_width>>1) + outx - 2.0 * arrowWidth * vec[0] + round(-arrowWidth*out[0]);
|
|
|
|
y1 = (screen_height * CENTEROFFSET) + outy - 2.0 * arrowWidth * vec[1] + round(-arrowWidth*out[1]);
|
|
|
|
x2 = (screen_width>>1) + outx - 2.0 * arrowWidth * vec[0] + round(arrowWidth*out[0]);
|
|
|
|
y2 = (screen_height * CENTEROFFSET) + outy - 2.0 * arrowWidth * vec[1] + round(arrowWidth*out[1]);
|
|
|
|
x3 = (screen_width>>1) + outx - arrowWidth * vec[0];
|
|
|
|
y3 = (screen_height * CENTEROFFSET) + outy - arrowWidth * vec[1];
|
|
|
|
filledTrigonRGBA(renderer, x1, y1, x2, y2, x3, y3, planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
// arrow 2
|
2020-03-19 06:22:59 +01:00
|
|
|
x1 = (screen_width>>1) + outx - 3.0 * arrowWidth * vec[0] + round(-arrowWidth*out[0]);
|
|
|
|
y1 = (screen_height * CENTEROFFSET) + outy - 3.0 * arrowWidth * vec[1] + round(-arrowWidth*out[1]);
|
|
|
|
x2 = (screen_width>>1) + outx - 3.0 * arrowWidth * vec[0] + round(arrowWidth*out[0]);
|
|
|
|
y2 = (screen_height * CENTEROFFSET) + outy - 3.0 * arrowWidth * vec[1] + round(arrowWidth*out[1]);
|
|
|
|
x3 = (screen_width>>1) + outx - 2.0 * arrowWidth * vec[0];
|
|
|
|
y3 = (screen_height * CENTEROFFSET) + outy - 2.0 * arrowWidth * vec[1];
|
|
|
|
filledTrigonRGBA(renderer, x1, y1, x2, y2, x3, y3, planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
*returnx = x3;
|
|
|
|
*returny = y3;
|
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawPlaneIcon(int x, int y, float heading, SDL_Color planeColor)
|
2019-09-09 06:23:38 +02:00
|
|
|
{
|
2020-03-19 06:22:59 +01:00
|
|
|
float body = 8.0 * screen_uiscale;
|
|
|
|
float wing = 6.0 * screen_uiscale;
|
|
|
|
float tail = 3.0 * screen_uiscale;
|
|
|
|
float bodyWidth = 2.0 * screen_uiscale;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float vec[3];
|
2019-09-09 06:23:38 +02:00
|
|
|
vec[0] = sin(heading * M_PI / 180);
|
|
|
|
vec[1] = -cos(heading * M_PI / 180);
|
|
|
|
vec[2] = 0;
|
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float up[] = {0,0,1};
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float out[3];
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
CROSSVP(out,vec,up);
|
|
|
|
|
|
|
|
int x1, x2, y1, y2;
|
|
|
|
|
|
|
|
//body
|
|
|
|
x1 = x + round(-body*vec[0]);
|
|
|
|
y1 = y + round(-body*vec[1]);
|
|
|
|
x2 = x + round(body*vec[0]);
|
|
|
|
y2 = y + round(body*vec[1]);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
thickLineRGBA(renderer,x,y,x2,y2,bodyWidth,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
|
|
filledTrigonRGBA(renderer, x + round(-wing*.35*out[0]), y + round(-wing*.35*out[1]), x + round(wing*.35*out[0]), y + round(wing*.35*out[1]), x1, y1,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
|
|
|
filledCircleRGBA(renderer, x2,y2,screen_uiscale,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
//wing
|
|
|
|
x1 = x + round(-wing*out[0]);
|
|
|
|
y1 = y + round(-wing*out[1]);
|
|
|
|
x2 = x + round(wing*out[0]);
|
|
|
|
y2 = y + round(wing*out[1]);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
filledTrigonRGBA(renderer, x1, y1, x2, y2, x+round(body*.35*vec[0]), y+round(body*.35*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
//tail
|
|
|
|
x1 = x + round(-body*.75*vec[0]) + round(-tail*out[0]);
|
|
|
|
y1 = y + round(-body*.75*vec[1]) + round(-tail*out[1]);
|
|
|
|
x2 = x + round(-body*.75*vec[0]) + round(tail*out[0]);
|
|
|
|
y2 = y + round(-body*.75*vec[1]) + round(tail*out[1]);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
filledTrigonRGBA (renderer, x1, y1, x2, y2, x+round(-body*.5*vec[0]), y+round(-body*.5*vec[1]),planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
void View::drawTrail(Aircraft *p) {
|
2019-09-09 06:23:38 +02:00
|
|
|
int currentX, currentY, prevX, prevY;
|
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
std::list<float>::iterator lon_idx = std::next(p->lonHistory.begin());
|
|
|
|
std::list<float>::iterator lat_idx = std::next(p->latHistory.begin());
|
|
|
|
std::list<float>::iterator heading_idx = std::next(p->headingHistory.begin());
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
int idx = p->lonHistory.size();
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
for(; lon_idx != p->lonHistory.end(); ++lon_idx, ++lat_idx, ++heading_idx) {
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float dx, dy;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
pxFromLonLat(&dx, &dy, *lon_idx, *lat_idx);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
screenCoords(¤tX, ¤tY, dx, dy);
|
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
pxFromLonLat(&dx, &dy, *(std::prev(lon_idx)), *(std::prev(lat_idx)));
|
2019-09-09 06:23:38 +02:00
|
|
|
|
|
|
|
screenCoords(&prevX, &prevY, dx, dy);
|
|
|
|
|
|
|
|
if(outOfBounds(currentX,currentY)) {
|
2019-09-16 02:54:06 +02:00
|
|
|
continue;
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(outOfBounds(prevX,prevY)) {
|
2019-09-16 02:54:06 +02:00
|
|
|
continue;
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
// float age = pow(1.0 - (float)idx / (float)p->lonHistory.size(), 2.2);
|
|
|
|
float age = 1.0 - (float)idx / (float)p->lonHistory.size();
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
uint8_t colorVal = (uint8_t)floor(255.0 * clamp(age,0,0.5));
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
thickLineRGBA(renderer, prevX, prevY, currentX, currentY, 2 * screen_uiscale, 255, 255, 255, colorVal);
|
2020-03-03 07:44:32 +01:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
//age = pow(1.0 - (float)idx / 10.0f, 2.2);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
//colorVal = (uint8_t)floor(255.0 * clamp(age,0.1,1));
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
// float vec[3];
|
|
|
|
// vec[0] = sin(*heading_idx * M_PI / 180);
|
|
|
|
// vec[1] = -cos(*heading_idx * M_PI / 180);
|
|
|
|
// vec[2] = 0;
|
2020-02-19 00:37:41 +01:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
// float up[] = {0,0,1};
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
// float out[3];
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
// CROSSVP(out,vec,up);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
// int x1, y1, x2, y2;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
// int cross_size = 5 * screen_uiscale * age;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
// // //forward cross
|
|
|
|
// x1 = currentX + round(-cross_size*vec[0]);
|
|
|
|
// y1 = currentY + round(-cross_size*vec[1]);
|
|
|
|
// x2 = currentX + round(cross_size*vec[0]);
|
|
|
|
// y2 = currentY + round(cross_size*vec[1]);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
// thickLineRGBA(renderer,x1,y1,x2,y2,screen_uiscale,255,255,255,64);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
// //side cross
|
|
|
|
// x1 = currentX + round(-cross_size*out[0]);
|
|
|
|
// y1 = currentY + round(-cross_size*out[1]);
|
|
|
|
// x2 = currentX + round(cross_size*out[0]);
|
|
|
|
// y2 = currentY + round(cross_size*out[1]);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
// thickLineRGBA(renderer,x1,y1,x2,y2,screen_uiscale,255,255,255,64);
|
2020-03-13 00:56:26 +01:00
|
|
|
|
|
|
|
idx--;
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawScaleBars()
|
2019-09-09 06:23:38 +02:00
|
|
|
{
|
2020-02-08 08:04:52 +01:00
|
|
|
int scalePower = 0;
|
|
|
|
int scaleBarDist = screenDist((float)pow(10,scalePower));
|
|
|
|
|
2020-03-02 07:58:10 +01:00
|
|
|
char scaleLabel[13] = "";
|
2020-02-08 08:04:52 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
lineRGBA(renderer,10,10,10,10*screen_uiscale,style.scaleBarColor.r, style.scaleBarColor.g, style.scaleBarColor.b, 255);
|
2020-02-08 08:04:52 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
while(scaleBarDist < screen_width) {
|
|
|
|
lineRGBA(renderer,10+scaleBarDist,8,10+scaleBarDist,16*screen_uiscale,style.scaleBarColor.r, style.scaleBarColor.g, style.scaleBarColor.b, 255);
|
2020-02-08 08:04:52 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if (metric) {
|
2020-03-02 07:58:10 +01:00
|
|
|
snprintf(scaleLabel,13,"%dkm", (int)pow(10,scalePower));
|
2020-02-08 08:04:52 +01:00
|
|
|
} else {
|
2020-03-02 07:58:10 +01:00
|
|
|
snprintf(scaleLabel,13,"%dmi", (int)pow(10,scalePower));
|
2020-02-08 08:04:52 +01:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
drawString(scaleLabel, 10+scaleBarDist, 15*screen_uiscale, mapFont, style.scaleBarColor);
|
2020-02-08 08:04:52 +01:00
|
|
|
|
|
|
|
scalePower++;
|
|
|
|
scaleBarDist = screenDist((float)pow(10,scalePower));
|
|
|
|
}
|
|
|
|
|
|
|
|
scalePower--;
|
|
|
|
scaleBarDist = screenDist((float)pow(10,scalePower));
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
lineRGBA(renderer,10,10+5*screen_uiscale,10+scaleBarDist,10+5*screen_uiscale, style.scaleBarColor.r, style.scaleBarColor.g, style. scaleBarColor.b, 255);
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
void View::drawPolys(float screen_lat_min, float screen_lat_max, float screen_lon_min, float screen_lon_max) {
|
|
|
|
std::list<Polygon> polyList = map.getPolys(screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max);
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
std::list<Polygon>::iterator currentPolygon;
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
for (currentPolygon = polyList.begin(); currentPolygon != polyList.end(); ++currentPolygon) {
|
2020-01-22 08:24:29 +01:00
|
|
|
int x1,y1,x2,y2;
|
2020-03-19 06:22:59 +01:00
|
|
|
float dx,dy;
|
2020-01-22 08:24:29 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
std::list<Point>::iterator currentPoint;
|
|
|
|
std::list<Point>::iterator prevPoint;
|
2020-01-20 09:01:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
for (currentPoint = std::next(currentPolygon->points.begin()); currentPoint != currentPolygon->points.end(); ++currentPoint) {
|
|
|
|
prevPoint = std::prev(currentPoint);
|
2020-01-20 09:01:45 +01:00
|
|
|
|
2020-01-22 08:24:29 +01:00
|
|
|
pxFromLonLat(&dx, &dy, prevPoint->lon, prevPoint->lat);
|
|
|
|
screenCoords(&x1, &y1, dx, dy);
|
2020-01-20 09:01:45 +01:00
|
|
|
|
2020-01-22 08:24:29 +01:00
|
|
|
if(outOfBounds(x1,y1)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float d1 = dx* dx + dy * dy;
|
2020-01-22 08:24:29 +01:00
|
|
|
|
|
|
|
pxFromLonLat(&dx, &dy, currentPoint->lon, currentPoint->lat);
|
|
|
|
screenCoords(&x2, &y2, dx, dy);
|
|
|
|
|
|
|
|
if(outOfBounds(x2,y2)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
//this needs a differnt approach for the std list setup
|
2020-01-22 08:24:29 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
// if((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1) < MIN_MAP_FEATURE){
|
|
|
|
// currentPoint = currentPoint->next;
|
|
|
|
// continue;
|
|
|
|
// }
|
2020-01-22 08:24:29 +01:00
|
|
|
|
2020-02-27 07:44:30 +01:00
|
|
|
float d2 = dx* dx + dy * dy;
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float factor = 1.0 - (d1+d2) / (3* maxDist * maxDist);
|
2020-02-18 03:11:05 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
SDL_Color lineColor = lerpColor(style.mapOuterColor, style.mapInnerColor, factor);
|
2020-01-20 09:01:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
lineRGBA(renderer, x1, y1, x2, y2, lineColor.r, lineColor.g, lineColor.b, 255);
|
2020-01-22 08:24:29 +01:00
|
|
|
}
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-01-20 09:01:45 +01:00
|
|
|
////bounding boxes
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
// int x, y;
|
|
|
|
|
2020-01-20 09:01:45 +01:00
|
|
|
// pxFromLonLat(&dx, &dy, currentPolygon->lon_min, currentPolygon->lat_min);
|
|
|
|
// screenCoords(&x, &y, dx, dy);
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-01-20 09:01:45 +01:00
|
|
|
// int top = y;
|
|
|
|
// int left = x;
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-01-20 09:01:45 +01:00
|
|
|
// pxFromLonLat(&dx, &dy, currentPolygon->lon_max, currentPolygon->lat_max);
|
|
|
|
// screenCoords(&x, &y, dx, dy);
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-01-20 09:01:45 +01:00
|
|
|
// int bottom = y;
|
|
|
|
// int right = x;
|
2020-03-02 07:40:11 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
// rectangleRGBA(renderer, left, top, right, bottom, purple.r, purple.g, purple.b, 255);
|
2020-01-20 07:22:58 +01:00
|
|
|
}
|
2020-03-19 06:22:59 +01:00
|
|
|
|
2020-01-20 07:22:58 +01:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawGeography() {
|
2020-02-27 07:44:30 +01:00
|
|
|
float screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max;
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
latLonFromScreenCoords(&screen_lat_min, &screen_lon_min, 0, screen_height * -0.2);
|
|
|
|
latLonFromScreenCoords(&screen_lat_max, &screen_lon_max, screen_width, screen_height * 1.2);
|
2020-01-20 07:22:58 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
drawPolys(screen_lat_min, screen_lat_max, screen_lon_min, screen_lon_max);
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawSignalMarks(Aircraft *p, int x, int y) {
|
2019-09-16 02:54:06 +02:00
|
|
|
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 = (Uint8) (255.0 - (mstime() - p->msSeen) / 4.0);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
circleRGBA(renderer, x + mapFontWidth, y - 5, 2 * screen_uiscale, barColor.r, barColor.g, barColor.b, seenFade);
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
seenFade = (Uint8) (255.0 - (mstime() - p->msSeenLatLon) / 4.0);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
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);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
2019-09-09 08:17:40 +02:00
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawPlaneText(Aircraft *p) {
|
2019-09-22 03:46:52 +02:00
|
|
|
int maxCharCount = 0;
|
2019-09-16 02:54:06 +02:00
|
|
|
int currentCharCount;
|
|
|
|
|
|
|
|
int currentLine = 0;
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p->pressure * screen_width< 0.4f) {
|
2019-09-22 03:46:52 +02:00
|
|
|
drawSignalMarks(p, p->x, p->y);
|
2019-09-16 02:54:06 +02:00
|
|
|
|
2019-09-22 03:46:52 +02:00
|
|
|
char flight[10] = " ";
|
|
|
|
maxCharCount = snprintf(flight,10," %s", p->flight);
|
2019-09-09 06:52:09 +02:00
|
|
|
|
2020-02-18 07:47:42 +01:00
|
|
|
if(maxCharCount > 1) {
|
2020-03-19 06:22:59 +01:00
|
|
|
drawStringBG(flight, p->x, p->y, mapBoldFont, white, black);
|
|
|
|
//roundedRectangleRGBA(renderer, p->x, p->y, p->x + maxCharCount * mapFontWidth, p->y + mapFontHeight, ROUND_RADIUS, white.r, white.g, white.b, SDL_ALPHA_OPAQUE);
|
|
|
|
//drawString(flight, p->x, p->y, mapBoldFont, white);
|
2019-09-22 03:46:52 +02:00
|
|
|
currentLine++;
|
|
|
|
}
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p->pressure * screen_width < 0.2f) {
|
2019-09-22 03:46:52 +02:00
|
|
|
char alt[10] = " ";
|
2020-03-19 06:22:59 +01:00
|
|
|
if (metric) {
|
2019-09-22 03:46:52 +02:00
|
|
|
currentCharCount = snprintf(alt,10," %dm", (int) (p->altitude / 3.2828));
|
|
|
|
} else {
|
|
|
|
currentCharCount = snprintf(alt,10," %d'", p->altitude);
|
|
|
|
}
|
2019-09-16 02:54:06 +02:00
|
|
|
|
2020-02-18 07:47:42 +01:00
|
|
|
if(currentCharCount > 1) {
|
2020-03-19 06:22:59 +01:00
|
|
|
drawStringBG(alt, p->x, p->y + currentLine * mapFontHeight, mapFont, grey, black);
|
2019-09-22 03:46:52 +02:00
|
|
|
currentLine++;
|
|
|
|
}
|
2019-09-09 06:52:09 +02:00
|
|
|
|
2019-09-22 03:46:52 +02:00
|
|
|
if(currentCharCount > maxCharCount) {
|
|
|
|
maxCharCount = currentCharCount;
|
|
|
|
}
|
2019-09-16 02:54:06 +02:00
|
|
|
|
2019-09-22 03:46:52 +02:00
|
|
|
char speed[10] = " ";
|
2020-03-19 06:22:59 +01:00
|
|
|
if (metric) {
|
2019-09-22 03:46:52 +02:00
|
|
|
currentCharCount = snprintf(speed,10," %dkm/h", (int) (p->speed * 1.852));
|
|
|
|
} else {
|
|
|
|
currentCharCount = snprintf(speed,10," %dmph", p->speed);
|
|
|
|
}
|
|
|
|
|
2020-02-18 07:47:42 +01:00
|
|
|
if(currentCharCount > 1) {
|
2020-03-19 06:22:59 +01:00
|
|
|
drawStringBG(speed, p->x, p->y + currentLine * mapFontHeight, mapFont, grey, black);
|
2019-09-22 03:46:52 +02:00
|
|
|
currentLine++;
|
|
|
|
}
|
2019-09-16 02:54:06 +02:00
|
|
|
|
2019-09-22 03:46:52 +02:00
|
|
|
if(currentCharCount > maxCharCount) {
|
|
|
|
maxCharCount = currentCharCount;
|
|
|
|
}
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
2020-02-18 07:47:42 +01:00
|
|
|
if(maxCharCount > 1) {
|
2019-09-22 03:46:52 +02:00
|
|
|
|
|
|
|
Sint16 vx[4] = {p->cx, p->cx + (p->x - p->cx) / 2, p->x, p->x};
|
2020-03-19 06:22:59 +01:00
|
|
|
Sint16 vy[4] = {p->cy, p->cy + (p->y - p->cy) / 2, p->y - mapFontHeight, p->y};
|
2019-09-22 03:46:52 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p->cy > p->y + currentLine * mapFontHeight) {
|
|
|
|
vy[2] = p->y + currentLine * mapFontHeight + mapFontHeight;
|
|
|
|
vy[3] = p->y + currentLine * mapFontHeight;
|
2019-09-22 03:46:52 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
bezierRGBA(renderer,vx,vy,4,2,200,200,200,SDL_ALPHA_OPAQUE);
|
2019-09-22 03:46:52 +02:00
|
|
|
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
thickLineRGBA(renderer,p->x,p->y,p->x,p->y+currentLine*mapFontHeight,screen_uiscale,200,200,200,SDL_ALPHA_OPAQUE);
|
2019-09-22 03:46:52 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
p->w = maxCharCount * mapFontWidth;
|
|
|
|
p->h = currentLine * mapFontHeight;
|
2019-09-09 06:52:09 +02:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawSelectedAircraftText(Aircraft *p) {
|
2020-02-18 07:47:42 +01:00
|
|
|
if(p == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2019-09-09 08:17:40 +02:00
|
|
|
|
2020-02-18 07:47:42 +01:00
|
|
|
int x = p->cx - 20;
|
|
|
|
int y = p->cy + 22;
|
|
|
|
|
|
|
|
int maxCharCount = 0;
|
|
|
|
int currentCharCount;
|
|
|
|
|
|
|
|
int currentLine = 0;
|
|
|
|
|
|
|
|
drawSignalMarks(p, x, y);
|
|
|
|
|
|
|
|
char flight[10] = " ";
|
|
|
|
maxCharCount = snprintf(flight,10," %s", p->flight);
|
|
|
|
|
|
|
|
if(maxCharCount > 1) {
|
2020-03-19 06:22:59 +01:00
|
|
|
drawStringBG(flight, x, y, mapBoldFont, white, black);
|
|
|
|
//roundedRectangleRGBA(renderer, p->x, p->y, p->x + maxCharCount * mapFontWidth, p->y + mapFontHeight, ROUND_RADIUS, white.r, white.g, white.b, SDL_ALPHA_OPAQUE);
|
|
|
|
//drawString(flight, p->x, p->y, mapBoldFont, white);
|
2020-02-18 07:47:42 +01:00
|
|
|
currentLine++;
|
|
|
|
}
|
|
|
|
|
|
|
|
char alt[10] = " ";
|
2020-03-19 06:22:59 +01:00
|
|
|
if (metric) {
|
2020-02-18 07:47:42 +01:00
|
|
|
currentCharCount = snprintf(alt,10," %dm", (int) (p->altitude / 3.2828));
|
|
|
|
} else {
|
|
|
|
currentCharCount = snprintf(alt,10," %d'", p->altitude);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(currentCharCount > 1) {
|
2020-03-19 06:22:59 +01:00
|
|
|
drawStringBG(alt, x, y + currentLine * mapFontHeight, mapFont, grey, black);
|
2020-02-18 07:47:42 +01:00
|
|
|
currentLine++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(currentCharCount > maxCharCount) {
|
|
|
|
maxCharCount = currentCharCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
char speed[10] = " ";
|
2020-03-19 06:22:59 +01:00
|
|
|
if (metric) {
|
2020-02-18 07:47:42 +01:00
|
|
|
currentCharCount = snprintf(speed,10," %dkm/h", (int) (p->speed * 1.852));
|
|
|
|
} else {
|
|
|
|
currentCharCount = snprintf(speed,10," %dmph", p->speed);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(currentCharCount > 1) {
|
2020-03-19 06:22:59 +01:00
|
|
|
drawStringBG(speed, x, y + currentLine * mapFontHeight, mapFont, grey, black);
|
2020-02-18 07:47:42 +01:00
|
|
|
currentLine++;
|
|
|
|
}
|
|
|
|
}
|
2019-09-09 08:17:40 +02:00
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::resolveLabelConflicts() {
|
2020-03-19 06:22:59 +01:00
|
|
|
Aircraft *p = appData->aircraftList.head;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
while(p) {
|
2019-09-09 08:17:40 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
Aircraft *check_p = appData->aircraftList.head;
|
2019-09-09 08:17:40 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
int p_left = p->x - 10 * screen_uiscale;
|
|
|
|
int p_right = p->x + p->w + 10 * screen_uiscale;
|
|
|
|
int p_top = p->y - 10 * screen_uiscale;
|
|
|
|
int p_bottom = p->y + p->h + 10 * screen_uiscale;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
//debug box
|
2020-03-19 06:22:59 +01:00
|
|
|
//rectangleRGBA(renderer, p->x, p->y, p->x + p->w, p->y + p->h, 255,0,0, SDL_ALPHA_OPAQUE);
|
|
|
|
//lineRGBA(renderer, p->cx, p->cy, p->x, p->y, 0,255,0, SDL_ALPHA_OPAQUE);
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
//apply damping
|
|
|
|
|
2019-09-22 03:46:52 +02:00
|
|
|
p->ddox -= 0.07f * p->dox;
|
|
|
|
p->ddoy -= 0.07f * p->doy;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
//spring back to origin
|
2019-09-22 03:46:52 +02:00
|
|
|
p->ddox -= 0.005f * p->ox;
|
|
|
|
p->ddoy -= 0.005f * p->oy;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
// // //screen edge
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p_left < 10 * screen_uiscale) {
|
|
|
|
p->ox += (float)(10 * screen_uiscale - p_left);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p_right > (screen_width - 10 * screen_uiscale)) {
|
|
|
|
p->ox -= (float)(p_right - (screen_width - 10 * screen_uiscale));
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p_top < 10 * screen_uiscale) {
|
|
|
|
p->oy += (float)(10 * screen_uiscale - p_top);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p_bottom > (screen_height - 10 * screen_uiscale)) {
|
|
|
|
p->oy -= (float)(p_bottom - (screen_height - 10 * screen_uiscale));
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
2019-09-22 03:46:52 +02:00
|
|
|
p->pressure = 0;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
|
2019-09-22 03:46:52 +02:00
|
|
|
//check against other labels
|
2019-09-16 02:54:06 +02:00
|
|
|
while(check_p) {
|
|
|
|
if(check_p->addr != p->addr) {
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
int check_left = check_p->x - 5 * screen_uiscale;
|
|
|
|
int check_right = check_p->x + check_p->w + 5 * screen_uiscale;
|
|
|
|
int check_top = check_p->y - 5 * screen_uiscale;
|
|
|
|
int check_bottom = check_p->y + check_p->h + 5 * screen_uiscale;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
2019-09-22 03:46:52 +02:00
|
|
|
|
|
|
|
p->pressure += 1.0f / ((check_p->cx - p->cx) * (check_p->cx - p->cx) + (check_p->cy - p->cy) * (check_p->cy - p->cy));
|
|
|
|
|
|
|
|
|
2019-09-16 02:54:06 +02:00
|
|
|
//if(check_left > (p_right + 10) || check_right < (p_left - 10)) {
|
|
|
|
if(check_left > p_right || check_right < p_left) {
|
|
|
|
check_p = check_p -> next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//if(check_top > (p_bottom + 10) || check_bottom < (p_top - 10)) {
|
|
|
|
if(check_top > p_bottom || check_bottom < p_top) {
|
|
|
|
check_p = check_p -> next;
|
|
|
|
continue;
|
|
|
|
}
|
2019-09-09 08:17:40 +02:00
|
|
|
|
2019-09-16 02:54:06 +02:00
|
|
|
//left collision
|
|
|
|
if(check_left > p_left && check_left < p_right) {
|
2019-09-22 03:46:52 +02:00
|
|
|
check_p->ddox -= 0.01f * (float)(check_left - p_right);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//right collision
|
|
|
|
if(check_right > p_left && check_right < p_right) {
|
2019-09-22 03:46:52 +02:00
|
|
|
check_p->ddox -= 0.01f * (float)(check_right - p_left);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//top collision
|
|
|
|
if(check_top > p_top && check_top < p_bottom) {
|
2019-09-22 03:46:52 +02:00
|
|
|
check_p->ddoy -= 0.01f * (float)(check_top - p_bottom);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//bottom collision
|
|
|
|
if(check_bottom > p_top && check_bottom < p_bottom) {
|
2019-09-22 03:46:52 +02:00
|
|
|
check_p->ddoy -= 0.01f * (float)(check_bottom - p_top);
|
|
|
|
}
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
check_p = check_p -> next;
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
check_p = appData->aircraftList.head;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
//check against plane icons (include self)
|
|
|
|
|
2020-02-08 08:04:52 +01:00
|
|
|
float plane_force = 0.08f;
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
p_left = p->x - 5 * screen_uiscale;
|
|
|
|
p_right = p->x + 5 * screen_uiscale;
|
|
|
|
p_top = p->y - 5 * screen_uiscale;
|
|
|
|
p_bottom = p->y + 5 * screen_uiscale;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
while(check_p) {
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
int check_left = check_p->x - 5 * screen_uiscale;
|
|
|
|
int check_right = check_p->x + check_p->w + 5 * screen_uiscale;
|
|
|
|
int check_top = check_p->y - 5 * screen_uiscale;
|
|
|
|
int check_bottom = check_p->y + check_p->h + 5 * screen_uiscale;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
if(check_left > p_right || check_right < p_left) {
|
|
|
|
check_p = check_p -> next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(check_top > p_bottom || check_bottom < p_top) {
|
|
|
|
check_p = check_p -> next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
//left collision
|
|
|
|
if(check_left > p_left && check_left < p_right) {
|
2020-02-08 08:04:52 +01:00
|
|
|
check_p->ddox -= plane_force * (float)(check_left - p_right);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//right collision
|
|
|
|
if(check_right > p_left && check_right < p_right) {
|
2020-02-08 08:04:52 +01:00
|
|
|
check_p->ddox -= plane_force * (float)(check_right - p_left);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//top collision
|
|
|
|
if(check_top > p_top && check_top < p_bottom) {
|
2020-02-08 08:04:52 +01:00
|
|
|
check_p->ddoy -= plane_force * (float)(check_top - p_bottom);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//bottom collision
|
|
|
|
if(check_bottom > p_top && check_bottom < p_bottom) {
|
2020-02-08 08:04:52 +01:00
|
|
|
check_p->ddoy -= plane_force * (float)(check_bottom - p_top);
|
2019-09-16 02:54:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
check_p = check_p -> next;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = p->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
//update
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
p = appData->aircraftList.head;
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
while(p) {
|
2020-02-18 07:47:42 +01:00
|
|
|
//incorporate acceleration from label conflict resolution
|
2019-09-16 02:54:06 +02:00
|
|
|
|
|
|
|
p->dox += p->ddox;
|
|
|
|
p->doy += p->ddoy;
|
|
|
|
|
|
|
|
if(fabs(p->dox) > 10.0f) {
|
|
|
|
p->dox = sign(p->dox) * 10.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fabs(p->doy) > 10.0f) {
|
|
|
|
p->doy = sign(p->doy) * 10.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fabs(p->dox) < 1.0f) {
|
|
|
|
p->dox = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fabs(p->doy) < 1.0f) {
|
|
|
|
p->doy = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
p->ox += p->dox;
|
|
|
|
p->oy += p->doy;
|
|
|
|
|
|
|
|
//printf("p_ox: %f, p_oy %f\n",p->ox, p->oy);
|
|
|
|
|
|
|
|
p->ddox = 0;
|
|
|
|
p->ddoy = 0;
|
|
|
|
|
|
|
|
p->x = p->cx + (int)round(p->ox);
|
|
|
|
p->y = p->cy + (int)round(p->oy);
|
|
|
|
|
|
|
|
p = p->next;
|
|
|
|
}
|
2019-09-09 08:17:40 +02:00
|
|
|
}
|
|
|
|
|
2019-09-16 02:54:06 +02:00
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawPlanes() {
|
2020-03-19 06:22:59 +01:00
|
|
|
Aircraft *p = appData->aircraftList.head;
|
2019-09-09 06:23:38 +02:00
|
|
|
time_t now = time(NULL);
|
2019-09-09 08:17:40 +02:00
|
|
|
SDL_Color planeColor;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-02-18 08:17:19 +01:00
|
|
|
// draw all trails first so they don't cover up planes and text
|
|
|
|
// also find closest plane to selection point
|
2019-09-09 06:23:38 +02:00
|
|
|
while(p) {
|
2020-03-13 00:56:26 +01:00
|
|
|
drawTrail(p);
|
2019-09-09 08:17:40 +02:00
|
|
|
p = p->next;
|
|
|
|
}
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(selectedAircraft) {
|
|
|
|
mapTargetLon = selectedAircraft->lon;
|
|
|
|
mapTargetLat = selectedAircraft->lat;
|
2020-02-18 08:17:19 +01:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
p = appData->aircraftList.head;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2019-09-09 08:17:40 +02:00
|
|
|
while(p) {
|
2020-03-08 05:28:55 +01:00
|
|
|
if (p->lon && p->lat) {
|
|
|
|
int x, y;
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-08 05:28:55 +01:00
|
|
|
float dx, dy;
|
|
|
|
pxFromLonLat(&dx, &dy, p->lon, p->lat);
|
|
|
|
screenCoords(&x, &y, dx, dy);
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-08 05:28:55 +01:00
|
|
|
if(p->created == 0) {
|
|
|
|
p->created = mstime();
|
|
|
|
}
|
2019-09-09 06:23:38 +02:00
|
|
|
|
2020-03-08 05:28:55 +01:00
|
|
|
float age_ms = (float)(mstime() - p->created);
|
|
|
|
if(age_ms < 500) {
|
2020-03-19 06:22:59 +01:00
|
|
|
circleRGBA(renderer, x, y, 500 - age_ms, 255,255, 255, (uint8_t)(255.0 * age_ms / 500.0));
|
2020-03-08 05:28:55 +01:00
|
|
|
} else {
|
|
|
|
if(MODES_ACFLAGS_HEADING_VALID) {
|
|
|
|
int usex = x;
|
|
|
|
int usey = y;
|
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
if(p->seenLatLon > p->timestampHistory.back()) {
|
2020-03-08 05:28:55 +01:00
|
|
|
int oldx, oldy;
|
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
pxFromLonLat(&dx, &dy, p->lonHistory.back(), p->latHistory.back());
|
2020-03-08 05:28:55 +01:00
|
|
|
screenCoords(&oldx, &oldy, dx, dy);
|
|
|
|
|
2020-03-13 00:56:26 +01:00
|
|
|
float velx = (x - oldx) / (1000.0 * (p->seenLatLon - p->timestampHistory.back()));
|
|
|
|
float vely = (y - oldy) / (1000.0 * (p->seenLatLon - p->timestampHistory.back()));
|
2019-09-16 02:54:06 +02:00
|
|
|
|
2020-03-08 05:28:55 +01:00
|
|
|
usex = x + (mstime() - p->msSeenLatLon) * velx;
|
|
|
|
usey = y + (mstime() - p->msSeenLatLon) * vely;
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p == selectedAircraft) {
|
2020-03-08 05:28:55 +01:00
|
|
|
// this logic should be in input, register a callback for click?
|
2020-03-19 06:22:59 +01:00
|
|
|
float elapsed = mstime() - clickTime;
|
2020-03-08 05:28:55 +01:00
|
|
|
|
|
|
|
int boxSize;
|
|
|
|
if(elapsed < 300) {
|
|
|
|
boxSize = (int)(20.0 * (1.0 - (1.0 - elapsed / 300.0) * cos(sqrt(elapsed))));
|
2019-09-16 02:54:06 +02:00
|
|
|
} else {
|
2020-03-08 05:28:55 +01:00
|
|
|
boxSize = 20;
|
2020-02-18 07:47:42 +01:00
|
|
|
}
|
2020-03-19 06:22:59 +01:00
|
|
|
//rectangleRGBA(renderer, usex - boxSize, usey - boxSize, usex + boxSize, usey + boxSize, pink.r, pink.g, pink.b, 255);
|
|
|
|
lineRGBA(renderer, usex - boxSize, usey - boxSize, usex - boxSize/2, usey - boxSize, pink.r, pink.g, pink.b, 255);
|
|
|
|
lineRGBA(renderer, usex - boxSize, usey - boxSize, usex - boxSize, usey - boxSize/2, pink.r, pink.g, pink.b, 255);
|
2020-03-08 05:28:55 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
lineRGBA(renderer, usex + boxSize, usey - boxSize, usex + boxSize/2, usey - boxSize, pink.r, pink.g, pink.b, 255);
|
|
|
|
lineRGBA(renderer, usex + boxSize, usey - boxSize, usex + boxSize, usey - boxSize/2, pink.r, pink.g, pink.b, 255);
|
2020-03-08 05:28:55 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
lineRGBA(renderer, usex + boxSize, usey + boxSize, usex + boxSize/2, usey + boxSize, pink.r, pink.g, pink.b, 255);
|
|
|
|
lineRGBA(renderer, usex + boxSize, usey + boxSize, usex + boxSize, usey + boxSize/2, pink.r, pink.g, pink.b, 255);
|
2020-03-08 05:28:55 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
lineRGBA(renderer, usex - boxSize, usey + boxSize, usex - boxSize/2, usey + boxSize, pink.r, pink.g, pink.b, 255);
|
|
|
|
lineRGBA(renderer, usex - boxSize, usey + boxSize, usex - boxSize, usey + boxSize/2, pink.r, pink.g, pink.b, 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
planeColor = lerpColor(style.planeColor, style.planeGoneColor, (now - p->seen) / (float) DISPLAY_ACTIVE);
|
|
|
|
|
2020-03-08 05:28:55 +01:00
|
|
|
if(outOfBounds(x,y)) {
|
|
|
|
drawPlaneOffMap(x, y, &(p->cx), &(p->cy), planeColor);
|
|
|
|
} else {
|
|
|
|
drawPlaneIcon(usex, usey, p->track, planeColor);
|
|
|
|
p->cx = usex;
|
|
|
|
p->cy = usey;
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(p != selectedAircraft) {
|
2020-03-08 05:28:55 +01:00
|
|
|
drawPlaneText(p);
|
|
|
|
}
|
|
|
|
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p = p->next;
|
|
|
|
}
|
2020-02-17 06:54:46 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
drawSelectedAircraftText(selectedAircraft);
|
2019-09-09 06:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::animateCenterAbsolute(float x, float y) {
|
2020-03-19 06:22:59 +01:00
|
|
|
float scale_factor = (screen_width > screen_height) ? screen_width : screen_height;
|
2020-03-07 00:44:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float dx = -1.0 * (0.75*(double)screen_width / (double)screen_height) * (x - screen_width/2) * maxDist / (0.95 * scale_factor * 0.5);
|
|
|
|
float dy = 1.0 * (y - screen_height/2) * maxDist / (0.95 * scale_factor * 0.5);
|
2020-03-07 00:44:45 +01:00
|
|
|
|
|
|
|
float outLat = dy * (1.0/6371.0) * (180.0f / M_PI);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float outLon = dx * (1.0/6371.0) * (180.0f / M_PI) / cos(((centerLat)/2.0f) * M_PI / 180.0f);
|
2020-03-07 00:44:45 +01:00
|
|
|
|
|
|
|
//double outLon, outLat;
|
|
|
|
//latLonFromScreenCoords(&outLat, &outLon, event.tfinger.dx, event.tfinger.dy);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapTargetLon = centerLon - outLon;
|
|
|
|
mapTargetLat = centerLat - outLat;
|
2020-03-07 00:44:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapTargetMaxDist = 0.25 * maxDist;
|
2020-03-07 00:44:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapMoved = 1;
|
2020-03-07 00:44:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::moveCenterAbsolute(float x, float y) {
|
2020-03-19 06:22:59 +01:00
|
|
|
float scale_factor = (screen_width > screen_height) ? screen_width : screen_height;
|
2020-03-07 00:44:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float dx = -1.0 * (0.75*(double)screen_width / (double)screen_height) * (x - screen_width/2) * maxDist / (0.95 * scale_factor * 0.5);
|
|
|
|
float dy = 1.0 * (y - screen_height/2) * maxDist / (0.95 * scale_factor * 0.5);
|
2020-03-07 00:44:45 +01:00
|
|
|
|
|
|
|
float outLat = dy * (1.0/6371.0) * (180.0f / M_PI);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float outLon = dx * (1.0/6371.0) * (180.0f / M_PI) / cos(((centerLat)/2.0f) * M_PI / 180.0f);
|
2020-03-07 00:44:45 +01:00
|
|
|
|
|
|
|
//double outLon, outLat;
|
|
|
|
//latLonFromScreenCoords(&outLat, &outLon, event.tfinger.dx, event.tfinger.dy);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
centerLon += outLon;
|
|
|
|
centerLat += outLat;
|
2020-03-07 00:44:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapTargetLon = 0;
|
|
|
|
mapTargetLat = 0;
|
2020-03-07 00:44:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapMoved = 1;
|
2020-03-07 00:44:45 +01:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::moveCenterRelative(float dx, float dy) {
|
2020-03-06 00:02:40 +01:00
|
|
|
//
|
|
|
|
// need to make lonlat to screen conversion class - this is just the inverse of the stuff in draw.c, without offsets
|
|
|
|
//
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float scale_factor = (screen_width > screen_height) ? screen_width : screen_height;
|
2020-03-06 00:02:40 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
dx = -1.0 * (0.75*(double)screen_width / (double)screen_height) * dx * maxDist / (0.95 * scale_factor * 0.5);
|
|
|
|
dy = 1.0 * dy * maxDist / (0.95 * scale_factor * 0.5);
|
2020-03-06 00:02:40 +01:00
|
|
|
|
2020-03-07 00:44:45 +01:00
|
|
|
float outLat = dy * (1.0/6371.0) * (180.0f / M_PI);
|
2020-03-06 00:02:40 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
float outLon = dx * (1.0/6371.0) * (180.0f / M_PI) / cos(((centerLat)/2.0f) * M_PI / 180.0f);
|
2020-03-06 00:02:40 +01:00
|
|
|
|
|
|
|
//double outLon, outLat;
|
|
|
|
//latLonFromScreenCoords(&outLat, &outLon, event.tfinger.dx, event.tfinger.dy);
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
centerLon += outLon;
|
|
|
|
centerLat += outLat;
|
2020-03-06 00:02:40 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapTargetLon = 0;
|
|
|
|
mapTargetLat = 0;
|
2020-03-07 00:44:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapMoved = 1;
|
2020-03-06 00:02:40 +01:00
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::zoomMapToTarget() {
|
2020-03-19 06:22:59 +01:00
|
|
|
if(mapTargetMaxDist) {
|
|
|
|
if(fabs(mapTargetMaxDist - maxDist) > 0.0001) {
|
|
|
|
maxDist += 0.1 * (mapTargetMaxDist - maxDist);
|
2020-03-07 00:44:45 +01:00
|
|
|
} else {
|
2020-03-19 06:22:59 +01:00
|
|
|
mapTargetMaxDist = 0;
|
2020-03-07 00:44:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::moveMapToTarget() {
|
2020-03-19 06:22:59 +01:00
|
|
|
if(mapTargetLon && mapTargetLat) {
|
|
|
|
if(fabs(mapTargetLon - centerLon) > 0.0001 || fabs(mapTargetLat - centerLat) > 0.0001) {
|
|
|
|
centerLon += 0.1 * (mapTargetLon- centerLon);
|
|
|
|
centerLat += 0.1 * (mapTargetLat - centerLat);
|
2020-03-07 00:44:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapMoved = 1;
|
2020-03-07 00:44:45 +01:00
|
|
|
} else {
|
2020-03-19 06:22:59 +01:00
|
|
|
mapTargetLon = 0;
|
|
|
|
mapTargetLat = 0;
|
2020-03-07 00:44:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::drawMouse() {
|
2020-03-19 06:22:59 +01:00
|
|
|
if(mouseMovedTime == 0 || (mstime() - mouseMovedTime) > 1000) {
|
|
|
|
mouseMovedTime = 0;
|
2020-03-06 00:02:40 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
int alpha = (int)(255.0f - 255.0f * (float)(mstime() - mouseMovedTime) / 1000.0f);
|
2020-03-06 00:02:40 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
lineRGBA(renderer, mousex - 10 * screen_uiscale, mousey, mousex + 10 * screen_uiscale, mousey, white.r, white.g, white.b, alpha);
|
|
|
|
lineRGBA(renderer, mousex, mousey - 10 * screen_uiscale, mousex, mousey + 10 * screen_uiscale, white.r, white.g, white.b, alpha);
|
2020-03-06 00:02:40 +01:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
void View::drawClick() {
|
|
|
|
if(clickx && clicky) {
|
|
|
|
|
|
|
|
int radius = .25 * (mstime() - clickTime);
|
|
|
|
int alpha = 128 - (int)(0.5 * (mstime() - clickTime));
|
|
|
|
if(alpha < 0 ) {
|
|
|
|
alpha = 0;
|
|
|
|
clickx = 0;
|
|
|
|
clicky = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
filledCircleRGBA(renderer, clickx, clicky, radius, white.r, white.g, white.b, alpha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void View::registerClick(int tapcount, int x, int y) {
|
|
|
|
if(tapcount == 1) {
|
|
|
|
Aircraft *p = appData->aircraftList.head;
|
2020-03-08 02:22:20 +01:00
|
|
|
Aircraft *selection = NULL;
|
2020-03-07 00:44:45 +01:00
|
|
|
|
|
|
|
while(p) {
|
2020-03-19 06:22:59 +01:00
|
|
|
if(x && y) {
|
|
|
|
if((p->cx - x) * (p->cx - x) + (p->cy - y) * (p->cy - y) < 900) {
|
2020-03-07 00:44:45 +01:00
|
|
|
if(selection) {
|
2020-03-19 06:22:59 +01:00
|
|
|
if((p->cx - x) * (p->cx - x) + (p->cy - y) * (p->cy - y) <
|
|
|
|
(selection->cx - x) * (selection->cx - x) + (selection->cy - y) * (selection->cy - y)) {
|
2020-03-07 00:44:45 +01:00
|
|
|
selection = p;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
selection = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = p->next;
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
selectedAircraft = selection;
|
|
|
|
} else if(tapcount == 2) {
|
|
|
|
mapTargetMaxDist = 0.25 * maxDist;
|
|
|
|
animateCenterAbsolute(x, y);
|
2020-03-07 00:44:45 +01:00
|
|
|
}
|
2020-03-19 06:22:59 +01:00
|
|
|
|
|
|
|
clickx = x;
|
|
|
|
clicky = y;
|
|
|
|
clickTime = mstime();
|
|
|
|
}
|
|
|
|
|
|
|
|
void View::registerMouseMove(int x, int y) {
|
|
|
|
lastFrameTime = mstime();
|
|
|
|
|
|
|
|
this->mousex = x;
|
|
|
|
this->mousey = y;
|
2020-03-07 00:44:45 +01:00
|
|
|
}
|
|
|
|
|
2019-09-09 06:23:38 +02:00
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
void View::draw() {
|
2020-02-18 07:19:45 +01:00
|
|
|
uint64_t drawStartTime = mstime();
|
|
|
|
|
2020-03-07 00:44:45 +01:00
|
|
|
moveMapToTarget();
|
|
|
|
zoomMapToTarget();
|
|
|
|
|
2020-03-08 02:22:20 +01:00
|
|
|
//updatePlanes();
|
2019-09-08 01:11:20 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
if(mapMoved) {
|
|
|
|
SDL_SetRenderTarget(renderer, mapTexture);
|
2020-02-19 00:37:41 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
SDL_SetRenderDrawColor(renderer, style.backgroundColor.r, style.backgroundColor.g, style.backgroundColor.b, 255);
|
2020-03-07 05:51:47 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
SDL_RenderClear(renderer);
|
2020-03-03 07:44:32 +01:00
|
|
|
|
2020-02-18 07:19:45 +01:00
|
|
|
drawGeography();
|
2020-02-19 00:37:41 +01:00
|
|
|
|
2020-02-18 07:19:45 +01:00
|
|
|
drawScaleBars();
|
2017-09-14 05:21:36 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
SDL_SetRenderTarget(renderer, NULL );
|
2017-10-06 05:25:30 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
mapMoved = 0;
|
2020-02-18 07:19:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = 0; i < 4; i++) {
|
|
|
|
resolveLabelConflicts();
|
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
//SDL_SetRenderDrawColor( renderer, 0, 15, 30, 0);
|
|
|
|
SDL_SetRenderDrawColor(renderer, style.backgroundColor.r, style.backgroundColor.g, style.backgroundColor.b, 255);
|
2019-09-08 01:11:20 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
SDL_RenderClear(renderer);
|
2017-09-14 05:21:36 +02:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
SDL_RenderCopy(renderer, mapTexture, NULL, NULL);
|
2020-02-18 07:19:45 +01:00
|
|
|
|
|
|
|
drawPlanes();
|
2019-09-08 21:29:21 +02:00
|
|
|
drawStatus();
|
2020-03-06 00:02:40 +01:00
|
|
|
drawMouse();
|
|
|
|
|
2020-03-02 07:58:10 +01:00
|
|
|
char fps[13] = " ";
|
2020-03-19 06:22:59 +01:00
|
|
|
snprintf(fps,13," %.1ffps", 1000.0 / (mstime() - lastFrameTime));
|
|
|
|
drawStringBG(fps, 0,0, mapFont, grey, black);
|
2020-02-18 07:19:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
SDL_RenderPresent(renderer);
|
2020-02-18 07:19:45 +01:00
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
lastFrameTime = mstime();
|
2020-02-18 07:19:45 +01:00
|
|
|
|
|
|
|
if ((mstime() - drawStartTime) < FRAMETIME) {
|
|
|
|
usleep(1000 * (FRAMETIME - (mstime() - drawStartTime)));
|
|
|
|
}
|
2020-03-08 02:22:20 +01:00
|
|
|
}
|
|
|
|
|
2020-03-19 06:22:59 +01:00
|
|
|
View::View(AppData *appData){
|
|
|
|
this->appData = appData;
|
|
|
|
|
|
|
|
// Display options
|
|
|
|
screen_uiscale = 1;
|
|
|
|
screen_width = 0;
|
|
|
|
screen_height = 0;
|
|
|
|
screen_depth = 32;
|
|
|
|
fullscreen = 0;
|
|
|
|
screen_index = 0;
|
|
|
|
|
|
|
|
maxDist = 25.0;
|
|
|
|
|
|
|
|
selectedAircraft = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
View::~View() {
|
|
|
|
closeFont(mapFont);
|
|
|
|
closeFont(mapBoldFont);
|
|
|
|
closeFont(messageFont);
|
|
|
|
closeFont(labelFont);
|
|
|
|
closeFont(listFont);
|
|
|
|
|
|
|
|
TTF_Quit();
|
|
|
|
SDL_Quit();
|
2017-10-05 16:58:23 +02:00
|
|
|
}
|