A Python wrapper of hmm
(of which Delatin is a port) for fast terrain mesh generation.
A screenshot of Glacier National Park taken from the demo. The mesh is created using pydelatin
, encoded using quantized-mesh-encoder
, served on-demand using dem-tiler
, and rendered with deck.gl.
With pip:
or with Conda:
conda install -c conda-forge pydelatin
On Windows, installing via Conda is strongly recommended.
If installing with pip on Windows, glm
is a prerequisite for building from source. Open an issue if you'd like to help package binary wheels for Windows.
from pydelatin import Delatin tin = Delatin(terrain, width, height) # Mesh vertices tin.vertices # Mesh triangles tin.triangles
The API is similar to that of hmm
.
Additionally I include a helper function: decode_ele
, to decode a Mapbox Terrain RGB or Terrarium PNG array to elevations.
arr
(numpy ndarray
): data array. If a 2D array, dimensions are expected to be (height, width). If a 1D array, height and width parameters must be passed, and the array is assumed to be in C order.height
(int
, default: None
): height of array; required when arr is not 2Dwidth
(int
, default: None
): width of array; required when arr is not 2Dz_scale
(float
, default: 1
): z scale relative to x & yz_exag
(float
, default: 1
): z exaggerationmax_error
(float
, default: 0.001
): maximum triangulation errormax_triangles
(int
, default: None
): maximum number of trianglesmax_points
(int
, default: None
): maximum number of verticesbase_height
(float
, default: 0
): solid base heightlevel
(bool
, default: False
): auto level input to full grayscale rangeinvert
(bool
, default: False
): invert heightmapblur
(int
, default: 0
): gaussian blur sigmagamma
(float
, default: 0
): gamma curve exponentborder_size
(int
, default: 0
): border size in pixelsborder_height
(float
, default: 1
): border z heightvertices
(ndarray
of shape (-1, 3)
): the interleaved 3D coordinates of each vertex, e.g. [[x0, y0, z0], [x1, y1, z1], ...]
.triangles
(ndarray
of shape (-1, 3)
): represents indices within the vertices
array. So [0, 1, 3, ...]
would use the first, second, and fourth vertices within the vertices
array as a single triangle.error
(float
): the maximum error of the mesh.A helper function to rescale the vertices
output to a new bounding box. Returns an ndarray
of shape (-1, 3)
with positions rescaled. Each row represents a single 3D point.
vertices
: (np.ndarray
) vertices output from Delatinbounds
: (Tuple[float]
) linearly rescale position values to this extent. Expected to be [minx, miny, maxx, maxy]
.flip_y
: (bool
, default False
) Flip y coordinates. Can be useful since images' coordinate origin is in the top left.A common mesh format for the web is the Quantized Mesh format, which is supported in Cesium and deck.gl (via loaders.gl). You can use quantized-mesh-encoder
to save in this format:
import quantized_mesh_encoder from pydelatin import Delatin from pydelatin.util import rescale_positions tin = Delatin(terrain, max_error=30) vertices, triangles = tin.vertices, tin.triangles # Rescale vertices linearly from pixel units to world coordinates rescaled_vertices = rescale_positions(vertices, bounds) with open('output.terrain', 'wb') as f: quantized_mesh_encoder.encode(f, rescaled_vertices, triangles)
Alternatively, you can save to a variety of mesh formats using meshio
:
from pydelatin import Delatin import meshio tin = Delatin(terrain, max_error=30) vertices, triangles = tin.vertices, tin.triangles cells = [("triangle", triangles)] mesh = meshio.Mesh(vertices, cells) # Example output format # Refer to meshio documentation mesh.write('foo.vtk')
Two popular algorithms for terrain mesh generation are the "Martini" algorithm, found in the JavaScript martini
library and the Python pymartini
library, and the "Delatin" algorithm, found in the C++ hmm
library, this Python pydelatin
library, and the JavaScript delatin
library.
Which to use?
For most purposes, use pydelatin
over pymartini
. A good breakdown from a Martini issue:
Martini:
- Only works on square 2^n+1 x 2^n+1 grids.
- Generates a hierarchy of meshes (pick arbitrary detail after a single run)
- Optimized for meshing speed rather than quality.
Delatin:
- Works on arbitrary raster grids.
- Generates a single mesh for a particular detail.
- Optimized for quality (as few triangles as possible for a given error).
The following uses the same dataset as the pymartini
benchmarks, a 512x512 pixel heightmap of Mt. Fuji.
For the 30-meter mesh, pydelatin
is 25% slower than pymartini
, but the mesh is much more efficient: it has 40% fewer vertices and triangles.
pydelatin
is 4-5x faster than the JavaScript delatin
package.
git clone https://github.com/kylebarron/pydelatin cd pydelatin pip install '.[test]' python bench.py
mesh (max_error=30m): 27.322ms
vertices: 5668, triangles: 11140
mesh (max_error=1m): 282.946ms
mesh (max_error=2m): 215.839ms
mesh (max_error=3m): 163.424ms
mesh (max_error=4m): 127.203ms
mesh (max_error=5m): 106.596ms
mesh (max_error=6m): 91.868ms
mesh (max_error=7m): 82.572ms
mesh (max_error=8m): 74.335ms
mesh (max_error=9m): 65.893ms
mesh (max_error=10m): 60.999ms
mesh (max_error=11m): 55.213ms
mesh (max_error=12m): 54.475ms
mesh (max_error=13m): 48.662ms
mesh (max_error=14m): 47.029ms
mesh (max_error=15m): 44.517ms
mesh (max_error=16m): 42.059ms
mesh (max_error=17m): 39.699ms
mesh (max_error=18m): 37.657ms
mesh (max_error=19m): 36.333ms
mesh (max_error=20m): 34.131ms
This benchmarks against the delatin
JavaScript module.
git clone https://github.com/kylebarron/pydelatin cd test/bench_js/ yarn wget https://raw.githubusercontent.com/mapbox/delatin/master/index.js node -r esm bench.js
mesh (max_error=30m): 143.038ms
vertices: 5668
triangles: 11140
mesh (max_error=0m): 1169.226ms
mesh (max_error=1m): 917.290ms
mesh (max_error=2m): 629.776ms
mesh (max_error=3m): 476.958ms
mesh (max_error=4m): 352.907ms
mesh (max_error=5m): 290.946ms
mesh (max_error=6m): 240.556ms
mesh (max_error=7m): 234.181ms
mesh (max_error=8m): 188.273ms
mesh (max_error=9m): 162.743ms
mesh (max_error=10m): 145.734ms
mesh (max_error=11m): 130.119ms
mesh (max_error=12m): 119.865ms
mesh (max_error=13m): 114.645ms
mesh (max_error=14m): 101.390ms
mesh (max_error=15m): 100.065ms
mesh (max_error=16m): 96.247ms
mesh (max_error=17m): 89.508ms
mesh (max_error=18m): 85.754ms
mesh (max_error=19m): 79.838ms
mesh (max_error=20m): 75.607ms
This package wraps @fogleman's hmm
, a C++ library that is also MIT-licensed.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4