Templated Interpolation for Multi-dimensional Inputs. A modern C++17 header-only library for n-dimensional linear interpolation.
TIMI provides efficient multilinear interpolation on rectilinear grids. It supports both 1D interpolation and arbitrary n-dimensional grids, with a clean API that works with custom data types.
Use cases:
- Scientific computing and numerical analysis
- Graphics and color interpolation
- Lookup tables and data approximation
- Signal processing and sensor data
- Header-only - Single
#include, no linking required - No dependencies - Uses only the C++ Standard Library
- 1D and N-dimensional - From simple curves to multidimensional fields
- Dual API - Functional (one-shot) and stateful (reusable) interfaces
- Custom types - Works with any type supporting
+and*operators - Thread-safe - Const sampling operations safe for concurrent use
- Boundary handling - Automatic clamping for out-of-range queries
- C++17 compatible compiler (GCC, Clang, MSVC)
- CMake 3.14+ (for building tests and examples)
- Gtest (for building and running tests)
Copy the include/timi directory to your project:
cp -r include/timi /path/to/your/project/include/Then include in your code:
#include <timi/timi.hpp>Add as a subdirectory:
add_subdirectory(timi)
target_link_libraries(your_target PRIVATE timi)Or use FetchContent:
include(FetchContent)
FetchContent_Declare(
timi
GIT_REPOSITORY https://github.com/your-username/timi.git
GIT_TAG main
)
FetchContent_MakeAvailable(timi)
target_link_libraries(your_target PRIVATE timi)#include <timi/timi.hpp>
// Sample data: pressure vs altitude
std::vector<double> altitude = {0.0, 1000.0, 5000.0, 10000.0};
std::vector<double> pressure = {101.3, 89.9, 54.0, 26.5};
// Create a reusable interpolator
timi::Interpolator1D<double, double> interp(altitude, pressure);
// Query at any point
double p = interp(2500.0); // Interpolated pressure at 2500m// Define a 3x3 temperature grid
std::vector<std::vector<double>> axes = {
{0.0, 5.0, 10.0}, // x-axis (meters)
{0.0, 5.0, 10.0} // y-axis (meters)
};
// Values in row-major order (x varies fastest)
std::vector<double> temperatures = {
20.0, 22.0, 25.0, // y=0
21.0, 24.0, 28.0, // y=5
23.0, 27.0, 32.0 // y=10
};
timi::InterpolatorND<double, double> temp_field(axes, temperatures);
// Query at any point
double t = temp_field({2.5, 7.5}); // Temperature at (2.5, 7.5)Any type with operator+ and operator* works:
struct Color {
double r, g, b;
};
Color operator+(const Color& a, const Color& b) {
return {a.r + b.r, a.g + b.g, a.b + b.b};
}
Color operator*(const Color& c, double s) {
return {c.r * s, c.g * s, c.b * s};
}
// Create a color gradient
std::vector<double> positions = {0.0, 0.5, 1.0};
std::vector<Color> colors = {
{1.0, 0.0, 0.0}, // Red
{0.0, 1.0, 0.0}, // Green
{0.0, 0.0, 1.0} // Blue
};
timi::Interpolator1D<double, Color> gradient(positions, colors);
Color c = gradient(0.25); // Interpolated colorOne-shot interpolation without storing data:
// 1D interpolation
template<typename Scalar, typename T>
T timi::interpolate(
const std::vector<Scalar>& x_vals, // Sorted ascending coordinates
const std::vector<T>& y_vals, // Corresponding values
Scalar x // Query point
);
// N-D interpolation
template<typename Scalar, typename T>
T timi::interpolate(
const std::vector<std::vector<Scalar>>& axes, // Coordinate vectors per dimension
const std::vector<T>& values, // Flat array in row-major order
const std::vector<Scalar>& point // Query point
);Reusable interpolators that store data:
// 1D interpolator
template<typename Scalar, typename T>
class timi::Interpolator1D {
Interpolator1D(std::vector<Scalar> x_vals, std::vector<T> y_vals);
T operator()(Scalar x) const;
const std::vector<Scalar>& x_values() const;
const std::vector<T>& y_values() const;
std::size_t size() const;
};
// N-D interpolator
template<typename Scalar, typename T>
class timi::InterpolatorND {
InterpolatorND(std::vector<std::vector<Scalar>> axes, std::vector<T> values);
T operator()(const std::vector<Scalar>& point) const;
std::size_t num_dimensions() const;
const std::vector<std::vector<Scalar>>& axes() const;
const std::vector<T>& values() const;
};For N-dimensional grids, values are stored in row-major order where the first axis varies fastest:
2D example with axes x=[0,1], y=[0,1]:
values = {f(0,0), f(1,0), f(0,1), f(1,1)}
└─x=0─┘ └─x=1─┘ └─x=0─┘ └─x=1─┘
y=0 y=0 y=1 y=1
- Coordinate vectors must be sorted in ascending order
- Each axis requires at least 2 points
- Value count must equal the product of axis sizes
- Maximum 16 dimensions supported
# Configure and build
cmake -B build
cmake --build build
# Run tests
cd build && ctest --output-on-failure
# Or run directly
./build/timi_tests
# Run examples
./build/basic_2d
./build/custom_classContributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE fore the details.