Creating continuous splines / Making a smooth transition between splines - algorithm

I'm working on a project that involves creating a spline from a defined set of points (tens of thousands of points).
I first create a spline for the first 1000 points and simulate "driving" on that path with an arrow (it is drawn using the tangent and the current point on spline). When I'm approaching the end of the path I take the next 1000 points and create a new spline and continue my "driving".
The problem that I have is the fact that the splines (previous spline and current spline) don't match at the end. By not matching I mean they don't have the same tangent (first derivative doesn't match) and there is a difference between the last point of the previous spline and first point on the new spline (this is because I'm not using an interpolating spline but a smooth spline - see NOTE1 below). This makes my arrow "jump" at the end of spline, when switching to the newly created spline.
NOTE1: I'm NOT using interpolating splines. I'm using smooth splines. See here and here for more details. This means that the set of points given as input may not be on the resulting spline (In my case they are quite close to the spline - but usually NOT on the spline).
NOTE2: Using an interpolating spline is out of the question because I have a lot of noise in the data used for computing spline.
NOTE3: Computing a spline for the entire set of points takes a lot of time (more than 30 seconds) on a 3Ghz PC with 2 GB RAM (our target platform for the application); so doing this is also out of the question.
I'd be interested to overcome that unwanted "jump" when switching splines.
So my questions are:
Are there some ways/algorithms for doing a smooth "jump"/transition to the new spline?
Can I do something with a special type of spline to overcome this? (This is what I tried so far without a considerable improvement).
Thank you for any ideas,
Iulian

This is a pretty unsophisticated suggestion, admittedly, but one obvious hack would be to fit overlapping rather than distinct subsets of points and then interpolate between the resulting splines in the overlapping region.
Eg, generate a smooth spline for points 1-1000. While you're animating from 1-900, generate the next spline from 901-1900. For the region between 901 and 1000, use a weighted combination of the corresponding positions in both splines, where the weighting is 1:0 at 901 and 0:1 at 1000. The same for 1801-1900 and so on.
I'd guess that a simple linear interpolation would suffice and the margins probably wouldn't need to be huge, but you could determine that empirically.

Related

Dividing cubic spline computation

I have n points (20k to 30k) in 3D, I want to interpolate them using cubic spline. The problem here is that I will not have all of these points at the same time, they will be sent to me. so I don't want to wait until receive all of them to start the interpolation.
As a result, I choose to split these points into subsets, interpolate the first subset of points ,use it, and by the time start interpolate the next subset of points and so on
(split these points into subsets of hundreds points n1,n2,... and find the splines for each subset so that the result is identical to the result of the n point splines curves.)
I thought that overlapping these subset during computation is enough to do that but it seems not. what do you suggest to solve this?
You can start the interpolation at any time, using the available points (presumably in the correct order !). Cubic spline interpolation is a very stable process and when you add more points, most of the curve remains unchanged.
If your concern is that you want to avoid redoing the whole computation several times, I guess that it is enough to work on several sections with some overlap (say 20 points) and discard the results of the 10 extreme points of all sections.
Calculation of interpolation splines is performed over the whole point sequence, and results for two separate halves with overlapping would be slightly different. Note, for example, that border condition for the last point of the first spline might include predefined bias or zero curvature, while the same part of the second spline is calculated to provide continuity.
You can try to calculate some kind of smooth transition for overlapping region.
Edit
After question update - I don't see relation between parallel treatment and your problem.
Instead you can connect subranges with C1-continuity:
Calculate splines interpolation for the first set of point. Use free-end condition - zero curvature. Remember bias (linear coefficient) in the terminal point.
For the every next set calculate spline interpolation using predefined starting bias - from the last set, and ending zero curvature condition again.
BTW, spline interpolation for thousands of points should work very fast (it is linear algorithm). Is it really bottleneck?

Interpolating missing contour lines between existing contour lines

