SDK JS
    Preparing search index...

    LepccMapLibreLayer — a MapLibre CustomLayerInterface that loads a standalone LEPCC point cloud (an LPC1 container bundling the per-attribute Esri LEPCC blobs: xyz + rgb + intensity + LAS flags) via @bitruvius/turbo-lepcc and renders it georeferenced in the map.

    The same friendly placement vocabulary as every single-model layer (ModelPlacement), and the same scene citizenship: geo-sun env grading + cascaded shadow cast/receive, pickPosition for the measurement tools, and sampleSurfaceHeights for volume/DSM. LiDAR is real data — the stray-splat cull never touches point tiles. Under a non-affine (globe) projection the layer degrades to hidden — Mercator is the supported mode.

    const layer = new LepccMapLibreLayer({
    id: 'scan',
    url: 'https://…/scan.lepcc',
    anchor: { lng: -123.06875, lat: 44.05625, altitude: 0 },
    placement: { anchorPoint: 'bottom-center' },
    point: { colorMode: 'rgb' },
    });
    map.addLayer(layer);

    LepccMapLibreLayerOptions for every constructor option.

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    abort: AbortController = ...
    adapter: MapLibreViewerAdapter | null = null
    anchor: GeoAnchor
    decoder: Decoder
    id: string

    A unique layer id.

    map: Map$1 | null = null
    model: Mat4
    model_profile: ModelProfile | null = null
    points: PointCloudRenderer
    renderingMode: "3d" = ...

    Either "2d" or "3d". Defaults to "2d".

    splats: SplatRenderer
    type: "custom" = ...

    The layer's type. Must be "custom".

    Methods

    • Revert to the ungraded (full-daylight) look — the clearSun half of SunLightable.

      Returns void

    • The colour this layer draws a classification code in — the override when one is set, else the ASPRS default. What a swatch beside a class checkbox should show.

      Parameters

      • code: number

        The LAS classification code.

      Returns Rgb

      sRGB [r, g, b], each channel 0-1.

    • LAS classification codes present in the loaded point cloud — the input a class show/hide UI needs.

      Returns ClassificationInfo[]

      One entry per present class (code, human label, point count), sorted by code. Empty for clouds without a classification attribute.

    • The active colour ramp, or undefined when the built-in Turbo ramp is in use.

      Returns ColorRamp | undefined

    • The model's geographic footprint as [west, south, east, north] in degrees.

      Returns LayerExtent | null

      [west, south, east, north] in degrees, or null before the decode produces bounds.

      Derived rather than declared: a single-model container carries no georeference of its own — it is local metres plus wherever the app anchored it — so this is the decoded bounds, scaled by the resolved placement and offset from the anchor. That makes it move when setPlacement or setAnchor moves the model, which is correct and is the difference from a streaming layer's fixed service extent.

      The horizontal half-extent is taken as the larger of the two source axes across the up axis, so a rotated capture is bounded rather than clipped — this is a conservative box for deciding "is it on screen", not a tight hull.

    • The cloud's world-space height range — what the auto-fitted 'height' ramp spans, and the only sane range for a height-ramp slider.

      Returns [number, number] | null

      [min, max] in metres, or null before the decode.

    • Which renderer the decoded asset drove — the profile gate the settings widget uses to tell a splat capture from a point cloud, since one class (BvcMapLibreLayer) serves both.

      Returns ModelProfile | null

      'splat' / 'pointcloud', or null until the header parse completes.

    • The applied render settings, so a settings UI opens AGREEING with the scene instead of guessing from documented defaults. Keys match the control names LayerSettingsWidget reads.

      Returns Record<string, unknown>

      A flat snapshot of the applied values.

      Placement is not in here — getPlacement and getAnchor already report it, resolved. Nor is the intensity ramp: its slider is denominated in multiples of the full u16 range while the option is the raw multiplier, and seeding one from the other would move the control without moving the scene.

    • MapLibre CustomLayerInterface hook — invoked when the layer is added with map.addLayer; initializes GL resources and begins decoding.

      Parameters

      Returns void

    • MapLibre CustomLayerInterface hook — invoked when the layer is removed with map.removeLayer; aborts decoding and releases GL resources.

      Returns void

    • Pick the exact 3D position under a screen pixel — the PositionPickable seam the measurement tools consume (pickScenePosition / MeasurementWidget.pickLayers).

      Parameters

      • x: number

        Canvas X in CSS pixels (e.g. a MapLibre click event's e.point.x).

      • y: number

        Canvas Y in CSS pixels.

      • snapRadiusPx: number = 0

        Snap radius in CSS pixels (default 0 = exact pixel).

      Returns PickedPosition | null

      The picked position, or null on a miss / before the first frame.

    • Optional method called during a render frame to allow a layer to prepare resources or render into a texture.

      The layer cannot make any assumptions about the current GL state and must bind a framebuffer before rendering.

      Parameters

      Returns void

    • Rebuild the model matrix (and the point-cloud dequant offset), refresh the splat sort, and repaint — the single re-place site every mutation funnels through.

      Returns void

    • Called during a render frame allowing the layer to draw into the GL context.

      The layer can assume blending and depth state is set to allow the layer to properly blend and clip other layers. The layer cannot make any other assumptions about the current GL state.

      If the layer needs to render to a texture, it should implement the prerender method to do this and only use the render method for drawing directly into the main framebuffer.

      The blend function is set to gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA). This expects colors to be provided in premultiplied alpha form where the r, g and b values are already multiplied by the a value. If you are unable to provide colors in premultiplied form you may want to change the blend function to gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA).

      Parameters

      Returns void

    • Sample the height of the topmost rendered surface at each position — the on-nadir DSM the volume / elevation-profile tools consume (SurfaceSampleable).

      Parameters

      • points: readonly { lat: number; lng: number }[]

        lng/lat in degrees.

      • Optionalopts: SurfaceSampleOptions

        Optional: gridPx sets the overhead pass's long-axis resolution.

      Returns (number | null)[]

      Height per point (metres above the rendered ground datum), or null where the model has no surface / before the decode completes.

    • Move the model to a new geographic anchor. Repaints; the decoded data is untouched.

      Parameters

      • anchor: GeoAnchor

        The new GeoAnchor (lng/lat degrees, altitude meters).

      Returns void

    • Recolour one LAS classification code, leaving the rest of the palette untouched.

      Parameters

      • code: number

        The LAS classification code (e.g. 2 = ground).

      • color: Rgb | undefined

        sRGB [r, g, b], each channel 0-1, or undefined to restore the ASPRS default.

      Returns void

      The ASPRS palette is a convention rather than a rule, and a survey's own scheme routinely disagrees with it — "building" red over a red-roofed city reads as noise. Live GPU LUT update: no re-decode, no re-stream. Only classification colour mode is affected.

    • Show or hide one LAS classification code, leaving the rest untouched — the per-checkbox convenience over setPointOptions. Live GPU mask update.

      Parameters

      • code: number

        The LAS classification code (e.g. 2 = ground).

      • visible: boolean

        true to show points of this class, false to hide them.

      Returns void

    • Replace the colour ramp used by the intensity and height colour modes.

      Parameters

      • ramp: ColorRamp | undefined

        Stops (or a bare colour list spaced evenly), or undefined for Turbo.

      Returns void

      Turbo is a good default for LiDAR intensity and a poor one for a printed figure, a colour-blind reader, or a house style. Stops interpolate linearly in sRGB and need not be sorted; outside the end stops the ramp holds rather than fades. Live GPU LUT update.

      layer.setColorRamp([[0.05, 0.05, 0.2], [0.9, 0.9, 1]]); // dark blue → white
      layer.setColorRamp(undefined); // back to Turbo
    • Pin the colorMode: 'height' ramp to an explicit world-space window, or let it auto-fit.

      Parameters

      • opts: { max?: number | null; min?: number | null }

        min/max in metres; null (or omitted with the other set) returns that end to auto-fitting the loaded cloud.

      Returns void

    • The intensity → ramp mapping used by colorMode: 'intensity': t = i * scale + bias, where i is the raw u16 intensity. The default scale of 1/65535 spans the full u16 range, so a survey using only the low end of it comes out nearly black until the scale is raised.

      Parameters

      • opts: { bias?: number; scale?: number }

        scale multiplies the raw intensity; bias offsets the result.

      Returns void

    • Merge placement fields over the current ones and re-place the model — cheap (no re-decode or re-upload); repaints and refreshes the splat depth sort. Calling this exits raw-basis mode if setBasis was used.

      Parameters

      • partial: Partial<ModelPlacement>

        The ModelPlacement fields to merge (e.g. { heading: 45 }).

      Returns void

    • Update point-cloud render options at runtime (e.g. color mode, hidden classes).

      Parameters

      • partial: Partial<PointCloudOptions>

        The point-cloud options to merge over the current ones.

      Returns void

      Mirrors the hidden-class set so setClassVisible can toggle ONE code without the caller rebuilding the whole list, then hands off to the base for the apply and the settings snapshot — every option change funnels through one place.

    • Adjust point sizing: fixedPx > 0 = constant pixel size; otherwise perspective attenuation from pointRadiusM, clamped to [minPx, maxPx].

      Parameters

      • opts: { fixedPx?: number; maxPx?: number; minPx?: number; pointRadiusM?: number }

        The sizing fields to change; each is applied independently when set.

      Returns void

    • Draw round points instead of square ones.

      Parameters

      • on: boolean

      Returns void

    • Toggle cascaded sun shadows (cast onto terrain + self-shadow receive) at runtime — part of SunLightable, so the sun widget's Shadows switch reaches this layer.

      Parameters

      • on: boolean

      Returns void

    • The splat rasterization knobs: nSigma is the quad extent in standard deviations (smaller = tighter, cheaper, more clipping at the edges) and lowpass is the screen-space dilation in px² that keeps sub-pixel splats from aliasing away.

      Parameters

      • opts: { lowpass?: number; nSigma?: number }

        Each field is applied independently when set.

      Returns void

    • Grade the model by the environment (day/night exposure + sun tint) — satisfies the atmosphere system's SunLightable, so atmo.addLayer(layer) relights it. Splat captures are pre-lit, so this is a final color grade (no directional relight); the sun state also drives the cascaded shadow CAST (see setShadows).

      Parameters

      • sun: SunState

        The current sun state (from the geo-sun system / SunControlWidget).

      Returns void

    • Toggle degree-1+ view-dependent lighting (spherical harmonics) on a splat capture. false is flatter and cheaper; a no-op on a capture stored at SH degree 0.

      Parameters

      • on: boolean

      Returns void

    • Show or hide the model without removing the layer. The decode is untouched and stays on the GPU, so toggling back is instant.

      Parameters

      • visible: boolean

        false to skip the draw.

      Returns void

    • Upload one decoded tile to the GPU.

      Parameters

      • t: DecodedTile

        The decoded tile.

      Returns void

      Overridable, but NOT the place to drop splats. The stray-splat cull already ran before this — see SingleModelLayerInit.cullStray, which is ON by default and culls before the bounds pass — so filtering again here culls an already-culled distribution. Because the cutoff is self-scaling (factor x r90), a second pass recomputes r90 against the tight remainder and discards most of the subject; the model appears briefly and then all but vanishes, leaving a rim. warnIfUploadShrank says so out loud rather than leaving it to be discovered.