HeightMap
2D grid of float values for procedural generation.
Overview
HeightMap is the universal canvas for procedural generation. It stores float values that can be manipulated, combined, and applied to Grid and Layer objects. All terrain generation, noise sampling, and BSP operations produce or consume HeightMaps.
Quick Reference
# Create a heightmap
hmap = mcrfpy.HeightMap((100, 100))
# Method chaining for terrain generation
hmap.fill(0.5).add_hill((50, 50), 20, 0.3).normalize()
# Subscript access
value = hmap[25, 30]
# Combine multiple heightmaps
noise_map = noise_source.sample((100, 100))
hmap.multiply(noise_map) # Apply as mask
# Convert BSP to heightmap
rooms = bsp.to_heightmap(select='leaves', shrink=1)
hmap.add(rooms)
Constructor
mcrfpy.HeightMap(size: tuple[int, int], fill: float = 0.0)
| Parameter | Type | Description |
|---|---|---|
size |
tuple[int, int] | Dimensions (width, height). Immutable after creation. |
fill |
float | Initial value for all cells. Default: 0.0 |
Properties
| Property | Type | Description |
|---|---|---|
size |
tuple[int, int] | Dimensions (width, height). Read-only. |
Query Methods
| Method | Description |
|---|---|
get(x, y) |
Get height value at integer coordinates |
get_interpolated(x, y) |
Get bilinearly interpolated value at float coordinates |
get_slope(x, y) |
Get slope angle (0 to pi/2) at coordinates |
get_normal(x, y, water_level=0.0) |
Get normal vector (nx, ny, nz) for lighting |
min_max() |
Returns (min_value, max_value) tuple |
count_in_range((min, max)) |
Count cells with values in range |
Scalar Operations
All scalar operations support optional region parameters and return self for chaining.
| Method | Description |
|---|---|
fill(value, *, pos=None, size=None) |
Set cells to specified value |
clear() |
Set all cells to 0.0 |
add_constant(value, *, pos=None, size=None) |
Add constant to each cell |
scale(factor, *, pos=None, size=None) |
Multiply each cell by factor |
clamp(min=0.0, max=1.0, *, pos=None, size=None) |
Clamp values to range |
normalize(min=0.0, max=1.0, *, pos=None, size=None) |
Rescale values to target range |
Combination Operations
Combine two heightmaps with optional region parameters. All return self for chaining.
| Method | Description |
|---|---|
add(other, *, pos=None, source_pos=None, size=None) |
Add other’s values |
subtract(other, *, pos=None, source_pos=None, size=None) |
Subtract other’s values |
multiply(other, *, pos=None, source_pos=None, size=None) |
Multiply by other (masking) |
lerp(other, t, *, pos=None, source_pos=None, size=None) |
Linear interpolation |
copy_from(other, *, pos=None, source_pos=None, size=None) |
Copy values from other |
max(other, *, pos=None, source_pos=None, size=None) |
Take maximum of each cell |
min(other, *, pos=None, source_pos=None, size=None) |
Take minimum of each cell |
Threshold Operations
These return NEW HeightMap objects (original unchanged).
| Method | Description |
|---|---|
threshold((min, max)) |
Original values where in range, 0.0 elsewhere |
threshold_binary((min, max), value=1.0) |
Uniform value where in range, 0.0 elsewhere |
inverse() |
Returns (1.0 - value) for each cell |
Terrain Generation
Methods that add procedural terrain features. All return self for chaining.
| Method | Description |
|---|---|
add_hill(center, radius, height) |
Add smooth hill at position |
dig_hill(center, radius, target_height) |
Dig pit/crater (only lowers cells) |
add_voronoi(num_points, coefficients=(1.0, -0.5), seed=None) |
Add Voronoi terrain |
mid_point_displacement(roughness=0.5, seed=None) |
Diamond-square terrain |
rain_erosion(drops, erosion=0.1, sedimentation=0.05, seed=None) |
Simulate erosion |
dig_bezier(points, start_radius, end_radius, start_height, end_height) |
Dig canal along Bezier curve |
smooth(iterations=1) |
Average neighboring cells |
Convolution Operations
Convolution kernels for image processing and analysis. Return NEW HeightMap objects.
| Method | Description |
|---|---|
sparse_kernel(weights, *, min_level=-inf, max_level=inf) |
Sparse convolution with dict weights {(dx, dy): weight}. Returns new HeightMap. |
sparse_kernel_from(source, weights, *, min_level=-inf, max_level=inf) |
Sparse convolution from source into self (in-place). |
kernel3(weights, *, normalize=True) |
Optimized 3×3 dense convolution with 9-element sequence. Returns new HeightMap. |
kernel3_from(source, weights, *, normalize=True) |
3×3 convolution from source into self (in-place). |
Kernel layout for kernel3: [0,1,2] = top row, [3,4,5] = middle, [6,7,8] = bottom.
# Edge detection with sparse kernel
edges = hmap.sparse_kernel({(-1, 0): -1, (1, 0): -1, (0, -1): -1, (0, 1): -1, (0, 0): 4})
# Gaussian blur with 3x3 kernel
blur_weights = [1, 2, 1, 2, 4, 2, 1, 2, 1]
blurred = hmap.kernel3(blur_weights)
# Reuse buffer in hot loop
buffer = mcrfpy.HeightMap(hmap.size)
for _ in range(10):
buffer.kernel3_from(hmap, blur_weights)
hmap, buffer = buffer, hmap # Swap
Gradient Analysis
| Method | Description |
|---|---|
gradients(dx=True, dy=True) |
Compute partial derivatives. Returns (dx, dy) tuple, single HeightMap, or None depending on args. |
Pass existing HeightMaps for dx/dy to reuse buffers in performance-critical loops.
# Get both gradients
dx, dy = hmap.gradients()
# Get only horizontal gradient
dx = hmap.gradients(dy=False)
# Reuse buffers
dx_buf = mcrfpy.HeightMap(hmap.size)
dy_buf = mcrfpy.HeightMap(hmap.size)
hmap.gradients(dx=dx_buf, dy=dy_buf) # Writes into existing buffers
Direct Source Sampling
Sample from NoiseSource or BSP directly without intermediate HeightMaps.
| Method | Description |
|---|---|
add_noise(source, world_origin=(0,0), world_size=None, mode='fbm', octaves=4, scale=1.0) |
Add sampled noise |
multiply_noise(source, world_origin=(0,0), world_size=None, mode='fbm', octaves=4, scale=1.0) |
Multiply by sampled noise |
add_bsp(bsp, *, pos=None, select='leaves', nodes=None, shrink=0, value=1.0) |
Add BSP regions |
multiply_bsp(bsp, *, pos=None, select='leaves', nodes=None, shrink=0, value=1.0) |
Multiply by BSP regions |
Subscript Access
# Get value at coordinates
value = hmap[x, y]
# Equivalent to get()
value = hmap.get(x, y)
Region Parameters
Many methods accept region parameters for operating on subsets:
# pos: destination start (x, y)
# source_pos: source start (x, y) for binary operations
# size: region dimensions (width, height)
# Fill a 10x10 region starting at (5, 5)
hmap.fill(1.0, pos=(5, 5), size=(10, 10))
# Copy from source region to destination region
hmap.copy_from(other, pos=(10, 10), source_pos=(0, 0), size=(20, 20))