2020-06-19 05:03:38 +02:00
// 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.
//
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"
2020-06-10 20:28:52 +02:00
2019-09-09 06:23:38 +02:00
//color schemes
# include "parula.h"
2017-09-14 05:21:36 +02:00
2020-03-08 02:22:20 +01:00
# include "View.h"
2020-06-12 06:55:04 +02:00
# include <iostream>
2020-06-13 05:32:42 +02:00
# include <thread>
2020-06-12 06:55:04 +02:00
2020-06-15 00:26:26 +02:00
using fmilliseconds = std : : chrono : : duration < float , std : : milli > ;
using fseconds = std : : chrono : : duration < float > ;
2020-06-12 06:55:04 +02:00
2020-06-15 00:26:26 +02:00
static std : : chrono : : high_resolution_clock : : time_point now ( ) {
return std : : chrono : : high_resolution_clock : : now ( ) ;
2020-06-12 06:55:04 +02:00
}
2020-06-15 00:26:26 +02:00
static float elapsed ( std : : chrono : : high_resolution_clock : : time_point ref ) {
2020-06-27 05:40:03 +02:00
return ( fmilliseconds { now ( ) - ref } ) . count ( ) ;
2020-06-12 06:55:04 +02:00
}
2020-06-15 00:26:26 +02:00
static float elapsed_s ( std : : chrono : : high_resolution_clock : : time_point ref ) {
2020-06-27 05:40:03 +02:00
return ( fseconds { now ( ) - ref } ) . count ( ) ;
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 ;
2020-06-10 20:28:52 +02:00
if ( s < = 0.0 ) {
2019-09-22 03:46:52 +02:00
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 ;
2020-06-14 05:54:21 +02:00
// return round(0.95 * scale_factor * 0.5 * fabs(d) / maxDist);
return round ( 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-06-14 05:54:21 +02:00
// for accurate reprojection use the extra cos term
* dx = LATLONMULT * ( lon - centerLon ) * cos ( ( ( lat + centerLat ) / 2.0f ) * M_PI / 180.0f ) ;
* dy = LATLONMULT * ( lat - centerLat ) ;
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-06-18 07:01:18 +02:00
return outOfBounds ( x , y , 0 , 0 , screen_width , screen_height ) ;
}
int View : : outOfBounds ( int x , int y , int left , int top , int right , int bottom ) {
if ( x < left | | x > = right | | y < top | | y > = bottom ) {
2019-09-09 06:23:38 +02:00
return 1 ;
} else {
return 0 ;
}
}
2020-03-19 06:22:59 +01:00
//
// Font stuff
//
2020-06-17 00:03:05 +02:00
TTF_Font * View : : loadFont ( const char * name , int size )
2020-03-19 06:22:59 +01:00
{
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 ;
}
2020-06-11 09:11:52 +02:00
window = SDL_CreateWindow ( " viz1090 " , SDL_WINDOWPOS_CENTERED_DISPLAY ( screen_index ) , SDL_WINDOWPOS_CENTERED_DISPLAY ( screen_index ) , screen_width , screen_height , flags ) ;
2020-06-13 05:32:42 +02:00
renderer = SDL_CreateRenderer ( window , - 1 , SDL_RENDERER_ACCELERATED ) ;
2020-03-19 06:22:59 +01:00
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 ;
}
2020-06-17 00:03:05 +02:00
void View : : drawString ( std : : string text , int x , int y , TTF_Font * font , SDL_Color color )
2020-03-19 06:22:59 +01:00
{
2020-06-17 00:03:05 +02:00
if ( ! text . length ( ) ) {
2020-03-19 06:22:59 +01:00
return ;
}
SDL_Surface * surface ;
SDL_Rect dest ;
2020-06-17 00:03:05 +02:00
surface = TTF_RenderUTF8_Solid ( font , text . c_str ( ) , color ) ;
2020-03-19 06:22:59 +01:00
if ( surface = = NULL )
{
2020-06-17 00:03:05 +02:00
printf ( " Couldn't create String %s: %s \n " , text . c_str ( ) , SDL_GetError ( ) ) ;
2020-03-19 06:22:59 +01:00
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 ) ;
}
2020-06-17 00:03:05 +02:00
void View : : drawStringBG ( std : : string text , int x , int y , TTF_Font * font , SDL_Color color , SDL_Color bgColor ) {
if ( ! text . length ( ) ) {
2020-03-19 06:22:59 +01:00
return ;
}
SDL_Surface * surface ;
SDL_Rect dest ;
2020-06-17 00:03:05 +02:00
surface = TTF_RenderUTF8_Shaded ( font , text . c_str ( ) , color , bgColor ) ;
2020-03-19 06:22:59 +01:00
if ( surface = = NULL )
{
2020-06-17 00:03:05 +02:00
printf ( " Couldn't create String %s: %s \n " , text . c_str ( ) , SDL_GetError ( ) ) ;
2020-03-19 06:22:59 +01:00
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 ) ;
}
//
// Status boxes
//
2020-06-17 00:03:05 +02:00
void View : : drawStatusBox ( int * left , int * top , std : : string label , std : : string message , SDL_Color color ) {
int labelWidth = ( label . length ( ) + ( ( label . length ( ) > 0 ) ? 1 : 0 ) ) * labelFontWidth ;
int messageWidth = ( message . length ( ) + ( ( message . length ( ) > 0 ) ? 1 : 0 ) ) * messageFontWidth ;
2020-03-19 06:22:59 +01:00
if ( * left + labelWidth + messageWidth + PAD > screen_width ) {
* left = PAD ;
* top = * top - messageFontHeight - PAD ;
}
// filled black background
if ( messageWidth ) {
2020-06-23 07:21:47 +02:00
roundedBoxRGBA ( renderer , * left , * top , * left + labelWidth + messageWidth , * top + messageFontHeight , ROUND_RADIUS , style . buttonBackground . r , style . buttonBackground . g , style . buttonBackground . b , SDL_ALPHA_OPAQUE ) ;
2020-03-19 06:22:59 +01:00
}
// 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 ) ;
}
2020-06-23 07:21:47 +02:00
drawString ( label , * left + labelFontWidth / 2 , * top , labelFont , style . buttonBackground ) ;
2020-03-19 06:22:59 +01:00
//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 ] = " " ;
2020-03-19 06:38:00 +01:00
snprintf ( strPlaneCount , 10 , " %d/%d " , appData - > numVisiblePlanes , appData - > numPlanes ) ;
2020-03-19 06:22:59 +01:00
drawStatusBox ( & left , & top , " disp " , strPlaneCount , style . buttonColor ) ;
char strMsgRate [ 18 ] = " " ;
2020-03-19 06:38:00 +01:00
snprintf ( strMsgRate , 18 , " %.0f/s " , appData - > msgRate ) ;
2020-03-19 06:22:59 +01:00
drawStatusBox ( & left , & top , " rate " , strMsgRate , style . buttonColor ) ;
char strSig [ 18 ] = " " ;
2020-03-19 06:38:00 +01:00
snprintf ( strSig , 18 , " %.0f%% " , 100.0 * appData - > avgSig / 1024.0 ) ;
2020-03-19 06:22:59 +01:00
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 ] ;
2020-06-27 05:40:03 +02:00
trigonRGBA ( 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 ] ;
2020-06-27 05:40:03 +02:00
trigonRGBA ( 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 ;
2020-06-27 05:40:03 +02:00
float wingThick = 0.35 ;
2020-03-19 06:22:59 +01:00
float tail = 3.0 * screen_uiscale ;
2020-06-27 05:40:03 +02:00
float tailThick = 0.5 ;
float bodyWidth = 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
2020-06-27 05:40:03 +02:00
x1 = x + round ( - bodyWidth * out [ 0 ] ) ;
y1 = y + round ( - bodyWidth * out [ 1 ] ) ;
x2 = x + round ( bodyWidth * out [ 0 ] ) ;
y2 = y + round ( bodyWidth * out [ 1 ] ) ;
2019-09-09 06:23:38 +02:00
2020-06-27 05:40:03 +02:00
trigonRGBA ( renderer , x1 , y1 , x2 , y2 , x + round ( - body * vec [ 0 ] ) , y + round ( - body * vec [ 1 ] ) , planeColor . r , planeColor . g , planeColor . b , SDL_ALPHA_OPAQUE ) ;
trigonRGBA ( renderer , x1 , y1 , x2 , y2 , x + round ( body * vec [ 0 ] ) , y + round ( body * vec [ 1 ] ) , planeColor . r , planeColor . g , planeColor . b , SDL_ALPHA_OPAQUE ) ;
// x1 = x + round(-body*vec[0] - bodyWidth*out[0]);
// y1 = y + round(-body*vec[1] - bodyWidth*out[1]);
// x2 = x + round(body*vec[0] - bodyWidth*out[0]);
// y2 = y + round(body*vec[1] - bodyWidth*out[1]);
// lineRGBA(renderer,x,y,x2,y2,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
// x1 = x + round(-body*vec[0] + bodyWidth*out[0]);
// y1 = y + round(-body*vec[1] + bodyWidth*out[1]);
// x2 = x + round(body*vec[0] + bodyWidth*out[0]);
// y2 = y + round(body*vec[1] + bodyWidth*out[1]);
// lineRGBA(renderer,x,y,x2,y2,planeColor.r,planeColor.g,planeColor.b,SDL_ALPHA_OPAQUE);
//trigonRGBA(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);
// circleRGBA(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-06-27 05:40:03 +02:00
trigonRGBA ( renderer , x1 , y1 , x2 , y2 , x + round ( body * wingThick * vec [ 0 ] ) , y + round ( body * wingThick * vec [ 1 ] ) , planeColor . r , planeColor . g , planeColor . b , SDL_ALPHA_OPAQUE ) ;
2019-09-09 06:23:38 +02:00
//tail
2020-06-27 05:40:03 +02:00
x1 = x + round ( - body * .75 * vec [ 0 ] - tail * out [ 0 ] ) ;
y1 = y + round ( - body * .75 * vec [ 1 ] - tail * out [ 1 ] ) ;
x2 = x + round ( - body * .75 * vec [ 0 ] + tail * out [ 0 ] ) ;
y2 = y + round ( - body * .75 * vec [ 1 ] + tail * out [ 1 ] ) ;
2019-09-09 06:23:38 +02:00
2020-06-27 05:40:03 +02:00
trigonRGBA ( renderer , x1 , y1 , x2 , y2 , x + round ( - body * tailThick * vec [ 0 ] ) , y + round ( - body * tailThick * vec [ 1 ] ) , planeColor . r , planeColor . g , planeColor . b , SDL_ALPHA_OPAQUE ) ;
2019-09-09 06:23:38 +02:00
}
2020-06-18 07:01:18 +02:00
void View : : drawTrails ( int left , int top , int right , int bottom ) {
2019-09-09 06:23:38 +02:00
int currentX , currentY , prevX , prevY ;
2020-06-15 00:26:26 +02:00
float dx , dy ;
2019-09-09 06:23:38 +02:00
2020-06-18 07:01:18 +02:00
Aircraft * p = appData - > aircraftList . head ;
2019-09-09 06:23:38 +02:00
2020-06-18 07:01:18 +02:00
while ( p ) {
if ( p - > lon & & p - > lat ) {
if ( p - > lonHistory . empty ( ) ) {
return ;
}
2019-09-09 06:23:38 +02:00
2020-06-27 05:40:03 +02:00
SDL_Color color = lerpColor ( style . trailColor , style . planeGoneColor , float ( elapsed_s ( p - > msSeen ) ) / ( float ) DISPLAY_ACTIVE ) ;
if ( p = = selectedAircraft ) {
color = style . selectedColor ;
}
2020-06-18 07:01:18 +02:00
std : : vector < float > : : iterator lon_idx = p - > lonHistory . begin ( ) ;
std : : vector < float > : : iterator lat_idx = p - > latHistory . begin ( ) ;
std : : vector < float > : : iterator heading_idx = p - > headingHistory . begin ( ) ;
2020-02-19 00:37:41 +01:00
2020-06-23 07:21:47 +02:00
float age = 0 ;
2019-09-09 06:23:38 +02:00
2020-06-23 07:21:47 +02:00
for ( ; std : : next ( lon_idx ) ! = p - > lonHistory . end ( ) ; + + lon_idx , + + lat_idx , + + heading_idx , age + = 1.0 ) {
2019-09-09 06:23:38 +02:00
2020-06-18 07:01:18 +02:00
pxFromLonLat ( & dx , & dy , * ( std : : next ( lon_idx ) ) , * ( std : : next ( lat_idx ) ) ) ;
screenCoords ( & currentX , & currentY , dx , dy ) ;
2019-09-09 06:23:38 +02:00
2020-06-18 07:01:18 +02:00
pxFromLonLat ( & dx , & dy , * lon_idx , * lat_idx ) ;
2019-09-09 06:23:38 +02:00
2020-06-18 07:01:18 +02:00
screenCoords ( & prevX , & prevY , dx , dy ) ;
if ( outOfBounds ( currentX , currentY , left , top , right , bottom ) & & outOfBounds ( prevX , prevY , left , top , right , bottom ) ) {
continue ;
}
2019-09-09 06:23:38 +02:00
2020-06-27 05:40:03 +02:00
uint8_t colorVal = ( uint8_t ) floor ( 127.0 * ( age / ( float ) p - > lonHistory . size ( ) ) ) ;
2020-06-18 07:01:18 +02:00
2020-06-23 07:21:47 +02:00
//thickLineRGBA(renderer, prevX, prevY, currentX, currentY, 2 * screen_uiscale, 255, 255, 255, colorVal);
2020-06-27 05:40:03 +02:00
lineRGBA ( renderer , prevX , prevY , currentX , currentY , color . r , color . g , color . b , colorVal ) ;
2020-03-13 00:56:26 +01:00
2020-06-18 07:01:18 +02:00
}
}
p = p - > next ;
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-06-18 07:01:18 +02:00
void View : : drawLines ( int left , int top , int right , int bottom , int bailTime ) {
float screen_lat_min , screen_lat_max , screen_lon_min , screen_lon_max ;
latLonFromScreenCoords ( & screen_lat_min , & screen_lon_min , left , top ) ;
latLonFromScreenCoords ( & screen_lat_max , & screen_lon_max , right , bottom ) ;
2020-06-23 07:21:47 +02:00
drawLinesRecursive ( & ( map . root ) , screen_lat_min , screen_lat_max , screen_lon_min , screen_lon_max , style . geoColor ) ;
2020-06-21 06:44:30 +02:00
2020-06-23 07:21:47 +02:00
drawLinesRecursive ( & ( map . airport_root ) , screen_lat_min , screen_lat_max , screen_lon_min , screen_lon_max , style . airportColor ) ;
2020-06-18 07:01:18 +02:00
drawTrails ( left , top , right , bottom ) ;
}
2020-06-21 06:44:30 +02:00
void View : : drawLinesRecursive ( QuadTree * tree , float screen_lat_min , float screen_lat_max , float screen_lon_min , float screen_lon_max , SDL_Color color ) {
2020-06-27 05:40:03 +02:00
2020-06-14 07:15:47 +02:00
if ( tree = = NULL ) {
return ;
}
if ( tree - > lat_min > screen_lat_max | | screen_lat_min > tree - > lat_max ) {
return ;
}
if ( tree - > lon_min > screen_lon_max | | screen_lon_min > tree - > lon_max ) {
return ;
}
2020-06-21 06:44:30 +02:00
drawLinesRecursive ( tree - > nw , screen_lat_min , screen_lat_max , screen_lon_min , screen_lon_max , color ) ;
2020-06-14 07:15:47 +02:00
2020-06-21 06:44:30 +02:00
drawLinesRecursive ( tree - > sw , screen_lat_min , screen_lat_max , screen_lon_min , screen_lon_max , color ) ;
2020-06-14 07:15:47 +02:00
2020-06-21 06:44:30 +02:00
drawLinesRecursive ( tree - > ne , screen_lat_min , screen_lat_max , screen_lon_min , screen_lon_max , color ) ;
2020-06-14 07:15:47 +02:00
2020-06-21 06:44:30 +02:00
drawLinesRecursive ( tree - > se , screen_lat_min , screen_lat_max , screen_lon_min , screen_lon_max , color ) ;
2020-06-14 07:15:47 +02:00
std : : vector < Line * > : : iterator currentLine ;
for ( currentLine = tree - > lines . begin ( ) ; currentLine ! = tree - > lines . end ( ) ; + + currentLine ) {
int x1 , y1 , x2 , y2 ;
float dx , dy ;
pxFromLonLat ( & dx , & dy , ( * currentLine ) - > start . lon , ( * currentLine ) - > start . lat ) ;
screenCoords ( & x1 , & y1 , dx , dy ) ;
pxFromLonLat ( & dx , & dy , ( * currentLine ) - > end . lon , ( * currentLine ) - > end . lat ) ;
screenCoords ( & x2 , & y2 , dx , dy ) ;
lineCount + + ;
if ( outOfBounds ( x1 , y1 ) & & outOfBounds ( x2 , y2 ) ) {
continue ;
}
if ( x1 = = x2 & & y1 = = y2 ) {
continue ;
}
2020-06-21 06:44:30 +02:00
lineRGBA ( renderer , x1 , y1 , x2 , y2 , color . r , color . g , color . b , 255 ) ;
2020-06-14 07:15:47 +02:00
}
2020-06-19 04:29:45 +02:00
// //Debug quadtree
// int tl_x,tl_y,tr_x,tr_y,bl_x,bl_y,br_x,br_y;
// float dx,dy;
2020-06-18 08:42:39 +02:00
2020-06-19 04:29:45 +02:00
// pxFromLonLat(&dx, &dy, tree->lon_min, tree->lat_min);
// screenCoords(&tl_x, &tl_y, dx, dy);
2020-06-18 08:42:39 +02:00
2020-06-19 04:29:45 +02:00
// pxFromLonLat(&dx, &dy, tree->lon_max, tree->lat_min);
// screenCoords(&tr_x, &tr_y, dx, dy);
2020-06-18 08:42:39 +02:00
2020-06-19 04:29:45 +02:00
// pxFromLonLat(&dx, &dy, tree->lon_min, tree->lat_max);
// screenCoords(&bl_x, &bl_y, dx, dy);
2020-06-18 08:42:39 +02:00
2020-06-19 04:29:45 +02:00
// pxFromLonLat(&dx, &dy, tree->lon_max, tree->lat_max);
// screenCoords(&br_x, &br_y, dx, dy);
2020-06-18 08:42:39 +02:00
2020-06-19 04:29:45 +02:00
// lineRGBA(renderer, tl_x, tl_y, tr_x, tr_y, 50, 50, 50, 255);
// lineRGBA(renderer, tr_x, tr_y, br_x, br_y, 50, 50, 50, 255);
// lineRGBA(renderer, bl_x, bl_y, br_x, br_y, 50, 50, 50, 255);
// lineRGBA(renderer, tl_x, tl_y, bl_x, bl_y, 50, 50, 50, 255);
// // pixelRGBA(renderer,tl_x, tl_y,255,0,0,255);
// pixelRGBA(renderer,tr_x, tr_y,0,255,0,255);
// pixelRGBA(renderer,bl_x, bl_y,0,0,255,255);
// pixelRGBA(renderer,br_x, br_y,255,255,0,255);
2020-06-14 07:15:47 +02:00
}
2020-06-20 07:04:57 +02:00
void View : : drawPlaceNames ( ) {
for ( std : : vector < Label * > : : iterator label = map . mapnames . begin ( ) ; label ! = map . mapnames . end ( ) ; + + label ) {
float dx , dy ;
int x , y ;
pxFromLonLat ( & dx , & dy , ( * label ) - > location . lon , ( * label ) - > location . lat ) ;
screenCoords ( & x , & y , dx , dy ) ;
if ( outOfBounds ( x , y ) ) {
continue ;
}
2020-06-23 07:21:47 +02:00
drawString ( ( * label ) - > text , x , y , mapFont , style . geoColor ) ;
2020-06-20 07:04:57 +02:00
}
2020-06-21 06:44:30 +02:00
for ( std : : vector < Label * > : : iterator label = map . airportnames . begin ( ) ; label ! = map . airportnames . end ( ) ; + + label ) {
float dx , dy ;
int x , y ;
pxFromLonLat ( & dx , & dy , ( * label ) - > location . lon , ( * label ) - > location . lat ) ;
screenCoords ( & x , & y , dx , dy ) ;
if ( outOfBounds ( x , y ) ) {
continue ;
}
2020-06-23 07:21:47 +02:00
drawString ( ( * label ) - > text , x , y , listFont , style . airportColor ) ;
2020-06-21 06:44:30 +02:00
}
2020-06-20 07:04:57 +02:00
}
2020-01-20 07:22:58 +01:00
2020-06-18 07:01:18 +02:00
void View : : drawGeography ( ) {
2020-01-22 08:24:29 +01:00
2020-06-20 07:04:57 +02:00
if ( ( mapRedraw & & ! mapMoved ) | | ( mapAnimating & & elapsed ( lastRedraw ) > 8 * FRAMETIME ) | | elapsed ( lastRedraw ) > 2000 ) {
2020-01-20 07:22:58 +01:00
2020-06-18 07:01:18 +02:00
SDL_SetRenderTarget ( renderer , mapTexture ) ;
SDL_SetRenderDrawColor ( renderer , style . backgroundColor . r , style . backgroundColor . g , style . backgroundColor . b , 255 ) ;
2020-01-20 07:22:58 +01:00
2020-06-18 07:01:18 +02:00
SDL_RenderClear ( renderer ) ;
drawLines ( 0 , 0 , screen_width , screen_height , 0 ) ;
2020-06-20 07:04:57 +02:00
drawPlaceNames ( ) ;
2020-06-14 05:54:21 +02:00
2020-06-18 07:01:18 +02:00
SDL_SetRenderTarget ( renderer , NULL ) ;
2020-01-20 07:22:58 +01:00
2020-06-18 07:01:18 +02:00
mapMoved = 0 ;
mapRedraw = 0 ;
mapAnimating = 0 ;
2020-06-14 05:54:21 +02:00
2020-06-18 07:01:18 +02:00
lastRedraw = now ( ) ;
currentLon = centerLon ;
currentLat = centerLat ;
currentMaxDist = maxDist ;
2020-01-20 07:22:58 +01:00
}
2020-06-18 07:01:18 +02:00
2020-03-19 06:22:59 +01:00
2020-01-20 07:22:58 +01:00
2020-06-18 07:01:18 +02:00
SDL_SetRenderDrawColor ( renderer , style . backgroundColor . r , style . backgroundColor . g , style . backgroundColor . b , 255 ) ;
2020-01-20 07:22:58 +01:00
2020-06-18 07:01:18 +02:00
SDL_RenderClear ( renderer ) ;
2020-01-20 07:22:58 +01:00
2020-06-18 07:01:18 +02:00
int shiftx = 0 ;
int shifty = 0 ;
if ( mapMoved ) {
float dx , dy ;
int x1 , y1 , x2 , y2 ;
pxFromLonLat ( & dx , & dy , currentLon , currentLat ) ;
screenCoords ( & x1 , & y1 , dx , dy ) ;
pxFromLonLat ( & dx , & dy , centerLon , centerLat ) ;
screenCoords ( & x2 , & y2 , dx , dy ) ;
shiftx = x1 - x2 ;
shifty = y1 - y2 ;
SDL_Rect dest ;
dest . x = shiftx + ( screen_width / 2 ) * ( 1 - currentMaxDist / maxDist ) ;
dest . y = shifty + ( screen_height / 2 ) * ( 1 - currentMaxDist / maxDist ) ;
dest . w = screen_width * currentMaxDist / maxDist ;
dest . h = screen_height * currentMaxDist / maxDist ;
//left
if ( dest . x > 0 ) {
drawLines ( 0 , 0 , dest . x , screen_height , FRAMETIME / 4 ) ;
}
//top
if ( dest . y > 0 ) {
drawLines ( 0 , screen_height - dest . y , screen_width , screen_height , FRAMETIME / 4 ) ;
}
//right
if ( dest . x + dest . w < screen_width ) {
drawLines ( dest . x + dest . w , 0 , screen_width , screen_height , FRAMETIME / 4 ) ;
}
//bottom
if ( dest . y + dest . h < screen_height ) {
drawLines ( 0 , 0 , screen_width , screen_height - dest . y - dest . h , FRAMETIME / 4 ) ;
}
//attempt rest before bailing
//drawGeography(dest.x, screen_height - dest.y, dest.x + dest.w, screen_height - dest.y - dest.h, 1);
SDL_RenderCopy ( renderer , mapTexture , NULL , & dest ) ;
2020-06-14 05:54:21 +02:00
2020-06-18 07:01:18 +02:00
mapRedraw = 1 ;
mapMoved = 0 ;
} else {
SDL_RenderCopy ( renderer , mapTexture , NULL , NULL ) ;
}
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 ) ;
2020-06-14 07:15:47 +02:00
Uint8 seenFade ;
2019-09-16 02:54:06 +02:00
2020-06-14 07:15:47 +02:00
if ( elapsed ( p - > msSeen ) < 1024 ) {
seenFade = ( Uint8 ) ( 255.0 - elapsed ( p - > msSeen ) / 4.0 ) ;
2019-09-16 02:54:06 +02:00
2020-06-14 07:15:47 +02:00
circleRGBA ( renderer , x + mapFontWidth , y - 5 , 2 * screen_uiscale , barColor . r , barColor . g , barColor . b , seenFade ) ;
}
2020-06-15 00:26:26 +02:00
2020-06-14 07:15:47 +02:00
if ( elapsed ( p - > msSeenLatLon ) < 1024 ) {
seenFade = ( Uint8 ) ( 255.0 - elapsed ( p - > msSeenLatLon ) / 4.0 ) ;
2019-09-16 02:54:06 +02:00
2020-06-14 07:15:47 +02: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-06-15 00:39:02 +02:00
float pressure_scale = 2.0f ; //this should be set by a UI slider eventually
2020-06-15 00:26:26 +02:00
if ( p - > pressure * screen_width < pressure_scale ) {
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-06-23 07:21:47 +02:00
drawStringBG ( flight , p - > x , p - > y , mapBoldFont , style . labelColor , style . labelBackground ) ;
2020-03-19 06:22:59 +01:00
//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-06-15 00:26:26 +02:00
if ( p - > pressure * screen_width < 0.5f * pressure_scale ) {
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-06-23 07:21:47 +02:00
drawStringBG ( alt , p - > x , p - > y + currentLine * mapFontHeight , mapFont , style . subLabelColor , style . labelBackground ) ;
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-06-23 07:21:47 +02:00
drawStringBG ( speed , p - > x , p - > y + currentLine * mapFontHeight , mapFont , style . subLabelColor , style . labelBackground ) ;
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
2020-06-17 00:03:05 +02:00
Sint16 vx [ 4 ] = {
static_cast < Sint16 > ( p - > cx ) ,
static_cast < Sint16 > ( p - > cx + ( p - > x - p - > cx ) / 2 ) ,
static_cast < Sint16 > ( p - > x ) ,
static_cast < Sint16 > ( p - > x ) } ;
Sint16 vy [ 4 ] = {
static_cast < Sint16 > ( p - > cy ) ,
static_cast < Sint16 > ( p - > cy + ( p - > y - p - > cy ) / 2 ) ,
static_cast < Sint16 > ( p - > y - mapFontHeight ) ,
static_cast < Sint16 > ( 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-06-23 07:21:47 +02:00
bezierRGBA ( renderer , vx , vy , 4 , 2 , style . labelLineColor . r , style . labelLineColor . g , style . labelLineColor . b , SDL_ALPHA_OPAQUE ) ;
2019-09-22 03:46:52 +02:00
2020-06-27 05:40:03 +02:00
lineRGBA ( renderer , p - > x , p - > y , p - > x , p - > y + currentLine * mapFontHeight , style . labelLineColor . r , style . labelLineColor . g , style . labelLineColor . b , 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 ;
2020-06-15 00:26:26 +02:00
if ( elapsed ( p - > msSeenLatLon ) < 500 ) {
circleRGBA ( renderer , p - > cx , p - > cy , elapsed ( p - > msSeenLatLon ) * screen_width / ( 8192 ) , 255 , 255 , 255 , 64 - ( uint8_t ) ( 64.0 * elapsed ( p - > msSeenLatLon ) / 500.0 ) ) ;
}
2020-02-18 07:47:42 +01:00
drawSignalMarks ( p , x , y ) ;
char flight [ 10 ] = " " ;
maxCharCount = snprintf ( flight , 10 , " %s " , p - > flight ) ;
if ( maxCharCount > 1 ) {
2020-06-23 07:21:47 +02:00
drawStringBG ( flight , x , y , mapBoldFont , style . labelColor , style . labelBackground ) ;
2020-03-19 06:22:59 +01:00
//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-06-23 07:21:47 +02:00
drawStringBG ( alt , x , y + currentLine * mapFontHeight , mapFont , style . subLabelColor , style . labelBackground ) ;
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-06-23 07:21:47 +02:00
drawStringBG ( speed , x , y + currentLine * mapFontHeight , mapFont , style . subLabelColor , style . labelBackground ) ;
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
2020-03-21 06:08:40 +01:00
float label_force = 0.01f ;
float plane_force = 0.01f ;
float damping_force = 0.95f ;
float spring_force = 0.02f ;
float spring_length = 10.0f ;
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);
2020-03-21 06:08:40 +01:00
p - > ddox = 0 ;
p - > ddoy = 0 ;
2019-09-16 02:54:06 +02:00
2020-03-21 06:08:40 +01:00
float o_mag = sqrt ( p - > ox * p - > ox + p - > oy * p - > oy ) ;
2019-09-16 02:54:06 +02:00
//spring back to origin
2020-03-21 06:08:40 +01:00
if ( o_mag > 0 ) {
p - > ddox - = p - > ox / o_mag * spring_force * ( o_mag - spring_length ) ;
p - > ddoy - = p - > oy / o_mag * spring_force * ( o_mag - spring_length ) ;
}
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 ) {
2020-03-21 06:08:40 +01:00
check_p - > ddox - = label_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-03-21 06:08:40 +01:00
check_p - > ddox - = label_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-03-21 06:08:40 +01:00
check_p - > ddoy - = label_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-03-21 06:08:40 +01:00
check_p - > ddoy - = label_force * ( float ) ( check_bottom - p_top ) ;
2019-09-22 03:46:52 +02:00
}
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-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 ) {
p - > dox + = p - > ddox ;
p - > doy + = p - > ddoy ;
2020-03-21 06:08:40 +01:00
p - > dox * = damping_force ;
p - > doy * = damping_force ;
2019-09-16 02:54:06 +02:00
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 ;
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 08:17:40 +02:00
SDL_Color planeColor ;
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 ) {
2020-06-21 06:44:30 +02:00
// if lon lat argments were not provided, start by snapping to the first plane we see
if ( centerLon = = 0 & & centerLat = = 0 ) {
mapTargetLon = p - > lon ;
mapTargetLat = p - > lat ;
}
2020-03-08 05:28:55 +01:00
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-06-15 00:26:26 +02:00
float age_ms = elapsed ( p - > created ) ;
2020-03-08 05:28:55 +01:00
if ( age_ms < 500 ) {
2020-06-15 00:39:02 +02:00
float ratio = age_ms / 500.0f ;
float radius = ( 1.0f - ratio * ratio ) * screen_width / 8 ;
for ( float theta = 0 ; theta < 2 * M_PI ; theta + = M_PI / 4 ) {
pixelRGBA ( renderer , x + radius * cos ( theta ) , y + radius * sin ( theta ) , style . planeColor . r , style . planeColor . g , style . planeColor . b , 255 * ratio ) ;
}
// 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-06-15 00:26:26 +02:00
//draw predicted position
// if(p->timestampHistory.size() > 2) {
2020-03-08 05:28:55 +01:00
2020-06-15 00:26:26 +02:00
// int x1, y1, x2, y2;
2019-09-16 02:54:06 +02:00
2020-06-15 00:26:26 +02:00
// pxFromLonLat(&dx, &dy, p->lonHistory.end()[-1], p->latHistory.end()[-1]);
// screenCoords(&x1, &y1, dx, dy);
2020-03-19 06:22:59 +01:00
2020-06-15 00:26:26 +02:00
// pxFromLonLat(&dx, &dy, p->lonHistory.end()[-2], p->latHistory.end()[-2]);
// screenCoords(&x2, &y2, dx, dy);
// //printf("latlon: [%f %f] -> [%f %f], px: [%d %d] -> [%d %d]\n",p->lonHistory.end()[-1], p->latHistory.end()[-1],p->lonHistory.end()[-2], p->latHistory.end()[-2], x1,y1,x2,y2);
// float velx = float(x1 - x2) / (fmilliseconds{p->timestampHistory.end()[-1] - p->timestampHistory.end()[-2]}).count();
// float vely = float(y1 - y2) / (fmilliseconds{p->timestampHistory.end()[-1] - p->timestampHistory.end()[-2]}).count();
// //printf("diff: %f\n",(fmilliseconds{p->timestampHistory.end()[-1] - p->timestampHistory.end()[-2]}).count());
// //printf("%f %f, %d - %d \n", velx,vely,p->timestampHistory.end()[-1], p->timestampHistory.end()[-2]);
// usex = x + float(elapsed(p->msSeenLatLon)) * velx;
// usey = y + float(elapsed(p->msSeenLatLon)) * vely;
// }
planeColor = lerpColor ( style . planeColor , style . planeGoneColor , float ( elapsed_s ( p - > msSeen ) ) / ( float ) DISPLAY_ACTIVE ) ;
2020-03-19 06:22:59 +01:00
2020-03-22 04:30:23 +01:00
if ( p = = selectedAircraft ) {
planeColor = style . selectedColor ;
}
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 ) ;
2020-06-21 06:44:30 +02:00
p - > x + = usex - p - > cx ;
p - > y + = usey - p - > cy ;
2020-03-08 05:28:55 +01:00
p - > cx = usex ;
p - > cy = usey ;
}
2020-03-19 06:22:59 +01:00
if ( p ! = selectedAircraft ) {
2020-06-16 23:40:03 +02:00
//show latlon ping
if ( elapsed ( p - > msSeenLatLon ) < 500 ) {
circleRGBA ( renderer , p - > cx , p - > cy , elapsed ( p - > msSeenLatLon ) * screen_width / ( 8192 ) , 127 , 127 , 127 , 255 - ( uint8_t ) ( 255.0 * elapsed ( p - > msSeenLatLon ) / 500.0 ) ) ;
}
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-06-12 06:55:04 +02:00
dx = - 1.0 * 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-06-16 23:40:03 +02:00
mapAnimating = 1 ;
mapMoved = 1 ;
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-06-16 23:40:03 +02:00
mapAnimating = 1 ;
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-06-23 07:21:47 +02:00
// void View::drawMouse() {
// if(!mouseMoved) {
// return;
// }
2020-06-15 00:26:26 +02:00
2020-06-23 07:21:47 +02:00
// if(elapsed(mouseMovedTime) > 1000) {
// mouseMoved = false;
// return;
// }
2020-03-06 00:02:40 +01:00
2020-06-23 07:21:47 +02:00
// int alpha = (int)(255.0f - 255.0f * (float)elapsed(mouseMovedTime) / 1000.0f);
2020-03-06 00:02:40 +01:00
2020-06-23 07:21:47 +02: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 ) {
2020-06-12 06:55:04 +02:00
int radius = .25 * elapsed ( clickTime ) ;
int alpha = 128 - ( int ) ( 0.5 * elapsed ( clickTime ) ) ;
2020-03-19 06:22:59 +01:00
if ( alpha < 0 ) {
alpha = 0 ;
clickx = 0 ;
clicky = 0 ;
}
2020-06-23 07:21:47 +02:00
filledCircleRGBA ( renderer , clickx , clicky , radius , style . clickColor . r , style . clickColor . g , style . clickColor . b , alpha ) ;
2020-03-19 06:22:59 +01:00
}
2020-03-22 04:30:23 +01:00
if ( selectedAircraft ) {
// this logic should be in input, register a callback for click?
int boxSize ;
2020-06-12 06:55:04 +02:00
if ( elapsed ( clickTime ) < 300 ) {
boxSize = ( int ) ( 20.0 * ( 1.0 - ( 1.0 - float ( elapsed ( clickTime ) ) / 300.0 ) * cos ( sqrt ( float ( elapsed ( clickTime ) ) ) ) ) ) ;
2020-03-22 04:30:23 +01:00
} else {
boxSize = 20 ;
}
//rectangleRGBA(renderer, selectedAircraft->cx - boxSize, selectedAircraft->cy - boxSize, selectedAircraft->cx + boxSize, selectedAircraft->cy + boxSize, style.selectedColor.r, style.selectedColor.g, style.selectedColor.b, 255);
lineRGBA ( renderer , selectedAircraft - > cx - boxSize , selectedAircraft - > cy - boxSize , selectedAircraft - > cx - boxSize / 2 , selectedAircraft - > cy - boxSize , style . selectedColor . r , style . selectedColor . g , style . selectedColor . b , 255 ) ;
lineRGBA ( renderer , selectedAircraft - > cx - boxSize , selectedAircraft - > cy - boxSize , selectedAircraft - > cx - boxSize , selectedAircraft - > cy - boxSize / 2 , style . selectedColor . r , style . selectedColor . g , style . selectedColor . b , 255 ) ;
lineRGBA ( renderer , selectedAircraft - > cx + boxSize , selectedAircraft - > cy - boxSize , selectedAircraft - > cx + boxSize / 2 , selectedAircraft - > cy - boxSize , style . selectedColor . r , style . selectedColor . g , style . selectedColor . b , 255 ) ;
lineRGBA ( renderer , selectedAircraft - > cx + boxSize , selectedAircraft - > cy - boxSize , selectedAircraft - > cx + boxSize , selectedAircraft - > cy - boxSize / 2 , style . selectedColor . r , style . selectedColor . g , style . selectedColor . b , 255 ) ;
lineRGBA ( renderer , selectedAircraft - > cx + boxSize , selectedAircraft - > cy + boxSize , selectedAircraft - > cx + boxSize / 2 , selectedAircraft - > cy + boxSize , style . selectedColor . r , style . selectedColor . g , style . selectedColor . b , 255 ) ;
lineRGBA ( renderer , selectedAircraft - > cx + boxSize , selectedAircraft - > cy + boxSize , selectedAircraft - > cx + boxSize , selectedAircraft - > cy + boxSize / 2 , style . selectedColor . r , style . selectedColor . g , style . selectedColor . b , 255 ) ;
lineRGBA ( renderer , selectedAircraft - > cx - boxSize , selectedAircraft - > cy + boxSize , selectedAircraft - > cx - boxSize / 2 , selectedAircraft - > cy + boxSize , style . selectedColor . r , style . selectedColor . g , style . selectedColor . b , 255 ) ;
2020-06-23 07:21:47 +02:00
lineRGBA ( renderer , selectedAircraft - > cx - boxSize , selectedAircraft - > cy + boxSize , selectedAircraft - > cx - boxSize , selectedAircraft - > cy + boxSize / 2 , style . selectedColor . r , style . selectedColor . g , style . selectedColor . b , 255 ) ;
2020-03-22 04:30:23 +01:00
}
2020-03-19 06:22:59 +01:00
}
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 ;
2020-06-12 06:55:04 +02:00
clickTime = now ( ) ;
2020-03-19 06:22:59 +01:00
}
void View : : registerMouseMove ( int x , int y ) {
2020-06-15 00:26:26 +02:00
mouseMoved = true ;
2020-06-12 06:55:04 +02:00
mouseMovedTime = now ( ) ;
2020-03-19 06:22:59 +01:00
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-06-13 05:32:42 +02:00
drawStartTime = now ( ) ;
2020-06-27 05:40:03 +02:00
2020-03-07 00:44:45 +01:00
moveMapToTarget ( ) ;
zoomMapToTarget ( ) ;
2020-06-23 07:21:47 +02:00
for ( int i = 0 ; i < 8 ; i + + ) {
2020-02-18 07:19:45 +01:00
resolveLabelConflicts ( ) ;
}
2020-06-18 07:01:18 +02:00
lineCount = 0 ;
2020-06-13 05:32:42 +02:00
2020-06-18 07:01:18 +02:00
drawGeography ( ) ;
2020-06-13 05:32:42 +02:00
drawScaleBars ( ) ;
2020-02-18 07:19:45 +01:00
drawPlanes ( ) ;
2019-09-08 21:29:21 +02:00
drawStatus ( ) ;
2020-06-18 07:01:18 +02:00
//drawMouse();
2020-03-22 04:30:23 +01:00
drawClick ( ) ;
2020-03-06 00:02:40 +01:00
2020-06-27 05:40:03 +02:00
//char fps[60] = " ";
//snprintf(fps,40," %d lines @ %.1ffps", lineCount, 1000.0 / elapsed(lastFrameTime));
//drawStringBG(fps, 0,0, mapFont, style.subLabelColor, style.backgroundColor);
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-06-13 05:32:42 +02:00
if ( elapsed ( drawStartTime ) < FRAMETIME ) {
2020-06-15 00:26:26 +02:00
std : : this_thread : : sleep_for ( fmilliseconds { FRAMETIME } - ( now ( ) - drawStartTime ) ) ;
2020-02-18 07:19:45 +01:00
}
2020-06-12 06:55:04 +02:00
2020-06-13 05:32:42 +02:00
lastFrameTime = now ( ) ;
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 ;
2020-06-21 06:44:30 +02:00
centerLon = 0 ;
centerLat = 0 ;
2020-03-19 06:22:59 +01:00
maxDist = 25.0 ;
2020-06-13 05:32:42 +02:00
mapMoved = 1 ;
mapRedraw = 1 ;
2020-03-19 06:22:59 +01:00
selectedAircraft = NULL ;
}
View : : ~ View ( ) {
closeFont ( mapFont ) ;
closeFont ( mapBoldFont ) ;
closeFont ( messageFont ) ;
closeFont ( labelFont ) ;
closeFont ( listFont ) ;
TTF_Quit ( ) ;
SDL_Quit ( ) ;
2020-06-12 06:55:04 +02:00
}