//
// Written by Curtis Olson, started April 1998.
//
-// Copyright (C) 1998 Curtis L. Olson - curt@me.umn.edu
+// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the
-// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-// Boston, MA 02111-1307, USA.
+// 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.
//
// $Id$
#include <simgear/compiler.h>
-#include <stdlib.h> // for exit()
+#include <string>
-#include STL_STRING
-
-#include <simgear/fg_zlib.h>
#include <simgear/debug/logstream.hxx>
-#include <simgear/misc/fgstream.hxx>
+#include <simgear/misc/sgstream.hxx>
+#include <simgear/props/props.hxx>
#include "interpolater.hxx"
-FG_USING_STD(string);
+SG_USING_STD(string);
+
+// Constructor -- starts with an empty table.
+SGInterpTable::SGInterpTable()
+{
+}
+SGInterpTable::SGInterpTable(const SGPropertyNode* interpolation)
+{
+ if (!interpolation)
+ return;
+ std::vector<SGPropertyNode_ptr> entries = interpolation->getChildren("entry");
+ for (unsigned i = 0; i < entries.size(); ++i)
+ addEntry(entries[i]->getDoubleValue("ind", 0.0),
+ entries[i]->getDoubleValue("dep", 0.0));
+}
// Constructor -- loads the interpolation table from the specified
// file
-SGInterpTable::SGInterpTable( const string& file ) {
- FG_LOG( FG_MATH, FG_INFO, "Initializing Interpolator for " << file );
+SGInterpTable::SGInterpTable( const string& file )
+{
+ SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
- fg_gzifstream in( file );
+ sg_gzifstream in( file );
if ( !in.is_open() ) {
- FG_LOG( FG_GENERAL, FG_ALERT, "Cannot open file: " << file );
- exit(-1);
+ SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
+ return;
}
- size = 0;
in >> skipcomment;
while ( in ) {
- if ( size < MAX_TABLE_SIZE ) {
- in >> table[size][0] >> table[size][1];
- in >> skipws;
- size++;
- } else {
- FG_LOG( FG_MATH, FG_ALERT,
- "fgInterpolateInit(): Exceed max table size = "
- << MAX_TABLE_SIZE );
- exit(-1);
- }
+ double ind, dep;
+ in >> ind >> dep;
+ in >> skipws;
+ _table[ind] = dep;
}
}
-// Given an x value, linearly interpolate the y value from the table
-double SGInterpTable::interpolate(double x) {
- int i;
- double y;
-
- i = 0;
-
- while ( (x > table[i][0]) && (i < size) ) {
- // cout << " i = " << i << " table[i][0] = " << table[i][0] << endl;
- // cout << " size = " << size << endl;
- i++;
- }
-
- // printf ("i = %d ", i);
-
- if ( (i == 0) && (x < table[0][0]) ) {
- FG_LOG( FG_MATH, FG_DEBUG,
- "interpolate(): lookup error, x to small = " << x );
- return table[0][1];
- }
-
- // cout << " table[size-1][0] = " << table[size-1][0] << endl;
- if ( x > table[size-1][0] ) {
- FG_LOG( FG_MATH, FG_DEBUG,
- "interpolate(): lookup error, x to big = " << x );
- return table[size-1][1];
- }
-
- // y = y1 + (y0 - y1)(x - x1) / (x0 - x1)
- y = table[i][1] +
- ( (table[i-1][1] - table[i][1]) *
- (x - table[i][0]) ) /
- (table[i-1][0] - table[i][0]);
+// Add an entry to the table.
+void SGInterpTable::addEntry (double ind, double dep)
+{
+ _table[ind] = dep;
+}
- return(y);
+// Given an x value, linearly interpolate the y value from the table
+double SGInterpTable::interpolate(double x) const
+{
+ // Empty table??
+ if (_table.empty())
+ return 0;
+
+ // Find the table bounds for the requested input.
+ Table::const_iterator upBoundIt = _table.upper_bound(x);
+ // points to a value outside the map. That is we are out of range.
+ // use the last entry
+ if (upBoundIt == _table.end())
+ return _table.rbegin()->second;
+
+ // points to the first key must be lower
+ // use the first entry
+ if (upBoundIt == _table.begin())
+ return upBoundIt->second;
+
+ // we know that we do not stand at the beginning, so it is safe to do so
+ Table::const_iterator loBoundIt = upBoundIt;
+ --loBoundIt;
+
+ // Just do linear interpolation.
+ double loBound = loBoundIt->first;
+ double upBound = upBoundIt->first;
+ double loVal = loBoundIt->second;
+ double upVal = upBoundIt->second;
+
+ // division by zero should not happen since the std::map
+ // has sorted out duplicate entries before. Also since we have a
+ // map, we know that we get different first values for different iterators
+ return loVal + (upVal - loVal)*(x - loBound)/(upBound - loBound);
}
// Destructor
-SGInterpTable::~SGInterpTable( void ) {
+SGInterpTable::~SGInterpTable() {
}