patternMinor
Heightmap generation using midpoint displacement
Viewed 0 times
midpointdisplacementheightmapgenerationusing
Problem
I am writing a program to generate a height map following the midpoint displacement algorithm (somewhat similar to diamond-square).
I'm at the point where I have a recursive program that paints the whole map but still needs some modifications to provide the desired result.
Before I do, I would like a code review on what I have so far to make sure everything so far is ok.
height_map.fs
midpoint_displacement.fs
```
module MidpointDisplacement
open HeightMap
// set the four corners to random values
let initCorners (hm:HeightMap) =
let rnd = System.Random()
let size = hm.Size
hm.Set 0 0 (rnd.NextDouble())
hm.Set 0 (size - 1) (rnd.NextDouble())
hm.Set (size - 1) 0 (rnd.NextDouble())
hm.Set (size - 1) (size - 1) (rnd.NextDouble())
// set the middle values between each corner (c1 c2 c3 c4)
// variation is a function that is applied on each pixel to modify it's value
let middle (hm:HeightMap) (x1, y1) (x2
I'm at the point where I have a recursive program that paints the whole map but still needs some modifications to provide the desired result.
Before I do, I would like a code review on what I have so far to make sure everything so far is ok.
height_map.fs
module HeightMap
// contains the height map types and common functions that can be re-used for
// different generation algorithms
type HeightMap = {Size:int; Map:float array} with
member this.Get x y =
this.Map.[x * this.Size + y]
member this.Set x y value =
this.Map.[x * this.Size + y] 0.0
| v when v > 1.0 -> 1.0
| _ -> v
// converts a float point ranging from 0.0 to 1.0 to a rgb value
// 0.0 represents black and 1.0 white. The conversion is in greyscale
let convertFloatToRgb (pct:float) : int * int * int =
let greyscale = int (float 255 * pct)
(greyscale, greyscale, greyscale)
// returns the average between two values
let avgf (a:float) (b:float) =
(a + b) / 2.0
// find the middle between two points in our map
let avgi (a:int) (b:int) =
(a + b) / 2
// returns a floating number which is generated using bounds as a control of the range of possible values
let randomize (rnd:System.Random) (bound:int) : float =
float (rnd.Next(-bound, bound) / bound)midpoint_displacement.fs
```
module MidpointDisplacement
open HeightMap
// set the four corners to random values
let initCorners (hm:HeightMap) =
let rnd = System.Random()
let size = hm.Size
hm.Set 0 0 (rnd.NextDouble())
hm.Set 0 (size - 1) (rnd.NextDouble())
hm.Set (size - 1) 0 (rnd.NextDouble())
hm.Set (size - 1) (size - 1) (rnd.NextDouble())
// set the middle values between each corner (c1 c2 c3 c4)
// variation is a function that is applied on each pixel to modify it's value
let middle (hm:HeightMap) (x1, y1) (x2
Solution
First thing to do when you see a boilerplate code is to represent code as data.
So your function middle is quite simple iterate all sides of a square(represented as a pair of points) use side points and a point between them and apply change. In short you could write something like that
One additional trick when you work with an array with some cursor inside it and have to do some recursive work then you could apply comonads.
So your function middle is quite simple iterate all sides of a square(represented as a pair of points) use side points and a point between them and apply change. In short you could write something like that
let middle (hm:HeightMap) (x1, y1) (x2, y2) (x3, y3) (x4, y4) (variation) =
let points = [|x1, y1; x2, y2; x4, y4; x3, y3; x1, y1|]//clockwise iterate sides
for i in 0..3 do
let x1, y1 = points.[i]
let x2, y2 = points.[i + 1]
let mx, my = avgi x1 x2, avgi y1 y2
if hm.Get mx my = 0.0 then
hm.Set mx my (avgf (hm.Get x1 y1) (hm.Get x2 y2) |> variation |> normalizeValue)One additional trick when you work with an array with some cursor inside it and have to do some recursive work then you could apply comonads.
Code Snippets
let middle (hm:HeightMap) (x1, y1) (x2, y2) (x3, y3) (x4, y4) (variation) =
let points = [|x1, y1; x2, y2; x4, y4; x3, y3; x1, y1|]//clockwise iterate sides
for i in 0..3 do
let x1, y1 = points.[i]
let x2, y2 = points.[i + 1]
let mx, my = avgi x1 x2, avgi y1 y2
if hm.Get mx my = 0.0 then
hm.Set mx my (avgf (hm.Get x1 y1) (hm.Get x2 y2) |> variation |> normalizeValue)Context
StackExchange Code Review Q#122875, answer score: 3
Revisions (0)
No revisions yet.