@bitruvius/geo-core
v0.3.1
Published
Bitruvius geospatial SDK core: decoder/renderer/viewer-adapter contracts, geospatial math (ENU/ECEF/mercator), map-style expressions, and the dequantization reference. Builds on @bitruvius/foundation.
Readme
@bitruvius/geo-core
The contracts and geospatial math every Bitruvius package shares, in pure TypeScript with no GPU, wasm or DOM.
Internal building block. This package exists so that
@bitruvius/sdk-maplibreand the Bitruvius codecs can resolve their dependencies on npm. It has no standalone product story. Unless you are deliberately building against it, install the SDK instead.
Why it is a separate package
The SDK is assembled from packages that must not know about each other. A codec must not depend on a streaming engine. An engine must not depend on a codec. A renderer must not depend on a viewer. Each of those boundaries is an interface, and an interface has to live somewhere both sides can import it from without importing each other. That is this package.
The seams are real, not theoretical:
@bitruvius/turbo-lepccand@bitruvius/bvcboth implementI3sPointCloudDecoder. The@bitruvius/i3sengine imports the interface and never a codec, so you swap LEPCC for BVC without touching streaming or rendering.@bitruvius/draco,@bitruvius/meshoptand@bitruvius/ktx2implementDracoGeometryDecoder,MeshoptDecoderandKtx2Transcoder. They are injected into@bitruvius/gltf, which is why a codec package depends on geo-core and never on the parser.- The renderers (
splats,ptcloud,mesh,point-symbols,raster) are driven entirely throughViewerAdapterandFrameState. They do not know MapLibre exists. A new host is one adapter file, not a renderer fork.
The second reason is purity. Nothing here touches WebGL, wasm or the DOM, so the same code
runs on the main thread, inside a decode worker, and under bun test with no browser. That
is a requirement, not a preference: the worker packs a tile into the shared ENU grid, the
shader expands it back, and the tests prove the two agree. Both sides have to be reading
the same arithmetic from the same file.
Twenty other packages in this repository depend on geo-core. It depends on one thing,
@bitruvius/foundation.
What is in it
Contracts. Decoder and DecoderFactory, Renderer and TileHandle, ViewerAdapter
and FrameState, plus the per-format decode seams: GltfSplatDecoder,
I3sPointCloudDecoder, I3sMeshDecoder, CesiumPointDecoder, MeshTileDecoder.
The decoded model. DecodedSplatTile, DecodedPointTile and ContainerMeta carry
quantized structure-of-arrays straight out of the decoder, because dequantization is
deferred to the render shaders. PackedPointTile and PackedMeshTile are the ENU-rebased,
GPU-ready forms the renderers upload. No floating-point geometry crosses this boundary.
Geospatial math. WGS84 geodetic to ECEF and back (Bowring closed form), ECEF to ENU,
and Web Mercator implemented from the public definition to match MapLibre's
MercatorCoordinate exactly, so this math is interchangeable with the viewer's own.
Column-major mat4/mat3 and planes for frustum culling and clipping.
Measurement. What the SDK's measure tools are built on: slope and horizontal
distance, bearing, polyline length, polygon area and perimeter, the sampling grid behind
cut-and-fill volume, and contour extraction. These solve in the ENU tangent plane at the
feature being measured rather than on the ellipsoid, which is exact at city scale and
starts to drift past roughly 50 km; haversineDistance on the mean sphere is the
long-range cross-check and the axis measure for elevation profiles.
Packing. packPointTileEnu, packI3sPointsEnu, packGltfPointsEnu and packMeshEnu
rebase a decoded tile into the shared ENU meters frame and requantize it onto the
renderer's integer grid, so coordinates stay f32-exact however far the dataset sits from
the scene anchor. extractHardEdges derives the lines a person would draw if asked to
sketch a building, since no I3S or 3D Tiles service ships edge geometry.
Placement. ModelPlacement is the vocabulary the single-model layers expose: upAxis
preset, heading/pitch/roll in degrees, scale, anchorPoint. placementBasis and
modelPlacementMatrix compose the correct basis, including the mercator Y-flip that users
must never see. QuantBoundsAccumulator derives source-space bounds from streamed
quantized tiles, with robust percentiles, because splat captures arrive wrapped in a halo
of far-field background outliers that would otherwise hold the bounding box hostage.
Style and metadata. compileSqlFilter (Esri Building Scene Layer filterExpression)
and compileStyleExpression (3D Tiles declarative styling) compile to one AST and one
closure, evaluated per feature against a PropertyGetter. Hand-written tokenizer and
recursive-descent parser, no eval. I3S attributes, 3D Tiles batch tables and glTF
EXT_structural_metadata property tables all normalize into the same feature columns.
Dequant reference. The canonical inverse-quantization formulas. The GLSL shaders port these functions, and this module is the parity oracle they are tested against.
Because geo-core re-exports @bitruvius/foundation, importing it also gives you the
domain-agnostic base: TaskQueue, WorkerPool, detectCapabilities,
recommendDecodeBackend, SDK config and BitruviusError.
import { placementMatrix, toFloat32 } from '@bitruvius/geo-core';
const model = placementMatrix({ lng: -73.99, lat: 40.75, altitude: 0 });
gl.uniformMatrix4fv(uModel, false, toFloat32(model));Should you depend on it directly
Usually not. Install @bitruvius/sdk-maplibre
and you get this package as a transitive dependency.
Depend on it directly when you are implementing one of its seams: a decoder for your own
container format that an SDK engine should stream, or a ViewerAdapter for a host the SDK
does not ship. Those are the cases where you want the interface and nothing else.
It is published for that purpose, not as a general-purpose geospatial math library. The API tracks what the SDK needs and moves with SDK releases.
npm i @bitruvius/geo-coreTrademarks
Esri, ArcGIS, I3S and LEPCC are trademarks of Environmental Systems Research Institute, Inc. Cesium and 3D Tiles are trademarks of Cesium GS, Inc. Khronos, glTF and KTX are trademarks of The Khronos Group Inc. Google and Draco are trademarks of Google LLC. Niantic and SPZ are trademarks of Niantic, Inc. MapLibre is a trademark of the MapLibre organization. All other marks are the property of their respective owners.
These names are used solely to describe the data formats this software interoperates with. WebGL is a trademark of The Khronos Group Inc.
Bitruvius is not affiliated with, sponsored by, or endorsed by any of them, and no such relationship is implied.
License
Proprietary. The full terms ship as LICENSE inside this package, and are readable
before installing at cdn.bitruvius.com/legal/sdk-license-v1.txt.
© Bitruvius, Inc.
