]> git.mxchange.org Git - flightgear.git/blob - utils/fgelev/fgelev.cxx
3ad0b5850cedb11276d2da157db1623b93af3088
[flightgear.git] / utils / fgelev / fgelev.cxx
1 // fgelev.cxx -- compute scenery elevation
2 //
3 // Copyright (C) 2009 - 2012  Mathias Froehlich
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <iostream>
24 #include <cstdlib>
25 #include <iomanip>
26
27 #include <osg/ArgumentParser>
28 #include <osg/Image>
29
30 #include <simgear/props/props.hxx>
31 #include <simgear/props/props_io.hxx>
32 #include <simgear/misc/sg_path.hxx>
33 #include <simgear/misc/ResourceManager.hxx>
34 #include <simgear/bvh/BVHNode.hxx>
35 #include <simgear/bvh/BVHLineSegmentVisitor.hxx>
36 #include <simgear/bvh/BVHPager.hxx>
37 #include <simgear/bvh/BVHPageNode.hxx>
38 #include <simgear/scene/material/matlib.hxx>
39 #include <simgear/scene/model/BVHPageNodeOSG.hxx>
40 #include <simgear/scene/model/ModelRegistry.hxx>
41 #include <simgear/scene/util/SGReaderWriterOptions.hxx>
42 #include <simgear/scene/util/OptionsReadFileCallback.hxx>
43 #include <simgear/scene/tgdb/userdata.hxx>
44
45 namespace sg = simgear;
46
47 class Visitor : public sg::BVHLineSegmentVisitor {
48 public:
49     Visitor(const SGLineSegmentd& lineSegment, sg::BVHPager& pager) :
50         BVHLineSegmentVisitor(lineSegment, 0),
51         _pager(pager)
52     { }
53     virtual ~Visitor()
54     { }
55     virtual void apply(sg::BVHPageNode& node)
56     {
57         // we have a non threaded pager so load just right here.
58         _pager.use(node);
59         BVHLineSegmentVisitor::apply(node);
60     }
61 private:
62     sg::BVHPager& _pager;
63 };
64
65 // Short circuit reading image files.
66 class ReadFileCallback : public sg::OptionsReadFileCallback {
67 public:
68     virtual ~ReadFileCallback()
69     { }
70
71     virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& name, const osgDB::Options*)
72     { return new osg::Image; }
73 };
74
75 static bool
76 intersect(sg::BVHNode& node, sg::BVHPager& pager,
77           const SGVec3d& start, SGVec3d& end, double offset)
78 {
79     SGVec3d perp = offset*perpendicular(start - end);
80     Visitor visitor(SGLineSegmentd(start + perp, end + perp), pager);
81     node.accept(visitor);
82     if (visitor.empty())
83         return false;
84     end = visitor.getLineSegment().getEnd();
85     return true;
86 }
87
88 int
89 main(int argc, char** argv)
90 {
91     /// Read arguments and environment variables.
92
93     // use an ArgumentParser object to manage the program arguments.
94     osg::ArgumentParser arguments(&argc, argv);
95
96     std::string fg_root;
97     if (arguments.read("--fg-root", fg_root)) {
98     } else if (const char *fg_root_env = std::getenv("FG_ROOT")) {
99         fg_root = fg_root_env;
100     } else {
101         fg_root = PKGLIBDIR;
102     }
103
104     std::string fg_scenery;
105     if (arguments.read("--fg-scenery", fg_scenery)) {
106     } else if (const char *fg_scenery_env = std::getenv("FG_SCENERY")) {
107         fg_scenery = fg_scenery_env;
108     } else {
109         SGPath path(fg_root);
110         path.append("Scenery");
111         fg_scenery = path.str();
112     }
113
114     SGSharedPtr<SGPropertyNode> props = new SGPropertyNode;
115     try {
116         SGPath preferencesFile = fg_root;
117         preferencesFile.append("preferences.xml");
118         readProperties(preferencesFile.str(), props);
119     } catch (...) {
120         // In case of an error, at least make summer :)
121         props->getNode("sim/startup/season", true)->setStringValue("summer");
122
123         SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading FlightGear preferences.\n"
124                << "Probably FG_ROOT is not properly set.");
125     }
126
127     /// now set up the simgears required model stuff
128
129     simgear::ResourceManager::instance()->addBasePath(fg_root, simgear::ResourceManager::PRIORITY_DEFAULT);
130     // Just reference simgears reader writer stuff so that the globals get
131     // pulled in by the linker ...
132     simgear::ModelRegistry::instance();
133
134     sgUserDataInit(props.get());
135     SGMaterialLibPtr ml = new SGMaterialLib;
136     SGPath mpath(fg_root);
137     mpath.append("Materials/default/materials.xml");
138     try {
139         ml->load(fg_root, mpath.str(), props);
140     } catch (...) {
141         SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading FlightGear materials.\n"
142                << "Probably FG_ROOT is not properly set.");
143     }
144     simgear::SGModelLib::init(fg_root, props);
145
146     // Set up the reader/writer options
147     osg::ref_ptr<simgear::SGReaderWriterOptions> options;
148     if (osgDB::Options* ropt = osgDB::Registry::instance()->getOptions())
149         options = new simgear::SGReaderWriterOptions(*ropt);
150     else
151         options = new simgear::SGReaderWriterOptions;
152     osgDB::convertStringPathIntoFilePathList(fg_scenery,
153                                              options->getDatabasePathList());
154     options->setMaterialLib(ml);
155     options->setPropertyNode(props);
156     options->setReadFileCallback(new ReadFileCallback);
157     options->setPluginStringData("SimGear::FG_ROOT", fg_root);
158     // we do not need the builtin boundingvolumes
159     options->setPluginStringData("SimGear::BOUNDINGVOLUMES", "OFF");
160     // And we only want terrain, no objects on top.
161     options->setPluginStringData("SimGear::FG_ONLY_TERRAIN", "ON");
162     props->getNode("sim/rendering/random-objects", true)->setBoolValue(false);
163     props->getNode("sim/rendering/random-vegetation", true)->setBoolValue(false);
164
165     // Here, all arguments are processed
166     arguments.reportRemainingOptionsAsUnrecognized();
167     arguments.writeErrorMessages(std::cerr);
168
169     // Get the whole world bvh tree
170     SGSharedPtr<sg::BVHNode> node;
171     node = sg::BVHPageNodeOSG::load("w180s90-360x180.spt", options);
172
173     // if no model has been successfully loaded report failure.
174     if (!node.valid()) {
175         SG_LOG(SG_GENERAL, SG_ALERT, arguments.getApplicationName()
176                << ": No data loaded");
177         return EXIT_FAILURE;
178     }
179
180     // We assume that the above is a paged database.
181     sg::BVHPager pager;
182
183     while (std::cin.good()) {
184         // Increment the paging relevant number
185         pager.setUseStamp(1 + pager.getUseStamp());
186         // and expire everything not accessed for the past 30 requests
187         pager.update(10);
188
189         std::string id;
190         std::cin >> id;
191         double lon, lat;
192         std::cin >> lon >> lat;
193         if (std::cin.fail())
194             return EXIT_FAILURE;
195         std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
196
197         SGVec3d start = SGVec3d::fromGeod(SGGeod::fromDegM(lon, lat, 10000));
198         SGVec3d end = SGVec3d::fromGeod(SGGeod::fromDegM(lon, lat, -1000));
199
200         // Try to find an intersection
201         bool found = intersect(*node, pager, start, end, 0);
202         double scale = 1e-5;
203         while (!found && scale <= 1) {
204             found = intersect(*node, pager, start, end, scale);
205             scale *= 2;
206         }
207         if (1e-5 < scale)
208             std::cerr << "Found hole of minimum diameter "
209                       << scale << "m at lon = " << lon
210                       << "deg lat = " << lat << "deg" << std::endl;
211
212         std::cout << id << ": ";
213         if (!found) {
214             std::cout << "-1000" << std::endl;
215         } else {
216             SGGeod geod = SGGeod::fromCart(end);
217             std::cout << std::fixed << std::setprecision(3) << geod.getElevationM() << std::endl;
218         }
219     }
220
221     return EXIT_SUCCESS;
222 }