-- NORMAL -- ~/projets/pointcloud-viewer.md projet 04 / 06

pointcloud-viewer

Un nuage LiDAR lu en Rust compilé en WebAssembly, puis posé sur la carte par three.js : tout se passe dans le navigateur.

Stack
Rust · WASM · React · three.js
Année
2026
Dépôt
github.com/Popoch39/pointcloud-viewer ↗
A

Anatomie

7 pièces · une seule les compte
Fig. 1 Un tour de tête, 628 points
  1. 01.las / .lazL78–87 ↗

    Choisir le fichier

    Un .las ou un .laz part à la conversion ; un .bin déjà converti s’ouvre aussitôt.

    openFile()

    78const openFile = useCallback(

    79 (file: File) => {

    80 if (/\.(bin|pcbk)$/i.test(file.name)) {

  2. 02Web WorkerL13–37 ↗

    Travailler en arrière-plan

    Lance la conversion à part, sans figer la page, puis rend le résultat sans le recopier.

    self.onmessage

    13let wasmReady: Promise<unknown> | null = null

    15self.onmessage = async (event: MessageEvent<BakeRequest>) => {

    16 const post = (message: BakeWorkerMessage, transfer: Transferable[] = []) =>

  3. 03reader.points()L48–132 ↗

    Convertir les points

    Rust relit chaque point et le recentre sur le coin du nuage pour rester précis en 32 bits.

    bake_to_pcbk()

    48pub fn bake_to_pcbk(

    49 las_bytes: Vec<u8>,

    50 mut on_progress: impl FnMut(u64, u64),

  4. 04TypedArrayL41–91 ↗

    Lire le format maison

    Un en-tête de 72 octets, puis 18 octets par point, lus sur place sans rien décoder.

    parseBakedPointCloud()

    41export function parseBakedPointCloud(buffer: ArrayBuffer): BakedPointCloud {

    42 if (buffer.byteLength < HEADER_SIZE) {

    43 throw new Error('PCBK buffer is smaller than its header')

  5. Placer le nuage sur la carte

    Seul le coin du nuage passe du Lambert-93 au GPS ; tous les points s’y accrochent.

    computeAnchor()

    22export function computeAnchor(cloud: BakedPointCloud, epsg: number): Anchor {

    23 const { worldOffset, bboxMin, bboxMax } = cloud

    24 const lngLat = toWgs84(epsg, worldOffset.x, worldOffset.y)

  6. 06custom layerL25–121 ↗

    Dessiner les points

    three.js dessine le nuage par-dessus le fond de carte, en un seul envoi au GPU.

    PointCloudLayer

    25export class PointCloudLayer implements CustomLayerInterface {

    26 readonly id = 'pointcloud'

    27 readonly type = 'custom' as const

  7. Changer les couleurs

    RGB, intensité, classe ou altitude : une seule valeur change, les points restent.

    createPointsMaterial()

    127export function createPointsMaterial(

    128 cloud: BakedPointCloud,

    129 mode: ColorMode,

100 000 pts · 1,80 Mo · EPSG:2154
Lecture des notes

Visez le terrain : la tête tourne vers le pointeur · clic sur la roue : couleurTouchez le terrain : la tête tourne jusqu’au point · toucher la roue : couleur

Fig. 1 — Le scanner relit sample.laz, le fichier d’essai du dépôt : 100 000 points en spirale autour d’une station du 6ᵉ arrondissement, en Lambert-93. Chaque tour de tête lit 628 points. Le miroir, c’est-à-dire le bake Rust compilé en WebAssembly dans un Web Worker, recentre chaque point sur la borne d’angle, le minimum du nuage, pour qu’il reste précis en f32. Le disque reçoit alors le PCBK : 72 octets d’en-tête au moyeu, puis 18 octets par point, en quatre secteurs, un par bloc. Le bake fini, three.js pose tout le nuage d’un coup sur le fond IGN, et la roue en change les couleurs sans toucher à la géométrie. Un point dessiné en représente 40, et l’instrument n’est pas à l’échelle du terrain.

Nomen­clature

  1. 01 Carte LAS/LAZ Le fichier choisi. Un .las ou un .laz part au bake dans un Worker, un .bin déjà cuit s’ouvre sur place. Code : src/hooks/use-bake.ts, lignes 78–87 ↗
  2. 02 Boîtier scellé Le Web Worker : il lit les octets du fichier, initialise le WebAssembly une seule fois, remonte la progression et rend le PCBK par transfert, sans copie. Code : src/workers/bake-worker.ts, lignes 13–37 ↗
  3. 03 Tambour du miroir Le bake Rust compilé en WebAssembly : il parcourt les points du LAS/LAZ, les recentre sur le minimum par axe pour qu’ils restent précis en f32, puis écrit l’en-tête de 72 octets et les blocs planaires. Code : webassembly/src/lib.rs, lignes 48–132 ↗
  4. 04 Disque PCBK Le format maison : vérifie le magic et la version, puis pose des vues TypedArray sur le buffer, sans rien décoder. Code : src/lib/baked-pointcloud.ts, lignes 41–91 ↗
  5. 05 Borne d’angle L’ancre : seul le World Offset est reprojeté (proj4 vers WGS84, puis Mercator), et tout le nuage se place autour de lui. Code : src/lib/map-anchor.ts, lignes 22–46 ↗
  6. 06 Nuage de points Le calque three.js sur le contexte WebGL de MapLibre : positions envoyées telles quelles, matrices composées en doubles à chaque image. Code : src/lib/pointcloud-layer.ts, lignes 25–121 ↗
  7. 07 Roue de filtres Le mode de couleur (RGB, intensité, classification, altitude) : un uniform change, la géométrie reste. Code : src/lib/pointcloud-shaders.ts, lignes 127–156 ↗