@mcolabs/threebox-plugin 4.0.0

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.
@@ -0,0 +1,3521 @@
1
+ import * as THREE from "three";
2
+ import { OBJLoader } from "three/addons/loaders/OBJLoader.js";
3
+ import { MTLLoader } from "three/addons/loaders/MTLLoader.js";
4
+ import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
5
+ import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
6
+ import { ColladaLoader } from "three/addons/loaders/ColladaLoader.js";
7
+ import { Line2 } from "three/addons/lines/Line2.js";
8
+ import { LineMaterial } from "three/addons/lines/LineMaterial.js";
9
+ import { LineGeometry } from "three/addons/lines/LineGeometry.js";
10
+ const WORLD_SIZE = 1024e3;
11
+ const FOV_ORTHO = 0.1 / 180 * Math.PI;
12
+ const FOV = Math.atan(3 / 4);
13
+ const EARTH_RADIUS = 63710088e-1;
14
+ const EARTH_CIRCUMFERENCE_EQUATOR = 40075017;
15
+ const ThreeboxConstants = {
16
+ WORLD_SIZE,
17
+ PROJECTION_WORLD_SIZE: WORLD_SIZE / (EARTH_RADIUS * Math.PI * 2),
18
+ MERCATOR_A: EARTH_RADIUS,
19
+ DEG2RAD: Math.PI / 180,
20
+ RAD2DEG: 180 / Math.PI,
21
+ EARTH_RADIUS,
22
+ EARTH_CIRCUMFERENCE: 2 * Math.PI * EARTH_RADIUS,
23
+ //40075000, // In meters
24
+ EARTH_CIRCUMFERENCE_EQUATOR,
25
+ FOV_ORTHO,
26
+ // closest to 0
27
+ FOV,
28
+ // Math.atan(3/4) radians. If this value is changed, FOV_DEGREES must be calculated
29
+ FOV_DEGREES: FOV * 180 / Math.PI,
30
+ // Math.atan(3/4) in degrees
31
+ TILE_SIZE: 512
32
+ };
33
+ function Validate() {
34
+ }
35
+ Validate.prototype = {
36
+ Coords: function(input) {
37
+ if (input.constructor !== Array) {
38
+ console.error("Coords must be an array");
39
+ return;
40
+ }
41
+ if (input.length < 2) {
42
+ console.error("Coords length must be at least 2");
43
+ return;
44
+ }
45
+ for (const member of input) {
46
+ if (member.constructor !== Number) {
47
+ console.error("Coords values must be numbers");
48
+ return;
49
+ }
50
+ }
51
+ if (Math.abs(input[1]) > 90) {
52
+ console.error("Latitude must be between -90 and 90");
53
+ return;
54
+ }
55
+ return input;
56
+ },
57
+ Line: function(input) {
58
+ var scope = this;
59
+ if (input.constructor !== Array) {
60
+ console.error("Line must be an array");
61
+ return;
62
+ }
63
+ for (const coord of input) {
64
+ if (!scope.Coords(coord)) {
65
+ console.error("Each coordinate in a line must be a valid Coords type");
66
+ return;
67
+ }
68
+ }
69
+ return input;
70
+ },
71
+ Rotation: function(input) {
72
+ if (input.constructor === Number) input = { z: input };
73
+ else if (input.constructor === Object) {
74
+ for (const key of Object.keys(input)) {
75
+ if (!["x", "y", "z"].includes(key)) {
76
+ console.error("Rotation parameters must be x, y, or z");
77
+ return;
78
+ }
79
+ if (input[key].constructor !== Number) {
80
+ console.error("Individual rotation values must be numbers");
81
+ return;
82
+ }
83
+ }
84
+ } else {
85
+ console.error("Rotation must be an object or a number");
86
+ return;
87
+ }
88
+ return input;
89
+ },
90
+ Scale: function(input) {
91
+ if (input.constructor === Number) {
92
+ input = { x: input, y: input, z: input };
93
+ } else if (input.constructor === Object) {
94
+ for (const key of Object.keys(input)) {
95
+ if (!["x", "y", "z"].includes(key)) {
96
+ console.error("Scale parameters must be x, y, or z");
97
+ return;
98
+ }
99
+ if (input[key].constructor !== Number) {
100
+ console.error("Individual scale values must be numbers");
101
+ return;
102
+ }
103
+ }
104
+ } else {
105
+ console.error("Scale must be an object or a number");
106
+ return;
107
+ }
108
+ return input;
109
+ }
110
+ };
111
+ var utils = {
112
+ prettyPrintMatrix: function(uglymatrix) {
113
+ for (var s = 0; s < 4; s++) {
114
+ var quartet = [
115
+ uglymatrix[s],
116
+ uglymatrix[s + 4],
117
+ uglymatrix[s + 8],
118
+ uglymatrix[s + 12]
119
+ ];
120
+ console.log(quartet.map(function(num) {
121
+ return num.toFixed(4);
122
+ }));
123
+ }
124
+ },
125
+ makePerspectiveMatrix: function(fovy, aspect, near, far) {
126
+ var out = new THREE.Matrix4();
127
+ var f = 1 / Math.tan(fovy / 2), nf = 1 / (near - far);
128
+ var newMatrix = [
129
+ f / aspect,
130
+ 0,
131
+ 0,
132
+ 0,
133
+ 0,
134
+ f,
135
+ 0,
136
+ 0,
137
+ 0,
138
+ 0,
139
+ (far + near) * nf,
140
+ -1,
141
+ 0,
142
+ 0,
143
+ 2 * far * near * nf,
144
+ 0
145
+ ];
146
+ out.elements = newMatrix;
147
+ return out;
148
+ },
149
+ //[jscastro] new orthographic matrix calculations https://en.wikipedia.org/wiki/Orthographic_projection and validated with https://bit.ly/3rPvB9Y
150
+ makeOrthographicMatrix: function(left, right, top, bottom, near, far) {
151
+ var out = new THREE.Matrix4();
152
+ const w = 1 / (right - left);
153
+ const h = 1 / (top - bottom);
154
+ const p = 1 / (far - near);
155
+ const x = (right + left) * w;
156
+ const y = (top + bottom) * h;
157
+ const z = near * p;
158
+ var newMatrix = [
159
+ 2 * w,
160
+ 0,
161
+ 0,
162
+ 0,
163
+ 0,
164
+ 2 * h,
165
+ 0,
166
+ 0,
167
+ 0,
168
+ 0,
169
+ -1 * p,
170
+ 0,
171
+ -x,
172
+ -y,
173
+ -z,
174
+ 1
175
+ ];
176
+ out.elements = newMatrix;
177
+ return out;
178
+ },
179
+ //gimme radians
180
+ radify: function(deg) {
181
+ function convert(degrees) {
182
+ degrees = degrees || 0;
183
+ return Math.PI * 2 * degrees / 360;
184
+ }
185
+ if (typeof deg === "object") {
186
+ if (deg.length > 0) {
187
+ return deg.map(function(degree) {
188
+ return convert(degree);
189
+ });
190
+ } else {
191
+ return [convert(deg.x), convert(deg.y), convert(deg.z)];
192
+ }
193
+ } else return convert(deg);
194
+ },
195
+ //gimme degrees
196
+ degreeify: function(rad2) {
197
+ function convert(radians) {
198
+ radians = radians || 0;
199
+ return radians * 360 / (Math.PI * 2);
200
+ }
201
+ if (typeof rad2 === "object") {
202
+ return [convert(rad2.x), convert(rad2.y), convert(rad2.z)];
203
+ } else return convert(rad2);
204
+ },
205
+ projectToWorld: function(coords) {
206
+ var projected = [
207
+ -ThreeboxConstants.MERCATOR_A * ThreeboxConstants.DEG2RAD * coords[0] * ThreeboxConstants.PROJECTION_WORLD_SIZE,
208
+ -ThreeboxConstants.MERCATOR_A * Math.log(Math.tan(Math.PI * 0.25 + 0.5 * ThreeboxConstants.DEG2RAD * coords[1])) * ThreeboxConstants.PROJECTION_WORLD_SIZE
209
+ ];
210
+ if (!coords[2]) projected.push(0);
211
+ else {
212
+ var pixelsPerMeter = this.projectedUnitsPerMeter(coords[1]);
213
+ projected.push(coords[2] * pixelsPerMeter);
214
+ }
215
+ var result = new THREE.Vector3(projected[0], projected[1], projected[2]);
216
+ return result;
217
+ },
218
+ projectedUnitsPerMeter: function(latitude) {
219
+ return Math.abs(ThreeboxConstants.WORLD_SIZE / Math.cos(ThreeboxConstants.DEG2RAD * latitude) / ThreeboxConstants.EARTH_CIRCUMFERENCE);
220
+ },
221
+ _circumferenceAtLatitude: function(latitude) {
222
+ return ThreeboxConstants.EARTH_CIRCUMFERENCE * Math.cos(latitude * Math.PI / 180);
223
+ },
224
+ mercatorZfromAltitude: function(altitude2, lat) {
225
+ return altitude2 / this._circumferenceAtLatitude(lat);
226
+ },
227
+ _scaleVerticesToMeters: function(centerLatLng, vertices) {
228
+ var pixelsPerMeter = this.projectedUnitsPerMeter(centerLatLng[1]);
229
+ this.projectToWorld(centerLatLng);
230
+ for (var i = 0; i < vertices.length; i++) {
231
+ vertices[i].multiplyScalar(pixelsPerMeter);
232
+ }
233
+ return vertices;
234
+ },
235
+ projectToScreen: function(coords) {
236
+ console.log("WARNING: Projecting to screen coordinates is not yet implemented");
237
+ },
238
+ unprojectFromScreen: function(pixel) {
239
+ console.log("WARNING: unproject is not yet implemented");
240
+ },
241
+ //world units to lnglat
242
+ unprojectFromWorld: function(worldUnits) {
243
+ var unprojected = [
244
+ -worldUnits.x / (ThreeboxConstants.MERCATOR_A * ThreeboxConstants.DEG2RAD * ThreeboxConstants.PROJECTION_WORLD_SIZE),
245
+ 2 * (Math.atan(Math.exp(worldUnits.y / (ThreeboxConstants.PROJECTION_WORLD_SIZE * -ThreeboxConstants.MERCATOR_A))) - Math.PI / 4) / ThreeboxConstants.DEG2RAD
246
+ ];
247
+ var pixelsPerMeter = this.projectedUnitsPerMeter(unprojected[1]);
248
+ var height = worldUnits.z || 0;
249
+ unprojected.push(height / pixelsPerMeter);
250
+ return unprojected;
251
+ },
252
+ toScreenPosition: function(obj, camera) {
253
+ var vector = new THREE.Vector3();
254
+ var widthHalf = 0.5 * renderer.context.canvas.width;
255
+ var heightHalf = 0.5 * renderer.context.canvas.height;
256
+ obj.updateMatrixWorld();
257
+ vector.setFromMatrixPosition(obj.matrixWorld);
258
+ vector.project(camera);
259
+ vector.x = vector.x * widthHalf + widthHalf;
260
+ vector.y = -(vector.y * heightHalf) + heightHalf;
261
+ return {
262
+ x: vector.x,
263
+ y: vector.y
264
+ };
265
+ },
266
+ //get the center point of a feature
267
+ getFeatureCenter: function getFeatureCenter(feature, model, level) {
268
+ let center = [];
269
+ let latitude = 0;
270
+ let longitude = 0;
271
+ let height = 0;
272
+ let coordinates = [...feature.geometry.coordinates[0]];
273
+ if (feature.geometry.type === "Point") {
274
+ center = [...coordinates[0]];
275
+ } else {
276
+ if (feature.geometry.type === "MultiPolygon") coordinates = coordinates[0];
277
+ coordinates.splice(-1, 1);
278
+ coordinates.forEach(function(c) {
279
+ latitude += c[0];
280
+ longitude += c[1];
281
+ });
282
+ center = [latitude / coordinates.length, longitude / coordinates.length];
283
+ }
284
+ height = this.getObjectHeightOnFloor(feature, model, level);
285
+ center.length < 3 ? center.push(height) : center[2] = height;
286
+ return center;
287
+ },
288
+ getObjectHeightOnFloor: function(feature, obj, level = feature.properties.level || 0) {
289
+ let floorHeightMin = level * (feature.properties.levelHeight || 0);
290
+ let base = feature.properties.base_height || feature.properties.min_height || 0;
291
+ let height = obj && obj.model ? 0 : feature.properties.height - base;
292
+ let objectHeight = height + base;
293
+ let modelHeightFloor = floorHeightMin + objectHeight;
294
+ return modelHeightFloor;
295
+ },
296
+ _flipMaterialSides: function(obj) {
297
+ },
298
+ // to improve precision, normalize a series of vector3's to their collective center, and move the resultant mesh to that center
299
+ normalizeVertices(vertices) {
300
+ let geometry = new THREE.BufferGeometry();
301
+ let positions = [];
302
+ for (var j = 0; j < vertices.length; j++) {
303
+ let p = vertices[j];
304
+ positions.push(p.x, p.y, p.z);
305
+ positions.push(p.x, p.y, p.z);
306
+ }
307
+ geometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(positions), 3));
308
+ geometry.computeBoundingSphere();
309
+ var center = geometry.boundingSphere.center;
310
+ var scaled = vertices.map(function(v3) {
311
+ var normalized = v3.sub(center);
312
+ return normalized;
313
+ });
314
+ return { vertices: scaled, position: center };
315
+ },
316
+ //flatten an array of Vector3's into a shallow array of values in x-y-z order, for bufferGeometry
317
+ flattenVectors(vectors) {
318
+ var flattenedArray = [];
319
+ for (let vertex of vectors) {
320
+ flattenedArray.push(vertex.x, vertex.y, vertex.z);
321
+ }
322
+ return flattenedArray;
323
+ },
324
+ //convert a line/polygon to Vector3's
325
+ lnglatsToWorld: function(coords) {
326
+ var vector3 = coords.map(
327
+ function(pt) {
328
+ var p = utils.projectToWorld(pt);
329
+ var v3 = new THREE.Vector3(p.x, p.y, p.z);
330
+ return v3;
331
+ }
332
+ );
333
+ return vector3;
334
+ },
335
+ extend: function(original, addition) {
336
+ for (let key in addition) original[key] = addition[key];
337
+ },
338
+ clone: function(original) {
339
+ var clone = {};
340
+ for (let key in original) clone[key] = original[key];
341
+ return clone;
342
+ },
343
+ clamp: function(n, min, max) {
344
+ return Math.min(max, Math.max(min, n));
345
+ },
346
+ // retrieve object parameters from an options object
347
+ types: {
348
+ rotation: function(r, currentRotation) {
349
+ if (!r) {
350
+ r = 0;
351
+ }
352
+ if (typeof r === "number") r = { z: r };
353
+ var degrees = this.applyDefault([r.x, r.y, r.z], currentRotation);
354
+ var radians = utils.radify(degrees);
355
+ return radians;
356
+ },
357
+ scale: function(s, currentScale) {
358
+ if (!s) {
359
+ s = 1;
360
+ }
361
+ if (typeof s === "number") return s = [s, s, s];
362
+ else return this.applyDefault([s.x, s.y, s.z], currentScale);
363
+ },
364
+ applyDefault: function(array, current) {
365
+ var output = array.map(function(item, index) {
366
+ item = item || current[index];
367
+ return item;
368
+ });
369
+ return output;
370
+ }
371
+ },
372
+ toDecimal: function(n, d) {
373
+ return Number(n.toFixed(d));
374
+ },
375
+ equal: function(obj1, obj2) {
376
+ const keys1 = Object.keys(obj1);
377
+ const keys2 = Object.keys(obj2);
378
+ if (keys1.length !== keys2.length) {
379
+ return false;
380
+ }
381
+ if (keys1.length == 0 && keys2.length == 0 && keys1 !== keys2) {
382
+ return false;
383
+ }
384
+ for (const key of keys1) {
385
+ const val1 = obj1[key];
386
+ const val2 = obj2[key];
387
+ const areObjects = this.isObject(val1) && this.isObject(val2);
388
+ if (areObjects && !equal(val1, val2) || !areObjects && val1 !== val2) {
389
+ return false;
390
+ }
391
+ }
392
+ return true;
393
+ },
394
+ isObject: function(object) {
395
+ return object != null && typeof object === "object";
396
+ },
397
+ curveToLine: (curve, params) => {
398
+ let { width, color } = params;
399
+ let geometry = new THREE.BufferGeometry().setFromPoints(
400
+ curve.getPoints(100)
401
+ );
402
+ let material2 = new THREE.LineBasicMaterial({
403
+ color,
404
+ linewidth: width
405
+ });
406
+ let line2 = new THREE.Line(geometry, material2);
407
+ return line2;
408
+ },
409
+ curvesToLines: (curves) => {
410
+ var colors = [16711680, 2031360, 2490623];
411
+ var lines = curves.map((curve, i) => {
412
+ let params = {
413
+ width: 3,
414
+ color: colors[i] || "purple"
415
+ };
416
+ let curveline = curveToLine(curve, params);
417
+ return curveline;
418
+ });
419
+ return lines;
420
+ },
421
+ _validate: function(userInputs, defaults2) {
422
+ userInputs = userInputs || {};
423
+ var validatedOutput = {};
424
+ utils.extend(validatedOutput, userInputs);
425
+ for (let key of Object.keys(defaults2)) {
426
+ if (userInputs[key] === void 0) {
427
+ if (defaults2[key] === null) {
428
+ console.error(key + " is required");
429
+ return;
430
+ } else validatedOutput[key] = defaults2[key];
431
+ } else validatedOutput[key] = userInputs[key];
432
+ }
433
+ return validatedOutput;
434
+ },
435
+ Validator: new Validate(),
436
+ exposedMethods: ["projectToWorld", "projectedUnitsPerMeter", "extend", "unprojectFromWorld"]
437
+ };
438
+ function CameraSync(map, camera, world) {
439
+ this.map = map;
440
+ this.camera = camera;
441
+ this.active = true;
442
+ this.camera.matrixAutoUpdate = false;
443
+ this.world = world || new THREE.Group();
444
+ this.world.position.x = this.world.position.y = ThreeboxConstants.WORLD_SIZE / 2;
445
+ this.world.matrixAutoUpdate = false;
446
+ this.state = {
447
+ translateCenter: new THREE.Matrix4().makeTranslation(ThreeboxConstants.WORLD_SIZE / 2, -ThreeboxConstants.WORLD_SIZE / 2, 0),
448
+ worldSizeRatio: ThreeboxConstants.TILE_SIZE / ThreeboxConstants.WORLD_SIZE,
449
+ worldSize: ThreeboxConstants.TILE_SIZE * this.map.transform.scale
450
+ };
451
+ let _this = this;
452
+ this.map.on("move", function() {
453
+ _this.updateCamera();
454
+ }).on("resize", function() {
455
+ _this.setupCamera();
456
+ });
457
+ this.setupCamera();
458
+ }
459
+ CameraSync.prototype = {
460
+ setupCamera: function() {
461
+ const t = this.map.transform;
462
+ this.camera.aspect = t.width / t.height;
463
+ this.halfFov = t._fov / 2;
464
+ this.cameraToCenterDistance = 0.5 / Math.tan(this.halfFov) * t.height;
465
+ const maxPitch = t._maxPitch * Math.PI / 180;
466
+ this.acuteAngle = Math.PI / 2 - maxPitch;
467
+ this.updateCamera();
468
+ },
469
+ updateCamera: function(ev) {
470
+ if (!this.camera) {
471
+ console.log("nocamera");
472
+ return;
473
+ }
474
+ const t = this.map.transform;
475
+ this.camera.aspect = t.width / t.height;
476
+ const offset = t.centerOffset || new THREE.Vector3();
477
+ let farZ = 0;
478
+ let furthestDistance = 0;
479
+ this.halfFov = t._fov / 2;
480
+ const groundAngle = Math.PI / 2 + t._pitch;
481
+ const pitchAngle = Math.cos(Math.PI / 2 - t._pitch);
482
+ this.cameraToCenterDistance = 0.5 / Math.tan(this.halfFov) * t.height;
483
+ let pixelsPerMeter = 1;
484
+ const worldSize = this.worldSize();
485
+ if (this.map.tb.mapboxVersion >= 2) {
486
+ pixelsPerMeter = this.mercatorZfromAltitude(1, t.center.lat) * worldSize;
487
+ const fovAboveCenter = t._fov * (0.5 + t.centerOffset.y / t.height);
488
+ const minElevationInPixels = t.elevation ? t.elevation.getMinElevationBelowMSL() * pixelsPerMeter : 0;
489
+ const cameraToSeaLevelDistance = (t._camera.position[2] * worldSize - minElevationInPixels) / Math.cos(t._pitch);
490
+ const topHalfSurfaceDistance = Math.sin(fovAboveCenter) * cameraToSeaLevelDistance / Math.sin(utils.clamp(Math.PI - groundAngle - fovAboveCenter, 0.01, Math.PI - 0.01));
491
+ furthestDistance = pitchAngle * topHalfSurfaceDistance + cameraToSeaLevelDistance;
492
+ const horizonDistance = cameraToSeaLevelDistance * (1 / t._horizonShift);
493
+ farZ = Math.min(furthestDistance * 1.01, horizonDistance);
494
+ } else {
495
+ const topHalfSurfaceDistance = Math.sin(this.halfFov) * this.cameraToCenterDistance / Math.sin(Math.PI - groundAngle - this.halfFov);
496
+ furthestDistance = pitchAngle * topHalfSurfaceDistance + this.cameraToCenterDistance;
497
+ farZ = furthestDistance * 1.01;
498
+ }
499
+ this.cameraTranslateZ = new THREE.Matrix4().makeTranslation(0, 0, this.cameraToCenterDistance);
500
+ const nz = t.height / 50;
501
+ const nearZ = Math.max(nz * pitchAngle, nz);
502
+ const h = t.height;
503
+ const w = t.width;
504
+ if (this.camera instanceof THREE.OrthographicCamera) {
505
+ this.camera.projectionMatrix = utils.makeOrthographicMatrix(w / -2, w / 2, h / 2, h / -2, nearZ, farZ);
506
+ } else {
507
+ this.camera.projectionMatrix = utils.makePerspectiveMatrix(t._fov, w / h, nearZ, farZ);
508
+ }
509
+ this.camera.projectionMatrix.elements[8] = -offset.x * 2 / t.width;
510
+ this.camera.projectionMatrix.elements[9] = offset.y * 2 / t.height;
511
+ let cameraWorldMatrix = this.calcCameraMatrix(t._pitch, t.angle);
512
+ if (t.elevation) cameraWorldMatrix.elements[14] = t._camera.position[2] * worldSize;
513
+ this.camera.matrixWorld.copy(cameraWorldMatrix);
514
+ let zoomPow = t.scale * this.state.worldSizeRatio;
515
+ let scale = new THREE.Matrix4();
516
+ let translateMap = new THREE.Matrix4();
517
+ let rotateMap = new THREE.Matrix4();
518
+ scale.makeScale(zoomPow, zoomPow, zoomPow);
519
+ let x = t.x || t.point.x;
520
+ let y = t.y || t.point.y;
521
+ translateMap.makeTranslation(-x, y, 0);
522
+ rotateMap.makeRotationZ(Math.PI);
523
+ this.world.matrix = new THREE.Matrix4().premultiply(rotateMap).premultiply(this.state.translateCenter).premultiply(scale).premultiply(translateMap);
524
+ this.map.fire("CameraSynced", { detail: { nearZ, farZ, pitch: t._pitch, angle: t.angle, furthestDistance, cameraToCenterDistance: this.cameraToCenterDistance, t: this.map.transform, tbProjMatrix: this.camera.projectionMatrix.elements, tbWorldMatrix: this.world.matrix.elements, cameraSyn: CameraSync } });
525
+ },
526
+ worldSize() {
527
+ let t = this.map.transform;
528
+ return t.tileSize * t.scale;
529
+ },
530
+ worldSizeFromZoom() {
531
+ let t = this.map.transform;
532
+ return Math.pow(2, t.zoom) * t.tileSize;
533
+ },
534
+ mercatorZfromAltitude(altitude2, lat) {
535
+ return altitude2 / this.circumferenceAtLatitude(lat);
536
+ },
537
+ mercatorZfromZoom() {
538
+ return this.cameraToCenterDistance / this.worldSizeFromZoom();
539
+ },
540
+ circumferenceAtLatitude(latitude) {
541
+ return ThreeboxConstants.EARTH_CIRCUMFERENCE * Math.cos(latitude * Math.PI / 180);
542
+ },
543
+ calcCameraMatrix(pitch, angle, trz) {
544
+ const t = this.map.transform;
545
+ const _pitch = pitch === void 0 ? t._pitch : pitch;
546
+ const _angle = angle === void 0 ? t.angle : angle;
547
+ const _trz = trz === void 0 ? this.cameraTranslateZ : trz;
548
+ return new THREE.Matrix4().premultiply(_trz).premultiply(new THREE.Matrix4().makeRotationX(_pitch)).premultiply(new THREE.Matrix4().makeRotationZ(_angle));
549
+ },
550
+ updateCameraState() {
551
+ let t = this.map.transform;
552
+ if (!t.height) return;
553
+ const dir = t._camera.forward();
554
+ const distance = t.cameraToCenterDistance;
555
+ const center = t.point;
556
+ t._cameraZoom ? t._cameraZoom : t._zoom;
557
+ const altitude2 = this.mercatorZfromZoom(t);
558
+ const height = altitude2 - this.mercatorZfromAltitude(t._centerAltitude, t.center.lat);
559
+ const updatedWorldSize = t.cameraToCenterDistance / height;
560
+ return [
561
+ center.x / this.worldSize() - dir[0] * distance / updatedWorldSize,
562
+ center.y / this.worldSize() - dir[1] * distance / updatedWorldSize,
563
+ this.mercatorZfromAltitude(t._centerAltitude, t._center.lat) + -dir[2] * distance / updatedWorldSize
564
+ ];
565
+ },
566
+ getWorldToCamera(worldSize, pixelsPerMeter) {
567
+ let t = this.map.transform;
568
+ const matrix = new THREE.Matrix4();
569
+ const matrixT = new THREE.Matrix4();
570
+ const o2 = t._camera._orientation;
571
+ const p = t._camera.position;
572
+ const invPosition = new THREE.Vector3(p[0], p[1], p[2]);
573
+ const quat = new THREE.Quaternion();
574
+ quat.set(o2[0], o2[1], o2[2], o2[3]);
575
+ const invOrientation = quat.conjugate();
576
+ invPosition.multiplyScalar(-worldSize);
577
+ matrixT.makeTranslation(invPosition.x, invPosition.y, invPosition.z);
578
+ matrix.makeRotationFromQuaternion(invOrientation).premultiply(matrixT);
579
+ matrix.elements[1] *= -1;
580
+ matrix.elements[5] *= -1;
581
+ matrix.elements[9] *= -1;
582
+ matrix.elements[13] *= -1;
583
+ matrix.elements[8] *= pixelsPerMeter;
584
+ matrix.elements[9] *= pixelsPerMeter;
585
+ matrix.elements[10] *= pixelsPerMeter;
586
+ matrix.elements[11] *= pixelsPerMeter;
587
+ return matrix;
588
+ },
589
+ translate(out, a, v) {
590
+ let x = v[0] || v.x, y = v[1] || v.y, z = v[2] || v.z;
591
+ let a00, a01, a02, a03;
592
+ let a10, a11, a12, a13;
593
+ let a20, a21, a22, a23;
594
+ if (a === out) {
595
+ out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
596
+ out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
597
+ out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
598
+ out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
599
+ } else {
600
+ a00 = a[0];
601
+ a01 = a[1];
602
+ a02 = a[2];
603
+ a03 = a[3];
604
+ a10 = a[4];
605
+ a11 = a[5];
606
+ a12 = a[6];
607
+ a13 = a[7];
608
+ a20 = a[8];
609
+ a21 = a[9];
610
+ a22 = a[10];
611
+ a23 = a[11];
612
+ out[0] = a00;
613
+ out[1] = a01;
614
+ out[2] = a02;
615
+ out[3] = a03;
616
+ out[4] = a10;
617
+ out[5] = a11;
618
+ out[6] = a12;
619
+ out[7] = a13;
620
+ out[8] = a20;
621
+ out[9] = a21;
622
+ out[10] = a22;
623
+ out[11] = a23;
624
+ out[12] = a00 * x + a10 * y + a20 * z + a[12];
625
+ out[13] = a01 * x + a11 * y + a21 * z + a[13];
626
+ out[14] = a02 * x + a12 * y + a22 * z + a[14];
627
+ out[15] = a03 * x + a13 * y + a23 * z + a[15];
628
+ }
629
+ return out;
630
+ }
631
+ };
632
+ var PI = Math.PI, sin = Math.sin, cos = Math.cos, tan = Math.tan, asin = Math.asin, atan = Math.atan2, acos = Math.acos, rad = PI / 180;
633
+ var dayMs = 1e3 * 60 * 60 * 24, J1970 = 2440588, J2000 = 2451545;
634
+ function toJulian(date) {
635
+ return date.valueOf() / dayMs - 0.5 + J1970;
636
+ }
637
+ function fromJulian(j) {
638
+ return new Date((j + 0.5 - J1970) * dayMs);
639
+ }
640
+ function toDays(date) {
641
+ return toJulian(date) - J2000;
642
+ }
643
+ var e = rad * 23.4397;
644
+ function rightAscension(l, b) {
645
+ return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l));
646
+ }
647
+ function declination(l, b) {
648
+ return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l));
649
+ }
650
+ function azimuth(H, phi, dec) {
651
+ return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi));
652
+ }
653
+ function altitude(H, phi, dec) {
654
+ return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H));
655
+ }
656
+ function siderealTime(d, lw) {
657
+ return rad * (280.16 + 360.9856235 * d) - lw;
658
+ }
659
+ function astroRefraction(h) {
660
+ if (h < 0)
661
+ h = 0;
662
+ return 2967e-7 / Math.tan(h + 312536e-8 / (h + 0.08901179));
663
+ }
664
+ function solarMeanAnomaly(d) {
665
+ return rad * (357.5291 + 0.98560028 * d);
666
+ }
667
+ function eclipticLongitude(M) {
668
+ var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 3e-4 * sin(3 * M)), P = rad * 102.9372;
669
+ return M + C + P + PI;
670
+ }
671
+ function sunCoords(d) {
672
+ var M = solarMeanAnomaly(d), L = eclipticLongitude(M);
673
+ return {
674
+ dec: declination(L, 0),
675
+ ra: rightAscension(L, 0)
676
+ };
677
+ }
678
+ var SunCalc = {};
679
+ SunCalc.getPosition = function(date, lat, lng) {
680
+ var lw = rad * -lng, phi = rad * lat, d = toDays(date), c = sunCoords(d), H = siderealTime(d, lw) - c.ra;
681
+ return {
682
+ azimuth: azimuth(H, phi, c.dec),
683
+ altitude: altitude(H, phi, c.dec)
684
+ };
685
+ };
686
+ SunCalc.toJulian = function(date) {
687
+ return toJulian(date);
688
+ };
689
+ var times = SunCalc.times = [
690
+ [-0.833, "sunrise", "sunset"],
691
+ [-0.3, "sunriseEnd", "sunsetStart"],
692
+ [-6, "dawn", "dusk"],
693
+ [-12, "nauticalDawn", "nauticalDusk"],
694
+ [-18, "nightEnd", "night"],
695
+ [6, "goldenHourEnd", "goldenHour"]
696
+ ];
697
+ SunCalc.addTime = function(angle, riseName, setName) {
698
+ times.push([angle, riseName, setName]);
699
+ };
700
+ var J0 = 9e-4;
701
+ function julianCycle(d, lw) {
702
+ return Math.round(d - J0 - lw / (2 * PI));
703
+ }
704
+ function approxTransit(Ht, lw, n) {
705
+ return J0 + (Ht + lw) / (2 * PI) + n;
706
+ }
707
+ function solarTransitJ(ds, M, L) {
708
+ return J2000 + ds + 53e-4 * sin(M) - 69e-4 * sin(2 * L);
709
+ }
710
+ function hourAngle(h, phi, d) {
711
+ return acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d)));
712
+ }
713
+ function observerAngle(height) {
714
+ return -2.076 * Math.sqrt(height) / 60;
715
+ }
716
+ function getSetJ(h, lw, phi, dec, n, M, L) {
717
+ var w = hourAngle(h, phi, dec), a = approxTransit(w, lw, n);
718
+ return solarTransitJ(a, M, L);
719
+ }
720
+ SunCalc.getTimes = function(date, lat, lng, height) {
721
+ height = height || 0;
722
+ var lw = rad * -lng, phi = rad * lat, dh = observerAngle(height), d = toDays(date), n = julianCycle(d, lw), ds = approxTransit(0, lw, n), M = solarMeanAnomaly(ds), L = eclipticLongitude(M), dec = declination(L, 0), Jnoon = solarTransitJ(ds, M, L), i, len, time, h0, Jset, Jrise;
723
+ var result = {
724
+ solarNoon: fromJulian(Jnoon),
725
+ nadir: fromJulian(Jnoon - 0.5)
726
+ };
727
+ for (i = 0, len = times.length; i < len; i += 1) {
728
+ time = times[i];
729
+ h0 = (time[0] + dh) * rad;
730
+ Jset = getSetJ(h0, lw, phi, dec, n, M, L);
731
+ Jrise = Jnoon - (Jset - Jnoon);
732
+ result[time[1]] = fromJulian(Jrise);
733
+ result[time[2]] = fromJulian(Jset);
734
+ }
735
+ return result;
736
+ };
737
+ function moonCoords(d) {
738
+ var L = rad * (218.316 + 13.176396 * d), M = rad * (134.963 + 13.064993 * d), F = rad * (93.272 + 13.22935 * d), l = L + rad * 6.289 * sin(M), b = rad * 5.128 * sin(F), dt = 385001 - 20905 * cos(M);
739
+ return {
740
+ ra: rightAscension(l, b),
741
+ dec: declination(l, b),
742
+ dist: dt
743
+ };
744
+ }
745
+ SunCalc.getMoonPosition = function(date, lat, lng) {
746
+ var lw = rad * -lng, phi = rad * lat, d = toDays(date), c = moonCoords(d), H = siderealTime(d, lw) - c.ra, h = altitude(H, phi, c.dec), pa = atan(sin(H), tan(phi) * cos(c.dec) - sin(c.dec) * cos(H));
747
+ h = h + astroRefraction(h);
748
+ return {
749
+ azimuth: azimuth(H, phi, c.dec),
750
+ altitude: h,
751
+ distance: c.dist,
752
+ parallacticAngle: pa
753
+ };
754
+ };
755
+ SunCalc.getMoonIllumination = function(date) {
756
+ var d = toDays(date || /* @__PURE__ */ new Date()), s = sunCoords(d), m = moonCoords(d), sdist = 149598e3, phi = acos(sin(s.dec) * sin(m.dec) + cos(s.dec) * cos(m.dec) * cos(s.ra - m.ra)), inc = atan(sdist * sin(phi), m.dist - sdist * cos(phi)), angle = atan(cos(s.dec) * sin(s.ra - m.ra), sin(s.dec) * cos(m.dec) - cos(s.dec) * sin(m.dec) * cos(s.ra - m.ra));
757
+ return {
758
+ fraction: (1 + cos(inc)) / 2,
759
+ phase: 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math.PI,
760
+ angle
761
+ };
762
+ };
763
+ function hoursLater(date, h) {
764
+ return new Date(date.valueOf() + h * dayMs / 24);
765
+ }
766
+ SunCalc.getMoonTimes = function(date, lat, lng, inUTC) {
767
+ var t = new Date(date);
768
+ if (inUTC) t.setUTCHours(0, 0, 0, 0);
769
+ else t.setHours(0, 0, 0, 0);
770
+ var hc = 0.133 * rad, h0 = SunCalc.getMoonPosition(t, lat, lng).altitude - hc, h1, h2, rise, set, a, b, xe, ye, d, roots, x1, x2, dx;
771
+ for (var i = 1; i <= 24; i += 2) {
772
+ h1 = SunCalc.getMoonPosition(hoursLater(t, i), lat, lng).altitude - hc;
773
+ h2 = SunCalc.getMoonPosition(hoursLater(t, i + 1), lat, lng).altitude - hc;
774
+ a = (h0 + h2) / 2 - h1;
775
+ b = (h2 - h0) / 2;
776
+ xe = -b / (2 * a);
777
+ ye = (a * xe + b) * xe + h1;
778
+ d = b * b - 4 * a * h1;
779
+ roots = 0;
780
+ if (d >= 0) {
781
+ dx = Math.sqrt(d) / (Math.abs(a) * 2);
782
+ x1 = xe - dx;
783
+ x2 = xe + dx;
784
+ if (Math.abs(x1) <= 1) roots++;
785
+ if (Math.abs(x2) <= 1) roots++;
786
+ if (x1 < -1) x1 = x2;
787
+ }
788
+ if (roots === 1) {
789
+ if (h0 < 0) rise = i + x1;
790
+ else set = i + x1;
791
+ } else if (roots === 2) {
792
+ rise = i + (ye < 0 ? x2 : x1);
793
+ set = i + (ye < 0 ? x1 : x2);
794
+ }
795
+ if (rise && set) break;
796
+ h0 = h2;
797
+ }
798
+ var result = {};
799
+ if (rise) result.rise = hoursLater(t, rise);
800
+ if (set) result.set = hoursLater(t, set);
801
+ if (!rise && !set) result[ye > 0 ? "alwaysUp" : "alwaysDown"] = true;
802
+ return result;
803
+ };
804
+ var defaults$1 = {
805
+ material: "MeshBasicMaterial",
806
+ color: "black",
807
+ opacity: 1
808
+ };
809
+ function material(options2) {
810
+ var output;
811
+ if (options2) {
812
+ options2 = utils._validate(options2, defaults$1);
813
+ if (options2.material && options2.material.isMaterial) output = options2.material;
814
+ else if (options2.material || options2.color || options2.opacity) {
815
+ output = new THREE[options2.material]({ color: options2.color, transparent: options2.opacity < 1 });
816
+ } else output = generateDefaultMaterial();
817
+ output.opacity = options2.opacity;
818
+ if (options2.side) output.side = options2.side;
819
+ } else output = generateDefaultMaterial();
820
+ function generateDefaultMaterial() {
821
+ return new THREE[defaults$1.material]({ color: defaults$1.color });
822
+ }
823
+ return output;
824
+ }
825
+ function AnimationManager(map) {
826
+ this.map = map;
827
+ this.enrolledObjects = [];
828
+ this.previousFrameTime;
829
+ }
830
+ AnimationManager.prototype = {
831
+ unenroll: function(obj) {
832
+ this.enrolledObjects.splice(this.enrolledObjects.indexOf(obj), 1);
833
+ },
834
+ enroll: function(obj) {
835
+ obj.clock = new THREE.Clock();
836
+ obj.hasDefaultAnimation = false;
837
+ obj.defaultAction;
838
+ obj.actions = [];
839
+ obj.mixer;
840
+ if (obj.animations && obj.animations.length > 0) {
841
+ obj.hasDefaultAnimation = true;
842
+ let daIndex = obj.userData.defaultAnimation ? obj.userData.defaultAnimation : 0;
843
+ obj.mixer = new THREE.AnimationMixer(obj);
844
+ setAction(daIndex);
845
+ }
846
+ function setAction(animationIndex) {
847
+ for (let i = 0; i < obj.animations.length; i++) {
848
+ if (animationIndex > obj.animations.length)
849
+ console.log("The animation index " + animationIndex + " doesn't exist for this object");
850
+ let animation = obj.animations[i];
851
+ let action = obj.mixer.clipAction(animation);
852
+ obj.actions.push(action);
853
+ if (animationIndex === i) {
854
+ obj.defaultAction = action;
855
+ action.setEffectiveWeight(1);
856
+ } else {
857
+ action.setEffectiveWeight(0);
858
+ }
859
+ action.play();
860
+ }
861
+ }
862
+ let _isPlaying = false;
863
+ Object.defineProperty(obj, "isPlaying", {
864
+ get() {
865
+ return _isPlaying;
866
+ },
867
+ set(value) {
868
+ if (_isPlaying != value) {
869
+ _isPlaying = value;
870
+ obj.dispatchEvent({ type: "IsPlayingChanged", detail: obj });
871
+ }
872
+ }
873
+ });
874
+ this.enrolledObjects.push(obj);
875
+ obj.animationQueue = [];
876
+ obj.set = function(options2) {
877
+ if (options2.duration > 0) {
878
+ let newParams = {
879
+ start: Date.now(),
880
+ expiration: Date.now() + options2.duration,
881
+ endState: {}
882
+ };
883
+ utils.extend(options2, newParams);
884
+ let translating = options2.coords;
885
+ let rotating = options2.rotation;
886
+ let scaling = options2.scale || options2.scaleX || options2.scaleY || options2.scaleZ;
887
+ if (rotating) {
888
+ let r = obj.rotation;
889
+ options2.startRotation = [r.x, r.y, r.z];
890
+ options2.endState.rotation = utils.types.rotation(options2.rotation, options2.startRotation);
891
+ options2.rotationPerMs = options2.endState.rotation.map(function(angle, index) {
892
+ return (angle - options2.startRotation[index]) / options2.duration;
893
+ });
894
+ }
895
+ if (scaling) {
896
+ let s = obj.scale;
897
+ options2.startScale = [s.x, s.y, s.z];
898
+ options2.endState.scale = utils.types.scale(options2.scale, options2.startScale);
899
+ options2.scalePerMs = options2.endState.scale.map(function(scale, index) {
900
+ return (scale - options2.startScale[index]) / options2.duration;
901
+ });
902
+ }
903
+ if (translating) options2.pathCurve = new THREE.CatmullRomCurve3(utils.lnglatsToWorld([obj.coordinates, options2.coords]));
904
+ let entry = {
905
+ type: "set",
906
+ parameters: options2
907
+ };
908
+ this.animationQueue.push(entry);
909
+ tb.map.repaint = true;
910
+ } else {
911
+ this.stop();
912
+ options2.rotation = utils.radify(options2.rotation);
913
+ this._setObject(options2);
914
+ }
915
+ return this;
916
+ };
917
+ obj.animationMethod = null;
918
+ obj.stop = function(index) {
919
+ if (obj.mixer) {
920
+ obj.isPlaying = false;
921
+ cancelAnimationFrame(obj.animationMethod);
922
+ }
923
+ this.animationQueue = [];
924
+ return this;
925
+ };
926
+ obj.followPath = function(options2, cb) {
927
+ let entry = {
928
+ type: "followPath",
929
+ parameters: utils._validate(options2, defaults.followPath)
930
+ };
931
+ utils.extend(
932
+ entry.parameters,
933
+ {
934
+ pathCurve: new THREE.CatmullRomCurve3(
935
+ utils.lnglatsToWorld(options2.path)
936
+ ),
937
+ start: Date.now(),
938
+ expiration: Date.now() + entry.parameters.duration,
939
+ cb
940
+ }
941
+ );
942
+ this.animationQueue.push(entry);
943
+ tb.map.repaint = true;
944
+ return this;
945
+ };
946
+ obj._setObject = function(options2) {
947
+ obj.setScale();
948
+ let p = options2.position;
949
+ let r = options2.rotation;
950
+ let s = options2.scale;
951
+ let w = options2.worldCoordinates;
952
+ let q = options2.quaternion;
953
+ let t = options2.translate;
954
+ let wt = options2.worldTranslate;
955
+ if (p) {
956
+ this.coordinates = p;
957
+ let c = utils.projectToWorld(p);
958
+ this.position.copy(c);
959
+ }
960
+ if (t) {
961
+ this.coordinates = [this.coordinates[0] + t[0], this.coordinates[1] + t[1], this.coordinates[2] + t[2]];
962
+ let c = utils.projectToWorld(t);
963
+ this.position.copy(c);
964
+ options2.position = this.coordinates;
965
+ }
966
+ if (wt) {
967
+ this.translateX(wt.x);
968
+ this.translateY(wt.y);
969
+ this.translateZ(wt.z);
970
+ let p2 = utils.unprojectFromWorld(this.position);
971
+ this.coordinates = options2.position = p2;
972
+ }
973
+ if (r) {
974
+ this.rotation.set(r[0], r[1], r[2]);
975
+ options2.rotation = new THREE.Vector3(r[0], r[1], r[2]);
976
+ }
977
+ if (s) {
978
+ this.scale.set(s[0], s[1], s[2]);
979
+ options2.scale = this.scale;
980
+ }
981
+ if (q) {
982
+ this.quaternion.setFromAxisAngle(q[0], q[1]);
983
+ options2.rotation = q[0].multiplyScalar(q[1]);
984
+ }
985
+ if (w) {
986
+ this.position.copy(w);
987
+ let p2 = utils.unprojectFromWorld(w);
988
+ this.coordinates = options2.position = p2;
989
+ }
990
+ this.setBoundingBoxShadowFloor();
991
+ this.setReceiveShadowFloor();
992
+ this.updateMatrixWorld();
993
+ tb.map.repaint = true;
994
+ let e2 = { type: "ObjectChanged", detail: { object: this, action: { position: options2.position, rotation: options2.rotation, scale: options2.scale } } };
995
+ this.dispatchEvent(e2);
996
+ };
997
+ obj.playDefault = function(options2) {
998
+ if (obj.mixer && obj.hasDefaultAnimation) {
999
+ let newParams = {
1000
+ start: Date.now(),
1001
+ expiration: Date.now() + options2.duration,
1002
+ endState: {}
1003
+ };
1004
+ utils.extend(options2, newParams);
1005
+ obj.mixer.timeScale = options2.speed || 1;
1006
+ let entry = {
1007
+ type: "playDefault",
1008
+ parameters: options2
1009
+ };
1010
+ this.animationQueue.push(entry);
1011
+ tb.map.repaint = true;
1012
+ return this;
1013
+ }
1014
+ };
1015
+ obj.playAnimation = function(options2) {
1016
+ if (obj.mixer) {
1017
+ if (options2.animation) {
1018
+ setAction(options2.animation);
1019
+ }
1020
+ obj.playDefault(options2);
1021
+ }
1022
+ };
1023
+ obj.pauseAllActions = function() {
1024
+ if (obj.mixer) {
1025
+ obj.actions.forEach(function(action) {
1026
+ action.paused = true;
1027
+ });
1028
+ }
1029
+ };
1030
+ obj.unPauseAllActions = function() {
1031
+ if (obj.mixer) {
1032
+ obj.actions.forEach(function(action) {
1033
+ action.paused = false;
1034
+ });
1035
+ }
1036
+ };
1037
+ obj.deactivateAllActions = function() {
1038
+ if (obj.mixer) {
1039
+ obj.actions.forEach(function(action) {
1040
+ action.stop();
1041
+ });
1042
+ }
1043
+ };
1044
+ obj.activateAllActions = function() {
1045
+ if (obj.mixer) {
1046
+ obj.actions.forEach(function(action) {
1047
+ action.play();
1048
+ });
1049
+ }
1050
+ };
1051
+ obj.idle = function() {
1052
+ if (obj.mixer) {
1053
+ obj.mixer.update(0.01);
1054
+ }
1055
+ tb.map.repaint = true;
1056
+ return this;
1057
+ };
1058
+ },
1059
+ update: function(now) {
1060
+ if (this.previousFrameTime === void 0) this.previousFrameTime = now;
1061
+ if (!this.enrolledObjects) return false;
1062
+ for (let a = this.enrolledObjects.length - 1; a >= 0; a--) {
1063
+ let object = this.enrolledObjects[a];
1064
+ if (!object.animationQueue || object.animationQueue.length === 0) continue;
1065
+ for (let i = object.animationQueue.length - 1; i >= 0; i--) {
1066
+ let item = object.animationQueue[i];
1067
+ if (!item) continue;
1068
+ let options2 = item.parameters;
1069
+ if (!options2.expiration) {
1070
+ object.animationQueue.splice(i, 1);
1071
+ if (object.animationQueue[i]) object.animationQueue[i].parameters.start = now;
1072
+ return;
1073
+ }
1074
+ let expiring = now >= options2.expiration;
1075
+ if (expiring) {
1076
+ options2.expiration = false;
1077
+ if (item.type === "playDefault") {
1078
+ object.stop();
1079
+ } else {
1080
+ if (options2.endState) object._setObject(options2.endState);
1081
+ if (typeof options2.cb != "undefined") options2.cb();
1082
+ }
1083
+ } else {
1084
+ let timeProgress = (now - options2.start) / options2.duration;
1085
+ if (item.type === "set") {
1086
+ let objectState = {};
1087
+ if (options2.pathCurve) objectState.worldCoordinates = options2.pathCurve.getPoint(timeProgress);
1088
+ if (options2.rotationPerMs) {
1089
+ objectState.rotation = options2.startRotation.map(function(rad2, index) {
1090
+ return rad2 + options2.rotationPerMs[index] * timeProgress * options2.duration;
1091
+ });
1092
+ }
1093
+ if (options2.scalePerMs) {
1094
+ objectState.scale = options2.startScale.map(function(scale, index) {
1095
+ return scale + options2.scalePerMs[index] * timeProgress * options2.duration;
1096
+ });
1097
+ }
1098
+ object._setObject(objectState);
1099
+ }
1100
+ if (item.type === "followPath") {
1101
+ let position = options2.pathCurve.getPointAt(timeProgress);
1102
+ let objectState = { worldCoordinates: position };
1103
+ if (options2.trackHeading) {
1104
+ let tangent = options2.pathCurve.getTangentAt(timeProgress).normalize();
1105
+ let axis = new THREE.Vector3(0, 0, 0);
1106
+ let up = new THREE.Vector3(0, 1, 0);
1107
+ axis.crossVectors(up, tangent).normalize();
1108
+ let radians = Math.acos(up.dot(tangent));
1109
+ objectState.quaternion = [axis, radians];
1110
+ }
1111
+ object._setObject(objectState);
1112
+ }
1113
+ if (item.type === "playDefault") {
1114
+ object.activateAllActions();
1115
+ object.isPlaying = true;
1116
+ object.animationMethod = requestAnimationFrame(this.update);
1117
+ object.mixer.update(object.clock.getDelta());
1118
+ tb.map.repaint = true;
1119
+ }
1120
+ }
1121
+ }
1122
+ }
1123
+ this.previousFrameTime = now;
1124
+ }
1125
+ };
1126
+ const defaults = {
1127
+ followPath: {
1128
+ path: null,
1129
+ duration: 1e3,
1130
+ trackHeading: true
1131
+ }
1132
+ };
1133
+ class CSS2DObject extends THREE.Object3D {
1134
+ constructor(element) {
1135
+ super();
1136
+ this.element = element || document.createElement("div");
1137
+ this.element.style.position = "absolute";
1138
+ this.element.style.userSelect = "none";
1139
+ this.element.setAttribute("draggable", false);
1140
+ this.alwaysVisible = false;
1141
+ Object.defineProperty(this, "layer", {
1142
+ get() {
1143
+ return this.parent && this.parent.parent ? this.parent.parent.layer : null;
1144
+ }
1145
+ });
1146
+ this.dispose = function() {
1147
+ this.remove();
1148
+ this.element = null;
1149
+ };
1150
+ this.remove = function() {
1151
+ if (this.element instanceof Element && this.element.parentNode !== null) {
1152
+ this.element.parentNode.removeChild(this.element);
1153
+ }
1154
+ };
1155
+ this.addEventListener("removed", function() {
1156
+ this.remove();
1157
+ });
1158
+ }
1159
+ copy(source, recursive) {
1160
+ super.copy(source, recursive);
1161
+ this.element = source.element.cloneNode(true);
1162
+ return this;
1163
+ }
1164
+ }
1165
+ CSS2DObject.prototype.isCSS2DObject = true;
1166
+ const _vector = new THREE.Vector3();
1167
+ const _viewMatrix = new THREE.Matrix4();
1168
+ const _viewProjectionMatrix = new THREE.Matrix4();
1169
+ const _a = new THREE.Vector3();
1170
+ const _b = new THREE.Vector3();
1171
+ class CSS2DRenderer {
1172
+ constructor() {
1173
+ const _this = this;
1174
+ let _width, _height;
1175
+ let _widthHalf, _heightHalf;
1176
+ const cache = {
1177
+ objects: /* @__PURE__ */ new WeakMap(),
1178
+ list: /* @__PURE__ */ new Map()
1179
+ };
1180
+ this.cacheList = cache.list;
1181
+ const domElement = document.createElement("div");
1182
+ domElement.style.overflow = "hidden";
1183
+ this.domElement = domElement;
1184
+ this.getSize = function() {
1185
+ return {
1186
+ width: _width,
1187
+ height: _height
1188
+ };
1189
+ };
1190
+ this.render = function(scene, camera) {
1191
+ if (scene.autoUpdate === true) scene.updateMatrixWorld();
1192
+ if (camera.parent === null) camera.updateMatrixWorld();
1193
+ _viewMatrix.copy(camera.matrixWorldInverse);
1194
+ _viewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, _viewMatrix);
1195
+ renderObject(scene, scene, camera);
1196
+ zOrder(scene);
1197
+ };
1198
+ this.setSize = function(width, height) {
1199
+ _width = width;
1200
+ _height = height;
1201
+ _widthHalf = _width / 2;
1202
+ _heightHalf = _height / 2;
1203
+ domElement.style.width = width + "px";
1204
+ domElement.style.height = height + "px";
1205
+ };
1206
+ function renderObject(object, scene, camera) {
1207
+ if (object.isCSS2DObject) {
1208
+ if (!object.visible) {
1209
+ cache.objects.delete({ key: object.uuid });
1210
+ cache.list.delete(object.uuid);
1211
+ object.remove();
1212
+ } else {
1213
+ object.onBeforeRender(_this, scene, camera);
1214
+ _vector.setFromMatrixPosition(object.matrixWorld);
1215
+ _vector.applyMatrix4(_viewProjectionMatrix);
1216
+ const element = object.element;
1217
+ var style;
1218
+ if (/apple/i.test(navigator.vendor)) {
1219
+ style = "translate(-50%,-50%) translate(" + Math.round(_vector.x * _widthHalf + _widthHalf) + "px," + Math.round(-_vector.y * _heightHalf + _heightHalf) + "px)";
1220
+ } else {
1221
+ style = "translate(-50%,-50%) translate(" + (_vector.x * _widthHalf + _widthHalf) + "px," + (-_vector.y * _heightHalf + _heightHalf) + "px)";
1222
+ }
1223
+ element.style.WebkitTransform = style;
1224
+ element.style.MozTransform = style;
1225
+ element.style.oTransform = style;
1226
+ element.style.transform = style;
1227
+ element.style.display = object.visible && _vector.z >= -1 && _vector.z <= 1 ? "" : "none";
1228
+ const objectData = {
1229
+ distanceToCameraSquared: getDistanceToSquared(camera, object)
1230
+ };
1231
+ cache.objects.set({ key: object.uuid }, objectData);
1232
+ cache.list.set(object.uuid, object);
1233
+ if (element.parentNode !== domElement) {
1234
+ domElement.appendChild(element);
1235
+ }
1236
+ object.onAfterRender(_this, scene, camera);
1237
+ }
1238
+ }
1239
+ for (let i = 0, l = object.children.length; i < l; i++) {
1240
+ renderObject(object.children[i], scene, camera);
1241
+ }
1242
+ }
1243
+ function getDistanceToSquared(object1, object2) {
1244
+ _a.setFromMatrixPosition(object1.matrixWorld);
1245
+ _b.setFromMatrixPosition(object2.matrixWorld);
1246
+ return _a.distanceToSquared(_b);
1247
+ }
1248
+ function filterAndFlatten(scene) {
1249
+ const result = [];
1250
+ scene.traverse(function(object) {
1251
+ if (object.isCSS2DObject) result.push(object);
1252
+ });
1253
+ return result;
1254
+ }
1255
+ function zOrder(scene) {
1256
+ const sorted = filterAndFlatten(scene).sort(function(a, b) {
1257
+ let cacheA = cache.objects.get({ key: a.uuid });
1258
+ let cacheB = cache.objects.get({ key: b.uuid });
1259
+ if (cacheA && cacheB) {
1260
+ const distanceA = cacheA.distanceToCameraSquared;
1261
+ const distanceB = cacheB.distanceToCameraSquared;
1262
+ return distanceA - distanceB;
1263
+ }
1264
+ });
1265
+ const zMax = sorted.length;
1266
+ for (let i = 0, l = sorted.length; i < l; i++) {
1267
+ sorted[i].element.style.zIndex = zMax - i;
1268
+ }
1269
+ }
1270
+ }
1271
+ }
1272
+ function Objects() {
1273
+ }
1274
+ Objects.prototype = {
1275
+ // standard 1px line with gl
1276
+ line: function(obj) {
1277
+ obj = utils._validate(obj, this._defaults.line);
1278
+ var straightProject = utils.lnglatsToWorld(obj.geometry);
1279
+ var normalized = utils.normalizeVertices(straightProject);
1280
+ var flattenedArray = utils.flattenVectors(normalized.vertices);
1281
+ var positions = new Float32Array(flattenedArray);
1282
+ var geometry = new THREE.BufferGeometry();
1283
+ geometry.setAttribute("position", new THREE.BufferAttribute(positions, 3));
1284
+ var material2 = new THREE.LineBasicMaterial({ color: 16711680, linewidth: 21 });
1285
+ var line2 = new THREE.Line(geometry, material2);
1286
+ line2.options = options || {};
1287
+ line2.position.copy(normalized.position);
1288
+ return line2;
1289
+ },
1290
+ extrusion: function(options2) {
1291
+ },
1292
+ unenroll: function(obj, isStatic) {
1293
+ var root = this;
1294
+ if (isStatic) ;
1295
+ else {
1296
+ root.animationManager.unenroll(obj);
1297
+ }
1298
+ },
1299
+ _addMethods: function(obj, isStatic) {
1300
+ var root = this;
1301
+ const labelName = "label";
1302
+ const tooltipName = "tooltip";
1303
+ const helpName = "help";
1304
+ const shadowPlane = "shadowPlane";
1305
+ if (isStatic) ;
1306
+ else {
1307
+ let _applyAxisAngle = function(model, point, axis, degrees) {
1308
+ let theta = utils.radify(degrees);
1309
+ model.position.sub(point);
1310
+ model.position.applyAxisAngle(axis, theta);
1311
+ model.position.add(point);
1312
+ model.rotateOnAxis(axis, theta);
1313
+ tb.map.repaint = true;
1314
+ }, zoomScale = function(zoom) {
1315
+ return Math.pow(2, zoom);
1316
+ };
1317
+ if (!obj.coordinates) obj.coordinates = [0, 0, 0];
1318
+ Object.defineProperty(obj, "model", {
1319
+ get() {
1320
+ return obj.getObjectByName("model");
1321
+ }
1322
+ });
1323
+ Object.defineProperty(obj, "animations", {
1324
+ get() {
1325
+ const model = obj.model;
1326
+ if (model) {
1327
+ return model.animations;
1328
+ } else return null;
1329
+ }
1330
+ //set(value) { _animations = value}
1331
+ });
1332
+ root.animationManager.enroll(obj);
1333
+ obj.setCoords = function(lnglat) {
1334
+ if (obj.userData.topMargin && obj.userData.feature) {
1335
+ lnglat[2] += ((obj.userData.feature.properties.height || 0) - (obj.userData.feature.properties.base_height || obj.userData.feature.properties.min_height || 0)) * (obj.userData.topMargin || 0);
1336
+ }
1337
+ obj.coordinates = lnglat;
1338
+ obj.set({ position: lnglat });
1339
+ return obj;
1340
+ };
1341
+ obj.setTranslate = function(lnglat) {
1342
+ obj.set({ translate: lnglat });
1343
+ return obj;
1344
+ };
1345
+ obj.setRotation = function(xyz) {
1346
+ if (typeof xyz === "number") xyz = { z: xyz };
1347
+ var r = {
1348
+ x: utils.radify(xyz.x) || obj.rotation.x,
1349
+ y: utils.radify(xyz.y) || obj.rotation.y,
1350
+ z: utils.radify(xyz.z) || obj.rotation.z
1351
+ };
1352
+ obj._setObject({ rotation: [r.x, r.y, r.z] });
1353
+ };
1354
+ obj.calculateAdjustedPosition = function(lnglat, xyz, inverse) {
1355
+ let location = lnglat.slice();
1356
+ let newCoords = utils.unprojectFromWorld(obj.modelSize);
1357
+ if (inverse) {
1358
+ location[0] -= xyz.x != 0 ? newCoords[0] / xyz.x : 0;
1359
+ location[1] -= xyz.y != 0 ? newCoords[1] / xyz.y : 0;
1360
+ location[2] -= xyz.z != 0 ? newCoords[2] / xyz.z : 0;
1361
+ } else {
1362
+ location[0] += xyz.x != 0 ? newCoords[0] / xyz.x : 0;
1363
+ location[1] += xyz.y != 0 ? newCoords[1] / xyz.y : 0;
1364
+ location[2] += xyz.z != 0 ? newCoords[2] / xyz.z : 0;
1365
+ }
1366
+ return location;
1367
+ };
1368
+ obj.setRotationAxis = function(xyz) {
1369
+ if (typeof xyz === "number") xyz = { z: xyz };
1370
+ let bb = obj.modelBox();
1371
+ let point = new THREE.Vector3(bb.max.x, bb.max.y, bb.min.z);
1372
+ if (xyz.x != 0) _applyAxisAngle(obj, point, new THREE.Vector3(0, 0, 1), xyz.x);
1373
+ if (xyz.y != 0) _applyAxisAngle(obj, point, new THREE.Vector3(0, 0, 1), xyz.y);
1374
+ if (xyz.z != 0) _applyAxisAngle(obj, point, new THREE.Vector3(0, 0, 1), xyz.z);
1375
+ };
1376
+ Object.defineProperty(obj, "scaleGroup", {
1377
+ get() {
1378
+ return obj.getObjectByName("scaleGroup");
1379
+ }
1380
+ });
1381
+ Object.defineProperty(obj, "boxGroup", {
1382
+ get() {
1383
+ return obj.getObjectByName("boxGroup");
1384
+ }
1385
+ });
1386
+ Object.defineProperty(obj, "boundingBox", {
1387
+ get() {
1388
+ return obj.getObjectByName("boxModel");
1389
+ }
1390
+ });
1391
+ Object.defineProperty(obj, "boundingBoxShadow", {
1392
+ get() {
1393
+ return obj.getObjectByName("boxShadow");
1394
+ }
1395
+ });
1396
+ obj.drawBoundingBox = function() {
1397
+ let bb = obj.box3();
1398
+ let boxGroup = new THREE.Group();
1399
+ boxGroup.name = "boxGroup";
1400
+ boxGroup.updateMatrixWorld(true);
1401
+ let boxModel = new THREE.Box3Helper(bb, Objects.prototype._defaults.colors.yellow);
1402
+ boxModel.name = "boxModel";
1403
+ boxGroup.add(boxModel);
1404
+ boxModel.layers.disable(0);
1405
+ let bb2 = bb.clone();
1406
+ bb2.max.z = bb2.min.z;
1407
+ let boxShadow = new THREE.Box3Helper(bb2, Objects.prototype._defaults.colors.black);
1408
+ boxShadow.name = "boxShadow";
1409
+ boxGroup.add(boxShadow);
1410
+ boxShadow.layers.disable(0);
1411
+ boxGroup.visible = false;
1412
+ obj.scaleGroup.add(boxGroup);
1413
+ obj.setBoundingBoxShadowFloor();
1414
+ };
1415
+ obj.setBoundingBoxShadowFloor = function() {
1416
+ if (obj.boundingBoxShadow) {
1417
+ let h = -obj.modelHeight, r = obj.rotation, o2 = obj.boundingBoxShadow;
1418
+ o2.box.max.z = o2.box.min.z = h;
1419
+ o2.rotation.y = r.y;
1420
+ o2.rotation.x = -r.x;
1421
+ }
1422
+ };
1423
+ obj.setAnchor = function(anchor) {
1424
+ const b = obj.box3();
1425
+ const c = b.getCenter(new THREE.Vector3());
1426
+ obj.none = { x: 0, y: 0, z: 0 };
1427
+ obj.center = { x: c.x, y: c.y, z: b.min.z };
1428
+ obj.bottom = { x: c.x, y: b.max.y, z: b.min.z };
1429
+ obj.bottomLeft = { x: b.max.x, y: b.max.y, z: b.min.z };
1430
+ obj.bottomRight = { x: b.min.x, y: b.max.y, z: b.min.z };
1431
+ obj.top = { x: c.x, y: b.min.y, z: b.min.z };
1432
+ obj.topLeft = { x: b.max.x, y: b.min.y, z: b.min.z };
1433
+ obj.topRight = { x: b.min.x, y: b.min.y, z: b.min.z };
1434
+ obj.left = { x: b.max.x, y: c.y, z: b.min.z };
1435
+ obj.right = { x: b.min.x, y: c.y, z: b.min.z };
1436
+ switch (anchor) {
1437
+ case "center":
1438
+ obj.anchor = obj.center;
1439
+ break;
1440
+ case "top":
1441
+ obj.anchor = obj.top;
1442
+ break;
1443
+ case "top-left":
1444
+ obj.anchor = obj.topLeft;
1445
+ break;
1446
+ case "top-right":
1447
+ obj.anchor = obj.topRight;
1448
+ break;
1449
+ case "left":
1450
+ obj.anchor = obj.left;
1451
+ break;
1452
+ case "right":
1453
+ obj.anchor = obj.right;
1454
+ break;
1455
+ case "bottom":
1456
+ obj.anchor = obj.bottom;
1457
+ break;
1458
+ case "bottom-left":
1459
+ default:
1460
+ obj.anchor = obj.bottomLeft;
1461
+ break;
1462
+ case "bottom-right":
1463
+ obj.anchor = obj.bottomRight;
1464
+ break;
1465
+ case "auto":
1466
+ case "none":
1467
+ obj.anchor = obj.none;
1468
+ }
1469
+ obj.model.position.set(-obj.anchor.x, -obj.anchor.y, -obj.anchor.z);
1470
+ };
1471
+ obj.setCenter = function(center) {
1472
+ if (center && (center.x != 0 || center.y != 0 || center.z != 0)) {
1473
+ let size = obj.getSize();
1474
+ obj.anchor = { x: obj.anchor.x - size.x * center.x, y: obj.anchor.y - size.y * center.y, z: obj.anchor.z - size.z * center.z };
1475
+ obj.model.position.set(-obj.anchor.x, -obj.anchor.y, -obj.anchor.z);
1476
+ }
1477
+ };
1478
+ Object.defineProperty(obj, "label", {
1479
+ get() {
1480
+ return obj.getObjectByName(labelName);
1481
+ }
1482
+ });
1483
+ Object.defineProperty(obj, "tooltip", {
1484
+ get() {
1485
+ return obj.getObjectByName(tooltipName);
1486
+ }
1487
+ });
1488
+ Object.defineProperty(obj, "help", {
1489
+ get() {
1490
+ return obj.getObjectByName(helpName);
1491
+ }
1492
+ });
1493
+ let _hidden = false;
1494
+ Object.defineProperty(obj, "hidden", {
1495
+ get() {
1496
+ return _hidden;
1497
+ },
1498
+ set(value) {
1499
+ if (_hidden != value) {
1500
+ _hidden = value;
1501
+ obj.visibility = !_hidden;
1502
+ }
1503
+ }
1504
+ });
1505
+ Object.defineProperty(obj, "visibility", {
1506
+ get() {
1507
+ return obj.visible;
1508
+ },
1509
+ set(value) {
1510
+ let _value = value;
1511
+ if (value == "visible" || value == true) {
1512
+ _value = true;
1513
+ if (obj.label) obj.label.visible = _value;
1514
+ } else if (value == "none" || value == false) {
1515
+ _value = false;
1516
+ if (obj.label && obj.label.alwaysVisible) obj.label.visible = _value;
1517
+ if (obj.tooltip) obj.tooltip.visible = _value;
1518
+ } else return;
1519
+ if (obj.visible != _value) {
1520
+ if (obj.hidden && _value) return;
1521
+ obj.visible = _value;
1522
+ if (obj.model) {
1523
+ obj.model.traverse(function(c) {
1524
+ if (c.type == "Mesh" || c.type == "SkinnedMesh") {
1525
+ if (_value && obj.raycasted) {
1526
+ c.layers.enable(0);
1527
+ } else {
1528
+ c.layers.disable(0);
1529
+ }
1530
+ }
1531
+ if (c.type == "LineSegments") {
1532
+ c.layers.disableAll();
1533
+ }
1534
+ });
1535
+ }
1536
+ }
1537
+ }
1538
+ });
1539
+ obj.addLabel = function(HTMLElement, visible, center, height) {
1540
+ if (HTMLElement) {
1541
+ obj.drawLabelHTML(HTMLElement, visible, center, height);
1542
+ }
1543
+ };
1544
+ obj.removeLabel = function() {
1545
+ obj.removeCSS2D(labelName);
1546
+ };
1547
+ obj.drawLabelHTML = function(HTMLElement, visible = false, center = obj.anchor, height = 0.5) {
1548
+ let divLabel = root.drawLabelHTML(HTMLElement, Objects.prototype._defaults.label.cssClass);
1549
+ let label = obj.addCSS2D(divLabel, labelName, center, height);
1550
+ label.alwaysVisible = visible;
1551
+ label.visible = visible;
1552
+ return label;
1553
+ };
1554
+ obj.addTooltip = function(tooltipText, mapboxStyle, center, custom = true, height = 1) {
1555
+ let t = obj.addHelp(tooltipText, tooltipName, mapboxStyle, center, height);
1556
+ t.visible = false;
1557
+ t.custom = custom;
1558
+ };
1559
+ obj.removeTooltip = function() {
1560
+ obj.removeCSS2D(tooltipName);
1561
+ };
1562
+ obj.addHelp = function(helpText, objName = helpName, mapboxStyle = false, center = obj.anchor, height = 0) {
1563
+ let divHelp = root.drawTooltip(helpText, mapboxStyle);
1564
+ let h = obj.addCSS2D(divHelp, objName, center, height);
1565
+ h.visible = true;
1566
+ return h;
1567
+ };
1568
+ obj.removeHelp = function() {
1569
+ obj.removeCSS2D(helpName);
1570
+ };
1571
+ obj.addCSS2D = function(element, objName, center = obj.anchor, height = 1) {
1572
+ if (element) {
1573
+ const box = obj.box3();
1574
+ const size = box.getSize(new THREE.Vector3());
1575
+ let bottomLeft = { x: box.max.x, y: box.max.y, z: box.min.z };
1576
+ obj.removeCSS2D(objName);
1577
+ let c = new CSS2DObject(element);
1578
+ c.name = objName;
1579
+ c.position.set(-size.x * 0.5 - obj.model.position.x - center.x + bottomLeft.x, -size.y * 0.5 - obj.model.position.y - center.y + bottomLeft.y, size.z * height);
1580
+ c.visible = false;
1581
+ obj.scaleGroup.add(c);
1582
+ return c;
1583
+ }
1584
+ };
1585
+ obj.removeCSS2D = function(objName) {
1586
+ let css2D = obj.getObjectByName(objName);
1587
+ if (css2D) {
1588
+ css2D.dispose();
1589
+ let g = obj.scaleGroup.children;
1590
+ g.splice(g.indexOf(css2D), 1);
1591
+ }
1592
+ };
1593
+ Object.defineProperty(obj, "shadowPlane", {
1594
+ get() {
1595
+ return obj.getObjectByName(shadowPlane);
1596
+ }
1597
+ });
1598
+ let _castShadow = false;
1599
+ Object.defineProperty(obj, "castShadow", {
1600
+ get() {
1601
+ return _castShadow;
1602
+ },
1603
+ set(value) {
1604
+ if (!obj.model || _castShadow === value) return;
1605
+ obj.model.traverse(function(c) {
1606
+ if (c.isMesh) c.castShadow = true;
1607
+ });
1608
+ if (value) {
1609
+ const s = obj.modelSize;
1610
+ const sz = [s.x, s.y, s.z, obj.modelHeight];
1611
+ const pSize = Math.max(...sz) * 10;
1612
+ const pGeo = new THREE.PlaneGeometry(pSize, pSize);
1613
+ const pMat = new THREE.ShadowMaterial();
1614
+ pMat.opacity = 0.5;
1615
+ let p = new THREE.Mesh(pGeo, pMat);
1616
+ p.name = shadowPlane;
1617
+ p.layers.enable(1);
1618
+ p.layers.disable(0);
1619
+ p.receiveShadow = value;
1620
+ obj.add(p);
1621
+ } else {
1622
+ obj.traverse(function(c) {
1623
+ if (c.isMesh && c.material instanceof THREE.ShadowMaterial)
1624
+ obj.remove(c);
1625
+ });
1626
+ }
1627
+ _castShadow = value;
1628
+ }
1629
+ });
1630
+ obj.setReceiveShadowFloor = function() {
1631
+ if (obj.castShadow) {
1632
+ let sp = obj.shadowPlane, p = sp.position, r = sp.rotation;
1633
+ p.z = -obj.modelHeight;
1634
+ r.y = obj.rotation.y;
1635
+ r.x = -obj.rotation.x;
1636
+ if (obj.userData.units === "meters") {
1637
+ const s = obj.modelSize;
1638
+ const sz = [s.x, s.y, s.z, -p.z];
1639
+ const ps = Math.max(...sz) * 10;
1640
+ const sc = ps / sp.geometry.parameters.width;
1641
+ sp.scale.set(sc, sc, sc);
1642
+ }
1643
+ }
1644
+ };
1645
+ let _receiveShadow = false;
1646
+ Object.defineProperty(obj, "receiveShadow", {
1647
+ get() {
1648
+ return _receiveShadow;
1649
+ },
1650
+ set(value) {
1651
+ if (!obj.model || _receiveShadow === value) return;
1652
+ obj.model.traverse(function(c) {
1653
+ if (c.isMesh) c.receiveShadow = true;
1654
+ });
1655
+ _receiveShadow = value;
1656
+ }
1657
+ });
1658
+ let _wireframe = false;
1659
+ Object.defineProperty(obj, "wireframe", {
1660
+ get() {
1661
+ return _wireframe;
1662
+ },
1663
+ set(value) {
1664
+ if (!obj.model || _wireframe === value) return;
1665
+ obj.model.traverse(function(c) {
1666
+ if (c.type == "Mesh" || c.type == "SkinnedMesh") {
1667
+ let materials = [];
1668
+ if (!Array.isArray(c.material)) {
1669
+ materials.push(c.material);
1670
+ } else {
1671
+ materials = c.material;
1672
+ }
1673
+ let m = materials[0];
1674
+ if (value) {
1675
+ c.userData.materials = m;
1676
+ c.material = m.clone();
1677
+ c.material.wireframe = c.material.transparent = value;
1678
+ c.material.opacity = 0.3;
1679
+ } else {
1680
+ c.material.dispose();
1681
+ c.material = c.userData.materials;
1682
+ c.userData.materials.dispose();
1683
+ c.userData.materials = null;
1684
+ }
1685
+ if (value) {
1686
+ c.layers.disable(0);
1687
+ c.layers.enable(1);
1688
+ } else {
1689
+ c.layers.disable(1);
1690
+ c.layers.enable(0);
1691
+ }
1692
+ }
1693
+ if (c.type == "LineSegments") {
1694
+ c.layers.disableAll();
1695
+ }
1696
+ });
1697
+ _wireframe = value;
1698
+ obj.dispatchEvent({ type: "Wireframed", detail: obj });
1699
+ }
1700
+ });
1701
+ let _color = null;
1702
+ Object.defineProperty(obj, "color", {
1703
+ get() {
1704
+ return _color;
1705
+ },
1706
+ set(value) {
1707
+ if (!obj.model || _color === value) return;
1708
+ obj.model.traverse(function(c) {
1709
+ if (c.type == "Mesh" || c.type == "SkinnedMesh") {
1710
+ let materials = [];
1711
+ if (!Array.isArray(c.material)) {
1712
+ materials.push(c.material);
1713
+ } else {
1714
+ materials = c.material;
1715
+ }
1716
+ let m = materials[0];
1717
+ if (value) {
1718
+ c.userData.materials = m;
1719
+ c.material = new THREE.MeshStandardMaterial();
1720
+ c.material.color.setHex(value);
1721
+ } else {
1722
+ c.material.dispose();
1723
+ c.material = c.userData.materials;
1724
+ c.userData.materials.dispose();
1725
+ c.userData.materials = null;
1726
+ }
1727
+ }
1728
+ });
1729
+ _color = value;
1730
+ }
1731
+ });
1732
+ let _selected = false;
1733
+ Object.defineProperty(obj, "selected", {
1734
+ get() {
1735
+ return _selected;
1736
+ },
1737
+ set(value) {
1738
+ if (value) {
1739
+ if (obj.userData.bbox && !obj.boundingBox) obj.drawBoundingBox();
1740
+ if (obj.boxGroup) {
1741
+ obj.boundingBox.material = Objects.prototype._defaults.materials.boxSelectedMaterial;
1742
+ obj.boundingBox.parent.visible = true;
1743
+ obj.boundingBox.layers.enable(1);
1744
+ obj.boundingBoxShadow.layers.enable(1);
1745
+ }
1746
+ if (obj.label && !obj.label.alwaysVisible) obj.label.visible = true;
1747
+ } else {
1748
+ if (obj.boxGroup) {
1749
+ obj.remove(obj.boxGroup);
1750
+ }
1751
+ if (obj.label && !obj.label.alwaysVisible) obj.label.visible = false;
1752
+ obj.removeHelp();
1753
+ }
1754
+ if (obj.tooltip) obj.tooltip.visible = value;
1755
+ if (_selected != value) {
1756
+ _selected = value;
1757
+ obj.dispatchEvent({ type: "SelectedChange", detail: obj });
1758
+ }
1759
+ }
1760
+ });
1761
+ let _raycasted = true;
1762
+ Object.defineProperty(obj, "raycasted", {
1763
+ get() {
1764
+ return _raycasted;
1765
+ },
1766
+ set(value) {
1767
+ if (!obj.model || _raycasted === value) return;
1768
+ obj.model.traverse(function(c) {
1769
+ if (c.type == "Mesh" || c.type == "SkinnedMesh") {
1770
+ if (!value) {
1771
+ c.layers.disable(0);
1772
+ c.layers.enable(1);
1773
+ } else {
1774
+ c.layers.disable(1);
1775
+ c.layers.enable(0);
1776
+ }
1777
+ }
1778
+ });
1779
+ _raycasted = value;
1780
+ }
1781
+ });
1782
+ let _over = false;
1783
+ Object.defineProperty(obj, "over", {
1784
+ get() {
1785
+ return _over;
1786
+ },
1787
+ set(value) {
1788
+ if (value) {
1789
+ if (!obj.selected) {
1790
+ if (obj.userData.bbox && !obj.boundingBox) obj.drawBoundingBox();
1791
+ if (obj.userData.tooltip && !obj.tooltip) obj.addTooltip(obj.uuid, true, obj.anchor, false);
1792
+ if (obj.boxGroup) {
1793
+ obj.boundingBox.material = Objects.prototype._defaults.materials.boxOverMaterial;
1794
+ obj.boundingBox.parent.visible = true;
1795
+ obj.boundingBox.layers.enable(1);
1796
+ obj.boundingBoxShadow.layers.enable(1);
1797
+ }
1798
+ }
1799
+ if (obj.label && !obj.label.alwaysVisible) {
1800
+ obj.label.visible = true;
1801
+ }
1802
+ obj.dispatchEvent({ type: "ObjectMouseOver", detail: obj });
1803
+ } else {
1804
+ if (!obj.selected) {
1805
+ if (obj.boxGroup) {
1806
+ obj.remove(obj.boxGroup);
1807
+ if (obj.tooltip && !obj.tooltip.custom) obj.removeTooltip();
1808
+ }
1809
+ if (obj.label && !obj.label.alwaysVisible) {
1810
+ obj.label.visible = false;
1811
+ }
1812
+ }
1813
+ obj.dispatchEvent({ type: "ObjectMouseOut", detail: obj });
1814
+ }
1815
+ if (obj.tooltip) obj.tooltip.visible = value || obj.selected;
1816
+ _over = value;
1817
+ }
1818
+ });
1819
+ obj.box3 = function() {
1820
+ obj.updateMatrix();
1821
+ obj.updateMatrixWorld(true, true);
1822
+ let bounds;
1823
+ if (obj.model) {
1824
+ let dup = obj.clone(true);
1825
+ let model = obj.model.clone();
1826
+ bounds = new THREE.Box3().setFromObject(model);
1827
+ if (obj.parent) {
1828
+ let rm = new THREE.Matrix4();
1829
+ let rmi = new THREE.Matrix4();
1830
+ obj.matrix.extractRotation(rm);
1831
+ rmi.copy(rm).invert();
1832
+ dup.setRotationFromMatrix(rmi);
1833
+ bounds = new THREE.Box3().setFromObject(model);
1834
+ }
1835
+ }
1836
+ return bounds;
1837
+ };
1838
+ obj.modelBox = function() {
1839
+ return obj.box3();
1840
+ };
1841
+ obj.getSize = function() {
1842
+ return obj.box3().getSize(new THREE.Vector3(0, 0, 0));
1843
+ };
1844
+ let _modelSize = false;
1845
+ Object.defineProperty(obj, "modelSize", {
1846
+ get() {
1847
+ _modelSize = obj.getSize();
1848
+ return _modelSize;
1849
+ },
1850
+ set(value) {
1851
+ if (_modelSize != value) {
1852
+ _modelSize = value;
1853
+ }
1854
+ }
1855
+ });
1856
+ Object.defineProperty(obj, "modelHeight", {
1857
+ get() {
1858
+ let h = obj.coordinates[2] || 0;
1859
+ if (obj.userData.units === "scene") h *= obj.unitsPerMeter / obj.scale.x;
1860
+ return h;
1861
+ }
1862
+ });
1863
+ Object.defineProperty(obj, "unitsPerMeter", {
1864
+ get() {
1865
+ return Number(utils.projectedUnitsPerMeter(obj.coordinates[1]).toFixed(7));
1866
+ }
1867
+ });
1868
+ Object.defineProperty(obj, "fixedZoom", {
1869
+ get() {
1870
+ return obj.userData.fixedZoom;
1871
+ },
1872
+ set(value) {
1873
+ if (obj.userData.fixedZoom === value) return;
1874
+ obj.userData.fixedZoom = value;
1875
+ obj.userData.units = value ? "scene" : "meters";
1876
+ }
1877
+ });
1878
+ obj.setFixedZoom = function(scale) {
1879
+ if (obj.fixedZoom != null && obj.fixedZoom != 0) {
1880
+ if (!scale) scale = obj.userData.mapScale;
1881
+ let s = zoomScale(obj.fixedZoom);
1882
+ if (s > scale) {
1883
+ let calc = s / scale;
1884
+ obj.scale.set(calc, calc, calc);
1885
+ } else {
1886
+ obj.scale.set(1, 1, 1);
1887
+ }
1888
+ }
1889
+ };
1890
+ obj.setScale = function(scale) {
1891
+ if (obj.userData.units != "scene") {
1892
+ let s = obj.unitsPerMeter;
1893
+ obj.scale.set(s, s, s);
1894
+ } else if (obj.fixedZoom) {
1895
+ if (scale) obj.userData.mapScale = scale;
1896
+ obj.setFixedZoom(obj.userData.mapScale);
1897
+ } else obj.scale.set(1, 1, 1);
1898
+ };
1899
+ obj.setObjectScale = function(scale) {
1900
+ obj.setScale(scale);
1901
+ obj.setBoundingBoxShadowFloor();
1902
+ obj.setReceiveShadowFloor();
1903
+ };
1904
+ }
1905
+ obj.add = function(o2) {
1906
+ obj.scaleGroup.add(o2);
1907
+ o2.position.z = obj.coordinates[2] ? -obj.coordinates[2] : 0;
1908
+ return o2;
1909
+ };
1910
+ obj.remove = function(o2) {
1911
+ if (!o2) return;
1912
+ o2.traverse((m) => {
1913
+ if (m.geometry) m.geometry.dispose();
1914
+ if (m.material) {
1915
+ if (m.material.isMaterial) {
1916
+ cleanMaterial(m.material);
1917
+ } else {
1918
+ for (const material2 of m.material) cleanMaterial(material2);
1919
+ }
1920
+ }
1921
+ if (m.dispose) m.dispose();
1922
+ });
1923
+ obj.scaleGroup.remove(o2);
1924
+ tb.map.repaint = true;
1925
+ };
1926
+ obj.duplicate = function(options2) {
1927
+ let dupe = obj.clone(true);
1928
+ dupe.getObjectByName("model").animations = obj.animations;
1929
+ if (dupe.userData.feature) {
1930
+ if (options2 && options2.feature) dupe.userData.feature = options2.feature;
1931
+ dupe.userData.feature.properties.uuid = dupe.uuid;
1932
+ }
1933
+ root._addMethods(dupe);
1934
+ if (!options2 || utils.equal(options2.scale, obj.userData.scale)) {
1935
+ dupe.copyAnchor(obj);
1936
+ return dupe;
1937
+ } else {
1938
+ dupe.userData = options2;
1939
+ dupe.userData.isGeoGroup = true;
1940
+ dupe.remove(dupe.boxGroup);
1941
+ const r = utils.types.rotation(options2.rotation, [0, 0, 0]);
1942
+ const s = utils.types.scale(options2.scale, [1, 1, 1]);
1943
+ dupe.model.position.set(0, 0, 0);
1944
+ dupe.model.rotation.set(r[0], r[1], r[2]);
1945
+ dupe.model.scale.set(s[0], s[1], s[2]);
1946
+ dupe.setAnchor(options2.anchor);
1947
+ dupe.setCenter(options2.adjustment);
1948
+ return dupe;
1949
+ }
1950
+ };
1951
+ obj.copyAnchor = function(o2) {
1952
+ obj.anchor = o2.anchor;
1953
+ obj.none = { x: 0, y: 0, z: 0 };
1954
+ obj.center = o2.center;
1955
+ obj.bottom = o2.bottom;
1956
+ obj.bottomLeft = o2.bottomLeft;
1957
+ obj.bottomRight = o2.bottomRight;
1958
+ obj.top = o2.top;
1959
+ obj.topLeft = o2.topLeft;
1960
+ obj.topRight = o2.topRight;
1961
+ obj.left = o2.left;
1962
+ obj.right = o2.right;
1963
+ };
1964
+ obj.dispose = function() {
1965
+ Objects.prototype.unenroll(obj);
1966
+ obj.traverse((o2) => {
1967
+ if (o2.parent && o2.parent.name == "world") return;
1968
+ if (o2.name === "threeboxObject") return;
1969
+ if (o2.geometry) o2.geometry.dispose();
1970
+ if (o2.material) {
1971
+ if (o2.material.isMaterial) {
1972
+ cleanMaterial(o2.material);
1973
+ } else {
1974
+ for (const material2 of o2.material) cleanMaterial(material2);
1975
+ }
1976
+ }
1977
+ if (o2.dispose) o2.dispose();
1978
+ });
1979
+ obj.children = [];
1980
+ };
1981
+ const cleanMaterial = (material2) => {
1982
+ material2.dispose();
1983
+ for (const key of Object.keys(material2)) {
1984
+ const value = material2[key];
1985
+ if (value && typeof value === "object" && "minFilter" in value) {
1986
+ value.dispose();
1987
+ }
1988
+ }
1989
+ let m = material2;
1990
+ let md = m.map || m.alphaMap || m.aoMap || m.bumpMap || m.displacementMap || m.emissiveMap || m.envMap || m.lightMap || m.metalnessMap || m.normalMap || m.roughnessMap;
1991
+ if (md) {
1992
+ if (m.map) m.map.dispose();
1993
+ if (m.alphaMap) m.alphaMap.dispose();
1994
+ if (m.aoMap) m.aoMap.dispose();
1995
+ if (m.bumpMap) m.bumpMap.dispose();
1996
+ if (m.displacementMap) m.displacementMap.dispose();
1997
+ if (m.emissiveMap) m.emissiveMap.dispose();
1998
+ if (m.envMap) m.envMap.dispose();
1999
+ if (m.lightMap) m.lightMap.dispose();
2000
+ if (m.metalnessMap) m.metalnessMap.dispose();
2001
+ if (m.normalMap) m.normalMap.dispose();
2002
+ if (m.roughnessMap) m.roughnessMap.dispose();
2003
+ }
2004
+ };
2005
+ return obj;
2006
+ },
2007
+ _makeGroup: function(obj, options2) {
2008
+ let projScaleGroup = new THREE.Group();
2009
+ projScaleGroup.name = "scaleGroup";
2010
+ projScaleGroup.add(obj);
2011
+ var geoGroup = new THREE.Group();
2012
+ geoGroup.userData = options2 || {};
2013
+ geoGroup.userData.isGeoGroup = true;
2014
+ if (geoGroup.userData.feature) {
2015
+ geoGroup.userData.feature.properties.uuid = geoGroup.uuid;
2016
+ }
2017
+ var isArrayOfObjects = projScaleGroup.length;
2018
+ if (isArrayOfObjects) for (o of projScaleGroup) geoGroup.add(o);
2019
+ else geoGroup.add(projScaleGroup);
2020
+ geoGroup.name = "threeboxObject";
2021
+ return geoGroup;
2022
+ },
2023
+ animationManager: new AnimationManager(),
2024
+ //[jscastro] add tooltip method
2025
+ drawTooltip: function(tooltipText, mapboxStyle = false) {
2026
+ if (tooltipText) {
2027
+ let divToolTip;
2028
+ if (mapboxStyle) {
2029
+ let divContent = document.createElement("div");
2030
+ divContent.className = "mapboxgl-popup-content";
2031
+ let strong = document.createElement("strong");
2032
+ strong.innerHTML = tooltipText;
2033
+ divContent.appendChild(strong);
2034
+ let tip = document.createElement("div");
2035
+ tip.className = "mapboxgl-popup-tip";
2036
+ let div = document.createElement("div");
2037
+ div.className = "marker mapboxgl-popup-anchor-bottom";
2038
+ div.appendChild(tip);
2039
+ div.appendChild(divContent);
2040
+ divToolTip = document.createElement("div");
2041
+ divToolTip.className += "label3D";
2042
+ divToolTip.appendChild(div);
2043
+ } else {
2044
+ divToolTip = document.createElement("span");
2045
+ divToolTip.className = this._defaults.tooltip.cssClass;
2046
+ divToolTip.innerHTML = tooltipText;
2047
+ }
2048
+ return divToolTip;
2049
+ }
2050
+ },
2051
+ //[jscastro] draw label method can be invoked separately
2052
+ drawLabelHTML: function(HTMLElement, cssClass) {
2053
+ let div = document.createElement("div");
2054
+ div.className += cssClass;
2055
+ if (typeof HTMLElement == "string") {
2056
+ div.innerHTML = HTMLElement;
2057
+ } else {
2058
+ div.innerHTML = HTMLElement.outerHTML;
2059
+ }
2060
+ return div;
2061
+ },
2062
+ _defaults: {
2063
+ colors: {
2064
+ red: new THREE.Color(16711680),
2065
+ yellow: new THREE.Color(16776960),
2066
+ green: new THREE.Color(65280),
2067
+ black: new THREE.Color(0)
2068
+ },
2069
+ materials: {
2070
+ boxNormalMaterial: new THREE.LineBasicMaterial({ color: new THREE.Color(16711680) }),
2071
+ boxOverMaterial: new THREE.LineBasicMaterial({ color: new THREE.Color(16776960) }),
2072
+ boxSelectedMaterial: new THREE.LineBasicMaterial({ color: new THREE.Color(65280) })
2073
+ },
2074
+ line: {
2075
+ geometry: null,
2076
+ color: "black",
2077
+ width: 1,
2078
+ opacity: 1
2079
+ },
2080
+ label: {
2081
+ htmlElement: null,
2082
+ cssClass: " label3D",
2083
+ alwaysVisible: false,
2084
+ topMargin: -0.5
2085
+ },
2086
+ tooltip: {
2087
+ text: "",
2088
+ cssClass: "toolTip text-xs",
2089
+ mapboxStyle: false,
2090
+ topMargin: 0
2091
+ },
2092
+ sphere: {
2093
+ position: [0, 0, 0],
2094
+ radius: 1,
2095
+ sides: 20,
2096
+ units: "scene",
2097
+ material: "MeshBasicMaterial",
2098
+ anchor: "bottom-left",
2099
+ bbox: true,
2100
+ tooltip: true,
2101
+ raycasted: true
2102
+ },
2103
+ tube: {
2104
+ geometry: null,
2105
+ radius: 1,
2106
+ sides: 6,
2107
+ units: "scene",
2108
+ material: "MeshBasicMaterial",
2109
+ anchor: "center",
2110
+ bbox: true,
2111
+ tooltip: true,
2112
+ raycasted: true
2113
+ },
2114
+ loadObj: {
2115
+ type: null,
2116
+ obj: null,
2117
+ units: "scene",
2118
+ scale: 1,
2119
+ rotation: 0,
2120
+ defaultAnimation: 0,
2121
+ anchor: "bottom-left",
2122
+ bbox: true,
2123
+ tooltip: true,
2124
+ raycasted: true,
2125
+ clone: true,
2126
+ withCredentials: false
2127
+ },
2128
+ Object3D: {
2129
+ obj: null,
2130
+ units: "scene",
2131
+ anchor: "bottom-left",
2132
+ bbox: true,
2133
+ tooltip: true,
2134
+ raycasted: true
2135
+ },
2136
+ extrusion: {
2137
+ coordinates: [[[]]],
2138
+ geometryOptions: {},
2139
+ height: 100,
2140
+ materials: new THREE.MeshPhongMaterial({ color: 6684672, side: THREE.DoubleSide }),
2141
+ scale: 1,
2142
+ rotation: 0,
2143
+ units: "scene",
2144
+ anchor: "center",
2145
+ bbox: true,
2146
+ tooltip: true,
2147
+ raycasted: true
2148
+ }
2149
+ },
2150
+ geometries: {
2151
+ line: ["LineString"],
2152
+ tube: ["LineString"],
2153
+ sphere: ["Point"]
2154
+ }
2155
+ };
2156
+ function Object3D(opt) {
2157
+ opt = utils._validate(opt, Objects.prototype._defaults.Object3D);
2158
+ let obj = opt.obj;
2159
+ const r = utils.types.rotation(opt.rotation, [0, 0, 0]);
2160
+ const s = utils.types.scale(opt.scale, [1, 1, 1]);
2161
+ obj.rotation.set(r[0], r[1], r[2]);
2162
+ obj.scale.set(s[0], s[1], s[2]);
2163
+ obj.name = "model";
2164
+ let userScaleGroup = Objects.prototype._makeGroup(obj, opt);
2165
+ opt.obj.name = "model";
2166
+ Objects.prototype._addMethods(userScaleGroup);
2167
+ userScaleGroup.setAnchor(opt.anchor);
2168
+ userScaleGroup.setCenter(opt.adjustment);
2169
+ userScaleGroup.raycasted = opt.raycasted;
2170
+ userScaleGroup.visibility = true;
2171
+ return userScaleGroup;
2172
+ }
2173
+ function Sphere(opt) {
2174
+ opt = utils._validate(opt, Objects.prototype._defaults.sphere);
2175
+ let geometry = new THREE.SphereGeometry(opt.radius, opt.sides, opt.sides);
2176
+ let mat = material(opt);
2177
+ let output = new THREE.Mesh(geometry, mat);
2178
+ return new Object3D({ obj: output, units: opt.units, anchor: opt.anchor, adjustment: opt.adjustment, bbox: opt.bbox, tooltip: opt.tooltip, raycasted: opt.raycasted });
2179
+ }
2180
+ function extrusion(opt) {
2181
+ opt = utils._validate(opt, Objects.prototype._defaults.extrusion);
2182
+ let shape = extrusion.prototype.buildShape(opt.coordinates);
2183
+ let geometry = extrusion.prototype.buildGeometry(shape, opt.geometryOptions);
2184
+ let mesh = new THREE.Mesh(geometry, opt.materials);
2185
+ opt.obj = mesh;
2186
+ return new Object3D(opt);
2187
+ }
2188
+ extrusion.prototype = {
2189
+ buildShape: function(coords) {
2190
+ if (coords[0] instanceof (THREE.Vector2 || THREE.Vector3)) return new THREE.Shape(coords);
2191
+ let shape = new THREE.Shape();
2192
+ for (let i = 0; i < coords.length; i++) {
2193
+ if (i === 0) {
2194
+ shape = new THREE.Shape(this.buildPoints(coords[0], coords[0]));
2195
+ } else {
2196
+ shape.holes.push(new THREE.Path(this.buildPoints(coords[i], coords[0])));
2197
+ }
2198
+ }
2199
+ return shape;
2200
+ },
2201
+ buildPoints: function(coords, initCoords) {
2202
+ const points = [];
2203
+ let init = utils.projectToWorld([initCoords[0][0], initCoords[0][1], 0]);
2204
+ for (let i = 0; i < coords.length; i++) {
2205
+ let pos = utils.projectToWorld([coords[i][0], coords[i][1], 0]);
2206
+ points.push(new THREE.Vector2(utils.toDecimal(pos.x - init.x, 9), utils.toDecimal(pos.y - init.y, 9)));
2207
+ }
2208
+ return points;
2209
+ },
2210
+ buildGeometry: function(shape, settings) {
2211
+ let geometry = new THREE.ExtrudeGeometry(shape, settings);
2212
+ geometry.computeBoundingBox();
2213
+ return geometry;
2214
+ }
2215
+ };
2216
+ function Label(obj) {
2217
+ obj = utils._validate(obj, Objects.prototype._defaults.label);
2218
+ let div = Objects.prototype.drawLabelHTML(obj.htmlElement, obj.cssClass);
2219
+ let label = new CSS2DObject(div);
2220
+ label.name = "label";
2221
+ label.visible = obj.alwaysVisible;
2222
+ label.alwaysVisible = obj.alwaysVisible;
2223
+ var userScaleGroup = Objects.prototype._makeGroup(label, obj);
2224
+ Objects.prototype._addMethods(userScaleGroup);
2225
+ userScaleGroup.visibility = obj.alwaysVisible;
2226
+ return userScaleGroup;
2227
+ }
2228
+ function Tooltip(obj) {
2229
+ obj = utils._validate(obj, Objects.prototype._defaults.tooltip);
2230
+ if (obj.text) {
2231
+ let divToolTip = Objects.prototype.drawTooltip(obj.text, obj.mapboxStyle);
2232
+ let tooltip = new CSS2DObject(divToolTip);
2233
+ tooltip.visible = false;
2234
+ tooltip.name = "tooltip";
2235
+ var userScaleGroup = Objects.prototype._makeGroup(tooltip, obj);
2236
+ Objects.prototype._addMethods(userScaleGroup);
2237
+ return userScaleGroup;
2238
+ }
2239
+ }
2240
+ const objLoader = new OBJLoader();
2241
+ const materialLoader = new MTLLoader();
2242
+ const gltfLoader = new GLTFLoader();
2243
+ const fbxLoader = new FBXLoader();
2244
+ const daeLoader = new ColladaLoader();
2245
+ function loadObj(options2, cb, promise) {
2246
+ if (options2 === void 0) return console.error("Invalid options provided to loadObj()");
2247
+ options2 = utils._validate(options2, Objects.prototype._defaults.loadObj);
2248
+ let loader;
2249
+ if (!options2.type) {
2250
+ options2.type = "mtl";
2251
+ }
2252
+ switch (options2.type) {
2253
+ case "mtl":
2254
+ loader = objLoader;
2255
+ break;
2256
+ case "gltf":
2257
+ case "glb":
2258
+ loader = gltfLoader;
2259
+ break;
2260
+ case "fbx":
2261
+ loader = fbxLoader;
2262
+ break;
2263
+ case "dae":
2264
+ loader = daeLoader;
2265
+ break;
2266
+ }
2267
+ materialLoader.withCredentials = options2.withCredentials;
2268
+ materialLoader.load(options2.mtl, loadObject, () => null, (error) => {
2269
+ console.warn("No material file found " + error.stack);
2270
+ });
2271
+ function loadObject(materials) {
2272
+ if (materials && options2.type == "mtl") {
2273
+ materials.preload();
2274
+ loader.setMaterials(materials);
2275
+ }
2276
+ loader.withCredentials = options2.withCredentials;
2277
+ loader.load(options2.obj, (obj) => {
2278
+ let animations = [];
2279
+ switch (options2.type) {
2280
+ case "mtl":
2281
+ obj = obj.children[0];
2282
+ break;
2283
+ case "gltf":
2284
+ case "glb":
2285
+ case "dae":
2286
+ animations = obj.animations;
2287
+ obj = obj.scene;
2288
+ break;
2289
+ case "fbx":
2290
+ animations = obj.animations;
2291
+ break;
2292
+ }
2293
+ obj.animations = animations;
2294
+ const r = utils.types.rotation(options2.rotation, [0, 0, 0]);
2295
+ const s = utils.types.scale(options2.scale, [1, 1, 1]);
2296
+ obj.rotation.set(r[0], r[1], r[2]);
2297
+ obj.scale.set(s[0], s[1], s[2]);
2298
+ if (options2.normalize) {
2299
+ normalizeSpecular(obj);
2300
+ }
2301
+ obj.name = "model";
2302
+ let userScaleGroup = Objects.prototype._makeGroup(obj, options2);
2303
+ Objects.prototype._addMethods(userScaleGroup);
2304
+ userScaleGroup.setAnchor(options2.anchor);
2305
+ userScaleGroup.setCenter(options2.adjustment);
2306
+ userScaleGroup.raycasted = options2.raycasted;
2307
+ promise(userScaleGroup);
2308
+ cb(userScaleGroup);
2309
+ userScaleGroup.setFixedZoom(options2.mapScale);
2310
+ userScaleGroup.idle();
2311
+ }, () => null, (error) => {
2312
+ console.error("Could not load model file: " + options2.obj + " \n " + error.stack);
2313
+ promise("Error loading the model");
2314
+ });
2315
+ }
2316
+ function normalizeSpecular(model) {
2317
+ model.traverse(function(c) {
2318
+ if (c.isMesh) {
2319
+ let specularColor;
2320
+ if (c.material.type == "MeshStandardMaterial") {
2321
+ if (c.material.metalness) {
2322
+ c.material.metalness *= 0.1;
2323
+ }
2324
+ if (c.material.glossiness) {
2325
+ c.material.glossiness *= 0.25;
2326
+ }
2327
+ specularColor = new THREE.Color(12, 12, 12);
2328
+ } else if (c.material.type == "MeshPhongMaterial") {
2329
+ c.material.shininess = 0.1;
2330
+ specularColor = new THREE.Color(20, 20, 20);
2331
+ }
2332
+ if (c.material.specular && c.material.specular.isColor) {
2333
+ c.material.specular = specularColor;
2334
+ }
2335
+ }
2336
+ });
2337
+ }
2338
+ }
2339
+ function line(obj) {
2340
+ obj = utils._validate(obj, Objects.prototype._defaults.line);
2341
+ var straightProject = utils.lnglatsToWorld(obj.geometry);
2342
+ var normalized = utils.normalizeVertices(straightProject);
2343
+ var flattenedArray = utils.flattenVectors(normalized.vertices);
2344
+ var geometry = new LineGeometry();
2345
+ geometry.setPositions(flattenedArray);
2346
+ let matLine = new LineMaterial({
2347
+ color: obj.color,
2348
+ linewidth: obj.width,
2349
+ // in pixels
2350
+ dashed: false,
2351
+ opacity: obj.opacity
2352
+ });
2353
+ matLine.resolution.set(window.innerWidth, window.innerHeight);
2354
+ matLine.isMaterial = true;
2355
+ matLine.transparent = true;
2356
+ matLine.depthWrite = false;
2357
+ let lineObj = new Line2(geometry, matLine);
2358
+ lineObj.position.copy(normalized.position);
2359
+ lineObj.computeLineDistances();
2360
+ return lineObj;
2361
+ }
2362
+ function tube(opt, world) {
2363
+ opt = utils._validate(opt, Objects.prototype._defaults.tube);
2364
+ let points = [];
2365
+ opt.geometry.forEach((p) => {
2366
+ points.push(new THREE.Vector3(p[0], p[1], p[2]));
2367
+ });
2368
+ const curve = new THREE.CatmullRomCurve3(points);
2369
+ let tube2 = new THREE.TubeGeometry(curve, points.length, opt.radius, opt.sides, false);
2370
+ let mat = material(opt);
2371
+ let obj = new THREE.Mesh(tube2, mat);
2372
+ return new Object3D({ obj, units: opt.units, anchor: opt.anchor, adjustment: opt.adjustment, bbox: opt.bbox, tooltip: opt.tooltip, raycasted: opt.raycasted });
2373
+ }
2374
+ function LabelRenderer(map) {
2375
+ this.map = map;
2376
+ this.renderer = new CSS2DRenderer();
2377
+ this.renderer.setSize(this.map.getCanvas().clientWidth, this.map.getCanvas().clientHeight);
2378
+ this.renderer.domElement.style.position = "absolute";
2379
+ this.renderer.domElement.id = "labelCanvas";
2380
+ this.renderer.domElement.style.top = 0;
2381
+ this.renderer.domElement.style.zIndex = "0";
2382
+ this.map.getCanvasContainer().appendChild(this.renderer.domElement);
2383
+ this.scene, this.camera;
2384
+ this.dispose = function() {
2385
+ this.map.getCanvasContainer().removeChild(this.renderer.domElement);
2386
+ this.renderer.domElement.remove();
2387
+ this.renderer = {};
2388
+ };
2389
+ this.setSize = function(width, height) {
2390
+ this.renderer.setSize(width, height);
2391
+ };
2392
+ this.map.on("resize", (function() {
2393
+ this.renderer.setSize(this.map.getCanvas().clientWidth, this.map.getCanvas().clientHeight);
2394
+ }).bind(this));
2395
+ this.state = {
2396
+ reset: function() {
2397
+ }
2398
+ };
2399
+ this.render = async function(scene, camera) {
2400
+ this.scene = scene;
2401
+ this.camera = camera;
2402
+ return new Promise((resolve) => {
2403
+ resolve(this.renderer.render(scene, camera));
2404
+ });
2405
+ };
2406
+ this.toggleLabels = async function(layerId, visible) {
2407
+ return new Promise((resolve) => {
2408
+ resolve(this.setVisibility(layerId, visible, this.scene, this.camera, this.renderer));
2409
+ });
2410
+ };
2411
+ this.setVisibility = function(layerId, visible, scene, camera, renderer2) {
2412
+ var cache = this.renderer.cacheList;
2413
+ cache.forEach(function(l) {
2414
+ if (l.visible != visible && l.layer === layerId) {
2415
+ if (visible && l.alwaysVisible || !visible) {
2416
+ l.visible = visible;
2417
+ renderer2.renderObject(l, scene, camera);
2418
+ }
2419
+ }
2420
+ });
2421
+ };
2422
+ }
2423
+ class BuildingShadows {
2424
+ constructor(options2, threebox) {
2425
+ this.id = options2.layerId;
2426
+ this.type = "custom";
2427
+ this.renderingMode = "3d";
2428
+ this.opacity = 0.5;
2429
+ this.buildingsLayerId = options2.buildingsLayerId;
2430
+ this.minAltitude = options2.minAltitude || 0.1;
2431
+ this.tb = threebox;
2432
+ }
2433
+ onAdd(map, gl) {
2434
+ this.map = map;
2435
+ const sourceName = this.map.getLayer(this.buildingsLayerId).source;
2436
+ this.source = (this.map.style.sourceCaches || this.map.style._otherSourceCaches)[sourceName];
2437
+ if (!this.source) {
2438
+ console.warn(`Can't find layer ${this.buildingsLayerId}'s source.`);
2439
+ }
2440
+ const vertexSource = this._getVertexSource();
2441
+ const fragmentSource = `
2442
+ void main() {
2443
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 0.7);
2444
+ }
2445
+ `;
2446
+ const vertexShader = gl.createShader(gl.VERTEX_SHADER);
2447
+ gl.shaderSource(vertexShader, vertexSource);
2448
+ gl.compileShader(vertexShader);
2449
+ const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
2450
+ gl.shaderSource(fragmentShader, fragmentSource);
2451
+ gl.compileShader(fragmentShader);
2452
+ this.program = gl.createProgram();
2453
+ gl.attachShader(this.program, vertexShader);
2454
+ gl.attachShader(this.program, fragmentShader);
2455
+ gl.linkProgram(this.program);
2456
+ gl.validateProgram(this.program);
2457
+ this.uMatrix = gl.getUniformLocation(this.program, "u_matrix");
2458
+ this.uHeightFactor = gl.getUniformLocation(this.program, "u_height_factor");
2459
+ this.uAltitude = gl.getUniformLocation(this.program, "u_altitude");
2460
+ this.uAzimuth = gl.getUniformLocation(this.program, "u_azimuth");
2461
+ if (this.tb.mapboxVersion >= 2) {
2462
+ this.aPosNormal = gl.getAttribLocation(this.program, "a_pos_normal_ed");
2463
+ } else {
2464
+ this.aPos = gl.getAttribLocation(this.program, "a_pos");
2465
+ this.aNormal = gl.getAttribLocation(this.program, "a_normal_ed");
2466
+ }
2467
+ this.aBase = gl.getAttribLocation(this.program, "a_base");
2468
+ this.aHeight = gl.getAttribLocation(this.program, "a_height");
2469
+ }
2470
+ render(gl, matrix) {
2471
+ if (!this.source) return;
2472
+ gl.useProgram(this.program);
2473
+ const coords = this.source.getVisibleCoordinates().reverse();
2474
+ const buildingsLayer = this.map.getLayer(this.buildingsLayerId);
2475
+ const context = this.map.painter.context;
2476
+ const { lng, lat } = this.map.getCenter();
2477
+ const pos = this.tb.getSunPosition(this.tb.lightDateTime, [lng, lat]);
2478
+ gl.uniform1f(this.uAltitude, pos.altitude > this.minAltitude ? pos.altitude : 0);
2479
+ gl.uniform1f(this.uAzimuth, pos.azimuth + 3 * Math.PI / 2);
2480
+ gl.enable(gl.BLEND);
2481
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
2482
+ gl.getExtension("EXT_blend_minmax");
2483
+ gl.disable(gl.DEPTH_TEST);
2484
+ for (const coord of coords) {
2485
+ const tile = this.source.getTile(coord);
2486
+ const bucket = tile.getBucket(buildingsLayer);
2487
+ if (!bucket) continue;
2488
+ const [heightBuffer, baseBuffer] = bucket.programConfigurations.programConfigurations[this.buildingsLayerId]._buffers;
2489
+ gl.uniformMatrix4fv(this.uMatrix, false, coord.posMatrix || coord.projMatrix);
2490
+ gl.uniform1f(this.uHeightFactor, Math.pow(2, coord.overscaledZ) / tile.tileSize / 8);
2491
+ for (const segment of bucket.segments.get()) {
2492
+ const numPrevAttrib = context.currentNumAttributes || 0;
2493
+ const numNextAttrib = 2;
2494
+ for (let i = numNextAttrib; i < numPrevAttrib; i++) gl.disableVertexAttribArray(i);
2495
+ const vertexOffset = segment.vertexOffset || 0;
2496
+ gl.enableVertexAttribArray(this.aNormal);
2497
+ gl.enableVertexAttribArray(this.aHeight);
2498
+ gl.enableVertexAttribArray(this.aBase);
2499
+ bucket.layoutVertexBuffer.bind();
2500
+ if (this.tb.mapboxVersion >= 2) {
2501
+ gl.enableVertexAttribArray(this.aPosNormal);
2502
+ gl.vertexAttribPointer(this.aPosNormal, 4, gl.SHORT, false, 8, 8 * vertexOffset);
2503
+ } else {
2504
+ gl.enableVertexAttribArray(this.aPos);
2505
+ gl.vertexAttribPointer(this.aPos, 2, gl.SHORT, false, 12, 12 * vertexOffset);
2506
+ gl.vertexAttribPointer(this.aNormal, 4, gl.SHORT, false, 12, 4 + 12 * vertexOffset);
2507
+ }
2508
+ heightBuffer.bind();
2509
+ gl.vertexAttribPointer(this.aHeight, 1, gl.FLOAT, false, 4, 4 * vertexOffset);
2510
+ baseBuffer.bind();
2511
+ gl.vertexAttribPointer(this.aBase, 1, gl.FLOAT, false, 4, 4 * vertexOffset);
2512
+ bucket.indexBuffer.bind();
2513
+ context.currentNumAttributes = numNextAttrib;
2514
+ gl.drawElements(gl.TRIANGLES, segment.primitiveLength * 3, gl.UNSIGNED_SHORT, segment.primitiveOffset * 3 * 2);
2515
+ }
2516
+ }
2517
+ }
2518
+ _getVertexSource() {
2519
+ if (this.tb.mapboxVersion >= 2) {
2520
+ return `
2521
+ uniform mat4 u_matrix;
2522
+ uniform float u_height_factor;
2523
+ uniform float u_altitude;
2524
+ uniform float u_azimuth;
2525
+ attribute vec4 a_pos_normal_ed;
2526
+ attribute lowp vec2 a_base;
2527
+ attribute lowp vec2 a_height;
2528
+ void main() {
2529
+ float base = max(0.0, a_base.x);
2530
+ float height = max(0.0, a_height.x);
2531
+
2532
+ vec3 pos_nx = floor(a_pos_normal_ed.xyz * 0.5);
2533
+ mediump vec3 top_up_ny = a_pos_normal_ed.xyz - 2.0 * pos_nx;
2534
+ float t = top_up_ny.x;
2535
+ vec4 pos = vec4(pos_nx.xy, t > 0.0 ? height : base, 1);
2536
+
2537
+ float len = pos.z * u_height_factor / tan(u_altitude);
2538
+ pos.x += cos(u_azimuth) * len;
2539
+ pos.y += sin(u_azimuth) * len;
2540
+ pos.z = 0.0;
2541
+ gl_Position = u_matrix * pos;
2542
+ }
2543
+ `;
2544
+ } else {
2545
+ return `
2546
+ uniform mat4 u_matrix;
2547
+ uniform float u_height_factor;
2548
+ uniform float u_altitude;
2549
+ uniform float u_azimuth;
2550
+ attribute vec2 a_pos;
2551
+ attribute vec4 a_normal_ed;
2552
+ attribute lowp vec2 a_base;
2553
+ attribute lowp vec2 a_height;
2554
+ void main() {
2555
+ float base = max(0.0, a_base.x);
2556
+ float height = max(0.0, a_height.x);
2557
+ float t = mod(a_normal_ed.x, 2.0);
2558
+ vec4 pos = vec4(a_pos, t > 0.0 ? height : base, 1);
2559
+ float len = pos.z * u_height_factor / tan(u_altitude);
2560
+ pos.x += cos(u_azimuth) * len;
2561
+ pos.y += sin(u_azimuth) * len;
2562
+ pos.z = 0.0;
2563
+ gl_Position = u_matrix * pos;
2564
+ }
2565
+ `;
2566
+ }
2567
+ }
2568
+ }
2569
+ function Threebox(map, glContext, options2) {
2570
+ this.init(map, glContext, options2);
2571
+ }
2572
+ Threebox.prototype = {
2573
+ repaint: function() {
2574
+ this.map.repaint = true;
2575
+ },
2576
+ /**
2577
+ * Threebox constructor init method
2578
+ * @param {mapboxgl.map} map
2579
+ * @param {WebGLRenderingContext} glContext
2580
+ * @param {defaultOptions} options
2581
+ */
2582
+ init: function(map, glContext, options2) {
2583
+ this.options = utils._validate(options2 || {}, defaultOptions);
2584
+ this.map = map;
2585
+ this.map.tb = this;
2586
+ this.objects = new Objects();
2587
+ this.mapboxVersion = parseFloat(this.map.version);
2588
+ this.renderer = new THREE.WebGLRenderer({
2589
+ alpha: true,
2590
+ antialias: true,
2591
+ preserveDrawingBuffer: options2.preserveDrawingBuffer,
2592
+ canvas: map.getCanvas(),
2593
+ context: glContext
2594
+ });
2595
+ this.renderer.setPixelRatio(window.devicePixelRatio);
2596
+ this.renderer.setSize(this.map.getCanvas().clientWidth, this.map.getCanvas().clientHeight);
2597
+ this.renderer.outputColorSpace = THREE.SRGBColorSpace;
2598
+ this.renderer.autoClear = false;
2599
+ this.labelRenderer = new LabelRenderer(this.map);
2600
+ this.scene = new THREE.Scene();
2601
+ this.world = new THREE.Group();
2602
+ this.world.name = "world";
2603
+ this.scene.add(this.world);
2604
+ this.objectsCache = /* @__PURE__ */ new Map();
2605
+ this.zoomLayers = [];
2606
+ this.fov = this.options.fov;
2607
+ this.orthographic = this.options.orthographic || false;
2608
+ this.raycaster = new THREE.Raycaster();
2609
+ this.raycaster.layers.set(0);
2610
+ this.mapCenter = this.map.getCenter();
2611
+ this.mapCenterUnits = utils.projectToWorld([this.mapCenter.lng, this.mapCenter.lat]);
2612
+ this.lightDateTime = /* @__PURE__ */ new Date();
2613
+ this.lightLng = this.mapCenter.lng;
2614
+ this.lightLat = this.mapCenter.lat;
2615
+ this.sunPosition;
2616
+ this.rotationStep = 5;
2617
+ this.gridStep = 6;
2618
+ this.altitudeStep = 0.1;
2619
+ this.defaultCursor = "default";
2620
+ this.lights = this.initLights;
2621
+ if (this.options.defaultLights) this.defaultLights();
2622
+ if (this.options.realSunlight) this.realSunlight(this.options.realSunlightHelper);
2623
+ this.skyLayerName = "sky-layer";
2624
+ this.terrainSourceName = "mapbox-dem";
2625
+ this.terrainExaggeration = 1;
2626
+ this.terrainLayerName = "";
2627
+ this.enableSelectingFeatures = this.options.enableSelectingFeatures || false;
2628
+ this.enableSelectingObjects = this.options.enableSelectingObjects || false;
2629
+ this.enableDraggingObjects = this.options.enableDraggingObjects || false;
2630
+ this.enableRotatingObjects = this.options.enableRotatingObjects || false;
2631
+ this.enableTooltips = this.options.enableTooltips || false;
2632
+ this.multiLayer = this.options.multiLayer || false;
2633
+ this.enableHelpTooltips = this.options.enableHelpTooltips || false;
2634
+ this.map.on("style.load", function() {
2635
+ this.tb.zoomLayers = [];
2636
+ if (this.tb.options.multiLayer) this.addLayer({ id: "threebox_layer", type: "custom", renderingMode: "3d", map: this, onAdd: function(map2, gl) {
2637
+ }, render: function(gl, matrix) {
2638
+ this.map.tb.update();
2639
+ } });
2640
+ this.once("idle", () => {
2641
+ this.tb.setObjectsScale();
2642
+ });
2643
+ if (this.tb.options.sky) {
2644
+ this.tb.sky = true;
2645
+ }
2646
+ if (this.tb.options.terrain) {
2647
+ this.tb.terrain = true;
2648
+ }
2649
+ let rasterLayers = ["satellite", "mapbox-mapbox-satellite", "satelliteLayer"];
2650
+ rasterLayers.forEach((l) => {
2651
+ if (this.getLayer(l)) this.tb.terrainLayerName = l;
2652
+ });
2653
+ });
2654
+ this.map.on("load", function() {
2655
+ this.selectedObject;
2656
+ this.selectedFeature;
2657
+ this.draggedObject;
2658
+ let draggedAction;
2659
+ this.overedObject;
2660
+ this.overedFeature;
2661
+ let canvas = this.getCanvasContainer();
2662
+ this.getCanvasContainer().style.cursor = this.tb.defaultCursor;
2663
+ let start;
2664
+ let startCoords = [];
2665
+ let lngDiff;
2666
+ let latDiff;
2667
+ let altDiff;
2668
+ let rotationDiff;
2669
+ function mousePos(e2) {
2670
+ var rect = canvas.getBoundingClientRect();
2671
+ return {
2672
+ x: e2.originalEvent.clientX - rect.left - canvas.clientLeft,
2673
+ y: e2.originalEvent.clientY - rect.top - canvas.clientTop
2674
+ };
2675
+ }
2676
+ this.unselectObject = function() {
2677
+ this.selectedObject.selected = false;
2678
+ this.selectedObject = null;
2679
+ };
2680
+ this.outObject = function() {
2681
+ this.overedObject.over = false;
2682
+ this.overedObject = null;
2683
+ };
2684
+ this.unselectFeature = function(f) {
2685
+ if (typeof f.id == "undefined") return;
2686
+ this.setFeatureState(
2687
+ { source: f.source, sourceLayer: f.sourceLayer, id: f.id },
2688
+ { select: false }
2689
+ );
2690
+ this.removeTooltip(f);
2691
+ f = this.queryRenderedFeatures({ layers: [f.layer.id], filter: ["==", ["id"], f.id] })[0];
2692
+ if (f) this.fire("SelectedFeatureChange", { detail: f });
2693
+ this.selectedFeature = null;
2694
+ };
2695
+ this.selectFeature = function(f) {
2696
+ this.selectedFeature = f;
2697
+ this.setFeatureState(
2698
+ { source: this.selectedFeature.source, sourceLayer: this.selectedFeature.sourceLayer, id: this.selectedFeature.id },
2699
+ { select: true }
2700
+ );
2701
+ this.selectedFeature = this.queryRenderedFeatures({ layers: [this.selectedFeature.layer.id], filter: ["==", ["id"], this.selectedFeature.id] })[0];
2702
+ this.addTooltip(this.selectedFeature);
2703
+ this.fire("SelectedFeatureChange", { detail: this.selectedFeature });
2704
+ };
2705
+ this.outFeature = function(f) {
2706
+ if (this.overedFeature && typeof this.overedFeature != "undefined" && this.overedFeature.id != f) {
2707
+ map.setFeatureState(
2708
+ { source: this.overedFeature.source, sourceLayer: this.overedFeature.sourceLayer, id: this.overedFeature.id },
2709
+ { hover: false }
2710
+ );
2711
+ this.removeTooltip(this.overedFeature);
2712
+ this.overedFeature = null;
2713
+ }
2714
+ };
2715
+ this.addTooltip = function(f) {
2716
+ if (!this.tb.enableTooltips) return;
2717
+ let coordinates = this.tb.getFeatureCenter(f);
2718
+ let t = this.tb.tooltip({
2719
+ text: f.properties.name || f.id || f.type,
2720
+ mapboxStyle: true,
2721
+ feature: f
2722
+ });
2723
+ t.setCoords(coordinates);
2724
+ this.tb.add(t, f.layer.id);
2725
+ f.tooltip = t;
2726
+ f.tooltip.tooltip.visible = true;
2727
+ };
2728
+ this.removeTooltip = function(f) {
2729
+ if (f.tooltip) {
2730
+ f.tooltip.visibility = false;
2731
+ this.tb.remove(f.tooltip);
2732
+ f.tooltip = null;
2733
+ }
2734
+ };
2735
+ map.onContextMenu = function(e2) {
2736
+ alert("contextMenu");
2737
+ };
2738
+ this.onClick = function(e2) {
2739
+ let intersectionExists;
2740
+ let intersects = [];
2741
+ if (map.tb.enableSelectingObjects) {
2742
+ intersects = this.tb.queryRenderedFeatures(e2.point);
2743
+ }
2744
+ intersectionExists = typeof intersects[0] == "object";
2745
+ if (intersectionExists) {
2746
+ let nearestObject = Threebox.prototype.findParent3DObject(intersects[0]);
2747
+ if (nearestObject) {
2748
+ if (this.selectedFeature) {
2749
+ this.unselectFeature(this.selectedFeature);
2750
+ }
2751
+ if (!this.selectedObject) {
2752
+ this.selectedObject = nearestObject;
2753
+ this.selectedObject.selected = true;
2754
+ } else if (this.selectedObject.uuid != nearestObject.uuid) {
2755
+ this.selectedObject.selected = false;
2756
+ nearestObject.selected = true;
2757
+ this.selectedObject = nearestObject;
2758
+ } else if (this.selectedObject.uuid == nearestObject.uuid) {
2759
+ this.unselectObject();
2760
+ return;
2761
+ }
2762
+ this.selectedObject.dispatchEvent({ type: "Wireframed", detail: this.selectedObject });
2763
+ this.selectedObject.dispatchEvent({ type: "IsPlayingChanged", detail: this.selectedObject });
2764
+ this.repaint = true;
2765
+ e2.preventDefault();
2766
+ }
2767
+ } else {
2768
+ let features = [];
2769
+ if (map.tb.enableSelectingFeatures) {
2770
+ features = this.queryRenderedFeatures(e2.point);
2771
+ }
2772
+ if (features.length > 0) {
2773
+ if (features[0].layer.type == "fill-extrusion" && typeof features[0].id != "undefined") {
2774
+ if (this.selectedObject) {
2775
+ this.unselectObject();
2776
+ }
2777
+ if (!this.selectedFeature) {
2778
+ this.selectFeature(features[0]);
2779
+ } else if (this.selectedFeature.id != features[0].id) {
2780
+ this.unselectFeature(this.selectedFeature);
2781
+ this.selectFeature(features[0]);
2782
+ } else if (this.selectedFeature.id == features[0].id) {
2783
+ this.unselectFeature(this.selectedFeature);
2784
+ return;
2785
+ }
2786
+ }
2787
+ }
2788
+ }
2789
+ };
2790
+ this.onMouseMove = function(e2) {
2791
+ let current = mousePos(e2);
2792
+ this.getCanvasContainer().style.cursor = this.tb.defaultCursor;
2793
+ if (e2.originalEvent.altKey && this.draggedObject) {
2794
+ if (!map.tb.enableRotatingObjects) return;
2795
+ draggedAction = "rotate";
2796
+ this.getCanvasContainer().style.cursor = "move";
2797
+ Math.min(start.x, current.x);
2798
+ Math.max(start.x, current.x);
2799
+ Math.min(start.y, current.y);
2800
+ Math.max(start.y, current.y);
2801
+ let rotation = { x: 0, y: 0, z: Math.round(rotationDiff[2] + ~~((current.x - start.x) / this.tb.rotationStep) % 360 * this.tb.rotationStep % 360) };
2802
+ this.draggedObject.setRotation(rotation);
2803
+ if (map.tb.enableHelpTooltips) this.draggedObject.addHelp("rot: " + rotation.z + "&#176;");
2804
+ return;
2805
+ }
2806
+ if (e2.originalEvent.shiftKey && this.draggedObject) {
2807
+ if (!map.tb.enableDraggingObjects) return;
2808
+ draggedAction = "translate";
2809
+ this.getCanvasContainer().style.cursor = "move";
2810
+ let coords = e2.lngLat;
2811
+ let options3 = [Number((coords.lng + lngDiff).toFixed(this.tb.gridStep)), Number((coords.lat + latDiff).toFixed(this.tb.gridStep)), this.draggedObject.modelHeight];
2812
+ this.draggedObject.setCoords(options3);
2813
+ if (map.tb.enableHelpTooltips) this.draggedObject.addHelp("lng: " + options3[0] + "&#176;, lat: " + options3[1] + "&#176;");
2814
+ return;
2815
+ }
2816
+ if (e2.originalEvent.ctrlKey && this.draggedObject) {
2817
+ if (!map.tb.enableDraggingObjects) return;
2818
+ draggedAction = "altitude";
2819
+ this.getCanvasContainer().style.cursor = "move";
2820
+ let now = e2.point.y * this.tb.altitudeStep;
2821
+ let options3 = [this.draggedObject.coordinates[0], this.draggedObject.coordinates[1], Number((-now - altDiff).toFixed(this.tb.gridStep))];
2822
+ this.draggedObject.setCoords(options3);
2823
+ if (map.tb.enableHelpTooltips) this.draggedObject.addHelp("alt: " + options3[2] + "m");
2824
+ return;
2825
+ }
2826
+ let intersectionExists;
2827
+ let intersects = [];
2828
+ if (map.tb.enableSelectingObjects) {
2829
+ intersects = this.tb.queryRenderedFeatures(e2.point);
2830
+ }
2831
+ intersectionExists = typeof intersects[0] == "object";
2832
+ if (intersectionExists) {
2833
+ let nearestObject = Threebox.prototype.findParent3DObject(intersects[0]);
2834
+ if (nearestObject) {
2835
+ this.outFeature(this.overedFeature);
2836
+ this.getCanvasContainer().style.cursor = "pointer";
2837
+ if (!this.selectedObject || nearestObject.uuid != this.selectedObject.uuid) {
2838
+ if (this.overedObject && this.overedObject.uuid != nearestObject.uuid) {
2839
+ this.outObject();
2840
+ }
2841
+ nearestObject.over = true;
2842
+ this.overedObject = nearestObject;
2843
+ } else if (this.selectedObject && nearestObject.uuid == this.selectedObject.uuid) {
2844
+ nearestObject.over = true;
2845
+ this.overedObject = nearestObject;
2846
+ }
2847
+ this.repaint = true;
2848
+ e2.preventDefault();
2849
+ }
2850
+ } else {
2851
+ if (this.overedObject) {
2852
+ this.outObject();
2853
+ }
2854
+ let features = [];
2855
+ if (map.tb.enableSelectingFeatures) {
2856
+ features = this.queryRenderedFeatures(e2.point);
2857
+ }
2858
+ if (features.length > 0) {
2859
+ this.outFeature(features[0]);
2860
+ if (features[0].layer.type == "fill-extrusion" && typeof features[0].id != "undefined") {
2861
+ if (!this.selectedFeature || this.selectedFeature.id != features[0].id) {
2862
+ this.getCanvasContainer().style.cursor = "pointer";
2863
+ this.overedFeature = features[0];
2864
+ this.setFeatureState(
2865
+ { source: this.overedFeature.source, sourceLayer: this.overedFeature.sourceLayer, id: this.overedFeature.id },
2866
+ { hover: true }
2867
+ );
2868
+ this.overedFeature = map.queryRenderedFeatures({ layers: [this.overedFeature.layer.id], filter: ["==", ["id"], this.overedFeature.id] })[0];
2869
+ this.addTooltip(this.overedFeature);
2870
+ }
2871
+ }
2872
+ }
2873
+ }
2874
+ };
2875
+ this.onMouseDown = function(e2) {
2876
+ if (!((e2.originalEvent.shiftKey || e2.originalEvent.altKey || e2.originalEvent.ctrlKey) && e2.originalEvent.button === 0 && this.selectedObject)) return;
2877
+ if (!map.tb.enableDraggingObjects && !map.tb.enableRotatingObjects) return;
2878
+ e2.preventDefault();
2879
+ map.getCanvasContainer().style.cursor = "move";
2880
+ map.once("mouseup", this.onMouseUp);
2881
+ this.draggedObject = this.selectedObject;
2882
+ start = mousePos(e2);
2883
+ startCoords = this.draggedObject.coordinates;
2884
+ rotationDiff = utils.degreeify(this.draggedObject.rotation);
2885
+ lngDiff = startCoords[0] - e2.lngLat.lng;
2886
+ latDiff = startCoords[1] - e2.lngLat.lat;
2887
+ altDiff = -this.draggedObject.modelHeight - e2.point.y * this.tb.altitudeStep;
2888
+ };
2889
+ this.onMouseUp = function(e2) {
2890
+ this.getCanvasContainer().style.cursor = this.tb.defaultCursor;
2891
+ this.off("mouseup", this.onMouseUp);
2892
+ this.off("mouseout", this.onMouseUp);
2893
+ this.dragPan.enable();
2894
+ if (this.draggedObject) {
2895
+ this.draggedObject.dispatchEvent({ type: "ObjectDragged", detail: { draggedObject: this.draggedObject, draggedAction } });
2896
+ this.draggedObject.removeHelp();
2897
+ this.draggedObject = null;
2898
+ draggedAction = null;
2899
+ }
2900
+ };
2901
+ this.onMouseOut = function(e2) {
2902
+ if (this.overedFeature) {
2903
+ let features = this.queryRenderedFeatures(e2.point);
2904
+ if (features.length > 0 && this.overedFeature.id != features[0].id) {
2905
+ this.getCanvasContainer().style.cursor = this.tb.defaultCursor;
2906
+ this.outFeature(features[0]);
2907
+ }
2908
+ }
2909
+ };
2910
+ this.onZoom = function(e2) {
2911
+ this.tb.zoomLayers.forEach((l) => {
2912
+ this.tb.toggleLayer(l);
2913
+ });
2914
+ this.tb.setObjectsScale();
2915
+ };
2916
+ let shiftDown = false;
2917
+ let ctrlKey = 17, cmdKey = 91, shiftKey = 16, sK = 83;
2918
+ function onKeyDown(e2) {
2919
+ if (e2.which === ctrlKey || e2.which === cmdKey) ;
2920
+ if (e2.which === shiftKey) shiftDown = true;
2921
+ let obj = this.selectedObject;
2922
+ if (shiftDown && e2.which === sK && obj) {
2923
+ let dc = utils.toDecimal;
2924
+ if (!obj.help) {
2925
+ let s = obj.modelSize;
2926
+ let sf = 1;
2927
+ if (obj.userData.units !== "meters") {
2928
+ sf = utils.projectedUnitsPerMeter(obj.coordinates[1]);
2929
+ if (!sf) {
2930
+ sf = 1;
2931
+ }
2932
+ sf = dc(sf, 7);
2933
+ }
2934
+ if (map.tb.enableHelpTooltips) obj.addHelp("size(m): " + dc(s.x / sf, 3) + " W, " + dc(s.y / sf, 3) + " L, " + dc(s.z / sf, 3) + " H");
2935
+ this.repaint = true;
2936
+ } else {
2937
+ obj.removeHelp();
2938
+ }
2939
+ return false;
2940
+ }
2941
+ }
2942
+ function onKeyUp(e2) {
2943
+ if (e2.which == ctrlKey || e2.which == cmdKey) ;
2944
+ if (e2.which === shiftKey) shiftDown = false;
2945
+ }
2946
+ this.on("click", this.onClick);
2947
+ this.on("mousemove", this.onMouseMove);
2948
+ this.on("mouseout", this.onMouseOut);
2949
+ this.on("mousedown", this.onMouseDown);
2950
+ this.on("zoom", this.onZoom);
2951
+ this.on("zoomend", this.onZoom);
2952
+ document.addEventListener("keydown", onKeyDown.bind(this), true);
2953
+ document.addEventListener("keyup", onKeyUp.bind(this));
2954
+ });
2955
+ },
2956
+ //[jscastro] added property to manage an athmospheric sky layer
2957
+ get sky() {
2958
+ return this.options.sky;
2959
+ },
2960
+ set sky(value) {
2961
+ if (value) {
2962
+ this.createSkyLayer();
2963
+ } else {
2964
+ this.removeLayer(this.skyLayerName);
2965
+ }
2966
+ this.options.sky = value;
2967
+ },
2968
+ //[jscastro] added property to manage an athmospheric sky layer
2969
+ get terrain() {
2970
+ return this.options.terrain;
2971
+ },
2972
+ set terrain(value) {
2973
+ this.terrainLayerName = "";
2974
+ if (value) {
2975
+ this.createTerrainLayer();
2976
+ } else {
2977
+ if (this.mapboxVersion < 2) {
2978
+ console.warn("Terrain layer are only supported by Mapbox-gl-js > v2.0");
2979
+ return;
2980
+ }
2981
+ if (this.map.getTerrain()) {
2982
+ this.map.setTerrain(null);
2983
+ this.map.removeSource(this.terrainSourceName);
2984
+ }
2985
+ }
2986
+ this.options.terrain = value;
2987
+ },
2988
+ //[jscastro] added property to manage FOV for perspective camera
2989
+ get fov() {
2990
+ return this.options.fov;
2991
+ },
2992
+ set fov(value) {
2993
+ if (this.camera instanceof THREE.PerspectiveCamera && this.options.fov !== value) {
2994
+ this.map.transform.fov = value;
2995
+ this.camera.fov = this.map.transform.fov;
2996
+ this.cameraSync.setupCamera();
2997
+ this.map.repaint = true;
2998
+ this.options.fov = value;
2999
+ }
3000
+ },
3001
+ //[jscastro] added property to manage camera type
3002
+ get orthographic() {
3003
+ return this.options.orthographic;
3004
+ },
3005
+ set orthographic(value) {
3006
+ const h = this.map.getCanvas().clientHeight;
3007
+ const w = this.map.getCanvas().clientWidth;
3008
+ if (value) {
3009
+ this.map.transform.fov = 0;
3010
+ this.camera = new THREE.OrthographicCamera(w / -2, w / 2, h / 2, h / -2, 0.1, 1e21);
3011
+ } else {
3012
+ this.map.transform.fov = this.fov;
3013
+ this.camera = new THREE.PerspectiveCamera(this.map.transform.fov, w / h, 0.1, 1e21);
3014
+ }
3015
+ this.camera.layers.enable(0);
3016
+ this.camera.layers.enable(1);
3017
+ this.cameraSync = new CameraSync(this.map, this.camera, this.world);
3018
+ this.map.repaint = true;
3019
+ this.options.orthographic = value;
3020
+ },
3021
+ //[jscastro] method to create an athmospheric sky layer
3022
+ createSkyLayer: function() {
3023
+ if (this.mapboxVersion < 2) {
3024
+ console.warn("Sky layer are only supported by Mapbox-gl-js > v2.0");
3025
+ this.options.sky = false;
3026
+ return;
3027
+ }
3028
+ let layer = this.map.getLayer(this.skyLayerName);
3029
+ if (!layer) {
3030
+ this.map.addLayer({
3031
+ "id": this.skyLayerName,
3032
+ "type": "sky",
3033
+ "paint": {
3034
+ "sky-opacity": [
3035
+ "interpolate",
3036
+ ["linear"],
3037
+ ["zoom"],
3038
+ 0,
3039
+ 0,
3040
+ 5,
3041
+ 0.3,
3042
+ 8,
3043
+ 1
3044
+ ],
3045
+ // set up the sky layer for atmospheric scattering
3046
+ "sky-type": "atmosphere",
3047
+ // explicitly set the position of the sun rather than allowing the sun to be attached to the main light source
3048
+ "sky-atmosphere-sun": this.getSunSky(this.lightDateTime),
3049
+ // set the intensity of the sun as a light source (0-100 with higher values corresponding to brighter skies)
3050
+ "sky-atmosphere-sun-intensity": 10
3051
+ }
3052
+ });
3053
+ this.map.once("idle", () => {
3054
+ this.setSunlight();
3055
+ this.repaint();
3056
+ });
3057
+ }
3058
+ },
3059
+ //[jscastro] method to create a terrain layer
3060
+ createTerrainLayer: function() {
3061
+ if (this.mapboxVersion < 2) {
3062
+ console.warn("Terrain layer are only supported by Mapbox-gl-js > v2.0");
3063
+ this.options.terrain = false;
3064
+ return;
3065
+ }
3066
+ let layer = this.map.getTerrain();
3067
+ if (!layer) {
3068
+ this.map.addSource(this.terrainSourceName, {
3069
+ "type": "raster-dem",
3070
+ "url": "mapbox://mapbox.mapbox-terrain-dem-v1",
3071
+ "tileSize": 512,
3072
+ "maxzoom": 14
3073
+ });
3074
+ this.map.setTerrain({ "source": this.terrainSourceName, "exaggeration": this.terrainExaggeration });
3075
+ this.map.once("idle", () => {
3076
+ this.cameraSync.updateCamera();
3077
+ this.repaint();
3078
+ });
3079
+ }
3080
+ },
3081
+ // Objects
3082
+ sphere: function(options2) {
3083
+ this.setDefaultView(options2, this.options);
3084
+ return Sphere(options2, this.world);
3085
+ },
3086
+ line,
3087
+ label: Label,
3088
+ tooltip: Tooltip,
3089
+ tube: function(options2) {
3090
+ this.setDefaultView(options2, this.options);
3091
+ return tube(options2, this.world);
3092
+ },
3093
+ extrusion: function(options2) {
3094
+ this.setDefaultView(options2, this.options);
3095
+ return extrusion(options2);
3096
+ },
3097
+ Object3D: function(options2) {
3098
+ this.setDefaultView(options2, this.options);
3099
+ return Object3D(options2);
3100
+ },
3101
+ loadObj: async function loadObj$1(options2, cb) {
3102
+ this.setDefaultView(options2, this.options);
3103
+ if (options2.clone === false) {
3104
+ return new Promise(
3105
+ async (resolve) => {
3106
+ loadObj(options2, cb, async (obj) => {
3107
+ resolve(obj);
3108
+ });
3109
+ }
3110
+ );
3111
+ } else {
3112
+ let cache = this.objectsCache.get(options2.obj);
3113
+ if (cache) {
3114
+ cache.promise.then((obj) => {
3115
+ cb(obj.duplicate(options2));
3116
+ }).catch((err) => {
3117
+ this.objectsCache.delete(options2.obj);
3118
+ console.error("Could not load model file: " + options2.obj);
3119
+ });
3120
+ } else {
3121
+ this.objectsCache.set(options2.obj, {
3122
+ promise: new Promise(
3123
+ async (resolve, reject) => {
3124
+ loadObj(options2, cb, async (obj) => {
3125
+ if (obj.duplicate) {
3126
+ resolve(obj.duplicate());
3127
+ } else {
3128
+ reject(obj);
3129
+ }
3130
+ });
3131
+ }
3132
+ )
3133
+ });
3134
+ }
3135
+ }
3136
+ },
3137
+ // Material
3138
+ material: function(o2) {
3139
+ return material(o2);
3140
+ },
3141
+ initLights: {
3142
+ ambientLight: null,
3143
+ dirLight: null,
3144
+ dirLightBack: null,
3145
+ dirLightHelper: null,
3146
+ hemiLight: null,
3147
+ pointLight: null
3148
+ },
3149
+ utils,
3150
+ SunCalc,
3151
+ Constants: ThreeboxConstants,
3152
+ projectToWorld: function(coords) {
3153
+ return this.utils.projectToWorld(coords);
3154
+ },
3155
+ unprojectFromWorld: function(v3) {
3156
+ return this.utils.unprojectFromWorld(v3);
3157
+ },
3158
+ projectedUnitsPerMeter: function(lat) {
3159
+ return this.utils.projectedUnitsPerMeter(lat);
3160
+ },
3161
+ //get the center point of a feature
3162
+ getFeatureCenter: function getFeatureCenter2(feature, obj, level) {
3163
+ return utils.getFeatureCenter(feature, obj, level);
3164
+ },
3165
+ getObjectHeightOnFloor: function(feature, obj, level) {
3166
+ return utils.getObjectHeightOnFloor(feature, obj, level);
3167
+ },
3168
+ queryRenderedFeatures: function(point) {
3169
+ let mouse = new THREE.Vector2();
3170
+ mouse.x = point.x / this.map.transform.width * 2 - 1;
3171
+ mouse.y = 1 - point.y / this.map.transform.height * 2;
3172
+ this.raycaster.setFromCamera(mouse, this.camera);
3173
+ let intersects = this.raycaster.intersectObjects(this.world.children, true);
3174
+ return intersects;
3175
+ },
3176
+ //[jscastro] find 3D object of a mesh. this method is needed to know the object of a raycasted mesh
3177
+ findParent3DObject: function(mesh) {
3178
+ var result;
3179
+ mesh.object.traverseAncestors(function(m) {
3180
+ if (m.parent) {
3181
+ if (m.parent.type == "Group" && m.userData.obj) {
3182
+ result = m;
3183
+ }
3184
+ }
3185
+ });
3186
+ return result;
3187
+ },
3188
+ //[jscastro] method to replicate behaviour of map.setLayoutProperty when Threebox are affected
3189
+ setLayoutProperty: function(layerId, name, value) {
3190
+ this.map.setLayoutProperty(layerId, name, value);
3191
+ if (value !== null && value !== void 0) {
3192
+ if (name === "visibility") {
3193
+ this.world.children.filter((o2) => o2.layer === layerId).forEach((o2) => {
3194
+ o2.visibility = value;
3195
+ });
3196
+ }
3197
+ }
3198
+ },
3199
+ //[jscastro] Custom Layers doesn't work on minzoom and maxzoom attributes, and if the layer is including labels they don't hide either on minzoom
3200
+ setLayerZoomRange: function(layerId, minZoomLayer, maxZoomLayer) {
3201
+ if (this.map.getLayer(layerId)) {
3202
+ this.map.setLayerZoomRange(layerId, minZoomLayer, maxZoomLayer);
3203
+ if (!this.zoomLayers.includes(layerId)) this.zoomLayers.push(layerId);
3204
+ this.toggleLayer(layerId);
3205
+ }
3206
+ },
3207
+ //[jscastro] method to set the height of all the objects in a level. this only works if the objects have a geojson feature
3208
+ setLayerHeigthProperty: function(layerId, level) {
3209
+ let layer = this.map.getLayer(layerId);
3210
+ if (!layer) return;
3211
+ if (layer.type == "fill-extrusion") {
3212
+ let data = this.map.getStyle().sources[layer.source].data;
3213
+ let features = data.features;
3214
+ features.forEach(function(f) {
3215
+ f.properties.level = level;
3216
+ });
3217
+ this.map.getSource(layer.source).setData(data);
3218
+ } else if (layer.type == "custom") {
3219
+ this.world.children.forEach(function(obj) {
3220
+ let feature = obj.userData.feature;
3221
+ if (feature && feature.layer === layerId) {
3222
+ let location = this.tb.getFeatureCenter(feature, obj, level);
3223
+ obj.setCoords(location);
3224
+ }
3225
+ });
3226
+ }
3227
+ },
3228
+ //[jscastro] method to set globally all the objects that are fixedScale
3229
+ setObjectsScale: function() {
3230
+ this.world.children.filter((o2) => o2.fixedZoom != null).forEach((o2) => {
3231
+ o2.setObjectScale(this.map.transform.scale);
3232
+ });
3233
+ },
3234
+ //[jscastro] mapbox setStyle removes all the layers, including custom layers, so tb.world must be cleaned up too
3235
+ setStyle: function(styleId, options2) {
3236
+ this.clear().then(() => {
3237
+ this.map.setStyle(styleId, options2);
3238
+ });
3239
+ },
3240
+ //[jscastro] method to toggle Layer visibility checking zoom range
3241
+ toggleLayer: function(layerId, visible = true) {
3242
+ let l = this.map.getLayer(layerId);
3243
+ if (l) {
3244
+ if (!visible) {
3245
+ this.toggle(l.id, false);
3246
+ return;
3247
+ }
3248
+ let z = this.map.getZoom();
3249
+ if (l.minzoom && z < l.minzoom) {
3250
+ this.toggle(l.id, false);
3251
+ return;
3252
+ }
3253
+ if (l.maxzoom && z >= l.maxzoom) {
3254
+ this.toggle(l.id, false);
3255
+ return;
3256
+ }
3257
+ this.toggle(l.id, true);
3258
+ }
3259
+ },
3260
+ //[jscastro] method to toggle Layer visibility
3261
+ toggle: function(layerId, visible) {
3262
+ this.setLayoutProperty(layerId, "visibility", visible ? "visible" : "none");
3263
+ this.labelRenderer.toggleLabels(layerId, visible);
3264
+ },
3265
+ update: function() {
3266
+ if (this.map.repaint) this.map.repaint = false;
3267
+ var timestamp = Date.now();
3268
+ this.objects.animationManager.update(timestamp);
3269
+ this.updateLightHelper();
3270
+ this.renderer.resetState();
3271
+ this.renderer.render(this.scene, this.camera);
3272
+ this.labelRenderer.render(this.scene, this.camera);
3273
+ if (this.options.passiveRendering === false) this.map.triggerRepaint();
3274
+ },
3275
+ add: function(obj, layerId, sourceId) {
3276
+ if (!this.enableTooltips && obj.tooltip) {
3277
+ obj.tooltip.visibility = false;
3278
+ }
3279
+ this.world.add(obj);
3280
+ if (layerId) {
3281
+ obj.layer = layerId;
3282
+ obj.source = sourceId;
3283
+ let l = this.map.getLayer(layerId);
3284
+ if (l) {
3285
+ let v = l.visibility;
3286
+ let u = typeof v === "undefined";
3287
+ obj.visibility = u || v === "visible" ? true : false;
3288
+ }
3289
+ }
3290
+ },
3291
+ removeByName: function(name) {
3292
+ let obj = this.world.getObjectByName(name);
3293
+ if (obj) this.remove(obj);
3294
+ },
3295
+ remove: function(obj) {
3296
+ if (this.map.selectedObject && obj.uuid == this.map.selectedObject.uuid) this.map.unselectObject();
3297
+ if (this.map.draggedObject && obj.uuid == this.map.draggedObject.uuid) this.map.draggedObject = null;
3298
+ if (obj.dispose) obj.dispose();
3299
+ this.world.remove(obj);
3300
+ obj = null;
3301
+ },
3302
+ //[jscastro] this clears tb.world in order to dispose properly the resources
3303
+ clear: async function(layerId = null, dispose = false) {
3304
+ return new Promise((resolve, reject) => {
3305
+ let objects = [];
3306
+ this.world.children.forEach(function(object) {
3307
+ objects.push(object);
3308
+ });
3309
+ for (let i = 0; i < objects.length; i++) {
3310
+ let obj = objects[i];
3311
+ if (obj.layer === layerId || !layerId) {
3312
+ this.remove(obj);
3313
+ }
3314
+ }
3315
+ if (dispose) {
3316
+ this.objectsCache.forEach((value) => {
3317
+ value.promise.then((obj) => {
3318
+ obj.dispose();
3319
+ obj = null;
3320
+ });
3321
+ });
3322
+ }
3323
+ resolve("clear");
3324
+ });
3325
+ },
3326
+ //[jscastro] remove a layer clearing first the 3D objects from this layer in tb.world
3327
+ removeLayer: function(layerId) {
3328
+ this.clear(layerId, true).then(() => {
3329
+ this.map.removeLayer(layerId);
3330
+ });
3331
+ },
3332
+ //[jscastro] get the sun position (azimuth, altitude) from a given datetime, lng, lat
3333
+ getSunPosition: function(date, coords) {
3334
+ return SunCalc.getPosition(date || Date.now(), coords[1], coords[0]);
3335
+ },
3336
+ //[jscastro] get the sun times for sunrise, sunset, etc.. from a given datetime, lng, lat and alt
3337
+ getSunTimes: function(date, coords) {
3338
+ return SunCalc.getTimes(date, coords[1], coords[0], coords[2] ? coords[2] : 0);
3339
+ },
3340
+ //[jscastro] set shadows for fill-extrusion layers
3341
+ setBuildingShadows: function(options2) {
3342
+ if (this.map.getLayer(options2.buildingsLayerId)) {
3343
+ let layer = new BuildingShadows(options2, this);
3344
+ this.map.addLayer(layer, options2.buildingsLayerId);
3345
+ } else {
3346
+ console.warn("The layer '" + options2.buildingsLayerId + "' does not exist in the map.");
3347
+ }
3348
+ },
3349
+ //[jscastro] This method set the sun light for a given datetime and lnglat
3350
+ setSunlight: function(newDate = /* @__PURE__ */ new Date(), coords) {
3351
+ if (!this.lights.dirLight || !this.options.realSunlight) {
3352
+ console.warn("To use setSunlight it's required to set realSunlight : true in Threebox initial options.");
3353
+ return;
3354
+ }
3355
+ var date = new Date(newDate.getTime());
3356
+ if (coords) {
3357
+ if (coords.lng && coords.lat) this.mapCenter = coords;
3358
+ else this.mapCenter = { lng: coords[0], lat: coords[1] };
3359
+ } else {
3360
+ this.mapCenter = this.map.getCenter();
3361
+ }
3362
+ if (this.lightDateTime && this.lightDateTime.getTime() === date.getTime() && this.lightLng === this.mapCenter.lng && this.lightLat === this.mapCenter.lat) {
3363
+ return;
3364
+ }
3365
+ this.lightDateTime = date;
3366
+ this.lightLng = this.mapCenter.lng;
3367
+ this.lightLat = this.mapCenter.lat;
3368
+ this.sunPosition = this.getSunPosition(date, [this.mapCenter.lng, this.mapCenter.lat]);
3369
+ let altitude2 = this.sunPosition.altitude;
3370
+ let azimuth2 = Math.PI + this.sunPosition.azimuth;
3371
+ let radius = ThreeboxConstants.WORLD_SIZE / 2;
3372
+ let alt = Math.sin(altitude2);
3373
+ let altRadius = Math.cos(altitude2);
3374
+ let azCos = Math.cos(azimuth2) * altRadius;
3375
+ let azSin = Math.sin(azimuth2) * altRadius;
3376
+ this.lights.dirLight.position.set(azSin, azCos, alt);
3377
+ this.lights.dirLight.position.multiplyScalar(radius);
3378
+ this.lights.dirLight.intensity = Math.max(alt, 0);
3379
+ this.lights.hemiLight.intensity = Math.max(alt * 1, 0.1);
3380
+ this.lights.dirLight.updateMatrixWorld();
3381
+ this.updateLightHelper();
3382
+ if (this.map.loaded()) {
3383
+ this.updateSunGround(this.sunPosition);
3384
+ this.map.setLight({
3385
+ anchor: "map",
3386
+ position: [3, 180 + this.sunPosition.azimuth * 180 / Math.PI, 90 - this.sunPosition.altitude * 180 / Math.PI],
3387
+ intensity: Math.cos(this.sunPosition.altitude),
3388
+ //0.4,
3389
+ color: `hsl(40, ${50 * Math.cos(this.sunPosition.altitude)}%, ${Math.max(20, 20 + 96 * Math.sin(this.sunPosition.altitude))}%)`
3390
+ }, { duration: 0 });
3391
+ if (this.sky) {
3392
+ this.updateSunSky(this.getSunSky(date, this.sunPosition));
3393
+ }
3394
+ }
3395
+ },
3396
+ getSunSky: function(date, sunPos) {
3397
+ if (!sunPos) {
3398
+ var center = this.map.getCenter();
3399
+ sunPos = this.getSunPosition(
3400
+ date || Date.now(),
3401
+ [center.lng, center.lat]
3402
+ );
3403
+ }
3404
+ var sunAzimuth = 180 + sunPos.azimuth * 180 / Math.PI;
3405
+ var sunAltitude = 90 - sunPos.altitude * 180 / Math.PI;
3406
+ return [sunAzimuth, sunAltitude];
3407
+ },
3408
+ updateSunSky: function(sunPos) {
3409
+ if (this.sky) {
3410
+ this.map.setPaintProperty(this.skyLayerName, "sky-atmosphere-sun", sunPos);
3411
+ }
3412
+ },
3413
+ updateSunGround: function(sunPos) {
3414
+ if (this.terrainLayerName != "") {
3415
+ this.map.setPaintProperty(this.terrainLayerName, "raster-opacity", Math.max(Math.min(1, sunPos.altitude * 4), 0.25));
3416
+ }
3417
+ },
3418
+ //[jscastro] this updates the directional light helper
3419
+ updateLightHelper: function() {
3420
+ if (this.lights.dirLightHelper) {
3421
+ this.lights.dirLightHelper.position.setFromMatrixPosition(this.lights.dirLight.matrixWorld);
3422
+ this.lights.dirLightHelper.updateMatrix();
3423
+ this.lights.dirLightHelper.update();
3424
+ }
3425
+ },
3426
+ //[jscastro] method to fully dispose the resources, watch out is you call this without navigating to other page
3427
+ dispose: async function() {
3428
+ console.log(this.memory());
3429
+ return new Promise((resolve) => {
3430
+ resolve(
3431
+ this.clear(null, true).then((resolve2) => {
3432
+ this.map.remove();
3433
+ this.map = {};
3434
+ this.scene.remove(this.world);
3435
+ this.world.children = [];
3436
+ this.world = null;
3437
+ this.objectsCache.clear();
3438
+ this.labelRenderer.dispose();
3439
+ console.log(this.memory());
3440
+ this.renderer.dispose();
3441
+ return resolve2;
3442
+ })
3443
+ );
3444
+ });
3445
+ },
3446
+ defaultLights: function() {
3447
+ this.lights.ambientLight = new THREE.AmbientLight(new THREE.Color("hsl(0, 0%, 100%)"), 0.75);
3448
+ this.scene.add(this.lights.ambientLight);
3449
+ this.lights.dirLightBack = new THREE.DirectionalLight(new THREE.Color("hsl(0, 0%, 100%)"), 0.25);
3450
+ this.lights.dirLightBack.position.set(30, 100, 100);
3451
+ this.scene.add(this.lights.dirLightBack);
3452
+ this.lights.dirLight = new THREE.DirectionalLight(new THREE.Color("hsl(0, 0%, 100%)"), 0.25);
3453
+ this.lights.dirLight.position.set(-30, 100, -100);
3454
+ this.scene.add(this.lights.dirLight);
3455
+ },
3456
+ realSunlight: function(helper = false) {
3457
+ this.renderer.shadowMap.enabled = true;
3458
+ this.lights.dirLight = new THREE.DirectionalLight(16777215, 1);
3459
+ this.scene.add(this.lights.dirLight);
3460
+ if (helper) {
3461
+ this.lights.dirLightHelper = new THREE.DirectionalLightHelper(this.lights.dirLight, 5);
3462
+ this.scene.add(this.lights.dirLightHelper);
3463
+ }
3464
+ let d2 = 1e3;
3465
+ let r2 = 2;
3466
+ let mapSize2 = 8192;
3467
+ this.lights.dirLight.castShadow = true;
3468
+ this.lights.dirLight.shadow.radius = r2;
3469
+ this.lights.dirLight.shadow.mapSize.width = mapSize2;
3470
+ this.lights.dirLight.shadow.mapSize.height = mapSize2;
3471
+ this.lights.dirLight.shadow.camera.top = this.lights.dirLight.shadow.camera.right = d2;
3472
+ this.lights.dirLight.shadow.camera.bottom = this.lights.dirLight.shadow.camera.left = -d2;
3473
+ this.lights.dirLight.shadow.camera.near = 1;
3474
+ this.lights.dirLight.shadow.camera.visible = true;
3475
+ this.lights.dirLight.shadow.camera.far = 4e8;
3476
+ this.lights.hemiLight = new THREE.HemisphereLight(new THREE.Color(16777215), new THREE.Color(16777215), 0.6);
3477
+ this.lights.hemiLight.color.setHSL(0.661, 0.96, 0.12);
3478
+ this.lights.hemiLight.groundColor.setHSL(0.11, 0.96, 0.14);
3479
+ this.lights.hemiLight.position.set(0, 0, 50);
3480
+ this.scene.add(this.lights.hemiLight);
3481
+ this.setSunlight();
3482
+ this.map.once("idle", () => {
3483
+ this.setSunlight();
3484
+ this.repaint();
3485
+ });
3486
+ },
3487
+ setDefaultView: function(options2, defOptions) {
3488
+ options2.bbox = (options2.bbox || options2.bbox == null) && defOptions.enableSelectingObjects;
3489
+ options2.tooltip = (options2.tooltip || options2.tooltip == null) && defOptions.enableTooltips;
3490
+ options2.mapScale = this.map.transform.scale;
3491
+ },
3492
+ memory: function() {
3493
+ return this.renderer.info.memory;
3494
+ },
3495
+ programs: function() {
3496
+ return this.renderer.info.programs.length;
3497
+ },
3498
+ version: "2.2.7"
3499
+ };
3500
+ var defaultOptions = {
3501
+ defaultLights: false,
3502
+ realSunlight: false,
3503
+ realSunlightHelper: false,
3504
+ passiveRendering: true,
3505
+ preserveDrawingBuffer: false,
3506
+ enableSelectingFeatures: false,
3507
+ enableSelectingObjects: false,
3508
+ enableDraggingObjects: false,
3509
+ enableRotatingObjects: false,
3510
+ enableTooltips: false,
3511
+ enableHelpTooltips: false,
3512
+ multiLayer: false,
3513
+ orthographic: false,
3514
+ fov: ThreeboxConstants.FOV_DEGREES,
3515
+ sky: false,
3516
+ terrain: false
3517
+ };
3518
+ export {
3519
+ Threebox
3520
+ };
3521
+ //# sourceMappingURL=threebox.js.map