Package: pydelatin
pydelatinA Python wrapper ofhmm(of whichDelatinis a port) for fast terrain mesh generation.A screenshot of Glacier National Park taken fromthe demo. The mesh
is created usingpydelatin, encoded usingquantized-mesh-encoder, served on-demand usingdem-tiler, and rendered withdeck.gl.InstallWith pip:pip install pydelatinor with Conda:conda install -c conda-forge pydelatinOn Windows, installing via Conda is strongly recommended.If installing with pip on Windows,glmis a prerequisite for building
from source. Open an issue if you'd like to help package binary wheels for
Windows.UsingExamplefrompydelatinimportDelatintin=Delatin(terrain,width,height)# Mesh verticestin.vertices# Mesh trianglestin.trianglesAPIThe API is similar to that ofhmm.Additionally I include a helper function:decode_ele, to decode a Mapbox
Terrain RGB or Terrarium PNG array to elevations.DelatinArgumentsarr(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 heightAttributesvertices(ndarrayof shape(-1, 3)): the interleaved 3D coordinates of each vertex, e.g.[[x0, y0, z0], [x1, y1, z1], ...].triangles(ndarrayof shape(-1, 3)): representsindiceswithin theverticesarray. So[0, 1, 3, ...]would use the first, second, and fourth vertices within theverticesarray as a single triangle.error(float): the maximum error of the mesh.util.rescale_positionsA helper function to rescale theverticesoutput to a new bounding box.
Returns anndarrayof shape(-1, 3)with positions rescaled. Each row
represents a single 3D point.Argumentsvertices: (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 formatsQuantized MeshA common mesh format for the web is theQuantized Meshformat, which is supported in Cesium and deck.gl (vialoaders.gl). You can usequantized-mesh-encoderto save in this format:importquantized_mesh_encoderfrompydelatinimportDelatinfrompydelatin.utilimportrescale_positionstin=Delatin(terrain,max_error=30)vertices,triangles=tin.vertices,tin.triangles# Rescale vertices linearly from pixel units to world coordinatesrescaled_vertices=rescale_positions(vertices,bounds)withopen('output.terrain','wb')asf:quantized_mesh_encoder.encode(f,rescaled_vertices,triangles)MeshioAlternatively, you can save to a variety of mesh formats usingmeshio:frompydelatinimportDelatinimportmeshiotin=Delatin(terrain,max_error=30)vertices,triangles=tin.vertices,tin.trianglescells=[("triangle",triangles)]mesh=meshio.Mesh(vertices,cells)# Example output format# Refer to meshio documentationmesh.write('foo.vtk')MartiniorDelatin?Two popular algorithms for terrain mesh generation are the"Martini"algorithm, found in the JavaScriptmartinilibrary and the Pythonpymartinilibrary, and the"Delatin"algorithm, found in the
C++hmmlibrary, this Pythonpydelatinlibrary, and the JavaScriptdelatinlibrary.Which to use?For most purposes, usepydelatinoverpymartini. A good breakdown froma
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).BenchmarkThe following uses the same dataset as thepymartinibenchmarks, a 512x512 pixel heightmap of Mt. Fuji.For the 30-meter mesh,pydelatinis 25% slower thanpymartini, but the mesh
is much more efficient: it has 40% fewer vertices and triangles.pydelatinis 4-5x faster than the JavaScriptdelatinpackage.Pythongitclonehttps://github.com/kylebarron/pydelatincdpydelatin
pipinstall'.[test]'pythonbench.pymesh (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.131msJS (Node)This benchmarks against thedelatinJavaScript module.gitclonehttps://github.com/kylebarron/pydelatincdtest/bench_js/
yarn
wgethttps://raw.githubusercontent.com/mapbox/delatin/master/index.js
node-resmbench.jsmesh (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.607msLicenseThis package wraps @fogleman'shmm, a C++ library that is also
MIT-licensed.