4

I'm looking for interpolating some contour lines to generating a 3D view. The contours are not stored in a picture, coordinates of each point of the contour are simply stored in a std::vector.

for convex contours :

enter image description hereenter image description here

, it seems (I didn't check by myself) that the height can be easily calculates (linear interpolation) by using the distance between the two closest points of the two closest contours.

my contours are not necessarily convex :

enter image description hereenter image description here

, so it's more tricky... actualy I don't have any idea what kind of algorithm I can use.

UPDATE : 26 Nov. 2013

I finished to write a Discrete Laplace example :

enter image description here

you can get the code here

The Unholy Metal Machine
  • 1,093
  • 2
  • 17
  • 36

2 Answers2

3

What you have is basically the classical Dirichlet problem:

Given the values of a function on the boundary of a region of space, assign values to the function in the interior of the region so that it satisfies a specific equation (such as Laplace's equation, which essentially requires the function to have no arbitrary "bumps") everywhere in the interior.

There are many ways to calculate approximate solutions to the Dirichlet problem. A simple approach, which should be well suited to your problem, is to start by discretizing the system; that is, you take a finite grid of height values, assign fixed values to those points that lie on a contour line, and then solve a discretized version of Laplace's equation for the remaining points.

Now, what Laplace's equation actually specifies, in plain terms, is that every point should have a value equal to the average of its neighbors. In the mathematical formulation of the equation, we require this to hold true in the limit as the radius of the neighborhood tends towards zero, but since we're actually working on a finite lattice, we just need to pick a suitable fixed neighborhood. A few reasonable choices of neighborhoods include:

  • the four orthogonally adjacent points surrounding the center point (a.k.a. the von Neumann neighborhood),
  • the eight orthogonally and diagonally adjacent grid points (a.k.a. the Moore neigborhood), or
  • the eight orthogonally and diagonally adjacent grid points, weighted so that the orthogonally adjacent points are counted twice (essentially the sum or average of the above two choices).

(Out of the choices above, the last one generally produces the nicest results, since it most closely approximates a Gaussian kernel, but the first two are often almost as good, and may be faster to calculate.)

Once you've picked a neighborhood and defined the fixed boundary points, it's time to compute the solution. For this, you basically have two choices:

  1. Define a system of linear equations, one per each (unconstrained) grid point, stating that the value at each point is the average of its neighbors, and solve it. This is generally the most efficient approach, if you have access to a good sparse linear system solver, but writing one from scratch may be challenging.

  2. Use an iterative method, where you first assign an arbitrary initial guess to each unconstrained grid point (e.g. using linear interpolation, as you suggest) and then loop over the grid, replacing the value at each point with the average of its neighbors. Then keep repeating this until the values stop changing (much).

Community
  • 1
  • 1
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • Hi, about the grid, you mean a box like the one I drawn on the picture ? because the outer circle (biggest one) is at height zero, while the inner circle is at height of one, so I can't make a 2D grid.So I guess I should build a bounding box, discretize it then solve the Laplace equation at each node with the known values (circles aren't discretize on the picture)? – The Unholy Metal Machine Nov 21 '13 at 01:10
  • also for linear algebra I know it's not easy to code it, I tried and failed some years ago... then I played for fun with LAPACK... Now I will try with http://en.wikipedia.org/wiki/LinBox – The Unholy Metal Machine Nov 21 '13 at 01:18
  • @bob: You want to make a [height map](https://en.wikipedia.org/wiki/Heightmap), right? So the grid would be the heightmap viewed from above, with the value of each grid point giving the height of the terrain at that point. (That's assuming that the contours never intersect when viewed from above, i.e. that the terrain doesn't contain any caves or tunnels or overhangs. If it does, things get a lot more complicated.) – Ilmari Karonen Nov 21 '13 at 01:51
  • well, I forgot that z=f(x,y)=height=value... thx for your comment. there will have no intersection in my case – The Unholy Metal Machine Nov 21 '13 at 01:56
  • 1
    thx I finished an example. It give a nice result as the picture shows – The Unholy Metal Machine Nov 26 '13 at 16:11
2

You can generate the Constrained Delaunay Triangulation of the vertices and line segments describing the contours, then use the height defined at each vertex as a Z coordinate.

The resulting triangulation can then be rendered like any other triangle soup.

Despite the name, you can use TetGen to generate the triangulations, though it takes a bit of work to set up.

defube
  • 2,395
  • 1
  • 22
  • 34
  • I don't know yet if this is good or not, my first idea was to use a grid then calculating the height of each node by using the contours. I will give a try with tetgen and see what I get – The Unholy Metal Machine Nov 20 '13 at 22:24
  • I will try to implement the solution of Ilmari Karonen. Anyway thx for TetGen link, it will maybe useful for me in the futur – The Unholy Metal Machine Nov 21 '13 at 01:11
  • Good luck! Soving the Laplacian directly is a tricky problem, though as a point of interest, Pixar used a 3D variation of the idea when developing the technology used in The Incredibles. I don't have the link available at the moment, but the idea is to start with fixed values at the boundaries and repeatedly replace interior samples with averages of their neighbors. – defube Nov 21 '13 at 11:40