Contour lines (aka isolines) are curves that trace constant values across a 2D scalar field. For example, in a geographical map you might have contour lines to illustrate the elevation of the terrain by showing where the elevation is constant. In this case, let's store contour lines as lists of points on the map.
Suppose you have map that has several contour lines at known elevations, and otherwise you know nothing about the elevations of the map. What algorithm would you use to fill in additional contour lines to approximate the unknown elevations of the map, assuming the landscape is continuous and doesn't do anything surprising?
It is easy to find advise about interpolating the elevation of an individual point using contour lines. There are also algorithms like Marching Squares for turning point elevations into contour lines, but none of these exactly capture this use case. We don't need the elevation of any particular point; we just want the contour lines. Certainly we could solve this problem by filling an array with estimated elevations and then using Marching Squares to estimate the contour lines based on the array, but the two steps of that process seem unnecessarily expensive and likely to introduce artifacts. Surely there is a better way.
IMO, about all methods will amount to somehow reconstructing the 3D surface by interpolation, even if implicitly.
You may try by flattening the curves (turning them to polylines) and triangulating the resulting polygons thay they will define. (There will be a step of closing the curves that end on the border of the domain.)
By intersection of the triangles with a new level (unsing linear interpolation along the sides), you will obtain new polylines corresponding to new isocurves. Notice that the intersections with the old levels recreates the old polylines, which is sound.
You may apply a post-smoothing to the curves, but you will have no guarantee to retrieve the original old curves and cannot prevent close surves to cross each other.
Beware that increasing the density of points along the curves will give you a false feeling of accuracy, as the error due to the spacing of the isolines will remain (indeed the reconstructed surface will be cone-like, with one of the curvatures being null; the surface inside the bottommost and topmost lines will be flat).
Alternatively to using flat triangles, one may think of a scheme where you compute a gradient vector at every vertex (f.i. from a least square fit of a plane on the vertex and its neighbors), and use this information to generate a bivariate polynomial surface in the triangle. You must do this in such a way that the values along a side will coincide for the two triangles that share it. (Unfortunately, I have no formula to give you.)
The isolines are then obtained by a further subdivision of the triangle in smaller triangles, with a flat approximation.
Actually, this is not very different from getting sample points, (Delaunay) triangulating them and fitting picewise continuous patches to the triangles.
Whatever method you will use, be it 2D or 3D, it is useful to reason on what happens if you sweep the range of z values in a continous way. This thought experiment does reconstruct a 3D surface, which will possess continuity and smoothness properties.
A possible improvement over the crude "flat triangulation" model could be to extend every triangle side between to iso-polylines with sides leading to the next iso-polylines. This way, higher order interpolation (cubic) can be achieved, giving a smoother reconstruction.
Anyway, you can be sure that this will introduce discontinuities or other types of artifacts.
A mixed method:
flatten the isolines to polylines;
triangulate the poygons formed by the polylines and the borders;
on every node, estimate the surface gradient (least-square fit of a plane to the node and its neighborrs);
in every triangle, consider the two sides along which you need to interpolate and compute the derivative at endpoints (from the known gradients and the side directions);
use Hermite interpolation along these sides and solve for the desired iso-levels;
join the points obtained on both sides.
This method should be a good tradeoff between complexity and smoothness. It does reconstruct a continuous surface (except maybe for the remark below).
Note that is some cases, yo will obtain three solutions of the cubic. If there are three on each side, join them in order. Otherwise, make a decision on which to join and use the remaining two to close the curve.

Keyframe interpolation catmull rom

I understand there are many methods to do this. I am specifically interested in the catmull romfor animation purposes. I am having trouble understanding it however. All the sites I have visited have identified key poses as points. However key poses can also contain joint angles. Are these treated the same as points when interpolating? And are there any good sites for learning catmull rom?
The Catmull-Rom spline calculation is a mathematical tool used to make a smooth curve from a set of points. It is routinely used to plan the path of the camera so that the camera will smoothly transition, and won't sharply change view angles, while still allowing for the anchor points to be fairly sparse. It could definitely also be used to map the transitions of animation skeletons, or the poses, including joints and other values. The spline can be applied to any scalar value. So you could apply the spline to the positions of the joint locations in an animation sequence. You would calculate the X, Y and Z values separately. But you could also apply it to joint angles, or other scalar values that change over time. The spline will just interpolate a value along a smooth curve.
The best Catmull-Rom implementation I have found is Centripetal Implementation, where I give a detailed solution with full implementation here.
Catmull-rom curve with no cusps and no self-intersections
The principle article that helped me the most is here: http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
The main thing you need to understand is that this is a spline tool that takes a set of points and uses them as "anchor" points for curves that try to create a smooth path that goes through the points. The path will always go through all of your points. You have to add on two control points to either end. If you are creating a closed curve where the first and last point are the same, the points you add to the beginning is the next to last point, and the point you add to the end is the second point. If the line is open, you can repeat the first and end points, or in fact, I recommend extending the first and last segments in the same direction so that your line starts out with momentum moving in the direction of your lines. Here are some of the artifacts from the various parameterizations. Remember that the results from the "Uniform" version are the same as the unparameterized version.

