Giter VIP home page Giter VIP logo

splinelibrary's Introduction

SplineLibrary

A C++ library created to provide open-source reference implementations of many spline functions, e.g. Natural Splines and Catmull-Rom Splines. It's a challenge to find well-documented and FOSS implementations of these useful tools, and mathematical defintions of these things are really hard to decipher, so my hope is that this library will provide a starting point for others.

A spline is a formula for smoothly transitioning from one data point to the next in a data set. For example, you could create a spline containing ten colors (each stored as R, G, and B values) to create a color gradient that smoothly transitions from one color to the next.

Example

Create a Catmull-Rom Spline with four data points, and compute the interpolated position at T = 0.5

std::vector<QVector2D> splinePoints{
    QVector2D( 0, 0),
    QVector2D( 5, 0),
    QVector2D( 8, 3),
    QVector2D( 6, 1),
};
UniformCRSpline<QVector2D> mySpline(splinePoints);
QVector2D interpolatedPosition = mySpline.getPosition(0.5f);

Features

  • Interpolation of catmull-rom splines
    • Include spline_library/splines/uniform_cr_spline.h, create a UniformCRSpline object, and call its getPosition method.
    • Several more spline types. See Spline Types for the full list
  • Looping Splines
    • Also called "Periodic" or "Cyclic": These splines form a loop, in that the ending connects with the beginning
    • Calling getPosition(t) with an out-of-range T value will "wrap around" to the other end of the spline
    • To make a looping catmull-rom spline, include spline_library/splines/uniform_cr_spline.h and create a LoopingUniformCRSpline object.
    • Every spline type has both looping and non-looping variants
  • Compute the arc length of a spline
    • Call a spline's totalLength() method to find the arc length of the entire spline
    • Call a spline's arcLength(a,b) method to find the arc length between two arbitrary T values
  • Compute the inverse of a spline
    • Given a data point (not necessarily on the spline, or even close to it), what T value brings the spline closest to that data point?
    • Create a SplineInverter object and call its findClosestT method
  • Computation of the first, second, and third derivatives of the spline
    • The first derivative is called the "tangent" - this is how quickly and in what direction the interpolated position is changing, per T
    • The second derivative is called the "curvature" - this is how quickly and in what direction the interpolated tangent is changing, per T
    • The third derivative is called the "wiggle" - this is how quickly and in what direction the interpolated curvature is changing, per T

Documentation

Glossary - Glossary of important terms for understanding splines.

Spline class API - API documentation of the Spline base class.

Spline Types - Complete list of all supported spline formulas

Spline Utilities - Documentation of some utility classes for splines.

Project Layout

The root of the repository is a Qt Creator project that demonstrates some uses of the library. The source for the spline code itself is in the "spline_library" directory, and the code to set up the demo is in the "demo" directory.

Usage

Drop the spline_library directory in the root source folder of your project. It's header-only, so from here all you need to do is import it from your own code.

spline_library/spline_inverter.h and spline_library/arclength.h depend on Boost's Math module. If you don't want to install Boost, you can safely avoid including these two files - nothing else includes it, and nothing else relies on Boost.

Both the demo and the spline_library code require a fully compliant C++14 compiler.

Demo

Follow these steps to run the demo (Assuming you already have Qt 5.5+ installed and working):

  1. Install Boost. On Linux, this is in most package managers. On Mac, it can be installed via homebrew. Otherwise, visit http://www.boost.org/

  2. Create a file called SplineDemo_Include.pri in the root of the project

  3. In this file, paste the following, where /path/to/boost contains Boost's include files.

    INCLUDEPATH += "/path/to/boost"

    On windows, this might be: INCLUDEPATH += "C:\Boost\boost_1_60_0"

    On Mac, this might be: INCLUDEPATH += /usr/local/Cellar/boost/1.59.0/include

  4. Run qmake on SplineDemo.pro to generate a makefile, then build the makefile, and run the compiled executable

  5. OR, open SplineDemo.pro in Qt Creator and press play

License

This code is available under the Simplified BSD License

This project includes the nanoflann library for fast nearest-neighbor queries, which is also available under the Simplified BSD License

To-Do

  • Implement "composite splines", ie a spline that is made by combining two or more splines. Current ideas include a "sum spline" where the output for a given T is a sum of all the child spline results at T, and a "concatenation spline" formed simply by starting one spline where the previous leaves off.
  • More spline types as I discover them
  • Find an actual mathematical definition for the quintic catmull-rom spline. The quintic cubic hermite spline is well-defined, but I basically guessed on how to automatically compute the tangents and curvatures based on the input points for the catmull-rom equivalent.

splinelibrary's People

Contributors

abiso avatar ejmahler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

splinelibrary's Issues

A question about use the library

as the example in depository:

