#include <simgear/structure/event_mgr.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/timing/sg_time.hxx>
-#include <simgear/misc/interpolator.hxx>
#include <simgear/io/HTTPRequest.hxx>
#include <FDM/flight.hxx>
#include "fg_os.hxx"
#include "fg_commands.hxx"
#include "fg_props.hxx"
+#include "FGInterpolator.hxx"
#include "globals.hxx"
#include "logger.hxx"
#include "util.hxx"
* Built-in command: interpolate a property value over time
*
* property: the name of the property value to interpolate.
+ * type: the interpolation type ("numeric", "color", etc.)
+ * easing: name of easing function (see http://easings.net/)
* value[0..n] any number of constant values to interpolate
* time/rate[0..n] time between each value, number of time elements must
* match those of value elements. Instead of time also rate can
* be used which automatically calculates the time to change
* the property value at the given speed.
* -or-
- * property[1..n] any number of target values taken from named properties
+ * property[1..n+1] any number of target values taken from named properties
* time/rate[0..n] time between each value, number of time elements must
* match those of value elements. Instead of time also rate can
* be used which automatically calculates the time to change
static bool
do_property_interpolate (const SGPropertyNode * arg)
{
- SGPropertyNode * prop = get_prop(arg);
+ FGInterpolator* mgr =
+ static_cast<FGInterpolator*>
+ (
+ globals->get_subsystem_mgr()
+ ->get_group(SGSubsystemMgr::INIT)
+ ->get_subsystem("prop-interpolator")
+ );
- simgear::PropertyList valueNodes = arg->getChildren( "value" );
- simgear::PropertyList timeNodes = arg->getChildren( "time" );
- simgear::PropertyList rateNodes = arg->getChildren( "rate" );
+ if( !mgr )
+ {
+ SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
+ return false;
+ }
- if( !timeNodes.empty() && !rateNodes.empty() )
- // mustn't specify time and rate
- return false;
+ SGPropertyNode * prop = get_prop(arg);
+ simgear::PropertyList time_nodes = arg->getChildren("time");
+ simgear::PropertyList rate_nodes = arg->getChildren("rate");
- simgear::PropertyList::size_type num_times = timeNodes.empty()
- ? rateNodes.size()
- : timeNodes.size();
+ if( !time_nodes.empty() && !rate_nodes.empty() )
+ // mustn't specify time and rate
+ return false;
- boost::scoped_array<double> value;
- boost::scoped_array<double> time;
+ simgear::PropertyList::size_type num_times = time_nodes.empty()
+ ? rate_nodes.size()
+ : time_nodes.size();
- if( valueNodes.size() > 0 ) {
- // must match
- if( num_times != valueNodes.size() )
- return false;
+ simgear::PropertyList value_nodes = arg->getChildren("value");
+ if( value_nodes.empty() )
+ {
+ simgear::PropertyList prop_nodes = arg->getChildren("property");
- value.reset( new double[valueNodes.size()] );
- for( simgear::PropertyList::size_type n = 0; n < valueNodes.size(); n++ ) {
- value[n] = valueNodes[n]->getDoubleValue();
- }
- } else {
- valueNodes = arg->getChildren("property");
- // must have one more property node
- if( valueNodes.size() - 1 != num_times )
- return false;
+ // must have one more property node
+ if( prop_nodes.size() != num_times + 1 )
+ return false;
- value.reset( new double[valueNodes.size()-1] );
- for( simgear::PropertyList::size_type n = 0; n < valueNodes.size()-1; n++ ) {
- value[n] = fgGetNode(valueNodes[n+1]->getStringValue(), "/null")->getDoubleValue();
- }
+ value_nodes.reserve(num_times);
+ for( size_t i = 1; i < prop_nodes.size(); ++i )
+ value_nodes.push_back( fgGetNode(prop_nodes[i]->getStringValue()) );
+ }
- }
+ // must match
+ if( value_nodes.size() != num_times )
+ return false;
- time.reset( new double[num_times] );
- if( !timeNodes.empty() ) {
- for( simgear::PropertyList::size_type n = 0; n < num_times; n++ ) {
- time[n] = timeNodes[n]->getDoubleValue();
- }
- } else {
- for( simgear::PropertyList::size_type n = 0; n < num_times; n++ ) {
- double delta = value[n]
- - (n > 0 ? value[n - 1] : prop->getDoubleValue());
- time[n] = fabs(delta / rateNodes[n]->getDoubleValue());
- }
+ double_list deltas;
+ deltas.reserve(num_times);
+
+ if( !time_nodes.empty() )
+ {
+ for( size_t i = 0; i < num_times; ++i )
+ deltas.push_back( time_nodes[i]->getDoubleValue() );
+ }
+ else
+ {
+ for( size_t i = 0; i < num_times; ++i )
+ {
+ // TODO calculate delta based on property type
+ double delta = value_nodes[i]->getDoubleValue()
+ - ( i > 0
+ ? value_nodes[i - 1]->getDoubleValue()
+ : prop->getDoubleValue()
+ );
+ deltas.push_back( fabs(delta / rate_nodes[i]->getDoubleValue()) );
}
+ }
- ((SGInterpolator*)globals->get_subsystem_mgr()
- ->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator"))
- ->interpolate(prop, num_times, value.get(), time.get() );
+ mgr->interpolate
+ (
+ prop,
+ arg->getStringValue("type", "numeric"),
+ value_nodes,
+ deltas,
+ arg->getStringValue("easing", "linear")
+ );
- return true;
+ return true;
}
/**
#include <simgear/math/sg_random.h>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sg_dir.hxx>
-#include <simgear/misc/interpolator.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/structure/event_mgr.hxx>
#include <Main/globals.hxx>
#include <Main/util.hxx>
#include <Main/fg_props.hxx>
-
+#include <Main/FGInterpolator.hxx>
using std::map;
// value/delta numbers.
static naRef f_interpolate(naContext c, naRef me, int argc, naRef* args)
{
- SGPropertyNode* node;
- naRef prop = argc > 0 ? args[0] : naNil();
- if(naIsString(prop)) node = fgGetNode(naStr_data(prop), true);
- else if(naIsGhost(prop)) node = *(SGPropertyNode_ptr*)naGhost_ptr(prop);
- else return naNil();
-
- naRef curve = argc > 1 ? args[1] : naNil();
- if(!naIsVector(curve)) return naNil();
- int nPoints = naVec_size(curve) / 2;
- double* values = new double[nPoints];
- double* deltas = new double[nPoints];
- for(int i=0; i<nPoints; i++) {
- values[i] = naNumValue(naVec_get(curve, 2*i)).num;
- deltas[i] = naNumValue(naVec_get(curve, 2*i+1)).num;
- }
+ FGInterpolator* mgr =
+ static_cast<FGInterpolator*>
+ (
+ globals->get_subsystem_mgr()
+ ->get_group(SGSubsystemMgr::INIT)
+ ->get_subsystem("prop-interpolator")
+ );
+ if( !mgr )
+ {
+ SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available");
+ return naNil();
+ };
- ((SGInterpolator*)globals->get_subsystem_mgr()
- ->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator"))
- ->interpolate(node, nPoints, values, deltas);
+ SGPropertyNode* node;
+ naRef prop = argc > 0 ? args[0] : naNil();
+ if(naIsString(prop)) node = fgGetNode(naStr_data(prop), true);
+ else if(naIsGhost(prop)) node = *(SGPropertyNode_ptr*)naGhost_ptr(prop);
+ else return naNil();
- delete[] values;
- delete[] deltas;
- return naNil();
+ naRef curve = argc > 1 ? args[1] : naNil();
+ if(!naIsVector(curve)) return naNil();
+ int nPoints = naVec_size(curve) / 2;
+
+ simgear::PropertyList value_nodes;
+ value_nodes.reserve(nPoints);
+ double_list deltas;
+ deltas.reserve(nPoints);
+
+ for( int i = 0; i < nPoints; ++i )
+ {
+ SGPropertyNode* val = new SGPropertyNode;
+ val->setDoubleValue(naNumValue(naVec_get(curve, 2*i)).num);
+ value_nodes.push_back(val);
+ deltas.push_back(naNumValue(naVec_get(curve, 2*i+1)).num);
+ }
+
+ mgr->interpolate
+ (
+ node,
+ "numeric",
+ value_nodes,
+ deltas,
+ "linear"
+ );
+
+ return naNil();
}
// This is a better RNG than the one in the default Nasal distribution