]> git.mxchange.org Git - flightgear.git/blob - utils/fgelev/fgelev.cxx
add command line option --expire to fgelev, overriding the hardcoded
[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     unsigned expire;
97     if (arguments.read("--expire", expire)) {
98     } else expire = 10;
99     
100     std::string fg_root;
101     if (arguments.read("--fg-root", fg_root)) {
102     } else if (const char *fg_root_env = std::getenv("FG_ROOT")) {
103         fg_root = fg_root_env;
104     } else {
105         fg_root = PKGLIBDIR;
106     }
107
108     std::string fg_scenery;
109     if (arguments.read("--fg-scenery", fg_scenery)) {
110     } else if (const char *fg_scenery_env = std::getenv("FG_SCENERY")) {
111         fg_scenery = fg_scenery_env;
112     } else {
113         SGPath path(fg_root);
114         path.append("Scenery");
115         fg_scenery = path.str();
116     }
117
118     SGSharedPtr<SGPropertyNode> props = new SGPropertyNode;
119     try {
120         SGPath preferencesFile = fg_root;
121         preferencesFile.append("preferences.xml");
122         readProperties(preferencesFile.str(), props);
123     } catch (...) {
124         // In case of an error, at least make summer :)
125         props->getNode("sim/startup/season", true)->setStringValue("summer");
126
127         SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading FlightGear preferences.\n"
128                << "Probably FG_ROOT is not properly set.");
129     }
130
131     /// now set up the simgears required model stuff
132
133     simgear::ResourceManager::instance()->addBasePath(fg_root, simgear::ResourceManager::PRIORITY_DEFAULT);
134     // Just reference simgears reader writer stuff so that the globals get
135     // pulled in by the linker ...
136     simgear::ModelRegistry::instance();
137
138     sgUserDataInit(props.get());
139     SGMaterialLibPtr ml = new SGMaterialLib;
140     SGPath mpath(fg_root);
141     mpath.append("Materials/default/materials.xml");
142     try {
143         ml->load(fg_root, mpath.str(), props);
144     } catch (...) {
145         SG_LOG(SG_GENERAL, SG_ALERT, "Problems loading FlightGear materials.\n"
146                << "Probably FG_ROOT is not properly set.");
147     }
148     simgear::SGModelLib::init(fg_root, props);
149
150     // Set up the reader/writer options
151     osg::ref_ptr<simgear::SGReaderWriterOptions> options;
152     if (osgDB::Options* ropt = osgDB::Registry::instance()->getOptions())
153         options = new simgear::SGReaderWriterOptions(*ropt);
154     else
155         options = new simgear::SGReaderWriterOptions;
156     osgDB::convertStringPathIntoFilePathList(fg_scenery,
157                                              options->getDatabasePathList());
158     options->setMaterialLib(ml);
159     options->setPropertyNode(props);
160     options->setReadFileCallback(new ReadFileCallback);
161     options->setPluginStringData("SimGear::FG_ROOT", fg_root);
162     // we do not need the builtin boundingvolumes
163     options->setPluginStringData("SimGear::BOUNDINGVOLUMES", "OFF");
164     // And we only want terrain, no objects on top.
165     options->setPluginStringData("SimGear::FG_ONLY_TERRAIN", "ON");
166     props->getNode("sim/rendering/random-objects", true)->setBoolValue(false);
167     props->getNode("sim/rendering/random-vegetation", true)->setBoolValue(false);
168
169     // Here, all arguments are processed
170     arguments.reportRemainingOptionsAsUnrecognized();
171     arguments.writeErrorMessages(std::cerr);
172
173     // Get the whole world bvh tree
174     SGSharedPtr<sg::BVHNode> node;
175     node = sg::BVHPageNodeOSG::load("w180s90-360x180.spt", options);
176
177     // if no model has been successfully loaded report failure.
178     if (!node.valid()) {
179         SG_LOG(SG_GENERAL, SG_ALERT, arguments.getApplicationName()
180                << ": No data loaded");
181         return EXIT_FAILURE;
182     }
183
184     // We assume that the above is a paged database.
185     sg::BVHPager pager;
186
187     while (std::cin.good()) {
188         // Increment the paging relevant number
189         pager.setUseStamp(1 + pager.getUseStamp());
190         // and expire everything not accessed for the past 30 requests
191         pager.update(expire);
192
193         std::string id;
194         std::cin >> id;
195         double lon, lat;
196         std::cin >> lon >> lat;
197         if (std::cin.fail())
198             return EXIT_FAILURE;
199         std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
200
201         SGVec3d start = SGVec3d::fromGeod(SGGeod::fromDegM(lon, lat, 10000));
202         SGVec3d end = SGVec3d::fromGeod(SGGeod::fromDegM(lon, lat, -1000));
203
204         // Try to find an intersection
205         bool found = intersect(*node, pager, start, end, 0);
206         double scale = 1e-5;
207         while (!found && scale <= 1) {
208             found = intersect(*node, pager, start, end, scale);
209             scale *= 2;
210         }
211         if (1e-5 < scale)
212             std::cerr << "Found hole of minimum diameter "
213                       << scale << "m at lon = " << lon
214                       << "deg lat = " << lat << "deg" << std::endl;
215
216         std::cout << id << ": ";
217         if (!found) {
218             std::cout << "-1000" << std::endl;
219         } else {
220             SGGeod geod = SGGeod::fromCart(end);
221             std::cout << std::fixed << std::setprecision(3) << geod.getElevationM() << std::endl;
222         }
223     }
224
225     return EXIT_SUCCESS;
226 }