/////////////////////////////////////////////////////////////////////////////////////////////
std::vector splinePoints{
QVector2D( 0, 0),
QVector2D( 5, 0),
QVector2D( 8, 3),
QVector2D( 6, 1),
};
UniformCRSpline mySpline(splinePoints);
QVector2D interpolatedPosition = mySpline.getPosition(0.5f);
/////////////////////////////////////////////////////////////////////////////////////////////

I test it, and get the result, the interpolatedPosition is a point between second point "QVector2D( 5, 0)" and third point "QVector2D( 8, 3)", why?
In my mind, the result should be a point between first point "QVector2D( 0, 0)" and second point "QVector2D( 5, 0)", Am I wrong?
Hope for your reply, thank you.

Where can I find example code?

I'm having difficulties in understanding the library.

Specifically,

How can getPosition(floating_t t) be looped over so that the loop goes through "all t"?
Where do I find all t parameters that I must loop over?

Where can I see example code?

Typo in Glossary

In the "Continuous" section, "In order to meat this goal" should be "In order to meet this goal".

There are also a couple instances of missing u's. ("continous" instead of "continuous").

function suggestion

Dear ejmahler
Many thanks for SplineLibrary write by QT.
Cloud you add some function for SplineLibrary?
Exm as below.
function no. list
s1850 - Find all the intersections between a curve and a plane (if curve dimension and dim = 3) or a curve and a line (if curve dimension and dim = 2).
s1240 - Compute the length of a curve. The length calculated will not deviate more than epsge divided by the calculated length, from the real length of the curve.
s1364 - To check if a curve is closed, i.e. test if the distance between the end points of the curve is less than a given tolerance.
s1363 - To pick the parameter range of a curve.
s1241 - To calculate the area between a 2D curve and a 2D point. When the curve is rotating counter-clockwise around the point, the area contribution is positive. When the curve is rotating clockwise around the point, the area contribution is negative. If the curve is closed or periodic, the area calculated is independent of where the point is situated. The area is calculated exactly for B-spline curves, for NURBS the result is an approximation. This routine will only perform if the order of the curve is less than 7 (can easily be extended).
s1243 - To calculate the weight point and rotational momentum of an area between a 2D curve and a 2D point. The area is also calculated. When the curve is rotating counter-clockwise around the point, the area contribution is positive. When the curve is rotating clockwise around the point, the area contribution is negative. OBSERVE: FOR CALCULATION OF AREA ONLY, USE s1241().

Above functions is provided in project https://github.com/SINTEF-Geometry/SISL .
Now, i am using SISL.
Hope SplineLibrary will have above functions as QT is a better tool.

best regards,
jeff

tangent and curvature

Hello i am trying to use the library to fit splines on some data. It looks like the derivatives are not working properly.
Maybe i am using the library in the wrong way.
From what i can see the time is not exactly related to the x of each point.
I compute the first derivative at time t : auto d1 = ucbs.getTangent(u).tangent;
I compute the second derivative at time t : auto d2 = ucbs.getCurvature(u).curvature;

then i extract x and y and plot them.
The data are really simple:
(x,y);
(1, 30);
(2, 29);
(3, 27);
(4, 24);
(5, 20);
(6, 16);
(7, 9);

here the curve fitted with an uniform bspline and the two derivatives from the library:
uniform_cr_spline
fist_derivative_unif_bspl
second_derivative_unif_bspl

can you help me? Am i using the lib in the wrong way?

cubic spline tangent

Hello I try to use get cubic spline tangent, then compute normal dir of tangent to offset spline. but it strange as showing follow image:
ๅ›พ็‰‡
What may this problem?

Strange results comparing arcLength and totalLength

I'm playing with the demo and see the following: with the default point values, immediately after creating the spline, spline.arcLength(0, spline.getMaxT()) is not equal to spline.totalLength(), and the difference is quite significant (1699.87671 for the arcLength, 1666.14331 for the totalLength). This is for Normal Cubic Spline.

Feature request: equidistant split of a spline

Would be nice to have an API to equidistantly split a spline, like this:
std::vector<floating_t> Spline::splitByDistance (floating_t distance, floating_t tolerance)

Then the use case would be
std::vector<floating_t> result = aSpline.splitByDistance(distance, tolerance)

meeting this condition:
fabs (aSpline.arcLength (result[i], result[i+1]), distance) < tolerance

Apparently there is an implementation for matlab: https://se.mathworks.com/matlabcentral/fileexchange/34874-interparc

We have to scale this by the inverse of the t distance?

Came across

//tests and such have shown that we have to scale this by the inverse of the t distance, and i'm not sure why
//intuitively it would just be the 2nd derivative of the position function and nothing else
//if you know why please let me know

My uneducated guess:
https://stackoverflow.com/a/23980479/4599792 , 3rd paragraph:

