From 01b3d1f5ecf54771f2cb76872ed27cf913326670 Mon Sep 17 00:00:00 2001
From: till busch <buti@bux.at>
Date: Thu, 9 Oct 2008 20:41:07 +0200
Subject: [PATCH] add an elevation util v0.0.5

---
 configure.ac                     |    3 +-
 utils/Makefile.am                |    4 +-
 utils/elevation/Makefile.am      |   24 +++
 utils/elevation/README.elevation |   17 +++
 utils/elevation/elevation.cxx    |  289 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 334 insertions(+), 3 deletions(-)
 create mode 100644 utils/elevation/Makefile.am
 create mode 100644 utils/elevation/README.elevation
 create mode 100644 utils/elevation/elevation.cxx

diff --git a/configure.ac b/configure.ac
index 59fa9a6..4a64de4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -689,7 +689,8 @@ AC_CONFIG_FILES([ \
 	tests/Makefile \
 	utils/Makefile \
 	utils/GPSsmooth/Makefile \
-	utils/fgadmin/Makefile
+	utils/elevation/Makefile \
+	utils/fgadmin/Makefile \
 	utils/fgadmin/src/Makefile \
 	utils/js_server/Makefile \
 	utils/Modeller/Makefile \
diff --git a/utils/Makefile.am b/utils/Makefile.am
index e73dcc1..ba9918a 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -1,4 +1,4 @@
-DIST_SUBDIRS = GPSsmooth TerraSync Modeller js_server fgadmin xmlgrep
+DIST_SUBDIRS = GPSsmooth TerraSync Modeller js_server fgadmin xmlgrep elevation
 
-SUBDIRS = GPSsmooth TerraSync Modeller js_server
+SUBDIRS = GPSsmooth TerraSync Modeller js_server elevation
 
diff --git a/utils/elevation/Makefile.am b/utils/elevation/Makefile.am
new file mode 100644
index 0000000..cf05ed5
--- /dev/null
+++ b/utils/elevation/Makefile.am
@@ -0,0 +1,24 @@
+EXTRA_DIST = README
+
+bin_PROGRAMS = elevation
+
+elevation_SOURCES = elevation.cxx
+
+if WITH_THREADS
+THREAD_LIBS = -lsgthreads $(thread_LIBS)
+else
+THREAD_LIBS =
+endif
+
+LIBS=-losg -losgDB -losgParticle -losgUtil
+
+#INCLUDES = -I$(top_srcdir)/src/Scenery/ -I$(top_srcdir)/src/ -I$(top_srcdir)/
+
+elevation_LDADD = \
+	-lsgmaterial -lsgtgdb -lsgmodel \
+	-lsgutil -lsgio -lsgmath -lsgbucket -lsgprops \
+	-lsgdebug -lsgmisc -lsgnasal -lsgxml \
+	-lsgstructure \
+	-lplibsg -lplibul \
+	-lz
+
diff --git a/utils/elevation/README.elevation b/utils/elevation/README.elevation
new file mode 100644
index 0000000..fd653e9
--- /dev/null
+++ b/utils/elevation/README.elevation
@@ -0,0 +1,17 @@
+# GPL, (l) 2008 by till busch <buti@bux.at>
+
+WARNING: This is a quick hack. Do not expect more than that. There are no
+configuration options, all paths are hard-coded.
+
+The elevation-tool does intersection-testing on Scenery (including models!).
+It reads lines from stdin and writes results to stdout.
+
+INPUT FORMAT:
+id lat lon tile
+
+OUTPUT FORMAT:
+id lat lon tile elevation
+
+id and tile are not used internally (there is no need to provide meaningful
+numbers).
+
diff --git a/utils/elevation/elevation.cxx b/utils/elevation/elevation.cxx
new file mode 100644
index 0000000..c80ca1d
--- /dev/null
+++ b/utils/elevation/elevation.cxx
@@ -0,0 +1,289 @@
+// elevation.cxx - calculate terrain elevation
+// GPL, (l) 2008 by till busch <buti@bux.at>
+
+#include <config.h>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/scene/util/SGSceneFeatures.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/model/location.hxx>
+#include <simgear/scene/model/modellib.hxx>
+#include <simgear/scene/model/SGReaderWriterXMLOptions.hxx>
+#include <simgear/scene/material/mat.hxx>
+#include <simgear/scene/tgdb/userdata.hxx>
+#include <simgear/scene/tgdb/TileCache.hxx>
+#include <simgear/scene/tgdb/TileEntry.hxx>
+#include <simgear/scene/tgdb/SGReaderWriterBTGOptions.hxx>
+#include <simgear/scene/util/SGNodeMasks.hxx>
+#include <osg/Group>
+#include <osg/ArgumentParser>
+#include <osgDB/ReadFile>
+#include <osgUtil/LineSegmentIntersector>
+#include <OpenThreads/Thread>
+
+#include <iostream>
+
+#define FG_ROOT      "/usr/local/share/FlightGear"
+#define SCENERY_DIRS "/usr/local/share/FlightGear/Scenery:/usr/local/share/FlightGear/Scenery-Terrasync"
+
+//#define FG_ROOT      "/home/martin/GIT/fgdata/"
+//#define SCENERY_DIRS "/home/rgerlich/scenery/world_scenery-1.0/"
+
+#define OUTPUT id << " " << lat << " " << lon << " " << tile << " " << alt << std::endl
+//#define OUTPUT "update fgs_objects set ob_gndelev=" << alt << " where ob_id=" << id << ";" << std::endl
+
+#define visibility 20000.0
+#define SEASON "summer"
+
+#define DESCRIPTION \
+"    intersection-testing on flightgear scenery (optionally including models).\n" \
+"    reads lines from stdin and writes results to stdout.\n\n" \
+"    INPUT FORMAT:\n" \
+"        id lat lon tile\n\n" \
+"    OUTPUT FORMAT:\n" \
+"        id lat lon tile elevation\n\n" \
+"GPL, (l) 2008 by till busch <buti@bux.at>\n"
+
+using std::cin;
+using std::cout;
+using std::cerr;
+using std::endl;
+using std::ws;
+using simgear::TileCache;
+using simgear::TileEntry;
+using simgear::SGReaderWriterXMLOptions;
+
+void add_tile(TileCache &tile_cache, SGBucket &b, double timestamp, osgDB::ReaderWriter::Options *options);
+osg::ref_ptr<osg::Group> sceneGraph=new osg::Group;
+
+class ModelLoader : public simgear::ModelLoadHelper
+{
+public:
+    virtual osg::Node *loadTileModel(const string& modelPath, bool cacheModel) {
+        return osgDB::readNodeFile(modelPath, _options.get());
+    }
+    osg::ref_ptr<SGReaderWriterXMLOptions> _options;
+
+};
+
+int main(int argc, char *argv[])
+{
+    OpenThreads::Thread::Init();
+    string fg_root=FG_ROOT;
+    string scenery_dirs=SCENERY_DIRS;
+
+    osg::ArgumentParser arguments(&argc,argv);
+    osg::ApplicationUsage *au=arguments.getApplicationUsage();
+    au->setCommandLineUsage(arguments.getApplicationName()+" [option] ...");
+    au->addCommandLineOption("--models", "intersect scenery and models");
+    au->addCommandLineOption("--fg_root <path>", "set flightgear root to <path>", fg_root);
+    au->addCommandLineOption("--fg_scenery <path>", "set scenery dirs to <path> (separated by ':')", scenery_dirs);
+    au->setDescription(DESCRIPTION);
+
+    if (arguments.read("--help") || arguments.read("-h")) {
+        arguments.getApplicationUsage()->write(std::cerr);
+        std::cerr << "Description:" << std::endl;
+        std::cerr << arguments.getApplicationUsage()->getDescription() << std::endl;
+        return 1;
+    }
+
+    SGPropertyNode_ptr propRoot=new SGPropertyNode;
+
+    ModelLoader ml;
+    if (arguments.read("--models")) {
+        ml._options = new SGReaderWriterXMLOptions;
+        ml._options->setPropRoot(propRoot);
+        TileEntry::setModelLoadHelper(&ml);
+    }
+
+    arguments.read("--fg_root", fg_root);
+    arguments.read("--fg_scenery", scenery_dirs);
+
+    cerr << "fg_root=" << fg_root << endl;
+    cerr << "fg_scenery=" << scenery_dirs << endl;
+
+
+    // setting this higher may cause garbage on stdout
+    osg::setNotifyLevel(osg::WARN);
+
+    logbuf::set_log_classes(SG_ALL);
+    logbuf::set_log_priority(SG_WARN);
+//    logbuf::set_log_priority(SG_BULK);
+
+    //SGConfigureDirectionalLights( use_point_sprites, enhanced_lighting,
+    //                              distance_attenuation );
+
+    SGSceneFeatures::instance()->setEnablePointSpriteLights(false);
+    SGSceneFeatures::instance()->setEnableDistanceAttenuationLights(false);
+
+    propRoot->setDoubleValue("/environment/visibility-m", visibility);
+    propRoot->setStringValue("/sim/startup/season", SEASON);
+    propRoot->setBoolValue("/sim/rendering/random-objects", false);
+    propRoot->setBoolValue("/sim/rendering/random-vegetation", false);
+
+    sgUserDataInit( propRoot );
+    SGMaterialLib *matlib = new SGMaterialLib;
+    SGPath mpath(fg_root);
+    mpath.append("materials.xml");
+    if (!matlib->load(fg_root, mpath.str(), SEASON, propRoot))
+        SG_LOG( SG_GENERAL, SG_ALERT, "Error loading material lib!" );
+
+    simgear::SGModelLib::init(fg_root);
+
+    osg::ref_ptr<SGReaderWriterBTGOptions> options = new SGReaderWriterBTGOptions;
+    options->setMatlib(matlib);
+    options->setUseRandomObjects(false);
+    options->setUseRandomVegetation(false);
+    options->setCalcLights(false);
+
+    osgDB::FilePathList &fp = options->getDatabasePathList();
+    fp.clear();
+
+    string_list path_list = sgPathSplit(scenery_dirs);
+
+    for (unsigned i = 0; i < path_list.size(); i++) {
+
+        ulDir *d = ulOpenDir( path_list[i].c_str() );
+        if (d == NULL)
+            continue;
+        ulCloseDir( d );
+
+        SGPath pt( path_list[i] ), po( path_list[i] );
+        pt.append("Terrain");
+        po.append("Objects");
+
+        ulDir *td = ulOpenDir( pt.c_str() );
+        ulDir *od = ulOpenDir( po.c_str() );
+
+        if (td == NULL && od == NULL)
+            fp.push_back( path_list[i] );
+        else {
+            if (td != NULL) {
+                fp.push_back( pt.str() );
+                ulCloseDir( td );
+            }
+            if (od != NULL) {
+                fp.push_back( po.str() );
+                ulCloseDir( od );
+            }
+        }
+        // insert a marker for FGTileEntry::load(), so that
+        // FG_SCENERY=A:B becomes list ["A/Terrain", "A/Objects", "",
+        // "B/Terrain", "B/Objects", ""]
+        fp.push_back("");
+    }
+
+    double lon=-122.0, lat=37.0;
+    int id, tile;
+    double timestamp=0.0;
+
+    TileCache tile_cache;
+    tile_cache.set_max_cache_size(9);
+
+    SGBucket b,old_bucket;
+    b.make_bad();
+    old_bucket.make_bad();
+
+    while (!cin.eof()) {
+        double offset = 0.0;
+        timestamp++;
+        cin >> id >> ws >> lat >> ws >> lon >> ws >> tile;
+        bool hit=false;
+        int retry = 5;
+        while (!hit && retry--) {
+            b = sgBucketOffset( lon+offset, lat+offset, 0, 0 );
+
+            if (b != old_bucket) {
+                old_bucket=b;
+                // add 9 tiles
+                for (int x = -1; x <= 1; ++x) {
+                    for (int y = -1; y <= 1; ++y) {
+                        b = sgBucketOffset(lon+offset, lat+offset, x, y);
+                        add_tile(tile_cache, b, timestamp, options.get());
+                    }
+                }
+            }
+
+            SGGeod geod=SGGeod::fromDegM(lon+offset, lat+offset, SG_MAX_ELEVATION_M);
+            SGVec3d start = SGVec3d::fromGeod(geod);
+            SGVec3d contact;
+
+            geod.setElevationM(-10000.0);
+            SGVec3d end = SGVec3d::fromGeod(geod);
+
+            osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegment;
+            lineSegment = new osgUtil::LineSegmentIntersector(start.osg(), end.osg());
+
+            osgUtil::IntersectionVisitor intersectVisitor(lineSegment.get());
+            intersectVisitor.setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
+            intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
+
+            sceneGraph->accept(intersectVisitor);
+
+            osgUtil::LineSegmentIntersector::Intersections& intersections = lineSegment->getIntersections();
+            double alt=-10000.0;
+
+            for (osgUtil::LineSegmentIntersector::Intersections::iterator itr = intersections.begin();
+                 itr != intersections.end(); ++itr) {
+                const osgUtil::LineSegmentIntersector::Intersection& intersection = *itr;
+
+                contact.osg() = intersection.getWorldIntersectPoint();
+                /*
+                                 if(material) {
+                                     const osg::StateSet* stateSet = intersection.drawable->getStateSet();
+                                     *material = globals->get_matlib()->findMaterial(stateSet);
+                                 }
+                */
+                /*
+                                 cerr << "HIT ";
+                                 for(osg::NodePath::const_iterator it=(*itr).nodePath.begin(); it!=(*itr).nodePath.end(); ++it)
+                                     cerr << (*it)->getName() << ":";
+                                 cerr << endl;
+                */
+                SGGeod geod = SGGeod::fromCart(contact);
+                alt = geod.getElevationM() > alt ? geod.getElevationM() : alt;
+
+                hit=true;
+//                 break;
+            }
+            if (hit)
+                cout << OUTPUT;
+            else
+                offset+=0.0000001;
+        }
+        if (!hit)
+            cerr << "NO HIT AT " << id << " " << lat << " " << lon << " " << std::endl;
+        else if (offset > 0.00000001)
+            cerr << "HIT AT " << id << " " << lat+offset << " " << lon+offset << " (offset " << offset << ")" << std::endl;
+
+    }
+    cerr << "tile_cache size= " << tile_cache.get_size() << std::endl;
+
+    return 0;
+}
+
+void add_tile(TileCache &tile_cache, SGBucket &b, double timestamp, osgDB::ReaderWriter::Options *options)
+{
+
+
+    TileEntry *t = tile_cache.get_tile(b);
+    if (!t) {
+        // remove old tiles
+        while ( (int)tile_cache.get_size() > tile_cache.get_max_cache_size() ) {
+            long index = tile_cache.get_oldest_tile();
+            if ( index >= 0 ) {
+                TileEntry *old = tile_cache.get_tile( index );
+                tile_cache.clear_entry( index );
+                osg::ref_ptr<osg::Object> subgraph = old->getNode();
+                old->removeFromSceneGraph();
+                delete old;
+            } else
+                break;
+        }
+        t = new TileEntry(b);
+        tile_cache.insert_tile(t);
+        t->addToSceneGraph(sceneGraph.get());
+        t->getNode()->addChild(osgDB::readNodeFile(t->tileFileName, options));
+    }
+    t->set_timestamp(timestamp);
+}
+
-- 
1.5.4.3


