-
Notifications
You must be signed in to change notification settings - Fork 51
fix(pointcloud): near-term batch — correctness + code-org #614
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
louistrue
wants to merge
23
commits into
main
Choose a base branch
from
claude/pointcloud-near-term-LBxtJ
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
e81ae4b
fix(pointcloud): near-term batch — correctness + code-org
claude 11698d3
feat(pointcloud): near-term UX — hover XYZ, solid picker, legend, cancel
claude abcf25a
fix(pointcloud): map AbortError to "Cancelled" in federated loader
claude c2b7308
feat(pointcloud): PTS / XYZ ASCII reader
claude cdc4d0b
feat(pointcloud): E57 ScaledInteger codec — bit-packed cartesian / in…
claude 3541bd9
feat(pointcloud): E57 multi-scan pose merging
claude 4ed61f1
feat(pointcloud): GPU rectangle pick — marquee select for meshes + po…
claude 5cdfe03
feat(pointcloud): per-class visibility toggles for ASPRS scans
claude 5269c53
feat(pointcloud): section-plane drag preview — 1/4 density during sli…
claude 26b3d0b
feat(pointcloud): BIM ↔ scan deviation heatmap — GPU compute, all IFC
claude cbb8806
merge: PR-B PTS / XYZ ASCII reader
claude 0b30f7e
merge: PR-C E57 ScaledInteger codec
claude 3fc36a4
merge: PR-D E57 multi-scan pose merging
claude e7d2479
merge: PR-E GPU rectangle pick
claude bec68bc
merge: PR-F per-class visibility toggles
claude 9685f74
merge: PR-G section-plane drag preview
claude 4fe8f56
merge: PR-H BIM↔scan deviation heatmap (GPU compute)
claude 0dbb465
fix(pointcloud): address PR #614 review — correctness round
claude 7cdf6b3
fix(pointcloud): E57 packet bounds — no trailing CRC at packet level
claude 2b09650
chore(pointcloud): debug logging for classification colour mode
claude 21fb96d
feat(pointcloud): E57 classification field decode + clearer diagnostic
claude 6013ac6
fix(pointcloud): bypass laz-perf wasm fetch via Vite ?url asset
claude 5d0d26d
fix(pointcloud): address PR #614 review round 2
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| --- | ||
| "@ifc-lite/renderer": minor | ||
| "@ifc-lite/viewer": minor | ||
| --- | ||
|
|
||
| Per-class visibility toggles for ASPRS-classified point clouds. | ||
|
|
||
| A new "Classes" section in the point cloud panel exposes a checkbox | ||
| list of every LAS 1.4 standard class (Ground, Vegetation, Building, | ||
| Water, Wires, Bridge deck, ...). Toggling a class hides every point | ||
| with that classification. Works in any colour mode; the swatch | ||
| colours mirror the splat shader's classification palette so the UI | ||
| matches what's on screen. | ||
|
|
||
| Implementation: | ||
| - New `pointCloudClassMask: number` (u32 bitmask, default | ||
| `0xFFFFFFFF`) on the point cloud slice. `togglePointCloudClass(id)` | ||
| flips a single bit; `setPointCloudClassMask(mask)` replaces all 32. | ||
| - `PointCloudRenderOptions.classMask` plumbed through the renderer. | ||
| Stored in uniform slot `flags.w` (was unused). | ||
| - Splat shader checks `(flags.w >> classId) & 1` per vertex; hidden | ||
| classes get a degenerate `clipPos = vec4(0, 0, -2, 1)` so they're | ||
| culled before rasterisation rather than wasted on a fragment-stage | ||
| discard. | ||
| - New `PointCloudClasses` component in the panel renders a | ||
| `<details>` collapsible with "Show all" + per-class toggles. A | ||
| badge surfaces "N of 32 visible" when not all are on. | ||
| - `usePointCloudSync` forwards the mask to | ||
| `setPointCloudOptions({ classMask })`. | ||
|
|
||
| Class ids ≥32 always show — the mask only covers the standard | ||
| range. Custom-labelled scans need a richer UI (deferred). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| --- | ||
| "@ifc-lite/renderer": minor | ||
| "@ifc-lite/viewer": minor | ||
| --- | ||
|
|
||
| BIM ↔ scan deviation heatmap — GPU compute pipeline that colours each | ||
| scan point by signed distance to the nearest mesh surface. Works with | ||
| every IFC ingest path (STEP / IFCx / GLB / federated) and with every | ||
| point cloud format (inline IFCx + streamed LAS / LAZ / PLY / PCD / E57 | ||
| / PTS / XYZ — anywhere `Scene.forEachMeshData` reaches and any node | ||
| the splat pipeline already renders). | ||
|
|
||
| Pipeline: | ||
| 1. **Per-triangle BVH** built from `Scene.forEachMeshData()` — | ||
| reaches every CPU-side `MeshData` regardless of source. Median | ||
| split along longest axis, max 16 tris per leaf, flattened to a | ||
| `Float32Array` of 32-byte nodes during the build (no second | ||
| pass). | ||
| 2. **Two GPU storage buffers** — nodes + triangles — uploaded once | ||
| per mesh-set change. Cached by a `(meshCount, totalPositions)` | ||
| fingerprint so re-running deviation against the same model is a | ||
| pure dispatch. | ||
| 3. **Compute shader** with stack-based BVH descent (workgroup-size | ||
| 64). Per point: descend BVH pruning by squared point-to-AABB | ||
| distance, run Ericson §5.1.5 closest-point-on-triangle on every | ||
| leaf candidate, output signed distance via the closest face's | ||
| precomputed normal. | ||
| 4. **Per-chunk deviation buffer** allocated alongside the splat | ||
| vertex buffer (`STORAGE | VERTEX | COPY_DST`, 4 bytes per point, | ||
| zero-initialised). Compute reads the vertex buffer's positions | ||
| directly — no CPU copy of streamed clouds needed. | ||
| 5. **Splat shader** gains a 2nd vertex buffer (location 4 = `f32` | ||
| deviation), a new `deviation` color mode, and a diverging | ||
| blue → white → red `deviation_ramp`. Uniform block grows by 16 | ||
| bytes (new `deviationRange: vec4<f32>` slot for centre + half- | ||
| range), `POINT_UNIFORM_SIZE` 208 → 224. | ||
| 6. **Public API** — `Renderer.computeDeviations({ maxRange?, | ||
| forceRebuild? })` returns `{ bvhTriangles, bvhNodes, | ||
| chunksProcessed, pointsProcessed, bounds, suggestedHalfRange }`. | ||
| Awaits `queue.onSubmittedWorkDone` so callers see populated | ||
| buffers when the promise resolves. | ||
| 7. **UI** — new `DeviationPanel` inside `PointCloudPanel`. Compute | ||
| button (gated on `triangleCount > 0`), live progress + duration | ||
| readout, range slider in millimetres (1 mm to 1 m), inline | ||
| blue-white-red legend. Auto-suggests a half-range from the BVH | ||
| bbox (±max-extent / 1000) and auto-switches the colour mode to | ||
| `deviation` on success. | ||
| 8. **Slice** — `pointCloudColorMode` gains `'deviation'`, plus | ||
| `pointCloudDeviationCenterOffset`, `pointCloudDeviationHalfRange` | ||
| (default ±5 cm), and `pointCloudDeviationComputed`. Sync hook | ||
| forwards the range to the renderer uniform. | ||
|
|
||
| Sign convention: positive = scan point is on the outward-normal | ||
| side of the closest triangle (typical "scan overshoots wall by | ||
| 5 mm"). Negative = inside / behind. Non-watertight BIM (typical | ||
| IFC) means "inside the building" isn't globally defined, but | ||
| per-surface front/back is always meaningful. | ||
|
|
||
| Limitations / future work: | ||
| - The dispatch processes every uploaded point against every | ||
| triangle in the scene; isolated / hidden meshes still contribute | ||
| to the BVH. A `meshFilter` predicate is a natural follow-up. | ||
| - Histogram + auto-range from p5/p95 not yet implemented — the | ||
| default half-range suggestion is a coarse bbox/1000 heuristic. | ||
| Phase B will add a 2nd compute pass with atomic histogram. | ||
| - The BVH walk uses a 64-deep per-thread stack. Pathologically | ||
| unbalanced trees (>64 deep) silently drop the deepest branch. | ||
| Real BIMs don't get there; SAH or surface-area cost would help | ||
| if we ever hit it. | ||
|
|
||
| Verified: full repo typecheck (24/24), 655 viewer tests, viewer | ||
| Vite build green. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| --- | ||
| "@ifc-lite/pointcloud": minor | ||
| --- | ||
|
|
||
| E57 multi-scan pose merging — registered files now load. | ||
|
|
||
| Previously a multi-scan E57 with `<pose>` elements threw a clear | ||
| "re-export as merged" error. This change parses each Data3D's pose | ||
| (unit quaternion + translation) and applies it before merging, so | ||
| registered scans line up in the file's global frame. | ||
|
|
||
| Implementation: | ||
| - `Data3DEntry.hasPose: boolean` → `Data3DEntry.pose?: E57Pose` | ||
| carrying `{ rotation: {w,x,y,z}, translation: {x,y,z} }`. | ||
| - New `parsePoseElement` walks the `<pose><rotation/><translation/></pose>` | ||
| structure; non-finite values fall through to identity rather than | ||
| rejecting the whole file. | ||
| - New exported `applyPoseInPlace(positions, count, pose)` derives the | ||
| 3×3 rotation matrix from the quaternion (Hamilton convention, | ||
| `w + xi + yj + zk`) and computes `out = R · in + T` per point. | ||
| - `decodeE57` applies the pose after `decodeE57Scan` returns and | ||
| recomputes bbox; identity / absent poses are no-ops. | ||
| - The "Multi-scan pose merging is not yet supported" rejection is | ||
| removed. | ||
|
|
||
| 3 new tests: | ||
| - Pose extraction from XML (90°-around-Z quaternion + finite | ||
| translation, plus a no-pose sibling). | ||
| - `applyPoseInPlace` with a 90°-around-Z + translation, asserting | ||
| per-axis transforms. | ||
| - Identity pose round-trips positions unchanged. | ||
|
|
||
| Verified: 64 pointcloud unit tests pass, full repo typecheck (24/24), | ||
| viewer Vite build green. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| --- | ||
| "@ifc-lite/pointcloud": minor | ||
| "@ifc-lite/renderer": patch | ||
| --- | ||
|
|
||
| E57 ScaledInteger codec — bit-packed cartesian / intensity / colour. | ||
|
|
||
| ScaledInteger is the more compact encoding most real-world Faro, | ||
| Trimble, and Leica E57 exports use; previously we threw a clear | ||
| error on these files. This change implements the decoder so they | ||
| load directly. | ||
|
|
||
| Per spec ASTM E2807-11 §6.3.4: | ||
| - `bitsPerRecord = ceil(log2(maximum - minimum + 1))` | ||
| - Bytestream stores `raw_int = original − minimum` packed LSB-first | ||
| within each byte; decoded float = `(raw_int + minimum) * scale + offset` | ||
|
|
||
| Implementation: | ||
| - New `readBitsLE(bytes, bitOffset, bitsPerRecord)` walks a byte | ||
| buffer and reconstructs each value into a JS number using | ||
| `Math.pow(2, n)` instead of `<< n`, so precision holds up to 53 | ||
| bits (covers every real exporter — LiDAR + survey kit tops out | ||
| around 32 bits). Wider fields throw a clear error. | ||
| - `readCartesianStream` and `readIntensityStream` now branch on | ||
| field kind: Float / Integer paths unchanged, ScaledInteger path | ||
| bit-walks per record. | ||
| - `writeColorChannel` extended with a ScaledInteger branch that | ||
| remaps `raw → [0, 1]` via the declared min/max range. | ||
| - Per-axis packet capacity computation now varies by field kind | ||
| (Float = `length / byteSize`, ScaledInteger = `length * 8 / bitsPerRecord`) | ||
| via `floatOrSiPointCapacity`. | ||
|
|
||
| The "ScaledInteger throws clearly" error is removed for cartesian, | ||
| intensity, and colour — all three now decode. The earlier multi-scan | ||
| pose rejection stays in place; that's a separate piece of work. | ||
|
|
||
| 2 new tests: | ||
| - 8-bit ScaledInteger across all three cartesian axes (round-trip | ||
| through known raw values). | ||
| - 12-bit ScaledInteger that crosses byte boundaries (proves the | ||
| bit-pack walk is correct for non-multiples-of-8). | ||
|
|
||
| Verified: 63 pointcloud unit tests pass, full repo typecheck (24/24), | ||
| viewer Vite build green. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| --- | ||
| "@ifc-lite/pointcloud": patch | ||
| "@ifc-lite/viewer": patch | ||
| --- | ||
|
|
||
| Fix LAZ load failing with `WebAssembly: Response has unsupported MIME | ||
| type 'text/plain'` on real-world files (e.g. autzen-classified.laz). | ||
|
|
||
| `laz-perf`'s emscripten shim resolves the wasm via `locateFile()` and | ||
| calls `fetch("laz-perf.wasm")` relative to its own script directory. | ||
| In a Vite-bundled module worker that path becomes `/assets/<chunk>/…` | ||
| or just `/laz-perf.wasm` — both 404, and the SPA fallback returns | ||
| `index.html` as `text/plain`, which `instantiateStreaming` rightly | ||
| rejects. The async fallback then 404s the same way and aborts. | ||
|
|
||
| `loadLazPerf` now resolves the wasm asset URL through Vite's | ||
| `?url` import (`laz-perf/lib/web/laz-perf.wasm?url`), pre-fetches the | ||
| bytes itself, and hands them to emscripten as `Module.wasmBinary` so | ||
| the shim's own fetch is bypassed entirely. Failure modes (asset | ||
| resolution, fetch HTTP error) now produce a precise error message | ||
| naming the URL and status instead of the opaque emscripten "Aborted". |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| --- | ||
| "@ifc-lite/pointcloud": patch | ||
| "@ifc-lite/renderer": patch | ||
| "@ifc-lite/viewer": patch | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| --- | ||
|
|
||
| Near-term batch — correctness + robustness items from #611. | ||
|
|
||
| **`computeBBox` empty / non-finite guards.** Both `e57.ts` and | ||
| `ifcx-points.ts` now return `{0,0,0}/{0,0,0}` for empty arrays and | ||
| skip non-finite triplets. Previously a zero-point or NaN-poisoned | ||
| chunk produced ±Infinity bounds that broke camera fit-to-view and | ||
| section-plane sliders. | ||
|
|
||
| **Magic-byte-first format detection.** `detectPointCloudFormat` now | ||
| probes the buffer (E57 magic, LASF magic, "ply" / "#" / ".PCD" | ||
| ASCII tokens) before falling back to extension. A LAS file | ||
| mistakenly named `*.ply` no longer goes down the wrong decoder. LAS | ||
| vs LAZ still uses the extension to disambiguate (they share the | ||
| LASF magic). | ||
|
|
||
| **E57 packet-bounds + per-stream guards.** Validate that the | ||
| DataPacket header, bytestream-length table, and each individual | ||
| bytestream stay inside `payloadEnd = packetEnd - 4` before reading. | ||
| Corrupt files now fail with a precise "bytestream X runs past | ||
| packet payload" error instead of silently reading into the next | ||
| packet. | ||
|
|
||
| **`e57.ts` split (631 → 4 files).** `e57-page.ts` (header / page CRC | ||
| / section-header resolver), `e57-xml.ts` (prototype + Data3D | ||
| parser), `e57-decode.ts` (per-scan binary decoder), `e57.ts` | ||
| (orchestrator + re-exports). All four under the AGENTS ~400-line | ||
| guideline. | ||
|
|
||
| **`point-cloud-renderer.ts` extract.** Pulled the uniform-block | ||
| writer into `point-cloud-uniforms.ts` (`writePointCloudUniforms` + | ||
| mode index maps). Renderer drops below 400 lines. | ||
|
|
||
| Verified: 62 pointcloud unit tests pass, full repo typecheck | ||
| (24/24). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| --- | ||
| "@ifc-lite/renderer": minor | ||
| "@ifc-lite/viewer": minor | ||
| --- | ||
|
|
||
| Near-term UX features from #611. | ||
|
|
||
| **Hover XYZ readback.** GPU pick now also samples the depth texel at | ||
| the click position and unprojects it through the inverse view- | ||
| projection. `PickResult` carries an optional `worldXYZ`. Reverse-Z is | ||
| honoured (depth=1 = near, 0 = far / miss). The hover tooltip shows | ||
| `x, y, z` (2 decimals) under the entity id. Useful for measurement | ||
| hooks and point-cloud picks where the synthetic entity has no | ||
| surface property to display. | ||
|
|
||
| **Solid-color picker.** When the point-cloud panel's colour mode is | ||
| set to `fixed`, a native `<input type="color">` swatch appears. | ||
| Hex round-trips through the existing `[r,g,b,a]` store tuple. | ||
|
|
||
| **Colour-mode legend.** A new `PointCloudLegend` component renders | ||
| inline beneath the colour-mode buttons: | ||
| - Classification → list of ASPRS LAS 1.4 class id / colour swatch / | ||
| label (Ground, Vegetation, Building, ...). Palette mirrors | ||
| `point-shader.wgsl.ts` exactly. | ||
| - Intensity → black-to-white gradient bar with low/high labels. | ||
| - Height → cool-warm gradient bar (blue → cyan → green → yellow → | ||
| red), matching the shader's `height_ramp`. | ||
| RGB and Solid don't render a legend. | ||
|
|
||
| **Cancel button for in-flight streams.** New | ||
| `activeStreamCanceller` field on the loading slice. Both ingest | ||
| sites (`useIfcLoader`, `useIfcFederation`) register | ||
| `() => streamHandle.cancel()` after starting and clear on success / | ||
| error. `StatusBar` shows a Cancel button while the canceller is | ||
| non-null. AbortError on cancel is reported as "Cancelled" rather | ||
| than a scary error string. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| --- | ||
| "@ifc-lite/pointcloud": patch | ||
| "@ifc-lite/viewer": patch | ||
| --- | ||
|
|
||
| Round 2 of CodeRabbit feedback on PR #614: | ||
|
|
||
| - **E57 stride downsampling drops classifications.** `applyStride` rebuilt | ||
| positions / colors / intensities into new arrays but never copied the | ||
| per-point class IDs, so any non-default stride (`{ stride: 2 }` and up) | ||
| silently lost them and `hasClassification` flipped to false. | ||
| - **Federation abort can stomp a newer load.** The AbortError handler in | ||
| `useIfcFederation.addModel()` wrote `progress`, `error`, and `loading` | ||
| unconditionally — if a second `addModel()` started after the first was | ||
| cancelled, it lost its spinner and progress to the cancelled load's | ||
| cleanup. Added a `loadSessionRef` token (mirrors `useIfcLoader`) and | ||
| gate state writes on `loadSessionRef.current === currentSession`. | ||
| - **E57 Integer classification subtracts `minimum`.** Class IDs are | ||
| absolute labels (ASPRS LAS 1.4 0..31), not range-normalised offsets. | ||
| `raw - minimum` was corrupting class IDs whenever a producer declared | ||
| a non-zero `minimum` on the Integer-encoded classification field. The | ||
| Integer branch now matches the ScaledInteger branch's intent: keep | ||
| the raw byte, clamp to 0..255. | ||
| - **PCD probe missed `VERSION` / `FIELDS` headers.** The magic-byte | ||
| detector only recognised `# .PCD …` comment-style headers. Real PCDs | ||
| emitted by PCL's `pcl_io` and a few third-party tools start directly | ||
| with `VERSION 0.7\n…` or `FIELDS x y z\n…` — these now route through | ||
| the PCD decoder instead of falling through to extension-based | ||
| detection (which would mis-route a renamed PCD). | ||
| - **Catch-block logging.** Per repo convention, log point-cloud ingest | ||
| failures in `useIfcLoader.ts` before the early return so abort vs. | ||
| real-failure vs. stale-session paths are distinguishable in console | ||
| triage. | ||
|
|
||
| Test cleanup: drop the shadowed (and unused) ScaledInteger packet | ||
| buffer in `e57.test.ts` so only the live `fullBuf` setup remains. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| --- | ||
| "@ifc-lite/pointcloud": minor | ||
| "@ifc-lite/viewer": minor | ||
| --- | ||
|
|
||
| PTS / XYZ ASCII point cloud reader. | ||
|
|
||
| Both formats are line-oriented plain-text scans common in legacy | ||
| survey workflows. They share the same syntax — they differ only in | ||
| the optional first-line point count (PTS may have one; XYZ never | ||
| does). One shared decoder + streaming source handles both. | ||
|
|
||
| Auto-detected per-line layouts (by column count of the first data | ||
| line): | ||
| - 3 cols → `X Y Z` | ||
| - 4 cols → `X Y Z I` (intensity) | ||
| - 6 cols → `X Y Z R G B` | ||
| - 7 cols → `X Y Z I R G B` (canonical PTS) | ||
| - 9 cols → `X Y Z R G B Nx Ny Nz` (XYZ-with-normals; normals dropped) | ||
| - 10 cols → `X Y Z I R G B Nx Ny Nz` (PTS-with-normals; normals dropped) | ||
| - For XYZ with unknown column counts ≥3 we still emit positions and | ||
| skip the rest, so weird custom exports load instead of erroring. | ||
|
|
||
| Other behaviour: | ||
| - Comment lines (`#`, `//`) and blank lines are skipped. | ||
| - Intensity normalisation: 0..1 vs 0..255 vs raw sensor detected from | ||
| the observed maximum, then mapped to u16. | ||
| - RGB normalisation: same heuristic (>1.0 → 0..255 source). | ||
| - Whole-file decode wrapped in `AsciiPointsStreamingSource`; the | ||
| streaming host's 25M-point cap stride-downsamples on the way out. | ||
|
|
||
| Wired into the decode worker, format detection | ||
| (`detectPointCloudFormat` returns `'pts'` / `'xyz'`), the file | ||
| picker accept lists, drop handlers, and both `useIfcLoader` / | ||
| `useIfcFederation` ingest branches. The "PTS / XYZ ASCII points — | ||
| not yet supported" toast is removed from `describeUnsupportedFormat`. | ||
|
|
||
| 10 new unit tests cover layout probing, decoder round-trips for the | ||
| common shapes, and the comment / header-count edge cases. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.