@loaders.gl/potree 4.3.0-alpha.5 → 4.3.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dist.dev.js +19533 -16
- package/dist/dist.min.js +21 -1
- package/dist/index.cjs +172 -16
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/potree-node-source.d.ts +6 -6
- package/dist/lib/potree-node-source.d.ts.map +1 -1
- package/dist/lib/potree-node-source.js +12 -10
- package/dist/parsers/parse-potree-hierarchy-chunk.d.ts +21 -2
- package/dist/parsers/parse-potree-hierarchy-chunk.d.ts.map +1 -1
- package/dist/parsers/parse-potree-hierarchy-chunk.js +32 -18
- package/dist/potree-hierarchy-chunk-loader.js +1 -1
- package/dist/potree-loader.js +1 -1
- package/package.json +5 -5
- package/src/index.ts +1 -0
- package/src/lib/potree-node-source.ts +20 -16
- package/src/parsers/parse-potree-hierarchy-chunk.ts +52 -26
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import {load} from '@loaders.gl/core';
|
|
6
|
-
import {
|
|
6
|
+
import {Mesh} from '@loaders.gl/schema';
|
|
7
7
|
import {DataSource, DataSourceProps, LoaderOptions, resolvePath} from '@loaders.gl/loader-utils';
|
|
8
8
|
import {LASLoader} from '@loaders.gl/las';
|
|
9
9
|
import {PotreeMetadata} from '../types/potree-metadata';
|
|
@@ -59,6 +59,10 @@ export class PotreeNodesSource extends DataSource {
|
|
|
59
59
|
|
|
60
60
|
/** Initial data source loading */
|
|
61
61
|
async init() {
|
|
62
|
+
if (this.initPromise) {
|
|
63
|
+
await this.initPromise;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
62
66
|
this.metadata = await load(`${this.baseUrl}/cloud.js`, PotreeLoader);
|
|
63
67
|
await this.loadHierarchy();
|
|
64
68
|
this.isReady = true;
|
|
@@ -70,7 +74,7 @@ export class PotreeNodesSource extends DataSource {
|
|
|
70
74
|
return (
|
|
71
75
|
this.isReady &&
|
|
72
76
|
major === 1 &&
|
|
73
|
-
minor
|
|
77
|
+
minor <= 8 &&
|
|
74
78
|
typeof this.metadata?.pointAttributes === 'string' &&
|
|
75
79
|
['LAS', 'LAZ'].includes(this.metadata?.pointAttributes)
|
|
76
80
|
);
|
|
@@ -96,7 +100,7 @@ export class PotreeNodesSource extends DataSource {
|
|
|
96
100
|
* @param path array of numbers between 0-7 specifying successive octree divisions.
|
|
97
101
|
* @return node content geometry or null if the node doesn't exist
|
|
98
102
|
*/
|
|
99
|
-
async loadNodeContent(path: number[]): Promise<
|
|
103
|
+
async loadNodeContent(path: number[]): Promise<Mesh | null> {
|
|
100
104
|
await this.initPromise;
|
|
101
105
|
|
|
102
106
|
if (!this.isSupported()) {
|
|
@@ -106,25 +110,15 @@ export class PotreeNodesSource extends DataSource {
|
|
|
106
110
|
const isAvailable = await this.isNodeAvailable(path);
|
|
107
111
|
if (isAvailable) {
|
|
108
112
|
return load(
|
|
109
|
-
`${this.baseUrl}/${this.metadata
|
|
110
|
-
|
|
113
|
+
`${this.baseUrl}/${this.metadata?.octreeDir}/r/r${path.join(
|
|
114
|
+
''
|
|
115
|
+
)}.${this.getContentExtension()}`,
|
|
111
116
|
LASLoader
|
|
112
117
|
);
|
|
113
118
|
}
|
|
114
119
|
return null;
|
|
115
120
|
}
|
|
116
121
|
|
|
117
|
-
/**
|
|
118
|
-
* Load data source hierarchy into tree of available nodes
|
|
119
|
-
*/
|
|
120
|
-
async loadHierarchy(): Promise<void> {
|
|
121
|
-
await this.initPromise;
|
|
122
|
-
this.root = await load(
|
|
123
|
-
`${this.baseUrl}/${this.metadata?.octreeDir}/r/r.hrc`,
|
|
124
|
-
PotreeHierarchyChunkLoader
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
122
|
/**
|
|
129
123
|
* Check if a node exists in the octree
|
|
130
124
|
* @param path array of numbers between 0-7 specifying successive octree divisions
|
|
@@ -155,6 +149,16 @@ export class PotreeNodesSource extends DataSource {
|
|
|
155
149
|
return result;
|
|
156
150
|
}
|
|
157
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Load data source hierarchy into tree of available nodes
|
|
154
|
+
*/
|
|
155
|
+
private async loadHierarchy(): Promise<void> {
|
|
156
|
+
this.root = await load(
|
|
157
|
+
`${this.baseUrl}/${this.metadata?.octreeDir}/r/r.hrc`,
|
|
158
|
+
PotreeHierarchyChunkLoader
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
158
162
|
/**
|
|
159
163
|
* Deduce base url from the input url sring
|
|
160
164
|
* @param data - data source input data
|
|
@@ -54,32 +54,53 @@ Would have an index looking like this:
|
|
|
54
54
|
| r36 | `0b00000000` (=0) | `1` |
|
|
55
55
|
*/
|
|
56
56
|
|
|
57
|
-
/**
|
|
57
|
+
/** Node metadata from index file */
|
|
58
58
|
export type POTreeTileHeader = {
|
|
59
|
+
/** Number of child nodes */
|
|
59
60
|
childCount: number;
|
|
61
|
+
/** Human readable name */
|
|
60
62
|
name: string;
|
|
63
|
+
/** Child availability mask */
|
|
61
64
|
childMask: number;
|
|
62
65
|
};
|
|
63
66
|
|
|
64
|
-
/**
|
|
67
|
+
/** Hierarchical potree node structure */
|
|
65
68
|
export type POTreeNode = {
|
|
69
|
+
/** Index data */
|
|
66
70
|
header: POTreeTileHeader;
|
|
71
|
+
/** Human readable name */
|
|
67
72
|
name: string;
|
|
73
|
+
/** Number of points */
|
|
68
74
|
pointCount: number;
|
|
75
|
+
/** Node's level in the tree */
|
|
76
|
+
level: number;
|
|
77
|
+
/** Has children */
|
|
78
|
+
hasChildren: boolean;
|
|
79
|
+
/** Space between points */
|
|
80
|
+
spacing: number;
|
|
81
|
+
/** Available children */
|
|
69
82
|
children: POTreeNode[];
|
|
83
|
+
/** All children including unavailable */
|
|
70
84
|
childrenByIndex: POTreeNode[];
|
|
71
85
|
};
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
87
|
+
/**
|
|
88
|
+
* load hierarchy
|
|
89
|
+
* @param arrayBuffer - binary index data
|
|
90
|
+
* @returns root node
|
|
91
|
+
**/
|
|
92
|
+
export function parsePotreeHierarchyChunk(arrayBuffer: ArrayBuffer): POTreeNode {
|
|
77
93
|
const tileHeaders = parseBinaryChunk(arrayBuffer);
|
|
78
94
|
return buildHierarchy(tileHeaders);
|
|
79
95
|
}
|
|
80
96
|
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Parses the binary rows
|
|
99
|
+
* @param arrayBuffer - binary index data to parse
|
|
100
|
+
* @param byteOffset - byte offset to start from
|
|
101
|
+
* @returns flat nodes array
|
|
102
|
+
* */
|
|
103
|
+
function parseBinaryChunk(arrayBuffer: ArrayBuffer, byteOffset = 0): POTreeNode[] {
|
|
83
104
|
const dataView = new DataView(arrayBuffer);
|
|
84
105
|
|
|
85
106
|
const stack: POTreeNode[] = [];
|
|
@@ -90,8 +111,7 @@ function parseBinaryChunk(arrayBuffer: ArrayBuffer, byteOffset = 0) {
|
|
|
90
111
|
byteOffset = decodeRow(dataView, byteOffset, topTileHeader);
|
|
91
112
|
|
|
92
113
|
stack.push(topTileHeader);
|
|
93
|
-
|
|
94
|
-
const tileHeaders: POTreeTileHeader[] = [];
|
|
114
|
+
const tileHeaders: POTreeNode[] = [topTileHeader];
|
|
95
115
|
|
|
96
116
|
while (stack.length > 0) {
|
|
97
117
|
const snode = stack.shift();
|
|
@@ -100,11 +120,10 @@ function parseBinaryChunk(arrayBuffer: ArrayBuffer, byteOffset = 0) {
|
|
|
100
120
|
for (let i = 0; i < 8; i++) {
|
|
101
121
|
if (snode && (snode.header.childMask & mask) !== 0) {
|
|
102
122
|
// @ts-expect-error
|
|
103
|
-
const tileHeader:
|
|
123
|
+
const tileHeader: POTreeNode = {};
|
|
104
124
|
byteOffset = decodeRow(dataView, byteOffset, tileHeader);
|
|
105
125
|
tileHeader.name = snode.name + i;
|
|
106
126
|
|
|
107
|
-
// @ts-expect-error
|
|
108
127
|
stack.push(tileHeader);
|
|
109
128
|
tileHeaders.push(tileHeader);
|
|
110
129
|
snode.header.childCount++;
|
|
@@ -120,7 +139,14 @@ function parseBinaryChunk(arrayBuffer: ArrayBuffer, byteOffset = 0) {
|
|
|
120
139
|
return tileHeaders;
|
|
121
140
|
}
|
|
122
141
|
|
|
123
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Reads next row from binary index file
|
|
144
|
+
* @param dataView - index data
|
|
145
|
+
* @param byteOffset - current offset in the index data
|
|
146
|
+
* @param tileHeader - container to read to
|
|
147
|
+
* @returns new offset
|
|
148
|
+
*/
|
|
149
|
+
function decodeRow(dataView: DataView, byteOffset: number, tileHeader: POTreeNode): number {
|
|
124
150
|
tileHeader.header = tileHeader.header || {};
|
|
125
151
|
tileHeader.header.childMask = dataView.getUint8(byteOffset);
|
|
126
152
|
tileHeader.header.childCount = 0;
|
|
@@ -130,16 +156,16 @@ function decodeRow(dataView, byteOffset, tileHeader) {
|
|
|
130
156
|
return byteOffset;
|
|
131
157
|
}
|
|
132
158
|
|
|
133
|
-
|
|
134
|
-
function buildHierarchy(
|
|
159
|
+
/** Resolves the binary rows into a hierarchy (tree structure) */
|
|
160
|
+
function buildHierarchy(flatNodes: POTreeNode[], options: {spacing?: number} = {}): POTreeNode {
|
|
135
161
|
const DEFAULT_OPTIONS = {spacing: 100}; // TODO assert instead of default?
|
|
136
162
|
options = {...DEFAULT_OPTIONS, ...options};
|
|
137
163
|
|
|
138
|
-
const topNode =
|
|
164
|
+
const topNode: POTreeNode = flatNodes[0];
|
|
139
165
|
const nodes = {};
|
|
140
166
|
|
|
141
|
-
for (const
|
|
142
|
-
const {name} =
|
|
167
|
+
for (const node of flatNodes) {
|
|
168
|
+
const {name} = node;
|
|
143
169
|
|
|
144
170
|
const index = parseInt(name.charAt(name.length - 1), 10);
|
|
145
171
|
const parentName = name.substring(0, name.length - 1);
|
|
@@ -147,20 +173,20 @@ function buildHierarchy(tileHeaders, options: {spacing?: number} = {}): POTreeNo
|
|
|
147
173
|
const level = name.length - 1;
|
|
148
174
|
// assert(parentNode && level >= 0);
|
|
149
175
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
176
|
+
node.level = level;
|
|
177
|
+
node.hasChildren = Boolean(node.header.childCount);
|
|
178
|
+
node.children = [];
|
|
179
|
+
node.childrenByIndex = new Array(8).fill(null);
|
|
180
|
+
node.spacing = (options?.spacing || 0) / Math.pow(2, level);
|
|
155
181
|
// tileHeader.boundingVolume = Utils.createChildAABB(parentNode.boundingBox, index);
|
|
156
182
|
|
|
157
183
|
if (parentNode) {
|
|
158
|
-
parentNode.children.push(
|
|
159
|
-
parentNode.childrenByIndex[index] =
|
|
184
|
+
parentNode.children.push(node);
|
|
185
|
+
parentNode.childrenByIndex[index] = node;
|
|
160
186
|
}
|
|
161
187
|
|
|
162
188
|
// Add the node to the map
|
|
163
|
-
nodes[name] =
|
|
189
|
+
nodes[name] = node;
|
|
164
190
|
}
|
|
165
191
|
|
|
166
192
|
// First node is the root
|