-
Notifications
You must be signed in to change notification settings - Fork 33
/
combineTileset.js
143 lines (131 loc) · 6 KB
/
combineTileset.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
'use strict';
const Cesium = require('cesium');
const fsExtra = require('fs-extra');
const path = require('path');
const Promise = require('bluebird');
const zlib = require('zlib');
const getDefaultWriteCallback = require('./getDefaultWriteCallback');
const getJsonBufferPadded =require('./getJsonBufferPadded');
const isGzippedFile = require('./isGzippedFile');
const isJson = require('./isJson');
const readFile = require('./readFile');
const walkDirectory = require('./walkDirectory');
const Check = Cesium.Check;
const defaultValue = Cesium.defaultValue;
const defined = Cesium.defined;
module.exports = combineTileset;
/**
* Combines all external tilesets into a single tileset.json file.
*
* @param {Object} options Object with the following properties:
* @param {String} options.inputDirectory Path to the input directory.
* @param {Object} [options.outputDirectory] Path to the output directory.
* @param {String} [options.rootJson='tileset.json'] Relative path to the root json.
* @param {WriteCallback} [options.writeCallback] A callback function that writes files after they have been processed.
* @param {LogCallback} [options.logCallback] A callback function that logs messages.
*
* @returns {Promise} A promise that resolves with the operation completes.
*/
function combineTileset(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
let inputDirectory = options.inputDirectory;
let outputDirectory = options.outputDirectory;
let rootJsonFile = defaultValue(options.rootJson, 'tileset.json');
Check.typeOf.string('options.inputDirectory', inputDirectory);
inputDirectory = path.normalize(inputDirectory);
outputDirectory = path.normalize(defaultValue(outputDirectory,
path.join(path.dirname(inputDirectory), `${path.basename(inputDirectory) }-combined`)));
rootJsonFile = path.join(inputDirectory, rootJsonFile);
const writeCallback = defaultValue(options.writeCallback, getDefaultWriteCallback(outputDirectory));
const logCallback = options.logCallback;
const tilesets = [rootJsonFile];
return combine(rootJsonFile, inputDirectory, undefined, tilesets)
.then(function (json) {
if (defined(logCallback)) {
logCallback(`Combined ${ tilesets.length - 1 } external tilesets.`);
}
// If the root json is originally gzipped, save the output json as gzipped
const writeRootJsonPromise = isGzippedFile(rootJsonFile)
.then(function (gzipped) {
let data = getJsonBufferPadded(json, gzipped);
if (gzipped) {
data = zlib.gzipSync(data);
}
const relativePath = path.relative(inputDirectory, rootJsonFile);
return writeCallback(relativePath, data);
});
const copyFilesPromise = copyFiles(inputDirectory, tilesets, writeCallback);
return Promise.all([writeRootJsonPromise, copyFilesPromise]);
});
}
function combine(jsonFile, inputDirectory, parentTile, tilesets) {
return readFile(jsonFile, 'json')
.then(function (json) {
const tilesetDirectory = path.dirname(jsonFile);
const promises = [];
const root = json.root;
if (defined(root)) {
// Append the external tileset to the parent tile
if (defined(parentTile)) {
parentTile.content = root.content;
parentTile.children = root.children;
}
// Loop over all the tiles
const stack = [];
stack.push(root);
while (stack.length > 0) {
const tile = stack.pop();
// Look for external tilesets
if (defined(tile.content)) {
let uri = tile.content.uri;
if (isJson(uri)) {
// Load the external tileset
uri = path.join(tilesetDirectory, uri);
tilesets.push(uri);
const promise = combine(uri, inputDirectory, tile, tilesets);
promises.push(promise);
} else {
const contentUri = path.join(tilesetDirectory, uri);
tile.content.uri = getRelativePath(inputDirectory, contentUri);
}
}
// Push children to the stack
const children = tile.children;
if (defined(children)) {
const length = children.length;
for (let i = 0; i < length; ++i) {
stack.push(children[i]);
}
}
}
}
// Waits for all the external tilesets to finish loading before the promise resolves
return Promise.all(promises)
.then(function () {
return json;
});
});
}
function getRelativePath(inputDirectory, file) {
const relative = path.relative(inputDirectory, file);
return relative.replace(/\\/g, '/'); // Use forward slashes in the JSON
}
function isTileset(inputDirectory, file, tilesets) {
const relativePath = getRelativePath(inputDirectory, file);
return tilesets.indexOf(relativePath) >= 0;
}
function copyFiles(inputDirectory, tilesets, writeCallback) {
tilesets = tilesets.map(function(tileset) {
return getRelativePath(inputDirectory, tileset);
});
// Copy all files except tilesets
return walkDirectory(inputDirectory, function(file) {
if (!isTileset(inputDirectory, file, tilesets)) {
return fsExtra.readFile(file)
.then(function (data) {
const relativePath = getRelativePath(inputDirectory, file);
return writeCallback(relativePath, data);
});
}
});
}