zincjs 3.0.0 → 3.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/README.md +27 -22
- package/build/zinc.js +2 -2
- package/build/zinc.js.map +1 -1
- package/package.json +4 -1
- package/src/controls.js +1332 -1241
- package/src/geometryCSG.js +111 -115
- package/src/glyphsetCSG.js +51 -55
- package/src/loaders/GLTFToZincJSLoader.js +31 -33
- package/src/loaders/JSONLoader.js +339 -449
- package/src/loaders/OBJLoader.js +654 -851
- package/src/loaders/STLLoader.js +271 -329
- package/src/loaders/niftiReader.js +90 -59
- package/src/loaders/primitivesLoader.js +55 -52
- package/src/minimap.js +63 -43
- package/src/primitives/geometry.js +40 -44
- package/src/primitives/glyph.js +16 -19
- package/src/primitives/glyphset.js +229 -185
- package/src/primitives/label.js +29 -31
- package/src/primitives/lines.js +20 -20
- package/src/primitives/lines2.js +33 -39
- package/src/primitives/lod.js +43 -43
- package/src/primitives/marker.js +31 -32
- package/src/primitives/markerCluster.js +32 -35
- package/src/primitives/pointset.js +86 -83
- package/src/primitives/texturePrimitive.js +9 -10
- package/src/primitives/textureSlides.js +84 -97
- package/src/primitives/textureVolume.js +46 -49
- package/src/primitives/tubeLines.js +108 -108
- package/src/primitives/zincObject.js +176 -184
- package/src/region.js +145 -155
- package/src/renderRequests.js +3 -3
- package/src/renderer.js +635 -620
- package/src/scene.js +479 -419
- package/src/sceneExporter.js +22 -17
- package/src/sceneLoader.js +542 -296
- package/src/shaders/rgbVolumeRender.js +11 -18
- package/src/shaders/textureArray.js +5 -12
- package/src/shaders/textureSlide.js +10 -17
- package/src/shaders/volumeRender.js +11 -18
- package/src/shaders/volumeRender_old.js +11 -18
- package/src/shaders/volumeTexture.js +7 -14
- package/src/textSprite.js +23 -19
- package/src/texture/texture.js +14 -15
- package/src/texture/textureArray.js +14 -16
- package/src/three/InstancedPoints.js +2 -9
- package/src/three/Loader.js +334 -315
- package/src/three/line/Line.js +165 -215
- package/src/three/line/LineSegments.js +40 -55
- package/src/three/line/LineSegments2.js +322 -366
- package/src/three/line/LineSegmentsGeometry.js +239 -280
- package/src/three-js-csg.js +260 -252
- package/src/tsl/glyphRenderMaterial.js +12 -3
- package/src/tsl/glyphTransform.js +51 -29
- package/src/tsl/textureSlides.js +23 -24
- package/src/utilities.js +309 -371
- package/src/videoHandler.js +76 -83
- package/src/workers/geometryCSG.worker.js +33 -36
- package/src/workers/geometryCSGInternal.js +39 -44
- package/src/zinc.js +4 -7
- package/vite.config.js +7 -7
package/src/sceneLoader.js
CHANGED
|
@@ -41,14 +41,14 @@ const SceneLoader = function (sceneIn) {
|
|
|
41
41
|
this.progressMap = {};
|
|
42
42
|
viewLoaded = false;
|
|
43
43
|
errorDownload = false;
|
|
44
|
-
}
|
|
44
|
+
};
|
|
45
45
|
|
|
46
46
|
//Return a function which returns true if the loads requested before
|
|
47
47
|
//this call have been cancelled.
|
|
48
48
|
const createStaleCheck = () => {
|
|
49
49
|
const requestGeneration = generation;
|
|
50
50
|
return () => requestGeneration !== generation;
|
|
51
|
-
}
|
|
51
|
+
};
|
|
52
52
|
/**
|
|
53
53
|
* This function returns a three component array, which contains
|
|
54
54
|
* [totalsize, totalLoaded and errorDownload] of all the downloads happening
|
|
@@ -66,71 +66,72 @@ const SceneLoader = function (sceneIn) {
|
|
|
66
66
|
totalSize += progress[1];
|
|
67
67
|
totalLoaded += progress[0];
|
|
68
68
|
|
|
69
|
-
if (progress[1] == 0)
|
|
70
|
-
unknownFound = true;
|
|
69
|
+
if (progress[1] == 0) unknownFound = true;
|
|
71
70
|
}
|
|
72
71
|
if (unknownFound) {
|
|
73
72
|
totalSize = 0;
|
|
74
73
|
}
|
|
75
|
-
return [
|
|
76
|
-
}
|
|
74
|
+
return [totalSize, totalLoaded, errorDownload];
|
|
75
|
+
};
|
|
77
76
|
|
|
78
77
|
//Stores the current progress of downloads
|
|
79
|
-
this.onProgress = id => {
|
|
80
|
-
return xhr => {
|
|
81
|
-
this.progressMap[id] = [
|
|
78
|
+
this.onProgress = (id) => {
|
|
79
|
+
return (xhr) => {
|
|
80
|
+
this.progressMap[id] = [xhr.loaded, xhr.total];
|
|
82
81
|
};
|
|
83
|
-
}
|
|
82
|
+
};
|
|
84
83
|
|
|
85
|
-
this.onError = finishCallback => {
|
|
84
|
+
this.onError = (finishCallback) => {
|
|
86
85
|
const isStale = createStaleCheck();
|
|
87
|
-
return xhr => {
|
|
86
|
+
return (xhr) => {
|
|
88
87
|
if (isStale()) return;
|
|
89
88
|
this.toBeDownloaded = this.toBeDownloaded - 1;
|
|
90
89
|
errorDownload = true;
|
|
91
|
-
console.error(
|
|
90
|
+
console.error(
|
|
91
|
+
`There is an issue with external resource ${xhr?.responseURL ? ': ' + xhr?.responseURL : ''}.`,
|
|
92
|
+
);
|
|
92
93
|
const payload = {
|
|
93
|
-
type:
|
|
94
|
-
xhr
|
|
94
|
+
type: 'Error',
|
|
95
|
+
xhr,
|
|
95
96
|
};
|
|
96
97
|
if (finishCallback) {
|
|
97
98
|
finishCallback(payload);
|
|
98
99
|
}
|
|
99
|
-
}
|
|
100
|
+
};
|
|
100
101
|
};
|
|
101
102
|
|
|
102
103
|
let loadMultipleViews = (referenceURL, views) => {
|
|
103
104
|
const defaultView = views.Default;
|
|
104
105
|
if (views.Inline) {
|
|
105
|
-
|
|
106
|
+
scene.setupMultipleViews(defaultView, views.Entries);
|
|
106
107
|
} else {
|
|
107
108
|
const promises = [];
|
|
108
109
|
for (const [key, value] of Object.entries(views.Entries)) {
|
|
109
110
|
if (referenceURL) {
|
|
110
111
|
const newURL = createNewURL(value, referenceURL);
|
|
111
|
-
promises.push(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
112
|
+
promises.push(
|
|
113
|
+
new Promise((resolve, reject) => {
|
|
114
|
+
// Add parameters if we are sent them
|
|
115
|
+
fetch(newURL)
|
|
116
|
+
.then((response) => response.json())
|
|
117
|
+
.then((data) => resolve({ key: key, data: data }))
|
|
118
|
+
.catch((data) => reject(data));
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
118
121
|
}
|
|
119
122
|
}
|
|
120
|
-
Promise.all(promises)
|
|
121
|
-
.then(values => {
|
|
123
|
+
Promise.all(promises).then((values) => {
|
|
122
124
|
const entries = {};
|
|
123
|
-
values.forEach(entry => {
|
|
125
|
+
values.forEach((entry) => {
|
|
124
126
|
entries[entry.key] = entry.data;
|
|
125
127
|
});
|
|
126
128
|
scene.setupMultipleViews(defaultView, entries);
|
|
127
129
|
let zincCameraControls = scene.getZincCameraControls();
|
|
128
|
-
if (zincCameraControls)
|
|
129
|
-
zincCameraControls.setCurrentViewport(defaultView);
|
|
130
|
+
if (zincCameraControls) zincCameraControls.setCurrentViewport(defaultView);
|
|
130
131
|
viewLoaded = true;
|
|
131
132
|
});
|
|
132
133
|
}
|
|
133
|
-
}
|
|
134
|
+
};
|
|
134
135
|
|
|
135
136
|
/**
|
|
136
137
|
* Load the viewport from an external location provided by the url.
|
|
@@ -149,7 +150,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
149
150
|
})
|
|
150
151
|
.then((viewData) => {
|
|
151
152
|
if (isStale()) return;
|
|
152
|
-
scene.setupMultipleViews(
|
|
153
|
+
scene.setupMultipleViews('default', { default: viewData });
|
|
153
154
|
scene.resetView();
|
|
154
155
|
viewLoaded = true;
|
|
155
156
|
--this.toBeDownloaded;
|
|
@@ -159,39 +160,60 @@ const SceneLoader = function (sceneIn) {
|
|
|
159
160
|
})
|
|
160
161
|
.catch((error) => {
|
|
161
162
|
console.error(`Fetch failed for URL: ${requestURL}`, error);
|
|
162
|
-
|
|
163
|
+
this.onError(finishCallback)({ responseURL: requestURL });
|
|
163
164
|
});
|
|
164
|
-
|
|
165
|
+
};
|
|
165
166
|
|
|
166
|
-
/**
|
|
167
|
+
/**
|
|
167
168
|
* Load a legacy model(s) format with the provided URLs and parameters. This only loads the geometry
|
|
168
169
|
* without any of the metadata. Therefore, extra parameters should be provided.
|
|
169
170
|
*
|
|
170
171
|
* @deprecated
|
|
171
172
|
*/
|
|
172
|
-
this.loadModelsURL = (
|
|
173
|
+
this.loadModelsURL = (
|
|
174
|
+
region,
|
|
175
|
+
urls,
|
|
176
|
+
colours,
|
|
177
|
+
opacities,
|
|
178
|
+
timeEnabled,
|
|
179
|
+
morphColour,
|
|
180
|
+
finishCallback,
|
|
181
|
+
) => {
|
|
173
182
|
const number = urls.length;
|
|
174
183
|
this.toBeDownloaded += number;
|
|
175
184
|
for (let i = 0; i < number; i++) {
|
|
176
185
|
const filename = urls[i];
|
|
177
186
|
let colour = Zinc.defaultMaterialColor;
|
|
178
187
|
let opacity = Zinc.defaultOpacity;
|
|
179
|
-
if (colours != undefined && colours[i] != undefined)
|
|
180
|
-
|
|
181
|
-
if (opacities != undefined && opacities[i] != undefined)
|
|
182
|
-
opacity = opacities[i];
|
|
188
|
+
if (colours != undefined && colours[i] != undefined) colour = colours[i] ? true : false;
|
|
189
|
+
if (opacities != undefined && opacities[i] != undefined) opacity = opacities[i];
|
|
183
190
|
let localTimeEnabled = 0;
|
|
184
191
|
if (timeEnabled != undefined && timeEnabled[i] != undefined)
|
|
185
192
|
localTimeEnabled = timeEnabled[i] ? true : false;
|
|
186
193
|
let localMorphColour = false;
|
|
187
194
|
if (morphColour != undefined && morphColour[i] != undefined)
|
|
188
195
|
localMorphColour = morphColour[i] ? true : false;
|
|
189
|
-
primitivesLoader.load(
|
|
190
|
-
|
|
196
|
+
primitivesLoader.load(
|
|
197
|
+
filename,
|
|
198
|
+
meshloader(
|
|
199
|
+
region,
|
|
200
|
+
colour,
|
|
201
|
+
opacity,
|
|
202
|
+
localTimeEnabled,
|
|
203
|
+
localMorphColour,
|
|
204
|
+
undefined,
|
|
205
|
+
undefined,
|
|
206
|
+
undefined,
|
|
207
|
+
undefined,
|
|
208
|
+
finishCallback,
|
|
209
|
+
),
|
|
210
|
+
this.onProgress(filename),
|
|
211
|
+
this.onError(finishCallback),
|
|
212
|
+
);
|
|
191
213
|
}
|
|
192
|
-
}
|
|
214
|
+
};
|
|
193
215
|
|
|
194
|
-
|
|
216
|
+
/**
|
|
195
217
|
* Load a legacy file format containing the viewport and its meta file from an external
|
|
196
218
|
* location provided by the url. Use the new metadata format with
|
|
197
219
|
* {@link Zinc.SceneLoader.#loadMetadataURL} instead.
|
|
@@ -200,44 +222,53 @@ const SceneLoader = function (sceneIn) {
|
|
|
200
222
|
* @deprecated
|
|
201
223
|
*/
|
|
202
224
|
this.loadFromViewURL = (targetRegion, jsonFilePrefix, finishCallback) => {
|
|
203
|
-
const requestURL = jsonFilePrefix +
|
|
225
|
+
const requestURL = jsonFilePrefix + '_view.json';
|
|
204
226
|
const isStale = createStaleCheck();
|
|
205
227
|
fetch(requestURL)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
228
|
+
.then((response) => {
|
|
229
|
+
if (!response.ok) {
|
|
230
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
231
|
+
}
|
|
232
|
+
return response.json();
|
|
233
|
+
})
|
|
234
|
+
.then((viewData) => {
|
|
235
|
+
if (isStale()) return;
|
|
236
|
+
scene.loadView(viewData);
|
|
237
|
+
const urls = [];
|
|
238
|
+
const filename_prefix = jsonFilePrefix + '_';
|
|
239
|
+
for (let i = 0; i < viewData.numberOfResources; i++) {
|
|
240
|
+
const filename = filename_prefix + (i + 1) + '.json';
|
|
241
|
+
urls.push(filename);
|
|
242
|
+
}
|
|
243
|
+
this.loadModelsURL(
|
|
244
|
+
targetRegion,
|
|
245
|
+
urls,
|
|
246
|
+
viewData.colour,
|
|
247
|
+
viewData.opacity,
|
|
248
|
+
viewData.timeEnabled,
|
|
249
|
+
viewData.morphColour,
|
|
250
|
+
finishCallback,
|
|
251
|
+
);
|
|
252
|
+
})
|
|
253
|
+
.catch((error) => {
|
|
254
|
+
console.error(`Failed to load view data from: ${requestURL}`, error);
|
|
255
|
+
});
|
|
256
|
+
};
|
|
235
257
|
|
|
236
258
|
//Internal loader for a regular zinc geometry.
|
|
237
|
-
const linesloader = (
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
259
|
+
const linesloader = (
|
|
260
|
+
region,
|
|
261
|
+
localTimeEnabled,
|
|
262
|
+
localMorphColour,
|
|
263
|
+
groupName,
|
|
264
|
+
anatomicalId,
|
|
265
|
+
renderOrder,
|
|
266
|
+
lod,
|
|
267
|
+
tubeLines,
|
|
268
|
+
finishCallback,
|
|
269
|
+
) => {
|
|
270
|
+
const isStale = createStaleCheck();
|
|
271
|
+
return (geometry, materials) => {
|
|
241
272
|
if (isStale()) {
|
|
242
273
|
geometry.dispose();
|
|
243
274
|
return;
|
|
@@ -245,7 +276,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
245
276
|
const newLines = tubeLines ? new TubeLines() : new Lines();
|
|
246
277
|
let material = undefined;
|
|
247
278
|
if (materials && materials[0]) {
|
|
248
|
-
material = new THREE.LineBasicMaterial({color:materials[0].color.clone()});
|
|
279
|
+
material = new THREE.LineBasicMaterial({ color: materials[0].color.clone() });
|
|
249
280
|
if (1.0 > materials[0].opacity) {
|
|
250
281
|
material.transparent = true;
|
|
251
282
|
}
|
|
@@ -270,10 +301,10 @@ const SceneLoader = function (sceneIn) {
|
|
|
270
301
|
}
|
|
271
302
|
--this.toBeDownloaded;
|
|
272
303
|
geometry.dispose();
|
|
273
|
-
if (finishCallback != undefined &&
|
|
304
|
+
if (finishCallback != undefined && typeof finishCallback == 'function')
|
|
274
305
|
finishCallback(newLines);
|
|
275
306
|
};
|
|
276
|
-
}
|
|
307
|
+
};
|
|
277
308
|
|
|
278
309
|
/**
|
|
279
310
|
* Load lines into this scene object.
|
|
@@ -284,28 +315,57 @@ const SceneLoader = function (sceneIn) {
|
|
|
284
315
|
* @param {Function} finishCallback - Callback function which will be called
|
|
285
316
|
* once the glyphset is succssfully load in.
|
|
286
317
|
*/
|
|
287
|
-
this.loadLinesURL = (
|
|
288
|
-
|
|
318
|
+
this.loadLinesURL = (
|
|
319
|
+
region,
|
|
320
|
+
url,
|
|
321
|
+
timeEnabled,
|
|
322
|
+
morphColour,
|
|
323
|
+
groupName,
|
|
324
|
+
finishCallback,
|
|
325
|
+
options,
|
|
326
|
+
) => {
|
|
327
|
+
let localTimeEnabled = 0;
|
|
289
328
|
this.toBeDownloaded += 1;
|
|
290
329
|
let isInline = options?.isInline ? options.isInline : false;
|
|
291
330
|
let anatomicalId = options?.anatomicalId ? options.anatomicalId : undefined;
|
|
292
|
-
let renderOrder =
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (morphColour != undefined)
|
|
297
|
-
localMorphColour = morphColour ? true : false;
|
|
331
|
+
let renderOrder = options && 'renderOrder' in options ? options.renderOrder : undefined;
|
|
332
|
+
if (timeEnabled != undefined) localTimeEnabled = timeEnabled ? true : false;
|
|
333
|
+
let localMorphColour = 0;
|
|
334
|
+
if (morphColour != undefined) localMorphColour = morphColour ? true : false;
|
|
298
335
|
let tubeLines = options.tubeLines && !localTimeEnabled && !localMorphColour;
|
|
299
336
|
if (isInline) {
|
|
300
|
-
let object = primitivesLoader.parse(
|
|
301
|
-
|
|
302
|
-
|
|
337
|
+
let object = primitivesLoader.parse(url);
|
|
338
|
+
linesloader(
|
|
339
|
+
region,
|
|
340
|
+
localTimeEnabled,
|
|
341
|
+
localMorphColour,
|
|
342
|
+
groupName,
|
|
343
|
+
anatomicalId,
|
|
344
|
+
renderOrder,
|
|
345
|
+
options.lod,
|
|
346
|
+
tubeLines,
|
|
347
|
+
finishCallback,
|
|
348
|
+
)(object.geometry, object.materials);
|
|
303
349
|
} else {
|
|
304
|
-
primitivesLoader.load(
|
|
305
|
-
|
|
306
|
-
|
|
350
|
+
primitivesLoader.load(
|
|
351
|
+
url,
|
|
352
|
+
linesloader(
|
|
353
|
+
region,
|
|
354
|
+
localTimeEnabled,
|
|
355
|
+
localMorphColour,
|
|
356
|
+
groupName,
|
|
357
|
+
anatomicalId,
|
|
358
|
+
renderOrder,
|
|
359
|
+
options.lod,
|
|
360
|
+
tubeLines,
|
|
361
|
+
finishCallback,
|
|
362
|
+
),
|
|
363
|
+
this.onProgress(url),
|
|
364
|
+
this.onError(finishCallback),
|
|
365
|
+
options.loaderOptions,
|
|
366
|
+
);
|
|
307
367
|
}
|
|
308
|
-
}
|
|
368
|
+
};
|
|
309
369
|
|
|
310
370
|
const glyphsetloader = (region, glyphurl, groupName, finishCallback, options) => {
|
|
311
371
|
const isStale = createStaleCheck();
|
|
@@ -315,33 +375,32 @@ const SceneLoader = function (sceneIn) {
|
|
|
315
375
|
if (typeof glyphsetData === 'string' || glyphsetData instanceof String) {
|
|
316
376
|
glyphsetData = JSON.parse(data);
|
|
317
377
|
}
|
|
318
|
-
let isInline
|
|
319
|
-
let anatomicalId =
|
|
378
|
+
let isInline = options && options.isInline ? options.isInline : undefined;
|
|
379
|
+
let anatomicalId = options && options.anatomicalId ? options.anatomicalId : undefined;
|
|
320
380
|
let displayLabels = options?.displayLabels;
|
|
321
381
|
if (displayLabels === undefined) {
|
|
322
382
|
displayLabels = true;
|
|
323
383
|
}
|
|
324
|
-
let renderOrder =
|
|
384
|
+
let renderOrder = options && 'renderOrder' in options ? options.renderOrder : undefined;
|
|
325
385
|
const newGlyphset = new Glyphset();
|
|
326
386
|
newGlyphset.setDuration(scene.getDuration());
|
|
327
387
|
newGlyphset.groupName = groupName;
|
|
328
388
|
let myCallback = () => {
|
|
329
389
|
if (isStale()) return;
|
|
330
390
|
--this.toBeDownloaded;
|
|
331
|
-
if (finishCallback != undefined &&
|
|
391
|
+
if (finishCallback != undefined && typeof finishCallback == 'function')
|
|
332
392
|
finishCallback(newGlyphset);
|
|
333
|
-
}
|
|
393
|
+
};
|
|
334
394
|
++this.toBeDownloaded;
|
|
335
395
|
if (isInline) {
|
|
336
396
|
newGlyphset.load(glyphsetData, glyphurl, myCallback, isInline, displayLabels);
|
|
337
|
-
}
|
|
338
|
-
else {
|
|
397
|
+
} else {
|
|
339
398
|
newGlyphset.load(glyphsetData, glyphurl, myCallback, isInline, displayLabels);
|
|
340
399
|
}
|
|
341
400
|
newGlyphset.setAnatomicalId(anatomicalId);
|
|
342
401
|
newGlyphset.setRenderOrder(renderOrder);
|
|
343
402
|
region.addZincObject(newGlyphset);
|
|
344
|
-
}
|
|
403
|
+
};
|
|
345
404
|
};
|
|
346
405
|
|
|
347
406
|
//Load a glyphset into this scene.
|
|
@@ -357,7 +416,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
357
416
|
}
|
|
358
417
|
}
|
|
359
418
|
}
|
|
360
|
-
|
|
419
|
+
glyphsetloader(region, glyphurl, groupName, finishCallback, options)(glyphsetData);
|
|
361
420
|
}
|
|
362
421
|
};
|
|
363
422
|
};
|
|
@@ -373,13 +432,17 @@ const SceneLoader = function (sceneIn) {
|
|
|
373
432
|
* once the glyphset is succssfully load in.
|
|
374
433
|
*/
|
|
375
434
|
this.loadGlyphsetURL = (region, metaurl, glyphurl, groupName, finishCallback, options) => {
|
|
376
|
-
const isInline =
|
|
435
|
+
const isInline = options && options.isInline ? options.isInline : false;
|
|
377
436
|
if (isInline) {
|
|
378
|
-
|
|
437
|
+
glyphsetloader(region, glyphurl, groupName, finishCallback, options)(metaurl);
|
|
379
438
|
} else {
|
|
380
|
-
primitivesLoader.load(
|
|
381
|
-
|
|
382
|
-
|
|
439
|
+
primitivesLoader.load(
|
|
440
|
+
metaurl,
|
|
441
|
+
glyphsetloader(region, glyphurl, groupName, finishCallback, options),
|
|
442
|
+
this.onProgress(metaurl),
|
|
443
|
+
this.onError(finishCallback),
|
|
444
|
+
options.loaderOptions,
|
|
445
|
+
);
|
|
383
446
|
|
|
384
447
|
/*
|
|
385
448
|
const xmlhttp = new XMLHttpRequest();
|
|
@@ -389,10 +452,18 @@ const SceneLoader = function (sceneIn) {
|
|
|
389
452
|
xmlhttp.open("GET", metaurl, true);
|
|
390
453
|
xmlhttp.send();*/
|
|
391
454
|
}
|
|
392
|
-
}
|
|
455
|
+
};
|
|
393
456
|
|
|
394
457
|
//Internal loader for zinc pointset.
|
|
395
|
-
const pointsetloader = (
|
|
458
|
+
const pointsetloader = (
|
|
459
|
+
region,
|
|
460
|
+
localTimeEnabled,
|
|
461
|
+
localMorphColour,
|
|
462
|
+
groupName,
|
|
463
|
+
anatomicalId,
|
|
464
|
+
renderOrder,
|
|
465
|
+
finishCallback,
|
|
466
|
+
) => {
|
|
396
467
|
const isStale = createStaleCheck();
|
|
397
468
|
return (geometry, materials) => {
|
|
398
469
|
if (isStale()) {
|
|
@@ -400,12 +471,11 @@ const SceneLoader = function (sceneIn) {
|
|
|
400
471
|
return;
|
|
401
472
|
}
|
|
402
473
|
const newPointset = new Pointset();
|
|
403
|
-
let material = new THREE.PointsMaterial(
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
});
|
|
474
|
+
let material = new THREE.PointsMaterial({
|
|
475
|
+
alphaTest: 0.05,
|
|
476
|
+
size: 10,
|
|
477
|
+
sizeAttenuation: false,
|
|
478
|
+
});
|
|
409
479
|
if (materials && materials[0]) {
|
|
410
480
|
if (1.0 > materials[0].opacity) {
|
|
411
481
|
material.transparent = true;
|
|
@@ -427,10 +497,10 @@ const SceneLoader = function (sceneIn) {
|
|
|
427
497
|
}
|
|
428
498
|
geometry.dispose();
|
|
429
499
|
--this.toBeDownloaded;
|
|
430
|
-
if (finishCallback != undefined &&
|
|
500
|
+
if (finishCallback != undefined && typeof finishCallback == 'function')
|
|
431
501
|
finishCallback(newPointset);
|
|
432
502
|
};
|
|
433
|
-
}
|
|
503
|
+
};
|
|
434
504
|
|
|
435
505
|
/**
|
|
436
506
|
* Read a STL file into this scene, the geometry will be presented as
|
|
@@ -446,11 +516,25 @@ const SceneLoader = function (sceneIn) {
|
|
|
446
516
|
const colour = Zinc.defaultMaterialColor;
|
|
447
517
|
const opacity = Zinc.defaultOpacity;
|
|
448
518
|
const loader = new STLLoader();
|
|
449
|
-
loader.crossOrigin =
|
|
450
|
-
loader.load(
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
519
|
+
loader.crossOrigin = 'Anonymous';
|
|
520
|
+
loader.load(
|
|
521
|
+
url,
|
|
522
|
+
meshloader(
|
|
523
|
+
region,
|
|
524
|
+
colour,
|
|
525
|
+
opacity,
|
|
526
|
+
false,
|
|
527
|
+
false,
|
|
528
|
+
groupName,
|
|
529
|
+
undefined,
|
|
530
|
+
undefined,
|
|
531
|
+
{},
|
|
532
|
+
finishCallback,
|
|
533
|
+
),
|
|
534
|
+
this.onProgress(url),
|
|
535
|
+
this.onError(finishCallback),
|
|
536
|
+
);
|
|
537
|
+
};
|
|
454
538
|
|
|
455
539
|
/**
|
|
456
540
|
* Read a OBJ file into this scene, the geometry will be presented as
|
|
@@ -466,11 +550,25 @@ const SceneLoader = function (sceneIn) {
|
|
|
466
550
|
const colour = Zinc.defaultMaterialColor;
|
|
467
551
|
const opacity = Zinc.defaultOpacity;
|
|
468
552
|
const loader = new OBJLoader();
|
|
469
|
-
loader.crossOrigin =
|
|
470
|
-
loader.load(
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
553
|
+
loader.crossOrigin = 'Anonymous';
|
|
554
|
+
loader.load(
|
|
555
|
+
url,
|
|
556
|
+
objloader(
|
|
557
|
+
region,
|
|
558
|
+
colour,
|
|
559
|
+
opacity,
|
|
560
|
+
false,
|
|
561
|
+
false,
|
|
562
|
+
groupName,
|
|
563
|
+
undefined,
|
|
564
|
+
undefined,
|
|
565
|
+
{},
|
|
566
|
+
finishCallback,
|
|
567
|
+
),
|
|
568
|
+
this.onProgress(url),
|
|
569
|
+
this.onError(finishCallback),
|
|
570
|
+
);
|
|
571
|
+
};
|
|
474
572
|
|
|
475
573
|
/**
|
|
476
574
|
* Load a geometry into this scene, this is a subsequent called from
|
|
@@ -485,39 +583,84 @@ const SceneLoader = function (sceneIn) {
|
|
|
485
583
|
* @param {Function} finishCallback - Callback function which will be called
|
|
486
584
|
* once the geometry is succssfully loaded in.
|
|
487
585
|
*/
|
|
488
|
-
const loadSurfaceURL = (
|
|
586
|
+
const loadSurfaceURL = (
|
|
587
|
+
region,
|
|
588
|
+
url,
|
|
589
|
+
timeEnabled,
|
|
590
|
+
morphColour,
|
|
591
|
+
groupName,
|
|
592
|
+
finishCallback,
|
|
593
|
+
options,
|
|
594
|
+
) => {
|
|
489
595
|
this.toBeDownloaded += 1;
|
|
490
596
|
const colour = Zinc.defaultMaterialColor;
|
|
491
597
|
const opacity = Zinc.defaultOpacity;
|
|
492
598
|
let localTimeEnabled = 0;
|
|
493
|
-
let isInline =
|
|
494
|
-
let fileFormat =
|
|
495
|
-
let anatomicalId =
|
|
496
|
-
let renderOrder =
|
|
497
|
-
if (timeEnabled != undefined)
|
|
498
|
-
localTimeEnabled = timeEnabled ? true : false;
|
|
599
|
+
let isInline = options && options.isInline ? options.isInline : false;
|
|
600
|
+
let fileFormat = options && options.fileFormat ? options.fileFormat : undefined;
|
|
601
|
+
let anatomicalId = options && options.anatomicalId ? options.anatomicalId : undefined;
|
|
602
|
+
let renderOrder = options && 'renderOrder' in options ? options.renderOrder : undefined;
|
|
603
|
+
if (timeEnabled != undefined) localTimeEnabled = timeEnabled ? true : false;
|
|
499
604
|
let localMorphColour = 0;
|
|
500
|
-
if (morphColour != undefined)
|
|
501
|
-
localMorphColour = morphColour ? true : false;
|
|
605
|
+
if (morphColour != undefined) localMorphColour = morphColour ? true : false;
|
|
502
606
|
let loader = primitivesLoader;
|
|
503
|
-
if (fileFormat ==
|
|
504
|
-
const typedLoader = fileFormat ==
|
|
505
|
-
loader = fileFormat ==
|
|
506
|
-
loader.crossOrigin =
|
|
507
|
-
loader.load(
|
|
508
|
-
|
|
509
|
-
|
|
607
|
+
if (fileFormat == 'STL' || fileFormat == 'OBJ') {
|
|
608
|
+
const typedLoader = fileFormat == 'STL' ? meshloader : objloader;
|
|
609
|
+
loader = fileFormat == 'STL' ? new STLLoader() : new OBJLoader();
|
|
610
|
+
loader.crossOrigin = 'Anonymous';
|
|
611
|
+
loader.load(
|
|
612
|
+
url,
|
|
613
|
+
typedLoader(
|
|
614
|
+
region,
|
|
615
|
+
colour,
|
|
616
|
+
opacity,
|
|
617
|
+
localTimeEnabled,
|
|
618
|
+
localMorphColour,
|
|
619
|
+
groupName,
|
|
620
|
+
anatomicalId,
|
|
621
|
+
renderOrder,
|
|
622
|
+
options ? options : {},
|
|
623
|
+
finishCallback,
|
|
624
|
+
),
|
|
625
|
+
this.onProgress(url),
|
|
626
|
+
this.onError(finishCallback),
|
|
627
|
+
);
|
|
510
628
|
return;
|
|
511
629
|
}
|
|
512
630
|
if (isInline) {
|
|
513
|
-
const object = primitivesLoader.parse(
|
|
514
|
-
|
|
515
|
-
|
|
631
|
+
const object = primitivesLoader.parse(url);
|
|
632
|
+
meshloader(
|
|
633
|
+
region,
|
|
634
|
+
colour,
|
|
635
|
+
opacity,
|
|
636
|
+
localTimeEnabled,
|
|
637
|
+
localMorphColour,
|
|
638
|
+
groupName,
|
|
639
|
+
anatomicalId,
|
|
640
|
+
renderOrder,
|
|
641
|
+
options,
|
|
642
|
+
finishCallback,
|
|
643
|
+
)(object.geometry, object.materials);
|
|
516
644
|
} else {
|
|
517
|
-
loader.crossOrigin =
|
|
518
|
-
primitivesLoader.load(
|
|
519
|
-
|
|
520
|
-
|
|
645
|
+
loader.crossOrigin = 'Anonymous';
|
|
646
|
+
primitivesLoader.load(
|
|
647
|
+
url,
|
|
648
|
+
meshloader(
|
|
649
|
+
region,
|
|
650
|
+
colour,
|
|
651
|
+
opacity,
|
|
652
|
+
localTimeEnabled,
|
|
653
|
+
localMorphColour,
|
|
654
|
+
groupName,
|
|
655
|
+
anatomicalId,
|
|
656
|
+
renderOrder,
|
|
657
|
+
options,
|
|
658
|
+
finishCallback,
|
|
659
|
+
),
|
|
660
|
+
this.onProgress(url),
|
|
661
|
+
this.onError(finishCallback),
|
|
662
|
+
options.loaderOptions,
|
|
663
|
+
);
|
|
521
664
|
}
|
|
522
665
|
};
|
|
523
666
|
|
|
@@ -525,15 +668,14 @@ const SceneLoader = function (sceneIn) {
|
|
|
525
668
|
//allCompletedCallback is called
|
|
526
669
|
const metaFinishCallback = function (numberOfDownloaded, finishCallback, allCompletedCallback) {
|
|
527
670
|
let downloadedItem = 0;
|
|
528
|
-
return zincObject => {
|
|
671
|
+
return (zincObject) => {
|
|
529
672
|
downloadedItem = downloadedItem + 1;
|
|
530
|
-
if (zincObject &&
|
|
673
|
+
if (zincObject && finishCallback != undefined && typeof finishCallback == 'function') {
|
|
531
674
|
finishCallback(zincObject);
|
|
532
675
|
}
|
|
533
676
|
if (downloadedItem == numberOfDownloaded) {
|
|
534
|
-
if (viewLoaded === false)
|
|
535
|
-
|
|
536
|
-
if (allCompletedCallback != undefined && (typeof allCompletedCallback == 'function')) {
|
|
677
|
+
if (viewLoaded === false) scene.viewAll();
|
|
678
|
+
if (allCompletedCallback != undefined && typeof allCompletedCallback == 'function') {
|
|
537
679
|
allCompletedCallback();
|
|
538
680
|
let zincCameraControls = scene.getZincCameraControls();
|
|
539
681
|
if (zincCameraControls) {
|
|
@@ -553,32 +695,57 @@ const SceneLoader = function (sceneIn) {
|
|
|
553
695
|
* @param {Function} finishCallback - Callback function which will be called
|
|
554
696
|
* once the glyphset is succssfully load in.
|
|
555
697
|
*/
|
|
556
|
-
this.loadPointsetURL = (
|
|
698
|
+
this.loadPointsetURL = (
|
|
699
|
+
region,
|
|
700
|
+
url,
|
|
701
|
+
timeEnabled,
|
|
702
|
+
morphColour,
|
|
703
|
+
groupName,
|
|
704
|
+
finishCallback,
|
|
705
|
+
options,
|
|
706
|
+
) => {
|
|
557
707
|
let localTimeEnabled = 0;
|
|
558
708
|
this.toBeDownloaded += 1;
|
|
559
|
-
if (timeEnabled != undefined)
|
|
560
|
-
localTimeEnabled = timeEnabled ? true : false;
|
|
709
|
+
if (timeEnabled != undefined) localTimeEnabled = timeEnabled ? true : false;
|
|
561
710
|
let localMorphColour = 0;
|
|
562
|
-
if (morphColour != undefined)
|
|
563
|
-
|
|
564
|
-
let
|
|
565
|
-
let
|
|
566
|
-
let renderOrder = (options && "renderOrder" in options) ? options.renderOrder : undefined;
|
|
711
|
+
if (morphColour != undefined) localMorphColour = morphColour ? true : false;
|
|
712
|
+
let isInline = options && options.isInline ? options.isInline : false;
|
|
713
|
+
let anatomicalId = options && options.anatomicalId ? options.anatomicalId : undefined;
|
|
714
|
+
let renderOrder = options && 'renderOrder' in options ? options.renderOrder : undefined;
|
|
567
715
|
if (isInline) {
|
|
568
|
-
const object = primitivesLoader.parse(
|
|
569
|
-
|
|
570
|
-
|
|
716
|
+
const object = primitivesLoader.parse(url);
|
|
717
|
+
pointsetloader(
|
|
718
|
+
region,
|
|
719
|
+
localTimeEnabled,
|
|
720
|
+
localMorphColour,
|
|
721
|
+
groupName,
|
|
722
|
+
anatomicalId,
|
|
723
|
+
renderOrder,
|
|
724
|
+
finishCallback,
|
|
725
|
+
)(object.geometry, object.materials);
|
|
571
726
|
} else {
|
|
572
|
-
primitivesLoader.load(
|
|
573
|
-
|
|
574
|
-
|
|
727
|
+
primitivesLoader.load(
|
|
728
|
+
url,
|
|
729
|
+
pointsetloader(
|
|
730
|
+
region,
|
|
731
|
+
localTimeEnabled,
|
|
732
|
+
localMorphColour,
|
|
733
|
+
groupName,
|
|
734
|
+
anatomicalId,
|
|
735
|
+
renderOrder,
|
|
736
|
+
finishCallback,
|
|
737
|
+
),
|
|
738
|
+
this.onProgress(url),
|
|
739
|
+
this.onError(finishCallback),
|
|
740
|
+
options.loaderOptions,
|
|
741
|
+
);
|
|
575
742
|
}
|
|
576
|
-
}
|
|
743
|
+
};
|
|
577
744
|
|
|
578
745
|
const loadTexture = (region, referenceURL, textureData, groupName, finishCallback, options) => {
|
|
579
|
-
let isInline
|
|
580
|
-
let anatomicalId =
|
|
581
|
-
let renderOrder =
|
|
746
|
+
let isInline = options && options.isInline ? options.isInline : undefined;
|
|
747
|
+
let anatomicalId = options && options.anatomicalId ? options.anatomicalId : undefined;
|
|
748
|
+
let renderOrder = options && 'renderOrder' in options ? options.renderOrder : undefined;
|
|
582
749
|
let newTexture = undefined;
|
|
583
750
|
if (textureData) {
|
|
584
751
|
if (referenceURL && textureData.images && textureData.images.source) {
|
|
@@ -588,7 +755,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
588
755
|
textureData.images.source[i] = newURL;
|
|
589
756
|
}
|
|
590
757
|
}
|
|
591
|
-
if (textureData.type ===
|
|
758
|
+
if (textureData.type === 'slides') {
|
|
592
759
|
newTexture = new TextureSlides();
|
|
593
760
|
}
|
|
594
761
|
if (newTexture) {
|
|
@@ -602,9 +769,9 @@ const SceneLoader = function (sceneIn) {
|
|
|
602
769
|
//Add zincObject after it has sort out all the required download
|
|
603
770
|
region.addZincObject(newTexture);
|
|
604
771
|
--this.toBeDownloaded;
|
|
605
|
-
if (finishCallback != undefined &&
|
|
772
|
+
if (finishCallback != undefined && typeof finishCallback == 'function')
|
|
606
773
|
finishCallback(newTexture);
|
|
607
|
-
}
|
|
774
|
+
};
|
|
608
775
|
++this.toBeDownloaded;
|
|
609
776
|
newTexture.load(textureData, myCallback, isInline);
|
|
610
777
|
newTexture.setAnatomicalId(anatomicalId);
|
|
@@ -621,31 +788,31 @@ const SceneLoader = function (sceneIn) {
|
|
|
621
788
|
* once the glyphset is succssfully load in.
|
|
622
789
|
*/
|
|
623
790
|
this.loadTextureURL = (region, url, groupName, finishCallback, options) => {
|
|
624
|
-
const isInline =
|
|
791
|
+
const isInline = options && options.isInline ? options.isInline : false;
|
|
625
792
|
if (isInline) {
|
|
626
793
|
loadTexture(region, undefined, url, groupName, finishCallback, options);
|
|
627
794
|
} else {
|
|
628
795
|
const requestURL = url;
|
|
629
796
|
const isStale = createStaleCheck();
|
|
630
797
|
fetch(requestURL)
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
798
|
+
.then((response) => {
|
|
799
|
+
if (!response.ok) {
|
|
800
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
801
|
+
}
|
|
802
|
+
const referenceURL = response.url || new URL(requestURL).href;
|
|
803
|
+
return response.json().then((textureData) => ({ textureData, referenceURL }));
|
|
804
|
+
})
|
|
805
|
+
.then(({ textureData, referenceURL }) => {
|
|
806
|
+
if (isStale()) return;
|
|
807
|
+
loadTexture(region, referenceURL, textureData, groupName, finishCallback, options);
|
|
808
|
+
})
|
|
809
|
+
.catch((error) => {
|
|
810
|
+
console.error(`Fetch failed for texture URL: ${requestURL}`, error);
|
|
811
|
+
});
|
|
645
812
|
}
|
|
646
|
-
}
|
|
813
|
+
};
|
|
647
814
|
|
|
648
|
-
|
|
815
|
+
/**
|
|
649
816
|
* Add a user provided {THREE.Geometry} into the scene as zinc geometry.
|
|
650
817
|
*
|
|
651
818
|
* @param {Three.Geometry} geometry - The threejs geometry to be added as {@link Zinc.Geometry}.
|
|
@@ -670,13 +837,13 @@ const SceneLoader = function (sceneIn) {
|
|
|
670
837
|
materialIn,
|
|
671
838
|
groupName,
|
|
672
839
|
renderOrder,
|
|
673
|
-
anatomicalId
|
|
840
|
+
anatomicalId,
|
|
674
841
|
) => {
|
|
675
842
|
let options = {};
|
|
676
843
|
options.colour = colour;
|
|
677
844
|
options.opacity = opacity;
|
|
678
845
|
options.localTimeEnabled = localTimeEnabled;
|
|
679
|
-
options.localMorphColour = localMorphColour
|
|
846
|
+
options.localMorphColour = localMorphColour;
|
|
680
847
|
const newGeometry = new Geometry();
|
|
681
848
|
newGeometry.createMesh(geometryIn, materialIn, options);
|
|
682
849
|
if (newGeometry.getMorph()) {
|
|
@@ -685,7 +852,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
685
852
|
newGeometry.setAnatomicalId(anatomicalId);
|
|
686
853
|
if (region) region.addZincObject(newGeometry);
|
|
687
854
|
newGeometry.setDuration(scene.getDuration());
|
|
688
|
-
if (finishCallback != undefined &&
|
|
855
|
+
if (finishCallback != undefined && typeof finishCallback == 'function')
|
|
689
856
|
finishCallback(newGeometry);
|
|
690
857
|
if (newGeometry.videoHandler) {
|
|
691
858
|
scene.setVideoHandler(newGeometry.videoHandler);
|
|
@@ -693,7 +860,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
693
860
|
return newGeometry;
|
|
694
861
|
}
|
|
695
862
|
return undefined;
|
|
696
|
-
}
|
|
863
|
+
};
|
|
697
864
|
|
|
698
865
|
//Internal loader for a regular zinc geometry.
|
|
699
866
|
const meshloader = (
|
|
@@ -706,7 +873,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
706
873
|
anatomicalId,
|
|
707
874
|
renderOrder,
|
|
708
875
|
options,
|
|
709
|
-
finishCallback
|
|
876
|
+
finishCallback,
|
|
710
877
|
) => {
|
|
711
878
|
const isStale = createStaleCheck();
|
|
712
879
|
return (geometry, materials) => {
|
|
@@ -718,8 +885,19 @@ const SceneLoader = function (sceneIn) {
|
|
|
718
885
|
if (materials && materials[0]) {
|
|
719
886
|
material = materials[0];
|
|
720
887
|
}
|
|
721
|
-
const zincGeometry = addZincGeometry(
|
|
722
|
-
|
|
888
|
+
const zincGeometry = addZincGeometry(
|
|
889
|
+
region,
|
|
890
|
+
geometry,
|
|
891
|
+
colour,
|
|
892
|
+
opacity,
|
|
893
|
+
localTimeEnabled,
|
|
894
|
+
localMorphColour,
|
|
895
|
+
undefined,
|
|
896
|
+
material,
|
|
897
|
+
groupName,
|
|
898
|
+
renderOrder,
|
|
899
|
+
anatomicalId,
|
|
900
|
+
);
|
|
723
901
|
if (options?.lod?.levels) {
|
|
724
902
|
for (const [key, value] of Object.entries(options.lod.levels)) {
|
|
725
903
|
zincGeometry.addLOD(primitivesLoader, key, value.URL, value.Index, options.lod.preload);
|
|
@@ -727,11 +905,11 @@ const SceneLoader = function (sceneIn) {
|
|
|
727
905
|
}
|
|
728
906
|
--this.toBeDownloaded;
|
|
729
907
|
geometry.dispose();
|
|
730
|
-
if (finishCallback != undefined &&
|
|
908
|
+
if (finishCallback != undefined && typeof finishCallback == 'function') {
|
|
731
909
|
finishCallback(zincGeometry);
|
|
732
910
|
}
|
|
733
911
|
};
|
|
734
|
-
}
|
|
912
|
+
};
|
|
735
913
|
|
|
736
914
|
//Internal loader for OBJ files, OBJLoader returns a group and each mesh
|
|
737
915
|
//in it is added as a separate zinc geometry.
|
|
@@ -745,11 +923,21 @@ const SceneLoader = function (sceneIn) {
|
|
|
745
923
|
anatomicalId,
|
|
746
924
|
renderOrder,
|
|
747
925
|
options,
|
|
748
|
-
finishCallback
|
|
926
|
+
finishCallback,
|
|
749
927
|
) => {
|
|
750
928
|
const isStale = createStaleCheck();
|
|
751
|
-
const onMeshLoaded = meshloader(
|
|
752
|
-
|
|
929
|
+
const onMeshLoaded = meshloader(
|
|
930
|
+
region,
|
|
931
|
+
colour,
|
|
932
|
+
opacity,
|
|
933
|
+
localTimeEnabled,
|
|
934
|
+
localMorphColour,
|
|
935
|
+
groupName,
|
|
936
|
+
anatomicalId,
|
|
937
|
+
renderOrder,
|
|
938
|
+
options,
|
|
939
|
+
finishCallback,
|
|
940
|
+
);
|
|
753
941
|
return (group) => {
|
|
754
942
|
const meshes = [];
|
|
755
943
|
group.traverse((child) => {
|
|
@@ -773,16 +961,23 @@ const SceneLoader = function (sceneIn) {
|
|
|
773
961
|
this.toBeDownloaded += meshes.length - 1;
|
|
774
962
|
meshes.forEach((mesh) => onMeshLoaded(mesh.geometry));
|
|
775
963
|
};
|
|
776
|
-
}
|
|
964
|
+
};
|
|
777
965
|
|
|
778
966
|
//Turn ISO 8601 duration string into an array.
|
|
779
967
|
const parseDuration = (durationString) => {
|
|
780
|
-
const regex =
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
return {
|
|
784
|
-
|
|
785
|
-
|
|
968
|
+
const regex =
|
|
969
|
+
/P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/;
|
|
970
|
+
const [, years, months, weeks, days, hours, mins, secs] = durationString.match(regex);
|
|
971
|
+
return {
|
|
972
|
+
years: years,
|
|
973
|
+
months: months,
|
|
974
|
+
weeks: weeks,
|
|
975
|
+
days: days,
|
|
976
|
+
hours: hours,
|
|
977
|
+
mins: mins,
|
|
978
|
+
secs: secs,
|
|
979
|
+
};
|
|
980
|
+
};
|
|
786
981
|
|
|
787
982
|
//Load settings from metadata item.
|
|
788
983
|
this.loadSettings = (item) => {
|
|
@@ -803,7 +998,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
803
998
|
}
|
|
804
999
|
}
|
|
805
1000
|
}
|
|
806
|
-
}
|
|
1001
|
+
};
|
|
807
1002
|
|
|
808
1003
|
//Function to process each of the graphical metadata item except for view and
|
|
809
1004
|
//settings.
|
|
@@ -814,8 +1009,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
814
1009
|
if (item.URL) {
|
|
815
1010
|
//Convert it into an array
|
|
816
1011
|
newURL = item.URL;
|
|
817
|
-
if (referenceURL)
|
|
818
|
-
newURL = createNewURL(newURL, referenceURL);
|
|
1012
|
+
if (referenceURL) newURL = createNewURL(newURL, referenceURL);
|
|
819
1013
|
} else if (item.Inline) {
|
|
820
1014
|
newURL = item.Inline.URL;
|
|
821
1015
|
isInline = true;
|
|
@@ -826,13 +1020,13 @@ const SceneLoader = function (sceneIn) {
|
|
|
826
1020
|
lod.levels = {};
|
|
827
1021
|
for (const [key, value] of Object.entries(item.LOD.Levels)) {
|
|
828
1022
|
lod.levels[key] = {};
|
|
829
|
-
lod.levels[key][
|
|
830
|
-
lod.levels[key][
|
|
1023
|
+
lod.levels[key]['URL'] = createNewURL(value.URL, referenceURL);
|
|
1024
|
+
lod.levels[key]['Index'] = value.Index;
|
|
831
1025
|
}
|
|
832
1026
|
}
|
|
833
1027
|
let groupName = item.GroupName;
|
|
834
|
-
if (groupName === undefined || groupName ===
|
|
835
|
-
groupName =
|
|
1028
|
+
if (groupName === undefined || groupName === '') {
|
|
1029
|
+
groupName = '_Unnamed';
|
|
836
1030
|
}
|
|
837
1031
|
|
|
838
1032
|
let options = {
|
|
@@ -845,14 +1039,22 @@ const SceneLoader = function (sceneIn) {
|
|
|
845
1039
|
compression: item.compression,
|
|
846
1040
|
tubeLines: item.tubeLines,
|
|
847
1041
|
lod: lod,
|
|
848
|
-
renderOrder: order
|
|
1042
|
+
renderOrder: order,
|
|
849
1043
|
};
|
|
850
1044
|
|
|
851
1045
|
switch (item.Type) {
|
|
852
|
-
case
|
|
853
|
-
loadSurfaceURL(
|
|
1046
|
+
case 'Surfaces':
|
|
1047
|
+
loadSurfaceURL(
|
|
1048
|
+
region,
|
|
1049
|
+
newURL,
|
|
1050
|
+
item.MorphVertices,
|
|
1051
|
+
item.MorphColours,
|
|
1052
|
+
groupName,
|
|
1053
|
+
finishCallback,
|
|
1054
|
+
options,
|
|
1055
|
+
);
|
|
854
1056
|
break;
|
|
855
|
-
case
|
|
1057
|
+
case 'Glyph':
|
|
856
1058
|
let newGeometryURL = undefined;
|
|
857
1059
|
if (!isInline) {
|
|
858
1060
|
newGeometryURL = item.GlyphGeometriesURL;
|
|
@@ -867,13 +1069,29 @@ const SceneLoader = function (sceneIn) {
|
|
|
867
1069
|
options.loaderOptions.isGlyphsets = true;
|
|
868
1070
|
this.loadGlyphsetURL(region, newURL, newGeometryURL, groupName, finishCallback, options);
|
|
869
1071
|
break;
|
|
870
|
-
case
|
|
871
|
-
this.loadPointsetURL(
|
|
1072
|
+
case 'Points':
|
|
1073
|
+
this.loadPointsetURL(
|
|
1074
|
+
region,
|
|
1075
|
+
newURL,
|
|
1076
|
+
item.MorphVertices,
|
|
1077
|
+
item.MorphColours,
|
|
1078
|
+
groupName,
|
|
1079
|
+
finishCallback,
|
|
1080
|
+
options,
|
|
1081
|
+
);
|
|
872
1082
|
break;
|
|
873
|
-
case
|
|
874
|
-
this.loadLinesURL(
|
|
1083
|
+
case 'Lines':
|
|
1084
|
+
this.loadLinesURL(
|
|
1085
|
+
region,
|
|
1086
|
+
newURL,
|
|
1087
|
+
item.MorphVertices,
|
|
1088
|
+
item.MorphColours,
|
|
1089
|
+
groupName,
|
|
1090
|
+
finishCallback,
|
|
1091
|
+
options,
|
|
1092
|
+
);
|
|
875
1093
|
break;
|
|
876
|
-
case
|
|
1094
|
+
case 'Texture':
|
|
877
1095
|
this.loadTextureURL(region, newURL, groupName, finishCallback, options);
|
|
878
1096
|
break;
|
|
879
1097
|
default:
|
|
@@ -889,24 +1107,21 @@ const SceneLoader = function (sceneIn) {
|
|
|
889
1107
|
let isInline = false;
|
|
890
1108
|
if (item.URL) {
|
|
891
1109
|
newURL = item.URL;
|
|
892
|
-
if (referenceURL)
|
|
893
|
-
newURL = createNewURL(item.URL, referenceURL);
|
|
1110
|
+
if (referenceURL) newURL = createNewURL(item.URL, referenceURL);
|
|
894
1111
|
} else if (item.Inline) {
|
|
895
1112
|
newURL = item.Inline.URL;
|
|
896
1113
|
isInline = true;
|
|
897
1114
|
}
|
|
898
1115
|
switch (item.Type) {
|
|
899
|
-
case
|
|
1116
|
+
case 'View':
|
|
900
1117
|
if (isInline) {
|
|
901
|
-
scene.setupMultipleViews(
|
|
1118
|
+
scene.setupMultipleViews('default', { default: newURL });
|
|
902
1119
|
viewLoaded = true;
|
|
903
|
-
if (finishCallback != undefined &&
|
|
1120
|
+
if (finishCallback != undefined && typeof finishCallback == 'function')
|
|
904
1121
|
finishCallback();
|
|
905
|
-
}
|
|
906
|
-
else
|
|
907
|
-
this.loadViewURL(newURL, finishCallback);
|
|
1122
|
+
} else this.loadViewURL(newURL, finishCallback);
|
|
908
1123
|
break;
|
|
909
|
-
case
|
|
1124
|
+
case 'Settings':
|
|
910
1125
|
this.loadSettings(item);
|
|
911
1126
|
break;
|
|
912
1127
|
default:
|
|
@@ -924,16 +1139,22 @@ const SceneLoader = function (sceneIn) {
|
|
|
924
1139
|
*/
|
|
925
1140
|
this.loadGLTF = (region, url, finishCallback, allCompletedCallback, options) => {
|
|
926
1141
|
const loader = new GLTFToZincJSLoader();
|
|
927
|
-
loader.load(
|
|
928
|
-
|
|
929
|
-
|
|
1142
|
+
loader.load(
|
|
1143
|
+
scene,
|
|
1144
|
+
region,
|
|
1145
|
+
url,
|
|
1146
|
+
finishCallback,
|
|
1147
|
+
allCompletedCallback,
|
|
1148
|
+
options,
|
|
1149
|
+
createStaleCheck(),
|
|
1150
|
+
);
|
|
1151
|
+
};
|
|
930
1152
|
|
|
931
1153
|
let loadRegions = (currentRegion, referenceURL, regions, callback) => {
|
|
932
1154
|
if (regions.Primitives) {
|
|
933
|
-
regions.Primitives.forEach(primitive => {
|
|
1155
|
+
regions.Primitives.forEach((primitive) => {
|
|
934
1156
|
let order = 1;
|
|
935
|
-
if (primitive.Order)
|
|
936
|
-
order = primitive.Order;
|
|
1157
|
+
if (primitive.Order) order = primitive.Order;
|
|
937
1158
|
readPrimitivesItem(currentRegion, referenceURL, primitive, order, callback);
|
|
938
1159
|
});
|
|
939
1160
|
}
|
|
@@ -948,7 +1169,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
948
1169
|
}
|
|
949
1170
|
}
|
|
950
1171
|
}
|
|
951
|
-
}
|
|
1172
|
+
};
|
|
952
1173
|
|
|
953
1174
|
let supplementPrimitivesArray = (array, options) => {
|
|
954
1175
|
let newArray = array;
|
|
@@ -958,7 +1179,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
958
1179
|
if (include?.length || exclude?.length) {
|
|
959
1180
|
if (include) {
|
|
960
1181
|
newArray = array.filter((item) => {
|
|
961
|
-
if (item.Type ===
|
|
1182
|
+
if (item.Type === 'View') {
|
|
962
1183
|
return true;
|
|
963
1184
|
}
|
|
964
1185
|
for (let i = 0; i < include.length; i++) {
|
|
@@ -971,7 +1192,7 @@ const SceneLoader = function (sceneIn) {
|
|
|
971
1192
|
}
|
|
972
1193
|
if (exclude) {
|
|
973
1194
|
newArray = newArray.filter((item) => {
|
|
974
|
-
if (item.Type ===
|
|
1195
|
+
if (item.Type === 'View') {
|
|
975
1196
|
return true;
|
|
976
1197
|
}
|
|
977
1198
|
for (let i = 0; i < exclude.length; i++) {
|
|
@@ -985,72 +1206,81 @@ const SceneLoader = function (sceneIn) {
|
|
|
985
1206
|
}
|
|
986
1207
|
if (tubeLines) {
|
|
987
1208
|
newArray.forEach((item) => {
|
|
988
|
-
if (item.Type ===
|
|
1209
|
+
if (item.Type === 'Lines') {
|
|
989
1210
|
item.tubeLines = true;
|
|
990
1211
|
}
|
|
991
1212
|
});
|
|
992
1213
|
}
|
|
993
1214
|
return newArray;
|
|
994
|
-
}
|
|
1215
|
+
};
|
|
995
1216
|
|
|
996
1217
|
let supplementMetadataInArray = (metadata, options) => {
|
|
997
1218
|
if (Array.isArray(metadata)) {
|
|
998
1219
|
return supplementPrimitivesArray(metadata, options);
|
|
999
1220
|
}
|
|
1000
1221
|
return metadata;
|
|
1001
|
-
}
|
|
1222
|
+
};
|
|
1002
1223
|
|
|
1003
1224
|
let getNumberOfDownloadsInArray = (array, includeViews) => {
|
|
1004
1225
|
if (Array.isArray(array)) {
|
|
1005
1226
|
let count = 0;
|
|
1006
1227
|
for (let i = 0; i < array.length; i++) {
|
|
1007
|
-
if (
|
|
1008
|
-
|
|
1009
|
-
array[i].Type ===
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1228
|
+
if (
|
|
1229
|
+
array[i].Type &&
|
|
1230
|
+
((includeViews && array[i].Type === 'View') ||
|
|
1231
|
+
array[i].Type === 'Surfaces' ||
|
|
1232
|
+
array[i].Type === 'Glyph' ||
|
|
1233
|
+
array[i].Type === 'Points' ||
|
|
1234
|
+
array[i].Type === 'Lines' ||
|
|
1235
|
+
array[i].Type === 'Texture')
|
|
1236
|
+
) {
|
|
1015
1237
|
count++;
|
|
1016
1238
|
}
|
|
1017
1239
|
}
|
|
1018
1240
|
return count;
|
|
1019
1241
|
}
|
|
1020
1242
|
return 0;
|
|
1021
|
-
}
|
|
1243
|
+
};
|
|
1022
1244
|
|
|
1023
1245
|
let getNumberOfObjectsInRegions = (regionJson) => {
|
|
1024
|
-
let counts = regionJson.Primitives
|
|
1025
|
-
getNumberOfDownloadsInArray(regionJson.Primitives, false)
|
|
1246
|
+
let counts = regionJson.Primitives
|
|
1247
|
+
? getNumberOfDownloadsInArray(regionJson.Primitives, false)
|
|
1248
|
+
: 0;
|
|
1026
1249
|
if (regionJson.Children) {
|
|
1027
|
-
Object.values(regionJson.Children).forEach(childRegion => {
|
|
1250
|
+
Object.values(regionJson.Children).forEach((childRegion) => {
|
|
1028
1251
|
counts += getNumberOfObjectsInRegions(childRegion);
|
|
1029
1252
|
});
|
|
1030
1253
|
}
|
|
1031
1254
|
return counts;
|
|
1032
|
-
}
|
|
1255
|
+
};
|
|
1033
1256
|
|
|
1034
1257
|
let getNumberOfObjects = (metadata) => {
|
|
1035
1258
|
if (Array.isArray(metadata)) {
|
|
1036
1259
|
return getNumberOfDownloadsInArray(metadata, true);
|
|
1037
|
-
} else if (
|
|
1038
|
-
if (metadata.Version ===
|
|
1260
|
+
} else if (typeof metadata === 'object' && metadata !== null) {
|
|
1261
|
+
if (metadata.Version === '2.0') {
|
|
1039
1262
|
return getNumberOfObjectsInRegions(metadata.Regions);
|
|
1040
1263
|
}
|
|
1041
1264
|
}
|
|
1042
|
-
}
|
|
1265
|
+
};
|
|
1043
1266
|
|
|
1044
1267
|
let readVersionOneRegionPath = (region, referenceURL, item, order, callback) => {
|
|
1045
1268
|
let targetRegion = region;
|
|
1046
|
-
if (item.RegionPath && item.RegionPath !==
|
|
1269
|
+
if (item.RegionPath && item.RegionPath !== '') {
|
|
1047
1270
|
targetRegion = region.findOrCreateChildFromPath(item.RegionPath);
|
|
1048
1271
|
}
|
|
1049
1272
|
//Render order is set to i * 2 to account for front and back rendering
|
|
1050
1273
|
readPrimitivesItem(targetRegion, referenceURL, item, order * 2, callback);
|
|
1051
|
-
}
|
|
1274
|
+
};
|
|
1052
1275
|
|
|
1053
|
-
let loadVersionOne = (
|
|
1276
|
+
let loadVersionOne = (
|
|
1277
|
+
targetRegion,
|
|
1278
|
+
metadata,
|
|
1279
|
+
referenceURL,
|
|
1280
|
+
finishCallback,
|
|
1281
|
+
allCompletedCallback,
|
|
1282
|
+
options,
|
|
1283
|
+
) => {
|
|
1054
1284
|
const filteredMetada = supplementMetadataInArray(metadata, options);
|
|
1055
1285
|
let numberOfObjects = getNumberOfObjects(filteredMetada);
|
|
1056
1286
|
// view file does not receive callback
|
|
@@ -1061,30 +1291,33 @@ const SceneLoader = function (sceneIn) {
|
|
|
1061
1291
|
for (let i = 0; i < filteredMetada.length; i++) {
|
|
1062
1292
|
readVersionOneRegionPath(targetRegion, referenceURL, filteredMetada[i], i, callback);
|
|
1063
1293
|
}
|
|
1064
|
-
}
|
|
1294
|
+
};
|
|
1065
1295
|
|
|
1066
|
-
let loadVersionTwo = (
|
|
1296
|
+
let loadVersionTwo = (
|
|
1297
|
+
targetRegion,
|
|
1298
|
+
metadata,
|
|
1299
|
+
referenceURL,
|
|
1300
|
+
finishCallback,
|
|
1301
|
+
allCompletedCallback,
|
|
1302
|
+
) => {
|
|
1067
1303
|
let numberOfObjects = getNumberOfObjects(metadata);
|
|
1068
1304
|
// view file does not receive callback
|
|
1069
1305
|
let callback = new metaFinishCallback(numberOfObjects, finishCallback, allCompletedCallback);
|
|
1070
|
-
if (metadata.Settings)
|
|
1071
|
-
|
|
1072
|
-
if (metadata.
|
|
1073
|
-
|
|
1074
|
-
if (metadata.Regions)
|
|
1075
|
-
loadRegions(targetRegion, referenceURL, metadata.Regions, callback);
|
|
1076
|
-
}
|
|
1306
|
+
if (metadata.Settings) this.loadSettings(metadata.Settings);
|
|
1307
|
+
if (metadata.Views) loadMultipleViews(referenceURL, metadata.Views, referenceURL);
|
|
1308
|
+
if (metadata.Regions) loadRegions(targetRegion, referenceURL, metadata.Regions, callback);
|
|
1309
|
+
};
|
|
1077
1310
|
|
|
1078
1311
|
/**
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1312
|
+
* Load a metadata file from the provided URL into this scene. Once
|
|
1313
|
+
* succssful scene proceeds to read each items into scene for visualisations.
|
|
1314
|
+
*
|
|
1315
|
+
* @param {String} url - Location of the metadata file
|
|
1316
|
+
* @param {Function} finishCallback - Callback function which will be called
|
|
1317
|
+
* @param {options} Optional settings, it can be used to ignore some regions/groups
|
|
1318
|
+
* in the metadata file. Only supports version 1 at this moment.
|
|
1319
|
+
* for each glyphset and geometry that has been written in.
|
|
1320
|
+
*/
|
|
1088
1321
|
this.loadMetadataURL = (targetRegion, url, finishCallback, allCompletedCallback, options) => {
|
|
1089
1322
|
const requestURL = url;
|
|
1090
1323
|
const isStale = createStaleCheck();
|
|
@@ -1093,26 +1326,39 @@ const SceneLoader = function (sceneIn) {
|
|
|
1093
1326
|
if (!response.ok) {
|
|
1094
1327
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
1095
1328
|
}
|
|
1096
|
-
const referenceURL = response.url ||
|
|
1329
|
+
const referenceURL = response.url || new URL(requestURL).href;
|
|
1097
1330
|
return response.json().then((metadata) => ({ metadata, referenceURL }));
|
|
1098
1331
|
})
|
|
1099
|
-
.then(({metadata, referenceURL}) => {
|
|
1332
|
+
.then(({ metadata, referenceURL }) => {
|
|
1100
1333
|
if (isStale()) return;
|
|
1101
1334
|
scene.resetMetadata();
|
|
1102
1335
|
scene.resetDuration();
|
|
1103
1336
|
viewLoaded = false;
|
|
1104
1337
|
if (Array.isArray(metadata)) {
|
|
1105
|
-
loadVersionOne(
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1338
|
+
loadVersionOne(
|
|
1339
|
+
targetRegion,
|
|
1340
|
+
metadata,
|
|
1341
|
+
referenceURL,
|
|
1342
|
+
finishCallback,
|
|
1343
|
+
allCompletedCallback,
|
|
1344
|
+
options,
|
|
1345
|
+
);
|
|
1346
|
+
} else if (typeof metadata === 'object' && metadata !== null) {
|
|
1347
|
+
if (metadata.Version === '2.0') {
|
|
1348
|
+
loadVersionTwo(
|
|
1349
|
+
targetRegion,
|
|
1350
|
+
metadata,
|
|
1351
|
+
referenceURL,
|
|
1352
|
+
finishCallback,
|
|
1353
|
+
allCompletedCallback,
|
|
1354
|
+
);
|
|
1109
1355
|
}
|
|
1110
1356
|
}
|
|
1111
1357
|
})
|
|
1112
1358
|
.catch((error) => {
|
|
1113
1359
|
console.error(`Fetch failed for URL: ${requestURL}`, error);
|
|
1114
1360
|
});
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1361
|
+
};
|
|
1362
|
+
};
|
|
1117
1363
|
|
|
1118
1364
|
export { SceneLoader };
|