@loaders.gl/tile-converter 4.0.0-beta.8 → 4.0.1
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/converter.min.cjs +109 -109
- package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts +74 -0
- package/dist/i3s-converter/helpers/attribute-metadata-info.d.ts.map +1 -0
- package/dist/i3s-converter/helpers/attribute-metadata-info.js +157 -0
- package/dist/i3s-converter/helpers/attribute-metadata-info.js.map +1 -0
- package/dist/i3s-converter/helpers/feature-attributes.d.ts +3 -28
- package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -1
- package/dist/i3s-converter/helpers/feature-attributes.js +16 -125
- package/dist/i3s-converter/helpers/feature-attributes.js.map +1 -1
- package/dist/i3s-converter/i3s-converter.d.ts +11 -5
- package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
- package/dist/i3s-converter/i3s-converter.js +31 -44
- package/dist/i3s-converter/i3s-converter.js.map +1 -1
- package/dist/i3s-converter/types.d.ts +15 -0
- package/dist/i3s-converter/types.d.ts.map +1 -1
- package/dist/i3s-converter/types.js +6 -0
- package/dist/i3s-converter/types.js.map +1 -1
- package/dist/i3s-server/app.d.ts.map +1 -1
- package/dist/i3s-server/app.js +3 -6
- package/dist/i3s-server/app.js.map +1 -1
- package/dist/i3s-server/bin/i3s-server.min.cjs +86 -86
- package/dist/i3s-server/bin/www.js.map +1 -1
- package/dist/i3s-server/routes/index.d.ts +1 -1
- package/dist/i3s-server/routes/index.d.ts.map +1 -1
- package/dist/i3s-server/routes/index.js +2 -5
- package/dist/i3s-server/routes/index.js.map +1 -1
- package/dist/i3s-server/routes/slpk-router.d.ts.map +1 -1
- package/dist/i3s-server/routes/slpk-router.js +3 -3
- package/dist/i3s-server/routes/slpk-router.js.map +1 -1
- package/dist/index.cjs +269 -173
- package/package.json +15 -15
- package/src/i3s-converter/helpers/attribute-metadata-info.ts +246 -0
- package/src/i3s-converter/helpers/feature-attributes.ts +18 -180
- package/src/i3s-converter/i3s-converter.ts +46 -65
- package/src/i3s-converter/types.ts +16 -0
- package/src/i3s-server/app.ts +9 -4
- package/src/i3s-server/bin/www.ts +6 -0
- package/src/i3s-server/routes/index.ts +2 -4
- package/src/i3s-server/routes/slpk-router.ts +4 -3
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// loaders.gl, MIT license
|
|
2
2
|
// Copyright (c) vis.gl contributors
|
|
3
3
|
|
|
4
|
+
import {AttributeMetadataInfo} from './helpers/attribute-metadata-info';
|
|
5
|
+
|
|
4
6
|
import type {
|
|
5
7
|
FeatureTableJson,
|
|
6
8
|
Tiles3DLoaderOptions,
|
|
@@ -62,12 +64,8 @@ import {WorkerFarm} from '@loaders.gl/worker-utils';
|
|
|
62
64
|
import WriteQueue from '../lib/utils/write-queue';
|
|
63
65
|
import {BROWSER_ERROR_MESSAGE} from '../constants';
|
|
64
66
|
import {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
createdStorageAttribute,
|
|
68
|
-
getFieldAttributeType,
|
|
69
|
-
createFieldAttribute,
|
|
70
|
-
createPopupInfo
|
|
67
|
+
getAttributeTypesMapFromPropertyTable,
|
|
68
|
+
getAttributeTypesMapFromSchema
|
|
71
69
|
} from './helpers/feature-attributes';
|
|
72
70
|
import {NodeIndexDocument} from './helpers/node-index-document';
|
|
73
71
|
import {
|
|
@@ -94,6 +92,7 @@ const CESIUM_DATASET_PREFIX = 'https://';
|
|
|
94
92
|
* Converter from 3d-tiles tileset to i3s layer
|
|
95
93
|
*/
|
|
96
94
|
export default class I3SConverter {
|
|
95
|
+
attributeMetadataInfo: AttributeMetadataInfo;
|
|
97
96
|
nodePages: NodePages;
|
|
98
97
|
options: any;
|
|
99
98
|
layers0Path: string;
|
|
@@ -139,8 +138,18 @@ export default class I3SConverter {
|
|
|
139
138
|
meshTopologyTypes: new Set(),
|
|
140
139
|
metadataClasses: new Set()
|
|
141
140
|
};
|
|
141
|
+
/** Total count of tiles in tileset */
|
|
142
|
+
tileCountTotal: number = 0;
|
|
143
|
+
/** Count of tiles already converted plus one (refers to the tile currently being converted) */
|
|
144
|
+
tileCountCurrentlyConverting: number = 0;
|
|
145
|
+
/**
|
|
146
|
+
* The number of digits to appear after decimal point in the string representation of the tile count.
|
|
147
|
+
* It's calculated based on the total count of tiles.
|
|
148
|
+
*/
|
|
149
|
+
numberOfDigitsInPercentage: number = 0;
|
|
142
150
|
|
|
143
151
|
constructor() {
|
|
152
|
+
this.attributeMetadataInfo = new AttributeMetadataInfo();
|
|
144
153
|
this.nodePages = new NodePages(writeFile, HARDCODED_NODES_PER_PAGE, this);
|
|
145
154
|
this.options = {};
|
|
146
155
|
this.layers0Path = '';
|
|
@@ -301,8 +310,12 @@ export default class I3SConverter {
|
|
|
301
310
|
);
|
|
302
311
|
const {meshTopologyTypes, metadataClasses} = this.preprocessData;
|
|
303
312
|
|
|
313
|
+
this.numberOfDigitsInPercentage =
|
|
314
|
+
this.tileCountTotal > 100 ? Math.ceil(Math.log10(this.tileCountTotal)) - 2 : 0;
|
|
315
|
+
|
|
304
316
|
console.log(`------------------------------------------------`);
|
|
305
317
|
console.log(`Preprocess results:`);
|
|
318
|
+
console.log(`Tile count: ${this.tileCountTotal}`);
|
|
306
319
|
console.log(`glTF mesh topology types: ${Array.from(meshTopologyTypes).join(', ')}`);
|
|
307
320
|
|
|
308
321
|
if (metadataClasses.size) {
|
|
@@ -344,6 +357,7 @@ export default class I3SConverter {
|
|
|
344
357
|
return null;
|
|
345
358
|
}
|
|
346
359
|
if (sourceTile.id) {
|
|
360
|
+
this.tileCountTotal++;
|
|
347
361
|
console.log(`[analyze]: ${sourceTile.id}`); // eslint-disable-line
|
|
348
362
|
}
|
|
349
363
|
|
|
@@ -450,6 +464,14 @@ export default class I3SConverter {
|
|
|
450
464
|
this.options.maxDepth
|
|
451
465
|
);
|
|
452
466
|
|
|
467
|
+
this.layers0!.attributeStorageInfo = this.attributeMetadataInfo.attributeStorageInfo;
|
|
468
|
+
this.layers0!.fields = this.attributeMetadataInfo.fields;
|
|
469
|
+
this.layers0!.popupInfo = this.attributeMetadataInfo.popupInfo;
|
|
470
|
+
|
|
471
|
+
if (this.attributeMetadataInfo.attributeStorageInfo.length) {
|
|
472
|
+
this.layers0!.layerType = _3D_OBJECT_LAYER_TYPE;
|
|
473
|
+
}
|
|
474
|
+
|
|
453
475
|
this.layers0!.materialDefinitions = this.materialDefinitions;
|
|
454
476
|
// @ts-ignore
|
|
455
477
|
this.layers0.geometryDefinitions = transform(
|
|
@@ -596,7 +618,14 @@ export default class I3SConverter {
|
|
|
596
618
|
return traversalProps;
|
|
597
619
|
}
|
|
598
620
|
if (sourceTile.id) {
|
|
599
|
-
|
|
621
|
+
// Print the tile number that is currently being converted.
|
|
622
|
+
this.tileCountCurrentlyConverting++;
|
|
623
|
+
let percentString = '';
|
|
624
|
+
if (this.tileCountTotal) {
|
|
625
|
+
const percent = (this.tileCountCurrentlyConverting / this.tileCountTotal) * 100;
|
|
626
|
+
percentString = ' ' + percent.toFixed(this.numberOfDigitsInPercentage);
|
|
627
|
+
}
|
|
628
|
+
console.log(`[convert${percentString}%]: ${sourceTile.id}`); // eslint-disable-line
|
|
600
629
|
}
|
|
601
630
|
|
|
602
631
|
const {parentNodes, transform} = traversalProps;
|
|
@@ -775,7 +804,7 @@ export default class I3SConverter {
|
|
|
775
804
|
async () => (await this.nodePages.push({index: 0, obb: draftObb}, parentId)).index,
|
|
776
805
|
propertyTable,
|
|
777
806
|
this.featuresHashArray,
|
|
778
|
-
this.
|
|
807
|
+
this.attributeMetadataInfo.attributeStorageInfo,
|
|
779
808
|
this.options.draco,
|
|
780
809
|
this.generateBoundingVolumes,
|
|
781
810
|
this.options.mergeMaterials,
|
|
@@ -1081,14 +1110,14 @@ export default class I3SConverter {
|
|
|
1081
1110
|
childPath: string,
|
|
1082
1111
|
slpkChildPath: string
|
|
1083
1112
|
): Promise<void> {
|
|
1084
|
-
if (attributes?.length && this.
|
|
1113
|
+
if (attributes?.length && this.attributeMetadataInfo.attributeStorageInfo.length) {
|
|
1085
1114
|
const minimumLength =
|
|
1086
|
-
attributes.length < this.
|
|
1115
|
+
attributes.length < this.attributeMetadataInfo.attributeStorageInfo.length
|
|
1087
1116
|
? attributes.length
|
|
1088
|
-
: this.
|
|
1117
|
+
: this.attributeMetadataInfo.attributeStorageInfo.length;
|
|
1089
1118
|
|
|
1090
1119
|
for (let index = 0; index < minimumLength; index++) {
|
|
1091
|
-
const folderName = this.
|
|
1120
|
+
const folderName = this.attributeMetadataInfo.attributeStorageInfo[index].key;
|
|
1092
1121
|
const fileBuffer = new Uint8Array(attributes[index]);
|
|
1093
1122
|
|
|
1094
1123
|
if (this.options.slpk) {
|
|
@@ -1174,67 +1203,19 @@ export default class I3SConverter {
|
|
|
1174
1203
|
*/
|
|
1175
1204
|
let attributeTypesMap: Record<string, Attribute> | null = null;
|
|
1176
1205
|
if (this.options.metadataClass) {
|
|
1177
|
-
if (!this.
|
|
1178
|
-
attributeTypesMap =
|
|
1206
|
+
if (!this.attributeMetadataInfo.attributeStorageInfo.length && tileContent?.gltf) {
|
|
1207
|
+
attributeTypesMap = getAttributeTypesMapFromSchema(
|
|
1179
1208
|
tileContent.gltf,
|
|
1180
1209
|
this.options.metadataClass
|
|
1181
1210
|
);
|
|
1182
1211
|
}
|
|
1183
1212
|
} else if (propertyTable) {
|
|
1184
|
-
attributeTypesMap =
|
|
1213
|
+
attributeTypesMap = getAttributeTypesMapFromPropertyTable(propertyTable);
|
|
1185
1214
|
}
|
|
1186
1215
|
|
|
1187
1216
|
if (attributeTypesMap) {
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
/**
|
|
1193
|
-
* Creates Attribute Storage Info objects based on attribute's types
|
|
1194
|
-
* @param attributeTypesMap - set of attribute's types
|
|
1195
|
-
*/
|
|
1196
|
-
private createStorageAttributes(attributeTypesMap: Record<string, Attribute>): void {
|
|
1197
|
-
if (!Object.keys(attributeTypesMap).length) {
|
|
1198
|
-
return;
|
|
1199
|
-
}
|
|
1200
|
-
const attributeTypes: Record<string, Attribute> = {
|
|
1201
|
-
OBJECTID: 'OBJECTID',
|
|
1202
|
-
...attributeTypesMap
|
|
1203
|
-
};
|
|
1204
|
-
|
|
1205
|
-
let isUpdated = false;
|
|
1206
|
-
let attributeIndex = this.layers0!.attributeStorageInfo!.length;
|
|
1207
|
-
for (const key in attributeTypes) {
|
|
1208
|
-
/*
|
|
1209
|
-
We will append a new attribute only in case it has not been added to the attribute storage info yet.
|
|
1210
|
-
*/
|
|
1211
|
-
const elementFound = this.layers0!.attributeStorageInfo!.find(
|
|
1212
|
-
(element) => element.name === key
|
|
1213
|
-
);
|
|
1214
|
-
if (!elementFound) {
|
|
1215
|
-
const attributeType = attributeTypes[key];
|
|
1216
|
-
|
|
1217
|
-
const storageAttribute = createdStorageAttribute(attributeIndex, key, attributeType);
|
|
1218
|
-
const fieldAttributeType = getFieldAttributeType(attributeType);
|
|
1219
|
-
const fieldAttribute = createFieldAttribute(key, fieldAttributeType);
|
|
1220
|
-
|
|
1221
|
-
this.layers0!.attributeStorageInfo!.push(storageAttribute);
|
|
1222
|
-
this.layers0!.fields!.push(fieldAttribute);
|
|
1223
|
-
attributeIndex += 1;
|
|
1224
|
-
isUpdated = true;
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
if (isUpdated) {
|
|
1228
|
-
/*
|
|
1229
|
-
The attributeStorageInfo is updated. So, popupInfo should be recreated.
|
|
1230
|
-
Use attributeStorageInfo as a source of attribute names to create the popupInfo.
|
|
1231
|
-
*/
|
|
1232
|
-
const attributeNames: string[] = [];
|
|
1233
|
-
for (let info of this.layers0!.attributeStorageInfo!) {
|
|
1234
|
-
attributeNames.push(info.name);
|
|
1235
|
-
}
|
|
1236
|
-
this.layers0!.popupInfo = createPopupInfo(attributeNames);
|
|
1237
|
-
this.layers0!.layerType = _3D_OBJECT_LAYER_TYPE;
|
|
1217
|
+
// Add new storage attributes, fields and create popupInfo
|
|
1218
|
+
this.attributeMetadataInfo.addMetadataInfo(attributeTypesMap);
|
|
1238
1219
|
}
|
|
1239
1220
|
}
|
|
1240
1221
|
|
|
@@ -225,3 +225,19 @@ export type GLTFAttributesData = {
|
|
|
225
225
|
/** Model matrix to convert coordinate system of POSITION and NORMAL attributes from METER_OFFSETS to CARTESIAN */
|
|
226
226
|
cartesianModelMatrix: Matrix4;
|
|
227
227
|
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* I3S' types difine the following:
|
|
231
|
+
* type Attribute = 'OBJECTID' | 'string' | 'double' | 'Int32' | string;
|
|
232
|
+
* The AttributeType contains the string values of the Attribute type.
|
|
233
|
+
*/
|
|
234
|
+
export const AttributeType = {
|
|
235
|
+
/** Type of attribute that is linked with feature ids */
|
|
236
|
+
OBJECT_ID_TYPE: 'OBJECTID',
|
|
237
|
+
/** String data type name for feature attributes */
|
|
238
|
+
STRING_TYPE: 'string',
|
|
239
|
+
/** Double data type name for feature attributes */
|
|
240
|
+
DOUBLE_TYPE: 'double',
|
|
241
|
+
/** Integer data type name for feature attributes */
|
|
242
|
+
SHORT_INT_TYPE: 'Int32'
|
|
243
|
+
} as const;
|
package/src/i3s-server/app.ts
CHANGED
|
@@ -2,13 +2,18 @@ import express from 'express';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import logger from 'morgan';
|
|
4
4
|
import cors from 'cors';
|
|
5
|
+
// For local debug
|
|
6
|
+
// import {fileURLToPath} from 'url';
|
|
5
7
|
import {loadArchive} from './controllers/slpk-controller';
|
|
8
|
+
import {router as indexRouter} from './routes';
|
|
9
|
+
import {sceneServerRouter, router} from './routes/slpk-router';
|
|
10
|
+
|
|
11
|
+
// For local debug
|
|
12
|
+
// const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
// const __dirname = path.dirname(__filename);
|
|
6
14
|
|
|
7
15
|
const I3S_LAYER_PATH = process.env.I3sLayerPath || ''; // eslint-disable-line no-process-env, no-undef
|
|
8
16
|
const FULL_LAYER_PATH = path.join(process.cwd(), I3S_LAYER_PATH); // eslint-disable-line no-undef
|
|
9
|
-
loadArchive(FULL_LAYER_PATH);
|
|
10
|
-
|
|
11
|
-
const indexRouter = require('./routes/index');
|
|
12
17
|
|
|
13
18
|
export const app = express();
|
|
14
19
|
|
|
@@ -19,7 +24,7 @@ app.use(express.static(path.join(__dirname, 'public')));
|
|
|
19
24
|
app.use(cors());
|
|
20
25
|
|
|
21
26
|
if (/\.slpk$/.test(I3S_LAYER_PATH)) {
|
|
22
|
-
|
|
27
|
+
loadArchive(FULL_LAYER_PATH);
|
|
23
28
|
app.use('/SceneServer/layers/0', router);
|
|
24
29
|
app.use('/SceneServer', sceneServerRouter);
|
|
25
30
|
} else {
|
|
@@ -5,8 +5,14 @@ import https from 'https';
|
|
|
5
5
|
import http from 'http';
|
|
6
6
|
import fs from 'fs';
|
|
7
7
|
import path from 'path';
|
|
8
|
+
// For local debug
|
|
9
|
+
// import {fileURLToPath} from 'url';
|
|
8
10
|
import {formErrorHandler, formListeningHandler, normalizePort} from '../utils/server-utils';
|
|
9
11
|
|
|
12
|
+
// For local debug
|
|
13
|
+
// const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
// const __dirname = path.dirname(__filename);
|
|
15
|
+
|
|
10
16
|
/** Get port from environment and store in Express. */
|
|
11
17
|
const httpPort = normalizePort(process.env.PORT || '80');
|
|
12
18
|
if (httpPort === false) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
|
+
import {getFileNameByUrl} from '../controllers/index-controller';
|
|
2
3
|
|
|
3
|
-
const router = express.Router();
|
|
4
|
-
const {getFileNameByUrl} = require('../controllers/index-controller');
|
|
4
|
+
export const router = express.Router();
|
|
5
5
|
|
|
6
6
|
/* GET home page. */
|
|
7
7
|
router.get('*', async function (req, res, next) {
|
|
@@ -13,5 +13,3 @@ router.get('*', async function (req, res, next) {
|
|
|
13
13
|
res.send('File not found');
|
|
14
14
|
}
|
|
15
15
|
});
|
|
16
|
-
|
|
17
|
-
module.exports = router;
|
|
@@ -2,11 +2,13 @@ import express from 'express';
|
|
|
2
2
|
import {getFileByUrl} from '../controllers/slpk-controller';
|
|
3
3
|
import {createSceneServer} from '../utils/create-scene-server';
|
|
4
4
|
|
|
5
|
+
const textDecoder = new TextDecoder();
|
|
6
|
+
|
|
5
7
|
export const sceneServerRouter = express.Router();
|
|
6
8
|
sceneServerRouter.get('*', async function (req, res, next) {
|
|
7
9
|
const file = await getFileByUrl('/');
|
|
8
10
|
if (file) {
|
|
9
|
-
const layer = JSON.parse(
|
|
11
|
+
const layer = JSON.parse(textDecoder.decode(file));
|
|
10
12
|
const sceneServerResponse = createSceneServer(layer.name, layer);
|
|
11
13
|
res.send(sceneServerResponse);
|
|
12
14
|
} else {
|
|
@@ -17,10 +19,9 @@ sceneServerRouter.get('*', async function (req, res, next) {
|
|
|
17
19
|
|
|
18
20
|
export const router = express.Router();
|
|
19
21
|
router.get('*', async function (req, res, next) {
|
|
20
|
-
console.log(req.path);
|
|
21
22
|
const file = await getFileByUrl(req.path);
|
|
22
23
|
if (file) {
|
|
23
|
-
res.send(file);
|
|
24
|
+
res.send(Buffer.from(file));
|
|
24
25
|
} else {
|
|
25
26
|
res.status(404);
|
|
26
27
|
res.send('File not found');
|