UNPKG

@loaders.gl/potree

Version:

potree loaders for large point clouds.

318 lines (307 loc) 9.9 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // dist/index.js var dist_exports = {}; __export(dist_exports, { PotreeBinLoader: () => PotreeBinLoader, PotreeHierarchyChunkLoader: () => PotreeHierarchyChunkLoader, PotreeLoader: () => PotreeLoader, PotreeSource: () => PotreeSource }); module.exports = __toCommonJS(dist_exports); // dist/potree-loader.js var VERSION = true ? "4.3.2" : "latest"; var PotreeLoader = { dataType: null, batchType: null, name: "potree metadata", id: "potree", module: "potree", version: VERSION, extensions: ["js"], mimeTypes: ["application/json"], testText: (text) => text.indexOf("octreeDir") >= 0, parse: (data) => JSON.parse(new TextDecoder().decode(data)), parseTextSync: (text) => JSON.parse(text), options: { potree: {} } }; // dist/parsers/parse-potree-hierarchy-chunk.js function parsePotreeHierarchyChunk(arrayBuffer) { const tileHeaders = parseBinaryChunk(arrayBuffer); return buildHierarchy(tileHeaders); } function parseBinaryChunk(arrayBuffer, byteOffset = 0) { const dataView = new DataView(arrayBuffer); const stack = []; const topTileHeader = {}; byteOffset = decodeRow(dataView, byteOffset, topTileHeader); stack.push(topTileHeader); const tileHeaders = [topTileHeader]; while (stack.length > 0) { const snode = stack.shift(); let mask = 1; for (let i = 0; i < 8; i++) { if (snode && (snode.header.childMask & mask) !== 0) { const tileHeader = {}; byteOffset = decodeRow(dataView, byteOffset, tileHeader); tileHeader.name = snode.name + i; stack.push(tileHeader); tileHeaders.push(tileHeader); snode.header.childCount++; } mask = mask * 2; } if (byteOffset === dataView.byteLength) { break; } } return tileHeaders; } function decodeRow(dataView, byteOffset, tileHeader) { tileHeader.header = tileHeader.header || {}; tileHeader.header.childMask = dataView.getUint8(byteOffset); tileHeader.header.childCount = 0; tileHeader.pointCount = dataView.getUint32(byteOffset + 1, true); tileHeader.name = ""; byteOffset += 5; return byteOffset; } function buildHierarchy(flatNodes, options = {}) { const DEFAULT_OPTIONS = { spacing: 100 }; options = { ...DEFAULT_OPTIONS, ...options }; const topNode = flatNodes[0]; const nodes = {}; for (const node of flatNodes) { const { name } = node; const index = parseInt(name.charAt(name.length - 1), 10); const parentName = name.substring(0, name.length - 1); const parentNode = nodes[parentName]; const level = name.length - 1; node.level = level; node.hasChildren = Boolean(node.header.childCount); node.children = []; node.childrenByIndex = new Array(8).fill(null); node.spacing = ((options == null ? void 0 : options.spacing) || 0) / Math.pow(2, level); if (parentNode) { parentNode.children.push(node); parentNode.childrenByIndex[index] = node; } nodes[name] = node; } return topNode; } // dist/potree-hierarchy-chunk-loader.js var VERSION2 = true ? "4.3.2" : "latest"; var PotreeHierarchyChunkLoader = { dataType: null, batchType: null, name: "potree Hierarchy Chunk", id: "potree-hrc", module: "potree", version: VERSION2, extensions: ["hrc"], mimeTypes: ["application/octet-stream"], // binary potree files have no header bytes, no content test function possible // test: ['...'], parse: async (arrayBuffer, options) => parsePotreeHierarchyChunk(arrayBuffer), parseSync: (arrayBuffer, options) => parsePotreeHierarchyChunk(arrayBuffer), options: { potree: {} }, binary: true }; // dist/parsers/parse-potree-bin.js function parsePotreeBin(arrayBuffer, byteOffset, options, index) { return null; } // dist/potree-bin-loader.js var PotreeBinLoader = { dataType: null, batchType: null, name: "potree Binary Point Attributes", id: "potree", extensions: ["bin"], mimeTypes: ["application/octet-stream"], // Unfortunately binary potree files have no header bytes, no test possible // test: ['...'], parseSync, binary: true, options: {} // @ts-ignore }; function parseSync(arrayBuffer, options) { const index = {}; const byteOffset = 0; parsePotreeBin(arrayBuffer, byteOffset, options, index); return index; } // dist/lib/potree-node-source.js var import_core = require("@loaders.gl/core"); var import_loader_utils = require("@loaders.gl/loader-utils"); var import_las = require("@loaders.gl/las"); // dist/utils/parse-version.js function parseVersion(version) { const parts = version.split(".").map(Number); return { major: parts[0], minor: parts[1] }; } // dist/lib/potree-node-source.js var PotreeNodesSource = class extends import_loader_utils.DataSource { /** Dataset base URL */ baseUrl = ""; /** Input data: string - dataset url, blob - single file data */ data; /** Input props */ props; /** Meta information from `cloud.js` */ metadata = null; /** Root node */ root = null; /** Is data source ready to use after initial loading */ isReady = false; initPromise = null; /** * @constructor * @param data - if string - data set path url or path to `cloud.js` metadata file * - if Blob - single file data * @param props - data source properties */ constructor(data, props) { super(props); this.props = props; this.data = data; this.makeBaseUrl(this.data); this.initPromise = this.init(); } /** Initial data source loading */ async init() { if (this.initPromise) { await this.initPromise; return; } this.metadata = await (0, import_core.load)(`${this.baseUrl}/cloud.js`, PotreeLoader); await this.loadHierarchy(); this.isReady = true; } /** Is data set supported */ isSupported() { var _a, _b, _c; const { minor, major } = parseVersion(((_a = this.metadata) == null ? void 0 : _a.version) ?? ""); return this.isReady && major === 1 && minor <= 8 && typeof ((_b = this.metadata) == null ? void 0 : _b.pointAttributes) === "string" && ["LAS", "LAZ"].includes((_c = this.metadata) == null ? void 0 : _c.pointAttributes); } /** Get content files extension */ getContentExtension() { var _a; if (!this.isReady) { return null; } switch ((_a = this.metadata) == null ? void 0 : _a.pointAttributes) { case "LAS": return "las"; case "LAZ": return "laz"; default: return "bin"; } } /** * Load octree node content * @param path array of numbers between 0-7 specifying successive octree divisions. * @return node content geometry or null if the node doesn't exist */ async loadNodeContent(path) { var _a; await this.initPromise; if (!this.isSupported()) { return null; } const isAvailable = await this.isNodeAvailable(path); if (isAvailable) { return (0, import_core.load)(`${this.baseUrl}/${(_a = this.metadata) == null ? void 0 : _a.octreeDir}/r/r${path.join("")}.${this.getContentExtension()}`, import_las.LASLoader); } return null; } /** * Check if a node exists in the octree * @param path array of numbers between 0-7 specifying successive octree divisions * @returns true - the node does exist, false - the nodes doesn't exist */ async isNodeAvailable(path) { var _a; if ((_a = this.metadata) == null ? void 0 : _a.hierarchy) { return this.metadata.hierarchy.findIndex((item) => item[0] === `r${path.join()}`) !== -1; } if (!this.root) { return false; } let currentParent = this.root; let name = ""; let result = true; for (const nodeLevel of path) { const newName = `${name}${nodeLevel}`; const node = currentParent.children.find((child) => child.name === newName); if (node) { currentParent = node; name = newName; } else { result = false; break; } } return result; } /** * Load data source hierarchy into tree of available nodes */ async loadHierarchy() { var _a; this.root = await (0, import_core.load)(`${this.baseUrl}/${(_a = this.metadata) == null ? void 0 : _a.octreeDir}/r/r.hrc`, PotreeHierarchyChunkLoader); } /** * Deduce base url from the input url sring * @param data - data source input data */ makeBaseUrl(data) { this.baseUrl = typeof data === "string" ? (0, import_loader_utils.resolvePath)(data) : ""; if (this.baseUrl.endsWith("cloud.js")) { this.baseUrl = this.baseUrl.substring(0, -8); } if (this.baseUrl.endsWith("/")) { this.baseUrl = this.baseUrl.substring(0, -1); } } }; // dist/potree-source.js var VERSION3 = "1.7"; var PotreeSource = { name: "Potree", id: "potree", module: "potree", version: VERSION3, extensions: ["bin", "las", "laz"], mimeTypes: ["application/octet-stream"], options: { url: void 0, potree: {} }, type: "potree", fromUrl: true, fromBlob: true, testURL: (url) => url.endsWith(".js"), createDataSource: (url, props) => new PotreeNodesSource(url, props) }; //# sourceMappingURL=index.cjs.map