Averaging vector images to get in-between images

I am looking for an algorithm that takes vector image data (e.g. sets of edges) and interpolate another set of edges which is the "average" of the two (or more) sets.
To put it in another way, it is just like Adobe Flash where you "tween" two vector images and the software automatically computes the in-between images. Therefore you only specify the starting image and end image, then Flash takes care of all the in-between images.
Is there any established algorithm to do this? Especially in cases like different number of edges?
What exactly do you mean by edges? Are we talking about smooth vector graphics that use curves?
Well a basic strategy would be to simply do a linear interpolation on the points and directions of your control polygon.
Basically you could simply take two corresponding points (one of each curve/vector form) and interpolate them with:
x(t) = (1-t)*p1 + t*p2 with t in [0,1]
(t=0.5 would then of course give you the average between the two)
Since vector graphics usually use curves you'd need to do the same with the direction vector of each control point to get the direction vector of the averaged curve.
One big problem though is to match the right points of each control polygon, especially if both curves have a different degree. You could try doing a degree elevation on one to match the degree of the other and then one by one assign them to each other and interpolate.
Maybe that helps...

Drawing a Topographical Map

I've been working on a visualization project for 2-dimensional continuous data. It's the kind of thing you could use to study elevation data or temperature patterns on a 2D map. At its core, it's really a way of flattening 3-dimensions into two-dimensions-plus-color. In my particular field of study, I'm not actually working with geographical elevation data, but it's a good metaphor, so I'll stick with it throughout this post.
Anyhow, at this point, I have a "continuous color" renderer that I'm very pleased with:
The gradient is the standard color-wheel, where red pixels indicate coordinates with high values, and violet pixels indicate low values.
The underlying data structure uses some very clever (if I do say so myself) interpolation algorithms to enable arbitrarily deep zooming into the details of the map.
At this point, I want to draw some topographical contour lines (using quadratic bezier curves), but I haven't been able to find any good literature describing efficient algorithms for finding those curves.
To give you an idea for what I'm thinking about, here's a poor-man's implementation (where the renderer just uses a black RGB value whenever it encounters a pixel that intersects a contour line):
There are several problems with this approach, though:
Areas of the graph with a steeper slope result in thinner (and often broken) topo lines. Ideally, all topo lines should be continuous.
Areas of the graph with a flatter slope result in wider topo lines (and often entire regions of blackness, especially at the outer perimeter of the rendering region).
So I'm looking at a vector-drawing approach for getting those nice, perfect 1-pixel-thick curves. The basic structure of the algorithm will have to include these steps:
At each discrete elevation where I want to draw a topo line, find a set of coordinates where the elevation at that coordinate is extremely close (given an arbitrary epsilon value) to the desired elevation.
Eliminate redundant points. For example, if three points are in a perfectly-straight line, then the center point is redundant, since it can be eliminated without changing the shape of the curve. Likewise, with bezier curves, it is often possible to eliminate cetain anchor points by adjusting the position of adjacent control points.
Assemble the remaining points into a sequence, such that each segment between two points approximates an elevation-neutral trajectory, and such that no two line segments ever cross paths. Each point-sequence must either create a closed polygon, or must intersect the bounding box of the rendering region.
For each vertex, find a pair of control points such that the resultant curve exhibits a minimum error, with respect to the redundant points eliminated in step #2.
Ensure that all features of the topography visible at the current rendering scale are represented by appropriate topo lines. For example, if the data contains a spike with high altitude, but with extremely small diameter, the topo lines should still be drawn. Vertical features should only be ignored if their feature diameter is smaller than the overall rendering granularity of the image.
But even under those constraints, I can still think of several different heuristics for finding the lines:
Find the high-point within the rendering bounding-box. From that high point, travel downhill along several different trajectories. Any time the traversal line crossest an elevation threshold, add that point to an elevation-specific bucket. When the traversal path reaches a local minimum, change course and travel uphill.
Perform a high-resolution traversal along the rectangular bounding-box of the rendering region. At each elevation threshold (and at inflection points, wherever the slope reverses direction), add those points to an elevation-specific bucket. After finishing the boundary traversal, start tracing inward from the boundary points in those buckets.
Scan the entire rendering region, taking an elevation measurement at a sparse regular interval. For each measurement, use it's proximity to an elevation threshold as a mechanism to decide whether or not to take an interpolated measurement of its neighbors. Using this technique would provide better guarantees of coverage across the whole rendering region, but it'd be difficult to assemble the resultant points into a sensible order for constructing paths.
So, those are some of my thoughts...
Before diving deep into an implementation, I wanted to see whether anyone else on StackOverflow has experience with this sort of problem and could provide pointers for an accurate and efficient implementation.
Edit:
I'm especially interested in the "Gradient" suggestion made by ellisbben. And my core data structure (ignoring some of the optimizing interpolation shortcuts) can be represented as the summation of a set of 2D gaussian functions, which is totally differentiable.
I suppose I'll need a data structure to represent a three-dimensional slope, and a function for calculating that slope vector for at arbitrary point. Off the top of my head, I don't know how to do that (though it seems like it ought to be easy), but if you have a link explaining the math, I'd be much obliged!
UPDATE:
Thanks to the excellent contributions by ellisbben and Azim, I can now calculate the contour angle for any arbitrary point in the field. Drawing the real topo lines will follow shortly!
Here are updated renderings, with and without the ghetto raster-based topo-renderer that I've been using. Each image includes a thousand random sample points, represented by red dots. The angle-of-contour at that point is represented by a white line. In certain cases, no slope could be measured at the given point (based on the granularity of interpolation), so the red dot occurs without a corresponding angle-of-contour line.
Enjoy!
(NOTE: These renderings use a different surface topography than the previous renderings -- since I randomly generate the data structures on each iteration, while I'm prototyping -- but the core rendering method is the same, so I'm sure you get the idea.)
Here's a fun fact: over on the right-hand-side of these renderings, you'll see a bunch of weird contour lines at perfect horizontal and vertical angles. These are artifacts of the interpolation process, which uses a grid of interpolators to reduce the number of computations (by about 500%) necessary to perform the core rendering operations. All of those weird contour lines occur on the boundary between two interpolator grid cells.
Luckily, those artifacts don't actually matter. Although the artifacts are detectable during slope calculation, the final renderer won't notice them, since it operates at a different bit depth.
UPDATE AGAIN:
Aaaaaaaand, as one final indulgence before I go to sleep, here's another pair of renderings, one in the old-school "continuous color" style, and one with 20,000 gradient samples. In this set of renderings, I've eliminated the red dot for point-samples, since it unnecessarily clutters the image.
Here, you can really see those interpolation artifacts that I referred to earlier, thanks to the grid-structure of the interpolator collection. I should emphasize that those artifacts will be completely invisible on the final contour rendering (since the difference in magnitude between any two adjacent interpolator cells is less than the bit depth of the rendered image).
Bon appetit!!
The gradient is a mathematical operator that may help you.
If you can turn your interpolation into a differentiable function, the gradient of the height will always point in the direction of steepest ascent. All curves of equal height are perpendicular to the gradient of height evaluated at that point.
Your idea about starting from the highest point is sensible, but might miss features if there is more than one local maximum.
I'd suggest
pick height values at which you will draw lines
create a bunch of points on a fine, regularly spaced grid, then walk each point in small steps in the gradient direction towards the nearest height at which you want to draw a line
create curves by stepping each point perpendicular to the gradient; eliminate excess points by killing a point when another curve comes too close to it-- but to avoid destroying the center of hourglass like figures, you might need to check the angle between the oriented vector perpendicular to the gradient for both of the points. (When I say oriented, I mean make sure that the angle between the gradient and the perpendicular value you calculate is always 90 degrees in the same direction.)
In response to your comment to #erickson and to answer the point about calculating the gradient of your function. Instead of calculating the derivatives of your 300 term function you could do a numeric differentiation as follows.
Given a point [x,y] in your image you could calculate the gradient (direction of steepest decent)
g={ ( f(x+dx,y)-f(x-dx,y) )/(2*dx),
{ ( f(x,y+dy)-f(x,y-dy) )/(2*dy)
where dx and dy could be the spacing in your grid. The contour line will run perpendicular to the gradient. So, to get the contour direction, c, we can multiply g=[v,w] by matrix, A=[0 -1, 1 0] giving
c = [-w,v]
Alternately, there is the marching squares algorithm which seems appropriate to your problem, although you may want to smooth the results if you use a coarse grid.
The topo curves you want to draw are isosurfaces of a scalar field over 2 dimensions. For isosurfaces in 3 dimensions, there is the marching cubes algorithm.
I've wanted something like this myself, but haven't found a vector-based solution.
A raster-based solution isn't that bad, though, especially if your data is raster-based. If your data is vector-based too (in other words, you have a 3D model of your surface), you should be able to do some real math to find the intersection curves with horizontal planes at varying elevations.
For a raster-based approach, I look at each pair of neighboring pixels. If one is above a contour level, and one is below, obviously a contour line runs between them. The trick I used to anti-alias the contour line is to mix the contour line color into both pixels, proportional to their closeness to the idealized contour line.
Maybe some examples will help. Suppose that the current pixel is at an "elevation" of 12 ft, a neighbor is at an elevation of 8 ft, and contour lines are every 10 ft. Then, there is a contour line half way between; paint the current pixel with the contour line color at 50% opacity. Another pixel is at 11 feet and has a neighbor at 6 feet. Color the current pixel at 80% opacity.
alpha = (contour - neighbor) / (current - neighbor)
Unfortunately, I don't have the code handy, and there might have been a bit more to it (I vaguely recall looking at diagonal neighbors too, and adjusting by sqrt(2) / 2). I hope this enough to give you the gist.
It occurred to me that what you're trying to do would be pretty easy to do in MATLAB, using the contour function. Doing things like making low-density approximations to your contours can probably be done with some fairly simple post-processing of the contours.
Fortunately, GNU Octave, a MATLAB clone, has implementations of the various contour plotting functions. You could look at that code for an algorithm and implementation that's almost certainly mathematically sound. Or, you might just be able to offload the processing to Octave. Check out the page on interfacing with other languages to see if that would be easier.
Disclosure: I haven't used Octave very much, and I haven't actually tested it's contour plotting. However, from my experience with MATLAB, I can say that it will give you almost everything you're asking for in just a few lines of code, provided you get your data into MATLAB.
Also, congratulations on making a very VanGough-esque slopefield plot.
I always check places like http://mathworld.wolfram.com before going to deep on my own :)
Maybe their curves section would help? Or maybe the entry on maps.
compare what you have rendered with a real-world topo map - they look identical to me! i wouldn't change a thing...
Write the data out as an HGT file (very simple digital elevation data format used by USGS) and use the free and open-source gdal_contour tool to create contours. That works very well for terrestrial maps, the constraint being that the data points are signed 16-bit numbers, which fits the earthly range of heights in metres very well, but may not be enough for your data, which I assume not to be a map of actual terrain - although you do mention terrain maps.
I recommend the CONREC approach:
Create an empty line segment list
Split your data into regular grid squares
For each grid square, split the square into 4 component triangles:
For each triangle, handle the cases (a through j):
If a line segment crosses one of the cases:
Calculate its endpoints
Store the line segment in the list
Draw each line segment in the line segment list
If the lines are too jagged, use a smaller grid. If the lines are smooth enough and the algorithm is taking too long, use a larger grid.

Resources