speeduino/speeduino/table3d.h

130 lines
4.8 KiB
C

/**
* @defgroup table_3d 3D Tables
* @brief Structures and functions related to 3D tables, such as VE, Spark Advance, AFR etc.
*
* Logical:
* - each 3D table is a continuous height map spread over a cartesian (x, y) plane
* - Continuous: we expect to interpolate between any 4 points
* - The axes are
* - Bounded. I.e. non-infinite
* - Non-linear. I.e. x[n]-x[n-1] != x[n+1]-x[n]
* - Increasing. I.e. x[n] >= x[n-1]
* - Do not have to start at [0,0]
*
* E.g. for a 3x3 table, this is what the TS table editor would show:
* <pre>
* Y-Max V6 V7 V8
* Y-Int V3 V4 V5
* Y-Min V0 V1 V2
* X-Min X-Int X-Max
* </pre>
*
* In memory, we store rows in reverse:
* - Both axes are inverted:
* - <c>x[0]</c> stores \c X-Max
* - <c>x[2]</c> stores \c X-Min
* - <c>y[0]</c> stores \c Y-Max
* - <c>y[2]</c> stores \c Y-Min
* - The value locations match the axes.
* - <c>value[0][0]</c> stores \c V6.
* - <c>value[2][0]</c> stores \c V0.
*
* I.e.
* <pre>
* Y-Min V0 V1 V2
* Y-Int V3 V4 V5
* Y-Max V6 V7 V8
* X-Min X-Int X-Max
* </pre>
* @{
*/
/** \file
* @brief 3D table data types and functions
*/
#pragma once
#include "table3d_interpolate.h"
#include "table3d_axes.h"
#include "table3d_values.h"
#define TO_TYPE_KEY(size, xDom, yDom) table3d ## size ## xDom ## yDom ## _key
/**
* @brief Table \b type identifiers. Limited compile time RTTI
*
* With no virtual functions (they have quite a bit of overhead in both space &
* time), we have to pass void* around in certain cases. In order to cast that
* back to a concrete table type, we need to somehow identify the type.
*
* Once approach is to register each type - but that requires a central registry
* which will use RAM.
*
* Since we have a compile time fixed set of table types, we can map a unique
* identifier to the type via a cast - this enum is that unique identifier.
*
* Typically used in conjunction with the '#CONCRETE_TABLE_ACTION' macro
*/
enum table_type_t {
table_type_None,
#define TABLE3D_GEN_TYPEKEY(size, xDom, yDom) TO_TYPE_KEY(size, xDom, yDom),
TABLE3D_GENERATOR(TABLE3D_GEN_TYPEKEY)
};
// Generate the 3D table types
#define TABLE3D_GEN_TYPE(size, xDom, yDom) \
/** @brief A 3D table with size x size dimensions, xDom x-axis and yDom y-axis */ \
struct TABLE3D_TYPENAME_BASE(size, xDom, yDom) \
{ \
typedef TABLE3D_TYPENAME_AXIS(size, xDom) xaxis_t; \
typedef TABLE3D_TYPENAME_AXIS(size, yDom) yaxis_t; \
typedef TABLE3D_TYPENAME_VALUE(size, xDom, yDom) value_t; \
/* This will take up zero space unless we take the address somewhere */ \
static constexpr table_type_t type_key = TO_TYPE_KEY(size, xDom, yDom); \
\
table3DGetValueCache get_value_cache; \
value_t values; \
xaxis_t axisX; \
yaxis_t axisY; \
};
TABLE3D_GENERATOR(TABLE3D_GEN_TYPE)
// Generate get3DTableValue() functions
#define TABLE3D_GEN_GET_TABLE_VALUE(size, xDom, yDom) \
static inline table3d_value_t get3DTableValue(TABLE3D_TYPENAME_BASE(size, xDom, yDom) *pTable, table3d_axis_t y, table3d_axis_t x) \
{ \
return get3DTableValue( &pTable->get_value_cache, \
TABLE3D_TYPENAME_BASE(size, xDom, yDom)::value_t::row_size, \
pTable->values.values, \
pTable->axisX.axis, \
pTable->axisY.axis, \
y, x); \
}
TABLE3D_GENERATOR(TABLE3D_GEN_GET_TABLE_VALUE)
// =============================== Table function calls =========================
// With no templates or inheritance we need some way to call functions
// for the various distinct table types. CONCRETE_TABLE_ACTION dispatches
// to a caller defined function overloaded by the type of the table.
#define CONCRETE_TABLE_ACTION_INNER(size, xDomain, yDomain, action, ...) \
case TO_TYPE_KEY(size, xDomain, yDomain): action(size, xDomain, yDomain, ##__VA_ARGS__);
#define CONCRETE_TABLE_ACTION(testKey, action, defaultAction, ...) \
switch ((table_type_t)testKey) { \
TABLE3D_GENERATOR(CONCRETE_TABLE_ACTION_INNER, action, ##__VA_ARGS__ ) \
default: defaultAction; }
// =============================== Table function calls =========================
table_value_iterator rows_begin(void *pTable, table_type_t key);
table_axis_iterator x_begin(void *pTable, table_type_t key);
table_axis_iterator x_rbegin(void *pTable, table_type_t key);
table_axis_iterator y_begin(void *pTable, table_type_t key);
table_axis_iterator y_rbegin(void *pTable, table_type_t key);
/** @} */