A wrapper for hmm
Project description
pydelatin
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.
Install
With pip:
pip install pydelatin
or with Conda:
conda install -c conda-forge pydelatin
Binary wheels are provided for macOS and Linux. On Windows, glm
is a
prerequisite for building from source. Open an issue if you'd like to help
package binary wheels for Windows.
Using
Example
from pydelatin import Delatin
tin = Delatin(terrain, width, height)
# Mesh vertices
tin.vertices
# Mesh triangles
tin.triangles
API
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.
Delatin
Arguments
arr
(numpyndarray
): 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 height
Attributes
vertices
(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 thevertices
array. So[0, 1, 3, ...]
would use the first, second, and fourth vertices within thevertices
array as a single triangle.error
(float
): the maximum error of the mesh.
util.rescale_positions
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.
Arguments
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
, defaultFalse
) Flip y coordinates. Can be useful since images' coordinate origin is in the top left.
Saving to mesh formats
Quantized Mesh
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)
Meshio
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')
Martini
or Delatin
?
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).
Benchmark
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.
Python
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
JS (Node)
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
License
This package wraps @fogleman's hmm
, a C++ library that is also
MIT-licensed.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for pydelatin-0.2.2-cp39-cp39-manylinux2010_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c96d68388c8b32d9241274db63c801e358663c709c3e376b084827eb8ec4df18 |
|
MD5 | 328ab1e11a489fe045edb630794cc85e |
|
BLAKE2b-256 | dbe30ba54127815fa7c79b747eec4c3ed801fe96b9eeb0bb7e481e1503ceda59 |
Hashes for pydelatin-0.2.2-cp39-cp39-manylinux2010_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ebab206df27214884702746bf3325bb403a448dc823179c879db94eda7350c1a |
|
MD5 | b7be5857ef6c18441a992fbcc3707c1c |
|
BLAKE2b-256 | ebe632d6276e93f5ced74eb68abd4ee38a783866c808b67b419ad78c97eb1248 |
Hashes for pydelatin-0.2.2-cp39-cp39-macosx_10_9_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 425b17d7a7f221396989181512b376ff47203f68d48fc3a40681bbfbd41e2065 |
|
MD5 | 8aa0641e60a7ced1acb10e7fc111ee04 |
|
BLAKE2b-256 | cd31d351cf9eb14f8758c7064842b10ebca5bae6d5cb0f1099b39ba383414ca2 |
Hashes for pydelatin-0.2.2-cp38-cp38-manylinux2010_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8b92eb6be19d7b488352becdb40f74f55a673869ef28716b6c10f52496dfbe8a |
|
MD5 | fce4fb63174112182e4114dd0060d9f3 |
|
BLAKE2b-256 | ffb6f21a36422cf915dc85a1a8d9197d1902037b06ac8f7b9bc714cf43c47fc5 |
Hashes for pydelatin-0.2.2-cp38-cp38-manylinux2010_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 03c1ccc1f43b2cb98aef55b423a57294ef351b608e2a697a18e69513e77b99a5 |
|
MD5 | fe8901b77f616cb80cb0d0fd87e743af |
|
BLAKE2b-256 | a880a36c9be5ad8a600b6dbbf1ed2a5238be52588372bc187f9ab0805584ff0e |
Hashes for pydelatin-0.2.2-cp38-cp38-macosx_10_9_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | ce47356b42e4d1428eb66bf4aced44f601fa7b61fd3096957640aee2bbc9f51b |
|
MD5 | 9bc506dbda55d754eec5528c81541bcf |
|
BLAKE2b-256 | d6e5a43a60dc1b77d3e91f8d3b79884a15fe684ea9445484f00bad298098e72e |
Hashes for pydelatin-0.2.2-cp37-cp37m-manylinux2010_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e3daa27394d24a0f79c7df86cc9dfa1b484ebbbcd4ac3db0728c1961ae1454d5 |
|
MD5 | d00f7592c4de5067c11c3c1f3dc0675d |
|
BLAKE2b-256 | deb44ee5ef6cf59dffb2e068a042c299bf355d97e88e2d18acdea073778fc846 |
Hashes for pydelatin-0.2.2-cp37-cp37m-manylinux2010_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 782565565425170c8e8e62e79c610270146d31b1a688da53b8282e077ff784d0 |
|
MD5 | 59c09bbe9d7e5469db63df1d93ffe3e6 |
|
BLAKE2b-256 | aed5454d2ed814959fc309d775d7c85e9fc689bd3dbd7200f33e869cc8ecb73c |
Hashes for pydelatin-0.2.2-cp37-cp37m-macosx_10_9_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2eb338a1698a0b8e7733e36e67354ea5502f0902cbaf18e695efd1811dff3a07 |
|
MD5 | fe065fb0bf10f2d99d55aef91a3d51de |
|
BLAKE2b-256 | 1a391659d0474a3e58b9bc2c8e7693e4814724cfd2261907c23148a922e49736 |
Hashes for pydelatin-0.2.2-cp36-cp36m-manylinux2010_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 74ed299aa12e9df19064e4a71c19d4fe59c315d6d4ddbed44f2cee5e3f5e1e3e |
|
MD5 | fd7c88af7877e0778935a9096a2e94b9 |
|
BLAKE2b-256 | c70a737468ed4fead57f7445dd4e2c7bc66944fdcedb464fbbc36b6e6ed55ece |
Hashes for pydelatin-0.2.2-cp36-cp36m-manylinux2010_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8fe2756d08a5a87e8231f6a54b0db1d7fedf7a364dfdfac441ca47333934dc18 |
|
MD5 | abfd398381fbe2517c4a4c1a38cf8c74 |
|
BLAKE2b-256 | 4fd0f1ff2cc62870878da45442bc2f81fa01898f440f5e5491907316e04544f5 |
Hashes for pydelatin-0.2.2-cp36-cp36m-macosx_10_9_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | cca92e54d5171bd75ef55506b6b9e11c9e663af21072561aaf4edf822cb0914f |
|
MD5 | a6bcf83ed0ef2209d718acd02233820e |
|
BLAKE2b-256 | 69d273186beec10cdc9bbddac4d1864e6ab76c956b952c8efac5aaaf24ed23e9 |