Generating random but believable digital elevation model? [closed]

Is there a way to generate a DEM, programatically or otherwise, that will feed into ArcGIS Desktop for further spatial analysis?

Perhaps this needs to be broken down into smaller incremental steps:

1. Generate a grid
2. Fill grid with values where: `0 > value < maxElevation`
3. Neighbouring cells: `(x1-x2) < maxSlope`
• The site @Igor points you to suggests a need to clarify this question. It focuses on "synthetic terrains," apparently to create backgrounds for games and the like. Most of those techniques do not appear to focus on recreating actual DEMs: "realistic" is in the eye of the beholder rather than having any scientific content. In your question, "further spatial analysis" suggests you need your synthetic DEMs to reproduce certain characteristics of some class of actual DEMs. If this is so, just what features do you need to capture? Feb 28 '12 at 16:30
• The first link from @Aragon is broken, but it should point to this. Not enough credits to comment on his answer. Feb 11 '16 at 13:16
• Also take a look at this. Aug 15 '17 at 2:08

You can use fractals for this: .

The upper row was generated with the fractal dimension d=2.0005 (left: elevation map, right: aspect map), the lower row with fractal dimension d=2.90 (left: elevation map, right: aspect map). I used r.surf.fractal of GRASS GIS. Then simply export the artificial DEM with r.out.gdal (or the GUI) to GeoTIFF.

You could also consider having a script that takes random part of an existing real DEM.

• Plus it would need some kind of filltering at the end to nivelate those mosaic edges of random parts.. Nov 26 '12 at 8:02

Here's a great resource on terrain generation algorithms and software on vterrain.org: http://vterrain.org/Elevation/Artificial/

Here is an R solution using a Gaussian Kernel to add autocorrelation to a random raster. Although, I have to say that the GRASS r.surf.fractal function, suggested by @markusN, seems like the best approach.

``````require(raster)

# Create 100x100 random raster with a Z range of 500-1500
r <- raster(ncols=100, nrows=100, xmn=0)
r[] <- runif(ncell(r), min=500, max=1500)

# Gaussian Kernel Function
GaussianKernel <- function(sigma=s, n=d) {
m <- matrix(nc=n, nr=n)
col <- rep(1:n, n)
row <- rep(1:n, each=n)
x <- col - ceiling(n/2)
y <- row - ceiling(n/2)
m[cbind(row, col)] <- 1/(2*pi*sigma^2) * exp(-(x^2+y^2)/(2*sigma^2))
m / sum(m)
}

# Create autocorrelated raster using 9x9 Gaussian Kernel with a sigma of 1
r.sim <- focal(r, w=GaussianKernel(sigma=1, n=9))

# Plot results
par(mfcol=c(1,2))
plot(r, main="Random Raster")
plot(r.sim, main="Autocorrelated Random Raster sigma=1, n=9")
``````

You could try using Perlin noise to create some random fractal terrain. This answer on Stackoverflow explains a way you could get started in Python. The trick would be to zoom in on a very small area of the noisy grid so it's not too irregular looking.

libnoise gives you what you want. You will likely have to customize it to some extent. Check the 'complex planetary surface' example.

libnoise is a portable C++ library that is used to generate coherent noise, a type of smoothly-changing noise. libnoise can generate Perlin noise, ridged multifractal noise, and other types of coherent-noise.

Coherent noise is often used by graphics programmers to generate natural-looking textures, planetary terrain, and other things. The mountain scene shown above was rendered in Terragen with a terrain file generated by libnoise. You can also view some other examples of what libnoise can do.

In libnoise, coherent-noise generators are encapsulated in classes called noise modules. There are many different types of noise modules. Some noise modules can combine or modify the outputs of other noise modules in various ways; you can join these modules together to generate very complex coherent noise.

This code can be used to create a "Hill slope" DEM of just about any number of rows and columns:

``````# Building a fake hillslope
# hisllop is 5 rows by 6 columns

x <- seq(-15, 15, by=0.01)
z <- 1/(1+1.5^-x)
plot(z)

z <- 150 - (1-z)*5
plot(z)

# Doing it by hand - DELETE if needed - JUST HERE AS AN EXAMPLE!!!
elev <- c(mean(z[0:500]), mean(z[501:1000]), mean(z[1001:1500]), mean(z[1501:2000]), mean(z[2001:2500]),mean(z[2501:3000]))
plot(elev, type="l")

# doing it by loop
bins <- 6      # could also be considered the length or the hillslope - AKa the number of columns
elev1 <- numeric(bins)

for(i in 0:(bins-1))
{
begin <- floor( (0 + (length(z)/bins)*i) )
print(begin)
end <- floor( ( (length(z)/bins) * (i+1) ) )
print(end)
print(mean(z[begin:end]))
elev1[i+1] <- mean(z[begin:end])

}

plot(elev1, type="l")

# Making the hillslope wide - AKA creating identical rows
width <- 5

# creating empty matric
hillslope <- matrix(0, nrow=bins, ncol=width)

#overwriting the matrix with the elevation column
system.time(
{
for(i in 1:width)
hillslope[,i] <- elev1;
hillslope <- as.data.frame(hillslope)
}
)

# applying random error grid
error <- rnorm((width*bins), mean = 0, sd = 0.25)
error.matrix <- as.matrix(error, nrow=bins )

random.hillslope <- as.matrix(hillslope + error.matrix)
image(random.hillslope)
``````