@loaders.gl/i3s
Version:
i3s .
119 lines (108 loc) • 4 kB
text/typescript
import {OrientedBoundingBox} from '@math.gl/culling';
import {Ellipsoid} from '@math.gl/geospatial';
import {load} from '@loaders.gl/core';
import {TILE_TYPE, TILE_REFINEMENT, TILESET_TYPE} from '@loaders.gl/tiles';
import I3SNodePagesTiles from '../helpers/i3s-nodepages-tiles';
import {generateTileAttributeUrls, getUrlWithToken, getUrlWithoutParams} from '../utils/url-utils';
import {
I3STilesetHeader,
I3STileHeader,
Mbs,
I3SMinimalNodeData,
Node3DIndexDocument,
SceneLayer3D,
I3SParseOptions
} from '../../types';
import type {LoaderOptions, LoaderContext} from '@loaders.gl/loader-utils';
import { I3SLoader } from '../../i3s-loader';
export function normalizeTileData(tile : Node3DIndexDocument, context: LoaderContext): I3STileHeader {
const url: string = context.url || '';
let contentUrl: string | undefined;
if (tile.geometryData) {
contentUrl = `${url}/${tile.geometryData[0].href}`;
}
let textureUrl: string | undefined;
if (tile.textureData) {
textureUrl = `${url}/${tile.textureData[0].href}`;
}
let attributeUrls: string[] | undefined;
if (tile.attributeData) {
attributeUrls = generateTileAttributeUrls(url, tile);
}
const children = tile.children || [];
return normalizeTileNonUrlData({
...tile,
children,
url,
contentUrl,
textureUrl,
textureFormat: 'jpg', // `jpg` format will cause `ImageLoader` usage that will be able to handle `png` as well
attributeUrls,
isDracoGeometry: false
});
}
export function normalizeTileNonUrlData(tile : I3SMinimalNodeData): I3STileHeader {
const boundingVolume: {box?: number[]; sphere?: number[]} = {};
let mbs: Mbs = [0, 0, 0, 1];
if (tile.mbs) {
mbs = tile.mbs;
boundingVolume.sphere = [
...Ellipsoid.WGS84.cartographicToCartesian(tile.mbs.slice(0, 3)), // cartesian center of sphere
tile.mbs[3] // radius of sphere
] as Mbs;
} else if (tile.obb) {
boundingVolume.box = [
...Ellipsoid.WGS84.cartographicToCartesian(tile.obb.center), // cartesian center of box
...tile.obb.halfSize, // halfSize
...tile.obb.quaternion // quaternion
];
const obb = new OrientedBoundingBox().fromCenterHalfSizeQuaternion(
boundingVolume.box.slice(0, 3),
tile.obb.halfSize,
tile.obb.quaternion
);
const boundingSphere = obb.getBoundingSphere();
boundingVolume.sphere = [...boundingSphere.center , boundingSphere.radius] as Mbs;
mbs = [...tile.obb.center, boundingSphere.radius] as Mbs;
}
const lodMetricType = tile.lodSelection?.[0].metricType;
const lodMetricValue = tile.lodSelection?.[0].maxError;
const type = TILE_TYPE.MESH;
/**
* I3S specification supports only REPLACE
*/
const refine = TILE_REFINEMENT.REPLACE;
return {...tile, mbs, boundingVolume, lodMetricType, lodMetricValue, type, refine};
}
export async function normalizeTilesetData(tileset : SceneLayer3D, options : LoaderOptions, context: LoaderContext): Promise<I3STileHeader | I3STilesetHeader> {
const url = getUrlWithoutParams(context.url || '');
let nodePagesTile: I3SNodePagesTiles | undefined;
let root: I3STileHeader | I3STilesetHeader;
if (tileset.nodePages) {
nodePagesTile = new I3SNodePagesTiles(tileset, url, options);
root = await nodePagesTile.formTileFromNodePages(0);
} else {
const parseOptions = options.i3s as I3SParseOptions;
const rootNodeUrl = getUrlWithToken(`${url}/nodes/root`, parseOptions.token);
// eslint-disable-next-line no-use-before-define
root = await load(rootNodeUrl, I3SLoader, {
...options,
i3s: {
// @ts-expect-error options is not properly typed
...options.i3s,
loadContent: false, isTileHeader: true, isTileset: false}
});
}
return {
...tileset,
loader: I3SLoader,
url,
basePath: url,
type: TILESET_TYPE.I3S,
nodePagesTile,
// @ts-expect-error
root,
lodMetricType: root.lodMetricType,
lodMetricValue: root.lodMetricValue
}
}