diff --git a/lonboard/experimental/__init__.py b/lonboard/experimental/__init__.py index fd809b3f..c8bcedac 100644 --- a/lonboard/experimental/__init__.py +++ b/lonboard/experimental/__init__.py @@ -4,10 +4,11 @@ unexpected behavior when using them. """ -from ._layer import ArcLayer, TextLayer, TripsLayer +from ._layer import ArcLayer, SimpleMeshLayer, TextLayer, TripsLayer __all__ = [ "ArcLayer", + "SimpleMeshLayer", "TextLayer", "TripsLayer", ] diff --git a/lonboard/experimental/_layer.py b/lonboard/experimental/_layer.py index fc021ecc..40dc051d 100644 --- a/lonboard/experimental/_layer.py +++ b/lonboard/experimental/_layer.py @@ -15,7 +15,7 @@ from arro3.core import DataType, Scalar from lonboard._constants import EXTENSION_NAME, MIN_INTEGER_FLOAT32 -from lonboard._layer import BaseArrowLayer +from lonboard._layer import BaseArrowLayer, BaseLayer from lonboard._utils import timestamp_max_physical_value, timestamp_start_offset from lonboard.experimental.traits import TimestampAccessor from lonboard.traits import ( @@ -176,6 +176,19 @@ def __init__( ) +class SimpleMeshLayer(BaseLayer): + """SimpleMeshLayer.""" + + def __init__(self, **kwargs) -> None: + super().__init__(**kwargs) # type: ignore + + _layer_type = t.Unicode("simple-mesh").tag(sync=True) + + positions = PointAccessor(None, allow_none=True) + normals = PointAccessor(None, allow_none=True) + tex_coords = PointAccessor(None, allow_none=True) + + class TextLayer(BaseArrowLayer): """Render text labels at given coordinates.""" diff --git a/package-lock.json b/package-lock.json index d86d2007..f530761e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "@deck.gl/core": "^9.1.14", "@deck.gl/extensions": "^9.1.14", "@deck.gl/layers": "^9.1.14", + "@deck.gl/mesh-layers": "^9.1.14", "@deck.gl/react": "^9.1.14", "@geoarrow/deck.gl-layers": "^0.3.1", "@nextui-org/react": "^2.4.8", @@ -1402,7 +1403,6 @@ "version": "9.1.14", "resolved": "https://registry.npmjs.org/@deck.gl/mesh-layers/-/mesh-layers-9.1.14.tgz", "integrity": "sha512-NVUw0yG4stJfrklWCGP9j8bNlf9YQc4PccMeNNIHNrU/Je6/Va6dJZg0RGtVkeaTY1Lk3A7wRzq8/M5Urfvuiw==", - "peer": true, "dependencies": { "@loaders.gl/gltf": "^4.2.0", "@luma.gl/gltf": "~9.1.9", @@ -2394,7 +2394,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/@loaders.gl/draco/-/draco-4.3.4.tgz", "integrity": "sha512-4Lx0rKmYENGspvcgV5XDpFD9o+NamXoazSSl9Oa3pjVVjo+HJuzCgrxTQYD/3JvRrolW/QRehZeWD/L/cEC6mw==", - "peer": true, "dependencies": { "@loaders.gl/loader-utils": "4.3.4", "@loaders.gl/schema": "4.3.4", @@ -2434,7 +2433,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-4.3.4.tgz", "integrity": "sha512-EiUTiLGMfukLd9W98wMpKmw+hVRhQ0dJ37wdlXK98XPeGGB+zTQxCcQY+/BaMhsSpYt/OOJleHhTfwNr8RgzRg==", - "peer": true, "dependencies": { "@loaders.gl/draco": "4.3.4", "@loaders.gl/images": "4.3.4", @@ -2543,7 +2541,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/@loaders.gl/textures/-/textures-4.3.4.tgz", "integrity": "sha512-arWIDjlE7JaDS6v9by7juLfxPGGnjT9JjleaXx3wq/PTp+psLOpGUywHXm38BNECos3MFEQK3/GFShWI+/dWPw==", - "peer": true, "dependencies": { "@loaders.gl/images": "4.3.4", "@loaders.gl/loader-utils": "4.3.4", @@ -2666,7 +2663,6 @@ "version": "9.1.9", "resolved": "https://registry.npmjs.org/@luma.gl/gltf/-/gltf-9.1.9.tgz", "integrity": "sha512-KgVBIFCtRO1oadgMDycMJA5s+q519l/fQBGAZpUcLfWsaEDQfdHW2NLdrK/00VDv46Ng8tN/O6uyH6E40uLcLw==", - "peer": true, "dependencies": { "@loaders.gl/core": "^4.2.0", "@loaders.gl/textures": "^4.2.0", @@ -8777,8 +8773,7 @@ "node_modules/draco3d": { "version": "1.5.7", "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", - "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", - "peer": true + "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==" }, "node_modules/dunder-proto": { "version": "1.0.1", @@ -9989,7 +9984,6 @@ "version": "0.7.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", - "peer": true, "bin": { "image-size": "bin/image-size.js" }, @@ -10733,8 +10727,7 @@ "node_modules/ktx-parse": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.7.1.tgz", - "integrity": "sha512-FeA3g56ksdFNwjXJJsc1CCc7co+AJYDp6ipIp878zZ2bU8kWROatLYf39TQEd4/XRSUvBXovQ8gaVKWPXsCLEQ==", - "peer": true + "integrity": "sha512-FeA3g56ksdFNwjXJJsc1CCc7co+AJYDp6ipIp878zZ2bU8kWROatLYf39TQEd4/XRSUvBXovQ8gaVKWPXsCLEQ==" }, "node_modules/levn": { "version": "0.4.1", @@ -13624,8 +13617,7 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "peer": true + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/stackback": { "version": "0.0.2", @@ -14053,7 +14045,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz", "integrity": "sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig==", - "peer": true, "dependencies": { "argparse": "^1.0.10", "image-size": "^0.7.4" @@ -14066,7 +14057,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } diff --git a/package.json b/package.json index 82f5c2cf..40ba5f65 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "@deck.gl/core": "^9.1.14", "@deck.gl/extensions": "^9.1.14", "@deck.gl/layers": "^9.1.14", + "@deck.gl/mesh-layers": "^9.1.14", "@deck.gl/react": "^9.1.14", "@geoarrow/deck.gl-layers": "^0.3.1", "@babel/runtime": "^7.28.4", diff --git a/src/model/layer.ts b/src/model/layer.ts index e00614e9..0f2a3540 100644 --- a/src/model/layer.ts +++ b/src/model/layer.ts @@ -1,3 +1,4 @@ +import { SimpleMeshLayer, SimpleMeshLayerProps } from "@deck.gl/mesh-layers"; import { GeoArrowArcLayer, GeoArrowColumnLayer, @@ -772,6 +773,81 @@ export class SolidPolygonModel extends BaseArrowLayerModel { } } +type MeshPositions = { + value: Float32Array; + size: number; +}; + +type MeshNormals = { + value: Float32Array; + size: number; +}; + +type MeshTexCoords = { + value: Float32Array; + size: number; +}; + +const DUMMY_DATA: number[] = [1]; + +export class SimpleMeshModel extends BaseLayerModel { + static layerType = "simple-mesh"; + + protected positions!: MeshPositions; + protected normals!: MeshNormals; + protected texCoords!: MeshTexCoords; + + protected sizeScale: SimpleMeshLayerProps["sizeScale"]; + protected wireframe: SimpleMeshLayerProps["wireframe"]; + // protected material: SimpleMeshLayerProps["material"]; + // protected getPosition: SimpleMeshLayerProps["getPosition"] | null; + // protected getColor: SimpleMeshLayerProps["getColor"] | null; + // protected getOrientation: SimpleMeshLayerProps["getOrientation"] | null; + // protected getScale: SimpleMeshLayerProps["getScale"] | null; + // protected getTranslation: SimpleMeshLayerProps["getTranslation"] | null; + + constructor(model: WidgetModel, updateStateCallback: () => void) { + super(model, updateStateCallback); + + this.initVectorizedAccessor("positions", "positions"); + this.initVectorizedAccessor("normals", "normals"); + this.initVectorizedAccessor("tex_coords", "texCoords"); + + this.initRegularAttribute("size_scale", "sizeScale"); + this.initRegularAttribute("wireframe", "wireframe"); + } + + layerProps(): Omit { + return { + data: DUMMY_DATA, + mesh: { + positions: this.positions, + normals: this.normals, + texCoords: this.texCoords, + }, + ...(isDefined(this.sizeScale) && { sizeScale: this.sizeScale }), + ...(isDefined(this.wireframe) && { wireframe: this.wireframe }), + // ...(isDefined(this.material) && { material: this.material }), + // ...(isDefined(this.getPosition) && { getPosition: this.getPosition }), + // ...(isDefined(this.getColor) && { getColor: this.getColor }), + // ...(isDefined(this.getOrientation) && { + // getOrientation: this.getOrientation, + // }), + // ...(isDefined(this.getScale) && { getScale: this.getScale }), + // ...(isDefined(this.getTranslation) && { + // getTranslation: this.getTranslation, + // }), + }; + } + + render(): SimpleMeshLayer { + return new SimpleMeshLayer({ + ...this.baseLayerProps(), + ...this.layerProps(), + }); + } +} + export class TextModel extends BaseArrowLayerModel { static layerType = "text"; @@ -1025,6 +1101,10 @@ export async function initializeLayer( layerModel = new SolidPolygonModel(model, updateStateCallback); break; + case SimpleMeshModel.layerType: + layerModel = new SimpleMeshModel(model, updateStateCallback); + break; + case TextModel.layerType: layerModel = new TextModel(model, updateStateCallback); break;