--- Begin Message ---
Hello,
answering to Nick Prudent's proposal for a Windows front-end for osgdem,
I would suggest to create an XML configuration file parser. XML files
are easily editable from specialized XML editor given a schema
definition of the file content.
Advantages over a specialized front end are:
- cross platform for free
- repeatability (can rerun a configuration file on error)
- documentation (can extract configuration in a human readable form for
reports)
- maintenance and expansibility (only need to update configuration file
parser and XML schema)
I am using a similar approach within my pet project, Le Petit Poucet GPS
software (petit-poucet.org). Main application is downloading and
geo-referencing images, then writing an XML configuration file
(attached, conf.ptig), then a specialized version of osgdem called
pti_gen, it is parsing this XML file and generating .osga (attached is
the crude parser I wrote based on Expat, parse_config.cpp).
My parser is not covering all features of osgdem command line and
vpb::DataSet but could be extended easily.
Note that I am using extensively GDAL's VRT format to add
geo-referencing to image files but this geo-referencing could be
included into the osgdem configuration. It is possible to pass to GDAL a
string containing XML corresponding to a VRT file.
Antoine
<?xml version="1.0"?>
<pti_gen version='1.0'>
<archive_file>/home/tonio/.pti/cache/orig/YosemiteFall_gpx.osga</archive_file>
<srs>GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9108"]],AXIS["Lat",NORTH],AXIS["Long",EAST],AUTHORITY["EPSG","4326"]]</srs>
<geospatial_extents min_x='-119.631' min_y='37.7228' max_x='-119.57' max_y='37.781' geographic='1' />
<source image='1'>/home/tonio/.pti/cache/imagery/landsat/YosemiteFall_gpx_landsat.vrt</source>
<source image='0'>/home/tonio/.pti/cache/imagery/srtm/YosemiteFall_gpx_srtm.vrt</source>
<source image='1'>/home/tonio/.pti/cache/imagery/usgs_drg/YosemiteFall_gpx_usgs_drg.vrt</source>
<source image='0'>/home/tonio/.pti/cache/imagery/us_ned/YosemiteFall_gpx_us_ned.vrt</source>
</pti_gen>
///@file pti_gen.cpp
/// 3D terrain generator config file parser
///
///@author Antoine Hue
///@date 26.06.2007
/*
This file is part of Le-Petit-Poucet
Le-Petit-Poucet 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string>
#include <vpb/DataSet>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <ogr_spatialref.h>
#include <cpl_conv.h>
#include <expat.h>
#include <iostream>
typedef enum {
tt_unknown = 0,
tt_pti_gen,
tt_bin_path,
tt_archive_file,
tt_gdal_data,
tt_srs,
tt_geospatial_extents,
tt_source
} tag_type_t;
typedef struct tag_mapping {
tag_type_t tag_type; /* enum from above for this tag */
const char *tag_name; /* xpath-ish tag name */
} tag_mapping;
/*
* xpath(ish) mappings between full tag paths and internal identifers.
* These appear in the order they appear in the GPX specification.
* If it's not a tag we explictly handle, it doesn't go here.
*/
tag_mapping tag_path_map[] = {
{tt_pti_gen, "/pti_gen"},
{tt_bin_path, "/pti_gen/bin_path"},
{tt_archive_file, "/pti_gen/archive_file"},
{tt_gdal_data, "/pti_gen/gdal_data"},
{tt_srs, "/pti_gen/srs"},
{tt_geospatial_extents, "/pti_gen/geospatial_extents"},
{tt_source, "/pti_gen/source"},
{tt_unknown}
};
static tag_type_t get_tag(const char *t)
{
tag_mapping *tm;
for (tm = tag_path_map; tm->tag_type != tt_unknown; tm++)
if (0 == strcmp(tm->tag_name, t))
return tm->tag_type;
return tt_unknown;
}
static tag_type_t current_tag = tt_unknown;
static std::string xpath;
static std::string c_cdata;
static bool image_source = false;
static int n_source = 0;
static const char *get_attr ( const char **attr, const char *key )
{
while ( *attr ) {
if ( strcmp(*attr,key) == 0 )
return *(attr + 1);
attr += 2;
}
return NULL;
}
static void start(vpb::DataSet *ds, const char *el, const char **attr)
{
xpath += '/';
xpath += el;
current_tag = get_tag ( xpath.c_str() );
c_cdata.clear();
switch ( current_tag )
{
case tt_pti_gen:
case tt_bin_path:
case tt_archive_file:
case tt_gdal_data:
case tt_srs:
break;
case tt_geospatial_extents:
{
double xMin, yMin, xMax, yMax;
bool geo;
xMin = strtod(get_attr(attr, "min_x"), NULL);
yMin = strtod(get_attr(attr, "min_y"), NULL);
xMax = strtod(get_attr(attr, "max_x"), NULL);
yMax = strtod(get_attr(attr, "max_y"), NULL);
geo = atoi(get_attr(attr, "geographic"));
vpb::GeospatialExtents extents(xMin, yMin, xMax, yMax, geo);
if(extents.valid())
{
ds->setDestinationExtents(extents); // Needed before addition of other sources
}
}
break;
case tt_source:
image_source = atoi(get_attr(attr, "image"));
break;
default:
// Error or not ?
std::cerr << "Unknown tag '" << el << "'\n";
break;
}
}
static void end(vpb::DataSet *ds, const char *el)
{
//static struct tm tm;
// g_string_truncate ( xpath, el);
std::string sel(el);
size_t pos = xpath.find(sel);
xpath.erase(pos-1, sel.length()+1);
switch ( current_tag ) {
case tt_pti_gen:
break;
case tt_bin_path:
if(c_cdata.length() > 0)
{
osgDB::FilePathList binPaths;
binPaths.push_back(c_cdata);
osgDB::appendPlatformSpecificLibraryFilePaths(binPaths);
osgDB::setLibraryFilePathList(binPaths);
}
break;
case tt_archive_file:
if(c_cdata.length() > 0)
{
std::string strippedName = osgDB::getStrippedName(c_cdata);
std::string path = osgDB::getFilePath(c_cdata);
std::string dbFile = (strippedName + ".ive");
std::string archiveName;
if(path.length() > 0)
archiveName = path + "/" + strippedName + ".osga";
else
archiveName = strippedName + ".osga";
// Set output, to clean and to push into the cache
ds->setDestinationTileBaseName(strippedName);
ds->setDestinationTileExtension(".ive");
ds->setArchiveName(archiveName);
std::cerr << "pti_gen: archive name='"
<< archiveName << "'\n";
}
else
{
// Error handling needed
}
break;
case tt_gdal_data:
if(c_cdata.length() > 0)
CPLSetConfigOption("GDAL_DATA", c_cdata.c_str());
std::cerr << "Setting GDAL_DATA to " << c_cdata << std::endl;
break;
case tt_srs:
{
std::cerr << "Setting SRS to " << c_cdata << std::endl;
OGRSpatialReference *SRS = new OGRSpatialReference();
OSRSetFromUserInput((OGRSpatialReferenceH) SRS, c_cdata.c_str());
if(SRS->IsGeographic())
{
ds->setConvertFromGeographicToGeocentric(true);
ds->setEllipsoidModel(new osg::EllipsoidModel(SRS->GetSemiMajor(),
SRS->GetSemiMinor()));
}
ds->setDestinationCoordinateSystem(c_cdata.c_str());
}
break;
case tt_geospatial_extents:
break;
case tt_source:
{
vpb::DataSet::Source::Type type = (image_source)?
vpb::DataSet::Source::IMAGE : vpb::DataSet::Source::HEIGHT_FIELD;
vpb::DataSet::Source *source = new vpb::DataSet::Source(type, c_cdata);
ds->addSource(source);
n_source++;
}
break;
default: break;
}
current_tag = get_tag (xpath.c_str());
}
static void cdata(vpb::DataSet *ds, const XML_Char *s, int len)
{
switch ( current_tag ) {
case tt_bin_path:
case tt_archive_file:
case tt_gdal_data:
case tt_srs:
case tt_source:
c_cdata.append(s, len);
break;
default: break; /* ignore cdata from other things */
}
}
/// Read config file
int read_ptig( vpb::DataSet *ds, const std::string& ptig ) {
n_source = 0;
XML_Parser parser = XML_ParserCreate(NULL);
int done=0, len;
XML_SetElementHandler(parser, (XML_StartElementHandler) start, (XML_EndElementHandler) end);
XML_SetUserData(parser, ds);
XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler) cdata);
char buf[4096];
FILE* fh = fopen(ptig.c_str(), "r");
if(!fh)
return -1;
while (!done) {
len = fread(buf, 1, sizeof(buf)-7, fh);
done = feof(fh) || !len;
XML_Parse(parser, buf, len, done);
}
return n_source;
}
--- End Message ---