]> git.mxchange.org Git - flightgear.git/commitdiff
fgelev: tool to query scenery elevation.
authorMathias Froehlich <Mathias.Froehlich@web.de>
Sat, 18 Aug 2012 11:00:08 +0000 (13:00 +0200)
committerMathias Froehlich <Mathias.Froehlich@web.de>
Sun, 19 Aug 2012 18:02:09 +0000 (20:02 +0200)
utils/CMakeLists.txt
utils/fgelev/CMakeLists.txt [new file with mode: 0644]
utils/fgelev/fgelev.cxx [new file with mode: 0644]

index 42422971c2171a3cf3b1605fa0c1b232943f780f..70d89a487f8fa0bb609da7921e36682647605a06 100644 (file)
@@ -1,5 +1,6 @@
 add_subdirectory(TerraSync)
 add_subdirectory(fgviewer)
+add_subdirectory(fgelev)
 add_subdirectory(GPSsmooth)
 
 if (FLTK_FOUND)
diff --git a/utils/fgelev/CMakeLists.txt b/utils/fgelev/CMakeLists.txt
new file mode 100644 (file)
index 0000000..90b52c0
--- /dev/null
@@ -0,0 +1,10 @@
+add_executable(fgelev fgelev.cxx)
+
+target_link_libraries(fgelev
+       ${SIMGEAR_LIBRARIES}
+       ${OPENSCENEGRAPH_LIBRARIES}
+       ${OPENGL_LIBRARIES}
+        ${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
+)
+
+install(TARGETS fgelev RUNTIME DESTINATION bin)
diff --git a/utils/fgelev/fgelev.cxx b/utils/fgelev/fgelev.cxx
new file mode 100644 (file)
index 0000000..a4e2a71
--- /dev/null
@@ -0,0 +1,334 @@
+// fgelev.cxx -- compute scenery elevation
+//
+// Copyright (C) 2009 - 2012  Mathias Froehlich
+//
+// 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <iostream>
+#include <cstdlib>
+#include <iomanip>
+
+#include <osg/ArgumentParser>
+#include <osg/Camera>
+#include <osg/PagedLOD>
+#include <osg/ProxyNode>
+#include <osg/Transform>
+#include <osgDB/ReadFile>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/util/SGNodeMasks.hxx>
+#include <simgear/scene/util/SGReaderWriterOptions.hxx>
+#include <simgear/scene/util/SGSceneFeatures.hxx>
+#include <simgear/scene/util/SGSceneUserData.hxx>
+#include <simgear/scene/tgdb/userdata.hxx>
+#include <simgear/scene/model/ModelRegistry.hxx>
+#include <simgear/misc/ResourceManager.hxx>
+#include <simgear/scene/bvh/BVHNode.hxx>
+#include <simgear/scene/bvh/BVHLineSegmentVisitor.hxx>
+
+class FGSceneryIntersect : public osg::NodeVisitor {
+public:
+    FGSceneryIntersect(const SGLineSegmentd& lineSegment) :
+        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
+        _lineSegment(lineSegment),
+        _haveHit(false)
+    { }
+
+    bool getHaveHit() const
+    { return _haveHit; }
+    const SGLineSegmentd& getLineSegment() const
+    { return _lineSegment; }
+
+    virtual void apply(osg::Node& node)
+    {
+        if (!testBoundingSphere(node.getBound()))
+            return;
+
+        addBoundingVolume(node);
+    }
+
+    virtual void apply(osg::Group& group)
+    {
+        if (!testBoundingSphere(group.getBound()))
+            return;
+
+        traverse(group);
+        addBoundingVolume(group);
+    }
+
+    virtual void apply(osg::Transform& transform)
+    { handleTransform(transform); }
+    virtual void apply(osg::Camera& camera)
+    {
+        if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
+            return;
+        handleTransform(camera);
+    }
+
+    virtual void apply(osg::ProxyNode& proxyNode)
+    {
+        unsigned numFileNames = proxyNode.getNumFileNames();
+        for (unsigned i = 0; i < numFileNames; ++i) {
+            if (i < proxyNode.getNumChildren() && proxyNode.getChild(i))
+                continue;
+            // FIXME evaluate pagedLOD.getDatabasePath()
+            osg::ref_ptr<osg::Node> node;
+            node = osgDB::readNodeFile(proxyNode.getFileName(i),
+              static_cast<const osgDB::Options*>(proxyNode.getDatabaseOptions()));
+            if (!node.valid())
+                node = new osg::Group;
+            if (i < proxyNode.getNumChildren())
+                proxyNode.setChild(i, node);
+            else
+                proxyNode.addChild(node);
+        }
+
+        apply(static_cast<osg::Group&>(proxyNode));
+    }
+    virtual void apply(osg::PagedLOD& pagedLOD)
+    {
+        float range = std::numeric_limits<float>::max();
+        unsigned numFileNames = pagedLOD.getNumFileNames();
+        for (unsigned i = 0; i < numFileNames; ++i) {
+            if (range < pagedLOD.getMaxRange(i))
+                continue;
+            range = pagedLOD.getMaxRange(i);
+        }
+
+        for (unsigned i = pagedLOD.getNumChildren(); i < numFileNames; ++i) {
+            if (i < pagedLOD.getNumChildren() && pagedLOD.getChild(i))
+                continue;
+            osg::ref_ptr<osg::Node> node;
+            if (pagedLOD.getMaxRange(i) <= range) {
+                // FIXME evaluate pagedLOD.getDatabasePath()
+                node = osgDB::readNodeFile(pagedLOD.getFileName(i),
+                  static_cast<const osgDB::Options*>(pagedLOD.getDatabaseOptions()));
+            }
+            if (!node.valid())
+                node = new osg::Group;
+            pagedLOD.addChild(node.get());
+        }
+
+        apply(static_cast<osg::LOD&>(pagedLOD));
+    }
+
+private:
+    void handleTransform(osg::Transform& transform)
+    {
+        // Hmm, may be this needs to be refined somehow ...
+        if (transform.getReferenceFrame() != osg::Transform::RELATIVE_RF)
+            return;
+
+        if (!testBoundingSphere(transform.getBound()))
+            return;
+
+        osg::Matrix inverseMatrix;
+        if (!transform.computeWorldToLocalMatrix(inverseMatrix, this))
+            return;
+        osg::Matrix matrix;
+        if (!transform.computeLocalToWorldMatrix(matrix, this))
+            return;
+
+        SGLineSegmentd lineSegment = _lineSegment;
+        bool haveHit = _haveHit;
+
+        _haveHit = false;
+        _lineSegment = lineSegment.transform(SGMatrixd(inverseMatrix.ptr()));
+
+        addBoundingVolume(transform);
+        traverse(transform);
+
+        if (_haveHit) {
+            _lineSegment = _lineSegment.transform(SGMatrixd(matrix.ptr()));
+        } else {
+            _lineSegment = lineSegment;
+            _haveHit = haveHit;
+        }
+    }
+
+    simgear::BVHNode* getNodeBoundingVolume(osg::Node& node)
+    {
+        SGSceneUserData* userData = SGSceneUserData::getSceneUserData(&node);
+        if (!userData)
+            return 0;
+        return userData->getBVHNode();
+    }
+    void addBoundingVolume(osg::Node& node)
+    {
+        simgear::BVHNode* bvNode = getNodeBoundingVolume(node);
+        if (!bvNode)
+            return;
+
+        // Find ground intersection on the bvh nodes
+        simgear::BVHLineSegmentVisitor lineSegmentVisitor(_lineSegment,
+                                                          0/*startTime*/);
+        bvNode->accept(lineSegmentVisitor);
+        if (!lineSegmentVisitor.empty()) {
+            _lineSegment = lineSegmentVisitor.getLineSegment();
+            _haveHit = true;
+        }
+    }
+
+    bool testBoundingSphere(const osg::BoundingSphere& bound) const
+    {
+        if (!bound.valid())
+            return false;
+
+        SGSphered sphere(toVec3d(toSG(bound._center)), bound._radius);
+        return intersects(_lineSegment, sphere);
+    }
+
+    SGLineSegmentd _lineSegment;
+    bool _haveHit;
+};
+
+int
+main(int argc, char** argv)
+{
+    /// Read arguments and environment variables.
+
+    // use an ArgumentParser object to manage the program arguments.
+    osg::ArgumentParser arguments(&argc, argv);
+
+    std::string fg_root;
+    if (arguments.read("--fg-root", fg_root)) {
+    } else if (const char *fg_root_env = std::getenv("FG_ROOT")) {
+        fg_root = fg_root_env;
+    } else {
+        fg_root = PKGLIBDIR;
+    }
+
+    std::string fg_scenery;
+    if (arguments.read("--fg-scenery", fg_scenery)) {
+    } else if (const char *fg_scenery_env = std::getenv("FG_SCENERY")) {
+        fg_scenery = fg_scenery_env;
+    } else {
+        SGPath path(fg_root);
+        path.append("Scenery");
+        fg_scenery = path.str();
+    }
+
+    SGSharedPtr<SGPropertyNode> props = new SGPropertyNode;
+    try {
+        SGPath preferencesFile = fg_root;
+        preferencesFile.append("preferences.xml");
+        readProperties(preferencesFile.str(), props);
+    } catch (...) {
+        // In case of an error, at least make summer :)
+        props->getNode("sim/startup/season", true)->setStringValue("summer");
+
+        SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading FlightGear preferences.\n"
+               << "Probably FG_ROOT is not properly set.");
+    }
+
+    std::string config;
+    while (arguments.read("--config", config)) {
+        try {
+            readProperties(config, props);
+        } catch (...) {
+            SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading config file \"" << config
+                   << "\" given on the command line.");
+        }
+    }
+
+    std::string prop, value;
+    while (arguments.read("--prop", prop, value)) {
+        props->setStringValue(prop, value);
+    }
+
+    /// now set up the simgears required model stuff
+
+    simgear::ResourceManager::instance()->addBasePath(fg_root, simgear::ResourceManager::PRIORITY_DEFAULT);
+    // Just reference simgears reader writer stuff so that the globals get
+    // pulled in by the linker ...
+    simgear::ModelRegistry::instance();
+
+    sgUserDataInit(props.get());
+    SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::DoNotUseCompression);
+    SGMaterialLib* ml = new SGMaterialLib;
+    SGPath mpath(fg_root);
+    mpath.append("Materials/default/materials.xml");
+    try {
+        ml->load(fg_root, mpath.str(), props);
+    } catch (...) {
+        SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading FlightGear materials.\n"
+               << "Probably FG_ROOT is not properly set.");
+    }
+    simgear::SGModelLib::init(fg_root, props);
+
+    // Set up the reader/writer options
+    osg::ref_ptr<simgear::SGReaderWriterOptions> options;
+    if (osgDB::Options* ropt = osgDB::Registry::instance()->getOptions())
+        options = new simgear::SGReaderWriterOptions(*ropt);
+    else
+        options = new simgear::SGReaderWriterOptions;
+    osgDB::convertStringPathIntoFilePathList(fg_scenery,
+                                             options->getDatabasePathList());
+    options->setMaterialLib(ml);
+    options->setPropertyNode(props);
+    options->setPluginStringData("SimGear::FG_ROOT", fg_root);
+    options->setPluginStringData("SimGear::BOUNDINGVOLUMES", "ON");
+
+    // Here, all arguments are processed
+    arguments.reportRemainingOptionsAsUnrecognized();
+    arguments.writeErrorMessages(std::cerr);
+
+    /// Read the whole world paged model.
+    osg::ref_ptr<osg::Node> loadedModel;
+    loadedModel = osgDB::readNodeFile("w180s90-360x180.spt", options.get());
+
+    // if no model has been successfully loaded report failure.
+    if (!loadedModel.valid()) {
+        SG_LOG(SG_GENERAL, SG_ALERT, arguments.getApplicationName()
+               << ": No data loaded");
+        return EXIT_FAILURE;
+    }
+
+    // now handle all the position pairs
+    for(int i = 1; i < arguments.argc(); ++i) {
+        if (arguments.isOption(i))
+            continue;
+
+        std::istringstream ss(arguments[i]);
+        double lon, lat;
+        char sep;
+        ss >> lon >> sep >> lat;
+        if (ss.fail()) {
+            return EXIT_FAILURE;
+        }
+
+        SGVec3d start = SGVec3d::fromGeod(SGGeod::fromDegM(lon, lat, 10000));
+        SGVec3d end = SGVec3d::fromGeod(SGGeod::fromDegM(lon, lat, -1000));
+        FGSceneryIntersect intersectVisitor(SGLineSegmentd(start, end));
+        intersectVisitor.setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
+        loadedModel->accept(intersectVisitor);
+
+        std::cout << arguments[i] << ": ";
+        if (!intersectVisitor.getHaveHit()) {
+            std::cout << "-1000" << std::endl;
+        } else {
+            SGGeod geod = SGGeod::fromCart(intersectVisitor.getLineSegment().getEnd());
+            std::cout << std::fixed << std::setprecision(3) << geod.getElevationM() << std::endl;
+        }
+    }
+
+    return EXIT_SUCCESS;
+}