<p>The two graphs are graphing Cubic Splines but they are not equivalent splines. The method used in the code you linked produces a curve that is very local to the points and produces the tightest fit to a data set of any of the curves. This curve is only affect by adjacent (knots) control points.</p>
<p>The method used in the online calculator produces a similar curve but individual segments are affected by control points that are up to 2 positions away which change the tangent and causes the big dips in the curve shown in the graph.</p>
<p>You should be able to convince yourself of this by looking at the two matrices used in the solution for both curves. The tridiagonal matrix can only affect adjacent rows and columns where as the matrix shown in the solution for the online calculator effects several rows and columns, this translates to very different curves.</p>
<p>I attempted to use Mathematica to check the curve produced by the linked code but the resulting curve (as described by the wolfram math web link in the references you gave) was not even a cubic spline.</p>
<p>I was able to verify the curve output by the online calculator in the web link using Maple, they both produce almost identical equations. MatLab supposedly has a function that will produce the same spline linked in your code but I don't have access to that program so wasn't able to verify it.</p>
<p>I started to convert the equations between implicit/explicit/parametric forms but that turned into more math then I am willing to do (and I didn't want to post a  massive list of equations showing the conversion). But these are not implicit vs parametric forms of the same curve anyway so it would have been kind of pointless.</p>
<p>After all that I decided to implement my own version of the spline solver from the book wolfram references. ( I managed to get a used copy on the cheap ) My solution ended up being very similar to the code you linked and produced very similar results. The curves were slightly smoother at the control points but I think that I was using a different method of computing the values...along the lines of:</p>
<pre><code>segment_count = knot_count -1;
vec4 solved_coefficients[segment_count];
vec2 curve[segment_count *100];
for each segment_count
  vec4 coeff = solved_coefficients[segment];
  for x=0 x&lt;100; x++;
     t = 1.0/x;
     curve[knot*x] = calcPointOnLine( coeff, t);
</code></pre>
<p>This turned out to be a fun little side project into the different versions of fitted cubic splines.</p>
<p><strong>Edit:</strong>
The problem is that the terminology used to describe the splines is used so interchangeably that the different solutions which produce very different splines are given the same names. I found one paper which used the name &quot;Cubic Hermite Spline&quot; for the what we implemented,  and it gave the name &quot;Cubic Spline&quot; for what the online calculator implemented.</p>
<p>It is also possible to make the splines equivalent to each other by playing with the knot positions. I refitted the Cubic spline to a Cubic Hermite by moving/adding knot positions separated by a distance of 1 and got exactly the same splines from both solutions. The other direction (which I didn't try) is to fit the cubic Hermite spline to the cubic spline by changing the knot sequence from 0,1,2,3 to 0,141,149,255.</p>
<p>When it is all said and done I think it is more about what kind of fit works best for your algorithm.</p>

CC BY-SA 4.0
2021-09-26T15:08:16.207Z
Dang bro, that's one heck of an effort. So in the end, this means the implementation is alright. But we still don't know what this implementation actually represents? I think it's a cubic spline but as you said it's different in the sense where only the adjacent knots affect the segment. I still don't get why or how parametric or implicit forms can produce this difference i.e. parameteric form produces a spline where the only adjacent knots affect the curve where as in implicit a small change in a knot can affect more than the adjacent knots.
gallickgunner
CC BY-SA 4.0
2021-09-26T23:41:00.827Z
The only thing the two solutions have in common is the fact that they pass through the set of points and are both cubic. They are very different ways of fitting a cubic curve to a set of points and the fact that one produces a parametric equation while the other produces an explicit solution is just a side effect of the approach used. (oh and I added an edit)
pmw1234
CC BY-SA 4.0
2021-09-26T23:47:00.803Z
Oh, one more little detail is the wolfram solution avoids Runge's Phenomenon better then any other approach so it is possible to use an algorithm that can reduce it sample points to a minimum number and still get reasonably accurate results.
pmw1234
CC BY-SA 4.0
2021-09-27T06:45:06.627Z
This cleared up many details. Thanks for the effort mate, much appreciated.
gallickgunner
CC BY-SA 4.0
2021-09-27T10:41:08.900Z
I just bumbled across this web page which is yet another way to compute the spline, it also discusses 1d vs 2d vs 3d, there are links to demos at the bottom of the page to :https://blog.demofox.org/2015/08/08/cubic-hermite-interpolation/
pmw1234
CC BY-SA 4.0
2021-09-26T14:04:08.460Z
2021-09-26T23:38:01.113Z
2021-09-26T23:38:01.113Z
pmw1234
<p>I asked a similar question here before but since the previous post original question was different, I think it was confusing people. So I've voted to close that and asking the new question here. I'm doing a volume rendering project and made a cubic spline editor for transfer function. I used <a href="http://graphicsrunner.blogspot.com/2008/05/camera-animation-part-ii.html" rel="nofollow noreferrer">this</a> as a source which basically uses Wolfram as the main source. Now Wolfram defines a parametric representation. After I made it, I tried to compare it online but the curves are different. The only difference I found is that the online version is using a non-parametric representation.</p>
<p>Here's mine.
<a href="https://i.sstatic.net/Yo4am.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/Yo4am.png" alt="enter image description here" /></a></p>
<p>And here's the online version
<a href="https://i.sstatic.net/fEXlf.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/fEXlf.png" alt="enter image description here" /></a></p>
<p>In order to clarify a bit more on what I'm trying to do. I have 2 variables.</p>
<p><span class="math-container">$X = [0, 255] $</span></p>
<p><span class="math-container">$Y = [0, 1] $</span></p>
<p>For every given <span class="math-container">$X$</span> value I need the interpolated <span class="math-container">$Y$</span> value. At first glance it seems that the explicit form of cubic spline is what I want. But I have another case where <span class="math-container">$Y$</span> values are RGB triplets <span class="math-container">$(r,g,b)$</span>. Since the parametric representation doesn't have to deal with dimensions and since the code was already online I'm using the parametric form. The parametric form uses the parameter <span class="math-container">$t \in [0,1]$</span> for every segment.</p>
<p>Now things get a little trickier. Technichally my graph is of <span class="math-container">$(t, Y(t))$</span> but as you can see in the first picture the X-axis isn't <span class="math-container">$t$</span> but the previously defined <span class="math-container">$X$</span> which is in range <span class="math-container">$[0-255]$</span>. I'm simply rescaling between <span class="math-container">$X$</span> and <span class="math-container">$t$</span>. So if I get <span class="math-container">$t = 0.5$</span> for the first segment as an example, I'd take the two bounding control points which resolve to <span class="math-container">$(0,0)$</span> and <span class="math-container">$(141, 0.759)$</span> in the first picture. Then do simple rescaling like</p>
<p><span class="math-container">$0 + (141 - 0) * t$</span></p>
<p>to get my iso-value and plot the graph. Here's how I'm actually drawing the graph</p>
<pre><code>float t_step = 1/255.0f;
for(int i = 0; i &lt; knots.size() - 1; i++)
  {
    for (int i_step = 1; i_step &lt;= num_line_segments; i_step++)
    {
        glm::vec2 coord;
        coord.x = knots[i].iso_value + (t_step * i_step * (knots[i+1].iso_value - knots[i].iso_value));
        coord.y = glm::clamp(alpha_spline.getPointOnSpline(t_step * i_step, i).w, v_min.y, v_max.y);
        win-&gt;DrawList-&gt;_Path.push_back(getAbsMousePositionFromPoint(coord) );
    }
  }
  
getAbsMousePositionFromPoint(glm::vec2 v)
{
  glm::vec2 v_min(0,0), v_max(255, 1.0)
  glm::vec2 t = (v - v_min) / (v_max - v_min);
  return glm::mix(graph_bot_left, graph_top_right, t);   // both &quot;graph_bot_left&quot; and &quot;graph_top_right&quot; are absolute coordinates of the drawing region
}
</code></pre>
<p>Basically I need absolute coordinates for drawing anything on the screen. Each segment of the spline is basically drawn as a polyline. Just to be on the safe side I have currently set the number of line segments per curve of the spline to be <code>255</code>. This means per segment of the spline I need to draw 255 line segments. I step along <code>t</code> then transform it to the proper X-value by doing the transformation step as I told above then find absolute coordinates  from that X-value and draw the segment there.</p>
<p><em><strong>Now all I wanna know is, do parametric and explicit forms give different curves? If not, then is there something wrong with the rescaling step I'm doing above or something else?</strong></em></p>
<p>P.S :- I've checked the formulation and the boundary conditions of the <a href="https://timodenk.com/blog/cubic-spline-interpolation/" rel="nofollow noreferrer">online</a> one and all  are similar to the Wolfram one. Both mine and the online one are natural cubic splines. I've also double checked my code, even derived the whole parametric form on paper and checked the code with the one derived on paper and it matches perfectly so I'm pretty sure the code isn't wrong. Still <a href="https://github.com/gallickgunner/Volume-Renderer/blob/master/src/CubicSpline.cpp" rel="nofollow noreferrer">here's</a> my spline source as a reference if anybody here knows programming</p>
<p>UPDATE:- So I just found another guy using the same logic as well <a href="https://github.com/jose-villegas/VolumeRendering/blob/3de0008cbd6c1771dc25d0e382b47240220ee7cc/VolumeRendering/TransferFunction.cpp#L96" rel="nofollow noreferrer">here</a>.  I guess the math is all right then. Don't see where's the problem then.</p>

CC BY-SA 4.0
2021-08-24T13:36:36.030Z
The implicit and parametric forms are equivalent by definition. So the curves should look virtually identical. Are the coefficients reversed in the code? Usually the equation is $a^3t+b^2t+ct+d$ which would be $(((a * time) + b) * time + c) * time + d;$ but the linked coded seems to have $d^3t+c^2t+bt+a$ which is translated to $a + t * (b + t * (c + t * d))$
pmw1234
CC BY-SA 4.0
2021-08-24T16:31:13.437Z
@pmw1234 - Yea I seemed to have missed this point. The Wolfram and the code give the last equation that is $a + bt + ct^2 + dt^3$ where as the online has $ax^3 + bx^2 + cx + d$. But I don't think its making any difference because then in the online version the coeffecient $a$ and $b$ are actually $d$ and $c$ in my code respectively. Here's the link to the online just in case. Also added in OP. https://timodenk.com/blog/cubic-spline-interpolation/
gallickgunner
CC BY-SA 4.0
2021-08-24T18:47:46.560Z
If you're talking about defining y as a cubic function of x directly, versus defining x and y both as cubic functions of a parameter t, then yes those are totally different things and will behave differently. The former is a 1D spline and the latter is a 2D spline.
Nathan Reed
CC BY-SA 4.0
2021-08-24T18:50:33.977Z
But if you're just talking about a 1D spline and rescaling the parameter (t = x/255) then that shouldn't make any difference as long as you are doing the rescaling correctly.
Nathan Reed
CC BY-SA 4.0
2021-08-25T09:29:33.203Z
@NathanReed - Yes, I'm talking about the latter one (1D spline). Simply speaking I could have defined $Y(x)$ and gotten my interpolated values as a function of $x$ but I chose to do $Y(t)$ then rescale $x$ to $t$ and vice versa as mentioned above. But I'm still getting different results and I dunno why.
gallickgunner
<mathematics><spline>
Cubic Splines - Do Parametric and Explicit representation give different curves?
gallickgunner
# Cubic Splines - Do Parametric and Explicit representation give different curves?

(Asked by: username_0 on 2021-08-24)

I asked a similar question here before but since the previous post original question was different, I think it was confusing people. So I've voted to close that and asking the new question here. I'm doing a volume rendering project and made a cubic spline editor for transfer function. I used [this](http://graphicsrunner.blogspot.com/2008/05/camera-animation-part-ii.html) as a source which basically uses Wolfram as the main source. Now Wolfram defines a parametric representation. After I made it, I tried to compare it online but the curves are different. The only difference I found is that the online version is using a non-parametric representation.

Here's mine.
[![enter image description here](https://i.sstatic.net/Yo4am.png)](https://i.sstatic.net/Yo4am.png)

And here's the online version
[![enter image description here](https://i.sstatic.net/fEXlf.png)](https://i.sstatic.net/fEXlf.png)

In order to clarify a bit more on what I'm trying to do. I have 2 variables.

$X = [0, 255] $

$Y = [0, 1] $

For every given $X$ value I need the interpolated $Y$ value. At first glance it seems that the explicit form of cubic spline is what I want. But I have another case where $Y$ values are RGB triplets $(r,g,b)$. Since the parametric representation doesn't have to deal with dimensions and since the code was already online I'm using the parametric form. The parametric form uses the parameter $t \in [0,1]$ for every segment.

Now things get a little trickier. Technichally my graph is of $(t, Y(t))$ but as you can see in the first picture the X-axis isn't $t$ but the previously defined $X$ which is in range $[0-255]$. I'm simply rescaling between $X$ and $t$. So if I get $t = 0.5$ for the first segment as an example, I'd take the two bounding control points which resolve to $(0,0)$ and $(141, 0.759)$ in the first picture. Then do simple rescaling like

$0 + (141 - 0) \* t$

to get my iso-value and plot the graph. Here's how I'm actually drawing the graph

```
float t_step = 1/255.0f;
for(int i = 0; i < knots.size() - 1; i++)
  {
    for (int i_step = 1; i_step <= num_line_segments; i_step++)
    {
        glm::vec2 coord;
        coord.x = knots[i].iso_value + (t_step * i_step * (knots[i+1].iso_value - knots[i].iso_value));
        coord.y = glm::clamp(alpha_spline.getPointOnSpline(t_step * i_step, i).w, v_min.y, v_max.y);
        win->DrawList->_Path.push_back(getAbsMousePositionFromPoint(coord) );
    }
  }
  
getAbsMousePositionFromPoint(glm::vec2 v)
{
  glm::vec2 v_min(0,0), v_max(255, 1.0)
  glm::vec2 t = (v - v_min) / (v_max - v_min);
  return glm::mix(graph_bot_left, graph_top_right, t);   // both "graph_bot_left" and "graph_top_right" are absolute coordinates of the drawing region
}

```

Basically I need absolute coordinates for drawing anything on the screen. Each segment of the spline is basically drawn as a polyline. Just to be on the safe side I have currently set the number of line segments per curve of the spline to be `255`. This means per segment of the spline I need to draw 255 line segments. I step along `t` then transform it to the proper X-value by doing the transformation step as I told above then find absolute coordinates from that X-value and draw the segment there.

***Now all I wanna know is, do parametric and explicit forms give different curves? If not, then is there something wrong with the rescaling step I'm doing above or something else?***

P.S :- I've checked the formulation and the boundary conditions of the [online](https://timodenk.com/blog/cubic-spline-interpolation/) one and all are similar to the Wolfram one. Both mine and the online one are natural cubic splines. I've also double checked my code, even derived the whole parametric form on paper and checked the code with the one derived on paper and it matches perfectly so I'm pretty sure the code isn't wrong. Still [here's](https://github.com/username_0/Volume-Renderer/blob/master/src/CubicSpline.cpp) my spline source as a reference if anybody here knows programming

UPDATE:- So I just found another guy using the same logic as well [here](https://github.com/jose-villegas/VolumeRendering/blob/3de0008cbd6c1771dc25d0e382b47240220ee7cc/VolumeRendering/TransferFunction.cpp#L96). I guess the math is all right then. Don't see where's the problem then.

**Tags:** mathematics, spline

> **Comments:**
> **username_1**: The implicit and parametric forms are equivalent by definition. So the curves should look virtually identical. Are the coefficients reversed in the code? Usually the equation is $a^3t+b^2t+ct+d$ which would be $(((a * time) + b) * time + c) * time + d;$ but the linked coded seems to have $d^3t+c^2t+bt+a$ which is translated to $a + t * (b + t * (c + t * d))$  
> **username_0**: @username_1 - Yea I seemed to have missed this point. The Wolfram and the code give the last equation that is $a + bt + ct^2 + dt^3$ where as the online has $ax^3 + bx^2 + cx + d$. But I don't think its making any difference because then in the online version the coeffecient $a$ and $b$ are actually $d$ and $c$ in my code respectively. Here's the link to the online just in case. Also added in OP. https://timodenk.com/blog/cubic-spline-interpolation/  
> **username_2**: If you're talking about defining y as a cubic function of x directly, versus defining x and y both as cubic functions of a parameter t, then yes those are totally different things and will behave differently. The former is a 1D spline and the latter is a 2D spline.  
> **username_2**: But if you're just talking about a 1D spline and rescaling the parameter (t = x/255) then that shouldn't make any difference as long as you are doing the rescaling correctly.  
> **username_0**: @username_2 - Yes, I'm talking about the latter one (1D spline). Simply speaking I could have defined $Y(x)$ and gotten my interpolated values as a function of $x$ but I chose to do $Y(t)$ then rescale $x$ to $t$ and vice versa as mentioned above. But I'm still getting different results and I dunno why.  

---

## 1 answers

### Answer by username_1 on 2021-09-26. Score: 1 | Accepted answer

The two graphs are graphing Cubic Splines but they are not equivalent splines. The method used in the code you linked produces a curve that is very local to the points and produces the tightest fit to a data set of any of the curves. This curve is only affect by adjacent (knots) control points.

The method used in the online calculator produces a similar curve but individual segments are affected by control points that are up to 2 positions away which change the tangent and causes the big dips in the curve shown in the graph.

You should be able to convince yourself of this by looking at the two matrices used in the solution for both curves. The tridiagonal matrix can only affect adjacent rows and columns where as the matrix shown in the solution for the online calculator effects several rows and columns, this translates to very different curves.

I attempted to use Mathematica to check the curve produced by the linked code but the resulting curve (as described by the wolfram math web link in the references you gave) was not even a cubic spline.

I was able to verify the curve output by the online calculator in the web link using Maple, they both produce almost identical equations. MatLab supposedly has a function that will produce the same spline linked in your code but I don't have access to that program so wasn't able to verify it.

I started to convert the equations between implicit/explicit/parametric forms but that turned into more math then I am willing to do (and I didn't want to post a massive list of equations showing the conversion). But these are not implicit vs parametric forms of the same curve anyway so it would have been kind of pointless.

After all that I decided to implement my own version of the spline solver from the book wolfram references. ( I managed to get a used copy on the cheap ) My solution ended up being very similar to the code you linked and produced very similar results. The curves were slightly smoother at the control points but I think that I was using a different method of computing the values...along the lines of:

```
segment_count = knot_count -1;
vec4 solved_coefficients[segment_count];
vec2 curve[segment_count *100];
for each segment_count
  vec4 coeff = solved_coefficients[segment];
  for x=0 x<100; x++;
     t = 1.0/x;
     curve[knot*x] = calcPointOnLine( coeff, t);

```

This turned out to be a fun little side project into the different versions of fitted cubic splines.

**Edit:**
The problem is that the terminology used to describe the splines is used so interchangeably that the different solutions which produce very different splines are given the same names. I found one paper which used the name "Cubic Hermite Spline" for the what we implemented, and it gave the name "Cubic Spline" for what the online calculator implemented.

It is also possible to make the splines equivalent to each other by playing with the knot positions. I refitted the Cubic spline to a Cubic Hermite by moving/adding knot positions separated by a distance of 1 and got exactly the same splines from both solutions. The other direction (which I didn't try) is to fit the cubic Hermite spline to the cubic spline by changing the knot sequence from 0,1,2,3 to 0,141,149,255.

When it is all said and done I think it is more about what kind of fit works best for your algorithm.

> **Comments:**
> **username_0**: Dang bro, that's one heck of an effort. So in the end, this means the implementation is alright. But we still don't know what this implementation actually represents? I think it's a cubic spline but as you said it's different in the sense where only the adjacent knots affect the segment. I still don't get why or how parametric or implicit forms can produce this difference i.e. parameteric form produces a spline where the only adjacent knots affect the curve where as in implicit a small change in a knot can affect more than the adjacent knots.  
> **username_1**: The only thing the two solutions have in common is the fact that they pass through the set of points and are both cubic. They are very different ways of fitting a cubic curve to a set of points and the fact that one produces a parametric equation while the other produces an explicit solution is just a side effect of the approach used. (oh and I added an edit)  
> **username_1**: Oh, one more little detail is the wolfram solution avoids Runge's Phenomenon better then any other approach so it is possible to use an algorithm that can reduce it sample points to a minimum number and still get reasonably accurate results.  
> **username_0**: This cleared up many details. Thanks for the effort mate, much appreciated.  
> **username_1**: I just bumbled across this web page which is yet another way to compute the spline, it also discusses 1d vs 2d vs 3d, there are links to demos at the bottom of the page to :https://blog.demofox.org/2015/08/08/cubic-hermite-interpolation/  

---