One caveat is that the above tangents are computed for the interval (t1,t2), so if you want to evaluate the curve in the standard interval (0,1), simply rescale the tangents by multiplying them with the factor (t2-t1).

Do we have here exactly the opposite case: tangents are computed for the interval (0,1) and therefore the necessity to "to scale this by the inverse of the t distance"?

can use these spline with constant speed

Hi,
The spline has any issue that is hard to use, when a obj follow the spline, the speed is non-constant, do you have any way to solve this behavior? I know this is a common issue of the algorithm.
Thank you for your time!

a pointer to related work

Hi there!

I'd like to point you to my b-spline library vspline. Currently, it supports canonic b-splines only, but I've just opened up the evaluation code to use non-b-spline basis functions, so it may work for other types of splines as well. It's very comprehensive, and on top of the 'standard' b-spline code (prefiltering, point evaluation) it provides code for processing large raster data sets with multithreading and SIMD. Have a look! It may be the 'well-documented and FOSS implementation' you say you're missing.

With regards
Kay F. Jahnke

Arc length parameterization?

I am using your spline library to generate splines for moving a robot, and have been using the LoopingCubicHermiteSpline version successfully for a while. I am currently picking points from the spline based on time in a loop, so more or less at even steps in T. What I am experiencing, though, is that the arc length traversed between each step varies a lot (which is to be expected). What would be better for me is some sort of arc length parameterization that would allow me to sample points from the spline based on the arc length, not the internal T value. This would give me constant speed for the robot, given even steps in time.

I was looking at the ArcLength::partition function, and was wondering if that would work? I assume it would if I just gave it the current arc length point (based on time) I want, and throw away all but the first point? Is there a better way to go about this with the current code, or is there an easy addition that could be done to the code to allow this?

Wrong arcLength result

I'm looking on data like this:

Vector<3, double> points:
[0] (0.00000000000000000,0.00000000000000000,0.00000000000000000)
[1] (1.0000000000000000,0.00000000000000000,0.00000000000000000)
[2] (4.0000000000000000,0.00000000000000000,0.00000000000000000)
[3] (9.0000000000000000,0.00000000000000000,0.00000000000000000)
[4] (16.000000000000000,0.00000000000000000,0.00000000000000000)
[5] (25.000000000000000,0.00000000000000000,0.00000000000000000)

NaturalSpline<Vector<3,double>, double> spline(points, true, 0.5);
double t = 0.38215637207031250, t0 = 0.47108459472656250;

Then I get this:

	spline.arcLength(t0, t0 +t)	 == 0.50000331420977806

but:
spline.getPosition(t0) == (1.0000076740967552,0.00000000000000000,0.00000000000000000)

and
spline.getPosition(t0 + t) == (2.2312049143150867,0.00000000000000000,0.00000000000000000)

Since all the points are on the same straight line (and looks like there's no wiggles between t0 and t0 + t), I'd expect arcLength to be 1.2312....

QVector2D compile issue

hello,
can anybody watching/discussing this repo provide an example how to use the library
without QT?
Basically a bootstart simple example how to instantiate the spline?
I tried to exchange QVector2D for Vector2 but not working.
thanks a lot

Qt Demo: no change for alpha=0.5

Hello.
cat_mull_rom_05

As you see in the pic above, the centripetal variation does not avoid certain types of self-intersections...

It could be however a pure Qt problem, as startin the app from the Qt Creator I get warnings:

QMetaObject::connectSlotsByName: No matching signal for on_lineEdit_changed(QString)
QMetaObject::connectSlotsByName: No matching signal for on_checkBox_changed(bool)
QMetaObject::connectSlotsByName: No matching signal for on_spinBox_changed(int)
QMetaObject::connectSlotsByName: No matching signal for on_doubleSpinBox_changed(double)
QMetaObject::connectSlotsByName: No matching signal for on_slider_changed(int)

My OS: Windows 8.1
Qt versions I tried out: 5.8 an 5.9.1, both 64 bit.
Compiler: MSVC 2015 in both cases.

SplineLibrary cannot be compiled with g++/MinGW-w64

The library looks really interesting. It seems as if there were not too many C++ libraries offering quintic splines. Unfortunately MinGW-w64 won't compile the code. It seems as if the code is unclean, but MSVC tolerates much more than MinGW-w64 does.

accessing segments and knots

I needed to access the segments and knots from the NaturalSpline, because I am using the library to compute these values so I can re-use them later on in a different context. For that I added functions

NaturalSplineCommon::segments() const
NaturalSplineCommon::knots() const

Additionally the members variables have been renamed:

NaturalSplineCommon::mSegments;
NaturalSplineCommon::mKnots;

Find attached the patch to make the modification:

NaturalSpline_segments_knots.diff.zip

Maybe it's worth extended the interface such that this kind of information is accessible in general way. This patch just does it for the natural spline.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.