7

Does anyone know how to create a simulation raster elevation dataset - i.e. a 2d matrix of realistic elevation values - in R? R's jitter doesn't seem appropriate. In Java/Processing the noise() function achieves this with a Perlin noise algorithm e.g.:

size(200, 200);
float ns = 0.03; // for scaling
for (float i=0; i<200; i++) {
  for (float j=0; j<200; j++) {
    stroke(noise(i*ns, j*ns) * 255);
    point(i, j);
  }
}

enter image description here

But I've found no references to Perlin noise in R literature. Thanks in advance.

geotheory
  • 22,624
  • 29
  • 119
  • 196
  • 1
    see either the `RandomFields` package (methods for simulating a wide variety of Gaussian random fields), or perhaps a fractal surface: http://www.oceanographerschoice.com/2010/10/fractal-landscapes-in-r-part-two/ (I have some old code for this) – Ben Bolker Mar 13 '13 at 14:00
  • A quick search [brings up some C++ code](http://www.dreamincode.net/forums/topic/66480-perlin-noise/), which should not be too difficult to adjust. You could use `Rcpp` to use it directly or translate it to R. – Roland Mar 13 '13 at 14:05
  • Thanks Ben, Roland. The oceanograherschoice blog like a useful thing to try at some point when I have time, as would be learning C++. – geotheory Mar 13 '13 at 15:49

3 Answers3

16

Here is an implementation in R, following the explanations in http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html

perlin_noise <- function( 
  n = 5,   m = 7,    # Size of the grid for the vector field
  N = 100, M = 100   # Dimension of the image
) {
  # For each point on this n*m grid, choose a unit 1 vector
  vector_field <- apply(
    array( rnorm( 2 * n * m ), dim = c(2,n,m) ),
    2:3,
    function(u) u / sqrt(sum(u^2))
  )
  f <- function(x,y) {
    # Find the grid cell in which the point (x,y) is
    i <- floor(x)
    j <- floor(y)
    stopifnot( i >= 1 || j >= 1 || i < n || j < m )
    # The 4 vectors, from the vector field, at the vertices of the square
    v1 <- vector_field[,i,j]
    v2 <- vector_field[,i+1,j]
    v3 <- vector_field[,i,j+1]
    v4 <- vector_field[,i+1,j+1]
    # Vectors from the point to the vertices
    u1 <- c(x,y) - c(i,j)
    u2 <- c(x,y) - c(i+1,j)
    u3 <- c(x,y) - c(i,j+1)
    u4 <- c(x,y) - c(i+1,j+1)
    # Scalar products
    a1 <- sum( v1 * u1 )
    a2 <- sum( v2 * u2 )
    a3 <- sum( v3 * u3 )
    a4 <- sum( v4 * u4 )
    # Weighted average of the scalar products
    s <- function(p) 3 * p^2 - 2 * p^3
    p <- s( x - i )
    q <- s( y - j )
    b1 <- (1-p)*a1 + p*a2
    b2 <- (1-p)*a3 + p*a4
    (1-q) * b1 + q * b2
  }
  xs <- seq(from = 1, to = n, length = N+1)[-(N+1)]
  ys <- seq(from = 1, to = m, length = M+1)[-(M+1)]
  outer( xs, ys, Vectorize(f) )
}

image( perlin_noise() )

Perlin noise

You can have a more fractal structure by adding those matrices, with different grid sizes.

a <- .6
k <- 8
m <- perlin_noise(2,2,2^k,2^k)
for( i in 2:k )
  m <- m + a^i * perlin_noise(2^i,2^i,2^k,2^k)
image(m)
m[] <- rank(m) # Histogram equalization
image(m)

Perlin noise, Sum with different grid sizes

Vincent Zoonekynd
  • 31,893
  • 5
  • 69
  • 78
  • Spot on Vincent :) I've spent a couple of hours wading through other implementations - this code is far more elegant than mine would've turned out! Do you know who deserves attribution if necessary? – geotheory Mar 13 '13 at 15:46
  • Thanks also for the edit. I'm intrigued by the repeating blips where _high_ and _low_ extreme points neighbour each other. The model seems perfect aside from these points. – geotheory Mar 13 '13 at 16:49
  • 2
    That artefact was due to a missing `sqrt` when normalizing the vectors; I have fixed it and updated the plots accordingly. – Vincent Zoonekynd Mar 13 '13 at 17:59
1

An alternative method:

require(geoR)
sim <- grf(441, grid="reg", cov.pars=c(1, .25))
image(sim, col=gray(seq(1, .1, l=30)))

enter image description here

Can extract object data with cbind(sim[[1]], z = sim[[2]])

geotheory
  • 22,624
  • 29
  • 119
  • 196
0

Also now some functions in the {ambient} package.

geotheory
  • 22,624
  • 29
  • 119
  • 196