I am developping a program for UAV groundstation; it displays google earth tiles on screen and allows to scroll. The tiles are 640x 640 for a 1200 x 640 screen I did the first round of programming, and it is working, but: from time to time (every 20 - 30 renderings) there is a glitch, where the tiles are put on screen with an incorrect x offset (can be + 5 … +50 pixels or something similar). I traced (using cout the values passed for forming rectangle, and there are no programming errors, i.e. the rectange data is always correct, but in 2-4 % of rendings, the x is off… I suspected that it had to do with my management of graphic tiles in memory, so I switched to simply drawing rectangles (SDL_renderdrawrect), but the problem persisted…
When I put a delay (SDL_delay) after rendering, for values above 6 mS the intermittent offset diasppears…
I am pretty new to SDL, but I am at total loss where to look for problem…
I am running it on RPI Debian
// ---------------------------
int render_tile (char* file_nm, int srx, int sry, int srw, int srh, int dsx, int dsy, int dsw, int dsh)
{
int cur_mem_ndx;
char shortname[20];
char filename[128];
SDL_Rect SrcR;
SDL_Rect DestR;
SrcR.x = srx;
SrcR.y = sry;
SrcR.w = srw;
SrcR.h = srh;
dsy=0;
cout << dsx << " " << dsw << " \n";
dsh=640;
DestR.x = dsx;
DestR.y = dsy;
DestR.w = dsw;
DestR.h = dsh;
if (strcmp(file_nm,“EMPTY”)==0) { // if EMPTY, there is no image (on disk or in memory, so draw empty rectange
SDL_SetRenderDrawColor(renderer, 215, 125, 255, 123);
SDL_RenderDrawRect(renderer,&DestR);
return 1;
}
/*
cout << “Srcr.x:” << SrcR.x << “\n”;
cout << “Srcr.y:” << SrcR.y << “\n”;
cout << “Srcr.w:” << SrcR.w << “\n”;
cout << “Srcr.h:” << SrcR.h << “\n”;
cout << “Drcr.x:” << DestR.x << “\n”;
cout << “Drcr.y:” << DestR.y << “\n”;
cout << “Drcr.w:” << DestR.w << “\n”;
cout << “Drcr.h:” << DestR.h << “\n”;
cout << " ============= \n" ;*/
/*
cout << “Mem Tiles:\n”;
for (int i=0;i<mem_tiles_end;i++)
{cout << i << " kk " << mem_tiles_fname[i] << “\n”;}
cout << “mem_tiles_end:” << mem_tiles_end <<"\n";
*/
int ndx=0;
sprintf (shortname,"%s",file_nm);
while ((ndx<mem_tiles_end) and (!strcmp(mem_tiles_fname[ndx],shortname))==0) { ndx=ndx+1; }
if (ndx<mem_tiles_end)
{ // we found the correct file name!! ndx points to array
// cout << SrcR.x << " " << SrcR.w << " " << DestR.x << " " << DestR.w << “\n”;
// SDL_RenderCopy(renderer, mem_tiles[ndx], &SrcR, &DestR);
SDL_SetRenderDrawColor(renderer, 215, 225, 155, 123);
DestR.x = dsx+2;
DestR.y = dsy+2;
DestR.w = dsw-2;
DestR.h = dsh-2;
SDL_RenderDrawRect(renderer,&DestR);
}
else
{ // the file was not found in memory, so should be fetched from disk:
sprintf (filename,"/home/pi/Earth/%s",file_nm); // obtain path to file
SDL_Surface * image = IMG_Load(filename); // load image from file
if(!image) {
printf("IMG_Load: %s\n", IMG_GetError());
return 2; // this error really should not be happing, only if someone manually deleted
// files in the Earth folder
// I am not sure what should be done in this case
}
mem_tiles[mem_tiles_end]=SDL_CreateTextureFromSurface(renderer, image);
SDL_FreeSurface(image);
strcpy (mem_tiles_fname[mem_tiles_end],shortname);
cur_mem_ndx=mem_tiles_end;
if (mem_tiles_end<max_mem_tiles) {mem_tiles_end=mem_tiles_end+1;}
else
{ // overflow, delete first item to make room !!!
}
// SDL_RenderCopy(renderer, mem_tiles[cur_mem_ndx], &SrcR, &DestR);
SDL_SetRenderDrawColor(renderer, 115, 125, 155, 123);
DestR.x = dsx+2;
DestR.y = dsy+2;
DestR.w = dsw-4;
DestR.h = dsh-4;
SDL_RenderDrawRect(renderer,&DestR);
}
SDL_RenderPresent(renderer); // copy to screen
SDL_Delay (6); // NOT SURE WHY, BUT WITHOUT IT, THERE IS AN OCCASIONAL GLITCH
return 0;
}
int show_Earth (double yfrom, double xfrom, int screen_zoom)
{
FILE *fp;
char filename[128];
char url[256];
int db_res;
char buf[512];
char *zErrMsg = 0;
double Lat;
// if (yfrom<0) {Lat=yfrom;} else {Lat=yto;} // We need Latitude closest to equater, because the scale is largest there
Lat=yfrom;
// cout << “STARTING…\n”;
int zoomlevel = screen_zoom;
double Meters_per_pixel=156543.03392cos(Lat0.017453293)/(1 << zoomlevel);
double Latitude_1_degree=111.13295-0.55982cos(2Lat0.017453293)+0.00117cos(4Lat0.017453293); // in km
double Longitude_1_degree=111.41288cos(Lat0.017453293)-0.0935cos(3Lat0.017453293)+0.00012cos(5Lat0.017453293); // in km
double Screen_width_degrees=((NAV_window_xMeters_per_pixel)/Longitude_1_degree)/1000;
double Screen_height_degrees=((NAV_window_yMeters_per_pixel)/Latitude_1_degree)/1000;
double dx=Screen_width_degrees;
double dy=Screen_height_degrees;
double xto=xfrom+Screen_width_degrees;
double yto=yfrom+Screen_height_degrees;
double Tile_Size_X=(Meters_per_pixelGoogle_Tile_Size_X)/1000; // physical X dimension of a tile in km
double Tile_Size_Y=(Meters_per_pixelGoogle_Tile_Size_Y)/1000; // physical X dimension of a tile in km
double Tile_Side_X=Tile_Size_X/Longitude_1_degree; // in degrees
double Tile_Side_Y=Tile_Size_Y/Latitude_1_degree; // in degrees
double Tile_Side_X_Half=Tile_Side_X/2;
double Tile_Side_Y_Half=Tile_Side_Y/2;
int Tile_Side_Destination_X=abs ((Tile_Side_X/dx))*NAV_window_x; // !!!
int Tile_Side_Destination_Y=Tile_Side_Destination_X; // abs (Tile_Side_X/dx)*1200;
int wx=0;
int wy=0;
// Check if any tile in offline corresponds to left-upper corner:
sprintf (buf,“SELECT * FROM TILES WHERE ZOOMLEVEL = %d AND X_FROM<= %2.6f AND X_TO>= %2.6f AND Y_FROM>= %2.6f AND Y_TO<= %2.6f;”,zoomlevel,xfrom,xfrom,yfrom,yfrom);
sqlite_ndx=0;
db_res = sqlite3_exec(db, buf,get_tile, 0, &zErrMsg); // tile(s) data are in the arrays _a
if( db_res != SQLITE_OK ) {
fprintf(stderr, “SQL error: %s\n”, zErrMsg);
sqlite3_free(zErrMsg);
}
if (sqlite_ndx==0) {return 0;}
// if NOT, repeat search for UPPER RIGHT CORNER, adjust values below !!!
// if NOT, repeat search for LOWER LEFT CORNER
// ELSE: increase group id and create a new set of tiles
// ERROR: there is vertical error in images; it seems that a few lines are cut out
int ndx=0;
// cout << “FILE:” << file_a[ndx] << “\n”;
int tsx = int((abs(xfrom_a[ndx]-xfrom))/abs(xfrom_a[ndx]-xto_a[ndx])*Google_Tile_Size_X);
// cout << xfrom_a[ndx]-xfrom << " - ";
int tsy = int((abs(yfrom_a[ndx]-yfrom))/abs(yfrom_a[ndx]-yto_a[ndx])*Google_Tile_Size_Y);
int tsw = Google_Tile_Size_X-tsx;
int tsh = Google_Tile_Size_Y-tsy;
int grp_id=grpid_a[ndx];
// cout << tsx << " hhhhhhh " << tsw << “\n”;
render_tile (file_a[ndx],tsx,tsy,tsw,tsh,0,0,tsw,tsh); // first tile
return 0;
int tsx_st=tsx; // source x
int tsy_st=tsy; // source y
int tsw_st=tsw; // source width
int tsh_st=tsh; // source height
double scr_x_remain=NAV_window_x-tsw;
int tile_x_need=ceil(scr_x_remain/Google_Tile_Size_X); // how many tiles are needed to complete screen
double scr_y_remain=NAV_window_y-tsh;
int tile_y_need=ceil(scr_y_remain/Google_Tile_Size_Y);
double xstep=abs(xfrom_a[ndx]-xto_a[ndx]); // in degrees
double ystep=abs(yfrom_a[ndx]-yto_a[ndx]);
double xcenter=xfrom_a[ndx]+xstep/2;
double ycenter=yfrom_a[ndx]-ystep/2;
int grpx=grpx_a[ndx];
int grpy=grpy_a[ndx];
int x_ndx=grpx+1;
int y_ndx=grpy;
// cout << temp-tsx << " v\n";temp=tsx;
while (y_ndx<= grpy+tile_y_need) {
while (x_ndx<=grpx+tile_x_need) {
sqlite_ndx=0;
sprintf (buf,“SELECT * FROM TILES WHERE ZOOMLEVEL = %d AND GROUP_ID=%d AND GROUP_X=%d AND GROUP_Y=%d;”,zoomlevel,grp_id,x_ndx,y_ndx);
db_res = sqlite3_exec(db, buf,get_tile, 0, &zErrMsg); // tile(s) data are in the arrays _a
int xoff=x_ndx-grpx; // xoff,yoff = tile index ,1 tile = 1
int yoff=y_ndx-grpy;
if (xoff==0) {tsx=tsx_st;tsw=tsw_st;wx=0;} else {tsx=0;tsw=Google_Tile_Size_X;wx=tsw_st+Google_Tile_Size_X*(xoff-1);}
if (yoff==0) {tsy=tsy_st;tsh=tsh_st;wy=0;} else {tsy=0;tsh=Google_Tile_Size_Y;wy=tsh_st+Google_Tile_Size_Y*(yoff-1);}
if (sqlite_ndx>0) { // there is a tile in memory!!!
render_tile (file_a[ndx],tsx,tsy,tsw,tsh,wx,wy,tsw,tsh);
if ((y_ndx==grpy) and (x_ndx==grpx)) {cout << temp-tsx << " v\n";temp=tsx; }
}
else
{ // no tile in memory, must download!!}
get_next_id ();
get_google_tile (next_id, group_id, x_ndx,y_ndx,zoomlevel,Google_Tile_Size_X,Google_Tile_Size_Y,Meters_per_pixel,xcenter+xstep*xoff,ycenter-ystep*yoff,xstep,ystep);
sqlite_ndx=0;
sprintf (buf,"SELECT * FROM TILES WHERE ZOOMLEVEL = %d AND GROUP_ID=%d AND GROUP_X=%d AND GROUP_Y=%d;",zoomlevel,grp_id,x_ndx,y_ndx);
db_res = sqlite3_exec(db, buf,get_tile, 0, &zErrMsg); // tile(s) data are in the arrays _a
if (sqlite_ndx>0) { // there is a tile in memory!!!
render_tile (file_a[ndx],tsx,tsy,tsw,tsh,wx,wy,tsw,tsh); }
else
{ sprintf (buf,"%s","EMPTY");
render_tile (buf,tsx,tsy,tsw,tsh,wx,wy,tsw,tsh); }
}
x_ndx=x_ndx+1;
}
x_ndx=grpx;
y_ndx=y_ndx+1;
}
return 0;
}
// --------------------------------------------------------------