From 2d99b0b433f81ba49b6ab361a877c286dbe5371b Mon Sep 17 00:00:00 2001 From: curt Date: Tue, 3 Dec 2002 15:40:32 +0000 Subject: [PATCH] Initial revision. --- utils/TerraSync/Makefile.am | 5 + utils/TerraSync/README.txt | 62 ++++++++ utils/TerraSync/terrasync.cxx | 276 ++++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 utils/TerraSync/Makefile.am create mode 100644 utils/TerraSync/README.txt create mode 100644 utils/TerraSync/terrasync.cxx diff --git a/utils/TerraSync/Makefile.am b/utils/TerraSync/Makefile.am new file mode 100644 index 000000000..41702c003 --- /dev/null +++ b/utils/TerraSync/Makefile.am @@ -0,0 +1,5 @@ +bin_PROGRAMS = terrasync + +terrasync_SOURCES = terrasync.cxx + +terrasync_LDADD = -lplibnet -lplibul diff --git a/utils/TerraSync/README.txt b/utils/TerraSync/README.txt new file mode 100644 index 000000000..c71b48b2d --- /dev/null +++ b/utils/TerraSync/README.txt @@ -0,0 +1,62 @@ +TerraSync +========= + +Usage: + + terrasync -p [ -s ] -d + +Example: + + $ fgfs --atlas=socket,out,1,localhost,5500,udp --fg-scenery=/data1/Scenery-0.7.9 + $ nice terrasync -p 5500 -d /data1/Scenery-0.7.9 + +Requirements: + + - rsync util installed in your path. + - mkdir util installed in your path. + +TerraSync is a utility that is intended to run as a light weight +background process. It's purpose is to monitor the position of a +FlightGear flight and pre-fetch scenery tiles from a remote server +based on the current FlightGear position. + +This allows you to do a base install of FlightGear with no add on +scenery. Now just go and fly anywhere. Scenery is fetched "just in +time" and accumulated on your HD so it is already there next time you +fly. You can fly anywhere and essentially just the scenery you need +is auto-installed as you fly. + +Terrasync runs as a separate process and expects the --atlas=port +format to be sent from fgfs. The fgfs output tells the terrasync util +where FlightGear is currently flying. Terrasync will then issue the +appropriate commands to rsync the surrounding areas to your local +scenery directory. The user need to choose a port for +FlightGear->TerraSync communication and then specify the server +location and destation scenery tree. + +As you fly, terrasync will periodically refresh and pull any new +scenery tiles that you need for your position from the server. + +This also works if the scenery on the scenery server is updated. +Rsync will pull any missing files, or any updated files. + +There is a chicken/egg problem when you first start up in a brand new +area. FlightGear is expecting the scenery to be there *now* but it +may not have been fetched yet. I suppose without making a more +complex protocol, the user will need to be aware of this. The user +could restart flightgear after the initial rsync completes, and then +after that everything should be good, assuming the flight track is +"continuous" and the user has the necessary bandwidth to keep up with +flight speeds. + +Final notes: + +I have set up an initial scenery server at +baron.flightgear.org::Scenery-0.7.9. This is the 0.7.9 vintage +scenery with airports rebuilt to include lighting. Alex Perry also +has a partial rsync server, but I don't know it's current status. +William Riley has rebuilt the entire world, but the tiles are zipped +in 10x10 degree chunks on on a relatively low bandwidth connection. +There are aspects of the 0.7.9 scenery I like including the quality of +the terrain, but William scenery has roads and streams which is also +nice. diff --git a/utils/TerraSync/terrasync.cxx b/utils/TerraSync/terrasync.cxx new file mode 100644 index 000000000..eb5fb148c --- /dev/null +++ b/utils/TerraSync/terrasync.cxx @@ -0,0 +1,276 @@ +// terrasync.cxx -- "JIT" scenery fetcher +// +// Written by Curtis Olson, started November 2002. +// +// Copyright (C) 2002 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + + +#include // atoi() atof() abs() system() + +#include + +#include STL_IOSTREAM +#include STL_STRING + +#include +#include + +#include + +SG_USING_STD(string); +SG_USING_STD(cout); +SG_USING_STD(endl); + + +static string server = "baron.flightgear.org"; +static string source_module = "Scenery-0.7.9"; +static string source_base = server + (string)"::" + source_module; +static string dest_base = "/dest/scenery/dir"; + + +// display usage +static void usage( const string& prog ) { + cout << "Usage: " << prog + << " -p [ -s ] -d " << endl; +} + + +// parse message +static void parse_message( const string &msg, int *lat, int *lon ) { + double dlat, dlon; + string text = msg; + + // find GGA string and advance to start of lat + string::size_type pos = text.find( "$GPGGA" ); + string tmp = text.substr( pos + 7 ); + pos = text.find( "," ); + tmp = tmp.substr( pos + 1 ); + // cout << "-> " << tmp << endl; + + // find lat then advance to start of hemisphere + pos = tmp.find( "," ); + string lats = tmp.substr( 0, pos ); + dlat = atof( lats.c_str() ) / 100.0; + tmp = tmp.substr( pos + 1 ); + + // find N/S hemisphere and advance to start of lon + if ( tmp.substr( 0, 1 ) == "S" ) { + dlat = -dlat; + } + pos = tmp.find( "," ); + tmp = tmp.substr( pos + 1 ); + + // find lon + pos = tmp.find( "," ); + string lons = tmp.substr( 0, pos ); + dlon = atof( lons.c_str() ) / 100.0; + tmp = tmp.substr( pos + 1 ); + + // find E/W hemisphere and advance to start of lon + if ( tmp.substr( 0, 1 ) == "W" ) { + dlon = -dlon; + } + + if ( dlat < 0 ) { + *lat = (int)dlat - 1; + } else { + *lat = (int)dlat; + } + + if ( dlon < 0 ) { + *lon = (int)dlon - 1; + } else { + *lon = (int)dlon; + } +} + + +// sync area +static void sync_area( int lat, int lon ) { + char NS, EW; + int baselat, baselon; + + if ( lat < 0 ) { + int base = (int)(lat / 10); + if ( lat == base * 10 ) { + baselat = base * 10; + } else { + baselat = (base - 1) * 10; + } + NS = 's'; + } else { + baselat = (int)(lat / 10) * 10; + NS = 'n'; + } + if ( lon < 0 ) { + int base = (int)(lon / 10); + if ( lon == base * 10 ) { + baselon = base * 10; + } else { + baselon = (base - 1) * 10; + } + EW = 'w'; + } else { + baselon = (int)(lon / 10) * 10; + EW = 'e'; + } + + char command[512]; + + // make container directory + char container_dir[512]; + snprintf( container_dir, 512, "%s/%c%03d%c%02d", + dest_base.c_str(), EW, abs(baselon), NS, abs(baselat) ); + snprintf( command, 512, "mkdir -p %s", container_dir ); + cout << command << endl; + system( command ); + + char dir[512]; + snprintf( dir, 512, "%c%03d%c%02d/%c%03d%c%02d", + EW, abs(baselon), NS, abs(baselat), + EW, abs(lon), NS, abs(lat) ); + + snprintf( command, 512, + "rsync --verbose --archive --delete --perms --owner --group %s/%s/ %s/%s", + source_base.c_str(), dir, dest_base.c_str(), dir ); + cout << command << endl; + system( command ); +} + + +// sync areas +static void sync_areas( int lat, int lon, int lat_dir, int lon_dir ) { + // do current 1x1 degree area first + sync_area( lat, lon ); + + if ( lat_dir == 0 && lon_dir == 0 ) { + // now do surrounding 8 1x1 degree areas. + for ( int i = lat - 1; i <= lat + 1; ++i ) { + for ( int j = lon - 1; j <= lon + 1; ++j ) { + if ( i != lat || j != lon ) { + sync_area( i, j ); + } + } + } + } else { + if ( lat_dir != 0 ) { + sync_area( lat + lat_dir, lon ); + sync_area( lat + lat_dir, lon - 1 ); + sync_area( lat + lat_dir, lon + 1 ); + } + if ( lon_dir != 0 ) { + sync_area( lat, lon + lon_dir ); + sync_area( lat - 1, lon + lon_dir ); + sync_area( lat + 1, lon + lon_dir ); + } + } +} + + +int main( int argc, char **argv ) { + int port = 5501; + char host[256] = ""; // accept messages from anyone + + // parse arguments + int i = 1; + while ( i < argc ) { + if ( (string)argv[i] == "-p" ) { + ++i; + port = atoi( argv[i] ); + } else if ( (string)argv[i] == "-s" ) { + ++i; + source_base = argv[i]; + } else if ( (string)argv[i] == "-d" ) { + ++i; + dest_base = argv[i]; + } else { + usage( argv[0] ); + exit(-1); + } + ++i; + } + + // Must call this before any other net stuff + netInit( &argc,argv ); + + netSocket s; + + if ( ! s.open( false ) ) { // open a UDP socket + printf("error opening socket\n"); + return -1; + } + + s.setBlocking( false ); + + if ( s.bind( host, port ) == -1 ) { + printf("error binding to port %d\n", port); + return -1; + } + + char msg[256]; + int maxlen = 256; + int len; + int lat, lon; + int last_lat = -9999; + int last_lon = -9999; + bool recv_msg = false; + + while ( true ) { + recv_msg = false; + while ( (len = s.recv(msg, maxlen, 0)) >= 0 ) { + msg[len] = '\0'; + recv_msg = true; + + parse_message( msg, &lat, &lon ); + cout << "pos = " << lat << "," << lon << endl; + } + + if ( recv_msg ) { + if ( lat != last_lat || lon != last_lon ) { + int lat_dir, lon_dir, dist; + if ( last_lat == -9999 || last_lon == -9999 ) { + lat_dir = lon_dir = 0; + } else { + dist = lat - last_lat; + if ( dist != 0 ) { + lat_dir = dist / abs(dist); + } else { + lat_dir = 0; + } + dist = lon - last_lon; + if ( dist != 0 ) { + lon_dir = dist / abs(dist); + } else { + lon_dir = 0; + } + } + cout << "lat = " << lat << " lon = " << lon << endl; + cout << "lat_dir = " << lat_dir << " " << " lon_dir = " << lon_dir << endl; + sync_areas( lat, lon, lat_dir, lon_dir ); + } + + last_lat = lat; + last_lon = lon; + } + + ulSleep( 1 ); + } + + return 0; +} -- 2.39.5