kylebarron / quantized-mesh-encoder Goto Github PK
View Code? Open in Web Editor NEWA fast Python Quantized Mesh encoder
Home Page: https://kylebarron.dev/quantized-mesh-encoder
License: MIT License
A fast Python Quantized Mesh encoder
Home Page: https://kylebarron.dev/quantized-mesh-encoder
License: MIT License
I often dump the bytes of a numpy array to a buffer for fast writing to file
This probably uses system endianness. Since quantized mesh files must be little-endian, presumably files written on big-endian computers would be incorrect.
Look at the Numpy byte-swapping docs for a fix
Quantized mesh tiles are by gzip encoded per the spec. Show how easy it is for the file object to be a gzip file descriptor
to a buffer:
gzip.GzipFile(fileobj=io.BytesIO(), mode='w').writable()
https://stackoverflow.com/a/32794964
to a file:
with gzip.open("path/to/file.gz", 'wb') as f:
f.write(bytes)
TODO
comment in 87bddb4. It's been assigned to @kylebarron because they committed the code.It looks like (py)martini creates a mesh with vertices (at least sometimes) in clockwise order, while the Quantized Mesh spec requires counter-clockwise winding order.
e.g. here are the first three 2D vertices, and it looks like they define a clockwise triangle
So I should add an option, probably True
by default, that checks the input geometries and flips the order of indices
if the triangle is in clockwise winding order.
It looks like it shouldn't actually be too slow to check, though it might be best in Cython... not sure if I can vectorize it easily
how to obj import to lod tiles without using dem?
quantized-mesh-encoder/site/src/tile-layer/tile-layer.js
Lines 12 to 17 in 204bcfc
TODO
comment in 204bcfc. It's been assigned to @kylebarron because they committed the code.Optionally compute vertex normals extension. There's two parts:
Based on the quantized-mesh-tile
implementation, essentially for every vertex you look at all the triangles that touch it. For each triangle, compute its normal, and then average the normals of the touching triangles to find each per-vertex normal.
I think that to make it performant, you'd want to first compute all the normals of the triangles. And then you can use that array of normals somehow as a lookup table, so that you can find all the triangles per vertex at once, and then average within the axis...
Quantizing and encoding each x, y, z 96-bit floating point unit vector into an x,y 16-bit representation.
I don't want to add code to generate a water mask, since you can't assume elevations < 0
are ocean. But you could add an argument to encode
to allow a user to pass a pregenerated water mask.
TODO
comment in 87bddb4. It's been assigned to @kylebarron because they committed the code.Currently I only have the "naive" method of finding an axis-aligned bounding box, then finding the sphere from that box.
It would be good to finish the ritter method, then to take the minimum of the two of them.
References:
e.g. decode existing tile with quantized-mesh-tile
, encode with mine and check?
14/3090/6430.terrain?url=terrarium
viewed in quantized-mesh-viewer
Hi @kylebarron,
I can't visualize proper your example demo: https://kylebarron.dev/quantized-mesh-encoder/
Looks like it's related to CORS
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at
https://us-east-1-lambda.kylebarron.dev/dem/mesh/13/1507/2820.terrain?url=terrarium&mesh_max_error=9.41&mesh_algorithm=pydelatin&flip_y=true.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 530.
url:
https://api.maptiler.com/tiles/terrain-quantized-mesh/13/3090/5737.terrain?key=...
bounds:
-112.08251953125,
36.0791015625,
-112.1044921875,
36.057128906249986
x, y, level = 3090, 5737, 13
import numpy as np
self =GeographicTilingScheme()
class GeographicTilingScheme:
def __init__(self):
self._numberOfLevelZeroTilesX = 2
self._numberOfLevelZeroTilesY = 1
self._rectangle = (-np.pi, -np.pi/2, np.pi, np.pi/2)
def getNumberOfXTilesAtLevel(self, level):
"""
Gets the total number of tiles in the X direction at a specified level-of-detail
@param {Number} level The level-of-detail.
@returns {Number} The number of tiles in the X direction at the given level.
"""
return self._numberOfLevelZeroTilesX << level
def getNumberOfYTilesAtLevel(self, level):
"""
Gets the total number of tiles in the Y direction at a specified level-of-detail.
@param {Number} level The level-of-detail.
@returns {Number} The number of tiles in the Y direction at the given level.
"""
return self._numberOfLevelZeroTilesY << level
def tileXYToRectangle(self, x, y, level):
rectangle = self._rectangle
xTiles = self.getNumberOfXTilesAtLevel(level)
yTiles = self.getNumberOfYTilesAtLevel(level)
width = rectangle[2] - rectangle[0]
xTileWidth = width / xTiles
west = x * xTileWidth + rectangle[0]
east = (x + 1) * xTileWidth + rectangle[0]
height = rectangle[3] - rectangle[1]
yTileHeight = height / yTiles
north = rectangle[3] - y * yTileHeight
south = rectangle[3] - (y + 1) * yTileHeight
return np.array([east, south, west, north])
def tileXYToNativeRectangle(self, x, y, level):
"""
Converts tile x, y coordinates and level to a rectangle expressed in the native coordinates
of the tiling scheme.
Args:
- x: The integer x coordinate of the tile.
- y: The integer y coordinate of the tile.
- level: level The tile level-of-detail. Zero is the least detailed.
"""
return np.degrees(self.tileXYToRectangle(x, y, level))
from shapely.geometry import box
bounds = list(np.degrees(self.tileXYToRectangle(x, y, level)))
bounds[1] = np.abs(bounds[1])
bounds[3] = np.abs(bounds[3])
print(bounds)
g = box(bounds[0], bounds[3], bounds[2], bounds[1])
from keplergl_cli import Visualize
g.exterior.coords
Visualize(g)
type(g)
g.exterior.coords
box(*np.degrees(self.tileXYToRectangle(x, y, level)))
e.g. pydelatin currently returns a 2d array of shape (-1, 3)
(which is sensible) but encode_indices
expects a 1d array.
You should also cast to np.uint32
, the data type expected by the cython encode_indices
implementation.
You should also use .astype(np.uint32, casting='safe')
so that an error would be produced if the data can't be transformed effectively.
It would look much cleaner to just subclass TerrainLayer
, because the only thing you'd have to overwrite is loadTerrain
quantized-mesh-encoder/quantized_mesh_encoder/bounding_sphere.py
Lines 45 to 47 in 0e6b16e
TODO
comment in 0e6b16e. It's been assigned to @kylebarron because they committed the code.TODO
comment in 5fc5bb2. It's been assigned to @kylebarron because they committed the code.TODO
comment in 5fc5bb2. It's been assigned to @kylebarron because they committed the code.A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.